It is accomplished ...

git-svn-id: file:///srv/svn/repos/haiku/trunk/current@10 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
ejakowatz
2002-07-09 12:24:59 +00:00
commit 52a3801208
2025 changed files with 472889 additions and 0 deletions
+213
View File
@@ -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;
}
}
+49
View File
@@ -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
;
+35
View File
@@ -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);
}
+8
View File
@@ -0,0 +1,8 @@
#include <TestResult.h>
#include <LockerSyncObject.h>
TestResult::TestResult()
: CppUnit::TestResult(new LockerSyncObject())
{
}
+36
View File
@@ -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);
}
+8
View File
@@ -0,0 +1,8 @@
#include <TestSuite.h>
void
TestSuite::run (CppUnit::TestResult *result) {
setUp();
CppUnit::TestSuite::run(result);
tearDown();
}
+57
View File
@@ -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
+135
View File
@@ -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
+62
View File
@@ -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
+74
View File
@@ -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
}
+135
View File
@@ -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
+77
View File
@@ -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
+129
View File
@@ -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
+179
View File
@@ -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
+31
View File
@@ -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
+96
View File
@@ -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
+156
View File
@@ -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
+315
View File
@@ -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 += "&lt;";
break;
case '>':
escaped += "&gt;";
break;
case '&':
escaped += "&amp;";
break;
case '\'':
escaped += "&apos;";
break;
case '"':
escaped += "&quot;";
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