forked from doctest/doctest
-
Notifications
You must be signed in to change notification settings - Fork 1
/
stringification.cpp
166 lines (134 loc) · 4.06 KB
/
stringification.cpp
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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
#include <doctest/doctest.h>
#include "header.h"
DOCTEST_MAKE_STD_HEADERS_CLEAN_FROM_WARNINGS_ON_WALL_BEGIN
#include <string>
#include <vector>
#include <list>
#include <sstream>
DOCTEST_MAKE_STD_HEADERS_CLEAN_FROM_WARNINGS_ON_WALL_END
DOCTEST_MSVC_SUPPRESS_WARNING(5045) // Spectre mitigation diagnostics
// the standard forbids writing in the std namespace but it works on all compilers
namespace std
{
template <typename T>
ostream& operator<<(ostream& stream, const vector<T>& in) {
stream << "[";
for(size_t i = 0; i < in.size(); ++i)
if(i < in.size() - 1)
stream << in[i] << ", ";
else
stream << in[i];
stream << "]";
return stream;
}
}
// as an alternative you may write a specialization of doctest::StringMaker
namespace doctest
{
template <typename T>
struct StringMaker<std::list<T> >
{
static String convert(const std::list<T>& in) {
std::ostringstream oss;
oss << "[";
for(typename std::list<T>::const_iterator it = in.begin(); it != in.end(); ++it)
oss << *it << ", ";
oss << "]";
return oss.str().c_str();
}
};
}
template <typename T, typename K>
struct MyType
{
T one;
K two;
};
template <typename T>
struct MyTypeInherited : MyType<T, unsigned>
{};
template <typename T, typename K>
bool operator==(const MyType<T, K>& lhs, const MyType<T, K>& rhs) {
return lhs.one == rhs.one && lhs.two == rhs.two;
}
template <typename T, typename K>
std::ostream& operator<<(std::ostream& stream, const MyType<T, K>& in) {
stream << "[" << in.one << ", " << in.two << "]";
return stream;
}
namespace Bar
{
struct Foo
{
friend bool operator==(const Foo&, const Foo&) { return false; }
};
// as a third option you may provide an overload of toString()
inline doctest::String toString(const Foo&) { return "Foo{}"; }
struct MyOtherType
{
int data;
friend bool operator==(const MyOtherType& l, const MyOtherType& r) { return l.data == r.data; }
};
// you also can use a template operator<< if your code does not use std::ostream
template <class OStream>
OStream& operator<<(OStream& stream, const MyOtherType& in) {
stream << "MyOtherType: " << in.data;
return stream;
}
} // namespace Bar
// set an exception translator for MyTypeInherited<int>
REGISTER_EXCEPTION_TRANSLATOR(MyTypeInherited<int>& ex) {
return doctest::String("MyTypeInherited<int>(") + doctest::toString(ex.one) + ", " +
doctest::toString(ex.two) + ")";
}
TEST_CASE("all asserts should fail and show how the objects get stringified") {
MyTypeInherited<int> bla1;
bla1.one = 5;
bla1.two = 4u;
MyTypeInherited<int> bla2;
bla2.one = 5;
bla2.two = 6u;
Bar::Foo f1;
Bar::Foo f2;
CHECK(f1 == f2);
// std::string already has an operator<< working with std::ostream
std::string dummy1 = "omg";
std::string dummy2 = "tralala";
CHECK(dummy1 == dummy2);
std::vector<int> vec1;
vec1.push_back(1);
vec1.push_back(2);
vec1.push_back(3);
std::vector<int> vec2;
vec2.push_back(1);
vec2.push_back(2);
vec2.push_back(4);
CHECK(vec1 == vec2);
std::list<int> lst_1;
lst_1.push_back(1);
lst_1.push_back(42);
lst_1.push_back(3);
std::list<int> lst_2;
lst_2.push_back(1);
lst_2.push_back(2);
lst_2.push_back(666);
CHECK(lst_1 == lst_2);
{
Bar::MyOtherType s1 {42};
Bar::MyOtherType s2 {666};
INFO("s1=", s1, " s2=", s2);
CHECK(s1 == s2);
CHECK_MESSAGE(s1 == s2, s1, " is not really ", s2);
}
// lets see if this exception gets translated
throw_if(true, bla1);
}
static doctest::String intTranslator(int ex) {
return doctest::String("int: ") + doctest::toString(ex);
}
TEST_CASE("a test case that registers an exception translator for int and then throws one") {
// set an exception translator for int - note that this shouldn't be done in a test case but
// in main() or somewhere before executing the tests - but here I'm just lazy...
doctest::registerExceptionTranslator(intTranslator);
throw_if(true, 5);
}