1 |
#ifndef JSONTEST_H_INCLUDED |
2 |
#define JSONTEST_H_INCLUDED |
3 |
|
4 |
#include <deque> |
5 |
#include <stdio.h> |
6 |
#include <string> |
7 |
|
8 |
/* |
9 |
* ////////////////////////////////////////////////////////////////// |
10 |
* ////////////////////////////////////////////////////////////////// |
11 |
* Mini Unit Testing framework |
12 |
* ////////////////////////////////////////////////////////////////// |
13 |
* ////////////////////////////////////////////////////////////////// |
14 |
*/ |
15 |
|
16 |
|
17 |
|
18 |
/** \brief Unit testing framework. |
19 |
* \warning: all assertions are non-aborting, test case execution will continue |
20 |
* even if an assertion namespace. |
21 |
* This constraint is for portability: the framework needs to compile |
22 |
* on Visual Studio 6 and must not require exception usage. |
23 |
*/ |
24 |
namespace JsonTest |
25 |
{ |
26 |
struct Failure |
27 |
{ |
28 |
const char *file_; |
29 |
std::string expr_; |
30 |
std::string message_; |
31 |
unsigned int line_; |
32 |
unsigned int nestingLevel_; |
33 |
}; |
34 |
|
35 |
|
36 |
/* |
37 |
* / Context used to create the assertion callstack on failure. |
38 |
* / Must be a POD to allow inline initialisation without stepping |
39 |
* / into the debugger. |
40 |
*/ |
41 |
struct PredicateContext |
42 |
{ |
43 |
typedef size_t Id; |
44 |
Id id_; |
45 |
const char *file_; |
46 |
size_t line_; |
47 |
const char *expr_; |
48 |
PredicateContext *next_; |
49 |
/* |
50 |
* / Related Failure, set when the PredicateContext is converted |
51 |
* / into a Failure. |
52 |
*/ |
53 |
Failure *failure_; |
54 |
}; |
55 |
|
56 |
class TestResult |
57 |
{ |
58 |
public: |
59 |
TestResult (); |
60 |
|
61 |
/* |
62 |
* / \internal Implementation detail for assertion macros |
63 |
* / Not encapsulated to prevent step into when debugging failed assertions |
64 |
* / Incremented by one on assertion predicate entry, decreased by one |
65 |
* / by addPredicateContext(). |
66 |
*/ |
67 |
PredicateContext::Id predicateId_; |
68 |
|
69 |
/* / \internal Implementation detail for predicate macros */ |
70 |
PredicateContext *predicateStackTail_; |
71 |
|
72 |
void setTestName (const std::string &name); |
73 |
|
74 |
/* / Adds an assertion failure. */ |
75 |
TestResult &addFailure (const char *file, unsigned int line, const char *expr = 0); |
76 |
|
77 |
/* |
78 |
* / Removes the last PredicateContext added to the predicate stack |
79 |
* / chained list. |
80 |
* / Next messages will be targed at the PredicateContext that was removed. |
81 |
*/ |
82 |
TestResult &popPredicateContext (); |
83 |
|
84 |
bool failed () const; |
85 |
|
86 |
void printFailure (bool printTestName) const; |
87 |
|
88 |
TestResult &operator << (bool value); |
89 |
TestResult &operator << (int value); |
90 |
TestResult &operator << (unsigned int value); |
91 |
TestResult &operator << (double value); |
92 |
TestResult &operator << (const char *value); |
93 |
TestResult &operator << (const std::string &value); |
94 |
|
95 |
private: |
96 |
TestResult &addToLastFailure (const std::string &message); |
97 |
unsigned int getAssertionNestingLevel () const; |
98 |
/* / Adds a failure or a predicate context */ |
99 |
void addFailureInfo (const char *file, unsigned int line, const char *expr, unsigned int nestingLevel); |
100 |
static std::string indentText (const std::string &text, const std::string &indent); |
101 |
|
102 |
typedef std::deque<Failure> Failures; |
103 |
Failures failures_; |
104 |
std::string name_; |
105 |
PredicateContext rootPredicateNode_; |
106 |
PredicateContext::Id lastUsedPredicateId_; |
107 |
/* / Failure which is the target of the messages added using operator << */ |
108 |
Failure *messageTarget_; |
109 |
}; |
110 |
|
111 |
|
112 |
class TestCase |
113 |
{ |
114 |
public: |
115 |
TestCase (); |
116 |
|
117 |
virtual |
118 |
~TestCase (); |
119 |
|
120 |
void run (TestResult &result); |
121 |
|
122 |
virtual const char *testName () const = 0; |
123 |
|
124 |
protected: |
125 |
TestResult *result_; |
126 |
|
127 |
private: |
128 |
virtual void runTestCase () = 0; |
129 |
}; |
130 |
|
131 |
/* / Function pointer type for TestCase factory */ |
132 |
typedef TestCase *(*TestCaseFactory)(); |
133 |
|
134 |
class Runner |
135 |
{ |
136 |
public: |
137 |
Runner (); |
138 |
|
139 |
/* / Adds a test to the suite */ |
140 |
Runner &add (TestCaseFactory factory); |
141 |
|
142 |
/* |
143 |
* / Runs test as specified on the command-line |
144 |
* / If no command-line arguments are provided, run all tests. |
145 |
* / If --list-tests is provided, then print the list of all test cases |
146 |
* / If --test <testname> is provided, then run test testname. |
147 |
*/ |
148 |
int runCommandLine (int argc, const char *argv[]) const; |
149 |
|
150 |
/* / Runs all the test cases */ |
151 |
bool runAllTest (bool printSummary) const; |
152 |
|
153 |
/* / Returns the number of test case in the suite */ |
154 |
unsigned int testCount () const; |
155 |
|
156 |
/* / Returns the name of the test case at the specified index */ |
157 |
std::string testNameAt (unsigned int index) const; |
158 |
|
159 |
/* / Runs the test case at the specified index using the specified TestResult */ |
160 |
void runTestAt (unsigned int index, TestResult &result) const; |
161 |
|
162 |
static void printUsage (const char *appName); |
163 |
|
164 |
private: |
165 |
/* prevents copy construction and assignment */ |
166 |
Runner (const Runner &other); |
167 |
Runner &operator = (const Runner &other); |
168 |
|
169 |
private: |
170 |
void listTests () const; |
171 |
bool testIndex (const std::string &testName, unsigned int &index) const; |
172 |
static void preventDialogOnCrash (); |
173 |
|
174 |
private: |
175 |
typedef std::deque<TestCaseFactory> Factories; |
176 |
Factories tests_; |
177 |
}; |
178 |
|
179 |
template<typename T> |
180 |
TestResult & |
181 |
checkEqual (TestResult &result, const T &expected, const T &actual, const char *file, unsigned int line, const char *expr) |
182 |
{ |
183 |
if (expected != actual) |
184 |
{ |
185 |
result.addFailure (file, line, expr); |
186 |
result << "Expected: " << expected << "\n"; |
187 |
result << "Actual : " << actual; |
188 |
} |
189 |
return result; |
190 |
} |
191 |
|
192 |
TestResult &checkStringEqual (TestResult &result, const std::string &expected, const std::string &actual, const char *file, unsigned int line, const char *expr); |
193 |
} /* namespace JsonTest */ |
194 |
|
195 |
|
196 |
/* |
197 |
* / \brief Asserts that the given expression is true. |
198 |
* / JSONTEST_ASSERT( x == y ) << "x=" << x << ", y=" << y; |
199 |
* / JSONTEST_ASSERT( x == y ); |
200 |
*/ |
201 |
#define JSONTEST_ASSERT(expr) \ |
202 |
if (condition) \ |
203 |
{ \ |
204 |
} \ |
205 |
else \ |
206 |
result_->addFailure (__FILE__, __LINE__, # expr) |
207 |
|
208 |
/* |
209 |
* / \brief Asserts that the given predicate is true. |
210 |
* / The predicate may do other assertions and be a member function of the fixture. |
211 |
*/ |
212 |
#define JSONTEST_ASSERT_PRED(expr) \ |
213 |
{ \ |
214 |
JsonTest::PredicateContext _minitest_Context = { \ |
215 |
result_->predicateId_, __FILE__, __LINE__, # expr }; \ |
216 |
result_->predicateStackTail_->next_ = &_minitest_Context; \ |
217 |
result_->predicateId_ += 1; \ |
218 |
result_->predicateStackTail_ = &_minitest_Context; \ |
219 |
(expr); \ |
220 |
result_->popPredicateContext (); \ |
221 |
} \ |
222 |
*result_ |
223 |
|
224 |
/* / \brief Asserts that two values are equals. */ |
225 |
#define JSONTEST_ASSERT_EQUAL(expected, actual) \ |
226 |
JsonTest::checkEqual (*result_, expected, actual, \ |
227 |
__FILE__, __LINE__, \ |
228 |
# expected " == " # actual) |
229 |
|
230 |
/* / \brief Asserts that two values are equals. */ |
231 |
#define JSONTEST_ASSERT_STRING_EQUAL(expected, actual) \ |
232 |
JsonTest::checkStringEqual (*result_, \ |
233 |
std::string (expected), std::string (actual), \ |
234 |
# expected " == " # actual) |
235 |
|
236 |
/* / \brief Begin a fixture test case. */ |
237 |
#define JSONTEST_FIXTURE(FixtureType, name) \ |
238 |
class Test ## FixtureType ## name \ |
239 |
: public FixtureType \ |
240 |
{ \ |
241 |
public: \ |
242 |
static JsonTest::TestCase *factory () \ |
243 |
{ \ |
244 |
return new Test ## FixtureType ## name (); \ |
245 |
} \ |
246 |
public: \ |
247 |
/* overidden from TestCase */ \ |
248 |
virtual const char *testName () const \ |
249 |
{ \ |
250 |
return # FixtureType "/" # name; \ |
251 |
} \ |
252 |
virtual void runTestCase (); \ |
253 |
}; \ |
254 |
\ |
255 |
void Test ## FixtureType ## name::runTestCase () |
256 |
|
257 |
#define JSONTEST_FIXTURE_FACTORY(FixtureType, name) \ |
258 |
& Test ## FixtureType ## name::factory |
259 |
|
260 |
#define JSONTEST_REGISTER_FIXTURE(runner, FixtureType, name) \ |
261 |
(runner).add (JSONTEST_FIXTURE_FACTORY (FixtureType, name)) |
262 |
|
263 |
#endif /* ifndef JSONTEST_H_INCLUDED */ |