From 6bfbde5c24623ca8fbc02eb47d844bb7d71df191 Mon Sep 17 00:00:00 2001 From: Alexander Grund Date: Wed, 1 Apr 2020 12:22:41 +0200 Subject: [PATCH 1/5] Improve test_system Split parent and child code into functions for better output Introduce TEST_EQUAL for better output Compare each entry in env-pointer and argv Don't check env-pointer values against getenv() as they might differ: When launching the program from e.g. bash with `temp=bar`then there is TEMP and temp in the list (env-pointer) but getenv/GetEnvironmentVariable is case insensitive picking up the first matching value. --- test/test.hpp | 18 ++++ test/test_system.cpp | 218 ++++++++++++++++++++++++++++++++----------- 2 files changed, 179 insertions(+), 57 deletions(-) diff --git a/test/test.hpp b/test/test.hpp index 9bfb6df..13eaad3 100644 --- a/test/test.hpp +++ b/test/test.hpp @@ -51,6 +51,16 @@ inline void test_failed(const char* expr, const char* file, const int line, cons throw std::runtime_error(ss.str()); } +template +inline void test_equal_impl(const T& lhs, const U& rhs, const char* file, const int line, const char* function) +{ + if(lhs == rhs) + return; + std::ostringstream ss; + ss << "[" << lhs << "!=" << rhs << "]"; + test_failed(ss.str().c_str(), file, line, function); +} + #ifdef _MSC_VER #define DISABLE_CONST_EXPR_DETECTED __pragma(warning(push)) __pragma(warning(disable : 4127)) #define DISABLE_CONST_EXPR_DETECTED_POP __pragma(warning(pop)) @@ -68,5 +78,13 @@ inline void test_failed(const char* expr, const char* file, const int line, cons test_failed(#x, __FILE__, __LINE__, __FUNCTION__); \ DISABLE_CONST_EXPR_DETECTED \ } while(0) DISABLE_CONST_EXPR_DETECTED_POP +#define TEST_EQ(lhs, rhs) \ + do \ + { \ + test_mon(); \ + test_equal_impl((lhs), (rhs), __FILE__, __LINE__, __FUNCTION__); \ + break; \ + DISABLE_CONST_EXPR_DETECTED \ + } while(0) DISABLE_CONST_EXPR_DETECTED_POP #endif // #ifndef BOOST_NOWIDE_LIB_TEST_H_INCLUDED diff --git a/test/test_system.cpp b/test/test_system.cpp index 07f3f23..8156424 100644 --- a/test/test_system.cpp +++ b/test/test_system.cpp @@ -5,76 +5,180 @@ // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // +#ifdef _MSC_VER +#define _CRT_SECURE_NO_WARNINGS +#endif #include "test.hpp" #include #include +#include +#include +#include #include #include +#include +#include + +bool is_ascii(const std::string& s) +{ + for(std::string::const_iterator it = s.begin(); it != s.end(); ++it) + { + if(static_cast(*it) > 0x7F) + return false; + } + return true; +} + +std::string replace_non_ascii(const std::string& s) +{ + std::string::const_iterator it = s.begin(); + namespace utf = boost::nowide::detail::utf; + typedef utf::utf_traits utf8; + std::string result; + result.reserve(s.size()); + while(it != s.end()) + { + utf::code_point c = utf8::decode(it, s.end()); + TEST(c != utf::illegal && c != utf::incomplete); + if(c > 0x7F) + c = '?'; // WinAPI seems to do this + result.push_back(static_cast(c)); + } + return result; +} + +void compare_string_arrays(char** main_val, char** utf8_val, bool sort) +{ + std::vector vec_main, vec_utf8; + for(; *main_val; ++main_val) + vec_main.push_back(std::string(*main_val)); + for(; *utf8_val; ++utf8_val) + vec_utf8.push_back(std::string(*utf8_val)); + // Same number of strings + TEST_EQ(vec_main.size(), vec_utf8.size()); + if(sort) + { + // Order doesn't matter + std::sort(vec_main.begin(), vec_main.end()); + std::sort(vec_utf8.begin(), vec_utf8.end()); + } + for(size_t i = 0; i < vec_main.size(); ++i) + { + // Skip strings with non-ascii chars + if(!is_ascii(vec_main[i])) + continue; + if(vec_main[i] != vec_utf8[i]) + TEST_EQ(vec_main[i], replace_non_ascii(vec_utf8[i])); + } +} + +void compare_getenv(char** env) +{ + // For all all variables in env check against getenv + for(char** e = env; *e != 0; e++) + { + const char* key_begin = *e; + const char* key_end = strchr(key_begin, '='); + TEST(key_end); + std::string key = std::string(key_begin, key_end); + const char* std_value = std::getenv(key.c_str()); + const char* bnw_value = boost::nowide::getenv(key.c_str()); + // If std_value is set, bnw value must be too and be equal, else bnw value must be unset too + if(std_value) + { + TEST(bnw_value); + // Compare only if ascii + if(!is_ascii(std_value)) + continue; + if(std::string(std_value) != std::string(bnw_value)) + TEST_EQ(std_value, replace_non_ascii(bnw_value)); + } else + TEST(!bnw_value); + } +} + +const std::string example = "\xd7\xa9-\xd0\xbc-\xce\xbd"; + +void run_child(int argc, char** argv, char** env) +{ + // Test arguments + TEST(argc == 2); + TEST_EQ(argv[1], example); + TEST(argv[2] == 0); + + // Test getenv + TEST(boost::nowide::getenv("BOOST_NOWIDE_TEST")); + TEST_EQ(boost::nowide::getenv("BOOST_NOWIDE_TEST"), example); + TEST(boost::nowide::getenv("BOOST_NOWIDE_TEST_NONE") == 0); + // Empty variables are unreliable on windows, hence skip. E.g. using "set FOO=" unsets FOO +#ifndef BOOST_WINDOWS + TEST(boost::nowide::getenv("BOOST_NOWIDE_EMPTY")); + TEST_EQ(boost::nowide::getenv("BOOST_NOWIDE_EMPTY"), std::string()); +#endif // !_WIN32 + + // This must be contained in env + std::string sample = "BOOST_NOWIDE_TEST=" + example; + bool found = false; + for(char** e = env; *e != 0; e++) + { + if(*e == sample) + found = true; + } + TEST(found); + + std::cout << "Subprocess ok" << std::endl; +} + +void run_parent(const char* exe_path) +{ +#if BOOST_NOWIDE_TEST_USE_NARROW + TEST(boost::nowide::setenv("BOOST_NOWIDE_TEST", example.c_str(), 1) == 0); + TEST(boost::nowide::setenv("BOOST_NOWIDE_TEST_NONE", example.c_str(), 1) == 0); + TEST(boost::nowide::unsetenv("BOOST_NOWIDE_TEST_NONE") == 0); + TEST(boost::nowide::setenv("BOOST_NOWIDE_EMPTY", "", 1) == 0); + TEST(boost::nowide::getenv("BOOST_NOWIDE_EMPTY")); + std::string command = "\""; + command += exe_path; + command += "\" "; + command += example; + TEST(boost::nowide::system(command.c_str()) == 0); + std::cout << "Parent ok" << std::endl; +#else + std::wstring envVar = L"BOOST_NOWIDE_TEST=" + boost::nowide::widen(example); + TEST(_wputenv(envVar.c_str()) == 0); + std::wstring wcommand = boost::nowide::widen(exe_path) + L" " + boost::nowide::widen(example); + TEST(_wsystem(wcommand.c_str()) == 0); + std::cout << "Wide Parent ok" << std::endl; +#endif +} int main(int argc, char** argv, char** env) { try { - std::string example = "\xd7\xa9-\xd0\xbc-\xce\xbd"; - boost::nowide::args a(argc, argv, env); - if(argc == 2 && argv[1][0] != '-') + const int old_argc = argc; + char** old_argv = argv; + char** old_env = env; { - TEST(argv[1] == example); - TEST(argv[2] == 0); - TEST(boost::nowide::getenv("BOOST_NOWIDE_TEST")); - TEST(boost::nowide::getenv("BOOST_NOWIDE_TEST_NONE") == 0); - TEST(boost::nowide::getenv("BOOST_NOWIDE_TEST") == example); - // Empty variables are unreliable on windows, hence skip. E.g. using "set FOO=" unsets FOO -#ifndef BOOST_WINDOWS - TEST(boost::nowide::getenv("BOOST_NOWIDE_EMPTY")); - TEST(boost::nowide::getenv("BOOST_NOWIDE_EMPTY") == std::string()); -#endif // !_WIN32 - - std::string sample = "BOOST_NOWIDE_TEST=" + example; - bool found = false; - for(char** e = env; *e != 0; e++) - { - char* eptr = *e; - std::cout << "Checking " << eptr << std::endl; - char* key_end = strchr(eptr, '='); - TEST(key_end); - std::string key = std::string(eptr, key_end); - std::string value = key_end + 1; -#ifdef BOOST_WINDOWS - if(value.empty()) - continue; -#endif - std::cout << "Key: " << key << " Value: " << value << std::endl; - TEST(boost::nowide::getenv(key.c_str())); - TEST(boost::nowide::getenv(key.c_str()) == value); - if(*e == sample) - found = true; - } - TEST(found); - std::cout << "Subprocess ok" << std::endl; - } else if(argc == 1) - { -#if BOOST_NOWIDE_TEST_USE_NARROW - TEST(boost::nowide::setenv("BOOST_NOWIDE_TEST", example.c_str(), 1) == 0); - TEST(boost::nowide::setenv("BOOST_NOWIDE_TEST_NONE", example.c_str(), 1) == 0); - TEST(boost::nowide::unsetenv("BOOST_NOWIDE_TEST_NONE") == 0); - TEST(boost::nowide::setenv("BOOST_NOWIDE_EMPTY", "", 1) == 0); - TEST(boost::nowide::getenv("BOOST_NOWIDE_EMPTY")); - std::string command = "\""; - command += argv[0]; - command += "\" "; - command += example; - TEST(boost::nowide::system(command.c_str()) == 0); - std::cout << "Parent ok" << std::endl; -#else - std::wstring envVar = L"BOOST_NOWIDE_TEST=" + boost::nowide::widen(example); - TEST(_wputenv(envVar.c_str()) == 0); - std::wstring wcommand = boost::nowide::widen(argv[0]) + L" " + boost::nowide::widen(example); - TEST(_wsystem(wcommand.c_str()) == 0); - std::cout << "Wide Parent ok" << std::endl; -#endif + boost::nowide::args _(argc, argv, env); + TEST(argc == old_argc); + std::cout << "Checking arguments" << std::endl; + compare_string_arrays(old_argv, argv, false); + std::cout << "Checking env" << std::endl; + compare_string_arrays(old_env, env, true); + compare_getenv(env); } + // When `args` is destructed the old values must be restored + TEST(argc == old_argc); + TEST(argv == old_argv); + TEST(env == old_env); + + boost::nowide::args a(argc, argv, env); + if(argc == 1) + run_parent(argv[0]); + else + run_child(argc, argv, env); } catch(const std::exception& e) { std::cerr << "Failed " << e.what() << std::endl; From c51e4bd1a8794f30dcc7f31e71ec4fa303889a11 Mon Sep 17 00:00:00 2001 From: Alexander Grund Date: Thu, 2 Apr 2020 22:22:40 +0200 Subject: [PATCH 2/5] Disable test_system on OSX for shared libs THe child process can't start as RPATH/DYLIB_PATH is not set up correctly for child processes --- .azure-pipelines.yml | 1 - .travis.yml | 3 +-- test/Jamfile.v2 | 2 +- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/.azure-pipelines.yml b/.azure-pipelines.yml index bf51f7d..29ca05d 100644 --- a/.azure-pipelines.yml +++ b/.azure-pipelines.yml @@ -126,7 +126,6 @@ stages: B2_TOOLSET: clang B2_CXXSTD: 03,11,14,17,2a XCODE_APP: /Applications/Xcode_11.3.1.app - B2_LINK: static B2_JOBS: 3 # Workaround for https://github.com/boostorg/boost-ci/issues/50 steps: - bash: | diff --git a/.travis.yml b/.travis.yml index 2874b92..4ef851a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -77,8 +77,7 @@ jobs: - { compiler: clang++-libc++, env: 'SANITIZERS=1 B2_CXXSTD=03,11,14', addons: *libcpp, dist: trusty } - os: osx compiler: clang++ - # DYLD_LIBRARY_PATH causes problems on system() spawned processes -> static build only - env: SANITIZERS=1 B2_CXXSTD=03,11,14,1z B2_LINK=link=static + env: SANITIZERS=1 B2_CXXSTD=03,11,14,1z # Codecov - compiler: g++-8 env: COMMENT=codecov.io B2_CXXSTD=03,11 GCOV=gcov-8 diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 6a3c096..738dc0e 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -33,7 +33,7 @@ run test_fstream_cxx11.cpp : : : BOOST_NOWIDE_USE_FILEBUF_REPLACEMENT=1 run test_iostream.cpp ; run test_stackstring.cpp ; run test_stdio.cpp ; -run test_system.cpp : : : BOOST_NOWIDE_TEST_USE_NARROW=1 windows:shell32 : test_system_n ; +run test_system.cpp : : : BOOST_NOWIDE_TEST_USE_NARROW=1 windows:shell32 darwin,shared:no : test_system_n ; run test_system.cpp : : : BOOST_NOWIDE_TEST_USE_NARROW=0 windows:shell32 no windows:yes : test_system_w ; compile benchmark_fstream.cpp : BOOST_NOWIDE_USE_WIN_FSTREAM=1 /boost/chrono//boost_chrono/ ; From b870c3276fd62c5a4f2a8c0d465980a3272b8984 Mon Sep 17 00:00:00 2001 From: Alexander Grund Date: Fri, 3 Apr 2020 09:29:06 +0200 Subject: [PATCH 3/5] [CI] Update AzP CI script --- .azure-pipelines.yml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/.azure-pipelines.yml b/.azure-pipelines.yml index 29ca05d..c562944 100644 --- a/.azure-pipelines.yml +++ b/.azure-pipelines.yml @@ -34,10 +34,9 @@ pr: - develop variables: - - name: B2_VARIANT - value: release,debug - - name: B2_LINK - value: shared,static + B2_CI_VERSION: 1 + B2_VARIANT: release,debug + B2_LINK: shared,static stages: From 2f323ad9b2181af3e843cd2a79fd7660fe268b65 Mon Sep 17 00:00:00 2001 From: Alexander Grund Date: Fri, 3 Apr 2020 10:50:09 +0200 Subject: [PATCH 4/5] [CI] Use ppa directly on travis Workaround "Disallowing sources: ubuntu-toolchain-r-test" bug --- .travis.yml | 45 ++++++++++++++++++++++++--------------------- 1 file changed, 24 insertions(+), 21 deletions(-) diff --git a/.travis.yml b/.travis.yml index 4ef851a..fea6f9b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -25,48 +25,51 @@ env: anchors: libcpp: &libcpp { apt: { packages: [libc++-dev, libc++-helpers] } } + ubuntu-toolchain-r-test: + - &ubuntu-toolchain-r-test + sourceline: "ppa:ubuntu-toolchain-r/test" clang-33: &clang-33 { apt: { packages: [ "clang-3.3"] } } clang-34: &clang-34 { apt: { packages: [ "clang-3.4"] } } - clang-35: &clang-35 { apt: { packages: [ "clang-3.5"], sources: [ "ubuntu-toolchain-r-test" ] } } - clang-36: &clang-36 { apt: { packages: [ "clang-3.6"], sources: [ "ubuntu-toolchain-r-test" ] } } - clang-37: &clang-37 { apt: { packages: [ "clang-3.7"], sources: [ "ubuntu-toolchain-r-test" ] } } - clang-38: &clang-38 { apt: { packages: [ "clang-3.8"], sources: [ "ubuntu-toolchain-r-test" ] } } - clang-39: &clang-39 { apt: { packages: [ "clang-3.9"], sources: [ "ubuntu-toolchain-r-test" ] } } + clang-35: &clang-35 { apt: { packages: [ "clang-3.5"], sources: [ *ubuntu-toolchain-r-test ] } } + clang-36: &clang-36 { apt: { packages: [ "clang-3.6"], sources: [ *ubuntu-toolchain-r-test ] } } + clang-37: &clang-37 { apt: { packages: [ "clang-3.7"], sources: [ *ubuntu-toolchain-r-test ] } } + clang-38: &clang-38 { apt: { packages: [ "clang-3.8"], sources: [ *ubuntu-toolchain-r-test ] } } + clang-39: &clang-39 { apt: { packages: [ "clang-3.9"], sources: [ *ubuntu-toolchain-r-test ] } } clang-4: &clang-4 { apt: { packages: [ "clang-4.0", "libstdc++-6-dev" ], sources: [ "llvm-toolchain-xenial-4.0", - "ubuntu-toolchain-r-test" ] } } + *ubuntu-toolchain-r-test ] } } clang-5: &clang-5 { apt: { packages: [ "clang-5.0", "libstdc++-7-dev" ], sources: [ "llvm-toolchain-xenial-5.0", - "ubuntu-toolchain-r-test" ] } } + *ubuntu-toolchain-r-test ] } } clang-6: &clang-6 { apt: { packages: [ "clang-6.0", "libc6-dbg", "libc++-dev", "libstdc++-8-dev" ], sources: [ "llvm-toolchain-xenial-6.0", - "ubuntu-toolchain-r-test" ] } } + *ubuntu-toolchain-r-test ] } } clang-7: &clang-7 { apt: { packages: [ "clang-7", "libc6-dbg", "libc++-dev", "libstdc++-8-dev" ], sources: [ "llvm-toolchain-xenial-7", - "ubuntu-toolchain-r-test" ] } } + *ubuntu-toolchain-r-test ] } } clang-8: &clang-8 { apt: { packages: [ "clang-8", "libc6-dbg", "libc++-dev", "libstdc++-8-dev" ], sources: [ "llvm-toolchain-xenial-8", - "ubuntu-toolchain-r-test" ] } } - clang-9: &clang-9 { apt: { packages: [ "clang-9" ], sources: [ "ubuntu-toolchain-r-test", + *ubuntu-toolchain-r-test ] } } + clang-9: &clang-9 { apt: { packages: [ "clang-9" ], sources: [ *ubuntu-toolchain-r-test, { sourceline: 'deb https://apt.llvm.org/xenial/ llvm-toolchain-xenial-9 main', key_url: 'https://apt.llvm.org/llvm-snapshot.gpg.key'} ] } } - gcc-44: &gcc-44 { apt: { packages: [ "g++-4.4" ], sources: [ "ubuntu-toolchain-r-test" ] } } - gcc-46: &gcc-46 { apt: { packages: [ "g++-4.6" ], sources: [ "ubuntu-toolchain-r-test" ] } } - gcc-47: &gcc-47 { apt: { packages: [ "g++-4.7" ], sources: [ "ubuntu-toolchain-r-test" ] } } - gcc-48: &gcc-48 { apt: { packages: [ "g++-4.8" ], sources: [ "ubuntu-toolchain-r-test" ] } } - gcc-49: &gcc-49 { apt: { packages: [ "g++-4.9" ], sources: [ "ubuntu-toolchain-r-test" ] } } - gcc-5: &gcc-5 { apt: { packages: [ "g++-5" ], sources: [ "ubuntu-toolchain-r-test" ] } } - gcc-6: &gcc-6 { apt: { packages: [ "g++-6" ], sources: [ "ubuntu-toolchain-r-test" ] } } - gcc-7: &gcc-7 { apt: { packages: [ "g++-7" ], sources: [ "ubuntu-toolchain-r-test" ] } } - gcc-8: &gcc-8 { apt: { packages: [ "g++-8" ], sources: [ "ubuntu-toolchain-r-test" ] } } - gcc-9: &gcc-9 { apt: { packages: [ "g++-9" ], sources: [ "ubuntu-toolchain-r-test" ] } } + gcc-44: &gcc-44 { apt: { packages: [ "g++-4.4" ], sources: [ *ubuntu-toolchain-r-test ] } } + gcc-46: &gcc-46 { apt: { packages: [ "g++-4.6" ], sources: [ *ubuntu-toolchain-r-test ] } } + gcc-47: &gcc-47 { apt: { packages: [ "g++-4.7" ], sources: [ *ubuntu-toolchain-r-test ] } } + gcc-48: &gcc-48 { apt: { packages: [ "g++-4.8" ], sources: [ *ubuntu-toolchain-r-test ] } } + gcc-49: &gcc-49 { apt: { packages: [ "g++-4.9" ], sources: [ *ubuntu-toolchain-r-test ] } } + gcc-5: &gcc-5 { apt: { packages: [ "g++-5" ], sources: [ *ubuntu-toolchain-r-test ] } } + gcc-6: &gcc-6 { apt: { packages: [ "g++-6" ], sources: [ *ubuntu-toolchain-r-test ] } } + gcc-7: &gcc-7 { apt: { packages: [ "g++-7" ], sources: [ *ubuntu-toolchain-r-test ] } } + gcc-8: &gcc-8 { apt: { packages: [ "g++-8" ], sources: [ *ubuntu-toolchain-r-test ] } } + gcc-9: &gcc-9 { apt: { packages: [ "g++-9" ], sources: [ *ubuntu-toolchain-r-test ] } } jobs: include: From 6afb3f15abcb543c731b7a8c7ff134c193d0f309 Mon Sep 17 00:00:00 2001 From: Alexander Grund Date: Fri, 3 Apr 2020 14:18:31 +0200 Subject: [PATCH 5/5] Deduplicate tests and improve coverage Every test had the same pattern of a main catching exceptions and returning 0 or 1 based on that. Factor that into test.hpp. As most code in test.hpp is only executed on failure and those should not occur this file is excluded from coverage. Finally test.hpp is included last and the header to test first consistently to check for self-sufficient includes. --- codecov.yml | 2 + test/benchmark_fstream.cpp | 5 +- test/test.hpp | 21 ++- test/test_codecvt.cpp | 26 +-- test/test_convert.cpp | 98 +++++----- test/test_env.cpp | 56 +++--- test/test_fs.cpp | 92 ++++----- test/test_fstream.cpp | 45 ++--- test/test_fstream_cxx11.cpp | 25 +-- test/test_iostream.cpp | 99 +++++----- test/test_stackstring.cpp | 366 ++++++++++++++++++------------------ test/test_stdio.cpp | 171 ++++++++--------- test/test_system.cpp | 61 +++--- 13 files changed, 501 insertions(+), 566 deletions(-) diff --git a/codecov.yml b/codecov.yml index 4986738..d0a05c0 100644 --- a/codecov.yml +++ b/codecov.yml @@ -6,3 +6,5 @@ codecov: wait_for_ci: yes comment: layout: "diff, files" +ignore: + - "test/test.hpp" diff --git a/test/benchmark_fstream.cpp b/test/benchmark_fstream.cpp index 119b778..7ebcfcb 100644 --- a/test/benchmark_fstream.cpp +++ b/test/benchmark_fstream.cpp @@ -7,7 +7,8 @@ // http://www.boost.org/LICENSE_1_0.txt) // -#include "test.hpp" +#define BOOST_NOWIDE_TEST_NO_MAIN + #include #include #include @@ -22,6 +23,8 @@ #include #include +#include "test.hpp" + template Value get(const std::map& map, const Key2& key) { diff --git a/test/test.hpp b/test/test.hpp index 13eaad3..a8f9662 100644 --- a/test/test.hpp +++ b/test/test.hpp @@ -1,6 +1,6 @@ // // Copyright (c) 2012 Artyom Beilis (Tonkikh) -// Copyright (c) 2019 Alexander Grund +// Copyright (c) 2019-2020 Alexander Grund // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -10,6 +10,7 @@ #define BOOST_NOWIDE_LIB_TEST_H_INCLUDED #include +#include #include #include @@ -88,3 +89,21 @@ inline void test_equal_impl(const T& lhs, const U& rhs, const char* file, const } while(0) DISABLE_CONST_EXPR_DETECTED_POP #endif // #ifndef BOOST_NOWIDE_LIB_TEST_H_INCLUDED + +#ifndef BOOST_NOWIDE_TEST_NO_MAIN +// Tests should implement this +void test_main(int argc, char** argv, char** env); + +int main(int argc, char** argv, char** env) +{ + try + { + test_main(argc, argv, env); + } catch(const std::exception& e) + { + std::cerr << "Failed " << e.what() << std::endl; + return 1; + } + return 0; +} +#endif diff --git a/test/test_codecvt.cpp b/test/test_codecvt.cpp index ccdf2d9..7acc0f1 100644 --- a/test/test_codecvt.cpp +++ b/test/test_codecvt.cpp @@ -6,16 +6,18 @@ // http://www.boost.org/LICENSE_1_0.txt) // -#include "test.hpp" -#include "test_sets.hpp" -#include #include + +#include #include #include #include #include #include +#include "test.hpp" +#include "test_sets.hpp" + static const char* utf8_name = "\xf0\x9d\x92\x9e-\xD0\xBF\xD1\x80\xD0\xB8\xD0\xB2\xD0\xB5\xD1\x82-\xE3\x82\x84\xE3\x81\x82.txt"; static const std::wstring wide_name_str = boost::nowide::widen(utf8_name); @@ -318,19 +320,9 @@ void test_codecvt_subst() run_all(codecvt_to_wide, codecvt_to_narrow); } -int main() +void test_main(int, char**, char**) { - try - { - test_codecvt_conv(); - test_codecvt_err(); - test_codecvt_subst(); - - } catch(const std::exception& e) - { - std::cerr << "Failed : " << e.what() << std::endl; - return 1; - } - - return 0; + test_codecvt_conv(); + test_codecvt_err(); + test_codecvt_subst(); } diff --git a/test/test_convert.cpp b/test/test_convert.cpp index b35a741..788689c 100644 --- a/test/test_convert.cpp +++ b/test/test_convert.cpp @@ -6,11 +6,12 @@ // http://www.boost.org/LICENSE_1_0.txt) // -#include "test.hpp" -#include "test_sets.hpp" #include #include +#include "test.hpp" +#include "test_sets.hpp" + #if defined(BOOST_MSVC) && BOOST_MSVC < 1700 #pragma warning(disable : 4428) // universal-character-name encountered in source #endif @@ -67,60 +68,51 @@ std::string narrow_raw_string_and_size(const std::wstring& s) return boost::nowide::narrow(s2.c_str(), s.size()); } -int main() +void test_main(int, char**, char**) { - try - { - std::string hello = "\xd7\xa9\xd7\x9c\xd7\x95\xd7\x9d"; - std::wstring whello = L"\u05e9\u05dc\u05d5\u05dd"; - std::wstring whello_3e = L"\u05e9\u05dc\u05d5\ufffd"; - std::wstring whello_3 = L"\u05e9\u05dc\u05d5"; + std::string hello = "\xd7\xa9\xd7\x9c\xd7\x95\xd7\x9d"; + std::wstring whello = L"\u05e9\u05dc\u05d5\u05dd"; + std::wstring whello_3e = L"\u05e9\u05dc\u05d5\ufffd"; + std::wstring whello_3 = L"\u05e9\u05dc\u05d5"; - std::cout << "- boost::nowide::widen" << std::endl; - { - const char* b = hello.c_str(); - const char* e = b + hello.size(); - wchar_t buf[6] = {0, 0, 0, 0, 0, 1}; - TEST(boost::nowide::widen(buf, 5, b, e) == buf); - TEST(buf == whello); - TEST(buf[5] == 1); - TEST(boost::nowide::widen(buf, 4, b, e) == 0); - TEST(boost::nowide::widen(buf, 5, b, e - 1) == buf); - TEST(buf == whello_3e); - TEST(boost::nowide::widen(buf, 5, b, e - 2) == buf); - TEST(buf == whello_3); - TEST(boost::nowide::widen(buf, 5, b, b) == buf && buf[0] == 0); - TEST(boost::nowide::widen(buf, 5, b, b + 2) == buf && buf[1] == 0 && buf[0] == whello[0]); - } - std::cout << "- boost::nowide::narrow" << std::endl; - { - const wchar_t* b = whello.c_str(); - const wchar_t* e = b + whello.size(); //-V594 - char buf[10] = {0}; - buf[9] = 1; - TEST(boost::nowide::narrow(buf, 9, b, e) == buf); - TEST(buf == hello); - TEST(buf[9] == 1); - TEST(boost::nowide::narrow(buf, 8, b, e) == 0); - TEST(boost::nowide::narrow(buf, 7, b, e - 1) == buf); - TEST(buf == hello.substr(0, 6)); - } - - std::cout << "- (output_buffer, buffer_size, input_raw_string)" << std::endl; - run_all(widen_buf_ptr, narrow_buf_ptr); - std::cout << "- (output_buffer, buffer_size, input_raw_string, string_len)" << std::endl; - run_all(widen_buf_range, narrow_buf_range); - std::cout << "- (input_raw_string)" << std::endl; - run_all(widen_raw_string, narrow_raw_string); - std::cout << "- (input_raw_string, size)" << std::endl; - run_all(widen_raw_string_and_size, narrow_raw_string_and_size); - std::cout << "- (const std::string&)" << std::endl; - run_all(boost::nowide::widen, boost::nowide::narrow); - } catch(const std::exception& e) + std::cout << "- boost::nowide::widen" << std::endl; { - std::cerr << "Failed :" << e.what() << std::endl; - return 1; + const char* b = hello.c_str(); + const char* e = b + hello.size(); + wchar_t buf[6] = {0, 0, 0, 0, 0, 1}; + TEST(boost::nowide::widen(buf, 5, b, e) == buf); + TEST(buf == whello); + TEST(buf[5] == 1); + TEST(boost::nowide::widen(buf, 4, b, e) == 0); + TEST(boost::nowide::widen(buf, 5, b, e - 1) == buf); + TEST(buf == whello_3e); + TEST(boost::nowide::widen(buf, 5, b, e - 2) == buf); + TEST(buf == whello_3); + TEST(boost::nowide::widen(buf, 5, b, b) == buf && buf[0] == 0); + TEST(boost::nowide::widen(buf, 5, b, b + 2) == buf && buf[1] == 0 && buf[0] == whello[0]); + } + std::cout << "- boost::nowide::narrow" << std::endl; + { + const wchar_t* b = whello.c_str(); + const wchar_t* e = b + whello.size(); //-V594 + char buf[10] = {0}; + buf[9] = 1; + TEST(boost::nowide::narrow(buf, 9, b, e) == buf); + TEST(buf == hello); + TEST(buf[9] == 1); + TEST(boost::nowide::narrow(buf, 8, b, e) == 0); + TEST(boost::nowide::narrow(buf, 7, b, e - 1) == buf); + TEST(buf == hello.substr(0, 6)); } - return 0; + std::cout << "- (output_buffer, buffer_size, input_raw_string)" << std::endl; + run_all(widen_buf_ptr, narrow_buf_ptr); + std::cout << "- (output_buffer, buffer_size, input_raw_string, string_len)" << std::endl; + run_all(widen_buf_range, narrow_buf_range); + std::cout << "- (input_raw_string)" << std::endl; + run_all(widen_raw_string, narrow_raw_string); + std::cout << "- (input_raw_string, size)" << std::endl; + run_all(widen_raw_string_and_size, narrow_raw_string_and_size); + std::cout << "- (const std::string&)" << std::endl; + run_all(boost::nowide::widen, boost::nowide::narrow); } diff --git a/test/test_env.cpp b/test/test_env.cpp index 7b3a8c7..f9de36a 100644 --- a/test/test_env.cpp +++ b/test/test_env.cpp @@ -8,7 +8,6 @@ #include #include -#include #if defined(BOOST_NOWIDE_TEST_INCLUDE_WINDOWS) && defined(BOOST_WINDOWS) #include @@ -28,40 +27,31 @@ void strcpy_safe(char (&dest)[size], const char* src) dest[len] = 0; } -int main() +void test_main(int, char**, char**) { - try - { - std::string example = "\xd7\xa9-\xd0\xbc-\xce\xbd"; - char penv[256] = {0}; - strcpy_safe(penv, ("BOOST_TEST2=" + example + "x").c_str()); + std::string example = "\xd7\xa9-\xd0\xbc-\xce\xbd"; + char penv[256] = {0}; + strcpy_safe(penv, ("BOOST_TEST2=" + example + "x").c_str()); - TEST(boost::nowide::setenv("BOOST_TEST1", example.c_str(), 1) == 0); - TEST(boost::nowide::getenv("BOOST_TEST1")); - TEST(boost::nowide::getenv("BOOST_TEST1") == example); - TEST(boost::nowide::setenv("BOOST_TEST1", "xx", 0) == 0); - TEST(boost::nowide::getenv("BOOST_TEST1") == example); - TEST(boost::nowide::putenv(penv) == 0); - TEST(boost::nowide::getenv("BOOST_TEST2")); - TEST(boost::nowide::getenv("BOOST_TEST_INVALID") == 0); - TEST(boost::nowide::getenv("BOOST_TEST2") == example + "x"); + TEST(boost::nowide::setenv("BOOST_TEST1", example.c_str(), 1) == 0); + TEST(boost::nowide::getenv("BOOST_TEST1")); + TEST(boost::nowide::getenv("BOOST_TEST1") == example); + TEST(boost::nowide::setenv("BOOST_TEST1", "xx", 0) == 0); + TEST(boost::nowide::getenv("BOOST_TEST1") == example); + TEST(boost::nowide::putenv(penv) == 0); + TEST(boost::nowide::getenv("BOOST_TEST2")); + TEST(boost::nowide::getenv("BOOST_TEST_INVALID") == 0); + TEST(boost::nowide::getenv("BOOST_TEST2") == example + "x"); #ifdef BOOST_WINDOWS - // Passing a variable without an equals sign (before \0) is an error - // But GLIBC has an extension that unsets the env var instead - char penv2[256] = {0}; - const char* sPenv2 = "BOOST_TEST1SOMEGARBAGE="; - strcpy_safe(penv2, sPenv2); - // End the string before the equals sign -> Expect fail - penv2[strlen("BOOST_TEST1")] = '\0'; - TEST(boost::nowide::putenv(penv2) == -1); - TEST(boost::nowide::getenv("BOOST_TEST1")); - TEST(boost::nowide::getenv("BOOST_TEST1") == example); + // Passing a variable without an equals sign (before \0) is an error + // But GLIBC has an extension that unsets the env var instead + char penv2[256] = {0}; + const char* sPenv2 = "BOOST_TEST1SOMEGARBAGE="; + strcpy_safe(penv2, sPenv2); + // End the string before the equals sign -> Expect fail + penv2[strlen("BOOST_TEST1")] = '\0'; + TEST(boost::nowide::putenv(penv2) == -1); + TEST(boost::nowide::getenv("BOOST_TEST1")); + TEST(boost::nowide::getenv("BOOST_TEST1") == example); #endif - } catch(const std::exception& e) - { - std::cerr << "Failed " << e.what() << std::endl; - return 1; - } - - return 0; } diff --git a/test/test_fs.cpp b/test/test_fs.cpp index b7e0571..1859bd8 100644 --- a/test/test_fs.cpp +++ b/test/test_fs.cpp @@ -6,66 +6,56 @@ // http://www.boost.org/LICENSE_1_0.txt) // +#include + #include #include -#include #include #include -#include #include "test.hpp" -int main() +void test_main(int, char**, char**) { - try + boost::nowide::nowide_filesystem(); + const std::string prefix = boost::filesystem::unique_path("nowide-%%%%-%%%%-").string(); + const std::string utf8_name = + prefix + "\xf0\x9d\x92\x9e-\xD0\xBF\xD1\x80\xD0\xB8\xD0\xB2\xD0\xB5\xD1\x82-\xE3\x82\x84\xE3\x81\x82.txt"; + { - boost::nowide::nowide_filesystem(); - const std::string prefix = boost::filesystem::unique_path("nowide-%%%%-%%%%-").string(); - const std::string utf8_name = - prefix + "\xf0\x9d\x92\x9e-\xD0\xBF\xD1\x80\xD0\xB8\xD0\xB2\xD0\xB5\xD1\x82-\xE3\x82\x84\xE3\x81\x82.txt"; - - { - boost::nowide::ofstream f(utf8_name.c_str()); - TEST(f); - f << "Test" << std::endl; - } - - TEST(boost::filesystem::is_regular_file(boost::nowide::widen(utf8_name))); - TEST(boost::filesystem::is_regular_file(utf8_name)); - - TEST(boost::nowide::remove(utf8_name.c_str()) == 0); - - TEST(!boost::filesystem::is_regular_file(boost::nowide::widen(utf8_name))); - TEST(!boost::filesystem::is_regular_file(utf8_name)); - - const boost::filesystem::path path = utf8_name; - { - boost::nowide::ofstream f(path); - TEST(f); - f << "Test" << std::endl; - TEST(is_regular_file(path)); - } - { - boost::nowide::ifstream f(path); - TEST(f); - std::string test; - f >> test; - TEST(test == "Test"); - } - { - boost::nowide::fstream f(path); - TEST(f); - std::string test; - f >> test; - TEST(test == "Test"); - } - boost::filesystem::remove(path); - } catch(const std::exception& e) - { - std::cerr << "Failed : " << e.what() << std::endl; - return 1; + boost::nowide::ofstream f(utf8_name.c_str()); + TEST(f); + f << "Test" << std::endl; } - std::cout << "Ok" << std::endl; - return 0; + TEST(boost::filesystem::is_regular_file(boost::nowide::widen(utf8_name))); + TEST(boost::filesystem::is_regular_file(utf8_name)); + + TEST(boost::nowide::remove(utf8_name.c_str()) == 0); + + TEST(!boost::filesystem::is_regular_file(boost::nowide::widen(utf8_name))); + TEST(!boost::filesystem::is_regular_file(utf8_name)); + + const boost::filesystem::path path = utf8_name; + { + boost::nowide::ofstream f(path); + TEST(f); + f << "Test" << std::endl; + TEST(is_regular_file(path)); + } + { + boost::nowide::ifstream f(path); + TEST(f); + std::string test; + f >> test; + TEST(test == "Test"); + } + { + boost::nowide::fstream f(path); + TEST(f); + std::string test; + f >> test; + TEST(test == "Test"); + } + boost::filesystem::remove(path); } diff --git a/test/test_fstream.cpp b/test/test_fstream.cpp index 50b080d..9fdd1f8 100644 --- a/test/test_fstream.cpp +++ b/test/test_fstream.cpp @@ -7,14 +7,16 @@ // http://www.boost.org/LICENSE_1_0.txt) // -#include "test.hpp" +#include + #include #include -#include #include #include #include +#include "test.hpp" + namespace nw = boost::nowide; void make_empty_file(const char* filepath) @@ -488,33 +490,24 @@ void test_is_open(const char* filename) TEST(nw::remove(filename) == 0); } -int main(int, char** argv) +void test_main(int, char** argv, char**) { const std::string exampleFilename = std::string(argv[0]) + "-\xd7\xa9-\xd0\xbc-\xce\xbd.txt"; - try - { - std::cout << "Testing fstream" << std::endl; - test_ofstream_creates_file(exampleFilename.c_str()); - test_ofstream_write(exampleFilename.c_str()); - test_ifstream_open_read(exampleFilename.c_str()); - test_fstream(exampleFilename.c_str()); - test_is_open(exampleFilename.c_str()); + std::cout << "Testing fstream" << std::endl; + test_ofstream_creates_file(exampleFilename.c_str()); + test_ofstream_write(exampleFilename.c_str()); + test_ifstream_open_read(exampleFilename.c_str()); + test_fstream(exampleFilename.c_str()); + test_is_open(exampleFilename.c_str()); - std::cout << "Complex IO" << std::endl; - test_with_different_buffer_sizes(exampleFilename.c_str()); + std::cout << "Complex IO" << std::endl; + test_with_different_buffer_sizes(exampleFilename.c_str()); - std::cout << "filebuf::close" << std::endl; - test_close(exampleFilename.c_str()); + std::cout << "filebuf::close" << std::endl; + test_close(exampleFilename.c_str()); - std::cout << "Flush - Sanity Check" << std::endl; - test_flush(exampleFilename.c_str()); - std::cout << "Flush - Test" << std::endl; - test_flush(exampleFilename.c_str()); - } catch(const std::exception& e) - { - std::cerr << e.what() << std::endl; - return 1; - } - std::cout << "Ok" << std::endl; - return 0; + std::cout << "Flush - Sanity Check" << std::endl; + test_flush(exampleFilename.c_str()); + std::cout << "Flush - Test" << std::endl; + test_flush(exampleFilename.c_str()); } diff --git a/test/test_fstream_cxx11.cpp b/test/test_fstream_cxx11.cpp index e736c13..3ad16b7 100644 --- a/test/test_fstream_cxx11.cpp +++ b/test/test_fstream_cxx11.cpp @@ -10,13 +10,14 @@ #if BOOST_NOWIDE_CXX11 -#include "test.hpp" -#include #include -#include + +#include #include #include +#include "test.hpp" + namespace nw = boost::nowide; void create_file(const std::string& filename, const std::string& contents) @@ -180,21 +181,12 @@ void test_fstream(const std::string& filename) TEST(nw::remove(filename.c_str()) == 0); } -int main(int, char** argv) +void test_main(int, char** argv, char**) { const std::string exampleFilename = std::string(argv[0]) + "-\xd7\xa9-\xd0\xbc-\xce\xbd.txt"; - try - { - test_ifstream(exampleFilename); - test_ofstream(exampleFilename); - test_fstream(exampleFilename); - } catch(const std::exception& e) - { - std::cerr << e.what() << std::endl; - return 1; - } - std::cout << "Ok" << std::endl; - return 0; + test_ifstream(exampleFilename); + test_ofstream(exampleFilename); + test_fstream(exampleFilename); } #else @@ -204,7 +196,6 @@ int main(int, char** argv) int main() { std::cout << "Test skipped as there is no C++11 support by the compiler" << std::endl; - return 0; } #endif diff --git a/test/test_iostream.cpp b/test/test_iostream.cpp index d241184..cd5078f 100644 --- a/test/test_iostream.cpp +++ b/test/test_iostream.cpp @@ -6,9 +6,9 @@ // http://www.boost.org/LICENSE_1_0.txt) // -#include #include -#include + +#include #include #include "test.hpp" @@ -25,7 +25,7 @@ bool isValidUTF8(const std::string& s) return true; } -int main(int argc, char** argv) +void test_main(int argc, char** argv, char**) { const char* example = "Basic letters: \xd7\xa9-\xd0\xbc-\xce\xbd\n" "East Asian Letters: \xe5\x92\x8c\xe5\xb9\xb3\n" @@ -33,64 +33,55 @@ int main(int argc, char** argv) "Invalid UTF-8: `\xFF' `\xd7\xFF' `\xe5\xFF\x8c' `\xf0\x9d\x84\xFF' \n" "\n"; - try + // If we are using the standard rdbuf we can only put back 1 char + if(boost::nowide::cin.rdbuf() == std::cin.rdbuf()) { - // If we are using the standard rdbuf we can only put back 1 char - if(boost::nowide::cin.rdbuf() == std::cin.rdbuf()) + std::cout << "Using std::cin" << std::endl; + int maxval = 15000; + for(int i = 0; i < maxval; i++) { - std::cout << "Using std::cin" << std::endl; - int maxval = 15000; - for(int i = 0; i < maxval; i++) - { - char c = i % 96 + ' '; - TEST(boost::nowide::cin.putback(c)); - int ci = i % 96 + ' '; - TEST(boost::nowide::cin.get() == ci); - } - } else - { - int maxval = 15000; - for(int i = 0; i < maxval; i++) - { - char c = i % 96 + ' '; - TEST(boost::nowide::cin.putback(c)); - } - for(int i = maxval - 1; i >= 0; i--) - { - int c = i % 96 + ' '; - TEST(boost::nowide::cin.get() == c); - } + char c = i % 96 + ' '; + TEST(boost::nowide::cin.putback(c)); + int ci = i % 96 + ' '; + TEST(boost::nowide::cin.get() == ci); } - boost::nowide::cout << "Normal I/O:" << std::endl; - boost::nowide::cout << example << std::endl; - boost::nowide::cerr << example << std::endl; - - boost::nowide::cout << "Flushing each character:" << std::endl; - - for(const char* s = example; *s; s++) + } else + { + int maxval = 15000; + for(int i = 0; i < maxval; i++) { - boost::nowide::cout << *s << std::flush; - TEST(boost::nowide::cout); + char c = i % 96 + ' '; + TEST(boost::nowide::cin.putback(c)); } + for(int i = maxval - 1; i >= 0; i--) + { + int c = i % 96 + ' '; + TEST(boost::nowide::cin.get() == c); + } + } + boost::nowide::cout << "Normal I/O:" << std::endl; + boost::nowide::cout << example << std::endl; + boost::nowide::cerr << example << std::endl; + boost::nowide::cout << "Flushing each character:" << std::endl; + + for(const char* s = example; *s; s++) + { + boost::nowide::cout << *s << std::flush; TEST(boost::nowide::cout); - TEST(boost::nowide::cerr); - if(argc == 2 && argv[1] == std::string("-i")) - { - std::string v1, v2; - boost::nowide::cin >> v1 >> v2; - TEST(boost::nowide::cin); - TEST(isValidUTF8(v1)); - TEST(isValidUTF8(v2)); - boost::nowide::cout << "First: " << v1 << std::endl; - boost::nowide::cout << "Second: " << v2 << std::endl; - TEST(boost::nowide::cout); - } - } catch(const std::exception& e) - { - std::cerr << "Fail: " << e.what() << std::endl; - return 1; } - return 0; + TEST(boost::nowide::cout); + TEST(boost::nowide::cerr); + if(argc == 2 && argv[1] == std::string("-i")) + { + std::string v1, v2; + boost::nowide::cin >> v1 >> v2; + TEST(boost::nowide::cin); + TEST(isValidUTF8(v1)); + TEST(isValidUTF8(v2)); + boost::nowide::cout << "First: " << v1 << std::endl; + boost::nowide::cout << "Second: " << v2 << std::endl; + TEST(boost::nowide::cout); + } } diff --git a/test/test_stackstring.cpp b/test/test_stackstring.cpp index a1cfb0c..df675c5 100644 --- a/test/test_stackstring.cpp +++ b/test/test_stackstring.cpp @@ -7,12 +7,13 @@ // http://www.boost.org/LICENSE_1_0.txt) // -#include "test.hpp" -#include "test_sets.hpp" #include #include #include +#include "test.hpp" +#include "test_sets.hpp" + #if defined(BOOST_MSVC) && BOOST_MSVC < 1700 #pragma warning(disable : 4428) // universal-character-name encountered in source #endif @@ -71,194 +72,185 @@ std::string heap_stackstring_to_narrow(const std::wstring& s) return ss.get(); } -int main() +void test_main(int, char**, char**) { - try - { - std::string hello = "\xd7\xa9\xd7\x9c\xd7\x95\xd7\x9d"; - std::wstring whello = boost::nowide::widen(hello); - const wchar_t* wempty = L""; + std::string hello = "\xd7\xa9\xd7\x9c\xd7\x95\xd7\x9d"; + std::wstring whello = boost::nowide::widen(hello); + const wchar_t* wempty = L""; - { - std::cout << "-- Default constructed string is NULL" << std::endl; - const boost::nowide::short_stackstring s; - TEST(s.get() == NULL); - } - { - std::cout << "-- NULL ptr passed to ctor results in NULL" << std::endl; - const boost::nowide::short_stackstring s(NULL); - TEST(s.get() == NULL); - const boost::nowide::short_stackstring s2(NULL, NULL); - TEST(s2.get() == NULL); - } - { - std::cout << "-- NULL ptr passed to convert results in NULL" << std::endl; - boost::nowide::short_stackstring s(L"foo"); - TEST(s.get() == std::string("foo")); - s.convert(NULL); - TEST(s.get() == NULL); - boost::nowide::short_stackstring s2(L"foo"); - TEST(s2.get() == std::string("foo")); - s2.convert(NULL, NULL); - TEST(s2.get() == NULL); - } - { - std::cout << "-- An empty string is accepted" << std::endl; - const boost::nowide::short_stackstring s(wempty); - TEST(s.get()); - TEST(s.get() == std::string()); - const boost::nowide::short_stackstring s2(wempty, wempty); - TEST(s2.get()); - TEST(s2.get() == std::string()); - } - { - std::cout << "-- An empty string is accepted" << std::endl; - boost::nowide::short_stackstring s, s2; - TEST(s.convert(wempty)); - TEST(s.get() == std::string()); - TEST(s2.convert(wempty, wempty)); - TEST(s2.get() == std::string()); - } - { - std::cout << "-- Will be put on heap" << std::endl; - test_basic_stackstring sw; - TEST(sw.convert(hello.c_str())); - TEST(sw.uses_heap_memory()); - TEST(sw.get() == whello); - TEST(sw.convert(hello.c_str(), hello.c_str() + hello.size())); - TEST(sw.uses_heap_memory()); - TEST(sw.get() == whello); - } - { - std::cout << "-- Will be put on stack" << std::endl; - test_basic_stackstring sw; - TEST(sw.convert(hello.c_str())); - TEST(sw.uses_stack_memory()); - TEST(sw.get() == whello); - TEST(sw.convert(hello.c_str(), hello.c_str() + hello.size())); - TEST(sw.uses_stack_memory()); - TEST(sw.get() == whello); - } - { - std::cout << "-- Will be put on heap" << std::endl; - test_basic_stackstring sw; - TEST(sw.convert(whello.c_str())); - TEST(sw.uses_heap_memory()); - TEST(sw.get() == hello); - TEST(sw.convert(whello.c_str(), whello.c_str() + whello.size())); - TEST(sw.uses_heap_memory()); - TEST(sw.get() == hello); - } - { - std::cout << "-- Will be put on stack" << std::endl; - test_basic_stackstring sw; - TEST(sw.convert(whello.c_str())); - TEST(sw.uses_stack_memory()); - TEST(sw.get() == hello); - TEST(sw.convert(whello.c_str(), whello.c_str() + whello.size())); - TEST(sw.uses_stack_memory()); - TEST(sw.get() == hello); - } - { - typedef test_basic_stackstring stackstring; - const std::wstring heapVal = L"heapValue"; - const std::wstring stackVal = L"stack"; - const stackstring heap(boost::nowide::narrow(heapVal).c_str()); - const stackstring stack(boost::nowide::narrow(stackVal).c_str()); - TEST(heap.uses_heap_memory()); - TEST(stack.uses_stack_memory()); - - { - stackstring sw2(heap), sw3, sEmpty; - sw3 = heap; - TEST(sw2.get() == heapVal); - TEST(sw3.get() == heapVal); - // Self assign avoiding clang self-assign-overloaded warning - sw3 = static_cast(sw3); //-V570 - TEST(sw3.get() == heapVal); - // Assign empty - sw3 = sEmpty; //-V820 - TEST(sw3.get() == NULL); - } - { - stackstring sw2(stack), sw3, sEmpty; - sw3 = stack; - TEST(sw2.get() == stackVal); - TEST(sw3.get() == stackVal); - // Self assign avoiding clang self-assign-overloaded warning - sw3 = static_cast(sw3); //-V570 - TEST(sw3.get() == stackVal); - // Assign empty - sw3 = sEmpty; //-V820 - TEST(sw3.get() == NULL); - } - { - stackstring sw2(stack); - sw2 = heap; - TEST(sw2.get() == heapVal); - } - { - stackstring sw2(heap); - sw2 = stack; - TEST(sw2.get() == stackVal); - } - { - stackstring sw2(heap), sw3(stack), sEmpty1, sEmpty2; - swap(sw2, sw3); - TEST(sw2.get() == stackVal); - TEST(sw3.get() == heapVal); - swap(sw2, sw3); - TEST(sw2.get() == heapVal); - TEST(sw3.get() == stackVal); - swap(sw2, sEmpty1); - TEST(sEmpty1.get() == heapVal); - TEST(sw2.get() == NULL); - swap(sw3, sEmpty2); - TEST(sEmpty2.get() == stackVal); - TEST(sw3.get() == NULL); - } - { - stackstring sw2(heap), sw3(heap); - sw3.get()[0] = 'z'; - const std::wstring val2 = sw3.get(); - swap(sw2, sw3); - TEST(sw2.get() == val2); - TEST(sw3.get() == heapVal); - } - { - stackstring sw2(stack), sw3(stack); - sw3.get()[0] = 'z'; - const std::wstring val2 = sw3.get(); - swap(sw2, sw3); - TEST(sw2.get() == val2); - TEST(sw3.get() == stackVal); - } - std::cout << "-- Sanity check" << std::endl; - TEST(stack.get() == stackVal); - TEST(heap.get() == heapVal); - } - { - std::cout << "-- Test putting stackstrings into vector (done by args) class" << std::endl; - // Use a smallish buffer, to have stack and heap values - typedef boost::nowide::basic_stackstring stackstring; - std::vector strings; - strings.resize(2); - TEST(strings[0].convert("1234") == std::wstring(L"1234")); - TEST(strings[1].convert("Hello World") == std::wstring(L"Hello World")); - strings.push_back(stackstring("FooBar")); - TEST(strings[0].get() == std::wstring(L"1234")); - TEST(strings[1].get() == std::wstring(L"Hello World")); - TEST(strings[2].get() == std::wstring(L"FooBar")); - } - std::cout << "- Stackstring" << std::endl; - run_all(stackstring_to_wide, stackstring_to_narrow); - std::cout << "- Heap Stackstring" << std::endl; - run_all(heap_stackstring_to_wide, heap_stackstring_to_narrow); - } catch(const std::exception& e) { - std::cerr << "Failed :" << e.what() << std::endl; - return 1; + std::cout << "-- Default constructed string is NULL" << std::endl; + const boost::nowide::short_stackstring s; + TEST(s.get() == NULL); } + { + std::cout << "-- NULL ptr passed to ctor results in NULL" << std::endl; + const boost::nowide::short_stackstring s(NULL); + TEST(s.get() == NULL); + const boost::nowide::short_stackstring s2(NULL, NULL); + TEST(s2.get() == NULL); + } + { + std::cout << "-- NULL ptr passed to convert results in NULL" << std::endl; + boost::nowide::short_stackstring s(L"foo"); + TEST(s.get() == std::string("foo")); + s.convert(NULL); + TEST(s.get() == NULL); + boost::nowide::short_stackstring s2(L"foo"); + TEST(s2.get() == std::string("foo")); + s2.convert(NULL, NULL); + TEST(s2.get() == NULL); + } + { + std::cout << "-- An empty string is accepted" << std::endl; + const boost::nowide::short_stackstring s(wempty); + TEST(s.get()); + TEST(s.get() == std::string()); + const boost::nowide::short_stackstring s2(wempty, wempty); + TEST(s2.get()); + TEST(s2.get() == std::string()); + } + { + std::cout << "-- An empty string is accepted" << std::endl; + boost::nowide::short_stackstring s, s2; + TEST(s.convert(wempty)); + TEST(s.get() == std::string()); + TEST(s2.convert(wempty, wempty)); + TEST(s2.get() == std::string()); + } + { + std::cout << "-- Will be put on heap" << std::endl; + test_basic_stackstring sw; + TEST(sw.convert(hello.c_str())); + TEST(sw.uses_heap_memory()); + TEST(sw.get() == whello); + TEST(sw.convert(hello.c_str(), hello.c_str() + hello.size())); + TEST(sw.uses_heap_memory()); + TEST(sw.get() == whello); + } + { + std::cout << "-- Will be put on stack" << std::endl; + test_basic_stackstring sw; + TEST(sw.convert(hello.c_str())); + TEST(sw.uses_stack_memory()); + TEST(sw.get() == whello); + TEST(sw.convert(hello.c_str(), hello.c_str() + hello.size())); + TEST(sw.uses_stack_memory()); + TEST(sw.get() == whello); + } + { + std::cout << "-- Will be put on heap" << std::endl; + test_basic_stackstring sw; + TEST(sw.convert(whello.c_str())); + TEST(sw.uses_heap_memory()); + TEST(sw.get() == hello); + TEST(sw.convert(whello.c_str(), whello.c_str() + whello.size())); + TEST(sw.uses_heap_memory()); + TEST(sw.get() == hello); + } + { + std::cout << "-- Will be put on stack" << std::endl; + test_basic_stackstring sw; + TEST(sw.convert(whello.c_str())); + TEST(sw.uses_stack_memory()); + TEST(sw.get() == hello); + TEST(sw.convert(whello.c_str(), whello.c_str() + whello.size())); + TEST(sw.uses_stack_memory()); + TEST(sw.get() == hello); + } + { + typedef test_basic_stackstring stackstring; + const std::wstring heapVal = L"heapValue"; + const std::wstring stackVal = L"stack"; + const stackstring heap(boost::nowide::narrow(heapVal).c_str()); + const stackstring stack(boost::nowide::narrow(stackVal).c_str()); + TEST(heap.uses_heap_memory()); + TEST(stack.uses_stack_memory()); - return 0; + { + stackstring sw2(heap), sw3, sEmpty; + sw3 = heap; + TEST(sw2.get() == heapVal); + TEST(sw3.get() == heapVal); + // Self assign avoiding clang self-assign-overloaded warning + sw3 = static_cast(sw3); //-V570 + TEST(sw3.get() == heapVal); + // Assign empty + sw3 = sEmpty; //-V820 + TEST(sw3.get() == NULL); + } + { + stackstring sw2(stack), sw3, sEmpty; + sw3 = stack; + TEST(sw2.get() == stackVal); + TEST(sw3.get() == stackVal); + // Self assign avoiding clang self-assign-overloaded warning + sw3 = static_cast(sw3); //-V570 + TEST(sw3.get() == stackVal); + // Assign empty + sw3 = sEmpty; //-V820 + TEST(sw3.get() == NULL); + } + { + stackstring sw2(stack); + sw2 = heap; + TEST(sw2.get() == heapVal); + } + { + stackstring sw2(heap); + sw2 = stack; + TEST(sw2.get() == stackVal); + } + { + stackstring sw2(heap), sw3(stack), sEmpty1, sEmpty2; + swap(sw2, sw3); + TEST(sw2.get() == stackVal); + TEST(sw3.get() == heapVal); + swap(sw2, sw3); + TEST(sw2.get() == heapVal); + TEST(sw3.get() == stackVal); + swap(sw2, sEmpty1); + TEST(sEmpty1.get() == heapVal); + TEST(sw2.get() == NULL); + swap(sw3, sEmpty2); + TEST(sEmpty2.get() == stackVal); + TEST(sw3.get() == NULL); + } + { + stackstring sw2(heap), sw3(heap); + sw3.get()[0] = 'z'; + const std::wstring val2 = sw3.get(); + swap(sw2, sw3); + TEST(sw2.get() == val2); + TEST(sw3.get() == heapVal); + } + { + stackstring sw2(stack), sw3(stack); + sw3.get()[0] = 'z'; + const std::wstring val2 = sw3.get(); + swap(sw2, sw3); + TEST(sw2.get() == val2); + TEST(sw3.get() == stackVal); + } + std::cout << "-- Sanity check" << std::endl; + TEST(stack.get() == stackVal); + TEST(heap.get() == heapVal); + } + { + std::cout << "-- Test putting stackstrings into vector (done by args) class" << std::endl; + // Use a smallish buffer, to have stack and heap values + typedef boost::nowide::basic_stackstring stackstring; + std::vector strings; + strings.resize(2); + TEST(strings[0].convert("1234") == std::wstring(L"1234")); + TEST(strings[1].convert("Hello World") == std::wstring(L"Hello World")); + strings.push_back(stackstring("FooBar")); + TEST(strings[0].get() == std::wstring(L"1234")); + TEST(strings[1].get() == std::wstring(L"Hello World")); + TEST(strings[2].get() == std::wstring(L"FooBar")); + } + std::cout << "- Stackstring" << std::endl; + run_all(stackstring_to_wide, stackstring_to_narrow); + std::cout << "- Heap Stackstring" << std::endl; + run_all(heap_stackstring_to_wide, heap_stackstring_to_narrow); } diff --git a/test/test_stdio.cpp b/test/test_stdio.cpp index 5766458..250b601 100644 --- a/test/test_stdio.cpp +++ b/test/test_stdio.cpp @@ -50,7 +50,7 @@ void noop_invalid_param_handler(const wchar_t*, const wchar_t*, const wchar_t*, {} #endif -int main(int, char** argv) +void test_main(int, char** argv, char**) { const std::string prefix = argv[0]; const std::string filename = prefix + "\xd7\xa9-\xd0\xbc-\xce\xbd.txt"; @@ -59,95 +59,86 @@ int main(int, char** argv) _set_invalid_parameter_handler(noop_invalid_param_handler); #endif - try + std::cout << " -- fopen - existing file" << std::endl; { - std::cout << " -- fopen - existing file" << std::endl; - { - create_test_file(filename); - FILE* f = boost::nowide::fopen(filename.c_str(), "r"); - TEST(f); - char buf[16]; - TEST(std::fgets(buf, 16, f) != 0); - TEST(strcmp(buf, "test\n") == 0); - std::fclose(f); - } - std::cout << " -- remove" << std::endl; - { - create_test_file(filename); - TEST(file_exists(filename)); - TEST(boost::nowide::remove(filename.c_str()) == 0); - TEST(!file_exists(filename)); - } - std::cout << " -- fopen non-existing file" << std::endl; - { - boost::nowide::remove(filename.c_str()); - TEST(!file_exists(filename)); - TEST(boost::nowide::fopen(filename.c_str(), "r") == NULL); - TEST(!file_exists(filename)); - } - std::cout << " -- freopen" << std::endl; - { - create_test_file(filename); - FILE* f = boost::nowide::fopen(filename.c_str(), "r+"); - TEST(f); - std::cout << " -- Can read & write" << std::endl; - { - char buf[32]; - TEST(std::fgets(buf, 32, f) != 0); - TEST(strcmp(buf, "test\n") == 0); - TEST(std::fseek(f, 0, SEEK_END) == 0); - TEST(std::fputs("foobar\n", f) >= 0); - } - // Reopen in read mode - // Note that changing the mode is not possibly on all implementations - // E.g. MSVC disallows NULL completely as the file parameter - FILE* f2 = boost::nowide::freopen(NULL, "r", f); - if(!f2) - f2 = boost::nowide::freopen(filename.c_str(), "r", f); - std::cout << " -- no write possible" << std::endl; - { - TEST(f2 == f); - TEST(std::fputs("not-written\n", f) < 0); - TEST(std::fseek(f, 0, SEEK_SET) == 0); - char buf[32]; - TEST(std::fgets(buf, 32, f) != 0); - TEST(strcmp(buf, "test\n") == 0); - TEST(std::fgets(buf, 32, f) != 0); - TEST(strcmp(buf, "foobar\n") == 0); - } - std::cout << " -- Reopen different file" << std::endl; - const std::string filename2 = filename + ".1.txt"; - TEST(boost::nowide::freopen(filename2.c_str(), "w", f) == f); - { - char buf[32]; - TEST(std::fputs("baz\n", f) >= 0); - std::fclose(f); - f = boost::nowide::fopen(filename2.c_str(), "r"); - TEST(f); - TEST(std::fgets(buf, 32, f) != 0); - TEST(strcmp(buf, "baz\n") == 0); - } - std::fclose(f); - boost::nowide::remove(filename2.c_str()); - } - std::cout << " -- rename" << std::endl; - { - create_test_file(filename); - const std::string filename2 = filename + ".1.txt"; - boost::nowide::remove(filename2.c_str()); - TEST(file_exists(filename)); - TEST(!file_exists(filename2)); - TEST(boost::nowide::rename(filename.c_str(), filename2.c_str()) == 0); - TEST(!file_exists(filename)); - TEST(file_exists(filename2)); - TEST(boost::nowide::remove(filename.c_str()) < 0); - TEST(boost::nowide::remove(filename2.c_str()) == 0); - } - } catch(const std::exception& e) - { - std::cerr << "Failed " << e.what() << std::endl; - return 1; + create_test_file(filename); + FILE* f = boost::nowide::fopen(filename.c_str(), "r"); + TEST(f); + char buf[16]; + TEST(std::fgets(buf, 16, f) != 0); + TEST(strcmp(buf, "test\n") == 0); + std::fclose(f); + } + std::cout << " -- remove" << std::endl; + { + create_test_file(filename); + TEST(file_exists(filename)); + TEST(boost::nowide::remove(filename.c_str()) == 0); + TEST(!file_exists(filename)); + } + std::cout << " -- fopen non-existing file" << std::endl; + { + boost::nowide::remove(filename.c_str()); + TEST(!file_exists(filename)); + TEST(boost::nowide::fopen(filename.c_str(), "r") == NULL); + TEST(!file_exists(filename)); + } + std::cout << " -- freopen" << std::endl; + { + create_test_file(filename); + FILE* f = boost::nowide::fopen(filename.c_str(), "r+"); + TEST(f); + std::cout << " -- Can read & write" << std::endl; + { + char buf[32]; + TEST(std::fgets(buf, 32, f) != 0); + TEST(strcmp(buf, "test\n") == 0); + TEST(std::fseek(f, 0, SEEK_END) == 0); + TEST(std::fputs("foobar\n", f) >= 0); + } + // Reopen in read mode + // Note that changing the mode is not possibly on all implementations + // E.g. MSVC disallows NULL completely as the file parameter + FILE* f2 = boost::nowide::freopen(NULL, "r", f); + if(!f2) + f2 = boost::nowide::freopen(filename.c_str(), "r", f); + std::cout << " -- no write possible" << std::endl; + { + TEST(f2 == f); + TEST(std::fputs("not-written\n", f) < 0); + TEST(std::fseek(f, 0, SEEK_SET) == 0); + char buf[32]; + TEST(std::fgets(buf, 32, f) != 0); + TEST(strcmp(buf, "test\n") == 0); + TEST(std::fgets(buf, 32, f) != 0); + TEST(strcmp(buf, "foobar\n") == 0); + } + std::cout << " -- Reopen different file" << std::endl; + const std::string filename2 = filename + ".1.txt"; + TEST(boost::nowide::freopen(filename2.c_str(), "w", f) == f); + { + char buf[32]; + TEST(std::fputs("baz\n", f) >= 0); + std::fclose(f); + f = boost::nowide::fopen(filename2.c_str(), "r"); + TEST(f); + TEST(std::fgets(buf, 32, f) != 0); + TEST(strcmp(buf, "baz\n") == 0); + } + std::fclose(f); + boost::nowide::remove(filename2.c_str()); + } + std::cout << " -- rename" << std::endl; + { + create_test_file(filename); + const std::string filename2 = filename + ".1.txt"; + boost::nowide::remove(filename2.c_str()); + TEST(file_exists(filename)); + TEST(!file_exists(filename2)); + TEST(boost::nowide::rename(filename.c_str(), filename2.c_str()) == 0); + TEST(!file_exists(filename)); + TEST(file_exists(filename2)); + TEST(boost::nowide::remove(filename.c_str()) < 0); + TEST(boost::nowide::remove(filename2.c_str()) == 0); } - - return 0; } diff --git a/test/test_system.cpp b/test/test_system.cpp index 8156424..3a6f645 100644 --- a/test/test_system.cpp +++ b/test/test_system.cpp @@ -9,9 +9,9 @@ #define _CRT_SECURE_NO_WARNINGS #endif -#include "test.hpp" -#include #include + +#include #include #include #include @@ -20,6 +20,8 @@ #include #include +#include "test.hpp" + bool is_ascii(const std::string& s) { for(std::string::const_iterator it = s.begin(); it != s.end(); ++it) @@ -66,9 +68,7 @@ void compare_string_arrays(char** main_val, char** utf8_val, bool sort) for(size_t i = 0; i < vec_main.size(); ++i) { // Skip strings with non-ascii chars - if(!is_ascii(vec_main[i])) - continue; - if(vec_main[i] != vec_utf8[i]) + if(is_ascii(vec_main[i]) && vec_main[i] != vec_utf8[i]) TEST_EQ(vec_main[i], replace_non_ascii(vec_utf8[i])); } } @@ -89,9 +89,7 @@ void compare_getenv(char** env) { TEST(bnw_value); // Compare only if ascii - if(!is_ascii(std_value)) - continue; - if(std::string(std_value) != std::string(bnw_value)) + if(is_ascii(std_value) && std::string(std_value) != std::string(bnw_value)) TEST_EQ(std_value, replace_non_ascii(bnw_value)); } else TEST(!bnw_value); @@ -153,37 +151,28 @@ void run_parent(const char* exe_path) #endif } -int main(int argc, char** argv, char** env) +void test_main(int argc, char** argv, char** env) { - try + const int old_argc = argc; + char** old_argv = argv; + char** old_env = env; { - const int old_argc = argc; - char** old_argv = argv; - char** old_env = env; - { - boost::nowide::args _(argc, argv, env); - TEST(argc == old_argc); - std::cout << "Checking arguments" << std::endl; - compare_string_arrays(old_argv, argv, false); - std::cout << "Checking env" << std::endl; - compare_string_arrays(old_env, env, true); - compare_getenv(env); - } - // When `args` is destructed the old values must be restored + boost::nowide::args _(argc, argv, env); TEST(argc == old_argc); - TEST(argv == old_argv); - TEST(env == old_env); - - boost::nowide::args a(argc, argv, env); - if(argc == 1) - run_parent(argv[0]); - else - run_child(argc, argv, env); - } catch(const std::exception& e) - { - std::cerr << "Failed " << e.what() << std::endl; - return 1; + std::cout << "Checking arguments" << std::endl; + compare_string_arrays(old_argv, argv, false); + std::cout << "Checking env" << std::endl; + compare_string_arrays(old_env, env, true); + compare_getenv(env); } + // When `args` is destructed the old values must be restored + TEST(argc == old_argc); + TEST(argv == old_argv); + TEST(env == old_env); - return 0; + boost::nowide::args a(argc, argv, env); + if(argc == 1) + run_parent(argv[0]); + else + run_child(argc, argv, env); }