Read-only mirrors. Development, issues and pull requests are on GitHub.

summaryrefslogtreecommitdiffhomepage
path: root/include
diff options
context:
space:
mode:
authorPhil Nash2018-01-08 11:13:29 +0000
committerPhil Nash2018-01-08 11:13:29 +0000
commit161dd4ed2449c7b02ffdfda607ffb0924d916c3c (patch)
tree094b03b0135710bf1ef18d4c95afa2d56d4805ba /include
parent13ea4225e7c45214b0c6faf20cd65bb680937f4d (diff)
parent2c43620d9baed1fdcaa9146af1d3eb90520cbe92 (diff)
downloadcatch3-161dd4ed2449c7b02ffdfda607ffb0924d916c3c.tar.gz
Merge commit '2c43620d9baed1fdcaa9146af1d3eb90520cbe92'
Diffstat (limited to 'include')
-rw-r--r--include/internal/catch_tostring.h90
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)