init repo.
This commit is contained in:
430
third_party/jsoncpp/src/test_lib_json/jsontest.cpp
vendored
Normal file
430
third_party/jsoncpp/src/test_lib_json/jsontest.cpp
vendored
Normal file
@ -0,0 +1,430 @@
|
||||
// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors
|
||||
// Distributed under MIT license, or public domain if desired and
|
||||
// recognized in your jurisdiction.
|
||||
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
|
||||
|
||||
#define _CRT_SECURE_NO_WARNINGS 1 // Prevents deprecation warning with MSVC
|
||||
#include "jsontest.h"
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
// Used to install a report hook that prevent dialog on assertion and error.
|
||||
#include <crtdbg.h>
|
||||
#endif // if defined(_MSC_VER)
|
||||
|
||||
#if defined(_WIN32)
|
||||
// Used to prevent dialog on memory fault.
|
||||
// Limits headers included by Windows.h
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#define NOSERVICE
|
||||
#define NOMCX
|
||||
#define NOIME
|
||||
#define NOSOUND
|
||||
#define NOCOMM
|
||||
#define NORPC
|
||||
#define NOGDI
|
||||
#define NOUSER
|
||||
#define NODRIVERS
|
||||
#define NOLOGERROR
|
||||
#define NOPROFILER
|
||||
#define NOMEMMGR
|
||||
#define NOLFILEIO
|
||||
#define NOOPENFILE
|
||||
#define NORESOURCE
|
||||
#define NOATOM
|
||||
#define NOLANGUAGE
|
||||
#define NOLSTRING
|
||||
#define NODBCS
|
||||
#define NOKEYBOARDINFO
|
||||
#define NOGDICAPMASKS
|
||||
#define NOCOLOR
|
||||
#define NOGDIOBJ
|
||||
#define NODRAWTEXT
|
||||
#define NOTEXTMETRIC
|
||||
#define NOSCALABLEFONT
|
||||
#define NOBITMAP
|
||||
#define NORASTEROPS
|
||||
#define NOMETAFILE
|
||||
#define NOSYSMETRICS
|
||||
#define NOSYSTEMPARAMSINFO
|
||||
#define NOMSG
|
||||
#define NOWINSTYLES
|
||||
#define NOWINOFFSETS
|
||||
#define NOSHOWWINDOW
|
||||
#define NODEFERWINDOWPOS
|
||||
#define NOVIRTUALKEYCODES
|
||||
#define NOKEYSTATES
|
||||
#define NOWH
|
||||
#define NOMENUS
|
||||
#define NOSCROLL
|
||||
#define NOCLIPBOARD
|
||||
#define NOICONS
|
||||
#define NOMB
|
||||
#define NOSYSCOMMANDS
|
||||
#define NOMDI
|
||||
#define NOCTLMGR
|
||||
#define NOWINMESSAGES
|
||||
#include <windows.h>
|
||||
#endif // if defined(_WIN32)
|
||||
|
||||
namespace JsonTest {
|
||||
|
||||
// class TestResult
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
|
||||
TestResult::TestResult() {
|
||||
// The root predicate has id 0
|
||||
rootPredicateNode_.id_ = 0;
|
||||
rootPredicateNode_.next_ = nullptr;
|
||||
predicateStackTail_ = &rootPredicateNode_;
|
||||
}
|
||||
|
||||
void TestResult::setTestName(const Json::String& name) { name_ = name; }
|
||||
|
||||
TestResult& TestResult::addFailure(const char* file, unsigned int line,
|
||||
const char* expr) {
|
||||
/// Walks the PredicateContext stack adding them to failures_ if not already
|
||||
/// added.
|
||||
unsigned int nestingLevel = 0;
|
||||
PredicateContext* lastNode = rootPredicateNode_.next_;
|
||||
for (; lastNode != nullptr; lastNode = lastNode->next_) {
|
||||
if (lastNode->id_ > lastUsedPredicateId_) // new PredicateContext
|
||||
{
|
||||
lastUsedPredicateId_ = lastNode->id_;
|
||||
addFailureInfo(lastNode->file_, lastNode->line_, lastNode->expr_,
|
||||
nestingLevel);
|
||||
// Link the PredicateContext to the failure for message target when
|
||||
// popping the PredicateContext.
|
||||
lastNode->failure_ = &(failures_.back());
|
||||
}
|
||||
++nestingLevel;
|
||||
}
|
||||
|
||||
// Adds the failed assertion
|
||||
addFailureInfo(file, line, expr, nestingLevel);
|
||||
messageTarget_ = &(failures_.back());
|
||||
return *this;
|
||||
}
|
||||
|
||||
void TestResult::addFailureInfo(const char* file, unsigned int line,
|
||||
const char* expr, unsigned int nestingLevel) {
|
||||
Failure failure;
|
||||
failure.file_ = file;
|
||||
failure.line_ = line;
|
||||
if (expr) {
|
||||
failure.expr_ = expr;
|
||||
}
|
||||
failure.nestingLevel_ = nestingLevel;
|
||||
failures_.push_back(failure);
|
||||
}
|
||||
|
||||
TestResult& TestResult::popPredicateContext() {
|
||||
PredicateContext* lastNode = &rootPredicateNode_;
|
||||
while (lastNode->next_ != nullptr && lastNode->next_->next_ != nullptr) {
|
||||
lastNode = lastNode->next_;
|
||||
}
|
||||
// Set message target to popped failure
|
||||
PredicateContext* tail = lastNode->next_;
|
||||
if (tail != nullptr && tail->failure_ != nullptr) {
|
||||
messageTarget_ = tail->failure_;
|
||||
}
|
||||
// Remove tail from list
|
||||
predicateStackTail_ = lastNode;
|
||||
lastNode->next_ = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool TestResult::failed() const { return !failures_.empty(); }
|
||||
|
||||
void TestResult::printFailure(bool printTestName) const {
|
||||
if (failures_.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (printTestName) {
|
||||
printf("* Detail of %s test failure:\n", name_.c_str());
|
||||
}
|
||||
|
||||
// Print in reverse to display the callstack in the right order
|
||||
for (const auto& failure : failures_) {
|
||||
Json::String indent(failure.nestingLevel_ * 2, ' ');
|
||||
if (failure.file_) {
|
||||
printf("%s%s(%u): ", indent.c_str(), failure.file_, failure.line_);
|
||||
}
|
||||
if (!failure.expr_.empty()) {
|
||||
printf("%s\n", failure.expr_.c_str());
|
||||
} else if (failure.file_) {
|
||||
printf("\n");
|
||||
}
|
||||
if (!failure.message_.empty()) {
|
||||
Json::String reindented = indentText(failure.message_, indent + " ");
|
||||
printf("%s\n", reindented.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Json::String TestResult::indentText(const Json::String& text,
|
||||
const Json::String& indent) {
|
||||
Json::String reindented;
|
||||
Json::String::size_type lastIndex = 0;
|
||||
while (lastIndex < text.size()) {
|
||||
Json::String::size_type nextIndex = text.find('\n', lastIndex);
|
||||
if (nextIndex == Json::String::npos) {
|
||||
nextIndex = text.size() - 1;
|
||||
}
|
||||
reindented += indent;
|
||||
reindented += text.substr(lastIndex, nextIndex - lastIndex + 1);
|
||||
lastIndex = nextIndex + 1;
|
||||
}
|
||||
return reindented;
|
||||
}
|
||||
|
||||
TestResult& TestResult::addToLastFailure(const Json::String& message) {
|
||||
if (messageTarget_ != nullptr) {
|
||||
messageTarget_->message_ += message;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
TestResult& TestResult::operator<<(Json::Int64 value) {
|
||||
return addToLastFailure(Json::valueToString(value));
|
||||
}
|
||||
|
||||
TestResult& TestResult::operator<<(Json::UInt64 value) {
|
||||
return addToLastFailure(Json::valueToString(value));
|
||||
}
|
||||
|
||||
TestResult& TestResult::operator<<(bool value) {
|
||||
return addToLastFailure(value ? "true" : "false");
|
||||
}
|
||||
|
||||
// class TestCase
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
|
||||
TestCase::TestCase() = default;
|
||||
|
||||
TestCase::~TestCase() = default;
|
||||
|
||||
void TestCase::run(TestResult& result) {
|
||||
result_ = &result;
|
||||
runTestCase();
|
||||
}
|
||||
|
||||
// class Runner
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
|
||||
Runner::Runner() = default;
|
||||
|
||||
Runner& Runner::add(TestCaseFactory factory) {
|
||||
tests_.push_back(factory);
|
||||
return *this;
|
||||
}
|
||||
|
||||
size_t Runner::testCount() const { return tests_.size(); }
|
||||
|
||||
Json::String Runner::testNameAt(size_t index) const {
|
||||
TestCase* test = tests_[index]();
|
||||
Json::String name = test->testName();
|
||||
delete test;
|
||||
return name;
|
||||
}
|
||||
|
||||
void Runner::runTestAt(size_t index, TestResult& result) const {
|
||||
TestCase* test = tests_[index]();
|
||||
result.setTestName(test->testName());
|
||||
printf("Testing %s: ", test->testName());
|
||||
fflush(stdout);
|
||||
#if JSON_USE_EXCEPTION
|
||||
try {
|
||||
#endif // if JSON_USE_EXCEPTION
|
||||
test->run(result);
|
||||
#if JSON_USE_EXCEPTION
|
||||
} catch (const std::exception& e) {
|
||||
result.addFailure(__FILE__, __LINE__, "Unexpected exception caught:")
|
||||
<< e.what();
|
||||
}
|
||||
#endif // if JSON_USE_EXCEPTION
|
||||
delete test;
|
||||
const char* status = result.failed() ? "FAILED" : "OK";
|
||||
printf("%s\n", status);
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
bool Runner::runAllTest(bool printSummary) const {
|
||||
size_t const count = testCount();
|
||||
std::deque<TestResult> failures;
|
||||
for (size_t index = 0; index < count; ++index) {
|
||||
TestResult result;
|
||||
runTestAt(index, result);
|
||||
if (result.failed()) {
|
||||
failures.push_back(result);
|
||||
}
|
||||
}
|
||||
|
||||
if (failures.empty()) {
|
||||
if (printSummary) {
|
||||
printf("All %zu tests passed\n", count);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
for (auto& result : failures) {
|
||||
result.printFailure(count > 1);
|
||||
}
|
||||
|
||||
if (printSummary) {
|
||||
size_t const failedCount = failures.size();
|
||||
size_t const passedCount = count - failedCount;
|
||||
printf("%zu/%zu tests passed (%zu failure(s))\n", passedCount, count,
|
||||
failedCount);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Runner::testIndex(const Json::String& testName, size_t& indexOut) const {
|
||||
const size_t count = testCount();
|
||||
for (size_t index = 0; index < count; ++index) {
|
||||
if (testNameAt(index) == testName) {
|
||||
indexOut = index;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Runner::listTests() const {
|
||||
const size_t count = testCount();
|
||||
for (size_t index = 0; index < count; ++index) {
|
||||
printf("%s\n", testNameAt(index).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
int Runner::runCommandLine(int argc, const char* argv[]) const {
|
||||
// typedef std::deque<String> TestNames;
|
||||
Runner subrunner;
|
||||
for (int index = 1; index < argc; ++index) {
|
||||
Json::String opt = argv[index];
|
||||
if (opt == "--list-tests") {
|
||||
listTests();
|
||||
return 0;
|
||||
}
|
||||
if (opt == "--test-auto") {
|
||||
preventDialogOnCrash();
|
||||
} else if (opt == "--test") {
|
||||
++index;
|
||||
if (index < argc) {
|
||||
size_t testNameIndex;
|
||||
if (testIndex(argv[index], testNameIndex)) {
|
||||
subrunner.add(tests_[testNameIndex]);
|
||||
} else {
|
||||
fprintf(stderr, "Test '%s' does not exist!\n", argv[index]);
|
||||
return 2;
|
||||
}
|
||||
} else {
|
||||
printUsage(argv[0]);
|
||||
return 2;
|
||||
}
|
||||
} else {
|
||||
printUsage(argv[0]);
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
bool succeeded;
|
||||
if (subrunner.testCount() > 0) {
|
||||
succeeded = subrunner.runAllTest(subrunner.testCount() > 1);
|
||||
} else {
|
||||
succeeded = runAllTest(true);
|
||||
}
|
||||
return succeeded ? 0 : 1;
|
||||
}
|
||||
|
||||
#if defined(_MSC_VER) && defined(_DEBUG)
|
||||
// Hook MSVCRT assertions to prevent dialog from appearing
|
||||
static int msvcrtSilentReportHook(int reportType, char* message,
|
||||
int* /*returnValue*/) {
|
||||
// The default CRT handling of error and assertion is to display
|
||||
// an error dialog to the user.
|
||||
// Instead, when an error or an assertion occurs, we force the
|
||||
// application to terminate using abort() after display
|
||||
// the message on stderr.
|
||||
if (reportType == _CRT_ERROR || reportType == _CRT_ASSERT) {
|
||||
// calling abort() cause the ReportHook to be called
|
||||
// The following is used to detect this case and let's the
|
||||
// error handler fallback on its default behaviour (
|
||||
// display a warning message)
|
||||
static volatile bool isAborting = false;
|
||||
if (isAborting) {
|
||||
return TRUE;
|
||||
}
|
||||
isAborting = true;
|
||||
|
||||
fprintf(stderr, "CRT Error/Assert:\n%s\n", message);
|
||||
fflush(stderr);
|
||||
abort();
|
||||
}
|
||||
// Let's other reportType (_CRT_WARNING) be handled as they would by default
|
||||
return FALSE;
|
||||
}
|
||||
#endif // if defined(_MSC_VER)
|
||||
|
||||
void Runner::preventDialogOnCrash() {
|
||||
#if defined(_MSC_VER) && defined(_DEBUG)
|
||||
// Install a hook to prevent MSVCRT error and assertion from
|
||||
// popping a dialog
|
||||
// This function a NO-OP in release configuration
|
||||
// (which cause warning since msvcrtSilentReportHook is not referenced)
|
||||
_CrtSetReportHook(&msvcrtSilentReportHook);
|
||||
#endif // if defined(_MSC_VER)
|
||||
|
||||
// @todo investigate this handler (for buffer overflow)
|
||||
// _set_security_error_handler
|
||||
|
||||
#if defined(_WIN32)
|
||||
// Prevents the system from popping a dialog for debugging if the
|
||||
// application fails due to invalid memory access.
|
||||
SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX |
|
||||
SEM_NOOPENFILEERRORBOX);
|
||||
#endif // if defined(_WIN32)
|
||||
}
|
||||
|
||||
void Runner::printUsage(const char* appName) {
|
||||
printf("Usage: %s [options]\n"
|
||||
"\n"
|
||||
"If --test is not specified, then all the test cases be run.\n"
|
||||
"\n"
|
||||
"Valid options:\n"
|
||||
"--list-tests: print the name of all test cases on the standard\n"
|
||||
" output and exit.\n"
|
||||
"--test TESTNAME: executes the test case with the specified name.\n"
|
||||
" May be repeated.\n"
|
||||
"--test-auto: prevent dialog prompting for debugging on crash.\n",
|
||||
appName);
|
||||
}
|
||||
|
||||
// Assertion functions
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
|
||||
Json::String ToJsonString(const char* toConvert) {
|
||||
return Json::String(toConvert);
|
||||
}
|
||||
|
||||
Json::String ToJsonString(Json::String in) { return in; }
|
||||
|
||||
#if JSONCPP_USING_SECURE_MEMORY
|
||||
Json::String ToJsonString(std::string in) {
|
||||
return Json::String(in.data(), in.data() + in.length());
|
||||
}
|
||||
#endif
|
||||
|
||||
TestResult& checkStringEqual(TestResult& result, const Json::String& expected,
|
||||
const Json::String& actual, const char* file,
|
||||
unsigned int line, const char* expr) {
|
||||
if (expected != actual) {
|
||||
result.addFailure(file, line, expr);
|
||||
result << "Expected: '" << expected << "'\n";
|
||||
result << "Actual : '" << actual << "'";
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace JsonTest
|
Reference in New Issue
Block a user