blob: 0b7d12b974b5e304fe0f30a9ad0b0a8fea25c2a1 [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#define _CRT_SECURE_NO_WARNINGS 1 // Prevents deprecation warning with MSVC
7#include "jsontest.h"
Haibo Huangb0bee822021-02-24 15:40:15 -08008#include <cstdio>
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -04009#include <string>
10
11#if defined(_MSC_VER)
12// Used to install a report hook that prevent dialog on assertion and error.
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -050013#include <crtdbg.h>
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -040014#endif // if defined(_MSC_VER)
15
16#if defined(_WIN32)
17// Used to prevent dialog on memory fault.
18// Limits headers included by Windows.h
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -050019#define WIN32_LEAN_AND_MEAN
20#define NOSERVICE
21#define NOMCX
22#define NOIME
23#define NOSOUND
24#define NOCOMM
25#define NORPC
26#define NOGDI
27#define NOUSER
28#define NODRIVERS
29#define NOLOGERROR
30#define NOPROFILER
31#define NOMEMMGR
32#define NOLFILEIO
33#define NOOPENFILE
34#define NORESOURCE
35#define NOATOM
36#define NOLANGUAGE
37#define NOLSTRING
38#define NODBCS
39#define NOKEYBOARDINFO
40#define NOGDICAPMASKS
41#define NOCOLOR
42#define NOGDIOBJ
43#define NODRAWTEXT
44#define NOTEXTMETRIC
45#define NOSCALABLEFONT
46#define NOBITMAP
47#define NORASTEROPS
48#define NOMETAFILE
49#define NOSYSMETRICS
50#define NOSYSTEMPARAMSINFO
51#define NOMSG
52#define NOWINSTYLES
53#define NOWINOFFSETS
54#define NOSHOWWINDOW
55#define NODEFERWINDOWPOS
56#define NOVIRTUALKEYCODES
57#define NOKEYSTATES
58#define NOWH
59#define NOMENUS
60#define NOSCROLL
61#define NOCLIPBOARD
62#define NOICONS
63#define NOMB
64#define NOSYSCOMMANDS
65#define NOMDI
66#define NOCTLMGR
67#define NOWINMESSAGES
68#include <windows.h>
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -040069#endif // if defined(_WIN32)
70
71namespace JsonTest {
72
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -040073// class TestResult
74// //////////////////////////////////////////////////////////////////
75
Haibo Huangb0bee822021-02-24 15:40:15 -080076TestResult::TestResult() {
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -050077 // The root predicate has id 0
78 rootPredicateNode_.id_ = 0;
Haibo Huangb0bee822021-02-24 15:40:15 -080079 rootPredicateNode_.next_ = nullptr;
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -050080 predicateStackTail_ = &rootPredicateNode_;
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -040081}
82
Haibo Huangb0bee822021-02-24 15:40:15 -080083void TestResult::setTestName(const Json::String& name) { name_ = name; }
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -040084
Haibo Huangb0bee822021-02-24 15:40:15 -080085TestResult& TestResult::addFailure(const char* file, unsigned int line,
86 const char* expr) {
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -050087 /// Walks the PredicateContext stack adding them to failures_ if not already
88 /// added.
89 unsigned int nestingLevel = 0;
90 PredicateContext* lastNode = rootPredicateNode_.next_;
Haibo Huangb0bee822021-02-24 15:40:15 -080091 for (; lastNode != nullptr; lastNode = lastNode->next_) {
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -050092 if (lastNode->id_ > lastUsedPredicateId_) // new PredicateContext
93 {
94 lastUsedPredicateId_ = lastNode->id_;
Haibo Huangb0bee822021-02-24 15:40:15 -080095 addFailureInfo(lastNode->file_, lastNode->line_, lastNode->expr_,
96 nestingLevel);
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -050097 // Link the PredicateContext to the failure for message target when
98 // popping the PredicateContext.
99 lastNode->failure_ = &(failures_.back());
100 }
101 ++nestingLevel;
102 }
103
104 // Adds the failed assertion
105 addFailureInfo(file, line, expr, nestingLevel);
106 messageTarget_ = &(failures_.back());
107 return *this;
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -0400108}
109
Haibo Huangb0bee822021-02-24 15:40:15 -0800110void TestResult::addFailureInfo(const char* file, unsigned int line,
111 const char* expr, unsigned int nestingLevel) {
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -0500112 Failure failure;
113 failure.file_ = file;
114 failure.line_ = line;
115 if (expr) {
116 failure.expr_ = expr;
117 }
118 failure.nestingLevel_ = nestingLevel;
119 failures_.push_back(failure);
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -0400120}
121
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -0500122TestResult& TestResult::popPredicateContext() {
123 PredicateContext* lastNode = &rootPredicateNode_;
Haibo Huangb0bee822021-02-24 15:40:15 -0800124 while (lastNode->next_ != nullptr && lastNode->next_->next_ != nullptr) {
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -0500125 lastNode = lastNode->next_;
126 }
127 // Set message target to popped failure
128 PredicateContext* tail = lastNode->next_;
Haibo Huangb0bee822021-02-24 15:40:15 -0800129 if (tail != nullptr && tail->failure_ != nullptr) {
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -0500130 messageTarget_ = tail->failure_;
131 }
132 // Remove tail from list
133 predicateStackTail_ = lastNode;
Haibo Huangb0bee822021-02-24 15:40:15 -0800134 lastNode->next_ = nullptr;
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -0500135 return *this;
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -0400136}
137
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -0500138bool TestResult::failed() const { return !failures_.empty(); }
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -0400139
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -0500140void TestResult::printFailure(bool printTestName) const {
141 if (failures_.empty()) {
142 return;
143 }
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -0400144
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -0500145 if (printTestName) {
146 printf("* Detail of %s test failure:\n", name_.c_str());
147 }
148
149 // Print in reverse to display the callstack in the right order
Haibo Huangb0bee822021-02-24 15:40:15 -0800150 for (const auto& failure : failures_) {
151 Json::String indent(failure.nestingLevel_ * 2, ' ');
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -0500152 if (failure.file_) {
Haibo Huangb0bee822021-02-24 15:40:15 -0800153 printf("%s%s(%u): ", indent.c_str(), failure.file_, failure.line_);
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -0500154 }
155 if (!failure.expr_.empty()) {
156 printf("%s\n", failure.expr_.c_str());
157 } else if (failure.file_) {
158 printf("\n");
159 }
160 if (!failure.message_.empty()) {
Haibo Huangb0bee822021-02-24 15:40:15 -0800161 Json::String reindented = indentText(failure.message_, indent + " ");
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -0500162 printf("%s\n", reindented.c_str());
163 }
164 }
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -0400165}
166
Haibo Huangb0bee822021-02-24 15:40:15 -0800167Json::String TestResult::indentText(const Json::String& text,
168 const Json::String& indent) {
169 Json::String reindented;
170 Json::String::size_type lastIndex = 0;
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -0500171 while (lastIndex < text.size()) {
Haibo Huangb0bee822021-02-24 15:40:15 -0800172 Json::String::size_type nextIndex = text.find('\n', lastIndex);
173 if (nextIndex == Json::String::npos) {
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -0500174 nextIndex = text.size() - 1;
175 }
176 reindented += indent;
177 reindented += text.substr(lastIndex, nextIndex - lastIndex + 1);
178 lastIndex = nextIndex + 1;
179 }
180 return reindented;
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -0400181}
182
Haibo Huangb0bee822021-02-24 15:40:15 -0800183TestResult& TestResult::addToLastFailure(const Json::String& message) {
184 if (messageTarget_ != nullptr) {
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -0500185 messageTarget_->message_ += message;
186 }
187 return *this;
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -0400188}
189
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -0500190TestResult& TestResult::operator<<(Json::Int64 value) {
191 return addToLastFailure(Json::valueToString(value));
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -0400192}
193
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -0500194TestResult& TestResult::operator<<(Json::UInt64 value) {
195 return addToLastFailure(Json::valueToString(value));
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -0400196}
197
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -0500198TestResult& TestResult::operator<<(bool value) {
199 return addToLastFailure(value ? "true" : "false");
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -0400200}
201
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -0400202// class TestCase
203// //////////////////////////////////////////////////////////////////
204
Haibo Huangb0bee822021-02-24 15:40:15 -0800205TestCase::TestCase() = default;
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -0500206
Haibo Huangb0bee822021-02-24 15:40:15 -0800207TestCase::~TestCase() = default;
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -0500208
209void TestCase::run(TestResult& result) {
210 result_ = &result;
211 runTestCase();
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -0400212}
213
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -0400214// class Runner
215// //////////////////////////////////////////////////////////////////
216
Haibo Huangb0bee822021-02-24 15:40:15 -0800217Runner::Runner() = default;
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -0500218
219Runner& Runner::add(TestCaseFactory factory) {
220 tests_.push_back(factory);
221 return *this;
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -0400222}
223
Haibo Huangb0bee822021-02-24 15:40:15 -0800224size_t Runner::testCount() const { return tests_.size(); }
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -0400225
Haibo Huangb0bee822021-02-24 15:40:15 -0800226Json::String Runner::testNameAt(size_t index) const {
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -0500227 TestCase* test = tests_[index]();
Haibo Huangb0bee822021-02-24 15:40:15 -0800228 Json::String name = test->testName();
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -0500229 delete test;
230 return name;
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -0400231}
232
Haibo Huangb0bee822021-02-24 15:40:15 -0800233void Runner::runTestAt(size_t index, TestResult& result) const {
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -0500234 TestCase* test = tests_[index]();
235 result.setTestName(test->testName());
236 printf("Testing %s: ", test->testName());
237 fflush(stdout);
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -0400238#if JSON_USE_EXCEPTION
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -0500239 try {
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -0400240#endif // if JSON_USE_EXCEPTION
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -0500241 test->run(result);
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -0400242#if JSON_USE_EXCEPTION
Haibo Huangb0bee822021-02-24 15:40:15 -0800243 } catch (const std::exception& e) {
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -0500244 result.addFailure(__FILE__, __LINE__, "Unexpected exception caught:")
245 << e.what();
246 }
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -0400247#endif // if JSON_USE_EXCEPTION
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -0500248 delete test;
249 const char* status = result.failed() ? "FAILED" : "OK";
250 printf("%s\n", status);
251 fflush(stdout);
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -0400252}
253
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -0500254bool Runner::runAllTest(bool printSummary) const {
Haibo Huangb0bee822021-02-24 15:40:15 -0800255 size_t const count = testCount();
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -0500256 std::deque<TestResult> failures;
Haibo Huangb0bee822021-02-24 15:40:15 -0800257 for (size_t index = 0; index < count; ++index) {
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -0500258 TestResult result;
259 runTestAt(index, result);
260 if (result.failed()) {
261 failures.push_back(result);
262 }
263 }
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -0400264
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -0500265 if (failures.empty()) {
266 if (printSummary) {
Haibo Huangb0bee822021-02-24 15:40:15 -0800267 printf("All %zu tests passed\n", count);
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -0500268 }
269 return true;
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -0500270 }
Haibo Huangb0bee822021-02-24 15:40:15 -0800271 for (auto& result : failures) {
272 result.printFailure(count > 1);
273 }
274
275 if (printSummary) {
276 size_t const failedCount = failures.size();
277 size_t const passedCount = count - failedCount;
278 printf("%zu/%zu tests passed (%zu failure(s))\n", passedCount, count,
279 failedCount);
280 }
281 return false;
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -0500282}
283
Haibo Huangb0bee822021-02-24 15:40:15 -0800284bool Runner::testIndex(const Json::String& testName, size_t& indexOut) const {
285 const size_t count = testCount();
286 for (size_t index = 0; index < count; ++index) {
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -0500287 if (testNameAt(index) == testName) {
288 indexOut = index;
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -0400289 return true;
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -0500290 }
291 }
292 return false;
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -0400293}
294
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -0500295void Runner::listTests() const {
Haibo Huangb0bee822021-02-24 15:40:15 -0800296 const size_t count = testCount();
297 for (size_t index = 0; index < count; ++index) {
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -0500298 printf("%s\n", testNameAt(index).c_str());
299 }
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -0400300}
301
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -0500302int Runner::runCommandLine(int argc, const char* argv[]) const {
Haibo Huangb0bee822021-02-24 15:40:15 -0800303 // typedef std::deque<String> TestNames;
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -0500304 Runner subrunner;
305 for (int index = 1; index < argc; ++index) {
Haibo Huangb0bee822021-02-24 15:40:15 -0800306 Json::String opt = argv[index];
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -0500307 if (opt == "--list-tests") {
308 listTests();
309 return 0;
Haibo Huangb0bee822021-02-24 15:40:15 -0800310 }
311 if (opt == "--test-auto") {
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -0500312 preventDialogOnCrash();
313 } else if (opt == "--test") {
314 ++index;
315 if (index < argc) {
Haibo Huangb0bee822021-02-24 15:40:15 -0800316 size_t testNameIndex;
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -0500317 if (testIndex(argv[index], testNameIndex)) {
318 subrunner.add(tests_[testNameIndex]);
319 } else {
320 fprintf(stderr, "Test '%s' does not exist!\n", argv[index]);
321 return 2;
322 }
323 } else {
324 printUsage(argv[0]);
325 return 2;
326 }
327 } else {
328 printUsage(argv[0]);
329 return 2;
330 }
331 }
332 bool succeeded;
333 if (subrunner.testCount() > 0) {
334 succeeded = subrunner.runAllTest(subrunner.testCount() > 1);
335 } else {
336 succeeded = runAllTest(true);
337 }
338 return succeeded ? 0 : 1;
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -0400339}
340
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -0500341#if defined(_MSC_VER) && defined(_DEBUG)
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -0400342// Hook MSVCRT assertions to prevent dialog from appearing
Haibo Huangb0bee822021-02-24 15:40:15 -0800343static int msvcrtSilentReportHook(int reportType, char* message,
344 int* /*returnValue*/) {
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -0500345 // The default CRT handling of error and assertion is to display
346 // an error dialog to the user.
347 // Instead, when an error or an assertion occurs, we force the
348 // application to terminate using abort() after display
349 // the message on stderr.
350 if (reportType == _CRT_ERROR || reportType == _CRT_ASSERT) {
351 // calling abort() cause the ReportHook to be called
352 // The following is used to detect this case and let's the
353 // error handler fallback on its default behaviour (
354 // display a warning message)
355 static volatile bool isAborting = false;
356 if (isAborting) {
357 return TRUE;
358 }
359 isAborting = true;
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -0400360
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -0500361 fprintf(stderr, "CRT Error/Assert:\n%s\n", message);
362 fflush(stderr);
363 abort();
364 }
365 // Let's other reportType (_CRT_WARNING) be handled as they would by default
366 return FALSE;
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -0400367}
368#endif // if defined(_MSC_VER)
369
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -0500370void Runner::preventDialogOnCrash() {
371#if defined(_MSC_VER) && defined(_DEBUG)
372 // Install a hook to prevent MSVCRT error and assertion from
373 // popping a dialog
374 // This function a NO-OP in release configuration
375 // (which cause warning since msvcrtSilentReportHook is not referenced)
376 _CrtSetReportHook(&msvcrtSilentReportHook);
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -0400377#endif // if defined(_MSC_VER)
378
Haibo Huangb0bee822021-02-24 15:40:15 -0800379 // @todo investigate this handler (for buffer overflow)
380 // _set_security_error_handler
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -0400381
382#if defined(_WIN32)
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -0500383 // Prevents the system from popping a dialog for debugging if the
384 // application fails due to invalid memory access.
385 SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX |
386 SEM_NOOPENFILEERRORBOX);
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -0400387#endif // if defined(_WIN32)
388}
389
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -0500390void Runner::printUsage(const char* appName) {
391 printf("Usage: %s [options]\n"
392 "\n"
393 "If --test is not specified, then all the test cases be run.\n"
394 "\n"
395 "Valid options:\n"
396 "--list-tests: print the name of all test cases on the standard\n"
397 " output and exit.\n"
398 "--test TESTNAME: executes the test case with the specified name.\n"
399 " May be repeated.\n"
400 "--test-auto: prevent dialog prompting for debugging on crash.\n",
401 appName);
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -0400402}
403
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -0400404// Assertion functions
405// //////////////////////////////////////////////////////////////////
406
Haibo Huangb0bee822021-02-24 15:40:15 -0800407Json::String ToJsonString(const char* toConvert) {
408 return Json::String(toConvert);
409}
410
411Json::String ToJsonString(Json::String in) { return in; }
412
413#if JSONCPP_USING_SECURE_MEMORY
414Json::String ToJsonString(std::string in) {
415 return Json::String(in.data(), in.data() + in.length());
416}
417#endif
418
419TestResult& checkStringEqual(TestResult& result, const Json::String& expected,
420 const Json::String& actual, const char* file,
421 unsigned int line, const char* expr) {
Derek Sollenberger2eb3b4d2016-01-11 14:41:40 -0500422 if (expected != actual) {
423 result.addFailure(file, line, expr);
424 result << "Expected: '" << expected << "'\n";
425 result << "Actual : '" << actual << "'";
426 }
427 return result;
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -0400428}
429
Leon Scroggins IIIf59fb0e2014-05-28 15:19:42 -0400430} // namespace JsonTest