diff --git a/.azure-pipelines.yml b/.azure-pipelines.yml index bf51f7d..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: @@ -126,7 +125,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..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: @@ -77,8 +80,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/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/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/ ; 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 9bfb6df..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 @@ -51,6 +52,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 +79,31 @@ 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 + +#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 07f3f23..3a6f645 100644 --- a/test/test_system.cpp +++ b/test/test_system.cpp @@ -5,81 +5,174 @@ // 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 +#include -int main(int argc, char** argv, char** env) +#include "test.hpp" + +bool is_ascii(const std::string& s) { - try + for(std::string::const_iterator it = s.begin(); it != s.end(); ++it) { - std::string example = "\xd7\xa9-\xd0\xbc-\xce\xbd"; - boost::nowide::args a(argc, argv, env); - if(argc == 2 && argv[1][0] != '-') + 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]) && 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(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 + TEST(bnw_value); + // Compare only if ascii + 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); + } +} + +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(boost::nowide::getenv("BOOST_NOWIDE_EMPTY") == std::string()); + TEST(boost::nowide::getenv("BOOST_NOWIDE_EMPTY")); + TEST_EQ(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 - } - } catch(const std::exception& e) + // This must be contained in env + std::string sample = "BOOST_NOWIDE_TEST=" + example; + bool found = false; + for(char** e = env; *e != 0; e++) { - std::cerr << "Failed " << e.what() << std::endl; - return 1; + if(*e == sample) + found = true; } + TEST(found); - return 0; + 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 +} + +void test_main(int argc, char** argv, char** 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 + 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); }