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