Free Electron
jsontest.h
1 // Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors
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 <cstdio>
10 #include <deque>
11 #include <iomanip>
12 #include <json/config.h>
13 #include <json/value.h>
14 #include <json/writer.h>
15 #include <sstream>
16 #include <string>
17 
18 // //////////////////////////////////////////////////////////////////
19 // //////////////////////////////////////////////////////////////////
20 // Mini Unit Testing framework
21 // //////////////////////////////////////////////////////////////////
22 // //////////////////////////////////////////////////////////////////
23 
24 /** \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  */
30 namespace JsonTest {
31 
32 class Failure {
33 public:
34  const char* file_;
35  unsigned int line_;
36  Json::String expr_;
37  Json::String message_;
38  unsigned int nestingLevel_;
39 };
40 
41 /// Context used to create the assertion callstack on failure.
42 /// Must be a POD to allow inline initialisation without stepping
43 /// into the debugger.
45  using Id = unsigned int;
46  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 };
55 
56 class TestResult {
57 public:
58  TestResult();
59 
60  /// \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().
64  PredicateContext::Id predicateId_{1};
65 
66  /// \internal Implementation detail for predicate macros
67  PredicateContext* predicateStackTail_;
68 
69  void setTestName(const Json::String& name);
70 
71  /// Adds an assertion failure.
72  TestResult& addFailure(const char* file, unsigned int line,
73  const char* expr = nullptr);
74 
75  /// Removes the last PredicateContext added to the predicate stack
76  /// chained list.
77  /// Next messages will be targeted at the PredicateContext that was removed.
78  TestResult& popPredicateContext();
79 
80  bool failed() const;
81 
82  void printFailure(bool printTestName) const;
83 
84  // Generic operator that will work with anything ostream can deal with.
85  template <typename T> TestResult& operator<<(const T& value) {
86  Json::OStringStream oss;
87  oss << std::setprecision(16) << std::hexfloat << value;
88  return addToLastFailure(oss.str());
89  }
90 
91  // 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);
96 
97 private:
98  TestResult& addToLastFailure(const Json::String& message);
99  /// Adds a failure or a predicate context
100  void addFailureInfo(const char* file, unsigned int line, const char* expr,
101  unsigned int nestingLevel);
102  static Json::String indentText(const Json::String& text,
103  const Json::String& indent);
104 
105  using Failures = std::deque<Failure>;
106  Failures failures_;
107  Json::String name_;
108  PredicateContext rootPredicateNode_;
109  PredicateContext::Id lastUsedPredicateId_{0};
110  /// Failure which is the target of the messages added using operator <<
111  Failure* messageTarget_{nullptr};
112 };
113 
114 class TestCase {
115 public:
116  TestCase();
117 
118  virtual ~TestCase();
119 
120  void run(TestResult& result);
121 
122  virtual const char* testName() const = 0;
123 
124 protected:
125  TestResult* result_{nullptr};
126 
127 private:
128  virtual void runTestCase() = 0;
129 };
130 
131 /// Function pointer type for TestCase factory
132 using TestCaseFactory = TestCase* (*)();
133 
134 class Runner {
135 public:
136  Runner();
137 
138  /// Adds a test to the suite
139  Runner& add(TestCaseFactory factory);
140 
141  /// 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;
146 
147  /// Runs all the test cases
148  bool runAllTest(bool printSummary) const;
149 
150  /// Returns the number of test case in the suite
151  size_t testCount() const;
152 
153  /// Returns the name of the test case at the specified index
154  Json::String testNameAt(size_t index) const;
155 
156  /// Runs the test case at the specified index using the specified TestResult
157  void runTestAt(size_t index, TestResult& result) const;
158 
159  static void printUsage(const char* appName);
160 
161 private: // prevents copy construction and assignment
162  Runner(const Runner& other) = delete;
163  Runner& operator=(const Runner& other) = delete;
164 
165 private:
166  void listTests() const;
167  bool testIndex(const Json::String& testName, size_t& indexOut) const;
168  static void preventDialogOnCrash();
169 
170 private:
171  using Factories = std::deque<TestCaseFactory>;
172  Factories tests_;
173 };
174 
175 template <typename T, typename U>
176 TestResult& checkEqual(TestResult& result, T expected, U actual,
177  const char* file, unsigned int line, const char* expr) {
178  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 }
185 
186 Json::String ToJsonString(const char* toConvert);
187 Json::String ToJsonString(Json::String in);
188 #if JSONCPP_USING_SECURE_MEMORY
189 Json::String ToJsonString(std::string in);
190 #endif
191 
192 TestResult& checkStringEqual(TestResult& result, const Json::String& expected,
193  const Json::String& actual, const char* file,
194  unsigned int line, const char* expr);
195 
196 } // namespace JsonTest
197 
198 /// \brief Asserts that the given expression is true.
199 /// JSONTEST_ASSERT( x == y ) << "x=" << x << ", y=" << y;
200 /// JSONTEST_ASSERT( x == y );
201 #define JSONTEST_ASSERT(expr) \
202  if (expr) { \
203  } else \
204  result_->addFailure(__FILE__, __LINE__, #expr)
205 
206 /// \brief Asserts that the given predicate is true.
207 /// The predicate may do other assertions and be a member function of the
208 /// fixture.
209 #define JSONTEST_ASSERT_PRED(expr) \
210  do { \
211  JsonTest::PredicateContext _minitest_Context = { \
212  result_->predicateId_, __FILE__, __LINE__, #expr, NULL, NULL}; \
213  result_->predicateStackTail_->next_ = &_minitest_Context; \
214  result_->predicateId_ += 1; \
215  result_->predicateStackTail_ = &_minitest_Context; \
216  (expr); \
217  result_->popPredicateContext(); \
218  } while (0)
219 
220 /// \brief Asserts that two values are equals.
221 #define JSONTEST_ASSERT_EQUAL(expected, actual) \
222  JsonTest::checkEqual(*result_, expected, actual, __FILE__, __LINE__, \
223  #expected " == " #actual)
224 
225 /// \brief Asserts that two values are equals.
226 #define JSONTEST_ASSERT_STRING_EQUAL(expected, actual) \
227  JsonTest::checkStringEqual(*result_, JsonTest::ToJsonString(expected), \
228  JsonTest::ToJsonString(actual), __FILE__, \
229  __LINE__, #expected " == " #actual)
230 
231 /// \brief Asserts that a given expression throws an exception
232 #define JSONTEST_ASSERT_THROWS(expr) \
233  do { \
234  bool _threw = false; \
235  try { \
236  expr; \
237  } catch (...) { \
238  _threw = true; \
239  } \
240  if (!_threw) \
241  result_->addFailure(__FILE__, __LINE__, \
242  "expected exception thrown: " #expr); \
243  } while (0)
244 
245 /// \brief Begin a fixture test case.
246 #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  \
253  public: /* overridden from TestCase */ \
254  const char* testName() const override { return #FixtureType "/" #name; } \
255  void runTestCase() override; \
256  }; \
257  \
258  void Test##FixtureType##name::runTestCase()
259 
260 #define JSONTEST_FIXTURE_FACTORY(FixtureType, name) \
261  &Test##FixtureType##name::factory
262 
263 #define JSONTEST_REGISTER_FIXTURE(runner, FixtureType, name) \
264  (runner).add(JSONTEST_FIXTURE_FACTORY(FixtureType, name))
265 
266 /// \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 
288 #endif // ifndef JSONTEST_H_INCLUDED
Unit testing framework.
Definition: jsontest.h:30
TestCase *(*)() TestCaseFactory
Function pointer type for TestCase factory.
Definition: jsontest.h:132
Failure * failure_
Related Failure, set when the PredicateContext is converted into a Failure.
Definition: jsontest.h:53
Context used to create the assertion callstack on failure.
Definition: jsontest.h:44