blob: 4e8af0f2592b8b41127e37e8530a3b87b21977cb [file] [log] [blame]
Haibo Huangb0bee822021-02-24 15:40:15 -08001// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -04002// 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
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -05007#define JSONTEST_H_INCLUDED
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -04008
Haibo Huangb0bee822021-02-24 15:40:15 -08009#include <cstdio>
10#include <deque>
11#include <iomanip>
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -050012#include <json/config.h>
13#include <json/value.h>
14#include <json/writer.h>
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -050015#include <sstream>
16#include <string>
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -040017
18// //////////////////////////////////////////////////////////////////
19// //////////////////////////////////////////////////////////////////
20// Mini Unit Testing framework
21// //////////////////////////////////////////////////////////////////
22// //////////////////////////////////////////////////////////////////
23
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -040024/** \brief Unit testing framework.
25 * \warning: all assertions are non-aborting, test case execution will continue
26 * even if an assertion namespace.
27 * This constraint is for portability: the framework needs to compile
28 * on Visual Studio 6 and must not require exception usage.
29 */
30namespace JsonTest {
31
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -050032class Failure {
33public:
34 const char* file_;
35 unsigned int line_;
Haibo Huangb0bee822021-02-24 15:40:15 -080036 Json::String expr_;
37 Json::String message_;
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -050038 unsigned int nestingLevel_;
39};
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -040040
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -050041/// Context used to create the assertion callstack on failure.
42/// Must be a POD to allow inline initialisation without stepping
43/// into the debugger.
44struct PredicateContext {
Haibo Huangb0bee822021-02-24 15:40:15 -080045 using Id = unsigned int;
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -050046 Id id_;
47 const char* file_;
48 unsigned int line_;
49 const char* expr_;
50 PredicateContext* next_;
51 /// Related Failure, set when the PredicateContext is converted
52 /// into a Failure.
53 Failure* failure_;
54};
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -040055
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -050056class TestResult {
57public:
58 TestResult();
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -040059
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -050060 /// \internal Implementation detail for assertion macros
61 /// Not encapsulated to prevent step into when debugging failed assertions
62 /// Incremented by one on assertion predicate entry, decreased by one
63 /// by addPredicateContext().
Haibo Huangb0bee822021-02-24 15:40:15 -080064 PredicateContext::Id predicateId_{1};
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -040065
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -050066 /// \internal Implementation detail for predicate macros
67 PredicateContext* predicateStackTail_;
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -040068
Haibo Huangb0bee822021-02-24 15:40:15 -080069 void setTestName(const Json::String& name);
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -040070
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -050071 /// Adds an assertion failure.
Haibo Huangb0bee822021-02-24 15:40:15 -080072 TestResult& addFailure(const char* file, unsigned int line,
73 const char* expr = nullptr);
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -040074
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -050075 /// Removes the last PredicateContext added to the predicate stack
76 /// chained list.
77 /// Next messages will be targed at the PredicateContext that was removed.
78 TestResult& popPredicateContext();
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -040079
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -050080 bool failed() const;
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -040081
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -050082 void printFailure(bool printTestName) const;
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -040083
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -050084 // Generic operator that will work with anything ostream can deal with.
85 template <typename T> TestResult& operator<<(const T& value) {
Haibo Huangb0bee822021-02-24 15:40:15 -080086 Json::OStringStream oss;
87 oss << std::setprecision(16) << std::hexfloat << value;
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -050088 return addToLastFailure(oss.str());
89 }
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -040090
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -050091 // Specialized versions.
92 TestResult& operator<<(bool value);
93 // std:ostream does not support 64bits integers on all STL implementation
94 TestResult& operator<<(Json::Int64 value);
95 TestResult& operator<<(Json::UInt64 value);
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -040096
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -050097private:
Haibo Huangb0bee822021-02-24 15:40:15 -080098 TestResult& addToLastFailure(const Json::String& message);
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -050099 /// Adds a failure or a predicate context
Haibo Huangb0bee822021-02-24 15:40:15 -0800100 void addFailureInfo(const char* file, unsigned int line, const char* expr,
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -0500101 unsigned int nestingLevel);
Haibo Huangb0bee822021-02-24 15:40:15 -0800102 static Json::String indentText(const Json::String& text,
103 const Json::String& indent);
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -0400104
Haibo Huangb0bee822021-02-24 15:40:15 -0800105 using Failures = std::deque<Failure>;
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -0500106 Failures failures_;
Haibo Huangb0bee822021-02-24 15:40:15 -0800107 Json::String name_;
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -0500108 PredicateContext rootPredicateNode_;
Haibo Huangb0bee822021-02-24 15:40:15 -0800109 PredicateContext::Id lastUsedPredicateId_{0};
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -0500110 /// Failure which is the target of the messages added using operator <<
Haibo Huangb0bee822021-02-24 15:40:15 -0800111 Failure* messageTarget_{nullptr};
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -0500112};
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -0400113
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -0500114class TestCase {
115public:
116 TestCase();
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -0400117
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -0500118 virtual ~TestCase();
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -0400119
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -0500120 void run(TestResult& result);
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -0400121
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -0500122 virtual const char* testName() const = 0;
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -0400123
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -0500124protected:
Haibo Huangb0bee822021-02-24 15:40:15 -0800125 TestResult* result_{nullptr};
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -0400126
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -0500127private:
128 virtual void runTestCase() = 0;
129};
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -0400130
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -0500131/// Function pointer type for TestCase factory
Haibo Huangb0bee822021-02-24 15:40:15 -0800132using TestCaseFactory = TestCase* (*)();
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -0400133
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -0500134class Runner {
135public:
136 Runner();
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -0400137
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -0500138 /// Adds a test to the suite
139 Runner& add(TestCaseFactory factory);
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -0400140
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -0500141 /// Runs test as specified on the command-line
142 /// If no command-line arguments are provided, run all tests.
143 /// If --list-tests is provided, then print the list of all test cases
144 /// If --test <testname> is provided, then run test testname.
145 int runCommandLine(int argc, const char* argv[]) const;
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -0400146
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -0500147 /// Runs all the test cases
148 bool runAllTest(bool printSummary) const;
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -0400149
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -0500150 /// Returns the number of test case in the suite
Haibo Huangb0bee822021-02-24 15:40:15 -0800151 size_t testCount() const;
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -0400152
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -0500153 /// Returns the name of the test case at the specified index
Haibo Huangb0bee822021-02-24 15:40:15 -0800154 Json::String testNameAt(size_t index) const;
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -0400155
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -0500156 /// Runs the test case at the specified index using the specified TestResult
Haibo Huangb0bee822021-02-24 15:40:15 -0800157 void runTestAt(size_t index, TestResult& result) const;
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -0400158
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -0500159 static void printUsage(const char* appName);
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -0400160
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -0500161private: // prevents copy construction and assignment
Haibo Huangb0bee822021-02-24 15:40:15 -0800162 Runner(const Runner& other) = delete;
163 Runner& operator=(const Runner& other) = delete;
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -0400164
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -0500165private:
166 void listTests() const;
Haibo Huangb0bee822021-02-24 15:40:15 -0800167 bool testIndex(const Json::String& testName, size_t& indexOut) const;
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -0500168 static void preventDialogOnCrash();
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -0400169
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -0500170private:
Haibo Huangb0bee822021-02-24 15:40:15 -0800171 using Factories = std::deque<TestCaseFactory>;
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -0500172 Factories tests_;
173};
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -0400174
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -0500175template <typename T, typename U>
Haibo Huangb0bee822021-02-24 15:40:15 -0800176TestResult& checkEqual(TestResult& result, T expected, U actual,
177 const char* file, unsigned int line, const char* expr) {
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -0500178 if (static_cast<U>(expected) != actual) {
179 result.addFailure(file, line, expr);
180 result << "Expected: " << static_cast<U>(expected) << "\n";
181 result << "Actual : " << actual;
182 }
183 return result;
184}
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -0400185
Haibo Huangb0bee822021-02-24 15:40:15 -0800186Json::String ToJsonString(const char* toConvert);
187Json::String ToJsonString(Json::String in);
188#if JSONCPP_USING_SECURE_MEMORY
189Json::String ToJsonString(std::string in);
190#endif
191
192TestResult& checkStringEqual(TestResult& result, const Json::String& expected,
193 const Json::String& actual, const char* file,
194 unsigned int line, const char* expr);
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -0400195
196} // namespace JsonTest
197
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -0400198/// \brief Asserts that the given expression is true.
199/// JSONTEST_ASSERT( x == y ) << "x=" << x << ", y=" << y;
200/// JSONTEST_ASSERT( x == y );
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -0500201#define JSONTEST_ASSERT(expr) \
202 if (expr) { \
203 } else \
Haibo Huangb0bee822021-02-24 15:40:15 -0800204 result_->addFailure(__FILE__, __LINE__, #expr)
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -0400205
206/// \brief Asserts that the given predicate is true.
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -0500207/// The predicate may do other assertions and be a member function of the
208/// fixture.
209#define JSONTEST_ASSERT_PRED(expr) \
Haibo Huangb0bee822021-02-24 15:40:15 -0800210 do { \
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -0500211 JsonTest::PredicateContext _minitest_Context = { \
Haibo Huangb0bee822021-02-24 15:40:15 -0800212 result_->predicateId_, __FILE__, __LINE__, #expr, NULL, NULL}; \
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -0500213 result_->predicateStackTail_->next_ = &_minitest_Context; \
214 result_->predicateId_ += 1; \
215 result_->predicateStackTail_ = &_minitest_Context; \
216 (expr); \
217 result_->popPredicateContext(); \
Haibo Huangb0bee822021-02-24 15:40:15 -0800218 } while (0)
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -0400219
220/// \brief Asserts that two values are equals.
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -0500221#define JSONTEST_ASSERT_EQUAL(expected, actual) \
Haibo Huangb0bee822021-02-24 15:40:15 -0800222 JsonTest::checkEqual(*result_, expected, actual, __FILE__, __LINE__, \
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -0500223 #expected " == " #actual)
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -0400224
225/// \brief Asserts that two values are equals.
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -0500226#define JSONTEST_ASSERT_STRING_EQUAL(expected, actual) \
Haibo Huangb0bee822021-02-24 15:40:15 -0800227 JsonTest::checkStringEqual(*result_, JsonTest::ToJsonString(expected), \
228 JsonTest::ToJsonString(actual), __FILE__, \
229 __LINE__, #expected " == " #actual)
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -0500230
231/// \brief Asserts that a given expression throws an exception
232#define JSONTEST_ASSERT_THROWS(expr) \
Haibo Huangb0bee822021-02-24 15:40:15 -0800233 do { \
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -0500234 bool _threw = false; \
235 try { \
236 expr; \
Haibo Huangb0bee822021-02-24 15:40:15 -0800237 } catch (...) { \
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -0500238 _threw = true; \
239 } \
240 if (!_threw) \
Haibo Huangb0bee822021-02-24 15:40:15 -0800241 result_->addFailure(__FILE__, __LINE__, \
242 "expected exception thrown: " #expr); \
243 } while (0)
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -0400244
245/// \brief Begin a fixture test case.
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -0500246#define JSONTEST_FIXTURE(FixtureType, name) \
247 class Test##FixtureType##name : public FixtureType { \
248 public: \
249 static JsonTest::TestCase* factory() { \
250 return new Test##FixtureType##name(); \
251 } \
252 \
Haibo Huangb0bee822021-02-24 15:40:15 -0800253 public: /* overridden from TestCase */ \
254 const char* testName() const override { return #FixtureType "/" #name; } \
255 void runTestCase() override; \
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -0500256 }; \
257 \
258 void Test##FixtureType##name::runTestCase()
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -0400259
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -0500260#define JSONTEST_FIXTURE_FACTORY(FixtureType, name) \
261 &Test##FixtureType##name::factory
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -0400262
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -0500263#define JSONTEST_REGISTER_FIXTURE(runner, FixtureType, name) \
264 (runner).add(JSONTEST_FIXTURE_FACTORY(FixtureType, name))
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -0400265
Haibo Huangb0bee822021-02-24 15:40:15 -0800266/// \brief Begin a fixture test case.
267#define JSONTEST_FIXTURE_V2(FixtureType, name, collections) \
268 class Test##FixtureType##name : public FixtureType { \
269 public: \
270 static JsonTest::TestCase* factory() { \
271 return new Test##FixtureType##name(); \
272 } \
273 static bool collect() { \
274 (collections).push_back(JSONTEST_FIXTURE_FACTORY(FixtureType, name)); \
275 return true; \
276 } \
277 \
278 public: /* overridden from TestCase */ \
279 const char* testName() const override { return #FixtureType "/" #name; } \
280 void runTestCase() override; \
281 }; \
282 \
283 static bool test##FixtureType##name##collect = \
284 Test##FixtureType##name::collect(); \
285 \
286 void Test##FixtureType##name::runTestCase()
287
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -0400288#endif // ifndef JSONTEST_H_INCLUDED