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