expect.inl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
#ifndef CRUCIBLE_TESTING_EXPECT_INL #define CRUCIBLE_TESTING_EXPECT_INL #include "crucible/testing/expect.hpp" #include <cstdint> #include <cstring> #include <iomanip> #include <memory> #include <ostream> #include <sstream> #include <string> #include <type_traits> #include <typeinfo> namespace crucible::testing::expect { #ifdef _WIN32 constexpr char SOURCE_FILE_PATH_SEPARATOR { '\\' }; #else constexpr char SOURCE_FILE_PATH_SEPARATOR { '/' }; #endif // _WIN32 template<typename, typename = void> struct HasFormatMethod : std::false_type {}; template<typename T> struct HasFormatMethod<T, std::void_t<decltype(std::declval<T>().format())>> : std::true_type {}; template<typename T> constexpr bool has_format_method { HasFormatMethod<T>::value }; template<typename, typename = void> struct HasOstreamInsertion : std::false_type {}; template<typename T> struct HasOstreamInsertion<T, std::void_t<decltype(std::declval<std::ostream &>() << std::declval<T>())>> : std::true_type {}; template<typename T> constexpr bool has_ostream_insertion { HasOstreamInsertion<T>::value }; template<typename, typename = void> struct HasIteration : std::false_type {}; template<typename T> struct HasIteration<T, std::void_t<decltype(std::begin(std::declval<T>())), decltype(std::end(std::declval<T>()))>> : std::true_type {}; template<typename T> constexpr bool has_iteration { HasIteration<T>::value }; template<typename T> auto format_value(T const &value) -> std::string { if constexpr (has_format_method<T>) { return value.format(); } else { std::ostringstream buffer; if constexpr (has_ostream_insertion<T>) { if constexpr (std::is_same_v<T, bool>) { buffer << std::boolalpha << value; } else { buffer << value; } } else if constexpr(has_iteration<T>) { buffer << "{"; auto current { std::begin(value) }; auto const end { std::end(value) }; if (current != end) { buffer << format_value(*current); ++current; } while (current != end) { buffer << ", " << format_value(*current); ++current; } buffer << "}"; } else { std::type_info const &info { typeid(T) }; int const pointer_width { sizeof(void *) * 2 }; auto const pointer { reinterpret_cast<std::uintptr_t>(std::addressof(value)) }; buffer << "<" << info.name() << " " << "object at" << " " << "0x" << std::hex << std::setw(pointer_width) << std::setfill('0') << pointer << ">"; } return buffer.str(); } } template<typename T> auto fail(char const *expression, T const &value, char const *expected, char const *actual, char const *file, int const line, char const *function) -> void { char const *final_path_separator { std::strrchr(file, SOURCE_FILE_PATH_SEPARATOR) }; char const *truncated_file { final_path_separator ? final_path_separator + 1 : file }; std::ostringstream buffer; buffer << truncated_file << ":" << line << " [" << function << "]: " << "Expected `" << expression << "` to be `" << expected << "`, but got `" << actual << "`" << " " << "[`" << expression << "` = `" << format_value(value) << "`]"; throw ExpectFailed(buffer.str()); } template<typename LHS, typename RHS> auto fail_comparison(char const *lhs_expression, char const *rhs_expression, LHS const &lhs_value, RHS const &rhs_value, char const *operation, char const *file, int const line, char const *function) -> void { char const *final_path_separator { std::strrchr(file, SOURCE_FILE_PATH_SEPARATOR) }; char const *truncated_file { final_path_separator ? final_path_separator + 1 : file }; std::ostringstream buffer; buffer << truncated_file << ":" << line << " [" << function << "]:" << " " << "Expected `" << lhs_expression << "` " << operation << " `" << rhs_expression << "`" << " " << "[`" << lhs_expression << "` = `" << format_value(lhs_value) << "`, `" << rhs_expression << "` = `" << format_value(rhs_value) << "`]"; throw ExpectFailed(buffer.str()); } } #endif // CRUCIBLE_TESTING_EXPECT_INL