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