aboutsummaryrefslogtreecommitdiff
path: root/lib/jsoncpp/src/test_lib_json/jsontest.cpp
diff options
context:
space:
mode:
authortheuni <theuni-nospam-@xbmc.org>2011-01-24 16:05:21 -0500
committertheuni <theuni-nospam-@xbmc.org>2011-01-24 16:05:21 -0500
commitc51b1189e3d5353e842991f5859ddcea0f73e426 (patch)
treeef2cb8a6184699aa614f3655dca4ce661cdc108e /lib/jsoncpp/src/test_lib_json/jsontest.cpp
parentbe61ebdc9e897fe40c6f371111724de79ddee8d5 (diff)
Merged cptspiff's code-reshuffle branch.
Squashed commit due to build breakage during code-reshuffle history. Conflicts: xbmc/Util.cpp xbmc/cdrip/CDDARipper.cpp xbmc/filesystem/Directory.cpp xbmc/filesystem/File.cpp
Diffstat (limited to 'lib/jsoncpp/src/test_lib_json/jsontest.cpp')
-rw-r--r--lib/jsoncpp/src/test_lib_json/jsontest.cpp598
1 files changed, 598 insertions, 0 deletions
diff --git a/lib/jsoncpp/src/test_lib_json/jsontest.cpp b/lib/jsoncpp/src/test_lib_json/jsontest.cpp
new file mode 100644
index 0000000000..dfd2b5c77d
--- /dev/null
+++ b/lib/jsoncpp/src/test_lib_json/jsontest.cpp
@@ -0,0 +1,598 @@
+#define _CRT_SECURE_NO_WARNINGS 1 // Prevents deprecation warning with MSVC
+#include "jsontest.h"
+#include <stdio.h>
+#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()
+ : predicateId_( 1 )
+ , lastUsedPredicateId_( 0 )
+ , messageTarget_( 0 )
+{
+ // The root predicate has id 0
+ rootPredicateNode_.id_ = 0;
+ rootPredicateNode_.next_ = 0;
+ predicateStackTail_ = &rootPredicateNode_;
+}
+
+
+void
+TestResult::setTestName( const std::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 != 0; 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_ != 0 && lastNode->next_->next_ != 0 )
+ {
+ lastNode = lastNode->next_;
+ }
+ // Set message target to popped failure
+ PredicateContext *tail = lastNode->next_;
+ if ( tail != 0 && tail->failure_ != 0 )
+ {
+ messageTarget_ = tail->failure_;
+ }
+ // Remove tail from list
+ predicateStackTail_ = lastNode;
+ lastNode->next_ = 0;
+ return *this;
+}
+
+
+bool
+TestResult::failed() const
+{
+ return !failures_.empty();
+}
+
+
+unsigned int
+TestResult::getAssertionNestingLevel() const
+{
+ unsigned int level = 0;
+ const PredicateContext *lastNode = &rootPredicateNode_;
+ while ( lastNode->next_ != 0 )
+ {
+ lastNode = lastNode->next_;
+ ++level;
+ }
+ return level;
+}
+
+
+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
+ Failures::const_iterator itEnd = failures_.end();
+ for ( Failures::const_iterator it = failures_.begin(); it != itEnd; ++it )
+ {
+ const Failure &failure = *it;
+ std::string indent( failure.nestingLevel_ * 2, ' ' );
+ if ( failure.file_ )
+ {
+ printf( "%s%s(%d): ", 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() )
+ {
+ std::string reindented = indentText( failure.message_, indent + " " );
+ printf( "%s\n", reindented.c_str() );
+ }
+ }
+}
+
+
+std::string
+TestResult::indentText( const std::string &text,
+ const std::string &indent )
+{
+ std::string reindented;
+ std::string::size_type lastIndex = 0;
+ while ( lastIndex < text.size() )
+ {
+ std::string::size_type nextIndex = text.find( '\n', lastIndex );
+ if ( nextIndex == std::string::npos )
+ {
+ nextIndex = text.size() - 1;
+ }
+ reindented += indent;
+ reindented += text.substr( lastIndex, nextIndex - lastIndex + 1 );
+ lastIndex = nextIndex + 1;
+ }
+ return reindented;
+}
+
+
+TestResult &
+TestResult::addToLastFailure( const std::string &message )
+{
+ if ( messageTarget_ != 0 )
+ {
+ messageTarget_->message_ += message;
+ }
+ return *this;
+}
+
+
+TestResult &
+TestResult::operator << ( bool value )
+{
+ return addToLastFailure( value ? "true" : "false" );
+}
+
+
+TestResult &
+TestResult::operator << ( int value )
+{
+ char buffer[32];
+ sprintf( buffer, "%d", value );
+ return addToLastFailure( buffer );
+}
+
+
+TestResult &
+TestResult::operator << ( unsigned int value )
+{
+ char buffer[32];
+ sprintf( buffer, "%u", value );
+ return addToLastFailure( buffer );
+}
+
+
+TestResult &
+TestResult::operator << ( double value )
+{
+ char buffer[32];
+ sprintf( buffer, "%16g", value );
+ return addToLastFailure( buffer );
+}
+
+
+TestResult &
+TestResult::operator << ( const char *value )
+{
+ return addToLastFailure( value ? value
+ : "<NULL>" );
+}
+
+
+TestResult &
+TestResult::operator << ( const std::string &value )
+{
+ return addToLastFailure( value );
+}
+
+
+
+// class TestCase
+// //////////////////////////////////////////////////////////////////
+
+TestCase::TestCase()
+ : result_( 0 )
+{
+}
+
+
+void
+TestCase::run( TestResult &result )
+{
+ result_ = &result;
+ runTestCase();
+}
+
+
+
+// class Runner
+// //////////////////////////////////////////////////////////////////
+
+Runner::Runner()
+{
+}
+
+
+Runner &
+Runner::add( TestCaseFactory factory )
+{
+ tests_.push_back( factory );
+ return *this;
+}
+
+
+unsigned int
+Runner::testCount() const
+{
+ return static_cast<unsigned int>( tests_.size() );
+}
+
+
+std::string
+Runner::testNameAt( unsigned int index ) const
+{
+ TestCase *test = tests_[index]();
+ std::string name = test->testName();
+ delete test;
+ return name;
+}
+
+
+void
+Runner::runTestAt( unsigned int 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 caugth:" ) << 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
+{
+ unsigned int count = testCount();
+ std::deque<TestResult> failures;
+ for ( unsigned int index = 0; index < count; ++index )
+ {
+ TestResult result;
+ runTestAt( index, result );
+ if ( result.failed() )
+ {
+ failures.push_back( result );
+ }
+ }
+
+ if ( failures.empty() )
+ {
+ if ( printSummary )
+ {
+ printf( "All %d tests passed\n", count );
+ }
+ return true;
+ }
+ else
+ {
+ for ( unsigned int index = 0; index < failures.size(); ++index )
+ {
+ TestResult &result = failures[index];
+ result.printFailure( count > 1 );
+ }
+
+ if ( printSummary )
+ {
+ unsigned int failedCount = static_cast<unsigned int>( failures.size() );
+ unsigned int passedCount = count - failedCount;
+ printf( "%d/%d tests passed (%d failure(s))\n", passedCount, count, failedCount );
+ }
+ return false;
+ }
+}
+
+
+bool
+Runner::testIndex( const std::string &testName,
+ unsigned int &indexOut ) const
+{
+ unsigned int count = testCount();
+ for ( unsigned int index = 0; index < count; ++index )
+ {
+ if ( testNameAt(index) == testName )
+ {
+ indexOut = index;
+ return true;
+ }
+ }
+ return false;
+}
+
+
+void
+Runner::listTests() const
+{
+ unsigned int count = testCount();
+ for ( unsigned int index = 0; index < count; ++index )
+ {
+ printf( "%s\n", testNameAt( index ).c_str() );
+ }
+}
+
+
+int
+Runner::runCommandLine( int argc, const char *argv[] ) const
+{
+ typedef std::deque<std::string> TestNames;
+ Runner subrunner;
+ for ( int index = 1; index < argc; ++index )
+ {
+ std::string opt = argv[index];
+ if ( opt == "--list-tests" )
+ {
+ listTests();
+ return 0;
+ }
+ else if ( opt == "--test-auto" )
+ {
+ preventDialogOnCrash();
+ }
+ else if ( opt == "--test" )
+ {
+ ++index;
+ if ( index < argc )
+ {
+ unsigned int 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)
+// 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)
+ // Install a hook to prevent MSVCRT error and assertion from
+ // popping a dialog.
+ _CrtSetReportHook( &msvcrtSilentReportHook );
+#endif // if defined(_MSC_VER)
+
+ // @todo investiguate 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
+// //////////////////////////////////////////////////////////////////
+
+TestResult &
+checkStringEqual( TestResult &result,
+ const std::string &expected, const std::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