diff --git a/docs/configuration.md b/docs/configuration.md index a73e331a..ee17b819 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -127,6 +127,7 @@ Catch's selection, by defining either `CATCH_CONFIG_CPP11_TO_STRING` or ## C++17 toggles CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS // Use std::uncaught_exceptions instead of std::uncaught_exception + CATCH_CONFIG_CPP17_STRING_VIEW // Provide StringMaker specialization for std::string_view Catch contains basic compiler/standard detection and attempts to use some C++17 features whenever appropriate. This automatic detection diff --git a/include/internal/catch_compiler_capabilities.h b/include/internal/catch_compiler_capabilities.h index 0c20e6ea..1ae9635b 100644 --- a/include/internal/catch_compiler_capabilities.h +++ b/include/internal/catch_compiler_capabilities.h @@ -29,11 +29,11 @@ #ifdef __cplusplus -# if __cplusplus >= 201402L +# if (__cplusplus >= 201402L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201402L) # define CATCH_CPP14_OR_GREATER # endif -# if __cplusplus >= 201703L +# if (__cplusplus >= 201703L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) # define CATCH_CPP17_OR_GREATER # endif @@ -154,6 +154,16 @@ #define CATCH_INTERNAL_CONFIG_COUNTER #endif +//////////////////////////////////////////////////////////////////////////////// +// Check if string_view is available and usable +// The check is split apart to work around v140 (VS2015) preprocessor issue... +#if defined(__has_include) +#if __has_include() && defined(CATCH_CPP17_OR_GREATER) +# define CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW +#endif +#endif + + #if defined(CATCH_INTERNAL_CONFIG_COUNTER) && !defined(CATCH_CONFIG_NO_COUNTER) && !defined(CATCH_CONFIG_COUNTER) # define CATCH_CONFIG_COUNTER #endif @@ -177,6 +187,10 @@ # define CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS #endif +#if defined(CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_NO_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_CPP17_STRING_VIEW) +# define CATCH_CONFIG_CPP17_STRING_VIEW +#endif + #if defined(CATCH_CONFIG_EXPERIMENTAL_REDIRECT) # define CATCH_INTERNAL_CONFIG_NEW_CAPTURE #endif diff --git a/include/internal/catch_tostring.cpp b/include/internal/catch_tostring.cpp index 61b29771..4e0c027d 100644 --- a/include/internal/catch_tostring.cpp +++ b/include/internal/catch_tostring.cpp @@ -116,14 +116,9 @@ 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()); - for (auto c : wstr) { - s += (c <= 0xff) ? static_cast(c) : '?'; - } - return ::Catch::Detail::stringify(s); +#ifdef CATCH_CONFIG_CPP17_STRING_VIEW +std::string StringMaker::convert(std::string_view str) { + return ::Catch::Detail::stringify(std::string{ str }); } #endif @@ -141,7 +136,23 @@ std::string StringMaker::convert(char* str) { return{ "{null string}" }; } } + #ifdef CATCH_CONFIG_WCHAR +std::string StringMaker::convert(const std::wstring& wstr) { + std::string s; + s.reserve(wstr.size()); + for (auto c : wstr) { + s += (c <= 0xff) ? static_cast(c) : '?'; + } + return ::Catch::Detail::stringify(s); +} + +# ifdef CATCH_CONFIG_CPP17_STRING_VIEW +std::string StringMaker::convert(std::wstring_view str) { + return StringMaker::convert(std::wstring(str)); +} +# endif + std::string StringMaker::convert(wchar_t const * str) { if (str) { return ::Catch::Detail::stringify(std::wstring{ str }); diff --git a/include/internal/catch_tostring.h b/include/internal/catch_tostring.h index 2aa06f44..5f5610cb 100644 --- a/include/internal/catch_tostring.h +++ b/include/internal/catch_tostring.h @@ -16,6 +16,10 @@ #include "catch_compiler_capabilities.h" #include "catch_stream.h" +#ifdef CATCH_CONFIG_CPP17_STRING_VIEW +#include +#endif + #ifdef __OBJC__ #include "catch_objc_arc.hpp" #endif @@ -152,10 +156,11 @@ namespace Catch { struct StringMaker { static std::string convert(const std::string& str); }; -#ifdef CATCH_CONFIG_WCHAR + +#ifdef CATCH_CONFIG_CPP17_STRING_VIEW template<> - struct StringMaker { - static std::string convert(const std::wstring& wstr); + struct StringMaker { + static std::string convert(std::string_view str); }; #endif @@ -169,6 +174,18 @@ namespace Catch { }; #ifdef CATCH_CONFIG_WCHAR + template<> + struct StringMaker { + static std::string convert(const std::wstring& wstr); + }; + +# ifdef CATCH_CONFIG_CPP17_STRING_VIEW + template<> + struct StringMaker { + static std::string convert(std::wstring_view str); + }; +# endif + template<> struct StringMaker { static std::string convert(wchar_t const * str); diff --git a/projects/SelfTest/UsageTests/ToStringGeneral.tests.cpp b/projects/SelfTest/UsageTests/ToStringGeneral.tests.cpp index 3f6fa05f..acddf223 100644 --- a/projects/SelfTest/UsageTests/ToStringGeneral.tests.cpp +++ b/projects/SelfTest/UsageTests/ToStringGeneral.tests.cpp @@ -116,6 +116,18 @@ TEST_CASE("Static arrays are convertible to string", "[toString]") { } } +#ifdef CATCH_CONFIG_CPP17_STRING_VIEW + +TEST_CASE("String views are stringified like other strings", "[toString][approvals]") { + std::string_view view{"abc"}; + CHECK(Catch::Detail::stringify(view) == R"("abc")"); + + std::string_view arr[] { view }; + CHECK(Catch::Detail::stringify(arr) == R"({ "abc" })"); +} + +#endif + namespace { struct WhatException : std::exception {