From 352853ed7e2592f224fc9e9f01e1314660e906e1 Mon Sep 17 00:00:00 2001 From: Tomas Zeman Date: Thu, 1 Mar 2018 18:41:17 +0100 Subject: [PATCH 1/2] Introduce conditional wchar_t (and std::wstring) support The support is turned on by default but the user might need to be able to turn it off which is now possible by defining CATCH_CONFIG_NO_WCHAR. --- docs/configuration.md | 4 ++++ include/internal/catch_compiler_capabilities.h | 4 ++++ include/internal/catch_default_main.hpp | 2 +- include/internal/catch_session.cpp | 2 +- include/internal/catch_session.h | 2 +- include/internal/catch_tostring.cpp | 4 ++++ include/internal/catch_tostring.h | 5 +++++ projects/SelfTest/UsageTests/Misc.tests.cpp | 2 ++ 8 files changed, 22 insertions(+), 3 deletions(-) diff --git a/docs/configuration.md b/docs/configuration.md index c2fcc55e..3f963eec 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -120,6 +120,7 @@ by using `_NO_` in the macro, e.g. `CATCH_CONFIG_NO_CPP17_UNCAUGHT_EXCEPTIONS`. CATCH_CONFIG_WINDOWS_CRTDBG // Enable leak checking using Windows's CRT Debug Heap CATCH_CONFIG_DISABLE_STRINGIFICATION // Disable stringifying the original expression CATCH_CONFIG_DISABLE // Disables assertions and test case registration + CATCH_CONFIG_WCHAR // Enables use of wchart_t Currently Catch enables `CATCH_CONFIG_WINDOWS_SEH` only when compiled with MSVC, because some versions of MinGW do not have the necessary Win32 API support. @@ -127,6 +128,9 @@ Currently Catch enables `CATCH_CONFIG_WINDOWS_SEH` only when compiled with MSVC, `CATCH_CONFIG_WINDOWS_CRTDBG` is off by default. If enabled, Windows's CRT is used to check for memory leaks, and displays them after the tests finish running. +`CATCH_CONFIG_WCHAR` is on by default, but can be disabled. Currently +it is only used in support for DJGPP cross-compiler. + These toggles can be disabled by using `_NO_` form of the toggle, e.g. `CATCH_CONFIG_NO_WINDOWS_SEH`. ### `CATCH_CONFIG_FAST_COMPILE` diff --git a/include/internal/catch_compiler_capabilities.h b/include/internal/catch_compiler_capabilities.h index 50bb9e6e..b1acf99d 100644 --- a/include/internal/catch_compiler_capabilities.h +++ b/include/internal/catch_compiler_capabilities.h @@ -130,6 +130,10 @@ #if defined(CATCH_INTERNAL_CONFIG_POSIX_SIGNALS) && !defined(CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_POSIX_SIGNALS) # define CATCH_CONFIG_POSIX_SIGNALS #endif +// This is set by default, because we assume that compilers with no wchar_t support are just rare exceptions. +#if !defined(CATCH_INTERNAL_CONFIG_NO_WCHAR) && !defined(CATCH_CONFIG_NO_WCHAR) && !defined(CATCH_CONFIG_WCHAR) +# define CATCH_CONFIG_WCHAR +#endif #if defined(CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) && !defined(CATCH_CONFIG_NO_CPP17_UNCAUGHT_EXCEPTIONS) && !defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) # define CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS diff --git a/include/internal/catch_default_main.hpp b/include/internal/catch_default_main.hpp index 4372e9cc..17ad090a 100644 --- a/include/internal/catch_default_main.hpp +++ b/include/internal/catch_default_main.hpp @@ -12,7 +12,7 @@ #ifndef __OBJC__ -#if defined(WIN32) && defined(_UNICODE) && !defined(DO_NOT_USE_WMAIN) +#if defined(CATCH_CONFIG_WCHAR) && defined(WIN32) && defined(_UNICODE) && !defined(DO_NOT_USE_WMAIN) // Standard C/C++ Win32 Unicode wmain entry point extern "C" int wmain (int argc, wchar_t * argv[], wchar_t * []) { #else diff --git a/include/internal/catch_session.cpp b/include/internal/catch_session.cpp index 9ccb16f8..0039fcb5 100644 --- a/include/internal/catch_session.cpp +++ b/include/internal/catch_session.cpp @@ -202,7 +202,7 @@ namespace Catch { return returnCode; } -#if defined(WIN32) && defined(UNICODE) +#if defined(CATCH_CONFIG_WCHAR) && defined(WIN32) && defined(UNICODE) int Session::run( int argc, wchar_t* const argv[] ) { char **utf8Argv = new char *[ argc ]; diff --git a/include/internal/catch_session.h b/include/internal/catch_session.h index b814aa6a..39f7a0dd 100644 --- a/include/internal/catch_session.h +++ b/include/internal/catch_session.h @@ -30,7 +30,7 @@ namespace Catch { void useConfigData( ConfigData const& configData ); int run( int argc, char* argv[] ); - #if defined(WIN32) && defined(UNICODE) + #if defined(CATCH_CONFIG_WCHAR) && defined(WIN32) && defined(UNICODE) int run( int argc, wchar_t* const argv[] ); #endif int run(); diff --git a/include/internal/catch_tostring.cpp b/include/internal/catch_tostring.cpp index a9f7735e..0d0158fa 100644 --- a/include/internal/catch_tostring.cpp +++ b/include/internal/catch_tostring.cpp @@ -116,6 +116,7 @@ std::string StringMaker::convert(const std::string& str) { return s; } +#ifdef CATCH_CONFIG_WCHAR std::string StringMaker::convert(const std::wstring& wstr) { std::string s; s.reserve(wstr.size()); @@ -124,6 +125,7 @@ std::string StringMaker::convert(const std::wstring& wstr) { } return ::Catch::Detail::stringify(s); } +#endif std::string StringMaker::convert(char const* str) { if (str) { @@ -139,6 +141,7 @@ std::string StringMaker::convert(char* str) { return{ "{null string}" }; } } +#ifdef CATCH_CONFIG_WCHAR std::string StringMaker::convert(wchar_t const * str) { if (str) { return ::Catch::Detail::stringify(std::wstring{ str }); @@ -153,6 +156,7 @@ std::string StringMaker::convert(wchar_t * str) { return{ "{null string}" }; } } +#endif std::string StringMaker::convert(int value) { diff --git a/include/internal/catch_tostring.h b/include/internal/catch_tostring.h index bb9cb0be..26756fa9 100644 --- a/include/internal/catch_tostring.h +++ b/include/internal/catch_tostring.h @@ -13,6 +13,7 @@ #include #include #include +#include "catch_compiler_capabilities.h" #include "catch_stream.h" #ifdef __OBJC__ @@ -119,10 +120,12 @@ namespace Catch { struct StringMaker { static std::string convert(const std::string& str); }; +#ifdef CATCH_CONFIG_WCHAR template<> struct StringMaker { static std::string convert(const std::wstring& wstr); }; +#endif template<> struct StringMaker { @@ -132,6 +135,7 @@ namespace Catch { struct StringMaker { static std::string convert(char * str); }; +#ifdef CATCH_CONFIG_WCHAR template<> struct StringMaker { static std::string convert(wchar_t const * str); @@ -140,6 +144,7 @@ namespace Catch { struct StringMaker { static std::string convert(wchar_t * str); }; +#endif template struct StringMaker { diff --git a/projects/SelfTest/UsageTests/Misc.tests.cpp b/projects/SelfTest/UsageTests/Misc.tests.cpp index 683b8391..fa158705 100644 --- a/projects/SelfTest/UsageTests/Misc.tests.cpp +++ b/projects/SelfTest/UsageTests/Misc.tests.cpp @@ -290,6 +290,7 @@ TEST_CASE( "Tabs and newlines show in output", "[.][whitespace][failing]" ) { } +#ifdef CATCH_CONFIG_WCHAR TEST_CASE( "toString on const wchar_t const pointer returns the string contents", "[toString]" ) { const wchar_t * const s = L"wide load"; std::string result = ::Catch::Detail::stringify( s ); @@ -313,6 +314,7 @@ TEST_CASE( "toString on wchar_t returns the string contents", "[toString]" ) { std::string result = ::Catch::Detail::stringify( s ); CHECK( result == "\"wide load\"" ); } +#endif TEST_CASE( "long long" ) { long long l = std::numeric_limits::max(); From 95c849f613a79cb3c7f59aa0589304513688aba1 Mon Sep 17 00:00:00 2001 From: Tomas Zeman Date: Fri, 2 Mar 2018 14:39:01 +0100 Subject: [PATCH 2/2] Introduce support for DJGPP cross compiler DJGPP cross compiler is targeting DOS which does not support POSIX signals. Probably for the same reason (targeting DOS) this compiler does not support wide characters. --- .../internal/catch_compiler_capabilities.h | 9 +++++- include/internal/catch_console_colour.cpp | 7 ++++- .../Baselines/compact.sw.approved.txt | 12 ++++---- .../Baselines/console.sw.approved.txt | 12 ++++---- .../SelfTest/Baselines/xml.sw.approved.txt | 12 ++++---- .../SelfTest/UsageTests/Matchers.tests.cpp | 30 +++++++++++++++---- 6 files changed, 56 insertions(+), 26 deletions(-) diff --git a/include/internal/catch_compiler_capabilities.h b/include/internal/catch_compiler_capabilities.h index b1acf99d..2bbba4f0 100644 --- a/include/internal/catch_compiler_capabilities.h +++ b/include/internal/catch_compiler_capabilities.h @@ -67,7 +67,7 @@ //////////////////////////////////////////////////////////////////////////////// // We know some environments not to support full POSIX signals -#if defined(__CYGWIN__) || defined(__QNX__) || defined(__EMSCRIPTEN__) +#if defined(__CYGWIN__) || defined(__QNX__) || defined(__EMSCRIPTEN__) || defined(__DJGPP__) # if !defined(CATCH_CONFIG_POSIX_SIGNALS) # define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS @@ -111,6 +111,13 @@ //////////////////////////////////////////////////////////////////////////////// +// DJGPP +#ifdef __DJGPP__ +# define CATCH_INTERNAL_CONFIG_NO_WCHAR +#endif // __DJGPP__ + +//////////////////////////////////////////////////////////////////////////////// + // Use of __COUNTER__ is suppressed during code analysis in // CLion/AppCode 2017.2.x and former, because __COUNTER__ is not properly // handled by it. diff --git a/include/internal/catch_console_colour.cpp b/include/internal/catch_console_colour.cpp index f692b5c5..5fb1d07f 100644 --- a/include/internal/catch_console_colour.cpp +++ b/include/internal/catch_console_colour.cpp @@ -169,7 +169,12 @@ namespace { #ifdef CATCH_PLATFORM_MAC !isDebuggerActive() && #endif - isatty(STDOUT_FILENO); +#if !(defined(__DJGPP__) && defined(__STRICT_ANSI__)) + isatty(STDOUT_FILENO) +#else + false +#endif + ; } IColourImpl* platformColourInstance() { ErrnoGuard guard; diff --git a/projects/SelfTest/Baselines/compact.sw.approved.txt b/projects/SelfTest/Baselines/compact.sw.approved.txt index a4f85a68..4a1aeb78 100644 --- a/projects/SelfTest/Baselines/compact.sw.approved.txt +++ b/projects/SelfTest/Baselines/compact.sw.approved.txt @@ -236,9 +236,9 @@ Matchers.tests.cpp:: passed: 0., !WithinAbs(1., 0.99) for: 0.0 not Matchers.tests.cpp:: passed: 0., !WithinAbs(1., 0.99) for: 0.0 not is within 0.99 of 1.0 Matchers.tests.cpp:: passed: NAN, !WithinAbs(NAN, 0) for: nanf not is within 0.0 of nan Matchers.tests.cpp:: passed: 1., WithinULP(1., 0) for: 1.0 is within 0 ULPs of 1.0 -Matchers.tests.cpp:: passed: std::nextafter(1., 2.), WithinULP(1., 1) for: 1.0 is within 1 ULPs of 1.0 -Matchers.tests.cpp:: passed: std::nextafter(1., 0.), WithinULP(1., 1) for: 1.0 is within 1 ULPs of 1.0 -Matchers.tests.cpp:: passed: std::nextafter(1., 2.), !WithinULP(1., 0) for: 1.0 not is within 0 ULPs of 1.0 +Matchers.tests.cpp:: passed: nextafter(1., 2.), WithinULP(1., 1) for: 1.0 is within 1 ULPs of 1.0 +Matchers.tests.cpp:: passed: nextafter(1., 0.), WithinULP(1., 1) for: 1.0 is within 1 ULPs of 1.0 +Matchers.tests.cpp:: passed: nextafter(1., 2.), !WithinULP(1., 0) for: 1.0 not is within 0 ULPs of 1.0 Matchers.tests.cpp:: passed: 1., WithinULP(1., 0) for: 1.0 is within 0 ULPs of 1.0 Matchers.tests.cpp:: passed: -0., WithinULP(0., 0) for: -0.0 is within 0 ULPs of 0.0 Matchers.tests.cpp:: passed: NAN, !WithinULP(NAN, 123) for: nanf not is within 123 ULPs of nanf @@ -256,9 +256,9 @@ Matchers.tests.cpp:: passed: 0.f, !WithinAbs(1.f, 0.99f) for: 0.0f Matchers.tests.cpp:: passed: 0.f, WithinAbs(-0.f, 0) for: 0.0f is within 0.0 of -0.0 Matchers.tests.cpp:: passed: NAN, !WithinAbs(NAN, 0) for: nanf not is within 0.0 of nan Matchers.tests.cpp:: passed: 1.f, WithinULP(1.f, 0) for: 1.0f is within 0 ULPs of 1.0f -Matchers.tests.cpp:: passed: std::nextafter(1.f, 2.f), WithinULP(1.f, 1) for: 1.0f is within 1 ULPs of 1.0f -Matchers.tests.cpp:: passed: std::nextafter(1.f, 0.f), WithinULP(1.f, 1) for: 1.0f is within 1 ULPs of 1.0f -Matchers.tests.cpp:: passed: std::nextafter(1.f, 2.f), !WithinULP(1.f, 0) for: 1.0f not is within 0 ULPs of 1.0f +Matchers.tests.cpp:: passed: nextafter(1.f, 2.f), WithinULP(1.f, 1) for: 1.0f is within 1 ULPs of 1.0f +Matchers.tests.cpp:: passed: nextafter(1.f, 0.f), WithinULP(1.f, 1) for: 1.0f is within 1 ULPs of 1.0f +Matchers.tests.cpp:: passed: nextafter(1.f, 2.f), !WithinULP(1.f, 0) for: 1.0f not is within 0 ULPs of 1.0f Matchers.tests.cpp:: passed: 1.f, WithinULP(1.f, 0) for: 1.0f is within 0 ULPs of 1.0f Matchers.tests.cpp:: passed: -0.f, WithinULP(0.f, 0) for: -0.0f is within 0 ULPs of 0.0f Matchers.tests.cpp:: passed: NAN, !WithinULP(NAN, 123) for: nanf not is within 123 ULPs of nanf diff --git a/projects/SelfTest/Baselines/console.sw.approved.txt b/projects/SelfTest/Baselines/console.sw.approved.txt index 9c738463..70bff4a8 100644 --- a/projects/SelfTest/Baselines/console.sw.approved.txt +++ b/projects/SelfTest/Baselines/console.sw.approved.txt @@ -1873,19 +1873,19 @@ with expansion: Matchers.tests.cpp:: PASSED: - REQUIRE_THAT( std::nextafter(1., 2.), WithinULP(1., 1) ) + REQUIRE_THAT( nextafter(1., 2.), WithinULP(1., 1) ) with expansion: 1.0 is within 1 ULPs of 1.0 Matchers.tests.cpp:: PASSED: - REQUIRE_THAT( std::nextafter(1., 0.), WithinULP(1., 1) ) + REQUIRE_THAT( nextafter(1., 0.), WithinULP(1., 1) ) with expansion: 1.0 is within 1 ULPs of 1.0 Matchers.tests.cpp:: PASSED: - REQUIRE_THAT( std::nextafter(1., 2.), !WithinULP(1., 0) ) + REQUIRE_THAT( nextafter(1., 2.), !WithinULP(1., 0) ) with expansion: 1.0 not is within 0 ULPs of 1.0 @@ -2013,19 +2013,19 @@ with expansion: Matchers.tests.cpp:: PASSED: - REQUIRE_THAT( std::nextafter(1.f, 2.f), WithinULP(1.f, 1) ) + REQUIRE_THAT( nextafter(1.f, 2.f), WithinULP(1.f, 1) ) with expansion: 1.0f is within 1 ULPs of 1.0f Matchers.tests.cpp:: PASSED: - REQUIRE_THAT( std::nextafter(1.f, 0.f), WithinULP(1.f, 1) ) + REQUIRE_THAT( nextafter(1.f, 0.f), WithinULP(1.f, 1) ) with expansion: 1.0f is within 1 ULPs of 1.0f Matchers.tests.cpp:: PASSED: - REQUIRE_THAT( std::nextafter(1.f, 2.f), !WithinULP(1.f, 0) ) + REQUIRE_THAT( nextafter(1.f, 2.f), !WithinULP(1.f, 0) ) with expansion: 1.0f not is within 0 ULPs of 1.0f diff --git a/projects/SelfTest/Baselines/xml.sw.approved.txt b/projects/SelfTest/Baselines/xml.sw.approved.txt index 70868b59..227dee93 100644 --- a/projects/SelfTest/Baselines/xml.sw.approved.txt +++ b/projects/SelfTest/Baselines/xml.sw.approved.txt @@ -2121,7 +2121,7 @@ - std::nextafter(1., 2.), WithinULP(1., 1) + nextafter(1., 2.), WithinULP(1., 1) 1.0 is within 1 ULPs of 1.0 @@ -2129,7 +2129,7 @@ - std::nextafter(1., 0.), WithinULP(1., 1) + nextafter(1., 0.), WithinULP(1., 1) 1.0 is within 1 ULPs of 1.0 @@ -2137,7 +2137,7 @@ - std::nextafter(1., 2.), !WithinULP(1., 0) + nextafter(1., 2.), !WithinULP(1., 0) 1.0 not is within 0 ULPs of 1.0 @@ -2296,7 +2296,7 @@ - std::nextafter(1.f, 2.f), WithinULP(1.f, 1) + nextafter(1.f, 2.f), WithinULP(1.f, 1) 1.0f is within 1 ULPs of 1.0f @@ -2304,7 +2304,7 @@ - std::nextafter(1.f, 0.f), WithinULP(1.f, 1) + nextafter(1.f, 0.f), WithinULP(1.f, 1) 1.0f is within 1 ULPs of 1.0f @@ -2312,7 +2312,7 @@ - std::nextafter(1.f, 2.f), !WithinULP(1.f, 0) + nextafter(1.f, 2.f), !WithinULP(1.f, 0) 1.0f not is within 0 ULPs of 1.0f diff --git a/projects/SelfTest/UsageTests/Matchers.tests.cpp b/projects/SelfTest/UsageTests/Matchers.tests.cpp index 3c20caa1..05056b43 100644 --- a/projects/SelfTest/UsageTests/Matchers.tests.cpp +++ b/projects/SelfTest/UsageTests/Matchers.tests.cpp @@ -77,6 +77,20 @@ namespace { namespace MatchersTests { using namespace Catch::Matchers; +#ifdef __DJGPP__ + float nextafter(float from, float to) + { + return ::nextafterf(from, to); + } + + double nextafter(double from, double to) + { + return ::nextafter(from, to); + } +#else + using std::nextafter; +#endif + TEST_CASE("String matchers", "[matchers]") { REQUIRE_THAT(testStringForMatching(), Contains("string")); REQUIRE_THAT(testStringForMatching(), Contains("string", Catch::CaseSensitive::No)); @@ -130,12 +144,16 @@ namespace { namespace MatchersTests { (defined(_GLIBCXX_RELEASE) && \ _GLIBCXX_RELEASE > 4)))) +// DJGPP meets the above condition but does not work properly anyway +#ifndef __DJGPP__ REQUIRE_THAT(testStringForMatching(), Matches("this string contains 'abc' as a substring")); REQUIRE_THAT(testStringForMatching(), Matches("this string CONTAINS 'abc' as a substring", Catch::CaseSensitive::No)); REQUIRE_THAT(testStringForMatching(), Matches("^this string contains 'abc' as a substring$")); REQUIRE_THAT(testStringForMatching(), Matches("^.* 'abc' .*$")); REQUIRE_THAT(testStringForMatching(), Matches("^.* 'ABC' .*$", Catch::CaseSensitive::No)); +#endif + #endif REQUIRE_THAT(testStringForMatching2(), !Matches("this string contains 'abc' as a substring")); @@ -307,9 +325,9 @@ namespace { namespace MatchersTests { SECTION("ULPs") { REQUIRE_THAT(1.f, WithinULP(1.f, 0)); - REQUIRE_THAT(std::nextafter(1.f, 2.f), WithinULP(1.f, 1)); - REQUIRE_THAT(std::nextafter(1.f, 0.f), WithinULP(1.f, 1)); - REQUIRE_THAT(std::nextafter(1.f, 2.f), !WithinULP(1.f, 0)); + REQUIRE_THAT(nextafter(1.f, 2.f), WithinULP(1.f, 1)); + REQUIRE_THAT(nextafter(1.f, 0.f), WithinULP(1.f, 1)); + REQUIRE_THAT(nextafter(1.f, 2.f), !WithinULP(1.f, 0)); REQUIRE_THAT(1.f, WithinULP(1.f, 0)); REQUIRE_THAT(-0.f, WithinULP(0.f, 0)); @@ -344,9 +362,9 @@ namespace { namespace MatchersTests { SECTION("ULPs") { REQUIRE_THAT(1., WithinULP(1., 0)); - REQUIRE_THAT(std::nextafter(1., 2.), WithinULP(1., 1)); - REQUIRE_THAT(std::nextafter(1., 0.), WithinULP(1., 1)); - REQUIRE_THAT(std::nextafter(1., 2.), !WithinULP(1., 0)); + REQUIRE_THAT(nextafter(1., 2.), WithinULP(1., 1)); + REQUIRE_THAT(nextafter(1., 0.), WithinULP(1., 1)); + REQUIRE_THAT(nextafter(1., 2.), !WithinULP(1., 0)); REQUIRE_THAT(1., WithinULP(1., 0)); REQUIRE_THAT(-0., WithinULP(0., 0));