Wire Sysio Wire Sysion 1.0.0
Loading...
Searching...
No Matches
catch_tostring.h
Go to the documentation of this file.
1/*
2 * Created by Phil on 8/5/2012.
3 * Copyright 2012 Two Blue Cubes Ltd. All rights reserved.
4 *
5 * Distributed under the Boost Software License, Version 1.0. (See accompanying
6 * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7 */
8#ifndef TWOBLUECUBES_CATCH_TOSTRING_H_INCLUDED
9#define TWOBLUECUBES_CATCH_TOSTRING_H_INCLUDED
10
11
12#include <vector>
13#include <cstddef>
14#include <type_traits>
15#include <string>
17#include "catch_stream.h"
19
20#ifdef CATCH_CONFIG_CPP17_STRING_VIEW
21#include <string_view>
22#endif
23
24#ifdef __OBJC__
25#include "catch_objc_arc.hpp"
26#endif
27
28#ifdef _MSC_VER
29#pragma warning(push)
30#pragma warning(disable:4180) // We attempt to stream a function (address) by const&, which MSVC complains about but is harmless
31#endif
32
33namespace Catch {
34 namespace Detail {
35
36 extern const std::string unprintableString;
37
38 std::string rawMemoryToString( const void *object, std::size_t size );
39
40 template<typename T>
41 std::string rawMemoryToString( const T& object ) {
42 return rawMemoryToString( &object, sizeof(object) );
43 }
44
45 template<typename T>
46 class IsStreamInsertable {
47 template<typename SS, typename TT>
48 static auto test(int)
49 -> decltype(std::declval<SS&>() << std::declval<TT>(), std::true_type());
50
51 template<typename, typename>
52 static auto test(...)->std::false_type;
53
54 public:
55 static const bool value = decltype(test<std::ostream, const T&>(0))::value;
56 };
57
58 template<typename E>
59 std::string convertUnknownEnumToString( E e );
60
61 template<typename T>
62 typename std::enable_if<
63 !std::is_enum<T>::value && !std::is_base_of<std::exception, T>::value,
64 std::string>::type convertUnstreamable( T const& ) {
66 }
67 template<typename T>
68 typename std::enable_if<
69 !std::is_enum<T>::value && std::is_base_of<std::exception, T>::value,
70 std::string>::type convertUnstreamable(T const& ex) {
71 return ex.what();
72 }
73
74
75 template<typename T>
76 typename std::enable_if<
77 std::is_enum<T>::value
78 , std::string>::type convertUnstreamable( T const& value ) {
80 }
81
82#if defined(_MANAGED)
84 template<typename T>
85 std::string clrReferenceToString( T^ ref ) {
86 if (ref == nullptr)
87 return std::string("null");
88 auto bytes = System::Text::Encoding::UTF8->GetBytes(ref->ToString());
89 cli::pin_ptr<System::Byte> p = &bytes[0];
90 return std::string(reinterpret_cast<char const *>(p), bytes->Length);
91 }
92#endif
93
94 } // namespace Detail
95
96
97 // If we decide for C++14, change these to enable_if_ts
98 template <typename T, typename = void>
99 struct StringMaker {
100 template <typename Fake = T>
101 static
102 typename std::enable_if<::Catch::Detail::IsStreamInsertable<Fake>::value, std::string>::type
103 convert(const Fake& value) {
105 // NB: call using the function-like syntax to avoid ambiguity with
106 // user-defined templated operator<< under clang.
107 rss.operator<<(value);
108 return rss.str();
109 }
110
111 template <typename Fake = T>
112 static
113 typename std::enable_if<!::Catch::Detail::IsStreamInsertable<Fake>::value, std::string>::type
114 convert( const Fake& value ) {
115#if !defined(CATCH_CONFIG_FALLBACK_STRINGIFIER)
117#else
119#endif
120 }
121 };
122
123 namespace Detail {
124
125 // This function dispatches all stringification requests inside of Catch.
126 // Should be preferably called fully qualified, like ::Catch::Detail::stringify
127 template <typename T>
128 std::string stringify(const T& e) {
129 return ::Catch::StringMaker<typename std::remove_cv<typename std::remove_reference<T>::type>::type>::convert(e);
130 }
131
132 template<typename E>
133 std::string convertUnknownEnumToString( E e ) {
134 return ::Catch::Detail::stringify(static_cast<typename std::underlying_type<E>::type>(e));
135 }
136
137#if defined(_MANAGED)
138 template <typename T>
139 std::string stringify( T^ e ) {
140 return ::Catch::StringMaker<T^>::convert(e);
141 }
142#endif
143
144 } // namespace Detail
145
146 // Some predefined specializations
147
148 template<>
149 struct StringMaker<std::string> {
150 static std::string convert(const std::string& str);
151 };
152
153#ifdef CATCH_CONFIG_CPP17_STRING_VIEW
154 template<>
155 struct StringMaker<std::string_view> {
156 static std::string convert(std::string_view str);
157 };
158#endif
159
160 template<>
161 struct StringMaker<char const *> {
162 static std::string convert(char const * str);
163 };
164 template<>
165 struct StringMaker<char *> {
166 static std::string convert(char * str);
167 };
168
169#ifdef CATCH_CONFIG_WCHAR
170 template<>
171 struct StringMaker<std::wstring> {
172 static std::string convert(const std::wstring& wstr);
173 };
174
175# ifdef CATCH_CONFIG_CPP17_STRING_VIEW
176 template<>
177 struct StringMaker<std::wstring_view> {
178 static std::string convert(std::wstring_view str);
179 };
180# endif
181
182 template<>
183 struct StringMaker<wchar_t const *> {
184 static std::string convert(wchar_t const * str);
185 };
186 template<>
187 struct StringMaker<wchar_t *> {
188 static std::string convert(wchar_t * str);
189 };
190#endif
191
192 // TBD: Should we use `strnlen` to ensure that we don't go out of the buffer,
193 // while keeping string semantics?
194 template<int SZ>
195 struct StringMaker<char[SZ]> {
196 static std::string convert(char const* str) {
197 return ::Catch::Detail::stringify(std::string{ str });
198 }
199 };
200 template<int SZ>
201 struct StringMaker<signed char[SZ]> {
202 static std::string convert(signed char const* str) {
203 return ::Catch::Detail::stringify(std::string{ reinterpret_cast<char const *>(str) });
204 }
205 };
206 template<int SZ>
207 struct StringMaker<unsigned char[SZ]> {
208 static std::string convert(unsigned char const* str) {
209 return ::Catch::Detail::stringify(std::string{ reinterpret_cast<char const *>(str) });
210 }
211 };
212
213 template<>
214 struct StringMaker<int> {
215 static std::string convert(int value);
216 };
217 template<>
218 struct StringMaker<long> {
219 static std::string convert(long value);
220 };
221 template<>
222 struct StringMaker<long long> {
223 static std::string convert(long long value);
224 };
225 template<>
226 struct StringMaker<unsigned int> {
227 static std::string convert(unsigned int value);
228 };
229 template<>
230 struct StringMaker<unsigned long> {
231 static std::string convert(unsigned long value);
232 };
233 template<>
234 struct StringMaker<unsigned long long> {
235 static std::string convert(unsigned long long value);
236 };
237
238 template<>
239 struct StringMaker<bool> {
240 static std::string convert(bool b);
241 };
242
243 template<>
244 struct StringMaker<char> {
245 static std::string convert(char c);
246 };
247 template<>
248 struct StringMaker<signed char> {
249 static std::string convert(signed char c);
250 };
251 template<>
252 struct StringMaker<unsigned char> {
253 static std::string convert(unsigned char c);
254 };
255
256 template<>
257 struct StringMaker<std::nullptr_t> {
258 static std::string convert(std::nullptr_t);
259 };
260
261 template<>
262 struct StringMaker<float> {
263 static std::string convert(float value);
264 };
265 template<>
266 struct StringMaker<double> {
267 static std::string convert(double value);
268 };
269
270 template <typename T>
271 struct StringMaker<T*> {
272 template <typename U>
273 static std::string convert(U* p) {
274 if (p) {
275 return ::Catch::Detail::rawMemoryToString(p);
276 } else {
277 return "nullptr";
278 }
279 }
280 };
281
282 template <typename R, typename C>
283 struct StringMaker<R C::*> {
284 static std::string convert(R C::* p) {
285 if (p) {
286 return ::Catch::Detail::rawMemoryToString(p);
287 } else {
288 return "nullptr";
289 }
290 }
291 };
292
293#if defined(_MANAGED)
294 template <typename T>
295 struct StringMaker<T^> {
296 static std::string convert( T^ ref ) {
297 return ::Catch::Detail::clrReferenceToString(ref);
298 }
299 };
300#endif
301
302 namespace Detail {
303 template<typename InputIterator>
304 std::string rangeToString(InputIterator first, InputIterator last) {
306 rss << "{ ";
307 if (first != last) {
308 rss << ::Catch::Detail::stringify(*first);
309 for (++first; first != last; ++first)
310 rss << ", " << ::Catch::Detail::stringify(*first);
311 }
312 rss << " }";
313 return rss.str();
314 }
315 }
316
317#ifdef __OBJC__
318 template<>
319 struct StringMaker<NSString*> {
320 static std::string convert(NSString * nsstring) {
321 if (!nsstring)
322 return "nil";
323 return std::string("@") + [nsstring UTF8String];
324 }
325 };
326 template<>
327 struct StringMaker<NSObject*> {
328 static std::string convert(NSObject* nsObject) {
329 return ::Catch::Detail::stringify([nsObject description]);
330 }
331
332 };
333 namespace Detail {
334 inline std::string stringify( NSString* nsstring ) {
335 return StringMaker<NSString*>::convert( nsstring );
336 }
337
338 } // namespace Detail
339#endif // __OBJC__
340
341} // namespace Catch
342
344// Separate std-lib types stringification, so it can be selectively enabled
345// This means that we do not bring in
346
347#if defined(CATCH_CONFIG_ENABLE_ALL_STRINGMAKERS)
348# define CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER
349# define CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER
350# define CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER
351# define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER
352# define CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER
353#endif
354
355// Separate std::pair specialization
356#if defined(CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER)
357#include <utility>
358namespace Catch {
359 template<typename T1, typename T2>
360 struct StringMaker<std::pair<T1, T2> > {
361 static std::string convert(const std::pair<T1, T2>& pair) {
362 ReusableStringStream rss;
363 rss << "{ "
364 << ::Catch::Detail::stringify(pair.first)
365 << ", "
366 << ::Catch::Detail::stringify(pair.second)
367 << " }";
368 return rss.str();
369 }
370 };
371}
372#endif // CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER
373
374#if defined(CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER) && defined(CATCH_CONFIG_CPP17_OPTIONAL)
375#include <optional>
376namespace Catch {
377 template<typename T>
378 struct StringMaker<std::optional<T> > {
379 static std::string convert(const std::optional<T>& optional) {
380 ReusableStringStream rss;
381 if (optional.has_value()) {
382 rss << ::Catch::Detail::stringify(*optional);
383 } else {
384 rss << "{ }";
385 }
386 return rss.str();
387 }
388 };
389}
390#endif // CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER
391
392// Separate std::tuple specialization
393#if defined(CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER)
394#include <tuple>
395namespace Catch {
396 namespace Detail {
397 template<
398 typename Tuple,
399 std::size_t N = 0,
400 bool = (N < std::tuple_size<Tuple>::value)
401 >
402 struct TupleElementPrinter {
403 static void print(const Tuple& tuple, std::ostream& os) {
404 os << (N ? ", " : " ")
405 << ::Catch::Detail::stringify(std::get<N>(tuple));
406 TupleElementPrinter<Tuple, N + 1>::print(tuple, os);
407 }
408 };
409
410 template<
411 typename Tuple,
412 std::size_t N
413 >
414 struct TupleElementPrinter<Tuple, N, false> {
415 static void print(const Tuple&, std::ostream&) {}
416 };
417
418 }
419
420
421 template<typename ...Types>
422 struct StringMaker<std::tuple<Types...>> {
423 static std::string convert(const std::tuple<Types...>& tuple) {
424 ReusableStringStream rss;
425 rss << '{';
426 Detail::TupleElementPrinter<std::tuple<Types...>>::print(tuple, rss.get());
427 rss << " }";
428 return rss.str();
429 }
430 };
431}
432#endif // CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER
433
434#if defined(CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER) && defined(CATCH_CONFIG_CPP17_VARIANT)
435#include <variant>
436namespace Catch {
437 template<>
438 struct StringMaker<std::monostate> {
439 static std::string convert(const std::monostate&) {
440 return "{ }";
441 }
442 };
443
444 template<typename... Elements>
445 struct StringMaker<std::variant<Elements...>> {
446 static std::string convert(const std::variant<Elements...>& variant) {
447 if (variant.valueless_by_exception()) {
448 return "{valueless variant}";
449 } else {
450 return std::visit(
451 [](const auto& value) {
452 return ::Catch::Detail::stringify(value);
453 },
454 variant
455 );
456 }
457 }
458 };
459}
460#endif // CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER
461
462namespace Catch {
463 struct not_this_one {}; // Tag type for detecting which begin/ end are being selected
464
465 // Import begin/ end from std here so they are considered alongside the fallback (...) overloads in this namespace
466 using std::begin;
467 using std::end;
468
469 not_this_one begin( ... );
470 not_this_one end( ... );
471
472 template <typename T>
473 struct is_range {
474 static const bool value =
475 !std::is_same<decltype(begin(std::declval<T>())), not_this_one>::value &&
476 !std::is_same<decltype(end(std::declval<T>())), not_this_one>::value;
477 };
478
479#if defined(_MANAGED) // Managed types are never ranges
480 template <typename T>
481 struct is_range<T^> {
482 static const bool value = false;
483 };
484#endif
485
486 template<typename Range>
487 std::string rangeToString( Range const& range ) {
488 return ::Catch::Detail::rangeToString( begin( range ), end( range ) );
489 }
490
491 // Handle vector<bool> specially
492 template<typename Allocator>
493 std::string rangeToString( std::vector<bool, Allocator> const& v ) {
495 rss << "{ ";
496 bool first = true;
497 for( bool b : v ) {
498 if( first )
499 first = false;
500 else
501 rss << ", ";
502 rss << ::Catch::Detail::stringify( b );
503 }
504 rss << " }";
505 return rss.str();
506 }
507
508 template<typename R>
509 struct StringMaker<R, typename std::enable_if<is_range<R>::value && !::Catch::Detail::IsStreamInsertable<R>::value>::type> {
510 static std::string convert( R const& range ) {
511 return rangeToString( range );
512 }
513 };
514
515 template <typename T, int SZ>
516 struct StringMaker<T[SZ]> {
517 static std::string convert(T const(&arr)[SZ]) {
518 return rangeToString(arr);
519 }
520 };
521
522
523} // namespace Catch
524
525// Separate std::chrono::duration specialization
526#if defined(CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER)
527#include <ctime>
528#include <ratio>
529#include <chrono>
530
531
532namespace Catch {
533
534template <class Ratio>
535struct ratio_string {
536 static std::string symbol();
537};
538
539template <class Ratio>
540std::string ratio_string<Ratio>::symbol() {
542 rss << '[' << Ratio::num << '/'
543 << Ratio::den << ']';
544 return rss.str();
545}
546template <>
547struct ratio_string<std::atto> {
548 static std::string symbol();
549};
550template <>
551struct ratio_string<std::femto> {
552 static std::string symbol();
553};
554template <>
555struct ratio_string<std::pico> {
556 static std::string symbol();
557};
558template <>
559struct ratio_string<std::nano> {
560 static std::string symbol();
561};
562template <>
563struct ratio_string<std::micro> {
564 static std::string symbol();
565};
566template <>
567struct ratio_string<std::milli> {
568 static std::string symbol();
569};
570
572 // std::chrono::duration specializations
573 template<typename Value, typename Ratio>
574 struct StringMaker<std::chrono::duration<Value, Ratio>> {
575 static std::string convert(std::chrono::duration<Value, Ratio> const& duration) {
576 ReusableStringStream rss;
577 rss << duration.count() << ' ' << ratio_string<Ratio>::symbol() << 's';
578 return rss.str();
579 }
580 };
581 template<typename Value>
582 struct StringMaker<std::chrono::duration<Value, std::ratio<1>>> {
583 static std::string convert(std::chrono::duration<Value, std::ratio<1>> const& duration) {
584 ReusableStringStream rss;
585 rss << duration.count() << " s";
586 return rss.str();
587 }
588 };
589 template<typename Value>
590 struct StringMaker<std::chrono::duration<Value, std::ratio<60>>> {
591 static std::string convert(std::chrono::duration<Value, std::ratio<60>> const& duration) {
592 ReusableStringStream rss;
593 rss << duration.count() << " m";
594 return rss.str();
595 }
596 };
597 template<typename Value>
598 struct StringMaker<std::chrono::duration<Value, std::ratio<3600>>> {
599 static std::string convert(std::chrono::duration<Value, std::ratio<3600>> const& duration) {
600 ReusableStringStream rss;
601 rss << duration.count() << " h";
602 return rss.str();
603 }
604 };
605
607 // std::chrono::time_point specialization
608 // Generic time_point cannot be specialized, only std::chrono::time_point<system_clock>
609 template<typename Clock, typename Duration>
610 struct StringMaker<std::chrono::time_point<Clock, Duration>> {
611 static std::string convert(std::chrono::time_point<Clock, Duration> const& time_point) {
612 return ::Catch::Detail::stringify(time_point.time_since_epoch()) + " since epoch";
613 }
614 };
615 // std::chrono::time_point<system_clock> specialization
616 template<typename Duration>
617 struct StringMaker<std::chrono::time_point<std::chrono::system_clock, Duration>> {
618 static std::string convert(std::chrono::time_point<std::chrono::system_clock, Duration> const& time_point) {
619 auto converted = std::chrono::system_clock::to_time_t(time_point);
620
621#ifdef _MSC_VER
622 std::tm timeInfo = {};
623 gmtime_s(&timeInfo, &converted);
624#else
625 std::tm* timeInfo = std::gmtime(&converted);
626#endif
627
628 auto const timeStampSize = sizeof("2017-01-16T17:06:45Z");
629 char timeStamp[timeStampSize];
630 const char * const fmt = "%Y-%m-%dT%H:%M:%SZ";
631
632#ifdef _MSC_VER
633 std::strftime(timeStamp, timeStampSize, fmt, &timeInfo);
634#else
635 std::strftime(timeStamp, timeStampSize, fmt, timeInfo);
636#endif
637 return std::string(timeStamp);
638 }
639 };
640}
641#endif // CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER
642
643#define INTERNAL_CATCH_REGISTER_ENUM( enumName, ... ) \
644namespace Catch { \
645 template<> struct StringMaker<enumName> { \
646 static std::string convert( enumName value ) { \
647 static const auto& enumInfo = ::Catch::getMutableRegistryHub().getMutableEnumValuesRegistry().registerEnum( #enumName, #__VA_ARGS__, { __VA_ARGS__ } ); \
648 return enumInfo.lookup( static_cast<int>( value ) ); \
649 } \
650 }; \
651}
652
653#define CATCH_REGISTER_ENUM( enumName, ... ) INTERNAL_CATCH_REGISTER_ENUM( enumName, __VA_ARGS__ )
654
655#ifdef _MSC_VER
656#pragma warning(pop)
657#endif
658
659#endif // TWOBLUECUBES_CATCH_TOSTRING_H_INCLUDED
void print(std::ostream &os, int const level, std::string const &title, Catch::SourceLineInfo const &info)
#define CATCH_CONFIG_FALLBACK_STRINGIFIER
const mie::Vuint & p
Definition bn.cpp:27
auto str() const -> std::string
constexpr const microseconds & time_since_epoch() const
Definition time.hpp:52
os_t os
std::string convertUnknownEnumToString(E e)
const std::string unprintableString
std::string rangeToString(InputIterator first, InputIterator last)
std::enable_if<!std::is_enum< T >::value &&!std::is_base_of< std::exception, T >::value, std::string >::type convertUnstreamable(T const &)
std::string rawMemoryToString(const void *object, std::size_t size)
std::string stringify(const T &e)
not_this_one end(...)
not_this_one begin(...)
std::string rangeToString(Range const &range)
Definition name.hpp:106
#define value
Definition pkcs11.h:157
#define T(meth, val, expected)
const int N
Definition quantize.cpp:54
static std::string convert(R C::*p)
static std::string convert(U *p)
static std::string convert(T const(&arr)[SZ])
static std::string convert(char const *str)
static std::string convert(char const *str)
static std::string convert(long long value)
static std::string convert(signed char c)
static std::string convert(signed char const *str)
static std::string convert(unsigned char c)
static std::string convert(unsigned char const *str)
static std::string convert(unsigned int value)
static std::string convert(unsigned long value)
static std::string convert(unsigned long long value)
static std::string convert(wchar_t const *str)
static std::enable_if<::Catch::Detail::IsStreamInsertable< Fake >::value, std::string >::type convert(const Fake &value)
static std::enable_if<!::Catch::Detail::IsStreamInsertable< Fake >::value, std::string >::type convert(const Fake &value)
static const bool value
#define R
Definition dtoa.c:306