mirror of
https://github.com/catchorg/Catch2.git
synced 2025-08-01 12:55:40 +02:00
First commit for GitHub
This commit is contained in:
279
internal/catch_capture.hpp
Normal file
279
internal/catch_capture.hpp
Normal file
@@ -0,0 +1,279 @@
|
||||
/*
|
||||
* catch_capture.hpp
|
||||
* Catch
|
||||
*
|
||||
* Created by Phil on 18/10/2010.
|
||||
* Copyright 2010 Two Blue Cubes Ltd. All rights reserved.
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
*/
|
||||
#ifndef TWOBLUECUBES_CATCH_CAPTURE_HPP_INCLUDED
|
||||
#define TWOBLUECUBES_CATCH_CAPTURE_HPP_INCLUDED
|
||||
|
||||
#include "catch_resultinfo.hpp"
|
||||
#include <sstream>
|
||||
#include "math.h"
|
||||
|
||||
namespace Catch
|
||||
{
|
||||
|
||||
template<typename T>
|
||||
std::string toString( const T& value )
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << value;
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
class TestFailureException
|
||||
{
|
||||
};
|
||||
class DummyExceptionType_DontUse
|
||||
{
|
||||
};
|
||||
|
||||
class MutableResultInfo : public ResultInfo
|
||||
{
|
||||
public:
|
||||
|
||||
MutableResultInfo()
|
||||
{}
|
||||
|
||||
MutableResultInfo( const std::string& expr, bool isNot, const std::string& filename, size_t line, const std::string& macroName )
|
||||
: ResultInfo( ( isNot ? "!" : "" ) + expr, ResultWas::Unknown, isNot, filename, line, macroName )
|
||||
{
|
||||
}
|
||||
void setResultType( ResultWas::OfType result )
|
||||
{
|
||||
// Flip bool results if isNot is set
|
||||
if( m_isNot && result == ResultWas::Ok )
|
||||
m_result = ResultWas::ExpressionFailed;
|
||||
else if( m_isNot && result == ResultWas::ExpressionFailed )
|
||||
m_result = ResultWas::Ok;
|
||||
else
|
||||
m_result = result;
|
||||
}
|
||||
void setMessage( const std::string& message )
|
||||
{
|
||||
m_message = message;
|
||||
}
|
||||
|
||||
private:
|
||||
friend class ResultBuilder;
|
||||
void setLhs( const std::string& lhs )
|
||||
{
|
||||
m_lhs = lhs;
|
||||
}
|
||||
MutableResultInfo& setRhs( const std::string& op, const std::string& rhs )
|
||||
{
|
||||
m_op = op;
|
||||
m_rhs = rhs;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
class ResultBuilder
|
||||
{
|
||||
public:
|
||||
ResultBuilder( const char* expr, bool isNot, const std::string& filename, size_t line, const std::string& macroName )
|
||||
: m_result( expr, isNot, filename, line, macroName )
|
||||
{}
|
||||
|
||||
template<typename T>
|
||||
ResultBuilder& operator->*(const T & operand)
|
||||
{
|
||||
m_result.setLhs( toString( operand ) );
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename RhsT>
|
||||
MutableResultInfo& operator == ( const RhsT& rhs )
|
||||
{
|
||||
return m_result.setRhs( "==", toString( rhs ) );
|
||||
}
|
||||
template<typename RhsT>
|
||||
MutableResultInfo& operator != ( const RhsT& rhs )
|
||||
{
|
||||
return m_result.setRhs( "!=", toString( rhs ) );
|
||||
}
|
||||
template<typename RhsT>
|
||||
MutableResultInfo& operator < ( const RhsT& rhs )
|
||||
{
|
||||
return m_result.setRhs( "<", toString( rhs ) );
|
||||
}
|
||||
template<typename RhsT>
|
||||
MutableResultInfo& operator > ( const RhsT& rhs )
|
||||
{
|
||||
return m_result.setRhs( ">", toString( rhs ) );
|
||||
}
|
||||
template<typename RhsT>
|
||||
MutableResultInfo& operator <= ( const RhsT& rhs )
|
||||
{
|
||||
return m_result.setRhs( "<=", toString( rhs ) );
|
||||
}
|
||||
template<typename RhsT>
|
||||
MutableResultInfo& operator >= ( const RhsT& rhs )
|
||||
{
|
||||
return m_result.setRhs( ">=", toString( rhs ) );
|
||||
}
|
||||
operator MutableResultInfo&()
|
||||
{
|
||||
return m_result;
|
||||
}
|
||||
|
||||
private:
|
||||
MutableResultInfo m_result;
|
||||
|
||||
};
|
||||
|
||||
class TestCaseInfo;
|
||||
|
||||
struct IResultListener
|
||||
{
|
||||
virtual ~IResultListener(){}
|
||||
virtual void testEnded( const ResultInfo& result ) = 0;
|
||||
};
|
||||
|
||||
class ResultsCapture
|
||||
{
|
||||
private:
|
||||
ResultsCapture()
|
||||
: m_listener( 0 )
|
||||
{
|
||||
}
|
||||
|
||||
static ResultsCapture& instance()
|
||||
{
|
||||
static ResultsCapture instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
static IResultListener* setListener( IResultListener* listener )
|
||||
{
|
||||
IResultListener* prevListener = instance().m_listener;
|
||||
instance().m_listener = listener;
|
||||
return prevListener;
|
||||
}
|
||||
|
||||
static void acceptExpression( const MutableResultInfo& resultInfo )
|
||||
{
|
||||
instance().currentResult = resultInfo;
|
||||
}
|
||||
|
||||
static void acceptResult( bool result, bool stopOnFail )
|
||||
{
|
||||
acceptResult( result ? ResultWas::Ok : ResultWas::ExpressionFailed, stopOnFail );
|
||||
}
|
||||
|
||||
static void acceptResult( ResultWas::OfType result, bool stopOnFail )
|
||||
{
|
||||
if( !acceptResult( result ) && stopOnFail )
|
||||
{
|
||||
throw TestFailureException();
|
||||
}
|
||||
}
|
||||
|
||||
static bool acceptResult( ResultWas::OfType result )
|
||||
{
|
||||
MutableResultInfo& currentResult = instance().currentResult;
|
||||
currentResult.setResultType( result );
|
||||
|
||||
if( instance().m_listener )
|
||||
{
|
||||
instance().m_listener->testEnded( currentResult );
|
||||
}
|
||||
bool ok = currentResult.ok();
|
||||
instance().currentResult = MutableResultInfo();
|
||||
return ok;
|
||||
}
|
||||
|
||||
static bool acceptResult( bool expressionResult )
|
||||
{
|
||||
return acceptResult( expressionResult ? ResultWas::Ok : ResultWas::ExpressionFailed );
|
||||
}
|
||||
|
||||
static void acceptMessage( const std::string& msg )
|
||||
{
|
||||
instance().currentResult.setMessage( msg );
|
||||
}
|
||||
|
||||
private:
|
||||
MutableResultInfo currentResult;
|
||||
IResultListener* m_listener;
|
||||
};
|
||||
|
||||
// !TBD Need to clean this all up
|
||||
#define CATCH_absTol 1e-10
|
||||
#define CATCH_relTol 1e-10
|
||||
|
||||
class Approx
|
||||
{
|
||||
public:
|
||||
// !TBD more generic
|
||||
Approx( double d )
|
||||
: m_d( d )
|
||||
{
|
||||
}
|
||||
template<typename T>
|
||||
friend bool operator == ( const T& lhs, const Approx& rhs )
|
||||
{
|
||||
// !TBD Use proper tolerance
|
||||
// From: http://realtimecollisiondetection.net/blog/?p=89
|
||||
// see also: http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm
|
||||
return fabs( lhs - rhs.m_d ) <= std::max( CATCH_absTol, CATCH_relTol * std::max( fabs(lhs), fabs(rhs.m_d) ) );
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
friend bool operator != ( const T& lhs, const Approx& rhs )
|
||||
{
|
||||
return ! operator==( lhs, rhs );
|
||||
}
|
||||
|
||||
double m_d;
|
||||
};
|
||||
|
||||
template<>
|
||||
inline std::string toString<Approx>( const Approx& value )
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << "Approx( " << value.m_d << ")";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
|
||||
} // end namespace Catch
|
||||
|
||||
#define _CATCH_TEST( expr, isNot, stopOnFailure, macroName ) \
|
||||
Catch::ResultsCapture::acceptExpression( Catch::ResultBuilder( #expr, isNot, __FILE__, __LINE__, macroName )->*expr ); \
|
||||
Catch::ResultsCapture::acceptResult( expr, stopOnFailure );
|
||||
|
||||
#define _CATCH_THROWS( expr, exceptionType, nothrow, stopOnFailure, macroName ) \
|
||||
Catch::ResultsCapture::acceptExpression( Catch::ResultBuilder( #expr, false, __FILE__, __LINE__, macroName ) ); \
|
||||
try \
|
||||
{ \
|
||||
expr; \
|
||||
Catch::ResultsCapture::acceptResult( nothrow, stopOnFailure ); \
|
||||
} \
|
||||
catch( exceptionType ) \
|
||||
{ \
|
||||
Catch::ResultsCapture::acceptResult( !(nothrow), stopOnFailure ); \
|
||||
}
|
||||
|
||||
#define _CATCH_THROWS_AS( expr, exceptionType, nothrow, stopOnFailure, macroName ) \
|
||||
_CATCH_THROWS( expr, exceptionType, nothrow, stopOnFailure, macroName ) \
|
||||
catch( ... ) \
|
||||
{ \
|
||||
Catch::ResultsCapture::acceptResult( false, stopOnFailure ); \
|
||||
}
|
||||
|
||||
#define _CATCH_MSG( reason, resultType, stopOnFailure, macroName ) \
|
||||
Catch::ResultsCapture::acceptExpression( Catch::MutableResultInfo( "", false, __FILE__, __LINE__, macroName ) ); \
|
||||
Catch::ResultsCapture::acceptMessage( reason ); \
|
||||
Catch::ResultsCapture::acceptResult( resultType, stopOnFailure );
|
||||
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_CAPTURE_HPP_INCLUDED
|
174
internal/catch_commandline.hpp
Normal file
174
internal/catch_commandline.hpp
Normal file
@@ -0,0 +1,174 @@
|
||||
/*
|
||||
* catch_commandline.hpp
|
||||
* Catch
|
||||
*
|
||||
* Created by Phil on 02/11/2010.
|
||||
* Copyright 2010 Two Blue Cubes Ltd. All rights reserved.
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TWOBLUECUBES_CATCH_COMMANDLINE_HPP_INCLUDED
|
||||
#define TWOBLUECUBES_CATCH_COMMANDLINE_HPP_INCLUDED
|
||||
|
||||
#include "catch_runnerconfig.hpp"
|
||||
#include "catch_runner_impl.hpp"
|
||||
|
||||
namespace Catch
|
||||
{
|
||||
// -l --list:tests [xml] lists available tests (optionally in xml)
|
||||
// -l --list:reports [xml] lists available reports (optionally in xml)
|
||||
// -l --list:all [xml] lists available tests and reports (optionally in xml)
|
||||
// -t --test "testspec" (any number)
|
||||
// -r --report <type>
|
||||
// -o --output filename to write to
|
||||
// -s --success report successful cases too
|
||||
class ArgParser
|
||||
{
|
||||
enum Mode
|
||||
{
|
||||
modeNone,
|
||||
modeList,
|
||||
modeTest,
|
||||
modeReport,
|
||||
modeOutput,
|
||||
modeSuccess,
|
||||
|
||||
modeError
|
||||
};
|
||||
|
||||
public:
|
||||
ArgParser( int argc, char * const argv[], RunnerConfig& config )
|
||||
: m_mode( modeNone ),
|
||||
m_config( config )
|
||||
{
|
||||
for(size_t i=1; i < argc; ++i )
|
||||
{
|
||||
if( argv[i][0] == '-' )
|
||||
{
|
||||
std::string cmd = ( argv[i] );
|
||||
if( cmd == "-l" || cmd == "--list" )
|
||||
changeMode( cmd, modeList );
|
||||
else if( cmd == "-t" || cmd == "--test" )
|
||||
changeMode( cmd, modeTest );
|
||||
else if( cmd == "-r" || cmd == "--report" )
|
||||
changeMode( cmd, modeReport );
|
||||
else if( cmd == "-o" || cmd == "--output" )
|
||||
changeMode( cmd, modeOutput );
|
||||
else if( cmd == "-s" || cmd == "--success" )
|
||||
changeMode( cmd, modeSuccess );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_args.push_back( argv[i] );
|
||||
}
|
||||
if( m_mode == modeError )
|
||||
return;
|
||||
}
|
||||
changeMode( "", modeNone );
|
||||
}
|
||||
|
||||
private:
|
||||
std::string argsAsString()
|
||||
{
|
||||
std::ostringstream oss;
|
||||
std::vector<std::string>::const_iterator it = m_args.begin();
|
||||
std::vector<std::string>::const_iterator itEnd = m_args.end();
|
||||
for( bool first = true; it != itEnd; ++it, first = false )
|
||||
{
|
||||
if( !first )
|
||||
oss << " ";
|
||||
oss << *it;
|
||||
}
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
void changeMode( const std::string& cmd, Mode mode )
|
||||
{
|
||||
m_command = cmd;
|
||||
switch( m_mode )
|
||||
{
|
||||
case modeNone:
|
||||
if( m_args.size() > 0 )
|
||||
return setErrorMode( "Unexpected arguments before " + m_command + ": " + argsAsString() );
|
||||
break;
|
||||
case modeList:
|
||||
if( m_args.size() > 2 )
|
||||
{
|
||||
return setErrorMode( m_command + " expected upto 2 arguments but recieved: " + argsAsString() );
|
||||
}
|
||||
else
|
||||
{
|
||||
RunnerConfig::ListInfo listSpec = RunnerConfig::listAll;
|
||||
if( m_args.size() >= 1 )
|
||||
{
|
||||
if( m_args[0] == "tests" )
|
||||
listSpec = RunnerConfig::listTests;
|
||||
else if( m_args[0] == "reports" )
|
||||
listSpec = RunnerConfig::listReports;
|
||||
else
|
||||
return setErrorMode( m_command + " expected [tests] or [reports] but recieved: [" + m_args[0] + "]" );
|
||||
}
|
||||
if( m_args.size() >= 2 )
|
||||
{
|
||||
if( m_args[1] == "xml" )
|
||||
listSpec = (RunnerConfig::ListInfo)( listSpec | RunnerConfig::listAsXml );
|
||||
else if( m_args[1] == "text" )
|
||||
listSpec = (RunnerConfig::ListInfo)( listSpec | RunnerConfig::listAsText );
|
||||
else
|
||||
return setErrorMode( m_command + " expected [xml] or [text] but recieved: [" + m_args[1] + "]" );
|
||||
}
|
||||
m_config.m_listSpec = (RunnerConfig::ListInfo)( m_config.m_listSpec | listSpec );
|
||||
}
|
||||
break;
|
||||
case modeTest:
|
||||
if( m_args.size() == 0 )
|
||||
return setErrorMode( m_command + " expected at least 1 argument but recieved none" );
|
||||
{
|
||||
std::vector<std::string>::const_iterator it = m_args.begin();
|
||||
std::vector<std::string>::const_iterator itEnd = m_args.end();
|
||||
for(; it != itEnd; ++it )
|
||||
m_config.addTestSpec( *it );
|
||||
}
|
||||
break;
|
||||
case modeReport:
|
||||
if( m_args.size() != 1 )
|
||||
return setErrorMode( m_command + " expected one argument, recieved: " + argsAsString() );
|
||||
m_config.setReporterInfo( m_args[0] );
|
||||
break;
|
||||
case modeOutput:
|
||||
if( m_args.size() == 0 )
|
||||
return setErrorMode( m_command + " expected filename" );
|
||||
m_config.setFilename( m_args[0] );
|
||||
break;
|
||||
case modeSuccess:
|
||||
if( m_args.size() != 0 )
|
||||
return setErrorMode( m_command + " does not accept arguments" );
|
||||
m_config.setIncludeAll( true );
|
||||
break;
|
||||
}
|
||||
m_args.clear();
|
||||
m_mode = mode;
|
||||
}
|
||||
|
||||
void setErrorMode( const std::string& errorMessage )
|
||||
{
|
||||
m_mode = modeError;
|
||||
m_command = "";
|
||||
m_config.setError( errorMessage );
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
Mode m_mode;
|
||||
std::string m_command;
|
||||
std::vector<std::string> m_args;
|
||||
RunnerConfig& m_config;
|
||||
};
|
||||
|
||||
|
||||
} // end namespace Catch
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_COMMANDLINE_HPP_INCLUDED
|
20
internal/catch_common.h
Normal file
20
internal/catch_common.h
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* catch_common.h
|
||||
* Catch
|
||||
*
|
||||
* Created by Phil on 29/10/2010.
|
||||
* Copyright 2010 Two Blue Cubes Ltd. All rights reserved.
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TWOBLUECUBES_CATCH_COMMON_H_INCLUDED
|
||||
#define TWOBLUECUBES_CATCH_COMMON_H_INCLUDED
|
||||
|
||||
#define _CATCH_UNIQUE_NAME_LINE2( name, line ) name##line
|
||||
#define _CATCH_UNIQUE_NAME_LINE( name, line ) _CATCH_UNIQUE_NAME_LINE2( name, line )
|
||||
#define _CATCH_UNIQUE_NAME( name ) _CATCH_UNIQUE_NAME_LINE( name, __LINE__ )
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_COMMON_H_INCLUDED
|
66
internal/catch_list.hpp
Normal file
66
internal/catch_list.hpp
Normal file
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* catch_list.hpp
|
||||
* Catch
|
||||
*
|
||||
* Created by Phil on 5/11/2010.
|
||||
* Copyright 2010 Two Blue Cubes Ltd. All rights reserved.
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TWOBLUECUBES_CATCH_LIST_HPP_INCLUDED
|
||||
#define TWOBLUECUBES_CATCH_LIST_HPP_INCLUDED
|
||||
|
||||
#include "catch_commandline.hpp"
|
||||
|
||||
namespace Catch
|
||||
{
|
||||
inline int List( const RunnerConfig& config )
|
||||
{
|
||||
if( config.listWhat() & RunnerConfig::listReports )
|
||||
{
|
||||
std::cout << "Available reports:\n";
|
||||
ReporterRegistry::FactoryMap::const_iterator it = ReporterRegistry::instance().m_factories.begin();
|
||||
ReporterRegistry::FactoryMap::const_iterator itEnd = ReporterRegistry::instance().m_factories.end();
|
||||
for(; it != itEnd; ++it )
|
||||
{
|
||||
// !TBD: consider listAs()
|
||||
std::cout << "\t" << it->first << " '" << it->second->getDescription() << "'\n";
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
if( config.listWhat() & RunnerConfig::listTests )
|
||||
{
|
||||
std::cout << "Available tests:\n";
|
||||
std::vector<TestCaseInfo>::const_iterator it = TestRegistry::instance().getAllTests().begin();
|
||||
std::vector<TestCaseInfo>::const_iterator itEnd = TestRegistry::instance().getAllTests().end();
|
||||
for(; it != itEnd; ++it )
|
||||
{
|
||||
// !TBD: consider listAs()
|
||||
std::cout << "\t" << it->getName() << " '" << it->getDescription() << "'\n";
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
if( ( config.listWhat() & RunnerConfig::listAll ) == 0 )
|
||||
{
|
||||
std::cerr << "Unknown list type" << std::endl;
|
||||
return std::numeric_limits<int>::max();
|
||||
}
|
||||
|
||||
if( config.getReporter() )
|
||||
{
|
||||
std::cerr << "Reporters ignored when listing" << std::endl;
|
||||
}
|
||||
if( config.m_testSpecs.size() == 0 )
|
||||
{
|
||||
std::cerr << "Test specs ignored when listing" << std::endl;
|
||||
}
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
} // end namespace Catch
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_LIST_HPP_INCLUDED
|
116
internal/catch_registry.hpp
Normal file
116
internal/catch_registry.hpp
Normal file
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* catch_registry.hpp
|
||||
* Catch
|
||||
*
|
||||
* Created by Phil on 18/10/2010.
|
||||
* Copyright 2010 Two Blue Cubes Ltd. All rights reserved.
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
*/
|
||||
#ifndef TWOBLUECUBES_CATCH_REGISTRY_HPP_INCLUDED
|
||||
#define TWOBLUECUBES_CATCH_REGISTRY_HPP_INCLUDED
|
||||
|
||||
#include "catch_testcaseinfo.hpp"
|
||||
#include "catch_common.h"
|
||||
|
||||
#include <vector>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace Catch
|
||||
{
|
||||
class TestRegistry
|
||||
{
|
||||
public:
|
||||
|
||||
static TestRegistry& instance()
|
||||
{
|
||||
static TestRegistry reg;
|
||||
return reg;
|
||||
}
|
||||
|
||||
void registerTest( const TestCaseInfo& testInfo )
|
||||
{
|
||||
m_functions.push_back( testInfo );
|
||||
}
|
||||
|
||||
std::vector<TestCaseInfo> getAllTests() const
|
||||
{
|
||||
return m_functions;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
std::vector<TestCaseInfo> m_functions;
|
||||
};
|
||||
|
||||
typedef void(*TestFunction)();
|
||||
|
||||
struct FreeFunctionTestCase : TestCase
|
||||
{
|
||||
FreeFunctionTestCase( TestFunction fun )
|
||||
: fun( fun )
|
||||
{}
|
||||
|
||||
virtual void invoke() const
|
||||
{
|
||||
fun();
|
||||
}
|
||||
|
||||
virtual TestCase* clone() const
|
||||
{
|
||||
return new FreeFunctionTestCase( fun );
|
||||
}
|
||||
|
||||
private:
|
||||
TestFunction fun;
|
||||
};
|
||||
|
||||
template<typename C>
|
||||
struct MethodTestCase : TestCase
|
||||
{
|
||||
MethodTestCase( void (C::*method)() )
|
||||
: method( method )
|
||||
{}
|
||||
|
||||
virtual void invoke() const
|
||||
{
|
||||
C obj;
|
||||
(obj.*method)();
|
||||
}
|
||||
|
||||
virtual TestCase* clone() const
|
||||
{
|
||||
return new MethodTestCase<C>( method );
|
||||
}
|
||||
|
||||
private:
|
||||
void (C::*method)();
|
||||
};
|
||||
|
||||
struct AutoReg
|
||||
{
|
||||
AutoReg( TestFunction function, const std::string& name, const std::string& description )
|
||||
{
|
||||
TestRegistry::instance().registerTest( TestCaseInfo( new FreeFunctionTestCase( function ), name, description ) );
|
||||
}
|
||||
|
||||
template<typename C>
|
||||
AutoReg( void (C::*method)(), const std::string& name, const std::string& description )
|
||||
{
|
||||
TestRegistry::instance().registerTest( TestCaseInfo( new MethodTestCase<C>( method ), name, description ) );
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace Catch
|
||||
|
||||
#define CATCH_TEST_CASE( Name, Desc ) \
|
||||
static void _CATCH_UNIQUE_NAME( __catchTestFunction )(); \
|
||||
namespace{ Catch::AutoReg _CATCH_UNIQUE_NAME( autoRegistrar )( &_CATCH_UNIQUE_NAME( __catchTestFunction ), Name, Desc ); }\
|
||||
static void _CATCH_UNIQUE_NAME( __catchTestFunction )()
|
||||
|
||||
#define CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, Name, Desc ) \
|
||||
namespace{ Catch::AutoReg _CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, Name, Desc ); }
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_REGISTRY_HPP_INCLUDED
|
166
internal/catch_reporter_registry.hpp
Normal file
166
internal/catch_reporter_registry.hpp
Normal file
@@ -0,0 +1,166 @@
|
||||
/*
|
||||
* catch_registry.hpp
|
||||
* Catch
|
||||
*
|
||||
* Created by Phil on 29/10/2010.
|
||||
* Copyright 2010 Two Blue Cubes Ltd. All rights reserved.
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
*/
|
||||
#ifndef TWOBLUECUBES_CATCH_REPORTER_REGISTRY_HPP_INCLUDED
|
||||
#define TWOBLUECUBES_CATCH_REPORTER_REGISTRY_HPP_INCLUDED
|
||||
|
||||
#include "catch_testcaseinfo.hpp"
|
||||
#include "catch_resultinfo.hpp"
|
||||
#include "catch_common.h"
|
||||
|
||||
#include <map>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
namespace Catch
|
||||
{
|
||||
class ReporterConfig
|
||||
{
|
||||
private:
|
||||
ReporterConfig( const ReporterConfig& other );
|
||||
ReporterConfig& operator = ( const ReporterConfig& other );
|
||||
|
||||
public:
|
||||
|
||||
struct Include { enum What
|
||||
{
|
||||
FailedOnly,
|
||||
SuccessfulResults
|
||||
}; };
|
||||
|
||||
public:
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
explicit ReporterConfig( Include::What includeWhat = Include::FailedOnly )
|
||||
: m_includeWhat( includeWhat ),
|
||||
m_os( std::cout.rdbuf() )
|
||||
{
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
bool includeSuccessfulResults() const
|
||||
{
|
||||
return m_includeWhat == Include::SuccessfulResults;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
void setIncludeWhat(Include::What includeWhat )
|
||||
{
|
||||
m_includeWhat = includeWhat;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
std::ostream& stream() const
|
||||
{
|
||||
return m_os;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
void setStreamBuf( std::streambuf* buf )
|
||||
{
|
||||
m_os.rdbuf( buf );
|
||||
}
|
||||
|
||||
private:
|
||||
Include::What m_includeWhat;
|
||||
|
||||
mutable std::ostream m_os;
|
||||
};
|
||||
|
||||
struct ITestReporter
|
||||
{
|
||||
virtual ~ITestReporter(){}
|
||||
|
||||
// !TBD
|
||||
// StartTesting
|
||||
// EndTesting
|
||||
// StartGroup
|
||||
// EndGroup
|
||||
// StartSection
|
||||
// EndSection
|
||||
virtual void StartTestCase( const TestCaseInfo& testInfo ) = 0;
|
||||
virtual void Result( const ResultInfo& result ) = 0;
|
||||
virtual void EndTestCase( const TestCaseInfo& testInfo ) = 0;
|
||||
};
|
||||
|
||||
struct IReporterFactory
|
||||
{
|
||||
virtual ~IReporterFactory(){}
|
||||
|
||||
virtual ITestReporter* create( const ReporterConfig& config ) = 0;
|
||||
virtual std::string getDescription() const = 0;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class ReporterFactory : public IReporterFactory
|
||||
{
|
||||
virtual ITestReporter* create( const ReporterConfig& config )
|
||||
{
|
||||
return new T( config );
|
||||
}
|
||||
virtual std::string getDescription() const
|
||||
{
|
||||
return T::getDescription();
|
||||
}
|
||||
};
|
||||
|
||||
class ReporterRegistry
|
||||
{
|
||||
public:
|
||||
|
||||
static ReporterRegistry& instance()
|
||||
{
|
||||
static ReporterRegistry instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
~ReporterRegistry()
|
||||
{
|
||||
FactoryMap::const_iterator it = m_factories.begin();
|
||||
FactoryMap::const_iterator itEnd = m_factories.end();
|
||||
for(; it != itEnd; ++it )
|
||||
{
|
||||
delete it->second;
|
||||
}
|
||||
}
|
||||
|
||||
ITestReporter* create( const std::string& name, const ReporterConfig& config )
|
||||
{
|
||||
FactoryMap::const_iterator it = m_factories.find( name );
|
||||
if( it == m_factories.end() )
|
||||
return NULL;
|
||||
return it->second->create( config );
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void registerReporter( const std::string& name )
|
||||
{
|
||||
m_factories.insert( std::make_pair( name, new ReporterFactory<T>() ) );
|
||||
}
|
||||
|
||||
// private: // !TBD
|
||||
typedef std::map<std::string, IReporterFactory*> FactoryMap;
|
||||
FactoryMap m_factories;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct ReporterRegistrar
|
||||
{
|
||||
ReporterRegistrar( const std::string& name )
|
||||
{
|
||||
ReporterRegistry::instance().registerReporter<T>( name );
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#define CATCH_REGISTER_REPORTER( name, reporterType ) Catch::ReporterRegistrar<reporterType> _CATCH_UNIQUE_NAME( __catchReporterReg )( name );
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_REPORTER_REGISTRY_HPP_INCLUDED
|
122
internal/catch_resultinfo.hpp
Normal file
122
internal/catch_resultinfo.hpp
Normal file
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* catch_resultinfo.hpp
|
||||
* Catch
|
||||
*
|
||||
* Created by Phil on 28/10/2010.
|
||||
* Copyright 2010 Two Blue Cubes Ltd. All rights reserved.
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
*/
|
||||
#ifndef TWOBLUECUBES_CATCH_RESULT_INFO_HPP_INCLUDED
|
||||
#define TWOBLUECUBES_CATCH_RESULT_INFO_HPP_INCLUDED
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace Catch
|
||||
{
|
||||
struct ResultWas{ enum OfType
|
||||
{
|
||||
Unknown = -1,
|
||||
Ok = 0,
|
||||
ExpressionFailed = 1,
|
||||
|
||||
Info = 2,
|
||||
Warning = 3,
|
||||
ExplicitFailure = 4,
|
||||
|
||||
Exception = 0x100,
|
||||
|
||||
ThrewException = Exception | 1,
|
||||
DidntThrowException = Exception | 2
|
||||
|
||||
}; };
|
||||
|
||||
class ResultInfo
|
||||
{
|
||||
public:
|
||||
|
||||
ResultInfo()
|
||||
: m_result( ResultWas::Unknown ),
|
||||
m_isNot( false ),
|
||||
m_line( 0 )
|
||||
{}
|
||||
|
||||
ResultInfo( const std::string& expr, ResultWas::OfType result, bool isNot, const std::string& filename, size_t line, const std::string& macroName )
|
||||
: m_expr( expr ),
|
||||
m_result( result ),
|
||||
m_isNot( isNot ),
|
||||
m_op( m_expr[0] == '!' ? "!" : "" ),
|
||||
m_filename( filename ),
|
||||
m_line( line ),
|
||||
m_macroName( macroName )
|
||||
{
|
||||
}
|
||||
|
||||
bool ok() const
|
||||
{
|
||||
return m_result == ResultWas::Ok;
|
||||
}
|
||||
|
||||
ResultWas::OfType getResultType() const
|
||||
{
|
||||
return m_result;
|
||||
}
|
||||
|
||||
bool hasExpression() const
|
||||
{
|
||||
return !m_expr.empty();
|
||||
}
|
||||
bool hasMessage() const
|
||||
{
|
||||
return !m_message.empty();
|
||||
}
|
||||
std::string getExpression() const
|
||||
{
|
||||
return m_expr;
|
||||
}
|
||||
std::string getExpandedExpression() const
|
||||
{
|
||||
if( m_op == "" || m_isNot )
|
||||
return m_lhs.empty() ? m_expr : m_op + m_lhs;
|
||||
else if( m_op != "!" )
|
||||
return m_lhs + " " + m_op + " " + m_rhs;
|
||||
else
|
||||
return "{can't expand - use " + m_macroName + "_NOT( " + m_expr.substr(1) + " ) instead of " + m_macroName + "( " + m_expr + " ) for better diagnostics}";
|
||||
}
|
||||
|
||||
std::string getMessage() const
|
||||
{
|
||||
return m_message;
|
||||
}
|
||||
|
||||
std::string getFilename() const
|
||||
{
|
||||
return m_filename;
|
||||
}
|
||||
|
||||
size_t getLine() const
|
||||
{
|
||||
return m_line;
|
||||
}
|
||||
|
||||
std::string getTestMacroName() const
|
||||
{
|
||||
return m_macroName;
|
||||
}
|
||||
|
||||
protected:
|
||||
std::string m_macroName;
|
||||
std::string m_filename;
|
||||
size_t m_line;
|
||||
std::string m_expr, m_lhs, m_rhs, m_op;
|
||||
std::string m_message;
|
||||
ResultWas::OfType m_result;
|
||||
bool m_isNot;
|
||||
};
|
||||
|
||||
} // end namespace Catch
|
||||
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_RESULT_INFO_HPP_INCLUDED
|
145
internal/catch_runner_impl.hpp
Normal file
145
internal/catch_runner_impl.hpp
Normal file
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
* catch_runner.hpp
|
||||
* Catch
|
||||
*
|
||||
* Created by Phil on 22/10/2010.
|
||||
* Copyright 2010 Two Blue Cubes Ltd. All rights reserved.
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
*/
|
||||
#ifndef TWOBLUECUBES_INTERNAL_CATCH_RUNNER_HPP_INCLUDED
|
||||
#define TWOBLUECUBES_INTERNAL_CATCH_RUNNER_HPP_INCLUDED
|
||||
|
||||
#include "catch_reporter_registry.hpp"
|
||||
#include "catch_registry.hpp"
|
||||
#include "catch_capture.hpp"
|
||||
|
||||
namespace Catch
|
||||
{
|
||||
class TestSpec
|
||||
{
|
||||
public:
|
||||
TestSpec( const std::string& rawSpec )
|
||||
: m_rawSpec( rawSpec ),
|
||||
m_isWildcarded( false )
|
||||
{
|
||||
if( m_rawSpec[m_rawSpec.size()-1] == '*' )
|
||||
{
|
||||
m_rawSpec = m_rawSpec.substr( 0, m_rawSpec.size()-1 );
|
||||
m_isWildcarded = true;
|
||||
}
|
||||
}
|
||||
|
||||
bool matches( const std::string& testName ) const
|
||||
{
|
||||
if( !m_isWildcarded )
|
||||
return m_rawSpec == testName;
|
||||
else
|
||||
return testName.size() >= m_rawSpec.size() && testName.substr( 0, m_rawSpec.size() ) == m_rawSpec;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string m_rawSpec;
|
||||
bool m_isWildcarded;
|
||||
};
|
||||
|
||||
class Runner : public IResultListener
|
||||
{
|
||||
public:
|
||||
Runner()
|
||||
: m_successes( 0 ),
|
||||
m_failures( 0 ),
|
||||
m_reporter( 0 )
|
||||
{
|
||||
}
|
||||
|
||||
void setReporter( ITestReporter* reporter )
|
||||
{
|
||||
m_reporter = reporter;
|
||||
}
|
||||
|
||||
void runAll()
|
||||
{
|
||||
std::vector<TestCaseInfo> allTests = TestRegistry::instance().getAllTests();
|
||||
for( size_t i=0; i < allTests.size(); ++i )
|
||||
{
|
||||
runTest( allTests[i] );
|
||||
}
|
||||
}
|
||||
|
||||
size_t runMatching( const std::string& rawTestSpec )
|
||||
{
|
||||
TestSpec testSpec( rawTestSpec );
|
||||
|
||||
std::vector<TestCaseInfo> allTests = TestRegistry::instance().getAllTests();
|
||||
size_t testsRun = 0;
|
||||
for( size_t i=0; i < allTests.size(); ++i )
|
||||
{
|
||||
if( testSpec.matches( allTests[i].getName() ) )
|
||||
{
|
||||
runTest( allTests[i] );
|
||||
testsRun++;
|
||||
}
|
||||
}
|
||||
return testsRun;
|
||||
}
|
||||
|
||||
void runTest( const TestCaseInfo& testInfo )
|
||||
{
|
||||
IResultListener* prevListener = ResultsCapture::setListener( this );
|
||||
m_reporter->StartTestCase( testInfo );
|
||||
|
||||
try
|
||||
{
|
||||
testInfo.invoke();
|
||||
}
|
||||
catch( TestFailureException& ex )
|
||||
{
|
||||
// This just means the test was aborted due to failure
|
||||
}
|
||||
catch( std::exception& ex )
|
||||
{
|
||||
ResultsCapture::acceptMessage( ex.what() );
|
||||
ResultsCapture::acceptResult( ResultWas::ThrewException );
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
ResultsCapture::acceptMessage( "unknown exception" );
|
||||
ResultsCapture::acceptResult( ResultWas::ThrewException );
|
||||
}
|
||||
|
||||
m_reporter->EndTestCase( testInfo );
|
||||
ResultsCapture::setListener( prevListener );
|
||||
}
|
||||
|
||||
size_t getSuccessCount() const
|
||||
{
|
||||
return m_successes;
|
||||
}
|
||||
size_t getFailures() const
|
||||
{
|
||||
return m_failures;
|
||||
}
|
||||
|
||||
private: // IResultListener
|
||||
|
||||
virtual void testEnded( const ResultInfo& result )
|
||||
{
|
||||
if( result.ok() )
|
||||
m_successes++;
|
||||
else
|
||||
m_failures++;
|
||||
|
||||
m_reporter->Result( result );
|
||||
}
|
||||
|
||||
private:
|
||||
size_t m_successes;
|
||||
size_t m_failures;
|
||||
ITestReporter* m_reporter;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // TWOBLUECUBES_INTERNAL_CATCH_RUNNER_HPP_INCLUDED
|
39
internal/catch_section.hpp
Normal file
39
internal/catch_section.hpp
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* catch_section.hpp
|
||||
* Catch
|
||||
*
|
||||
* Created by Phil on 03/11/2010.
|
||||
* Copyright 2010 Two Blue Cubes Ltd. All rights reserved.
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TWOBLUECUBES_CATCH_SECTION_HPP_INCLUDED
|
||||
#define TWOBLUECUBES_CATCH_SECTION_HPP_INCLUDED
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace Catch
|
||||
{
|
||||
class Section
|
||||
{
|
||||
public:
|
||||
Section( const std::string& name, const std::string& description )
|
||||
{
|
||||
// !TBD notify the runner
|
||||
}
|
||||
|
||||
operator bool()
|
||||
{
|
||||
// !TBD get this from runner
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace Catch
|
||||
|
||||
#define CATCH_SECTION( name, desc ) if( Catch::Section __catchSection = Catch::Section( name, desc ) )
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_SECTION_HPP_INCLUDED
|
84
internal/catch_testcaseinfo.hpp
Normal file
84
internal/catch_testcaseinfo.hpp
Normal file
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* catch_testcaseinfo.hpp
|
||||
* Catch
|
||||
*
|
||||
* Created by Phil on 29/10/2010.
|
||||
* Copyright 2010 Two Blue Cubes Ltd. All rights reserved.
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TWOBLUECUBES_CATCH_TESTCASEINFO_HPP_INCLUDED
|
||||
#define TWOBLUECUBES_CATCH_TESTCASEINFO_HPP_INCLUDED
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
namespace Catch
|
||||
{
|
||||
struct TestCase
|
||||
{
|
||||
virtual ~TestCase(){}
|
||||
virtual void invoke() const = 0;
|
||||
virtual TestCase* clone() const = 0;
|
||||
};
|
||||
|
||||
class TestCaseInfo
|
||||
{
|
||||
public:
|
||||
TestCaseInfo( TestCase* testCase, const std::string& name, const std::string& description )
|
||||
: test( testCase ),
|
||||
name( name ),
|
||||
description( description )
|
||||
{
|
||||
}
|
||||
TestCaseInfo()
|
||||
: test( NULL )
|
||||
{
|
||||
}
|
||||
|
||||
TestCaseInfo( const TestCaseInfo& other )
|
||||
: test( other.test->clone() ),
|
||||
name( other.name ),
|
||||
description( other.description )
|
||||
{
|
||||
}
|
||||
|
||||
TestCaseInfo& operator = ( const TestCaseInfo& other )
|
||||
{
|
||||
test = other.test->clone();
|
||||
name = other.name;
|
||||
description = description;
|
||||
return *this;
|
||||
}
|
||||
|
||||
~TestCaseInfo()
|
||||
{
|
||||
delete test;
|
||||
}
|
||||
|
||||
void invoke() const
|
||||
{
|
||||
test->invoke();
|
||||
}
|
||||
|
||||
const std::string& getName() const
|
||||
{
|
||||
return name;
|
||||
}
|
||||
const std::string& getDescription() const
|
||||
{
|
||||
return description;
|
||||
}
|
||||
|
||||
private:
|
||||
TestCase* test;
|
||||
std::string name;
|
||||
std::string description;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_TESTCASEINFO_HPP_INCLUDED
|
Reference in New Issue
Block a user