mirror of
https://github.com/catchorg/Catch2.git
synced 2025-08-01 12:55:40 +02:00
Add stringification for std::chrono::{duration,time_point}
Also hides std::chrono, std::pair and std::chrono::* behind new configuration macros, CATCH_CONFIG_ENABLE_*_STRINGMAKER to avoid dragging in <utility>, <tuple> and <chrono> in common path, unless requested.
This commit is contained in:
@@ -12,7 +12,6 @@
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
#include <cstddef>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <string>
|
||||
|
||||
@@ -57,7 +56,7 @@ namespace Catch {
|
||||
public:
|
||||
static const bool value = decltype(test<std::ostream, const T&>(0))::value;
|
||||
};
|
||||
|
||||
|
||||
} // namespace Detail
|
||||
|
||||
// If we decide for C++14, change these to enable_if_ts
|
||||
@@ -241,7 +240,53 @@ namespace Catch {
|
||||
}
|
||||
};
|
||||
|
||||
// === Pair ===
|
||||
template<typename T>
|
||||
struct EnumStringMaker {
|
||||
static std::string convert(const T& t) {
|
||||
return ::Catch::Detail::stringify(static_cast<typename std::underlying_type<T>::type>(t));
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef __OBJC__
|
||||
template<>
|
||||
struct StringMaker<NSString*> {
|
||||
static std::string convert(NSString * nsstring) {
|
||||
if (!nsstring)
|
||||
return "nil";
|
||||
return std::string("@") + [nsstring UTF8String];
|
||||
}
|
||||
};
|
||||
template<>
|
||||
struct StringMaker<NSObject*> {
|
||||
static std::string convert(NSObject* nsObject) {
|
||||
return ::Catch::Detail::stringify([nsObject description]);
|
||||
}
|
||||
|
||||
};
|
||||
namespace Detail {
|
||||
inline std::string stringify( NSString* nsstring ) {
|
||||
return StringMaker<NSString*>::convert( nsstring );
|
||||
}
|
||||
|
||||
} // namespace Detail
|
||||
#endif // __OBJC__
|
||||
|
||||
} // namespace Catch
|
||||
|
||||
//////////////////////////////////////////////////////
|
||||
// Separate std-lib types stringification, so it can be selectively enabled
|
||||
// This means that we do not bring in
|
||||
|
||||
#if defined(CATCH_CONFIG_ENABLE_ALL_STRINGMAKERS)
|
||||
# define CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER
|
||||
# define CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER
|
||||
# define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER
|
||||
#endif
|
||||
|
||||
// Separate std::pair specialization
|
||||
#if defined(CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER)
|
||||
#include <utility>
|
||||
namespace Catch {
|
||||
template<typename T1, typename T2>
|
||||
struct StringMaker<std::pair<T1, T2> > {
|
||||
static std::string convert(const std::pair<T1, T2>& pair) {
|
||||
@@ -254,9 +299,13 @@ namespace Catch {
|
||||
return oss.str();
|
||||
}
|
||||
};
|
||||
}
|
||||
#endif // CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER
|
||||
|
||||
|
||||
|
||||
// Separate std::tuple specialization
|
||||
#if defined(CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER)
|
||||
#include <tuple>
|
||||
namespace Catch {
|
||||
namespace Detail {
|
||||
template<
|
||||
typename Tuple,
|
||||
@@ -292,40 +341,126 @@ namespace Catch {
|
||||
return os.str();
|
||||
}
|
||||
};
|
||||
}
|
||||
#endif // CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER
|
||||
|
||||
|
||||
template<typename T>
|
||||
struct EnumStringMaker {
|
||||
static std::string convert(const T& t) {
|
||||
return ::Catch::Detail::stringify(static_cast<typename std::underlying_type<T>::type>(t));
|
||||
// Separate std::chrono::duration specialization
|
||||
#if defined(CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER)
|
||||
#include <chrono>
|
||||
|
||||
#include <ratio>
|
||||
|
||||
template <class Ratio>
|
||||
struct ratio_string {
|
||||
static std::string symbol();
|
||||
};
|
||||
|
||||
template <class Ratio>
|
||||
std::string ratio_string<Ratio>::symbol() {
|
||||
std::ostringstream oss;
|
||||
oss << '[' << Ratio::num << '/'
|
||||
<< Ratio::den << ']';
|
||||
return oss.str();
|
||||
}
|
||||
template <>
|
||||
struct ratio_string<std::atto> {
|
||||
static std::string symbol() { return "a"; }
|
||||
};
|
||||
template <>
|
||||
struct ratio_string<std::femto> {
|
||||
static std::string symbol() { return "f"; }
|
||||
};
|
||||
template <>
|
||||
struct ratio_string<std::pico> {
|
||||
static std::string symbol() { return "p"; }
|
||||
};
|
||||
template <>
|
||||
struct ratio_string<std::nano> {
|
||||
static std::string symbol() { return "n"; }
|
||||
};
|
||||
template <>
|
||||
struct ratio_string<std::micro> {
|
||||
static std::string symbol() { return "u"; }
|
||||
};
|
||||
template <>
|
||||
struct ratio_string<std::milli> {
|
||||
static std::string symbol() { return "m"; }
|
||||
};
|
||||
|
||||
namespace Catch {
|
||||
////////////
|
||||
// std::chrono::duration specializations
|
||||
template<typename Value, typename Ratio>
|
||||
struct StringMaker<std::chrono::duration<Value, Ratio>> {
|
||||
static std::string convert(std::chrono::duration<Value, Ratio> const& duration) {
|
||||
std::ostringstream oss;
|
||||
oss << duration.count() << ' ' << ratio_string<Ratio>::symbol() << 's';
|
||||
return oss.str();
|
||||
}
|
||||
};
|
||||
template<typename Value>
|
||||
struct StringMaker<std::chrono::duration<Value, std::ratio<1>>> {
|
||||
static std::string convert(std::chrono::duration<Value, std::ratio<1>> const& duration) {
|
||||
std::ostringstream oss;
|
||||
oss << duration.count() << " s";
|
||||
return oss.str();
|
||||
}
|
||||
};
|
||||
template<typename Value>
|
||||
struct StringMaker<std::chrono::duration<Value, std::ratio<60>>> {
|
||||
static std::string convert(std::chrono::duration<Value, std::ratio<60>> const& duration) {
|
||||
std::ostringstream oss;
|
||||
oss << duration.count() << " m";
|
||||
return oss.str();
|
||||
}
|
||||
};
|
||||
template<typename Value>
|
||||
struct StringMaker<std::chrono::duration<Value, std::ratio<3600>>> {
|
||||
static std::string convert(std::chrono::duration<Value, std::ratio<3600>> const& duration) {
|
||||
std::ostringstream oss;
|
||||
oss << duration.count() << " h";
|
||||
return oss.str();
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef __OBJC__
|
||||
template<>
|
||||
struct StringMaker<NSString*> {
|
||||
static std::string convert(NSString * nsstring) {
|
||||
if (!nsstring)
|
||||
return "nil";
|
||||
return std::string("@") + [nsstring UTF8String];
|
||||
////////////
|
||||
// std::chrono::time_point specialization
|
||||
// Generic time_point cannot be specialized, only std::chrono::time_point<system_clock>
|
||||
template<typename Clock, typename Duration>
|
||||
struct StringMaker<std::chrono::time_point<Clock, Duration>> {
|
||||
static std::string convert(std::chrono::time_point<Clock, Duration> const& time_point) {
|
||||
return ::Catch::Detail::stringify(time_point.time_since_epoch()) + " since epoch";
|
||||
}
|
||||
};
|
||||
template<>
|
||||
struct StringMaker<NSObject*> {
|
||||
static std::string convert(NSObject* nsObject) {
|
||||
return ::Catch::Detail::stringify([nsObject description]);
|
||||
}
|
||||
// std::chrono::time_point<system_clock> specialization
|
||||
template<typename Duration>
|
||||
struct StringMaker<std::chrono::time_point<std::chrono::system_clock, Duration>> {
|
||||
static std::string convert(std::chrono::time_point<std::chrono::system_clock, Duration> const& time_point) {
|
||||
auto converted = std::chrono::system_clock::to_time_t(time_point);
|
||||
|
||||
#ifdef _MSC_VER
|
||||
std::tm timeInfo = {};
|
||||
gmtime_s(&timeInfo, &converted);
|
||||
#else
|
||||
std::tm* timeInfo = std::gmtime(&converted);
|
||||
#endif
|
||||
|
||||
auto const timeStampSize = sizeof("2017-01-16T17:06:45Z");
|
||||
char timeStamp[timeStampSize];
|
||||
const char * const fmt = "%Y-%m-%dT%H:%M:%SZ";
|
||||
|
||||
#ifdef _MSC_VER
|
||||
std::strftime(timeStamp, timeStampSize, fmt, &timeInfo);
|
||||
#else
|
||||
std::strftime(timeStamp, timeStampSize, fmt, timeInfo);
|
||||
#endif
|
||||
return std::string(timeStamp);
|
||||
}
|
||||
};
|
||||
namespace Detail {
|
||||
inline std::string stringify( NSString* nsstring ) {
|
||||
return StringMaker<NSString*>::convert( nsstring );
|
||||
}
|
||||
}
|
||||
#endif // CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER
|
||||
|
||||
} // namespace Detail
|
||||
#endif // __OBJC__
|
||||
|
||||
} // namespace Catch
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
|
Reference in New Issue
Block a user