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
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
|
// license:BSD-3-Clause
// copyright-holders:Couriersud
#ifndef PTESTS_H_
#define PTESTS_H_
///
/// \file ptests.h
///
/// google tests compatible (hopefully) test macros. This is work in progress!
///
#include <exception>
#include <functional>
#include <iostream>
#include <string>
#include <vector>
#if defined(__clang__)
#pragma clang diagnostic ignored "-Wglobal-constructors"
#endif
#define PEXPECT_EQ(exp1, exp2) PINT_EXPECT(eq, exp1, exp2)
#define PEXPECT_NE(exp1, exp2) PINT_EXPECT(ne, exp1, exp2)
#define PEXPECT_GT(exp1, exp2) PINT_EXPECT(gt, exp1, exp2)
#define PEXPECT_LT(exp1, exp2) PINT_EXPECT(lt, exp1, exp2)
#define PEXPECT_GE(exp1, exp2) PINT_EXPECT(ge, exp1, exp2)
#define PEXPECT_LE(exp1, exp2) PINT_EXPECT(le, exp1, exp2)
#define PEXPECT_TRUE(exp1) PINT_EXPECT(eq, exp1, true)
#define PEXPECT_FALSE(exp1) PINT_EXPECT(eq, exp1, false)
#define PEXPECT_THROW(exp, excep) PINT_EXPECT_THROW(exp, excep)
#define PEXPECT_NO_THROW(exp) PINT_EXPECT_NO_THROW(exp)
#define PTEST(name, desc) PINT_TEST(name, desc)
#define PTEST_F(name, desc) PINT_TEST_F(name, desc, name)
#define PRUN_ALL_TESTS() plib::testing::run_all_tests()
#define PINT_TEST(name, desc) PINT_TEST_F(name, desc, plib::testing::Test)
#define PINT_TEST_F(name, desc, base) \
class name ## _ ## desc : public base \
{ public:\
void desc (); \
void run() override { desc (); } \
}; \
extern const plib::testing::reg_entry<name ## _ ## desc> name ## _ ## desc ## _reg; \
const plib::testing::reg_entry<name ## _ ## desc> name ## _ ## desc ## _reg(#name, #desc); \
void name ## _ ## desc :: desc ()
#define PINT_EXPECT(comp, exp1, exp2) \
if (!plib::testing::internal_assert(plib::testing::comp_ ## comp (), # exp1, # exp2, exp1, exp2)) \
std::cout << __FILE__ << ":" << __LINE__ << ":1: error: test failed\n"
#define PINT_EXPECT_THROW(exp, excep) \
if (const char *ptest_f = __FILE__) \
{ \
try { exp; std::cout << ptest_f << ":" << __LINE__ << ":1: error: no " #excep " exception thrown\n";} \
catch (excep &) { std::cout << "\tOK: got " #excep " for " # exp "\n";} \
catch (std::exception &ptest_e) { std::cout << ptest_f << ":" << __LINE__ << ":1: error: unexpected exception thrown: " << ptest_e.what() << "\n"; } \
catch (...) { std::cout << ptest_f << ":" << __LINE__ << ":1: error: unexpected exception thrown\n"; } \
} else do {} while (0)
#define PINT_EXPECT_NO_THROW(exp) \
if (const char *ptest_f = __FILE__) \
{ \
try { exp; std::cout << "\tOK: got no exception for " # exp "\n";} \
catch (std::exception &ptest_e) { std::cout << ptest_f << ":" << __LINE__ << ":1: error: unexpected exception thrown: " << ptest_e.what() << "\n"; } \
catch (...) { std::cout << ptest_f << ":" << __LINE__ << ":1: error: unexpected exception thrown\n"; } \
} else do {} while (0)
namespace plib
{
namespace testing
{
class Test
{
public:
Test() = default;
virtual ~Test() = default;
Test(const Test &) = delete;
Test &operator=(const Test &) = delete;
Test(Test &&) = delete;
Test &operator=(Test &&) = delete;
virtual void run() {}
virtual void SetUp() {}
virtual void TearDown() {}
};
struct reg_entry_base
{
using list_t = std::vector<reg_entry_base *>;
reg_entry_base(const std::string &n, const std::string &d)
: name(n), desc(d)
{
registry().push_back(this);
}
reg_entry_base(const reg_entry_base &) = delete;
reg_entry_base &operator=(const reg_entry_base &) = delete;
reg_entry_base(reg_entry_base &&) = delete;
reg_entry_base &operator=(reg_entry_base &&) = delete;
virtual ~reg_entry_base() = default;
virtual Test *create() const { return nullptr; }
std::string name;
std::string desc;
public:
static list_t & registry()
{
static list_t prlist;
return prlist;
}
};
template <typename T>
struct reg_entry : public reg_entry_base
{
using reg_entry_base::reg_entry_base;
Test *create() const override { return new T(); } // NOLINT
};
template <typename C, typename T1, typename T2>
bool internal_assert(C comp,
const char* exp1, const char* exp2,
const T1& val1, const T2& val2)
{
if (comp(val1, val2))
{
std::cout << "\tOK: " << exp1 << " " << C::opstr() << " " << exp2 << "\n";
return true;
}
std::cout << "\tFAIL: " << exp1 << " " << C::opstr() << " " << exp2
<< " <" << val1 << ">,<" << val2 << ">\n";
return false;
}
static inline int run_all_tests()
{
std::cout << "======================================\n";
std::cout << "Running " << reg_entry_base::registry().size() << " tests\n";
std::cout << "======================================\n";
for (auto &e : reg_entry_base::registry())
{
std::cout << e->name << "::" << e->desc << ":\n";
Test *t = e->create();
t->SetUp();
t->run();
t->TearDown();
delete t;
}
return 0;
}
#define DEF_COMP(name, op) \
struct comp_ ## name \
{ \
static const char * opstr() { return #op ; } \
template <typename T1, typename T2> \
bool operator()(const T1 &v1, const T2 &v2) { return v1 op v2; } \
}; \
DEF_COMP(eq, ==)
DEF_COMP(ne, !=)
DEF_COMP(gt, >)
DEF_COMP(lt, <)
DEF_COMP(ge, >=)
DEF_COMP(le, <=)
#undef DEF_COMP
} // namespace testing
} // namespace plib
#endif // PTESTS_H_
|