8#ifndef TWOBLUECUBES_CATCH_TOSTRING_H_INCLUDED
9#define TWOBLUECUBES_CATCH_TOSTRING_H_INCLUDED
20#ifdef CATCH_CONFIG_CPP17_STRING_VIEW
30#pragma warning(disable:4180)
46 class IsStreamInsertable {
47 template<
typename SS,
typename TT>
49 ->
decltype(std::declval<SS&>() << std::declval<TT>(), std::true_type());
51 template<
typename,
typename>
52 static auto test(...)->std::false_type;
55 static const bool value =
decltype(test<std::ostream, const T&>(0))
::value;
62 typename std::enable_if<
63 !std::is_enum<T>::value && !std::is_base_of<std::exception, T>::value,
68 typename std::enable_if<
69 !std::is_enum<T>::value && std::is_base_of<std::exception, T>::value,
76 typename std::enable_if<
77 std::is_enum<T>::value
85 std::string clrReferenceToString(
T^ ref ) {
87 return std::string(
"null");
88 auto bytes = System::Text::Encoding::UTF8->GetBytes(ref->ToString());
89 cli::pin_ptr<System::Byte>
p = &bytes[0];
90 return std::string(
reinterpret_cast<char const *
>(
p), bytes->Length);
98 template <
typename T,
typename =
void>
100 template <
typename Fake = T>
102 typename std::enable_if<::Catch::Detail::IsStreamInsertable<Fake>::value, std::string>::type
107 rss.operator<<(
value);
111 template <
typename Fake = T>
113 typename std::enable_if<!::Catch::Detail::IsStreamInsertable<Fake>::value, std::string>::type
115#if !defined(CATCH_CONFIG_FALLBACK_STRINGIFIER)
127 template <
typename T>
129 return ::Catch::StringMaker<typename std::remove_cv<typename std::remove_reference<T>::type>::type>::convert(e);
134 return ::Catch::Detail::stringify(
static_cast<typename std::underlying_type<E>::type
>(e));
138 template <
typename T>
140 return ::Catch::StringMaker<T^>::convert(e);
149 struct StringMaker<
std::string> {
150 static std::string
convert(
const std::string& str);
153#ifdef CATCH_CONFIG_CPP17_STRING_VIEW
155 struct StringMaker<
std::string_view> {
156 static std::string
convert(std::string_view str);
161 struct StringMaker<char const *> {
166 static std::string convert(
char * str);
169#ifdef CATCH_CONFIG_WCHAR
171 struct StringMaker<
std::wstring> {
172 static std::string
convert(
const std::wstring& wstr);
175# ifdef CATCH_CONFIG_CPP17_STRING_VIEW
177 struct StringMaker<
std::wstring_view> {
178 static std::string
convert(std::wstring_view str);
183 struct StringMaker<wchar_t const *> {
184 static std::string
convert(
wchar_t const * str);
188 static std::string convert(
wchar_t * str);
195 struct StringMaker<char[SZ]> {
197 return ::Catch::Detail::stringify(std::string{ str });
201 struct StringMaker<signed char[SZ]> {
202 static std::string
convert(
signed char const* str) {
203 return ::Catch::Detail::stringify(std::string{
reinterpret_cast<char const *
>(str) });
207 struct StringMaker<unsigned char[SZ]> {
208 static std::string
convert(
unsigned char const* str) {
209 return ::Catch::Detail::stringify(std::string{
reinterpret_cast<char const *
>(str) });
214 struct StringMaker<int> {
218 struct StringMaker<long> {
222 struct StringMaker<long long> {
240 static std::string
convert(
bool b);
244 struct StringMaker<char> {
245 static std::string
convert(
char c);
248 struct StringMaker<signed char> {
258 static std::string
convert(std::nullptr_t);
262 struct StringMaker<float> {
266 struct StringMaker<double> {
270 template <
typename T>
271 struct StringMaker<
T*> {
272 template <
typename U>
275 return ::Catch::Detail::rawMemoryToString(
p);
282 template <
typename R,
typename C>
283 struct StringMaker<
R C::*> {
286 return ::Catch::Detail::rawMemoryToString(
p);
294 template <
typename T>
295 struct StringMaker<
T^> {
296 static std::string convert(
T^ ref ) {
297 return ::Catch::Detail::clrReferenceToString(ref);
303 template<
typename InputIterator>
309 for (++first; first != last; ++first)
319 struct StringMaker<NSString*> {
320 static std::string convert(NSString * nsstring) {
323 return std::string(
"@") + [nsstring UTF8String];
327 struct StringMaker<NSObject*> {
328 static std::string convert(NSObject* nsObject) {
329 return ::Catch::Detail::stringify([nsObject description]);
334 inline std::string
stringify( NSString* nsstring ) {
347#if defined(CATCH_CONFIG_ENABLE_ALL_STRINGMAKERS)
348# define CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER
349# define CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER
350# define CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER
351# define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER
352# define CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER
356#if defined(CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER)
359 template<
typename T1,
typename T2>
360 struct StringMaker<
std::pair<T1, T2> > {
361 static std::string
convert(
const std::pair<T1, T2>& pair) {
362 ReusableStringStream rss;
374#if defined(CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER) && defined(CATCH_CONFIG_CPP17_OPTIONAL)
378 struct StringMaker<
std::optional<T> > {
379 static std::string
convert(
const std::optional<T>& optional) {
380 ReusableStringStream rss;
381 if (optional.has_value()) {
393#if defined(CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER)
400 bool = (N < std::tuple_size<Tuple>::value)
402 struct TupleElementPrinter {
403 static void print(
const Tuple& tuple, std::ostream&
os) {
404 os << (
N ?
", " :
" ")
406 TupleElementPrinter<Tuple, N + 1>::print(tuple,
os);
414 struct TupleElementPrinter<Tuple,
N, false> {
415 static void print(
const Tuple&, std::ostream&) {}
421 template<
typename ...Types>
422 struct StringMaker<
std::tuple<Types...>> {
423 static std::string
convert(
const std::tuple<Types...>& tuple) {
424 ReusableStringStream rss;
426 Detail::TupleElementPrinter<std::tuple<Types...>>
::print(tuple, rss.get());
434#if defined(CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER) && defined(CATCH_CONFIG_CPP17_VARIANT)
438 struct StringMaker<
std::monostate> {
439 static std::string
convert(
const std::monostate&) {
444 template<
typename... Elements>
445 struct StringMaker<
std::variant<Elements...>> {
446 static std::string
convert(
const std::variant<Elements...>& variant) {
447 if (variant.valueless_by_exception()) {
448 return "{valueless variant}";
451 [](
const auto&
value) {
452 return ::Catch::Detail::stringify(
value);
463 struct not_this_one {};
469 not_this_one
begin( ... );
470 not_this_one
end( ... );
472 template <
typename T>
480 template <
typename T>
482 static const bool value =
false;
486 template<
typename Range>
488 return ::Catch::Detail::rangeToString(
begin( range ),
end( range ) );
492 template<
typename Allocator>
509 struct StringMaker<
R, typename
std::enable_if<is_range<R>::value && !::Catch::Detail::IsStreamInsertable<R>::value>::type> {
515 template <
typename T,
int SZ>
516 struct StringMaker<
T[SZ]> {
526#if defined(CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER)
534template <
class Ratio>
536 static std::string symbol();
539template <
class Ratio>
540std::string ratio_string<Ratio>::symbol() {
542 rss <<
'[' << Ratio::num <<
'/'
543 << Ratio::den <<
']';
547struct ratio_string<
std::atto> {
548 static std::string symbol();
551struct ratio_string<
std::femto> {
552 static std::string symbol();
555struct ratio_string<
std::pico> {
556 static std::string symbol();
559struct ratio_string<
std::nano> {
560 static std::string symbol();
563struct ratio_string<
std::micro> {
564 static std::string symbol();
567struct ratio_string<
std::milli> {
568 static std::string symbol();
573 template<
typename Value,
typename Ratio>
574 struct StringMaker<
std::chrono::duration<Value, Ratio>> {
575 static std::string
convert(std::chrono::duration<Value, Ratio>
const& duration) {
576 ReusableStringStream rss;
577 rss << duration.count() <<
' ' << ratio_string<Ratio>::symbol() <<
's';
581 template<
typename Value>
582 struct StringMaker<
std::chrono::duration<Value, std::ratio<1>>> {
583 static std::string
convert(std::chrono::duration<
Value, std::ratio<1>>
const& duration) {
584 ReusableStringStream rss;
585 rss << duration.count() <<
" s";
589 template<
typename Value>
590 struct StringMaker<
std::chrono::duration<Value, std::ratio<60>>> {
591 static std::string
convert(std::chrono::duration<
Value, std::ratio<60>>
const& duration) {
592 ReusableStringStream rss;
593 rss << duration.count() <<
" m";
597 template<
typename Value>
598 struct StringMaker<
std::chrono::duration<Value, std::ratio<3600>>> {
599 static std::string
convert(std::chrono::duration<
Value, std::ratio<3600>>
const& duration) {
600 ReusableStringStream rss;
601 rss << duration.count() <<
" h";
609 template<
typename Clock,
typename Duration>
610 struct StringMaker<
std::chrono::time_point<Clock, Duration>> {
611 static std::string
convert(std::chrono::time_point<Clock, Duration>
const& time_point) {
616 template<
typename Duration>
617 struct StringMaker<
std::chrono::time_point<std::chrono::system_clock, Duration>> {
618 static std::string
convert(std::chrono::time_point<std::chrono::system_clock, Duration>
const& time_point) {
619 auto converted = std::chrono::system_clock::to_time_t(time_point);
622 std::tm timeInfo = {};
623 gmtime_s(&timeInfo, &converted);
625 std::tm* timeInfo = std::gmtime(&converted);
628 auto const timeStampSize =
sizeof(
"2017-01-16T17:06:45Z");
629 char timeStamp[timeStampSize];
630 const char *
const fmt =
"%Y-%m-%dT%H:%M:%SZ";
633 std::strftime(timeStamp, timeStampSize, fmt, &timeInfo);
635 std::strftime(timeStamp, timeStampSize, fmt, timeInfo);
637 return std::string(timeStamp);
643#define INTERNAL_CATCH_REGISTER_ENUM( enumName, ... ) \
645 template<> struct StringMaker<enumName> { \
646 static std::string convert( enumName value ) { \
647 static const auto& enumInfo = ::Catch::getMutableRegistryHub().getMutableEnumValuesRegistry().registerEnum( #enumName, #__VA_ARGS__, { __VA_ARGS__ } ); \
648 return enumInfo.lookup( static_cast<int>( value ) ); \
653#define CATCH_REGISTER_ENUM( enumName, ... ) INTERNAL_CATCH_REGISTER_ENUM( enumName, __VA_ARGS__ )
void print(std::ostream &os, int const level, std::string const &title, Catch::SourceLineInfo const &info)
#define CATCH_CONFIG_FALLBACK_STRINGIFIER
auto str() const -> std::string
constexpr const microseconds & time_since_epoch() const
std::string convertUnknownEnumToString(E e)
const std::string unprintableString
std::string rangeToString(InputIterator first, InputIterator last)
std::enable_if<!std::is_enum< T >::value &&!std::is_base_of< std::exception, T >::value, std::string >::type convertUnstreamable(T const &)
std::string rawMemoryToString(const void *object, std::size_t size)
std::string stringify(const T &e)
std::string rangeToString(Range const &range)
sysio::time_point time_point
#define T(meth, val, expected)
static std::string convert(R const &range)
static std::string convert(R C::*p)
static std::string convert(U *p)
static std::string convert(T const(&arr)[SZ])
static std::string convert(char const *str)
static std::string convert(char const *str)
static std::string convert(long long value)
static std::string convert(signed char c)
static std::string convert(signed char const *str)
static std::string convert(unsigned char c)
static std::string convert(unsigned char const *str)
static std::string convert(unsigned int value)
static std::string convert(unsigned long value)
static std::string convert(unsigned long long value)
static std::string convert(wchar_t const *str)
static std::enable_if<::Catch::Detail::IsStreamInsertable< Fake >::value, std::string >::type convert(const Fake &value)
static std::enable_if<!::Catch::Detail::IsStreamInsertable< Fake >::value, std::string >::type convert(const Fake &value)