1 /*
2  *  Created by Phil on 23/4/2014.
3  *  Copyright 2014 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 
9 #if defined(__clang__)
10 #    pragma clang diagnostic push
11 #    pragma clang diagnostic ignored "-Wexit-time-destructors"
12 #    pragma clang diagnostic ignored "-Wglobal-constructors"
13 #endif
14 
15 // Enable specific decls locally
16 #if !defined(CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER)
17 #define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER
18 #endif
19 
20 #include "catch_tostring.h"
21 #include "catch_interfaces_config.h"
22 #include "catch_context.h"
23 #include "catch_polyfills.hpp"
24 
25 #include <cmath>
26 #include <iomanip>
27 
28 namespace Catch {
29 
30 namespace Detail {
31 
32     const std::string unprintableString = "{?}";
33 
34     namespace {
35         const int hexThreshold = 255;
36 
37         struct Endianness {
38             enum Arch { Big, Little };
39 
whichCatch::Detail::__anonb9f531120111::Endianness40             static Arch which() {
41                 int one = 1;
42                 // If the lowest byte we read is non-zero, we can assume
43                 // that little endian format is used.
44                 auto value = *reinterpret_cast<char*>(&one);
45                 return value ? Little : Big;
46             }
47         };
48     }
49 
rawMemoryToString(const void * object,std::size_t size)50     std::string rawMemoryToString( const void *object, std::size_t size ) {
51         // Reverse order for little endian architectures
52         int i = 0, end = static_cast<int>( size ), inc = 1;
53         if( Endianness::which() == Endianness::Little ) {
54             i = end-1;
55             end = inc = -1;
56         }
57 
58         unsigned char const *bytes = static_cast<unsigned char const *>(object);
59         ReusableStringStream rss;
60         rss << "0x" << std::setfill('0') << std::hex;
61         for( ; i != end; i += inc )
62              rss << std::setw(2) << static_cast<unsigned>(bytes[i]);
63        return rss.str();
64     }
65 }
66 
67 
68 template<typename T>
fpToString(T value,int precision)69 std::string fpToString( T value, int precision ) {
70     if (Catch::isnan(value)) {
71         return "nan";
72     }
73 
74     ReusableStringStream rss;
75     rss << std::setprecision( precision )
76         << std::fixed
77         << value;
78     std::string d = rss.str();
79     std::size_t i = d.find_last_not_of( '0' );
80     if( i != std::string::npos && i != d.size()-1 ) {
81         if( d[i] == '.' )
82             i++;
83         d = d.substr( 0, i+1 );
84     }
85     return d;
86 }
87 
88 
89 //// ======================================================= ////
90 //
91 //   Out-of-line defs for full specialization of StringMaker
92 //
93 //// ======================================================= ////
94 
convert(const std::string & str)95 std::string StringMaker<std::string>::convert(const std::string& str) {
96     if (!getCurrentContext().getConfig()->showInvisibles()) {
97         return '"' + str + '"';
98     }
99 
100     std::string s("\"");
101     for (char c : str) {
102         switch (c) {
103         case '\n':
104             s.append("\\n");
105             break;
106         case '\t':
107             s.append("\\t");
108             break;
109         default:
110             s.push_back(c);
111             break;
112         }
113     }
114     s.append("\"");
115     return s;
116 }
117 
118 #ifdef CATCH_CONFIG_CPP17_STRING_VIEW
convert(std::string_view str)119 std::string StringMaker<std::string_view>::convert(std::string_view str) {
120     return ::Catch::Detail::stringify(std::string{ str });
121 }
122 #endif
123 
convert(char const * str)124 std::string StringMaker<char const*>::convert(char const* str) {
125     if (str) {
126         return ::Catch::Detail::stringify(std::string{ str });
127     } else {
128         return{ "{null string}" };
129     }
130 }
convert(char * str)131 std::string StringMaker<char*>::convert(char* str) {
132     if (str) {
133         return ::Catch::Detail::stringify(std::string{ str });
134     } else {
135         return{ "{null string}" };
136     }
137 }
138 
139 #ifdef CATCH_CONFIG_WCHAR
convert(const std::wstring & wstr)140 std::string StringMaker<std::wstring>::convert(const std::wstring& wstr) {
141     std::string s;
142     s.reserve(wstr.size());
143     for (auto c : wstr) {
144         s += (c <= 0xff) ? static_cast<char>(c) : '?';
145     }
146     return ::Catch::Detail::stringify(s);
147 }
148 
149 # ifdef CATCH_CONFIG_CPP17_STRING_VIEW
convert(std::wstring_view str)150 std::string StringMaker<std::wstring_view>::convert(std::wstring_view str) {
151     return StringMaker<std::wstring>::convert(std::wstring(str));
152 }
153 # endif
154 
convert(wchar_t const * str)155 std::string StringMaker<wchar_t const*>::convert(wchar_t const * str) {
156     if (str) {
157         return ::Catch::Detail::stringify(std::wstring{ str });
158     } else {
159         return{ "{null string}" };
160     }
161 }
convert(wchar_t * str)162 std::string StringMaker<wchar_t *>::convert(wchar_t * str) {
163     if (str) {
164         return ::Catch::Detail::stringify(std::wstring{ str });
165     } else {
166         return{ "{null string}" };
167     }
168 }
169 #endif
170 
171 #if defined(CATCH_CONFIG_CPP17_BYTE)
172 #include <cstddef>
convert(std::byte value)173 std::string StringMaker<std::byte>::convert(std::byte value) {
174     return ::Catch::Detail::stringify(std::to_integer<unsigned long long>(value));
175 }
176 #endif // defined(CATCH_CONFIG_CPP17_BYTE)
177 
convert(int value)178 std::string StringMaker<int>::convert(int value) {
179     return ::Catch::Detail::stringify(static_cast<long long>(value));
180 }
convert(long value)181 std::string StringMaker<long>::convert(long value) {
182     return ::Catch::Detail::stringify(static_cast<long long>(value));
183 }
convert(long long value)184 std::string StringMaker<long long>::convert(long long value) {
185     ReusableStringStream rss;
186     rss << value;
187     if (value > Detail::hexThreshold) {
188         rss << " (0x" << std::hex << value << ')';
189     }
190     return rss.str();
191 }
192 
convert(unsigned int value)193 std::string StringMaker<unsigned int>::convert(unsigned int value) {
194     return ::Catch::Detail::stringify(static_cast<unsigned long long>(value));
195 }
convert(unsigned long value)196 std::string StringMaker<unsigned long>::convert(unsigned long value) {
197     return ::Catch::Detail::stringify(static_cast<unsigned long long>(value));
198 }
convert(unsigned long long value)199 std::string StringMaker<unsigned long long>::convert(unsigned long long value) {
200     ReusableStringStream rss;
201     rss << value;
202     if (value > Detail::hexThreshold) {
203         rss << " (0x" << std::hex << value << ')';
204     }
205     return rss.str();
206 }
207 
208 
convert(bool b)209 std::string StringMaker<bool>::convert(bool b) {
210     return b ? "true" : "false";
211 }
212 
convert(signed char value)213 std::string StringMaker<signed char>::convert(signed char value) {
214     if (value == '\r') {
215         return "'\\r'";
216     } else if (value == '\f') {
217         return "'\\f'";
218     } else if (value == '\n') {
219         return "'\\n'";
220     } else if (value == '\t') {
221         return "'\\t'";
222     } else if ('\0' <= value && value < ' ') {
223         return ::Catch::Detail::stringify(static_cast<unsigned int>(value));
224     } else {
225         char chstr[] = "' '";
226         chstr[1] = value;
227         return chstr;
228     }
229 }
convert(char c)230 std::string StringMaker<char>::convert(char c) {
231     return ::Catch::Detail::stringify(static_cast<signed char>(c));
232 }
convert(unsigned char c)233 std::string StringMaker<unsigned char>::convert(unsigned char c) {
234     return ::Catch::Detail::stringify(static_cast<char>(c));
235 }
236 
convert(std::nullptr_t)237 std::string StringMaker<std::nullptr_t>::convert(std::nullptr_t) {
238     return "nullptr";
239 }
240 
241 int StringMaker<float>::precision = 5;
242 
convert(float value)243 std::string StringMaker<float>::convert(float value) {
244     return fpToString(value, precision) + 'f';
245 }
246 
247 int StringMaker<double>::precision = 10;
248 
convert(double value)249 std::string StringMaker<double>::convert(double value) {
250     return fpToString(value, precision);
251 }
252 
symbol()253 std::string ratio_string<std::atto>::symbol() { return "a"; }
symbol()254 std::string ratio_string<std::femto>::symbol() { return "f"; }
symbol()255 std::string ratio_string<std::pico>::symbol() { return "p"; }
symbol()256 std::string ratio_string<std::nano>::symbol() { return "n"; }
symbol()257 std::string ratio_string<std::micro>::symbol() { return "u"; }
symbol()258 std::string ratio_string<std::milli>::symbol() { return "m"; }
259 
260 } // end namespace Catch
261 
262 #if defined(__clang__)
263 #    pragma clang diagnostic pop
264 #endif
265 
266