File indexing completed on 2025-01-18 09:54:08
0001
0002
0003
0004
0005
0006
0007
0008 #ifndef CATCH_TOSTRING_HPP_INCLUDED
0009 #define CATCH_TOSTRING_HPP_INCLUDED
0010
0011
0012 #include <vector>
0013 #include <cstddef>
0014 #include <type_traits>
0015 #include <string>
0016
0017 #include <catch2/internal/catch_compiler_capabilities.hpp>
0018 #include <catch2/internal/catch_config_wchar.hpp>
0019 #include <catch2/internal/catch_reusable_string_stream.hpp>
0020 #include <catch2/internal/catch_void_type.hpp>
0021 #include <catch2/interfaces/catch_interfaces_enum_values_registry.hpp>
0022
0023 #ifdef CATCH_CONFIG_CPP17_STRING_VIEW
0024 #include <string_view>
0025 #endif
0026
0027 #ifdef _MSC_VER
0028 #pragma warning(push)
0029 #pragma warning(disable:4180)
0030 #endif
0031
0032
0033 struct Catch_global_namespace_dummy{};
0034 std::ostream& operator<<(std::ostream&, Catch_global_namespace_dummy);
0035
0036 namespace Catch {
0037
0038
0039 using ::operator<<;
0040
0041 namespace Detail {
0042
0043 inline std::size_t catch_strnlen(const char *str, std::size_t n) {
0044 auto ret = std::char_traits<char>::find(str, n, '\0');
0045 if (ret != nullptr) {
0046 return static_cast<std::size_t>(ret - str);
0047 }
0048 return n;
0049 }
0050
0051 constexpr StringRef unprintableString = "{?}"_sr;
0052
0053
0054 std::string convertIntoString( StringRef string, bool escapeInvisibles );
0055
0056
0057
0058 std::string convertIntoString( StringRef string );
0059
0060 std::string rawMemoryToString( const void *object, std::size_t size );
0061
0062 template<typename T>
0063 std::string rawMemoryToString( const T& object ) {
0064 return rawMemoryToString( &object, sizeof(object) );
0065 }
0066
0067 template<typename T>
0068 class IsStreamInsertable {
0069 template<typename Stream, typename U>
0070 static auto test(int)
0071 -> decltype(std::declval<Stream&>() << std::declval<U>(), std::true_type());
0072
0073 template<typename, typename>
0074 static auto test(...)->std::false_type;
0075
0076 public:
0077 static const bool value = decltype(test<std::ostream, const T&>(0))::value;
0078 };
0079
0080 template<typename E>
0081 std::string convertUnknownEnumToString( E e );
0082
0083 template<typename T>
0084 std::enable_if_t<
0085 !std::is_enum<T>::value && !std::is_base_of<std::exception, T>::value,
0086 std::string> convertUnstreamable( T const& ) {
0087 return std::string(Detail::unprintableString);
0088 }
0089 template<typename T>
0090 std::enable_if_t<
0091 !std::is_enum<T>::value && std::is_base_of<std::exception, T>::value,
0092 std::string> convertUnstreamable(T const& ex) {
0093 return ex.what();
0094 }
0095
0096
0097 template<typename T>
0098 std::enable_if_t<
0099 std::is_enum<T>::value,
0100 std::string> convertUnstreamable( T const& value ) {
0101 return convertUnknownEnumToString( value );
0102 }
0103
0104 #if defined(_MANAGED)
0105
0106 template<typename T>
0107 std::string clrReferenceToString( T^ ref ) {
0108 if (ref == nullptr)
0109 return std::string("null");
0110 auto bytes = System::Text::Encoding::UTF8->GetBytes(ref->ToString());
0111 cli::pin_ptr<System::Byte> p = &bytes[0];
0112 return std::string(reinterpret_cast<char const *>(p), bytes->Length);
0113 }
0114 #endif
0115
0116 }
0117
0118
0119 template <typename T, typename = void>
0120 struct StringMaker {
0121 template <typename Fake = T>
0122 static
0123 std::enable_if_t<::Catch::Detail::IsStreamInsertable<Fake>::value, std::string>
0124 convert(const Fake& value) {
0125 ReusableStringStream rss;
0126
0127
0128 rss.operator<<(value);
0129 return rss.str();
0130 }
0131
0132 template <typename Fake = T>
0133 static
0134 std::enable_if_t<!::Catch::Detail::IsStreamInsertable<Fake>::value, std::string>
0135 convert( const Fake& value ) {
0136 #if !defined(CATCH_CONFIG_FALLBACK_STRINGIFIER)
0137 return Detail::convertUnstreamable(value);
0138 #else
0139 return CATCH_CONFIG_FALLBACK_STRINGIFIER(value);
0140 #endif
0141 }
0142 };
0143
0144 namespace Detail {
0145
0146
0147
0148 template <typename T>
0149 std::string stringify(const T& e) {
0150 return ::Catch::StringMaker<std::remove_cv_t<std::remove_reference_t<T>>>::convert(e);
0151 }
0152
0153 template<typename E>
0154 std::string convertUnknownEnumToString( E e ) {
0155 return ::Catch::Detail::stringify(static_cast<std::underlying_type_t<E>>(e));
0156 }
0157
0158 #if defined(_MANAGED)
0159 template <typename T>
0160 std::string stringify( T^ e ) {
0161 return ::Catch::StringMaker<T^>::convert(e);
0162 }
0163 #endif
0164
0165 }
0166
0167
0168
0169 template<>
0170 struct StringMaker<std::string> {
0171 static std::string convert(const std::string& str);
0172 };
0173
0174 #ifdef CATCH_CONFIG_CPP17_STRING_VIEW
0175 template<>
0176 struct StringMaker<std::string_view> {
0177 static std::string convert(std::string_view str);
0178 };
0179 #endif
0180
0181 template<>
0182 struct StringMaker<char const *> {
0183 static std::string convert(char const * str);
0184 };
0185 template<>
0186 struct StringMaker<char *> {
0187 static std::string convert(char * str);
0188 };
0189
0190 #if defined(CATCH_CONFIG_WCHAR)
0191 template<>
0192 struct StringMaker<std::wstring> {
0193 static std::string convert(const std::wstring& wstr);
0194 };
0195
0196 # ifdef CATCH_CONFIG_CPP17_STRING_VIEW
0197 template<>
0198 struct StringMaker<std::wstring_view> {
0199 static std::string convert(std::wstring_view str);
0200 };
0201 # endif
0202
0203 template<>
0204 struct StringMaker<wchar_t const *> {
0205 static std::string convert(wchar_t const * str);
0206 };
0207 template<>
0208 struct StringMaker<wchar_t *> {
0209 static std::string convert(wchar_t * str);
0210 };
0211 #endif
0212
0213 template<size_t SZ>
0214 struct StringMaker<char[SZ]> {
0215 static std::string convert(char const* str) {
0216 return Detail::convertIntoString(
0217 StringRef( str, Detail::catch_strnlen( str, SZ ) ) );
0218 }
0219 };
0220 template<size_t SZ>
0221 struct StringMaker<signed char[SZ]> {
0222 static std::string convert(signed char const* str) {
0223 auto reinterpreted = reinterpret_cast<char const*>(str);
0224 return Detail::convertIntoString(
0225 StringRef(reinterpreted, Detail::catch_strnlen(reinterpreted, SZ)));
0226 }
0227 };
0228 template<size_t SZ>
0229 struct StringMaker<unsigned char[SZ]> {
0230 static std::string convert(unsigned char const* str) {
0231 auto reinterpreted = reinterpret_cast<char const*>(str);
0232 return Detail::convertIntoString(
0233 StringRef(reinterpreted, Detail::catch_strnlen(reinterpreted, SZ)));
0234 }
0235 };
0236
0237 #if defined(CATCH_CONFIG_CPP17_BYTE)
0238 template<>
0239 struct StringMaker<std::byte> {
0240 static std::string convert(std::byte value);
0241 };
0242 #endif
0243 template<>
0244 struct StringMaker<int> {
0245 static std::string convert(int value);
0246 };
0247 template<>
0248 struct StringMaker<long> {
0249 static std::string convert(long value);
0250 };
0251 template<>
0252 struct StringMaker<long long> {
0253 static std::string convert(long long value);
0254 };
0255 template<>
0256 struct StringMaker<unsigned int> {
0257 static std::string convert(unsigned int value);
0258 };
0259 template<>
0260 struct StringMaker<unsigned long> {
0261 static std::string convert(unsigned long value);
0262 };
0263 template<>
0264 struct StringMaker<unsigned long long> {
0265 static std::string convert(unsigned long long value);
0266 };
0267
0268 template<>
0269 struct StringMaker<bool> {
0270 static std::string convert(bool b) {
0271 using namespace std::string_literals;
0272 return b ? "true"s : "false"s;
0273 }
0274 };
0275
0276 template<>
0277 struct StringMaker<char> {
0278 static std::string convert(char c);
0279 };
0280 template<>
0281 struct StringMaker<signed char> {
0282 static std::string convert(signed char c);
0283 };
0284 template<>
0285 struct StringMaker<unsigned char> {
0286 static std::string convert(unsigned char c);
0287 };
0288
0289 template<>
0290 struct StringMaker<std::nullptr_t> {
0291 static std::string convert(std::nullptr_t) {
0292 using namespace std::string_literals;
0293 return "nullptr"s;
0294 }
0295 };
0296
0297 template<>
0298 struct StringMaker<float> {
0299 static std::string convert(float value);
0300 CATCH_EXPORT static int precision;
0301 };
0302
0303 template<>
0304 struct StringMaker<double> {
0305 static std::string convert(double value);
0306 CATCH_EXPORT static int precision;
0307 };
0308
0309 template <typename T>
0310 struct StringMaker<T*> {
0311 template <typename U>
0312 static std::string convert(U* p) {
0313 if (p) {
0314 return ::Catch::Detail::rawMemoryToString(p);
0315 } else {
0316 return "nullptr";
0317 }
0318 }
0319 };
0320
0321 template <typename R, typename C>
0322 struct StringMaker<R C::*> {
0323 static std::string convert(R C::* p) {
0324 if (p) {
0325 return ::Catch::Detail::rawMemoryToString(p);
0326 } else {
0327 return "nullptr";
0328 }
0329 }
0330 };
0331
0332 #if defined(_MANAGED)
0333 template <typename T>
0334 struct StringMaker<T^> {
0335 static std::string convert( T^ ref ) {
0336 return ::Catch::Detail::clrReferenceToString(ref);
0337 }
0338 };
0339 #endif
0340
0341 namespace Detail {
0342 template<typename InputIterator, typename Sentinel = InputIterator>
0343 std::string rangeToString(InputIterator first, Sentinel last) {
0344 ReusableStringStream rss;
0345 rss << "{ ";
0346 if (first != last) {
0347 rss << ::Catch::Detail::stringify(*first);
0348 for (++first; first != last; ++first)
0349 rss << ", " << ::Catch::Detail::stringify(*first);
0350 }
0351 rss << " }";
0352 return rss.str();
0353 }
0354 }
0355
0356 }
0357
0358
0359
0360
0361
0362 #if defined(CATCH_CONFIG_ENABLE_ALL_STRINGMAKERS)
0363 # define CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER
0364 # define CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER
0365 # define CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER
0366 # define CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER
0367 #endif
0368
0369
0370 #if defined(CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER)
0371 #include <utility>
0372 namespace Catch {
0373 template<typename T1, typename T2>
0374 struct StringMaker<std::pair<T1, T2> > {
0375 static std::string convert(const std::pair<T1, T2>& pair) {
0376 ReusableStringStream rss;
0377 rss << "{ "
0378 << ::Catch::Detail::stringify(pair.first)
0379 << ", "
0380 << ::Catch::Detail::stringify(pair.second)
0381 << " }";
0382 return rss.str();
0383 }
0384 };
0385 }
0386 #endif
0387
0388 #if defined(CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER) && defined(CATCH_CONFIG_CPP17_OPTIONAL)
0389 #include <optional>
0390 namespace Catch {
0391 template<typename T>
0392 struct StringMaker<std::optional<T> > {
0393 static std::string convert(const std::optional<T>& optional) {
0394 if (optional.has_value()) {
0395 return ::Catch::Detail::stringify(*optional);
0396 } else {
0397 return "{ }";
0398 }
0399 }
0400 };
0401 }
0402 #endif
0403
0404
0405 #if defined(CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER)
0406 #include <tuple>
0407 namespace Catch {
0408 namespace Detail {
0409 template<
0410 typename Tuple,
0411 std::size_t N = 0,
0412 bool = (N < std::tuple_size<Tuple>::value)
0413 >
0414 struct TupleElementPrinter {
0415 static void print(const Tuple& tuple, std::ostream& os) {
0416 os << (N ? ", " : " ")
0417 << ::Catch::Detail::stringify(std::get<N>(tuple));
0418 TupleElementPrinter<Tuple, N + 1>::print(tuple, os);
0419 }
0420 };
0421
0422 template<
0423 typename Tuple,
0424 std::size_t N
0425 >
0426 struct TupleElementPrinter<Tuple, N, false> {
0427 static void print(const Tuple&, std::ostream&) {}
0428 };
0429
0430 }
0431
0432
0433 template<typename ...Types>
0434 struct StringMaker<std::tuple<Types...>> {
0435 static std::string convert(const std::tuple<Types...>& tuple) {
0436 ReusableStringStream rss;
0437 rss << '{';
0438 Detail::TupleElementPrinter<std::tuple<Types...>>::print(tuple, rss.get());
0439 rss << " }";
0440 return rss.str();
0441 }
0442 };
0443 }
0444 #endif
0445
0446 #if defined(CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER) && defined(CATCH_CONFIG_CPP17_VARIANT)
0447 #include <variant>
0448 namespace Catch {
0449 template<>
0450 struct StringMaker<std::monostate> {
0451 static std::string convert(const std::monostate&) {
0452 return "{ }";
0453 }
0454 };
0455
0456 template<typename... Elements>
0457 struct StringMaker<std::variant<Elements...>> {
0458 static std::string convert(const std::variant<Elements...>& variant) {
0459 if (variant.valueless_by_exception()) {
0460 return "{valueless variant}";
0461 } else {
0462 return std::visit(
0463 [](const auto& value) {
0464 return ::Catch::Detail::stringify(value);
0465 },
0466 variant
0467 );
0468 }
0469 }
0470 };
0471 }
0472 #endif
0473
0474 namespace Catch {
0475
0476 using std::begin;
0477 using std::end;
0478
0479 namespace Detail {
0480 template <typename T, typename = void>
0481 struct is_range_impl : std::false_type {};
0482
0483 template <typename T>
0484 struct is_range_impl<T, void_t<decltype(begin(std::declval<T>()))>> : std::true_type {};
0485 }
0486
0487 template <typename T>
0488 struct is_range : Detail::is_range_impl<T> {};
0489
0490 #if defined(_MANAGED)
0491 template <typename T>
0492 struct is_range<T^> {
0493 static const bool value = false;
0494 };
0495 #endif
0496
0497 template<typename Range>
0498 std::string rangeToString( Range const& range ) {
0499 return ::Catch::Detail::rangeToString( begin( range ), end( range ) );
0500 }
0501
0502
0503 template<typename Allocator>
0504 std::string rangeToString( std::vector<bool, Allocator> const& v ) {
0505 ReusableStringStream rss;
0506 rss << "{ ";
0507 bool first = true;
0508 for( bool b : v ) {
0509 if( first )
0510 first = false;
0511 else
0512 rss << ", ";
0513 rss << ::Catch::Detail::stringify( b );
0514 }
0515 rss << " }";
0516 return rss.str();
0517 }
0518
0519 template<typename R>
0520 struct StringMaker<R, std::enable_if_t<is_range<R>::value && !::Catch::Detail::IsStreamInsertable<R>::value>> {
0521 static std::string convert( R const& range ) {
0522 return rangeToString( range );
0523 }
0524 };
0525
0526 template <typename T, size_t SZ>
0527 struct StringMaker<T[SZ]> {
0528 static std::string convert(T const(&arr)[SZ]) {
0529 return rangeToString(arr);
0530 }
0531 };
0532
0533
0534 }
0535
0536
0537 #include <ctime>
0538 #include <ratio>
0539 #include <chrono>
0540
0541
0542 namespace Catch {
0543
0544 template <class Ratio>
0545 struct ratio_string {
0546 static std::string symbol() {
0547 Catch::ReusableStringStream rss;
0548 rss << '[' << Ratio::num << '/'
0549 << Ratio::den << ']';
0550 return rss.str();
0551 }
0552 };
0553
0554 template <>
0555 struct ratio_string<std::atto> {
0556 static char symbol() { return 'a'; }
0557 };
0558 template <>
0559 struct ratio_string<std::femto> {
0560 static char symbol() { return 'f'; }
0561 };
0562 template <>
0563 struct ratio_string<std::pico> {
0564 static char symbol() { return 'p'; }
0565 };
0566 template <>
0567 struct ratio_string<std::nano> {
0568 static char symbol() { return 'n'; }
0569 };
0570 template <>
0571 struct ratio_string<std::micro> {
0572 static char symbol() { return 'u'; }
0573 };
0574 template <>
0575 struct ratio_string<std::milli> {
0576 static char symbol() { return 'm'; }
0577 };
0578
0579
0580
0581 template<typename Value, typename Ratio>
0582 struct StringMaker<std::chrono::duration<Value, Ratio>> {
0583 static std::string convert(std::chrono::duration<Value, Ratio> const& duration) {
0584 ReusableStringStream rss;
0585 rss << duration.count() << ' ' << ratio_string<Ratio>::symbol() << 's';
0586 return rss.str();
0587 }
0588 };
0589 template<typename Value>
0590 struct StringMaker<std::chrono::duration<Value, std::ratio<1>>> {
0591 static std::string convert(std::chrono::duration<Value, std::ratio<1>> const& duration) {
0592 ReusableStringStream rss;
0593 rss << duration.count() << " s";
0594 return rss.str();
0595 }
0596 };
0597 template<typename Value>
0598 struct StringMaker<std::chrono::duration<Value, std::ratio<60>>> {
0599 static std::string convert(std::chrono::duration<Value, std::ratio<60>> const& duration) {
0600 ReusableStringStream rss;
0601 rss << duration.count() << " m";
0602 return rss.str();
0603 }
0604 };
0605 template<typename Value>
0606 struct StringMaker<std::chrono::duration<Value, std::ratio<3600>>> {
0607 static std::string convert(std::chrono::duration<Value, std::ratio<3600>> const& duration) {
0608 ReusableStringStream rss;
0609 rss << duration.count() << " h";
0610 return rss.str();
0611 }
0612 };
0613
0614
0615
0616
0617 template<typename Clock, typename Duration>
0618 struct StringMaker<std::chrono::time_point<Clock, Duration>> {
0619 static std::string convert(std::chrono::time_point<Clock, Duration> const& time_point) {
0620 return ::Catch::Detail::stringify(time_point.time_since_epoch()) + " since epoch";
0621 }
0622 };
0623
0624 template<typename Duration>
0625 struct StringMaker<std::chrono::time_point<std::chrono::system_clock, Duration>> {
0626 static std::string convert(std::chrono::time_point<std::chrono::system_clock, Duration> const& time_point) {
0627 auto converted = std::chrono::system_clock::to_time_t(time_point);
0628
0629 #ifdef _MSC_VER
0630 std::tm timeInfo = {};
0631 gmtime_s(&timeInfo, &converted);
0632 #else
0633 std::tm* timeInfo = std::gmtime(&converted);
0634 #endif
0635
0636 auto const timeStampSize = sizeof("2017-01-16T17:06:45Z");
0637 char timeStamp[timeStampSize];
0638 const char * const fmt = "%Y-%m-%dT%H:%M:%SZ";
0639
0640 #ifdef _MSC_VER
0641 std::strftime(timeStamp, timeStampSize, fmt, &timeInfo);
0642 #else
0643 std::strftime(timeStamp, timeStampSize, fmt, timeInfo);
0644 #endif
0645 return std::string(timeStamp, timeStampSize - 1);
0646 }
0647 };
0648 }
0649
0650 #include <catch2/interfaces/catch_interfaces_registry_hub.hpp>
0651
0652 #define INTERNAL_CATCH_REGISTER_ENUM( enumName, ... ) \
0653 namespace Catch { \
0654 template<> struct StringMaker<enumName> { \
0655 static std::string convert( enumName value ) { \
0656 static const auto& enumInfo = ::Catch::getMutableRegistryHub().getMutableEnumValuesRegistry().registerEnum( #enumName, #__VA_ARGS__, { __VA_ARGS__ } ); \
0657 return static_cast<std::string>(enumInfo.lookup( static_cast<int>( value ) )); \
0658 } \
0659 }; \
0660 }
0661
0662 #define CATCH_REGISTER_ENUM( enumName, ... ) INTERNAL_CATCH_REGISTER_ENUM( enumName, __VA_ARGS__ )
0663
0664 #ifdef _MSC_VER
0665 #pragma warning(pop)
0666 #endif
0667
0668 #endif