blob: d5714e8d4bd8ff7c446e00013a5111b8076fe63f [file] [log] [blame]
Phil Nash81a122e2012-05-08 08:10:49 +01001/*
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_HPP_INCLUDED
9#define TWOBLUECUBES_CATCH_TOSTRING_HPP_INCLUDED
10
11#include "catch_common.h"
Phil Nash5062d3e2013-04-16 22:55:31 +010012#include "catch_sfinae.hpp"
13
Phil Nash81a122e2012-05-08 08:10:49 +010014#include <sstream>
Phil Nash767f1582013-03-04 12:19:15 +010015#include <iomanip>
16#include <limits>
Phil Nash81a122e2012-05-08 08:10:49 +010017
Phil Nash0dc9e432012-08-01 08:17:07 +010018#ifdef __OBJC__
19#include "catch_objc_arc.hpp"
20#endif
21
Phil Nash2efc1142012-05-15 07:42:26 +010022namespace Catch {
Phil Nash003960d2013-04-20 23:12:17 +010023namespace Detail {
Phil Nash5062d3e2013-04-16 22:55:31 +010024
Phil Nash9fff9e42013-04-20 23:18:44 +010025// SFINAE is currently disabled by default for all compilers.
26// If the non SFINAE version of IsStreamInsertable is ambiguous for you
Phil Nash4dd3f682013-04-22 08:19:17 +010027// and your compiler supports SFINAE, try #defining CATCH_CONFIG_SFINAE
28#ifdef CATCH_CONFIG_SFINAE
Phil Nash5062d3e2013-04-16 22:55:31 +010029
Phil Nash5062d3e2013-04-16 22:55:31 +010030 template<typename T>
31 class IsStreamInsertableHelper {
32 template<int N> struct TrueIfSizeable : TrueType {};
33
34 template<typename T2>
35 static TrueIfSizeable<sizeof((*(std::ostream*)0) << *((T2 const*)0))> dummy(T2*);
36 static FalseType dummy(...);
37
38 public:
39 typedef SizedIf<sizeof(dummy((T*)0))> type;
40 };
Phil Nashf3d1f082013-07-03 19:14:59 +010041
Phil Nash5062d3e2013-04-16 22:55:31 +010042 template<typename T>
43 struct IsStreamInsertable : IsStreamInsertableHelper<T>::type {};
44
Phil Nash5062d3e2013-04-16 22:55:31 +010045#else
46
Phil Nash003960d2013-04-20 23:12:17 +010047 struct BorgType {
48 template<typename T> BorgType( T const& );
49 };
Phil Nashf3d1f082013-07-03 19:14:59 +010050
Phil Nash003960d2013-04-20 23:12:17 +010051 TrueType& testStreamable( std::ostream& );
52 FalseType testStreamable( FalseType );
Phil Nashf3d1f082013-07-03 19:14:59 +010053
Phil Nash003960d2013-04-20 23:12:17 +010054 FalseType operator<<( std::ostream const&, BorgType const& );
Phil Nash2efc1142012-05-15 07:42:26 +010055
Phil Nash003960d2013-04-20 23:12:17 +010056 template<typename T>
57 struct IsStreamInsertable {
58 static std::ostream &s;
Phil Nash2a9d8d92013-04-23 18:58:56 +010059 static T const&t;
Phil Nash003960d2013-04-20 23:12:17 +010060 enum { value = sizeof( testStreamable(s << t) ) == sizeof( TrueType ) };
61 };
Phil Nashf3d1f082013-07-03 19:14:59 +010062
Phil Nash003960d2013-04-20 23:12:17 +010063#endif
64
65 template<bool C>
66 struct StringMakerBase {
67 template<typename T>
68 static std::string convert( T const& ) { return "{?}"; }
69 };
70
71 template<>
72 struct StringMakerBase<true> {
73 template<typename T>
74 static std::string convert( T const& _value ) {
75 std::ostringstream oss;
76 oss << _value;
77 return oss.str();
78 }
Phil Nash81a122e2012-05-08 08:10:49 +010079 };
Phil Nashf3d1f082013-07-03 19:14:59 +010080
Phil Nash767f1582013-03-04 12:19:15 +010081} // end namespace Detail
82
Phil Nash767f1582013-03-04 12:19:15 +010083template<typename T>
Phil Nash1e2f1d12013-09-14 19:58:45 +010084std::string toString( T const& value );
85
86template<typename T>
Phil Nash003960d2013-04-20 23:12:17 +010087struct StringMaker :
88 Detail::StringMakerBase<Detail::IsStreamInsertable<T>::value> {};
Phil Nash5062d3e2013-04-16 22:55:31 +010089
Phil Nash767f1582013-03-04 12:19:15 +010090template<typename T>
91struct StringMaker<T*> {
Phil Nash503d5d02013-07-03 08:25:11 +010092 template<typename U>
93 static std::string convert( U* p ) {
Phil Nash81a122e2012-05-08 08:10:49 +010094 if( !p )
95 return INTERNAL_CATCH_STRINGIFY( NULL );
96 std::ostringstream oss;
97 oss << p;
98 return oss.str();
Phil Nash767f1582013-03-04 12:19:15 +010099 }
100};
Phil Nash81a122e2012-05-08 08:10:49 +0100101
Andy Sawyer0dbcf212013-09-17 22:22:47 +0100102namespace Detail {
103 template<typename InputIterator>
Andy Sawyerd6f23a92013-09-21 18:45:42 +0100104 std::string rangeToString( InputIterator first, InputIterator last );
Andy Sawyer0dbcf212013-09-17 22:22:47 +0100105}
106
107template<typename T, typename Allocator>
108struct StringMaker<std::vector<T, Allocator> > {
109 static std::string convert( std::vector<T,Allocator> const& v ) {
110 return Detail::rangeToString( v.begin(), v.end() );
111 }
Phil Nash767f1582013-03-04 12:19:15 +0100112};
Phil Nash81a122e2012-05-08 08:10:49 +0100113
Phil Nash767f1582013-03-04 12:19:15 +0100114namespace Detail {
115 template<typename T>
Phil Nash2a9d8d92013-04-23 18:58:56 +0100116 inline std::string makeString( T const& value ) {
Phil Nash767f1582013-03-04 12:19:15 +0100117 return StringMaker<T>::convert( value );
Phil Nashf3d1f082013-07-03 19:14:59 +0100118 }
Phil Nash81a122e2012-05-08 08:10:49 +0100119} // end namespace Detail
120
121/// \brief converts any type to a string
122///
Phil Nashf3d1f082013-07-03 19:14:59 +0100123/// The default template forwards on to ostringstream - except when an
124/// ostringstream overload does not exist - in which case it attempts to detect
Phil Nash81a122e2012-05-08 08:10:49 +0100125/// that and writes {?}.
126/// Overload (not specialise) this template for custom typs that you don't want
127/// to provide an ostream overload for.
128template<typename T>
Phil Nash2a9d8d92013-04-23 18:58:56 +0100129std::string toString( T const& value ) {
Phil Nash767f1582013-03-04 12:19:15 +0100130 return StringMaker<T>::convert( value );
Phil Nash81a122e2012-05-08 08:10:49 +0100131}
Phil Nashf3d1f082013-07-03 19:14:59 +0100132
Phil Nash81a122e2012-05-08 08:10:49 +0100133// Built in overloads
134
Phil Nash2a9d8d92013-04-23 18:58:56 +0100135inline std::string toString( std::string const& value ) {
Phil Nash81a122e2012-05-08 08:10:49 +0100136 return "\"" + value + "\"";
137}
138
Phil Nash2a9d8d92013-04-23 18:58:56 +0100139inline std::string toString( std::wstring const& value ) {
Phil Nash81a122e2012-05-08 08:10:49 +0100140 std::ostringstream oss;
141 oss << "\"";
142 for(size_t i = 0; i < value.size(); ++i )
143 oss << static_cast<char>( value[i] <= 0xff ? value[i] : '?');
144 oss << "\"";
145 return oss.str();
146}
147
148inline std::string toString( const char* const value ) {
149 return value ? Catch::toString( std::string( value ) ) : std::string( "{null string}" );
Phil Nashf3d1f082013-07-03 19:14:59 +0100150}
Phil Nash81a122e2012-05-08 08:10:49 +0100151
152inline std::string toString( char* const value ) {
153 return Catch::toString( static_cast<const char*>( value ) );
Phil Nashf3d1f082013-07-03 19:14:59 +0100154}
Phil Nash81a122e2012-05-08 08:10:49 +0100155
156inline std::string toString( int value ) {
157 std::ostringstream oss;
158 oss << value;
159 return oss.str();
160}
161
162inline std::string toString( unsigned long value ) {
163 std::ostringstream oss;
164 if( value > 8192 )
165 oss << "0x" << std::hex << value;
166 else
167 oss << value;
168 return oss.str();
169}
Phil Nashf3d1f082013-07-03 19:14:59 +0100170
Phil Nash81a122e2012-05-08 08:10:49 +0100171inline std::string toString( unsigned int value ) {
Phil Nash8d692082012-05-11 19:05:53 +0100172 return toString( static_cast<unsigned long>( value ) );
Phil Nash81a122e2012-05-08 08:10:49 +0100173}
Phil Nashf3d1f082013-07-03 19:14:59 +0100174
Phil Nash81a122e2012-05-08 08:10:49 +0100175inline std::string toString( const double value ) {
176 std::ostringstream oss;
Phil Nash2ddb9d32013-08-15 18:39:55 +0100177 oss << std::setprecision( 10 )
178 << std::fixed
Phil Nash767f1582013-03-04 12:19:15 +0100179 << value;
Phil Nash2ddb9d32013-08-15 18:39:55 +0100180 std::string d = oss.str();
181 std::size_t i = d.find_last_not_of( '0' );
182 if( i != std::string::npos && i != d.size()-1 ) {
183 if( d[i] == '.' )
184 i++;
185 d = d.substr( 0, i+1 );
186 }
187 return d;
Phil Nashf3d1f082013-07-03 19:14:59 +0100188}
Phil Nash81a122e2012-05-08 08:10:49 +0100189
190inline std::string toString( bool value ) {
191 return value ? "true" : "false";
192}
193
Phil Nash78372d02012-06-06 08:06:40 +0100194inline std::string toString( char value ) {
195 return value < ' '
Phil Nash86ad6342012-12-14 07:49:18 +0000196 ? toString( static_cast<unsigned int>( value ) )
Phil Nash78372d02012-06-06 08:06:40 +0100197 : Detail::makeString( value );
198}
199
200inline std::string toString( signed char value ) {
201 return toString( static_cast<char>( value ) );
202}
203
Phil Nash86ad6342012-12-14 07:49:18 +0000204inline std::string toString( unsigned char value ) {
205 return toString( static_cast<char>( value ) );
206}
207
Phil Nash5ec53b22012-05-10 07:58:48 +0100208#ifdef CATCH_CONFIG_CPP11_NULLPTR
Konrad Rudolph84434be2012-05-23 11:22:49 +0100209inline std::string toString( std::nullptr_t ) {
Phil Nash5ec53b22012-05-10 07:58:48 +0100210 return "nullptr";
211}
212#endif
213
Phil Nash0dc9e432012-08-01 08:17:07 +0100214#ifdef __OBJC__
Phil Nash0dc9e432012-08-01 08:17:07 +0100215 inline std::string toString( NSString const * const& nsstring ) {
Phil Nash32e70b22013-03-12 18:49:22 +0000216 if( !nsstring )
217 return "nil";
Phil Nash0dc9e432012-08-01 08:17:07 +0100218 return std::string( "@\"" ) + [nsstring UTF8String] + "\"";
219 }
220 inline std::string toString( NSString * CATCH_ARC_STRONG const& nsstring ) {
Phil Nash32e70b22013-03-12 18:49:22 +0000221 if( !nsstring )
222 return "nil";
Phil Nash0dc9e432012-08-01 08:17:07 +0100223 return std::string( "@\"" ) + [nsstring UTF8String] + "\"";
224 }
225 inline std::string toString( NSObject* const& nsObject ) {
226 return toString( [nsObject description] );
227 }
228#endif
229
Andy Sawyerd6f23a92013-09-21 18:45:42 +0100230 namespace Detail {
231 template<typename InputIterator>
232 std::string rangeToString( InputIterator first, InputIterator last ) {
233 std::ostringstream oss;
234 oss << "{ ";
235 if( first != last ) {
236 oss << toString( *first );
237 for( ++first ; first != last ; ++first ) {
238 oss << ", " << toString( *first );
239 }
240 }
241 oss << " }";
242 return oss.str();
243 }
244}
245
Phil Nash81a122e2012-05-08 08:10:49 +0100246} // end namespace Catch
247
248#endif // TWOBLUECUBES_CATCH_TOSTRING_HPP_INCLUDED