forked from kudaba/simpletest
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsimpletest.h
More file actions
208 lines (166 loc) · 7.95 KB
/
simpletest.h
File metadata and controls
208 lines (166 loc) · 7.95 KB
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
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
//#pragma once
#ifndef _SIMPLETEST_H_
#define _SIMPLETEST_H_
//---------------------------------------------------------------------------------
// Config
//---------------------------------------------------------------------------------
#if !defined(MESSAGE_SPACE)
//#define MESSAGE_SPACE 10 * 1024 // default 10k of message space is reserved per test
#define MESSAGE_SPACE 100 // default 100 bytes of message space is reserved per test
#endif
#if !defined(STRING_LENGTH)
#define STRING_LENGTH 64 // size of temp strings for converting types
#endif
#if !defined(BASE_FIXTURE)
#define BASE_FIXTURE TestFixture // use TestFixture as the test base class by default
#endif
typedef long long int64;
typedef unsigned int uint;
typedef unsigned long long uint64;
//---------------------------------------------------------------------------------
// Link list of errors build into MESSAGE_SPACE
//---------------------------------------------------------------------------------
struct TestError
{
TestError* next;
char message[1];
};
//---------------------------------------------------------------------------------
// simple converter of basic types to text
// TODO: Use a global template function for conversion so users can override this
//---------------------------------------------------------------------------------
struct TempString
{
TempString() : myTextPointer(myTextBuffer) {}
TempString(const TempString& other);
TempString(char const* string) : myTextPointer(string) {}
char const* operator*() const { return myTextPointer; }
char const* myTextPointer;
char myTextBuffer[STRING_LENGTH];
};
TempString TypeToString(int value);
TempString TypeToString(int64 value);
TempString TypeToString(uint value);
TempString TypeToString(uint64 value);
TempString TypeToString(float value);
TempString TypeToString(double value);
TempString TypeToString(bool value);
TempString TypeToString(char const* value);
TempString TypeToString(void const* value);
inline TempString TypeToString(char* value) { return TypeToString((char const*)value); }
inline TempString TypeToString(void* value) { return TypeToString((void const*)value); }
// if nothing specified then print some memory
template<typename T>
TempString TypeToString(T const&) { return TempString("(unknown type)"); }
template<typename T>
TempString TypeToString(T const* pointer) { return pointer == nullptr ? TempString("(nullptr)") : TypeToString(*pointer); }
template<typename T>
TempString TypeToString(T* pointer) { return pointer == nullptr ? TempString("(nullptr)") : TypeToString(*pointer); }
//---------------------------------------------------------------------------------
// Test fixture is the core of SimpleTest. It provides fixture behavior, access
// to registered tests and stores the results of a test run
// Everything is local here so tests can be multithreaded without any extra work
//---------------------------------------------------------------------------------
class TestFixture
{
public:
TestFixture();
//virtual ~TestFixture() {;}
virtual bool ExecuteTest() {
myNumTestsChecked = myNumErrors = 0;
myNextError = (TestError*)myMessageSpace;
TestFixture* lastCurrent = ourCurrentTest;
ourCurrentTest = this;
Setup();
RunTest();
TearDown();
ourCurrentTest = lastCurrent;
return myNumErrors == 0;}
virtual char const* TestName() {return nullptr;}//const = 0;
virtual char const* TestGroup() {return nullptr;}//const = 0;
// Reporting used during testing process
void AddTest() { ++myNumTestsChecked; }
void LogError(char const* string, ...);
// Stats from execution
int NumTests() const { return myNumTestsChecked; }
int NumErrors() const { return myNumErrors; }
// Access to any errrors generated
TestError const* GetFirstError() const { return (TestError*)myMessageSpace; }
TestError const* GetLastError() const { return myNextError; }
// Access to registered tests
static TestFixture* GetFirstTest() { return ourFirstTest; }
static TestFixture* GetCurrentTest() { return ourCurrentTest; }
TestFixture* GetNextTest() const { return myNextTest; }
enum OutputMode
{
Silent,
Normal,
Verbose
};
// Default execution implementation
static void (*Print)(char const* string);
static void Printf(char const* string, ...);
static bool ExecuteAllTests(char const* groupFilter = nullptr, char const* nameFilter = nullptr, OutputMode output = Normal);
static bool ExecuteAllTests(OutputMode output) { return ExecuteAllTests(nullptr, nullptr, output); }
static bool ExecuteTestGroup(char const* groupFilter, OutputMode output = Normal) { return ExecuteAllTests(groupFilter, nullptr, output); }
protected:
virtual void RunTest() {}//= 0;
virtual void Setup() {}
virtual void TearDown() {}
// Test registration
static TestFixture const* LinkTest(TestFixture* test);
static TestFixture* ourFirstTest;
static TestFixture* ourLastTest;
TestFixture* myNextTest;
int myNumTestsChecked;
int myNumErrors;
TestError* myNextError;
char myMessageSpace[MESSAGE_SPACE];
// allow access to current test outside of main code block
//static thread_local TestFixture* ourCurrentTest;
static TestFixture* ourCurrentTest;
};
//---------------------------------------------------------------------------------
// Test definition macros
//---------------------------------------------------------------------------------
#define DEFINE_TEST_FULL(name, group, fixture) \
struct TOK(group, name) final : public fixture { \
char const* TestName() /*const*/ override { return #name; } \
char const* TestGroup() /*const*/ override { return #group; } \
void RunTest() override; \
} TOK(TOK(group, name), Instance); \
void TOK(group, name)::RunTest()
#define DEFINE_TEST(name) DEFINE_TEST_FULL(name, Global, BASE_FIXTURE)
#define DEFINE_TEST_G(name, group) DEFINE_TEST_FULL(name, group, BASE_FIXTURE)
#define DEFINE_TEST_F(name, fixture) DEFINE_TEST_FULL(name, Global, fixture)
#define DEFINE_TEST_GF(name, group, fixture) DEFINE_TEST_FULL(name, group, fixture)
//---------------------------------------------------------------------------------
// Utils
//---------------------------------------------------------------------------------
template <typename T>
T TestDifference(T const& a, T const& b) { T tmp = a - b; return tmp < 0 ? -tmp : tmp; }
// why are these still needed?
#define STR2(x) #x
#define STR(x) STR2(x)
#define TOK2(a, b) a ## b
#define TOK(a, b) TOK2(a, b)
//---------------------------------------------------------------------------------
// Error reporting don't call directly
//---------------------------------------------------------------------------------
#define TEST_ERROR_PREFIX_ __FILE__ "(" STR(__LINE__) "): Condition [%s] Failed. "
#define TEST_ERROR_(message, ...) do { TestFixture::GetCurrentTest()->LogError(TEST_ERROR_PREFIX_ message, ##__VA_ARGS__); } while(0)
#define TEST_CHECK_(cond, condtext, message, ...) do { TestFixture::GetCurrentTest()->AddTest(); if (!(cond)) TEST_ERROR_(message, condtext, ##__VA_ARGS__); } while(0)
//---------------------------------------------------------------------------------
// Tests
//---------------------------------------------------------------------------------
#define TEST_OPERATOR(a, b, op1, op2) TEST_CHECK_((a) op1 (b), STR(a) " " STR(op1) " " STR(b), "%s " STR(op2) " %s", *TypeToString(a), *TypeToString(b))
#define TEST(cond) TEST_EQ(cond, true)
#define TEST_EQ(a, b) TEST_OPERATOR(a, b, ==, !=)
#define TEST_NEQ(a, b) TEST_OPERATOR(a, b, !=, ==)
#define TEST_GREATER(a, b) TEST_OPERATOR(a, b, >, <=)
#define TEST_GREATER_EQUAL(a, b) TEST_OPERATOR(a, b, >=, <)
#define TEST_LESS(a, b) TEST_OPERATOR(a, b, <, >=)
#define TEST_LESS_EQUAL(a, b) TEST_OPERATOR(a, b, <=, >)
#define TEST_CLOSE(a, b, eps) TEST_CHECK_(TestDifference(a,b) <= eps, STR(a) " Close to " STR(b), "Difference of %s is greater than " STR(eps), *TypeToString(TestDifference(a,b)))
#define TEST_MESSAGE(cond, message, ...) TEST_CHECK_(cond, STR(cond), message, ##__VA_ARGS__)
#endif // _SIMPLETEST_H_