diff options
| author | Phil Nash | 2018-01-08 11:13:29 +0000 |
|---|---|---|
| committer | Phil Nash | 2018-01-08 11:13:29 +0000 |
| commit | 161dd4ed2449c7b02ffdfda607ffb0924d916c3c (patch) | |
| tree | 094b03b0135710bf1ef18d4c95afa2d56d4805ba /include | |
| parent | 13ea4225e7c45214b0c6faf20cd65bb680937f4d (diff) | |
| parent | 2c43620d9baed1fdcaa9146af1d3eb90520cbe92 (diff) | |
| download | catch3-161dd4ed2449c7b02ffdfda607ffb0924d916c3c.tar.gz | |
Merge commit '2c43620d9baed1fdcaa9146af1d3eb90520cbe92'
Diffstat (limited to 'include')
| -rw-r--r-- | include/internal/catch_tostring.h | 90 |
1 files changed, 70 insertions, 20 deletions
diff --git a/include/internal/catch_tostring.h b/include/internal/catch_tostring.h index 79e02448..5ca019fc 100644 --- a/include/internal/catch_tostring.h +++ b/include/internal/catch_tostring.h @@ -57,25 +57,38 @@ namespace Catch { static const bool value = decltype(test<std::ostream, const T&>(0))::value; }; + template<typename E> + std::string convertUnknownEnumToString( E e ); + + template<typename T> + typename std::enable_if<!std::is_enum<T>::value, std::string>::type convertUnstreamable( T const& ) { + return Detail::unprintableString; + }; + template<typename T> + typename std::enable_if<std::is_enum<T>::value, std::string>::type convertUnstreamable( T const& value ) { + return convertUnknownEnumToString( value ); + }; + } // namespace Detail + // If we decide for C++14, change these to enable_if_ts - template <typename T> + template <typename T, typename = void> struct StringMaker { template <typename Fake = T> static typename std::enable_if<::Catch::Detail::IsStreamInsertable<Fake>::value, std::string>::type - convert(const Fake& t) { + convert(const Fake& value) { ReusableStringStream rss; - rss << t; + rss << value; return rss.str(); } template <typename Fake = T> static typename std::enable_if<!::Catch::Detail::IsStreamInsertable<Fake>::value, std::string>::type - convert(const Fake&) { - return Detail::unprintableString; + convert( const Fake& value ) { + return Detail::convertUnstreamable( value ); } }; @@ -88,8 +101,12 @@ namespace Catch { return ::Catch::StringMaker<typename std::remove_cv<typename std::remove_reference<T>::type>::type>::convert(e); } - } // namespace Detail + template<typename E> + std::string convertUnknownEnumToString( E e ) { + return ::Catch::Detail::stringify(static_cast<typename std::underlying_type<E>::type>(e)); + } + } // namespace Detail // Some predefined specializations @@ -233,20 +250,6 @@ namespace Catch { } } - template<typename T, typename Allocator> - struct StringMaker<std::vector<T, Allocator> > { - static std::string convert( std::vector<T,Allocator> const& v ) { - return ::Catch::Detail::rangeToString( v.begin(), v.end() ); - } - }; - - template<typename T> - struct EnumStringMaker { - static std::string convert(const T& t) { - return ::Catch::Detail::stringify(static_cast<typename std::underlying_type<T>::type>(t)); - } - }; - #ifdef __OBJC__ template<> struct StringMaker<NSString*> { @@ -344,6 +347,53 @@ namespace Catch { } #endif // CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER +namespace Catch { + struct not_this_one {}; // Tag type for detecting which begin/ end are being selected + + // Import begin/ end from std here so they are considered alongside the fallback (...) overloads in this namespace + using std::begin; + using std::end; + + not_this_one begin( ... ); + not_this_one end( ... ); + + template <typename T> + struct is_range { + static const bool value = + !std::is_same<decltype(begin(std::declval<T>())), not_this_one>::value && + !std::is_same<decltype(end(std::declval<T>())), not_this_one>::value; + }; + + template<typename Range> + std::string rangeToString( Range const& range ) { + return ::Catch::Detail::rangeToString( begin( range ), end( range ) ); + } + + // Handle vector<bool> specially + template<typename Allocator> + std::string rangeToString( std::vector<bool, Allocator> const& v ) { + ReusableStringStream rss; + rss << "{ "; + bool first = true; + for( bool b : v ) { + if( first ) + first = false; + else + rss << ", "; + rss << ::Catch::Detail::stringify( b ); + } + rss << " }"; + return rss.str(); + } + + template<typename R> + struct StringMaker<R, typename std::enable_if<is_range<R>::value>::type> { + static std::string convert( R const& range ) { + return rangeToString( range ); + } + }; + +} // namespace Catch // Separate std::chrono::duration specialization #if defined(CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER) |