It is accomplished ...
git-svn-id: file:///srv/svn/repos/haiku/trunk/current@10 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -0,0 +1,213 @@
|
||||
//----------------------------------------------------------------------
|
||||
// CppUnitShell.cpp - Copyright 2002 Tyler Dauwalder
|
||||
// This software is release under the GNU Lesser GPL
|
||||
// See the accompanying CppUnitShell.LICENSE file, or wander
|
||||
// over to: http://www.gnu.org/copyleft/lesser.html
|
||||
//----------------------------------------------------------------------
|
||||
#include "CppUnitShell.h"
|
||||
|
||||
#include <cppunit/Exception.h>
|
||||
#include <cppunit/Test.h>
|
||||
#include <cppunit/TestFailure.h>
|
||||
#include <cppunit/TestResult.h>
|
||||
#include <cppunit/TestSuite.h>
|
||||
#include <set>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
CppUnitShell::CppUnitShell(const std::string &description, SyncObject *syncObject)
|
||||
: fVerbosityLevel(v2)
|
||||
, fDescription(description)
|
||||
, fTestResults(syncObject)
|
||||
{
|
||||
};
|
||||
|
||||
void
|
||||
CppUnitShell::AddSuite(const std::string &name, const SuiteFunction suite) {
|
||||
if (suite != NULL)
|
||||
fTests[name] = suite;
|
||||
}
|
||||
|
||||
int
|
||||
CppUnitShell::Run(int argc, char *argv[]) {
|
||||
// Parse the command line args
|
||||
if (!ProcessArguments(argc, argv))
|
||||
return 0;
|
||||
|
||||
// Add the proper tests to our suite (or exit if there
|
||||
// are no tests installed).
|
||||
CppUnit::TestSuite suite;
|
||||
if (fTests.empty()) {
|
||||
|
||||
// No installed tests whatsoever, so bail
|
||||
cout << "ERROR: No installed tests to run!" << endl;
|
||||
return 0;
|
||||
|
||||
} else if (fTestsToRun.empty()) {
|
||||
|
||||
// None specified, so run them all
|
||||
std::map<std::string, SuiteFunction>::iterator i;
|
||||
for (i = fTests.begin(); i != fTests.end(); ++i)
|
||||
suite.addTest( i->second() );
|
||||
|
||||
} else {
|
||||
|
||||
// One or more specified, so only run those
|
||||
std::set<std::string>::const_iterator i;
|
||||
for (i = fTestsToRun.begin(); i != fTestsToRun.end(); ++i)
|
||||
suite.addTest( fTests[*i]() );
|
||||
|
||||
}
|
||||
|
||||
// Run all the tests
|
||||
InitOutput();
|
||||
suite.run(&fTestResults);
|
||||
PrintResults();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
CppUnitShell::VerbosityLevel
|
||||
CppUnitShell::Verbosity() const {
|
||||
return fVerbosityLevel;
|
||||
}
|
||||
|
||||
void
|
||||
CppUnitShell::PrintDescription(int argc, char *argv[]) {
|
||||
cout << endl << fDescription;
|
||||
}
|
||||
|
||||
void
|
||||
CppUnitShell::PrintHelp() {
|
||||
const char indent[] = " ";
|
||||
cout << endl;
|
||||
cout << "VALID ARGUMENTS: " << endl;
|
||||
cout << indent << "--help Displays this help text plus some other garbage" << endl;
|
||||
cout << indent << "--list Lists the names of classes with installed tests" << endl;
|
||||
cout << indent << "-v0 Sets verbosity level to 0 (concise summary only)" << endl;
|
||||
cout << indent << "-v1 Sets verbosity level to 1 (complete summary only)" << endl;
|
||||
cout << indent << "-v2 Sets verbosity level to 2 (*default* -- per-test results plus" << endl;
|
||||
cout << indent << " complete summary)" << endl;
|
||||
cout << indent << "-v3 Sets verbosity level to 3 (per-test results and timing info" << endl;
|
||||
cout << indent << " plus complete summary)" << endl;
|
||||
cout << indent << "CLASSNAME Instructs the program to run the test for the given class; if" << endl;
|
||||
cout << indent << " no classes are specified, all tests are run" << endl;
|
||||
cout << endl;
|
||||
|
||||
}
|
||||
|
||||
bool
|
||||
CppUnitShell::ProcessArguments(int argc, char *argv[]) {
|
||||
// If we're given no parameters, the default settings
|
||||
// will do just fine
|
||||
if (argc < 2)
|
||||
return true;
|
||||
|
||||
// Handle each command line argument (skipping the first
|
||||
// which is just the app name)
|
||||
for (int i = 1; i < argc; i++) {
|
||||
std::string str(argv[i]);
|
||||
|
||||
if (str == "--help") {
|
||||
PrintDescription(argc, argv);
|
||||
PrintHelp();
|
||||
return false;
|
||||
}
|
||||
else if (str == "--list") {
|
||||
// Print out the list of installed tests
|
||||
cout << "------------------------------------------------------------------------------" << endl;
|
||||
cout << "Available Tests:" << endl;
|
||||
cout << "------------------------------------------------------------------------------" << endl;
|
||||
map<std::string, SuiteFunction>::const_iterator i;
|
||||
for (i = fTests.begin(); i != fTests.end(); ++i)
|
||||
cout << i->first << endl;
|
||||
cout << endl;
|
||||
return false;
|
||||
}
|
||||
else if (str == "-v0") {
|
||||
fVerbosityLevel = v0;
|
||||
}
|
||||
else if (str == "-v1") {
|
||||
fVerbosityLevel = v1;
|
||||
}
|
||||
else if (str == "-v2") {
|
||||
fVerbosityLevel = v2;
|
||||
}
|
||||
else if (fTests.find(str) != fTests.end()) {
|
||||
fTestsToRun.insert(str);
|
||||
}
|
||||
else {
|
||||
cout << endl << "ERROR: Invalid argument \"" << str << "\"" << endl;
|
||||
PrintHelp();
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
CppUnitShell::InitOutput() {
|
||||
// For vebosity level 2, we output info about each test
|
||||
// as we go. This involves a custom CppUnit::TestListener
|
||||
// class.
|
||||
if (fVerbosityLevel == v2) {
|
||||
cout << "------------------------------------------------------------------------------" << endl;
|
||||
cout << "Tests" << endl;
|
||||
cout << "------------------------------------------------------------------------------" << endl;
|
||||
fTestResults.addListener(new CppUnitShell::TestListener);
|
||||
fTestResults.addListener(&fResultsCollector);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CppUnitShell::PrintResults() {
|
||||
|
||||
if (fVerbosityLevel > v0) {
|
||||
// Print out detailed results for verbosity levels > 0
|
||||
cout << "------------------------------------------------------------------------------" << endl;
|
||||
cout << "Results " << endl;
|
||||
cout << "------------------------------------------------------------------------------" << endl;
|
||||
|
||||
// Print failures and errors if there are any, otherwise just say "PASSED"
|
||||
::CppUnit::TestResultCollector::TestFailures::const_iterator iFailure;
|
||||
if (fResultsCollector.testFailuresTotal() > 0) {
|
||||
if (fResultsCollector.testFailures() > 0) {
|
||||
cout << "- FAILURES: " << fResultsCollector.testFailures() << endl;
|
||||
for (iFailure = fResultsCollector.failures().begin();
|
||||
iFailure != fResultsCollector.failures().end();
|
||||
++iFailure)
|
||||
{
|
||||
if (!(*iFailure)->isError())
|
||||
cout << " " << (*iFailure)->toString() << endl;
|
||||
}
|
||||
}
|
||||
if (fResultsCollector.testErrors() > 0) {
|
||||
cout << "- ERRORS: " << fResultsCollector.testErrors() << endl;
|
||||
for (iFailure = fResultsCollector.failures().begin();
|
||||
iFailure != fResultsCollector.failures().end();
|
||||
++iFailure)
|
||||
{
|
||||
if ((*iFailure)->isError())
|
||||
cout << " " << (*iFailure)->toString() << endl;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
cout << "+ PASSED" << endl;
|
||||
|
||||
cout << endl;
|
||||
|
||||
}
|
||||
else {
|
||||
// Print out concise results for verbosity level == 0
|
||||
if (fResultsCollector.testFailuresTotal() > 0)
|
||||
cout << "- FAILED" << endl;
|
||||
else
|
||||
cout << "+ PASSED" << endl;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
SubDir OBOS_TOP sources tools cppunit ;
|
||||
|
||||
rule CppUnitLibrary
|
||||
{
|
||||
# CppUnitLibrary <sources> ;
|
||||
local _lib = libcppunit.so ;
|
||||
|
||||
UseCppUnitHeaders ;
|
||||
SetupObjectsDir ;
|
||||
MakeLocateObjects [ FGristFiles $(<) ] ;
|
||||
Main $(_lib) : $(<) ;
|
||||
MakeLocate $(_lib) : /boot/home/config/lib ;
|
||||
LINKFLAGS on $(_lib) = $(LINKFLAGS) -nostart -Xlinker -soname=\"$(_lib)\" ;
|
||||
}
|
||||
|
||||
CppUnitLibrary
|
||||
CppUnitShell.cpp
|
||||
TestCase.cpp
|
||||
TestResult.cpp
|
||||
TestShell.cpp
|
||||
TestSuite.cpp
|
||||
cppunit/Asserter.cpp
|
||||
cppunit/CompilerOutputter.cpp
|
||||
cppunit/Exception.cpp
|
||||
cppunit/NotEqualException.cpp
|
||||
cppunit/RepeatedTest.cpp
|
||||
cppunit/SourceLine.cpp
|
||||
cppunit/SynchronizedObject.cpp
|
||||
cppunit/TestAssert.cpp
|
||||
cppunit/TestCase.cpp
|
||||
cppunit/TestFactoryRegistry.cpp
|
||||
cppunit/TestFailure.cpp
|
||||
cppunit/TestResult.cpp
|
||||
cppunit/TestResultCollector.cpp
|
||||
cppunit/TestRunner.cpp
|
||||
cppunit/TestSetUp.cpp
|
||||
cppunit/TestSucessListener.cpp
|
||||
cppunit/TestSuite.cpp
|
||||
cppunit/TextOutputter.cpp
|
||||
cppunit/TextTestProgressListener.cpp
|
||||
cppunit/TextTestResult.cpp
|
||||
cppunit/TypeInfoHelper.cpp
|
||||
cppunit/XmlOutputter.cpp
|
||||
;
|
||||
|
||||
LinkSharedOSLibs libcppunit.so :
|
||||
stdc++.r4
|
||||
/boot/develop/lib/x86/libbe.so
|
||||
;
|
||||
@@ -0,0 +1,35 @@
|
||||
#include <TestCase.h>
|
||||
#include <unistd.h>
|
||||
|
||||
TestCase::TestCase()
|
||||
: CppUnit::TestCase()
|
||||
, fValidCWD(false)
|
||||
{
|
||||
}
|
||||
|
||||
TestCase::TestCase(std::string name)
|
||||
: CppUnit::TestCase(name)
|
||||
, fValidCWD(false)
|
||||
{
|
||||
}
|
||||
|
||||
// Saves the location of the current working directory. To return to the
|
||||
// last saved working directory, all \ref RestorCWD().
|
||||
void
|
||||
TestCase::SaveCWD() {
|
||||
fValidCWD = getcwd(fCurrentWorkingDir, B_PATH_NAME_LENGTH);
|
||||
}
|
||||
|
||||
/* Restores the current working directory to last directory saved by a
|
||||
call to SaveCWD(). If SaveCWD() has not been called and an alternate
|
||||
directory is specified by alternate, the current working directory is
|
||||
changed to alternate. If alternate is null, the current working directory
|
||||
is not modified.
|
||||
*/
|
||||
void
|
||||
TestCase::RestoreCWD(const char *alternate) {
|
||||
if (fValidCWD)
|
||||
chdir(fCurrentWorkingDir);
|
||||
else if (alternate != NULL)
|
||||
chdir(alternate);
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
#include <TestResult.h>
|
||||
#include <LockerSyncObject.h>
|
||||
|
||||
TestResult::TestResult()
|
||||
: CppUnit::TestResult(new LockerSyncObject())
|
||||
{
|
||||
}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
#include <TestShell.h>
|
||||
#include <iostream>
|
||||
#include <Path.h>
|
||||
#include <stdio.h>
|
||||
|
||||
TestShell::TestShell(const std::string &description, SyncObject *syncObject)
|
||||
: CppUnitShell(description, syncObject),
|
||||
fTestDir(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
TestShell::~TestShell()
|
||||
{
|
||||
delete fTestDir;
|
||||
}
|
||||
|
||||
int
|
||||
TestShell::Run(int argc, char *argv[])
|
||||
{
|
||||
// Let's hope BPath does work. ;-)
|
||||
BPath path(argv[0]);
|
||||
if (path.InitCheck() == B_OK) {
|
||||
fTestDir = new BPath();
|
||||
if (path.GetParent(fTestDir) != B_OK)
|
||||
printf("Couldn't get test dir.\n");
|
||||
} else
|
||||
printf("Couldn't find the path to the test app.\n");
|
||||
return CppUnitShell::Run(argc, argv);
|
||||
}
|
||||
|
||||
const char*
|
||||
TestShell::TestDir() const
|
||||
{
|
||||
return (fTestDir ? fTestDir->Path() : NULL);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
#include <TestSuite.h>
|
||||
|
||||
void
|
||||
TestSuite::run (CppUnit::TestResult *result) {
|
||||
setUp();
|
||||
CppUnit::TestSuite::run(result);
|
||||
tearDown();
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
#include <cppunit/Asserter.h>
|
||||
#include <cppunit/NotEqualException.h>
|
||||
|
||||
|
||||
namespace CppUnit
|
||||
{
|
||||
|
||||
|
||||
namespace Asserter
|
||||
{
|
||||
|
||||
|
||||
void
|
||||
fail( std::string message,
|
||||
SourceLine sourceLine )
|
||||
{
|
||||
throw Exception( message, sourceLine );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
failIf( bool shouldFail,
|
||||
std::string message,
|
||||
SourceLine location )
|
||||
{
|
||||
if ( shouldFail )
|
||||
fail( message, location );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
failNotEqual( std::string expected,
|
||||
std::string actual,
|
||||
SourceLine sourceLine,
|
||||
std::string additionalMessage )
|
||||
{
|
||||
throw NotEqualException( expected,
|
||||
actual,
|
||||
sourceLine,
|
||||
additionalMessage );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
failNotEqualIf( bool shouldFail,
|
||||
std::string expected,
|
||||
std::string actual,
|
||||
SourceLine sourceLine,
|
||||
std::string additionalMessage )
|
||||
{
|
||||
if ( shouldFail )
|
||||
failNotEqual( expected, actual, sourceLine, additionalMessage );
|
||||
}
|
||||
|
||||
|
||||
} // namespace Asserter
|
||||
} // namespace CppUnit
|
||||
@@ -0,0 +1,202 @@
|
||||
#include <algorithm>
|
||||
#include <cppunit/NotEqualException.h>
|
||||
#include <cppunit/SourceLine.h>
|
||||
#include <cppunit/TestFailure.h>
|
||||
#include <cppunit/TestResultCollector.h>
|
||||
#include <cppunit/CompilerOutputter.h>
|
||||
|
||||
|
||||
namespace CppUnit
|
||||
{
|
||||
|
||||
CompilerOutputter::CompilerOutputter( TestResultCollector *result,
|
||||
std::ostream &stream ) :
|
||||
m_result( result ),
|
||||
m_stream( stream )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
CompilerOutputter::~CompilerOutputter()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
CompilerOutputter *
|
||||
CompilerOutputter::defaultOutputter( TestResultCollector *result,
|
||||
std::ostream &stream )
|
||||
{
|
||||
return new CompilerOutputter( result, stream );
|
||||
// For automatic adpatation...
|
||||
// return new CPPUNIT_DEFAULT_OUTPUTTER( result, stream );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CompilerOutputter::write()
|
||||
{
|
||||
if ( m_result->wasSuccessful() )
|
||||
printSucess();
|
||||
else
|
||||
printFailureReport();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CompilerOutputter::printSucess()
|
||||
{
|
||||
m_stream << "OK (" << m_result->runTests() << ")"
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CompilerOutputter::printFailureReport()
|
||||
{
|
||||
printFailuresList();
|
||||
printStatistics();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CompilerOutputter::printFailuresList()
|
||||
{
|
||||
for ( int index =0; index < m_result->testFailuresTotal(); ++index)
|
||||
{
|
||||
printFailureDetail( m_result->failures()[ index ] );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CompilerOutputter::printFailureDetail( TestFailure *failure )
|
||||
{
|
||||
printFailureLocation( failure->sourceLine() );
|
||||
printFailureType( failure );
|
||||
printFailedTestName( failure );
|
||||
printFailureMessage( failure );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CompilerOutputter::printFailureLocation( SourceLine sourceLine )
|
||||
{
|
||||
if ( sourceLine.isValid() )
|
||||
m_stream << sourceLine.fileName()
|
||||
<< "(" << sourceLine.lineNumber() << ") : ";
|
||||
else
|
||||
m_stream << "##Failure Location unknown## : ";
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CompilerOutputter::printFailureType( TestFailure *failure )
|
||||
{
|
||||
m_stream << (failure->isError() ? "Error" : "Assertion");
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CompilerOutputter::printFailedTestName( TestFailure *failure )
|
||||
{
|
||||
m_stream << std::endl;
|
||||
m_stream << "Test name: " << failure->failedTestName();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CompilerOutputter::printFailureMessage( TestFailure *failure )
|
||||
{
|
||||
m_stream << std::endl;
|
||||
Exception *thrownException = failure->thrownException();
|
||||
if ( thrownException->isInstanceOf( NotEqualException::type() ) )
|
||||
printNotEqualMessage( thrownException );
|
||||
else
|
||||
printDefaultMessage( thrownException );
|
||||
m_stream << std::endl;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CompilerOutputter::printNotEqualMessage( Exception *thrownException )
|
||||
{
|
||||
NotEqualException *e = (NotEqualException *)thrownException;
|
||||
m_stream << wrap( "- Expected : " + e->expectedValue() );
|
||||
m_stream << std::endl;
|
||||
m_stream << wrap( "- Actual : " + e->actualValue() );
|
||||
m_stream << std::endl;
|
||||
if ( !e->additionalMessage().empty() )
|
||||
{
|
||||
m_stream << wrap( e->additionalMessage() );
|
||||
m_stream << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CompilerOutputter::printDefaultMessage( Exception *thrownException )
|
||||
{
|
||||
std::string wrappedMessage = wrap( thrownException->what() );
|
||||
m_stream << wrappedMessage << std::endl;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CompilerOutputter::printStatistics()
|
||||
{
|
||||
m_stream << "Failures !!!" << std::endl;
|
||||
m_stream << "Run: " << m_result->runTests() << " "
|
||||
<< "Failure total: " << m_result->testFailuresTotal() << " "
|
||||
<< "Failures: " << m_result->testFailures() << " "
|
||||
<< "Errors: " << m_result->testErrors()
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
|
||||
std::string
|
||||
CompilerOutputter::wrap( std::string message )
|
||||
{
|
||||
Lines lines = splitMessageIntoLines( message );
|
||||
std::string wrapped;
|
||||
for ( Lines::iterator it = lines.begin(); it != lines.end(); ++it )
|
||||
{
|
||||
std::string line( *it );
|
||||
const int maxLineLength = 80;
|
||||
int index =0;
|
||||
while ( index < line.length() )
|
||||
{
|
||||
std::string line( line.substr( index, maxLineLength ) );
|
||||
wrapped += line;
|
||||
index += maxLineLength;
|
||||
if ( index < line.length() )
|
||||
wrapped += "\n";
|
||||
}
|
||||
wrapped += '\n';
|
||||
}
|
||||
return wrapped;
|
||||
}
|
||||
|
||||
|
||||
CompilerOutputter::Lines
|
||||
CompilerOutputter::splitMessageIntoLines( std::string message )
|
||||
{
|
||||
Lines lines;
|
||||
|
||||
std::string::iterator itStart = message.begin();
|
||||
while ( true )
|
||||
{
|
||||
std::string::iterator itEol = std::find( itStart,
|
||||
message.end(),
|
||||
'\n' );
|
||||
lines.push_back( message.substr( itStart - message.begin(),
|
||||
itEol - itStart ) );
|
||||
if ( itEol == message.end() )
|
||||
break;
|
||||
itStart = itEol +1;
|
||||
}
|
||||
return lines;
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace CppUnit
|
||||
@@ -0,0 +1,135 @@
|
||||
#include "cppunit/Exception.h"
|
||||
|
||||
|
||||
namespace CppUnit {
|
||||
|
||||
|
||||
#ifdef CPPUNIT_ENABLE_SOURCELINE_DEPRECATED
|
||||
/*!
|
||||
* \deprecated Use SourceLine::isValid() instead.
|
||||
*/
|
||||
const std::string Exception::UNKNOWNFILENAME = "<unknown>";
|
||||
|
||||
/*!
|
||||
* \deprecated Use SourceLine::isValid() instead.
|
||||
*/
|
||||
const long Exception::UNKNOWNLINENUMBER = -1;
|
||||
#endif
|
||||
|
||||
|
||||
/// Construct the exception
|
||||
Exception::Exception( const Exception &other ) :
|
||||
std::exception( other )
|
||||
{
|
||||
m_message = other.m_message;
|
||||
m_sourceLine = other.m_sourceLine;
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
* \deprecated Use other constructor instead.
|
||||
*/
|
||||
Exception::Exception( std::string message,
|
||||
SourceLine sourceLine ) :
|
||||
m_message( message ),
|
||||
m_sourceLine( sourceLine )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
#ifdef CPPUNIT_ENABLE_SOURCELINE_DEPRECATED
|
||||
/*!
|
||||
* \deprecated Use other constructor instead.
|
||||
*/
|
||||
Exception::Exception( std::string message,
|
||||
long lineNumber,
|
||||
std::string fileName ) :
|
||||
m_message( message ),
|
||||
m_sourceLine( fileName, lineNumber )
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/// Destruct the exception
|
||||
Exception::~Exception () throw()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/// Perform an assignment
|
||||
Exception&
|
||||
Exception::operator =( const Exception& other )
|
||||
{
|
||||
// Don't call superclass operator =(). VC++ STL implementation
|
||||
// has a bug. It calls the destructor and copy constructor of
|
||||
// std::exception() which reset the virtual table to std::exception.
|
||||
// SuperClass::operator =(other);
|
||||
|
||||
if ( &other != this )
|
||||
{
|
||||
m_message = other.m_message;
|
||||
m_sourceLine = other.m_sourceLine;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
/// Return descriptive message
|
||||
const char*
|
||||
Exception::what() const throw()
|
||||
{
|
||||
return m_message.c_str ();
|
||||
}
|
||||
|
||||
/// Location where the error occured
|
||||
SourceLine
|
||||
Exception::sourceLine() const
|
||||
{
|
||||
return m_sourceLine;
|
||||
}
|
||||
|
||||
|
||||
#ifdef CPPUNIT_ENABLE_SOURCELINE_DEPRECATED
|
||||
/// The line on which the error occurred
|
||||
long
|
||||
Exception::lineNumber() const
|
||||
{
|
||||
return m_sourceLine.isValid() ? m_sourceLine.lineNumber() :
|
||||
UNKNOWNLINENUMBER;
|
||||
}
|
||||
|
||||
|
||||
/// The file in which the error occurred
|
||||
std::string
|
||||
Exception::fileName() const
|
||||
{
|
||||
return m_sourceLine.isValid() ? m_sourceLine.fileName() :
|
||||
UNKNOWNFILENAME;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
Exception *
|
||||
Exception::clone() const
|
||||
{
|
||||
return new Exception( *this );
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Exception::isInstanceOf( const Type &exceptionType ) const
|
||||
{
|
||||
return exceptionType == type();
|
||||
}
|
||||
|
||||
|
||||
Exception::Type
|
||||
Exception::type()
|
||||
{
|
||||
return Type( "CppUnit::Exception" );
|
||||
}
|
||||
|
||||
|
||||
} // namespace CppUnit
|
||||
@@ -0,0 +1,111 @@
|
||||
#include <cppunit/NotEqualException.h>
|
||||
|
||||
namespace CppUnit {
|
||||
|
||||
|
||||
NotEqualException::NotEqualException( std::string expected,
|
||||
std::string actual,
|
||||
SourceLine sourceLine ,
|
||||
std::string additionalMessage ) :
|
||||
Exception( "Expected: " + expected +
|
||||
", but was: " + actual +
|
||||
"." + additionalMessage ,
|
||||
sourceLine),
|
||||
m_expected( expected ),
|
||||
m_actual( actual ),
|
||||
m_additionalMessage( additionalMessage )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
#ifdef CPPUNIT_ENABLE_SOURCELINE_DEPRECATED
|
||||
/*!
|
||||
* \deprecated Use other constructor instead.
|
||||
*/
|
||||
NotEqualException::NotEqualException( std::string expected,
|
||||
std::string actual,
|
||||
long lineNumber,
|
||||
std::string fileName ) :
|
||||
Exception( "Expected: " + expected + ", but was: " + actual,
|
||||
lineNumber,
|
||||
fileName ),
|
||||
m_expected( expected ),
|
||||
m_actual( actual )
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
NotEqualException::NotEqualException( const NotEqualException &other ) :
|
||||
Exception( other ),
|
||||
m_expected( other.m_expected ),
|
||||
m_actual( other.m_actual ),
|
||||
m_additionalMessage( other.m_additionalMessage )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
NotEqualException::~NotEqualException() throw()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
NotEqualException &
|
||||
NotEqualException::operator =( const NotEqualException &other )
|
||||
{
|
||||
Exception::operator =( other );
|
||||
|
||||
if ( &other != this )
|
||||
{
|
||||
m_expected = other.m_expected;
|
||||
m_actual = other.m_actual;
|
||||
m_additionalMessage = other.m_additionalMessage;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
Exception *
|
||||
NotEqualException::clone() const
|
||||
{
|
||||
return new NotEqualException( *this );
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
NotEqualException::isInstanceOf( const Type &exceptionType ) const
|
||||
{
|
||||
return exceptionType == type() ||
|
||||
Exception::isInstanceOf( exceptionType );
|
||||
}
|
||||
|
||||
|
||||
Exception::Type
|
||||
NotEqualException::type()
|
||||
{
|
||||
return Type( "CppUnit::NotEqualException" );
|
||||
}
|
||||
|
||||
|
||||
std::string
|
||||
NotEqualException::expectedValue() const
|
||||
{
|
||||
return m_expected;
|
||||
}
|
||||
|
||||
|
||||
std::string
|
||||
NotEqualException::actualValue() const
|
||||
{
|
||||
return m_actual;
|
||||
}
|
||||
|
||||
|
||||
std::string
|
||||
NotEqualException::additionalMessage() const
|
||||
{
|
||||
return m_additionalMessage;
|
||||
}
|
||||
|
||||
|
||||
} // namespace CppUnit
|
||||
@@ -0,0 +1,37 @@
|
||||
#include <cppunit/extensions/RepeatedTest.h>
|
||||
#include <cppunit/TestResult.h>
|
||||
|
||||
namespace CppUnit {
|
||||
|
||||
|
||||
|
||||
// Counts the number of test cases that will be run by this test.
|
||||
int
|
||||
RepeatedTest::countTestCases() const
|
||||
{
|
||||
return TestDecorator::countTestCases () * m_timesRepeat;
|
||||
}
|
||||
|
||||
|
||||
// Returns the name of the test instance.
|
||||
std::string
|
||||
RepeatedTest::toString() const
|
||||
{
|
||||
return TestDecorator::toString () + " (repeated)";
|
||||
}
|
||||
|
||||
// Runs a repeated test
|
||||
void
|
||||
RepeatedTest::run( TestResult *result )
|
||||
{
|
||||
for ( int n = 0; n < m_timesRepeat; n++ )
|
||||
{
|
||||
if ( result->shouldStop() )
|
||||
break;
|
||||
|
||||
TestDecorator::run( result );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // namespace TestAssert
|
||||
@@ -0,0 +1,62 @@
|
||||
#include <cppunit/SourceLine.h>
|
||||
|
||||
|
||||
namespace CppUnit
|
||||
{
|
||||
|
||||
SourceLine::SourceLine() :
|
||||
m_lineNumber( -1 )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
SourceLine::SourceLine( const std::string &fileName,
|
||||
int lineNumber ) :
|
||||
m_fileName( fileName ),
|
||||
m_lineNumber( lineNumber )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
SourceLine::~SourceLine()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
SourceLine::isValid() const
|
||||
{
|
||||
return !m_fileName.empty();
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
SourceLine::lineNumber() const
|
||||
{
|
||||
return m_lineNumber;
|
||||
}
|
||||
|
||||
|
||||
std::string
|
||||
SourceLine::fileName() const
|
||||
{
|
||||
return m_fileName;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
SourceLine::operator ==( const SourceLine &other ) const
|
||||
{
|
||||
return m_fileName == other.m_fileName &&
|
||||
m_lineNumber == other.m_lineNumber;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
SourceLine::operator !=( const SourceLine &other ) const
|
||||
{
|
||||
return !( *this == other );
|
||||
}
|
||||
|
||||
|
||||
} // namespace CppUnit
|
||||
@@ -0,0 +1,35 @@
|
||||
#include <cppunit/SynchronizedObject.h>
|
||||
|
||||
|
||||
namespace CppUnit
|
||||
{
|
||||
|
||||
|
||||
|
||||
|
||||
SynchronizedObject::SynchronizedObject( SynchronizationObject *syncObject )
|
||||
: m_syncObject( syncObject == 0 ? new SynchronizationObject() :
|
||||
syncObject )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
SynchronizedObject::~SynchronizedObject()
|
||||
{
|
||||
delete m_syncObject;
|
||||
}
|
||||
|
||||
|
||||
/** Accept a new synchronization object for protection of this instance
|
||||
* TestResult assumes ownership of the object
|
||||
*/
|
||||
void
|
||||
SynchronizedObject::setSynchronizationObject( SynchronizationObject *syncObject )
|
||||
{
|
||||
delete m_syncObject;
|
||||
m_syncObject = syncObject;
|
||||
}
|
||||
|
||||
|
||||
} // namespace CppUnit
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
#if HAVE_CMATH
|
||||
# include <cmath>
|
||||
#else
|
||||
# include <math.h>
|
||||
#endif
|
||||
|
||||
#include <cppunit/TestAssert.h>
|
||||
#include <cppunit/NotEqualException.h>
|
||||
|
||||
|
||||
namespace CppUnit {
|
||||
|
||||
|
||||
#ifdef CPPUNIT_ENABLE_SOURCELINE_DEPRECATED
|
||||
/// Check for a failed general assertion
|
||||
void
|
||||
TestAssert::assertImplementation( bool condition,
|
||||
std::string conditionExpression,
|
||||
long lineNumber,
|
||||
std::string fileName )
|
||||
{
|
||||
Asserter::failIf( condition,
|
||||
conditionExpression,
|
||||
SourceLine( fileName, lineNumber ) );
|
||||
}
|
||||
|
||||
|
||||
/// Reports failed equality
|
||||
void
|
||||
TestAssert::assertNotEqualImplementation( std::string expected,
|
||||
std::string actual,
|
||||
long lineNumber,
|
||||
std::string fileName )
|
||||
{
|
||||
Asserter::failNotEqual( expected,
|
||||
actual,
|
||||
SouceLine( fileName, lineNumber ), "" );
|
||||
}
|
||||
|
||||
|
||||
/// Check for a failed equality assertion
|
||||
void
|
||||
TestAssert::assertEquals( double expected,
|
||||
double actual,
|
||||
double delta,
|
||||
long lineNumber,
|
||||
std::string fileName )
|
||||
{
|
||||
if (fabs (expected - actual) > delta)
|
||||
assertNotEqualImplementation( assertion_traits<double>::toString(expected),
|
||||
assertion_traits<double>::toString(actual),
|
||||
lineNumber,
|
||||
fileName );
|
||||
}
|
||||
|
||||
#else // CPPUNIT_ENABLE_SOURCELINE_DEPRECATED
|
||||
|
||||
void
|
||||
TestAssert::assertDoubleEquals( double expected,
|
||||
double actual,
|
||||
double delta,
|
||||
SourceLine sourceLine )
|
||||
{
|
||||
Asserter::failNotEqualIf( fabs( expected - actual ) > delta,
|
||||
assertion_traits<double>::toString(expected),
|
||||
assertion_traits<double>::toString(actual),
|
||||
sourceLine );
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
#include <cppunit/Portability.h>
|
||||
#include <typeinfo>
|
||||
#include <stdexcept>
|
||||
|
||||
#include "cppunit/TestCase.h"
|
||||
#include "cppunit/Exception.h"
|
||||
#include "cppunit/TestResult.h"
|
||||
|
||||
|
||||
namespace CppUnit {
|
||||
|
||||
/// Create a default TestResult
|
||||
CppUnit::TestResult*
|
||||
TestCase::defaultResult()
|
||||
{
|
||||
return new TestResult;
|
||||
}
|
||||
|
||||
|
||||
/// Run the test and catch any exceptions that are triggered by it
|
||||
void
|
||||
TestCase::run( TestResult *result )
|
||||
{
|
||||
result->startTest(this);
|
||||
|
||||
try {
|
||||
setUp();
|
||||
|
||||
try {
|
||||
runTest();
|
||||
}
|
||||
catch ( Exception &e ) {
|
||||
Exception *copy = e.clone();
|
||||
result->addFailure( this, copy );
|
||||
}
|
||||
catch ( std::exception &e ) {
|
||||
result->addError( this, new Exception( e.what() ) );
|
||||
}
|
||||
catch (...) {
|
||||
Exception *e = new Exception( "caught unknown exception" );
|
||||
result->addError( this, e );
|
||||
}
|
||||
|
||||
try {
|
||||
tearDown();
|
||||
}
|
||||
catch (...) {
|
||||
result->addError( this, new Exception( "tearDown() failed" ) );
|
||||
}
|
||||
}
|
||||
catch (...) {
|
||||
result->addError( this, new Exception( "setUp() failed" ) );
|
||||
}
|
||||
|
||||
result->endTest( this );
|
||||
}
|
||||
|
||||
|
||||
/// A default run method
|
||||
TestResult *
|
||||
TestCase::run()
|
||||
{
|
||||
TestResult *result = defaultResult();
|
||||
|
||||
run (result);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/// All the work for runTest is deferred to subclasses
|
||||
void
|
||||
TestCase::runTest()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/** Constructs a test case.
|
||||
* \param name the name of the TestCase.
|
||||
**/
|
||||
TestCase::TestCase( std::string name )
|
||||
: m_name(name)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/** Constructs a test case for a suite.
|
||||
* This TestCase is intended for use by the TestCaller and should not
|
||||
* be used by a test case for which run() is called.
|
||||
**/
|
||||
TestCase::TestCase()
|
||||
: m_name( "" )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/// Destructs a test case
|
||||
TestCase::~TestCase()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/// Returns a count of all the tests executed
|
||||
int
|
||||
TestCase::countTestCases() const
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/// Returns the name of the test case
|
||||
std::string
|
||||
TestCase::getName() const
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
|
||||
|
||||
/// Returns the name of the test case instance
|
||||
std::string
|
||||
TestCase::toString() const
|
||||
{
|
||||
std::string className;
|
||||
|
||||
#if CPPUNIT_USE_TYPEINFO_NAME
|
||||
const std::type_info& thisClass = typeid( *this );
|
||||
className = thisClass.name();
|
||||
#else
|
||||
className = "TestCase";
|
||||
#endif
|
||||
|
||||
return className + "." + getName();
|
||||
}
|
||||
|
||||
|
||||
} // namespace CppUnit
|
||||
@@ -0,0 +1,176 @@
|
||||
#include <cppunit/extensions/TestFactoryRegistry.h>
|
||||
#include <cppunit/TestSuite.h>
|
||||
#include <set>
|
||||
|
||||
|
||||
#if CPPUNIT_USE_TYPEINFO_NAME
|
||||
# include "cppunit/extensions/TypeInfoHelper.h"
|
||||
#endif
|
||||
|
||||
|
||||
namespace CppUnit {
|
||||
|
||||
/** (Implementation) This class manages all the TestFactoryRegistry.
|
||||
*
|
||||
* Responsible for the life-cycle of the TestFactoryRegistry.
|
||||
*
|
||||
* TestFactory registry must call wasDestroyed() to indicate that
|
||||
* a given TestRegistry was destroyed, and needDestroy() to
|
||||
* know if a given TestFactory need to be destroyed (was not already
|
||||
* destroyed by another TestFactoryRegistry).
|
||||
*/
|
||||
class NamedRegistries
|
||||
{
|
||||
public:
|
||||
~NamedRegistries();
|
||||
|
||||
static NamedRegistries &getInstance();
|
||||
|
||||
TestFactoryRegistry &getRegistry( std::string name );
|
||||
|
||||
void wasDestroyed( TestFactory *factory );
|
||||
|
||||
bool needDestroy( TestFactory *factory );
|
||||
|
||||
private:
|
||||
typedef std::map<std::string, TestFactoryRegistry *> Registries;
|
||||
Registries m_registries;
|
||||
|
||||
typedef std::set<TestFactory *> Factories;
|
||||
Factories m_factoriesToDestroy;
|
||||
Factories m_destroyedFactories;
|
||||
};
|
||||
|
||||
|
||||
NamedRegistries::~NamedRegistries()
|
||||
{
|
||||
Registries::iterator it = m_registries.begin();
|
||||
while ( it != m_registries.end() )
|
||||
{
|
||||
TestFactoryRegistry *registry = (it++)->second;
|
||||
if ( needDestroy( registry ) )
|
||||
delete registry;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
NamedRegistries &
|
||||
NamedRegistries::getInstance()
|
||||
{
|
||||
static NamedRegistries namedRegistries;
|
||||
return namedRegistries;
|
||||
}
|
||||
|
||||
|
||||
TestFactoryRegistry &
|
||||
NamedRegistries::getRegistry( std::string name )
|
||||
{
|
||||
Registries::const_iterator foundIt = m_registries.find( name );
|
||||
if ( foundIt == m_registries.end() )
|
||||
{
|
||||
TestFactoryRegistry *factory = new TestFactoryRegistry( name );
|
||||
m_registries.insert( std::make_pair( name, factory ) );
|
||||
m_factoriesToDestroy.insert( factory );
|
||||
return *factory;
|
||||
}
|
||||
return *foundIt->second;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
NamedRegistries::wasDestroyed( TestFactory *factory )
|
||||
{
|
||||
m_factoriesToDestroy.erase( factory );
|
||||
m_destroyedFactories.insert( factory );
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
NamedRegistries::needDestroy( TestFactory *factory )
|
||||
{
|
||||
return m_destroyedFactories.count( factory ) == 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
TestFactoryRegistry::TestFactoryRegistry( std::string name ) :
|
||||
m_name( name )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
TestFactoryRegistry::~TestFactoryRegistry()
|
||||
{
|
||||
// The wasDestroyed() and needDestroy() is used to prevent
|
||||
// a double destruction of a factory registry.
|
||||
// registerFactory( "All Tests", getRegistry( "Unit Tests" ) );
|
||||
// => the TestFactoryRegistry "Unit Tests" is owned by both
|
||||
// the "All Tests" registry and the NamedRegistries...
|
||||
NamedRegistries::getInstance().wasDestroyed( this );
|
||||
|
||||
for ( Factories::iterator it = m_factories.begin(); it != m_factories.end(); ++it )
|
||||
{
|
||||
TestFactory *factory = it->second;
|
||||
if ( NamedRegistries::getInstance().needDestroy( factory ) )
|
||||
delete factory;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TestFactoryRegistry &
|
||||
TestFactoryRegistry::getRegistry()
|
||||
{
|
||||
return getRegistry( "All Tests" );
|
||||
}
|
||||
|
||||
|
||||
TestFactoryRegistry &
|
||||
TestFactoryRegistry::getRegistry( const std::string &name )
|
||||
{
|
||||
return NamedRegistries::getInstance().getRegistry( name );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TestFactoryRegistry::registerFactory( const std::string &name,
|
||||
TestFactory *factory )
|
||||
{
|
||||
m_factories[name] = factory;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TestFactoryRegistry::registerFactory( TestFactory *factory )
|
||||
{
|
||||
static int serialNumber = 1;
|
||||
|
||||
OStringStream ost;
|
||||
ost << "@Dummy@" << serialNumber++;
|
||||
|
||||
registerFactory( ost.str(), factory );
|
||||
}
|
||||
|
||||
|
||||
Test *
|
||||
TestFactoryRegistry::makeTest()
|
||||
{
|
||||
TestSuite *suite = new TestSuite( m_name );
|
||||
addTestToSuite( suite );
|
||||
return suite;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TestFactoryRegistry::addTestToSuite( TestSuite *suite )
|
||||
{
|
||||
for ( Factories::iterator it = m_factories.begin();
|
||||
it != m_factories.end();
|
||||
++it )
|
||||
{
|
||||
TestFactory *factory = (*it).second;
|
||||
suite->addTest( factory->makeTest() );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // namespace CppUnit
|
||||
@@ -0,0 +1,77 @@
|
||||
#include "cppunit/Exception.h"
|
||||
#include "cppunit/Test.h"
|
||||
#include "cppunit/TestFailure.h"
|
||||
|
||||
namespace CppUnit {
|
||||
|
||||
/// Constructs a TestFailure with the given test and exception.
|
||||
TestFailure::TestFailure( Test *failedTest,
|
||||
Exception *thrownException,
|
||||
bool isError ) :
|
||||
m_failedTest( failedTest ),
|
||||
m_thrownException( thrownException ),
|
||||
m_isError( isError )
|
||||
{
|
||||
}
|
||||
|
||||
/// Deletes the owned exception.
|
||||
TestFailure::~TestFailure()
|
||||
{
|
||||
delete m_thrownException;
|
||||
}
|
||||
|
||||
/// Gets the failed test.
|
||||
Test *
|
||||
TestFailure::failedTest() const
|
||||
{
|
||||
return m_failedTest;
|
||||
}
|
||||
|
||||
|
||||
/// Gets the thrown exception. Never \c NULL.
|
||||
Exception *
|
||||
TestFailure::thrownException() const
|
||||
{
|
||||
return m_thrownException;
|
||||
}
|
||||
|
||||
|
||||
/// Gets the failure location.
|
||||
SourceLine
|
||||
TestFailure::sourceLine() const
|
||||
{
|
||||
return m_thrownException->sourceLine();
|
||||
}
|
||||
|
||||
|
||||
/// Indicates if the failure is a failed assertion or an error.
|
||||
bool
|
||||
TestFailure::isError() const
|
||||
{
|
||||
return m_isError;
|
||||
}
|
||||
|
||||
|
||||
/// Gets the name of the failed test.
|
||||
std::string
|
||||
TestFailure::failedTestName() const
|
||||
{
|
||||
return m_failedTest->getName();
|
||||
}
|
||||
|
||||
|
||||
/// Returns a short description of the failure.
|
||||
std::string
|
||||
TestFailure::toString() const
|
||||
{
|
||||
return m_failedTest->toString() + ": " + m_thrownException->what();
|
||||
}
|
||||
|
||||
|
||||
TestFailure *
|
||||
TestFailure::clone() const
|
||||
{
|
||||
return new TestFailure( m_failedTest, m_thrownException->clone(), m_isError );
|
||||
}
|
||||
|
||||
} // namespace CppUnit
|
||||
@@ -0,0 +1,129 @@
|
||||
#include <cppunit/TestFailure.h>
|
||||
#include <cppunit/TestListener.h>
|
||||
#include <cppunit/TestResult.h>
|
||||
#include <algorithm>
|
||||
|
||||
namespace CppUnit {
|
||||
|
||||
/// Construct a TestResult
|
||||
TestResult::TestResult( SynchronizationObject *syncObject )
|
||||
: SynchronizedObject( syncObject )
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
|
||||
/// Destroys a test result
|
||||
TestResult::~TestResult()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/** Resets the result for a new run.
|
||||
*
|
||||
* Clear the previous run result.
|
||||
*/
|
||||
void
|
||||
TestResult::reset()
|
||||
{
|
||||
ExclusiveZone zone( m_syncObject );
|
||||
m_stop = false;
|
||||
}
|
||||
|
||||
|
||||
/** Adds an error to the list of errors.
|
||||
* The passed in exception
|
||||
* caused the error
|
||||
*/
|
||||
void
|
||||
TestResult::addError( Test *test,
|
||||
Exception *e )
|
||||
{
|
||||
addFailure( TestFailure( test, e, true ) );
|
||||
}
|
||||
|
||||
|
||||
/** Adds a failure to the list of failures. The passed in exception
|
||||
* caused the failure.
|
||||
*/
|
||||
void
|
||||
TestResult::addFailure( Test *test, Exception *e )
|
||||
{
|
||||
addFailure( TestFailure( test, e, false ) );
|
||||
}
|
||||
|
||||
|
||||
/** Called to add a failure to the list of failures.
|
||||
*/
|
||||
void
|
||||
TestResult::addFailure( const TestFailure &failure )
|
||||
{
|
||||
ExclusiveZone zone( m_syncObject );
|
||||
for ( TestListeners::iterator it = m_listeners.begin();
|
||||
it != m_listeners.end();
|
||||
++it )
|
||||
(*it)->addFailure( failure );
|
||||
}
|
||||
|
||||
|
||||
/// Informs the result that a test will be started.
|
||||
void
|
||||
TestResult::startTest( Test *test )
|
||||
{
|
||||
ExclusiveZone zone( m_syncObject );
|
||||
for ( TestListeners::iterator it = m_listeners.begin();
|
||||
it != m_listeners.end();
|
||||
++it )
|
||||
(*it)->startTest( test );
|
||||
}
|
||||
|
||||
|
||||
/// Informs the result that a test was completed.
|
||||
void
|
||||
TestResult::endTest( Test *test )
|
||||
{
|
||||
ExclusiveZone zone( m_syncObject );
|
||||
for ( TestListeners::iterator it = m_listeners.begin();
|
||||
it != m_listeners.end();
|
||||
++it )
|
||||
(*it)->endTest( test );
|
||||
}
|
||||
|
||||
|
||||
/// Returns whether testing should be stopped
|
||||
bool
|
||||
TestResult::shouldStop() const
|
||||
{
|
||||
ExclusiveZone zone( m_syncObject );
|
||||
return m_stop;
|
||||
}
|
||||
|
||||
|
||||
/// Stop testing
|
||||
void
|
||||
TestResult::stop()
|
||||
{
|
||||
ExclusiveZone zone( m_syncObject );
|
||||
m_stop = true;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TestResult::addListener( TestListener *listener )
|
||||
{
|
||||
ExclusiveZone zone( m_syncObject );
|
||||
m_listeners.push_back( listener );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TestResult::removeListener ( TestListener *listener )
|
||||
{
|
||||
ExclusiveZone zone( m_syncObject );
|
||||
m_listeners.erase( std::remove( m_listeners.begin(),
|
||||
m_listeners.end(),
|
||||
listener ),
|
||||
m_listeners.end());
|
||||
}
|
||||
|
||||
} // namespace CppUnit
|
||||
@@ -0,0 +1,110 @@
|
||||
#include <cppunit/TestFailure.h>
|
||||
#include <cppunit/TestResultCollector.h>
|
||||
|
||||
|
||||
namespace CppUnit
|
||||
{
|
||||
|
||||
|
||||
TestResultCollector::TestResultCollector( SynchronizationObject *syncObject )
|
||||
: TestSucessListener( syncObject )
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
|
||||
TestResultCollector::~TestResultCollector()
|
||||
{
|
||||
TestFailures::iterator itFailure = m_failures.begin();
|
||||
while ( itFailure != m_failures.end() )
|
||||
delete *itFailure++;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TestResultCollector::reset()
|
||||
{
|
||||
TestSucessListener::reset();
|
||||
|
||||
ExclusiveZone zone( m_syncObject );
|
||||
m_testErrors = 0;
|
||||
m_tests.clear();
|
||||
m_failures.clear();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TestResultCollector::startTest( Test *test )
|
||||
{
|
||||
ExclusiveZone zone (m_syncObject);
|
||||
m_tests.push_back( test );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TestResultCollector::addFailure( const TestFailure &failure )
|
||||
{
|
||||
TestSucessListener::addFailure( failure );
|
||||
|
||||
ExclusiveZone zone( m_syncObject );
|
||||
if ( failure.isError() )
|
||||
++m_testErrors;
|
||||
m_failures.push_back( failure.clone() );
|
||||
}
|
||||
|
||||
|
||||
/// Gets the number of run tests.
|
||||
int
|
||||
TestResultCollector::runTests() const
|
||||
{
|
||||
ExclusiveZone zone( m_syncObject );
|
||||
return m_tests.size();
|
||||
}
|
||||
|
||||
|
||||
/// Gets the number of detected errors (uncaught exception).
|
||||
int
|
||||
TestResultCollector::testErrors() const
|
||||
{
|
||||
ExclusiveZone zone( m_syncObject );
|
||||
return m_testErrors;
|
||||
}
|
||||
|
||||
|
||||
/// Gets the number of detected failures (failed assertion).
|
||||
int
|
||||
TestResultCollector::testFailures() const
|
||||
{
|
||||
ExclusiveZone zone( m_syncObject );
|
||||
return m_failures.size() - m_testErrors;
|
||||
}
|
||||
|
||||
|
||||
/// Gets the total number of detected failures.
|
||||
int
|
||||
TestResultCollector::testFailuresTotal() const
|
||||
{
|
||||
ExclusiveZone zone( m_syncObject );
|
||||
return m_failures.size();
|
||||
}
|
||||
|
||||
|
||||
/// Returns a the list failures (random access collection).
|
||||
const TestResultCollector::TestFailures &
|
||||
TestResultCollector::failures() const
|
||||
{
|
||||
ExclusiveZone zone( m_syncObject );
|
||||
return m_failures;
|
||||
}
|
||||
|
||||
|
||||
const TestResultCollector::Tests &
|
||||
TestResultCollector::tests() const
|
||||
{
|
||||
ExclusiveZone zone( m_syncObject );
|
||||
return m_tests;
|
||||
}
|
||||
|
||||
|
||||
} // namespace CppUnit
|
||||
|
||||
@@ -0,0 +1,179 @@
|
||||
#include <cppunit/TestSuite.h>
|
||||
#include <cppunit/TextTestResult.h>
|
||||
#include <cppunit/TextOutputter.h>
|
||||
#include <cppunit/TextTestProgressListener.h>
|
||||
#include <cppunit/TestResult.h>
|
||||
#include <cppunit/ui/text/TestRunner.h>
|
||||
#include <iostream>
|
||||
|
||||
|
||||
namespace CppUnit {
|
||||
namespace TextUi {
|
||||
|
||||
/*! Constructs a new text runner.
|
||||
* \param outputter used to print text result. Owned by the runner.
|
||||
*/
|
||||
TestRunner::TestRunner( Outputter *outputter )
|
||||
: m_outputter( outputter )
|
||||
, m_suite( new TestSuite( "All Tests" ) )
|
||||
, m_result( new TestResultCollector() )
|
||||
, m_eventManager( new TestResult() )
|
||||
{
|
||||
if ( !m_outputter )
|
||||
m_outputter = new TextOutputter( m_result, std::cout );
|
||||
m_eventManager->addListener( m_result );
|
||||
}
|
||||
|
||||
|
||||
TestRunner::~TestRunner()
|
||||
{
|
||||
delete m_eventManager;
|
||||
delete m_outputter;
|
||||
delete m_result;
|
||||
delete m_suite;
|
||||
}
|
||||
|
||||
|
||||
/*! Adds the specified test.
|
||||
*
|
||||
* \param test Test to add.
|
||||
*/
|
||||
void
|
||||
TestRunner::addTest( Test *test )
|
||||
{
|
||||
if ( test != NULL )
|
||||
m_suite->addTest( test );
|
||||
}
|
||||
|
||||
|
||||
/*! Runs the named test case.
|
||||
*
|
||||
* \param testName Name of the test case to run. If an empty is given, then
|
||||
* all added test are run. The name must be the name of
|
||||
* of an added test.
|
||||
* \param doWait if \c true then the user must press the RETURN key
|
||||
* before the run() method exit.
|
||||
* \param doPrintResult if \c true (default) then the test result are printed
|
||||
* on the standard output.
|
||||
* \param doPrintProgress if \c true (default) then TextTestProgressListener is
|
||||
* used to show the progress.
|
||||
* \return \c true is the test was successful, \c false if the test
|
||||
* failed or was not found.
|
||||
*/
|
||||
bool
|
||||
TestRunner::run( std::string testName,
|
||||
bool doWait,
|
||||
bool doPrintResult,
|
||||
bool doPrintProgress )
|
||||
{
|
||||
runTestByName( testName, doPrintProgress );
|
||||
printResult( doPrintResult );
|
||||
wait( doWait );
|
||||
return m_result->wasSuccessful();
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
TestRunner::runTestByName( std::string testName,
|
||||
bool doPrintProgress )
|
||||
{
|
||||
if ( testName.empty() )
|
||||
return runTest( m_suite, doPrintProgress );
|
||||
|
||||
Test *test = findTestByName( testName );
|
||||
if ( test != NULL )
|
||||
return runTest( test, doPrintProgress );
|
||||
|
||||
std::cout << "Test " << testName << " not found." << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TestRunner::wait( bool doWait )
|
||||
{
|
||||
if ( doWait )
|
||||
{
|
||||
std::cout << "<RETURN> to continue" << std::endl;
|
||||
std::cin.get ();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TestRunner::printResult( bool doPrintResult )
|
||||
{
|
||||
std::cout << std::endl;
|
||||
if ( doPrintResult )
|
||||
m_outputter->write();
|
||||
}
|
||||
|
||||
|
||||
Test *
|
||||
TestRunner::findTestByName( std::string name ) const
|
||||
{
|
||||
for ( std::vector<Test *>::const_iterator it = m_suite->getTests().begin();
|
||||
it != m_suite->getTests().end();
|
||||
++it )
|
||||
{
|
||||
Test *test = *it;
|
||||
if ( test->getName() == name )
|
||||
return test;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
TestRunner::runTest( Test *test,
|
||||
bool doPrintProgress )
|
||||
{
|
||||
TextTestProgressListener progress;
|
||||
if ( doPrintProgress )
|
||||
m_eventManager->addListener( &progress );
|
||||
|
||||
test->run( m_eventManager );
|
||||
|
||||
if ( doPrintProgress )
|
||||
m_eventManager->removeListener( &progress );
|
||||
return m_result->wasSuccessful();
|
||||
}
|
||||
|
||||
|
||||
/*! Returns the result of the test run.
|
||||
* Use this after calling run() to access the result of the test run.
|
||||
*/
|
||||
TestResultCollector &
|
||||
TestRunner::result() const
|
||||
{
|
||||
return *m_result;
|
||||
}
|
||||
|
||||
|
||||
/*! Returns the event manager.
|
||||
* The instance of TestResult results returned is the one that is used to run the
|
||||
* test. Use this to register additional TestListener before running the tests.
|
||||
*/
|
||||
TestResult &
|
||||
TestRunner::eventManager() const
|
||||
{
|
||||
return *m_eventManager;
|
||||
}
|
||||
|
||||
|
||||
/*! Specifies an alternate outputter.
|
||||
*
|
||||
* Notes that the outputter will be use after the test run only if \a printResult was
|
||||
* \c true.
|
||||
* \see CompilerOutputter, XmlOutputter, TextOutputter.
|
||||
*/
|
||||
void
|
||||
TestRunner::setOutputter( Outputter *outputter )
|
||||
{
|
||||
delete m_outputter;
|
||||
m_outputter = outputter;
|
||||
}
|
||||
|
||||
|
||||
} // namespace TextUi
|
||||
} // namespace CppUnit
|
||||
@@ -0,0 +1,31 @@
|
||||
#include <cppunit/extensions/TestSetUp.h>
|
||||
|
||||
namespace CppUnit {
|
||||
|
||||
TestSetUp::TestSetUp( Test *test ) : TestDecorator( test )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TestSetUp::setUp()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TestSetUp::tearDown()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TestSetUp::run( TestResult *result )
|
||||
{
|
||||
setUp();
|
||||
TestDecorator::run(result);
|
||||
tearDown();
|
||||
}
|
||||
|
||||
|
||||
} // namespace CppUnit
|
||||
@@ -0,0 +1,46 @@
|
||||
#include <cppunit/TestSucessListener.h>
|
||||
|
||||
|
||||
|
||||
namespace CppUnit
|
||||
{
|
||||
|
||||
|
||||
TestSucessListener::TestSucessListener( SynchronizationObject *syncObject )
|
||||
: SynchronizedObject( syncObject )
|
||||
, m_sucess( true )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
TestSucessListener::~TestSucessListener()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TestSucessListener::reset()
|
||||
{
|
||||
ExclusiveZone zone( m_syncObject );
|
||||
m_sucess = true;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TestSucessListener::addFailure( const TestFailure &failure )
|
||||
{
|
||||
ExclusiveZone zone( m_syncObject );
|
||||
m_sucess = false;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
TestSucessListener::wasSuccessful() const
|
||||
{
|
||||
ExclusiveZone zone( m_syncObject );
|
||||
return m_sucess;
|
||||
}
|
||||
|
||||
|
||||
} // namespace CppUnit
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
#include "cppunit/TestSuite.h"
|
||||
#include "cppunit/TestResult.h"
|
||||
|
||||
namespace CppUnit {
|
||||
|
||||
/// Default constructor
|
||||
TestSuite::TestSuite( std::string name )
|
||||
: m_name( name )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/// Destructor
|
||||
TestSuite::~TestSuite()
|
||||
{
|
||||
deleteContents();
|
||||
}
|
||||
|
||||
|
||||
/// Deletes all tests in the suite.
|
||||
void
|
||||
TestSuite::deleteContents()
|
||||
{
|
||||
for ( std::vector<Test *>::iterator it = m_tests.begin();
|
||||
it != m_tests.end();
|
||||
++it)
|
||||
delete *it;
|
||||
m_tests.clear();
|
||||
}
|
||||
|
||||
|
||||
/// Runs the tests and collects their result in a TestResult.
|
||||
void
|
||||
TestSuite::run( TestResult *result )
|
||||
{
|
||||
for ( std::vector<Test *>::iterator it = m_tests.begin();
|
||||
it != m_tests.end();
|
||||
++it )
|
||||
{
|
||||
if ( result->shouldStop() )
|
||||
break;
|
||||
|
||||
Test *test = *it;
|
||||
test->run( result );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Counts the number of test cases that will be run by this test.
|
||||
int
|
||||
TestSuite::countTestCases() const
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
for ( std::vector<Test *>::const_iterator it = m_tests.begin();
|
||||
it != m_tests.end();
|
||||
++it )
|
||||
count += (*it)->countTestCases();
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
/// Adds a test to the suite.
|
||||
void
|
||||
TestSuite::addTest( Test *test )
|
||||
{
|
||||
m_tests.push_back( test );
|
||||
}
|
||||
|
||||
|
||||
/// Returns a string representation of the test suite.
|
||||
std::string
|
||||
TestSuite::toString() const
|
||||
{
|
||||
return "suite " + getName();
|
||||
}
|
||||
|
||||
|
||||
/// Returns the name of the test suite.
|
||||
std::string
|
||||
TestSuite::getName() const
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
|
||||
|
||||
const std::vector<Test *> &
|
||||
TestSuite::getTests() const
|
||||
{
|
||||
return m_tests;
|
||||
}
|
||||
|
||||
|
||||
} // namespace CppUnit
|
||||
|
||||
@@ -0,0 +1,156 @@
|
||||
#include <cppunit/NotEqualException.h>
|
||||
#include <cppunit/TestFailure.h>
|
||||
#include <cppunit/SourceLine.h>
|
||||
#include <cppunit/TestResultCollector.h>
|
||||
#include <cppunit/TextOutputter.h>
|
||||
|
||||
|
||||
namespace CppUnit
|
||||
{
|
||||
|
||||
|
||||
TextOutputter::TextOutputter( TestResultCollector *result,
|
||||
std::ostream &stream )
|
||||
: m_result( result )
|
||||
, m_stream( stream )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
TextOutputter::~TextOutputter()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TextOutputter::write()
|
||||
{
|
||||
printHeader();
|
||||
m_stream << std::endl;
|
||||
printFailures();
|
||||
m_stream << std::endl;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TextOutputter::printFailures()
|
||||
{
|
||||
TestResultCollector::TestFailures::const_iterator itFailure = m_result->failures().begin();
|
||||
int failureNumber = 1;
|
||||
while ( itFailure != m_result->failures().end() )
|
||||
{
|
||||
m_stream << std::endl;
|
||||
printFailure( *itFailure++, failureNumber++ );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TextOutputter::printFailure( TestFailure *failure,
|
||||
int failureNumber )
|
||||
{
|
||||
printFailureListMark( failureNumber );
|
||||
m_stream << ' ';
|
||||
printFailureTestName( failure );
|
||||
m_stream << ' ';
|
||||
printFailureType( failure );
|
||||
m_stream << ' ';
|
||||
printFailureLocation( failure->sourceLine() );
|
||||
m_stream << std::endl;
|
||||
printFailureDetail( failure->thrownException() );
|
||||
m_stream << std::endl;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TextOutputter::printFailureListMark( int failureNumber )
|
||||
{
|
||||
m_stream << failureNumber << ")";
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TextOutputter::printFailureTestName( TestFailure *failure )
|
||||
{
|
||||
m_stream << "test: " << failure->failedTestName();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TextOutputter::printFailureType( TestFailure *failure )
|
||||
{
|
||||
m_stream << "("
|
||||
<< (failure->isError() ? "E" : "F")
|
||||
<< ")";
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TextOutputter::printFailureLocation( SourceLine sourceLine )
|
||||
{
|
||||
if ( !sourceLine.isValid() )
|
||||
return;
|
||||
|
||||
m_stream << "line: " << sourceLine.lineNumber()
|
||||
<< ' ' << sourceLine.fileName();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TextOutputter::printFailureDetail( Exception *thrownException )
|
||||
{
|
||||
if ( thrownException->isInstanceOf( NotEqualException::type() ) )
|
||||
{
|
||||
NotEqualException *e = (NotEqualException*)thrownException;
|
||||
m_stream << "expected: " << e->expectedValue() << std::endl
|
||||
<< "but was: " << e->actualValue();
|
||||
if ( !e->additionalMessage().empty() )
|
||||
{
|
||||
m_stream << std::endl;
|
||||
m_stream << "additional message:" << std::endl
|
||||
<< e->additionalMessage();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_stream << " \"" << thrownException->what() << "\"";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TextOutputter::printHeader()
|
||||
{
|
||||
if ( m_result->wasSuccessful() )
|
||||
m_stream << std::endl << "OK (" << m_result->runTests () << " tests)"
|
||||
<< std::endl;
|
||||
else
|
||||
{
|
||||
m_stream << std::endl;
|
||||
printFailureWarning();
|
||||
printStatistics();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TextOutputter::printFailureWarning()
|
||||
{
|
||||
m_stream << "!!!FAILURES!!!" << std::endl;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TextOutputter::printStatistics()
|
||||
{
|
||||
m_stream << "Test Results:" << std::endl;
|
||||
|
||||
m_stream << "Run: " << m_result->runTests()
|
||||
<< " Failures: " << m_result->testFailures()
|
||||
<< " Errors: " << m_result->testErrors()
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
|
||||
} // namespace CppUnit
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
#include <cppunit/TestFailure.h>
|
||||
#include <cppunit/TextTestProgressListener.h>
|
||||
#include <iostream>
|
||||
|
||||
|
||||
namespace CppUnit
|
||||
{
|
||||
|
||||
|
||||
TextTestProgressListener::TextTestProgressListener()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
TextTestProgressListener::~TextTestProgressListener()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TextTestProgressListener::startTest( Test *test )
|
||||
{
|
||||
std::cerr << ".";
|
||||
std::cerr.flush();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TextTestProgressListener::addFailure( const TestFailure &failure )
|
||||
{
|
||||
std::cerr << ( failure.isError() ? "E" : "F" );
|
||||
std::cerr.flush();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TextTestProgressListener::done()
|
||||
{
|
||||
std::cerr << std::endl;
|
||||
std::cerr.flush();
|
||||
}
|
||||
|
||||
} // namespace CppUnit
|
||||
|
||||
@@ -0,0 +1,177 @@
|
||||
#include <cppunit/Exception.h>
|
||||
#include <cppunit/NotEqualException.h>
|
||||
#include <cppunit/Test.h>
|
||||
#include <cppunit/TestFailure.h>
|
||||
#include <cppunit/TextTestResult.h>
|
||||
#include <iostream>
|
||||
|
||||
|
||||
namespace CppUnit {
|
||||
|
||||
|
||||
TextTestResult::TextTestResult()
|
||||
{
|
||||
addListener( this );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TextTestResult::addFailure( const TestFailure &failure )
|
||||
{
|
||||
TestResultCollector::addFailure( failure );
|
||||
std::cerr << ( failure.isError() ? "E" : "F" );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TextTestResult::startTest( Test *test )
|
||||
{
|
||||
TestResultCollector::startTest (test);
|
||||
std::cerr << ".";
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TextTestResult::printFailures( std::ostream &stream )
|
||||
{
|
||||
TestFailures::const_iterator itFailure = failures().begin();
|
||||
int failureNumber = 1;
|
||||
while ( itFailure != failures().end() )
|
||||
{
|
||||
stream << std::endl;
|
||||
printFailure( *itFailure++, failureNumber++, stream );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TextTestResult::printFailure( TestFailure *failure,
|
||||
int failureNumber,
|
||||
std::ostream &stream )
|
||||
{
|
||||
printFailureListMark( failureNumber, stream );
|
||||
stream << ' ';
|
||||
printFailureTestName( failure, stream );
|
||||
stream << ' ';
|
||||
printFailureType( failure, stream );
|
||||
stream << ' ';
|
||||
printFailureLocation( failure->sourceLine(), stream );
|
||||
stream << std::endl;
|
||||
printFailureDetail( failure->thrownException(), stream );
|
||||
stream << std::endl;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TextTestResult::printFailureListMark( int failureNumber,
|
||||
std::ostream &stream )
|
||||
{
|
||||
stream << failureNumber << ")";
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TextTestResult::printFailureTestName( TestFailure *failure,
|
||||
std::ostream &stream )
|
||||
{
|
||||
stream << "test: " << failure->failedTest()->getName();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TextTestResult::printFailureType( TestFailure *failure,
|
||||
std::ostream &stream )
|
||||
{
|
||||
stream << "("
|
||||
<< (failure->isError() ? "E" : "F")
|
||||
<< ")";
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TextTestResult::printFailureLocation( SourceLine sourceLine,
|
||||
std::ostream &stream )
|
||||
{
|
||||
if ( !sourceLine.isValid() )
|
||||
return;
|
||||
|
||||
stream << "line: " << sourceLine.lineNumber()
|
||||
<< ' ' << sourceLine.fileName();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TextTestResult::printFailureDetail( Exception *thrownException,
|
||||
std::ostream &stream )
|
||||
{
|
||||
if ( thrownException->isInstanceOf( NotEqualException::type() ) )
|
||||
{
|
||||
NotEqualException *e = (NotEqualException*)thrownException;
|
||||
stream << "expected: " << e->expectedValue() << std::endl
|
||||
<< "but was: " << e->actualValue();
|
||||
if ( !e->additionalMessage().empty() )
|
||||
{
|
||||
stream << std::endl;
|
||||
stream << "additional message:" << std::endl
|
||||
<< e->additionalMessage();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
stream << " \"" << thrownException->what() << "\"";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TextTestResult::print( std::ostream& stream )
|
||||
{
|
||||
printHeader( stream );
|
||||
stream << std::endl;
|
||||
printFailures( stream );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TextTestResult::printHeader( std::ostream &stream )
|
||||
{
|
||||
if (wasSuccessful ())
|
||||
stream << std::endl << "OK (" << runTests () << " tests)"
|
||||
<< std::endl;
|
||||
else
|
||||
{
|
||||
stream << std::endl;
|
||||
printFailureWarning( stream );
|
||||
printStatistics( stream );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TextTestResult::printFailureWarning( std::ostream &stream )
|
||||
{
|
||||
stream << "!!!FAILURES!!!" << std::endl;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TextTestResult::printStatistics( std::ostream &stream )
|
||||
{
|
||||
stream << "Test Results:" << std::endl;
|
||||
|
||||
stream << "Run: " << runTests()
|
||||
<< " Failures: " << testFailures()
|
||||
<< " Errors: " << testErrors()
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
|
||||
std::ostream &
|
||||
operator <<( std::ostream &stream,
|
||||
TextTestResult &result )
|
||||
{
|
||||
result.print (stream); return stream;
|
||||
}
|
||||
|
||||
|
||||
} // namespace CppUnit
|
||||
@@ -0,0 +1,30 @@
|
||||
#include <cppunit/Portability.h>
|
||||
|
||||
#if CPPUNIT_USE_TYPEINFO_NAME
|
||||
|
||||
#include <string>
|
||||
#include <cppunit/extensions/TypeInfoHelper.h>
|
||||
|
||||
|
||||
namespace CppUnit {
|
||||
|
||||
std::string
|
||||
TypeInfoHelper::getClassName( const std::type_info &info )
|
||||
{
|
||||
static std::string classPrefix( "class " );
|
||||
std::string name( info.name() );
|
||||
|
||||
bool has_class_prefix = 0 ==
|
||||
#if CPPUNIT_FUNC_STRING_COMPARE_STRING_FIRST
|
||||
name.compare( classPrefix, 0, classPrefix.length() );
|
||||
#else
|
||||
name.compare( 0, classPrefix.length(), classPrefix );
|
||||
#endif
|
||||
|
||||
return has_class_prefix ? name.substr( classPrefix.length() ) : name;
|
||||
}
|
||||
|
||||
|
||||
} // namespace CppUnit
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,315 @@
|
||||
#include <cppunit/Exception.h>
|
||||
#include <cppunit/Test.h>
|
||||
#include <cppunit/TestFailure.h>
|
||||
#include <cppunit/TestResultCollector.h>
|
||||
#include <cppunit/XmlOutputter.h>
|
||||
#include <map>
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
namespace CppUnit
|
||||
{
|
||||
|
||||
// XmlOutputter::Node
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
XmlOutputter::Node::Node( std::string elementName,
|
||||
std::string content ) :
|
||||
m_name( elementName ),
|
||||
m_content( content )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
XmlOutputter::Node::Node( std::string elementName,
|
||||
int numericContent ) :
|
||||
m_name( elementName )
|
||||
{
|
||||
m_content = asString( numericContent );
|
||||
}
|
||||
|
||||
|
||||
XmlOutputter::Node::~Node()
|
||||
{
|
||||
Nodes::iterator itNode = m_nodes.begin();
|
||||
while ( itNode != m_nodes.end() )
|
||||
delete *itNode++;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
XmlOutputter::Node::addAttribute( std::string attributeName,
|
||||
std::string value )
|
||||
{
|
||||
m_attributes.push_back( Attribute( attributeName, value ) );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
XmlOutputter::Node::addAttribute( std::string attributeName,
|
||||
int numericValue )
|
||||
{
|
||||
addAttribute( attributeName, asString( numericValue ) );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
XmlOutputter::Node::addNode( Node *node )
|
||||
{
|
||||
m_nodes.push_back( node );
|
||||
}
|
||||
|
||||
|
||||
std::string
|
||||
XmlOutputter::Node::toString() const
|
||||
{
|
||||
std::string element = "<";
|
||||
element += m_name;
|
||||
element += " ";
|
||||
element += attributesAsString();
|
||||
element += " >\n";
|
||||
|
||||
Nodes::const_iterator itNode = m_nodes.begin();
|
||||
while ( itNode != m_nodes.end() )
|
||||
{
|
||||
const Node *node = *itNode++;
|
||||
element += node->toString();
|
||||
}
|
||||
|
||||
element += m_content;
|
||||
|
||||
element += "</";
|
||||
element += m_name;
|
||||
element += ">\n";
|
||||
|
||||
return element;
|
||||
}
|
||||
|
||||
|
||||
std::string
|
||||
XmlOutputter::Node::attributesAsString() const
|
||||
{
|
||||
std::string attributes;
|
||||
Attributes::const_iterator itAttribute = m_attributes.begin();
|
||||
while ( itAttribute != m_attributes.end() )
|
||||
{
|
||||
const Attribute &attribute = *itAttribute++;
|
||||
attributes += attribute.first;
|
||||
attributes += "=\"";
|
||||
attributes += escape( attribute.second );
|
||||
attributes += "\"";
|
||||
}
|
||||
return attributes;
|
||||
}
|
||||
|
||||
|
||||
std::string
|
||||
XmlOutputter::Node::escape( std::string value ) const
|
||||
{
|
||||
std::string escaped;
|
||||
for ( int index =0; index < value.length(); ++index )
|
||||
{
|
||||
char c = value[index ];
|
||||
switch ( c ) // escape all predefined XML entity (safe?)
|
||||
{
|
||||
case '<':
|
||||
escaped += "<";
|
||||
break;
|
||||
case '>':
|
||||
escaped += ">";
|
||||
break;
|
||||
case '&':
|
||||
escaped += "&";
|
||||
break;
|
||||
case '\'':
|
||||
escaped += "'";
|
||||
break;
|
||||
case '"':
|
||||
escaped += """;
|
||||
break;
|
||||
default:
|
||||
escaped += c;
|
||||
}
|
||||
}
|
||||
|
||||
return escaped;
|
||||
}
|
||||
|
||||
// should be somewhere else... Future CppUnit::String ?
|
||||
std::string
|
||||
XmlOutputter::Node::asString( int value )
|
||||
{
|
||||
OStringStream stream;
|
||||
stream << value;
|
||||
return stream.str();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// XmlOutputter
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
|
||||
XmlOutputter::XmlOutputter( TestResultCollector *result,
|
||||
std::ostream &stream,
|
||||
std::string encoding ) :
|
||||
m_result( result ),
|
||||
m_stream( stream ),
|
||||
m_encoding( encoding )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
XmlOutputter::~XmlOutputter()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
XmlOutputter::write()
|
||||
{
|
||||
writeProlog();
|
||||
writeTestsResult();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
XmlOutputter::writeProlog()
|
||||
{
|
||||
m_stream << "<?xml version=\"1.0\" "
|
||||
"encoding='" << m_encoding << "' standalone='yes' ?>"
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
XmlOutputter::writeTestsResult()
|
||||
{
|
||||
Node *rootNode = makeRootNode();
|
||||
m_stream << rootNode->toString();
|
||||
delete rootNode;
|
||||
}
|
||||
|
||||
|
||||
XmlOutputter::Node *
|
||||
XmlOutputter::makeRootNode()
|
||||
{
|
||||
Node *rootNode = new Node( "TestRun" );
|
||||
|
||||
FailedTests failedTests;
|
||||
fillFailedTestsMap( failedTests );
|
||||
|
||||
addFailedTests( failedTests, rootNode );
|
||||
addSucessfulTests( failedTests, rootNode );
|
||||
addStatistics( rootNode );
|
||||
|
||||
return rootNode;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
XmlOutputter::fillFailedTestsMap( FailedTests &failedTests )
|
||||
{
|
||||
const TestResultCollector::TestFailures &failures = m_result->failures();
|
||||
TestResultCollector::TestFailures::const_iterator itFailure = failures.begin();
|
||||
while ( itFailure != failures.end() )
|
||||
{
|
||||
TestFailure *failure = *itFailure++;
|
||||
failedTests.insert( std::make_pair(failure->failedTest(), failure ) );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
XmlOutputter::addFailedTests( FailedTests &failedTests,
|
||||
Node *rootNode )
|
||||
{
|
||||
Node *testsNode = new Node( "FailedTests" );
|
||||
rootNode->addNode( testsNode );
|
||||
|
||||
const TestResultCollector::Tests &tests = m_result->tests();
|
||||
for ( int testNumber = 0; testNumber < tests.size(); ++testNumber )
|
||||
{
|
||||
Test *test = tests[testNumber];
|
||||
if ( failedTests.find( test ) != failedTests.end() )
|
||||
addFailedTest( test, failedTests[test], testNumber+1, testsNode );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
XmlOutputter::addSucessfulTests( FailedTests &failedTests,
|
||||
Node *rootNode )
|
||||
{
|
||||
Node *testsNode = new Node( "SucessfulTests" );
|
||||
rootNode->addNode( testsNode );
|
||||
|
||||
const TestResultCollector::Tests &tests = m_result->tests();
|
||||
for ( int testNumber = 0; testNumber < tests.size(); ++testNumber )
|
||||
{
|
||||
Test *test = tests[testNumber];
|
||||
if ( failedTests.find( test ) == failedTests.end() )
|
||||
addSucessfulTest( test, testNumber+1, testsNode );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
XmlOutputter::addStatistics( Node *rootNode )
|
||||
{
|
||||
Node *statisticsNode = new Node( "Statistics" );
|
||||
rootNode->addNode( statisticsNode );
|
||||
statisticsNode->addNode( new Node( "Tests", m_result->runTests() ) );
|
||||
statisticsNode->addNode( new Node( "FailuresTotal",
|
||||
m_result->testFailuresTotal() ) );
|
||||
statisticsNode->addNode( new Node( "Errors", m_result->testErrors() ) );
|
||||
statisticsNode->addNode( new Node( "Failures", m_result->testFailures() ) );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
XmlOutputter::addFailedTest( Test *test,
|
||||
TestFailure *failure,
|
||||
int testNumber,
|
||||
Node *testsNode )
|
||||
{
|
||||
Exception *thrownException = failure->thrownException();
|
||||
|
||||
Node *testNode = new Node( "FailedTest", thrownException->what() );
|
||||
testsNode->addNode( testNode );
|
||||
testNode->addAttribute( "id", testNumber );
|
||||
testNode->addNode( new Node( "Name", test->getName() ) );
|
||||
testNode->addNode( new Node( "FailureType",
|
||||
failure->isError() ? "Error" : "Assertion" ) );
|
||||
|
||||
if ( failure->sourceLine().isValid() )
|
||||
addFailureLocation( failure, testNode );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
XmlOutputter::addFailureLocation( TestFailure *failure,
|
||||
Node *testNode )
|
||||
{
|
||||
Node *locationNode = new Node( "Location" );
|
||||
testNode->addNode( locationNode );
|
||||
SourceLine sourceLine = failure->sourceLine();
|
||||
locationNode->addNode( new Node( "File", sourceLine.fileName() ) );
|
||||
locationNode->addNode( new Node( "Line", sourceLine.lineNumber() ) );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
XmlOutputter::addSucessfulTest( Test *test,
|
||||
int testNumber,
|
||||
Node *testsNode )
|
||||
{
|
||||
Node *testNode = new Node( "Test" );
|
||||
testsNode->addNode( testNode );
|
||||
testNode->addAttribute( "id", testNumber );
|
||||
testNode->addNode( new Node( "Name", test->getName() ) );
|
||||
}
|
||||
|
||||
|
||||
} // namespace CppUnit
|
||||
Reference in New Issue
Block a user