File Coverage

/usr/local/lib/perl5/site_perl/5.26.1/x86_64-linux/XS/libcatch.x/i/catch2/catch_tostring.hpp
Criterion Covered Total %
statement 4 4 100.0
branch 1 2 50.0
condition n/a
subroutine n/a
pod n/a
total 5 6 83.3


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