-
Notifications
You must be signed in to change notification settings - Fork 17
/
stupidunit.h
174 lines (138 loc) · 5.69 KB
/
stupidunit.h
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
// A stupid and simple unit test framework for C++ code.
// Evan Jones <[email protected]>
#ifndef STUPIDUNIT_H__
#define STUPIDUNIT_H__
#include <cstdlib>
#include <string>
#include <vector>
class Test;
// Contains and runs a collection of tests.
class TestSuite {
public:
void registerTest(Test* (*test_factory)());
// Returns the number of failed tests.
int runAll();
// Returns a properly initialized static global TestSuite. This is the "standard" test suite
// used by the TEST and TEST_F macros.
static TestSuite* globalInstance();
private:
std::vector<Test* (*)()> test_factories_;
};
// Base class for a single test. Each test creates a subclass of this that
// implements run(). Users create subclasses via the TEST_F helper macro.
class Test {
public:
Test() {}
virtual ~Test() {}
// Run the actual test.
virtual void run() = 0;
virtual const char* suiteName() const = 0;
virtual const char* testName() const = 0;
bool testSuccess() const { return errors_.empty(); }
// Fail the test with error.
void fail(const char* file, int line, const char* message);
// Output the errors for this test to standard output.
void printErrors() const;
int stupidunitNumErrors() const { return static_cast<int>(errors_.size()); }
const std::string& stupidunitError(size_t i) const;
private:
// Contains error messages if the test failed.
std::vector<std::string> errors_;
};
// A class used to statically register test instances with the global test suite.
template <typename T>
class RegisterTest {
public:
RegisterTest(TestSuite* suite) {
suite->registerTest(&RegisterTest<T>::create);
}
static Test* create() {
return new T();
}
};
// Creates a test subclass.
#define MAGIC_TEST_MACRO(parent_class, suite_name, test_name) \
class suite_name ## _ ## test_name : public parent_class { \
public: \
virtual ~suite_name ## _ ## test_name() {} \
virtual void run(); \
virtual const char* suiteName() const { return suite_name_; } \
virtual const char* testName() const { return test_name_; } \
\
private: \
static const char suite_name_[]; \
static const char test_name_[]; \
}; \
const char suite_name ## _ ## test_name::suite_name_[] = #suite_name; \
const char suite_name ## _ ## test_name::test_name_[] = #test_name; \
static RegisterTest<suite_name ## _ ## test_name> suite_name ## _ ## test_name ## _register(TestSuite::globalInstance()); \
void suite_name ## _ ## test_name::run()
// A magic macro to make a test part of a user-defined test subclass.
#define TEST_F(harness_name, test_name) MAGIC_TEST_MACRO(harness_name, harness_name, test_name)
// A magic macro to make a test subclass for a block of code.
#define TEST(suite_name, test_name) MAGIC_TEST_MACRO(Test, suite_name, test_name)
// Abuse macros to easily define all the EXPECT and ASSERT variants
#define STUPIDUNIT_MAKE_EXPECT_MACRO(operation, one, two) do { \
if (!((one) operation (two))) fail(__FILE__, __LINE__, #one " " #operation " " #two); \
} while (0)
#define EXPECT_EQ(one, two) STUPIDUNIT_MAKE_EXPECT_MACRO(==, one, two)
#define EXPECT_NE(one, two) STUPIDUNIT_MAKE_EXPECT_MACRO(!=, one, two)
#define EXPECT_LT(one, two) STUPIDUNIT_MAKE_EXPECT_MACRO(<, one, two)
#define EXPECT_LE(one, two) STUPIDUNIT_MAKE_EXPECT_MACRO(<=, one, two)
#define EXPECT_GT(one, two) STUPIDUNIT_MAKE_EXPECT_MACRO(>, one, two)
#define EXPECT_GE(one, two) STUPIDUNIT_MAKE_EXPECT_MACRO(>=, one, two)
#define EXPECT_TRUE(value) do { \
if (!(value)) fail(__FILE__, __LINE__, "Expected true; " #value " is false"); \
} while (0)
#define EXPECT_FALSE(value) do { \
if ((value)) fail(__FILE__, __LINE__, "Expected false; " #value " is true"); \
} while (0)
// The only difference between EXPECT and ASSERT is that ASSERT returns from
// the test method if the test fails
#define STUPIDUNIT_MAKE_ASSERT_MACRO(operation, one, two) do { \
if (!((one) operation (two))) { fail(__FILE__, __LINE__, #one " " #operation " " #two); return; } \
} while (0)
#define ASSERT_EQ(one, two) STUPIDUNIT_MAKE_ASSERT_MACRO(==, one, two)
#define ASSERT_NE(one, two) STUPIDUNIT_MAKE_ASSERT_MACRO(!=, one, two)
#define ASSERT_LT(one, two) STUPIDUNIT_MAKE_ASSERT_MACRO(<, one, two)
#define ASSERT_LE(one, two) STUPIDUNIT_MAKE_ASSERT_MACRO(<=, one, two)
#define ASSERT_GT(one, two) STUPIDUNIT_MAKE_ASSERT_MACRO(>, one, two)
#define ASSERT_GE(one, two) STUPIDUNIT_MAKE_ASSERT_MACRO(>=, one, two)
#define ASSERT_TRUE(value) do { \
if (!(value)) { fail(__FILE__, __LINE__, "Expected true; " #value " is false"); return; } \
} while (0)
#define ASSERT_FALSE(value) do { \
if ((value)) { fail(__FILE__, __LINE__, "Expected false; " #value " is true"); return; } \
} while (0)
namespace stupidunit {
enum ExpectDeathStatus {
// The caller is the child: run the block and exit.
EXECUTE_BLOCK,
SUCCESS,
FAILED
};
// Implements EXPECT_DEATH.
ExpectDeathStatus expectDeath();
// Helper that creates a temporary directory then changes into it. The
// directory will be automatically removed in the destructor.
class ChTempDir {
public:
ChTempDir();
~ChTempDir();
const std::string& name() const { return name_; }
private:
// The name of the temporary directory.
std::string name_;
};
extern const char OUT_FILE_ENVIRONMENT_VARIABLE[];
} // namespace stupidunit
#define EXPECT_DEATH(block) do { \
stupidunit::ExpectDeathStatus status = stupidunit::expectDeath(); \
if (status == stupidunit::EXECUTE_BLOCK) { \
block; \
exit(0); \
} else if (status == stupidunit::FAILED) { \
fail(__FILE__, __LINE__, "EXPECT_DEATH(" #block "): did not die"); \
} \
} while (0)
#endif // STUPIDUNIT_H__