Context methods are non-static - accessed via interface

This is a move towards allowing multiple contexts - with the concept of a (possibly thread local) "current" context
This commit is contained in:
Phil Nash 2012-05-21 18:52:09 +01:00
parent 89d2a3f911
commit 371db8b42f
17 changed files with 304 additions and 260 deletions

View File

@ -15,7 +15,6 @@
#include "internal/catch_generators.hpp" #include "internal/catch_generators.hpp"
#include "internal/catch_interfaces_exception.h" #include "internal/catch_interfaces_exception.h"
#include "internal/catch_approx.hpp" #include "internal/catch_approx.hpp"
#include "internal/catch_test_case_info.hpp"
#include "internal/catch_matchers.hpp" #include "internal/catch_matchers.hpp"
#ifdef __OBJC__ #ifdef __OBJC__

View File

@ -62,7 +62,9 @@ namespace Catch {
config.getReporter()->EndGroup( *it, runner.getTotals() - prevTotals ); config.getReporter()->EndGroup( *it, runner.getTotals() - prevTotals );
} }
} }
return static_cast<int>( runner.getTotals().assertions.failed ); int result = static_cast<int>( runner.getTotals().assertions.failed );
Catch::Context::cleanUp();
return result;
} }
inline void showHelp( std::string exeName ) { inline void showHelp( std::string exeName ) {
@ -87,25 +89,25 @@ namespace Catch {
if( !config.getMessage().empty() ) { if( !config.getMessage().empty() ) {
std::cerr << config.getMessage() << std::endl; std::cerr << config.getMessage() << std::endl;
Catch::Context::cleanUp();
return (std::numeric_limits<int>::max)(); return (std::numeric_limits<int>::max)();
} }
// Handle help // Handle help
if( config.showHelp() ) { if( config.showHelp() ) {
showHelp( argv[0] ); showHelp( argv[0] );
Catch::Context::cleanUp();
return 0; return 0;
} }
return Main( config ); return Main( config );
} }
inline int Main( int argc, char* const argv[] ) { inline int Main( int argc, char* const argv[] ) {
Config config; Config config;
// !TBD: This doesn't always work, for some reason
// if( isDebuggerActive() ) // if( isDebuggerActive() )
// config.useStream( "debug" ); // config.useStream( "debug" );
int result = Main( argc, argv, config ); return Main( argc, argv, config );
Catch::Context::cleanUp();
return result;
} }
} // end namespace Catch } // end namespace Catch

View File

@ -22,11 +22,11 @@ struct TestFailureException{};
class ScopedInfo { class ScopedInfo {
public: public:
ScopedInfo() : m_oss() { ScopedInfo() : m_oss() {
Context::getResultCapture().pushScopedInfo( this ); getCurrentContext().getResultCapture().pushScopedInfo( this );
} }
~ScopedInfo() { ~ScopedInfo() {
Context::getResultCapture().popScopedInfo( this ); getCurrentContext().getResultCapture().popScopedInfo( this );
} }
template<typename T> template<typename T>
@ -50,7 +50,7 @@ inline bool isTrue( bool value ){ return value; }
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_ACCEPT_EXPR( expr, stopOnFailure, originalExpr ) \ #define INTERNAL_CATCH_ACCEPT_EXPR( expr, stopOnFailure, originalExpr ) \
if( Catch::ResultAction::Value internal_catch_action = Catch::Context::getResultCapture().acceptExpression( expr ) ) \ if( Catch::ResultAction::Value internal_catch_action = Catch::getCurrentContext().getResultCapture().acceptExpression( expr ) ) \
{ \ { \
if( internal_catch_action == Catch::ResultAction::DebugFailed ) BreakIntoDebugger(); \ if( internal_catch_action == Catch::ResultAction::DebugFailed ) BreakIntoDebugger(); \
if( Catch::isTrue( stopOnFailure ) ) throw Catch::TestFailureException(); \ if( Catch::isTrue( stopOnFailure ) ) throw Catch::TestFailureException(); \
@ -64,19 +64,19 @@ inline bool isTrue( bool value ){ return value; }
}catch( Catch::TestFailureException& ){ \ }catch( Catch::TestFailureException& ){ \
throw; \ throw; \
} catch( ... ){ \ } catch( ... ){ \
INTERNAL_CATCH_ACCEPT_EXPR( ( Catch::ExpressionBuilder( CATCH_INTERNAL_LINEINFO, macroName, #expr ) << Catch::Context::getExceptionTranslatorRegistry().translateActiveException() ).setResultType( Catch::ResultWas::ThrewException ), false, expr ); \ INTERNAL_CATCH_ACCEPT_EXPR( ( Catch::ExpressionBuilder( CATCH_INTERNAL_LINEINFO, macroName, #expr ) << Catch::getCurrentContext().getExceptionTranslatorRegistry().translateActiveException() ).setResultType( Catch::ResultWas::ThrewException ), false, expr ); \
throw; \ throw; \
}}while( Catch::isTrue( false ) ) }}while( Catch::isTrue( false ) )
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_IF( expr, isNot, stopOnFailure, macroName ) \ #define INTERNAL_CATCH_IF( expr, isNot, stopOnFailure, macroName ) \
INTERNAL_CATCH_TEST( expr, isNot, stopOnFailure, macroName ); \ INTERNAL_CATCH_TEST( expr, isNot, stopOnFailure, macroName ); \
if( Catch::Context::getResultCapture().getLastResult()->ok() ) if( Catch::getCurrentContext().getResultCapture().getLastResult()->ok() )
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_ELSE( expr, isNot, stopOnFailure, macroName ) \ #define INTERNAL_CATCH_ELSE( expr, isNot, stopOnFailure, macroName ) \
INTERNAL_CATCH_TEST( expr, isNot, stopOnFailure, macroName ); \ INTERNAL_CATCH_TEST( expr, isNot, stopOnFailure, macroName ); \
if( !Catch::Context::getResultCapture().getLastResult()->ok() ) if( !Catch::getCurrentContext().getResultCapture().getLastResult()->ok() )
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_NO_THROW( expr, stopOnFailure, macroName ) \ #define INTERNAL_CATCH_NO_THROW( expr, stopOnFailure, macroName ) \
@ -87,7 +87,7 @@ inline bool isTrue( bool value ){ return value; }
} \ } \
catch( ... ) \ catch( ... ) \
{ \ { \
INTERNAL_CATCH_ACCEPT_EXPR( ( Catch::ExpressionBuilder( CATCH_INTERNAL_LINEINFO, macroName, #expr ) << Catch::Context::getExceptionTranslatorRegistry().translateActiveException() ).setResultType( Catch::ResultWas::ThrewException ), stopOnFailure, false ); \ INTERNAL_CATCH_ACCEPT_EXPR( ( Catch::ExpressionBuilder( CATCH_INTERNAL_LINEINFO, macroName, #expr ) << Catch::getCurrentContext().getExceptionTranslatorRegistry().translateActiveException() ).setResultType( Catch::ResultWas::ThrewException ), stopOnFailure, false ); \
} }
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
@ -111,12 +111,12 @@ inline bool isTrue( bool value ){ return value; }
INTERNAL_CATCH_THROWS( expr, exceptionType, stopOnFailure, macroName ) \ INTERNAL_CATCH_THROWS( expr, exceptionType, stopOnFailure, macroName ) \
catch( ... ) \ catch( ... ) \
{ \ { \
INTERNAL_CATCH_ACCEPT_EXPR( ( Catch::ExpressionBuilder( CATCH_INTERNAL_LINEINFO, macroName, #expr ) << Catch::Context::getExceptionTranslatorRegistry().translateActiveException() ).setResultType( Catch::ResultWas::ThrewException ), stopOnFailure, false ); \ INTERNAL_CATCH_ACCEPT_EXPR( ( Catch::ExpressionBuilder( CATCH_INTERNAL_LINEINFO, macroName, #expr ) << Catch::getCurrentContext().getExceptionTranslatorRegistry().translateActiveException() ).setResultType( Catch::ResultWas::ThrewException ), stopOnFailure, false ); \
} }
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_MSG( reason, resultType, stopOnFailure, macroName ) \ #define INTERNAL_CATCH_MSG( reason, resultType, stopOnFailure, macroName ) \
Catch::Context::getResultCapture().acceptExpression( ( Catch::ExpressionBuilder( CATCH_INTERNAL_LINEINFO, macroName ) << reason ).setResultType( resultType ) ); Catch::getCurrentContext().getResultCapture().acceptExpression( ( Catch::ExpressionBuilder( CATCH_INTERNAL_LINEINFO, macroName ) << reason ).setResultType( resultType ) );
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_SCOPED_INFO( log ) \ #define INTERNAL_CATCH_SCOPED_INFO( log ) \
@ -130,7 +130,7 @@ inline bool isTrue( bool value ){ return value; }
}catch( Catch::TestFailureException& ){ \ }catch( Catch::TestFailureException& ){ \
throw; \ throw; \
} catch( ... ){ \ } catch( ... ){ \
INTERNAL_CATCH_ACCEPT_EXPR( ( Catch::ExpressionBuilder( CATCH_INTERNAL_LINEINFO, macroName, #arg " " #matcher ) << Catch::Context::getExceptionTranslatorRegistry().translateActiveException() ).setResultType( Catch::ResultWas::ThrewException ), false, false ); \ INTERNAL_CATCH_ACCEPT_EXPR( ( Catch::ExpressionBuilder( CATCH_INTERNAL_LINEINFO, macroName, #arg " " #matcher ) << Catch::getCurrentContext().getExceptionTranslatorRegistry().translateActiveException() ).setResultType( Catch::ResultWas::ThrewException ), false, false ); \
throw; \ throw; \
}}while( Catch::isTrue( false ) ) }}while( Catch::isTrue( false ) )

View File

@ -62,7 +62,7 @@ namespace Catch {
void setReporter( const std::string& reporterName ) { void setReporter( const std::string& reporterName ) {
if( m_reporter.get() ) if( m_reporter.get() )
return setError( "Only one reporter may be specified" ); return setError( "Only one reporter may be specified" );
setReporter( Context::getReporterRegistry().create( reporterName, *this ) ); setReporter( getCurrentContext().getReporterRegistry().create( reporterName, *this ) );
} }
void addTestSpec( const std::string& testSpec ) { void addTestSpec( const std::string& testSpec ) {
@ -107,7 +107,7 @@ namespace Catch {
Ptr<IReporter> getReporter() { Ptr<IReporter> getReporter() {
if( !m_reporter.get() ) if( !m_reporter.get() )
const_cast<Config*>( this )->setReporter( Context::getReporterRegistry().create( "basic", *this ) ); const_cast<Config*>( this )->setReporter( getCurrentContext().getReporterRegistry().create( "basic", *this ) );
return m_reporter; return m_reporter;
} }

View File

@ -25,28 +25,56 @@ namespace Catch {
class StreamBufBase : public std::streambuf{}; class StreamBufBase : public std::streambuf{};
class Context { struct IContext
{
virtual IResultCapture& getResultCapture() = 0;
virtual IRunner& getRunner() = 0;
virtual IReporterRegistry& getReporterRegistry() = 0;
virtual ITestCaseRegistry& getTestCaseRegistry() = 0;
virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() = 0;
virtual size_t getGeneratorIndex( const std::string& fileInfo, size_t totalSize ) = 0;
virtual bool advanceGeneratorsForCurrentTest() = 0;
};
Context(); struct IMutableContext : IContext
{
virtual void setResultCapture( IResultCapture* resultCapture ) = 0;
virtual void setRunner( IRunner* runner ) = 0;
};
IContext& getCurrentContext();
IMutableContext& getCurrentMutableContext();
class Context : public IMutableContext {
Context();
Context( const Context& ); Context( const Context& );
void operator=( const Context& ); void operator=( const Context& );
static Context& me();
public: public: // friends
static void setRunner( IRunner* runner ); friend IContext& getCurrentContext() { return Context::getCurrent(); }
static void setResultCapture( IResultCapture* resultCapture ); friend IMutableContext& getCurrentMutableContext() { return Context::getCurrent(); }
static IResultCapture& getResultCapture();
static IReporterRegistry& getReporterRegistry(); public: // IContext
static ITestCaseRegistry& getTestCaseRegistry(); virtual IResultCapture& getResultCapture();
static IExceptionTranslatorRegistry& getExceptionTranslatorRegistry(); virtual IRunner& getRunner();
virtual IReporterRegistry& getReporterRegistry();
virtual ITestCaseRegistry& getTestCaseRegistry();
virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry();
virtual size_t getGeneratorIndex( const std::string& fileInfo, size_t totalSize );
virtual bool advanceGeneratorsForCurrentTest();
public: // IMutableContext
virtual void setResultCapture( IResultCapture* resultCapture );
virtual void setRunner( IRunner* runner );
public: // Statics
static std::streambuf* createStreamBuf( const std::string& streamName ); static std::streambuf* createStreamBuf( const std::string& streamName );
static IRunner& getRunner();
static size_t getGeneratorIndex( const std::string& fileInfo, size_t totalSize );
static bool advanceGeneratorsForCurrentTest();
static void cleanUp(); static void cleanUp();
private: private:
static Context*& singleInstance(); static Context& getCurrent();
static Context*& singleInstance();
GeneratorsForTest* findGeneratorsForCurrentTest(); GeneratorsForTest* findGeneratorsForCurrentTest();
GeneratorsForTest& getGeneratorsForCurrentTest(); GeneratorsForTest& getGeneratorsForCurrentTest();

View File

@ -17,13 +17,20 @@
namespace Catch { namespace Catch {
Context::Context() Context::Context()
: m_reporterRegistry( new ReporterRegistry ), : m_reporterRegistry( new ReporterRegistry ),
m_testCaseRegistry( new TestRegistry ), m_testCaseRegistry( new TestRegistry ),
m_exceptionTranslatorRegistry( new ExceptionTranslatorRegistry ) m_exceptionTranslatorRegistry( new ExceptionTranslatorRegistry )
{} {}
Context& Context::me() { Context*& Context::singleInstance() {
static Context* hub = NULL;
return hub;
}
Context& Context::getCurrent() {
Context*& hub = singleInstance(); Context*& hub = singleInstance();
if( !hub ) if( !hub )
hub = new Context(); hub = new Context();
@ -36,37 +43,32 @@ namespace Catch {
hub = NULL; hub = NULL;
} }
Context*& Context::singleInstance() {
static Context* hub = NULL;
return hub;
}
void Context::setRunner( IRunner* runner ) { void Context::setRunner( IRunner* runner ) {
me().m_runner = runner; m_runner = runner;
} }
void Context::setResultCapture( IResultCapture* resultCapture ) { void Context::setResultCapture( IResultCapture* resultCapture ) {
me().m_resultCapture = resultCapture; m_resultCapture = resultCapture;
} }
IResultCapture& Context::getResultCapture() { IResultCapture& Context::getResultCapture() {
return *me().m_resultCapture; return *m_resultCapture;
} }
IRunner& Context::getRunner() { IRunner& Context::getRunner() {
return *me().m_runner; return *m_runner;
} }
IReporterRegistry& Context::getReporterRegistry() { IReporterRegistry& Context::getReporterRegistry() {
return *me().m_reporterRegistry.get(); return *m_reporterRegistry.get();
} }
ITestCaseRegistry& Context::getTestCaseRegistry() { ITestCaseRegistry& Context::getTestCaseRegistry() {
return *me().m_testCaseRegistry.get(); return *m_testCaseRegistry.get();
} }
IExceptionTranslatorRegistry& Context::getExceptionTranslatorRegistry() { IExceptionTranslatorRegistry& Context::getExceptionTranslatorRegistry() {
return *me().m_exceptionTranslatorRegistry.get(); return *m_exceptionTranslatorRegistry.get();
} }
std::streambuf* Context::createStreamBuf( const std::string& streamName ) { std::streambuf* Context::createStreamBuf( const std::string& streamName ) {
@ -78,7 +80,7 @@ namespace Catch {
} }
GeneratorsForTest* Context::findGeneratorsForCurrentTest() { GeneratorsForTest* Context::findGeneratorsForCurrentTest() {
std::string testName = getResultCapture().getCurrentTestName(); std::string testName = getCurrentContext().getResultCapture().getCurrentTestName();
std::map<std::string, GeneratorsForTest*>::const_iterator it = std::map<std::string, GeneratorsForTest*>::const_iterator it =
m_generatorsByTestName.find( testName ); m_generatorsByTestName.find( testName );
@ -90,7 +92,7 @@ namespace Catch {
GeneratorsForTest& Context::getGeneratorsForCurrentTest() { GeneratorsForTest& Context::getGeneratorsForCurrentTest() {
GeneratorsForTest* generators = findGeneratorsForCurrentTest(); GeneratorsForTest* generators = findGeneratorsForCurrentTest();
if( !generators ) { if( !generators ) {
std::string testName = getResultCapture().getCurrentTestName(); std::string testName = getCurrentContext().getResultCapture().getCurrentTestName();
generators = new GeneratorsForTest(); generators = new GeneratorsForTest();
m_generatorsByTestName.insert( std::make_pair( testName, generators ) ); m_generatorsByTestName.insert( std::make_pair( testName, generators ) );
} }
@ -98,13 +100,13 @@ namespace Catch {
} }
size_t Context::getGeneratorIndex( const std::string& fileInfo, size_t totalSize ) { size_t Context::getGeneratorIndex( const std::string& fileInfo, size_t totalSize ) {
return me().getGeneratorsForCurrentTest() return getGeneratorsForCurrentTest()
.getGeneratorInfo( fileInfo, totalSize ) .getGeneratorInfo( fileInfo, totalSize )
.getCurrentIndex(); .getCurrentIndex();
} }
bool Context::advanceGeneratorsForCurrentTest() { bool Context::advanceGeneratorsForCurrentTest() {
GeneratorsForTest* generators = me().findGeneratorsForCurrentTest(); GeneratorsForTest* generators = findGeneratorsForCurrentTest();
return generators && generators->moveNext(); return generators && generators->moveNext();
} }
} }

View File

@ -20,26 +20,13 @@ namespace Internal {
IsGreaterThanOrEqualTo IsGreaterThanOrEqualTo
}; };
template<Operator Op> template<Operator Op> struct OperatorTraits { static const char* getName(){ return "*error*"; } };
struct OperatorTraits{ static const char* getName(){ return "*error - unknown operator*"; } }; template<> struct OperatorTraits<IsEqualTo> { static const char* getName(){ return "=="; } };
template<> struct OperatorTraits<IsNotEqualTo> { static const char* getName(){ return "!="; } };
template<> template<> struct OperatorTraits<IsLessThan> { static const char* getName(){ return "<"; } };
struct OperatorTraits<IsEqualTo>{ static const char* getName(){ return "=="; } }; template<> struct OperatorTraits<IsGreaterThan> { static const char* getName(){ return ">"; } };
template<> struct OperatorTraits<IsLessThanOrEqualTo> { static const char* getName(){ return "<="; } };
template<> template<> struct OperatorTraits<IsGreaterThanOrEqualTo>{ static const char* getName(){ return ">="; } };
struct OperatorTraits<IsNotEqualTo>{ static const char* getName(){ return "!="; } };
template<>
struct OperatorTraits<IsLessThan>{ static const char* getName(){ return "<"; } };
template<>
struct OperatorTraits<IsGreaterThan>{ static const char* getName(){ return ">"; } };
template<>
struct OperatorTraits<IsLessThanOrEqualTo>{ static const char* getName(){ return "<="; } };
template<>
struct OperatorTraits<IsGreaterThanOrEqualTo>{ static const char* getName(){ return ">="; } };
// So the compare overloads can be operator agnostic we convey the operator as a template // So the compare overloads can be operator agnostic we convey the operator as a template
// enum, which is used to specialise an Evaluator for doing the comparison. // enum, which is used to specialise an Evaluator for doing the comparison.

View File

@ -87,7 +87,7 @@ public:
} }
operator T () const { operator T () const {
size_t overallIndex = Context::getGeneratorIndex( m_fileInfo, m_totalSize ); size_t overallIndex = getCurrentContext().getGeneratorIndex( m_fileInfo, m_totalSize );
typename std::vector<const IGenerator<T>*>::const_iterator it = m_composed.begin(); typename std::vector<const IGenerator<T>*>::const_iterator it = m_composed.begin();
typename std::vector<const IGenerator<T>*>::const_iterator itEnd = m_composed.end(); typename std::vector<const IGenerator<T>*>::const_iterator itEnd = m_composed.end();

View File

@ -51,7 +51,7 @@ namespace Catch {
public: public:
template<typename T> template<typename T>
ExceptionTranslatorRegistrar( std::string(*translateFunction)( T& ) ) { ExceptionTranslatorRegistrar( std::string(*translateFunction)( T& ) ) {
Catch::Context::getExceptionTranslatorRegistry().registerTranslator getCurrentContext().getExceptionTranslatorRegistry().registerTranslator
( new ExceptionTranslator<T>( translateFunction ) ); ( new ExceptionTranslator<T>( translateFunction ) );
} }
}; };

View File

@ -14,10 +14,11 @@
namespace Catch { namespace Catch {
inline int List( Config& config ) { inline int List( Config& config ) {
IContext& context = getCurrentContext();
if( config.listWhat() & Config::List::Reports ) { if( config.listWhat() & Config::List::Reports ) {
std::cout << "Available reports:\n"; std::cout << "Available reports:\n";
IReporterRegistry::FactoryMap::const_iterator it = Context::getReporterRegistry().getFactories().begin(); IReporterRegistry::FactoryMap::const_iterator it = context.getReporterRegistry().getFactories().begin();
IReporterRegistry::FactoryMap::const_iterator itEnd = Context::getReporterRegistry().getFactories().end(); IReporterRegistry::FactoryMap::const_iterator itEnd = context.getReporterRegistry().getFactories().end();
for(; it != itEnd; ++it ) { for(; it != itEnd; ++it ) {
// !TBD: consider listAs() // !TBD: consider listAs()
std::cout << "\t" << it->first << "\n\t\t'" << it->second->getDescription() << "'\n"; std::cout << "\t" << it->first << "\n\t\t'" << it->second->getDescription() << "'\n";
@ -27,8 +28,8 @@ namespace Catch {
if( config.listWhat() & Config::List::Tests ) { if( config.listWhat() & Config::List::Tests ) {
std::cout << "Available tests:\n"; std::cout << "Available tests:\n";
std::vector<TestCaseInfo>::const_iterator it = Context::getTestCaseRegistry().getAllTests().begin(); std::vector<TestCaseInfo>::const_iterator it = context.getTestCaseRegistry().getAllTests().begin();
std::vector<TestCaseInfo>::const_iterator itEnd = Context::getTestCaseRegistry().getAllTests().end(); std::vector<TestCaseInfo>::const_iterator itEnd = context.getTestCaseRegistry().getAllTests().end();
for(; it != itEnd; ++it ) { for(; it != itEnd; ++it ) {
// !TBD: consider listAs() // !TBD: consider listAs()
std::cout << "\t" << it->getName() << "\n\t\t '" << it->getDescription() << "'\n"; std::cout << "\t" << it->getName() << "\n\t\t '" << it->getDescription() << "'\n";

View File

@ -137,7 +137,7 @@ namespace Catch {
std::string name = Detail::getAnnotation( cls, "Name", testCaseName ); std::string name = Detail::getAnnotation( cls, "Name", testCaseName );
std::string desc = Detail::getAnnotation( cls, "Description", testCaseName ); std::string desc = Detail::getAnnotation( cls, "Description", testCaseName );
Context::getTestCaseRegistry().registerTest( TestCaseInfo( new OcMethod( cls, selector ), name.c_str(), desc.c_str(), SourceLineInfo() ) ); getCurrentContext().getTestCaseRegistry().registerTest( TestCaseInfo( new OcMethod( cls, selector ), name.c_str(), desc.c_str(), SourceLineInfo() ) );
noTestMethods++; noTestMethods++;
} }
} }

View File

@ -29,7 +29,7 @@ namespace Catch {
public: public:
ReporterRegistrar( const std::string& name ) { ReporterRegistrar( const std::string& name ) {
Context::getReporterRegistry().registerReporter( name, new ReporterFactory() ); getCurrentContext().getReporterRegistry().registerReporter( name, new ReporterFactory() );
} }
}; };
} }

View File

@ -56,25 +56,26 @@ namespace Catch {
public: public:
explicit Runner( Config& config ) explicit Runner( Config& config )
: m_runningTest( NULL ), : m_context( getCurrentMutableContext() ),
m_runningTest( NULL ),
m_config( config ), m_config( config ),
m_reporter( config.getReporter() ), m_reporter( config.getReporter() ),
m_prevRunner( &Context::getRunner() ), m_prevRunner( &m_context.getRunner() ),
m_prevResultCapture( &Context::getResultCapture() ) m_prevResultCapture( &m_context.getResultCapture() )
{ {
Context::setRunner( this ); m_context.setRunner( this );
Context::setResultCapture( this ); m_context.setResultCapture( this );
m_reporter->StartTesting(); m_reporter->StartTesting();
} }
~Runner() { ~Runner() {
m_reporter->EndTesting( m_totals ); m_reporter->EndTesting( m_totals );
Context::setRunner( m_prevRunner ); m_context.setRunner( m_prevRunner );
Context::setResultCapture( m_prevResultCapture ); m_context.setResultCapture( m_prevResultCapture );
} }
virtual void runAll( bool runHiddenTests = false ) { virtual void runAll( bool runHiddenTests = false ) {
std::vector<TestCaseInfo> allTests = Context::getTestCaseRegistry().getAllTests(); const std::vector<TestCaseInfo>& allTests = getCurrentContext().getTestCaseRegistry().getAllTests();
for( std::size_t i=0; i < allTests.size(); ++i ) { for( std::size_t i=0; i < allTests.size(); ++i ) {
if( runHiddenTests || !allTests[i].isHidden() ) if( runHiddenTests || !allTests[i].isHidden() )
runTest( allTests[i] ); runTest( allTests[i] );
@ -84,7 +85,7 @@ namespace Catch {
virtual std::size_t runMatching( const std::string& rawTestSpec ) { virtual std::size_t runMatching( const std::string& rawTestSpec ) {
TestSpec testSpec( rawTestSpec ); TestSpec testSpec( rawTestSpec );
std::vector<TestCaseInfo> allTests = Context::getTestCaseRegistry().getAllTests(); const std::vector<TestCaseInfo>& allTests = getCurrentContext().getTestCaseRegistry().getAllTests();
std::size_t testsRun = 0; std::size_t testsRun = 0;
for( std::size_t i=0; i < allTests.size(); ++i ) { for( std::size_t i=0; i < allTests.size(); ++i ) {
if( testSpec.matches( allTests[i].getName() ) ) { if( testSpec.matches( allTests[i].getName() ) ) {
@ -114,7 +115,7 @@ namespace Catch {
} }
while( m_runningTest->hasUntestedSections() ); while( m_runningTest->hasUntestedSections() );
} }
while( Context::advanceGeneratorsForCurrentTest() ); while( getCurrentContext().advanceGeneratorsForCurrentTest() );
delete m_runningTest; delete m_runningTest;
m_runningTest = NULL; m_runningTest = NULL;
@ -251,13 +252,14 @@ namespace Catch {
// This just means the test was aborted due to failure // This just means the test was aborted due to failure
} }
catch(...) { catch(...) {
acceptMessage( Catch::Context::getExceptionTranslatorRegistry().translateActiveException() ); acceptMessage( getCurrentContext().getExceptionTranslatorRegistry().translateActiveException() );
acceptResult( ResultWas::ThrewException ); acceptResult( ResultWas::ThrewException );
} }
m_info.clear(); m_info.clear();
} }
private: private:
IMutableContext& m_context;
RunningTest* m_runningTest; RunningTest* m_runningTest;
ResultInfoBuilder m_currentResult; ResultInfoBuilder m_currentResult;
ResultInfo m_lastResult; ResultInfo m_lastResult;
@ -270,6 +272,7 @@ namespace Catch {
IRunner* m_prevRunner; IRunner* m_prevRunner;
IResultCapture* m_prevResultCapture; IResultCapture* m_prevResultCapture;
}; };
}
} // end namespace Catch
#endif // TWOBLUECUBES_INTERNAL_CATCH_RUNNER_HPP_INCLUDED #endif // TWOBLUECUBES_INTERNAL_CATCH_RUNNER_HPP_INCLUDED

View File

@ -21,12 +21,12 @@ namespace Catch {
const std::string& description, const std::string& description,
const SourceLineInfo& lineInfo ) const SourceLineInfo& lineInfo )
: m_name( name ), : m_name( name ),
m_sectionIncluded( Context::getResultCapture().sectionStarted( name, description, lineInfo, m_assertions ) ) m_sectionIncluded( getCurrentContext().getResultCapture().sectionStarted( name, description, lineInfo, m_assertions ) )
{} {}
~Section() { ~Section() {
if( m_sectionIncluded ) if( m_sectionIncluded )
Context::getResultCapture().sectionEnded( m_name, m_assertions ); getCurrentContext().getResultCapture().sectionEnded( m_name, m_assertions );
} }
// This indicates whether the section should be executed or not // This indicates whether the section should be executed or not

View File

@ -109,7 +109,7 @@ namespace Catch {
const char* name, const char* name,
const char* description, const char* description,
const SourceLineInfo& lineInfo ) { const SourceLineInfo& lineInfo ) {
Context::getTestCaseRegistry().registerTest( TestCaseInfo( testCase, name, description, lineInfo ) ); getCurrentContext().getTestCaseRegistry().registerTest( TestCaseInfo( testCase, name, description, lineInfo ) );
} }
} // end namespace Catch } // end namespace Catch

View File

@ -9,6 +9,7 @@
#define TWOBLUECUBES_CATCH_SELF_TEST_HPP_INCLUDED #define TWOBLUECUBES_CATCH_SELF_TEST_HPP_INCLUDED
#include "catch.hpp" #include "catch.hpp"
#include "catch_test_case_info.hpp"
#include "set" #include "set"
@ -143,7 +144,7 @@ namespace Catch {
static void runMatching( const std::string& testSpec, static void runMatching( const std::string& testSpec,
Expected::Result expectedResult ) { Expected::Result expectedResult ) {
forEach( Context::getTestCaseRegistry().getMatchingTestCases( testSpec ), forEach( getCurrentContext().getTestCaseRegistry().getMatchingTestCases( testSpec ),
MetaTestRunner( expectedResult ) ); MetaTestRunner( expectedResult ) );
} }

View File

@ -298,27 +298,55 @@ namespace Catch {
class StreamBufBase : public std::streambuf{}; class StreamBufBase : public std::streambuf{};
class Context { struct IContext
{
virtual IResultCapture& getResultCapture() = 0;
virtual IRunner& getRunner() = 0;
virtual IReporterRegistry& getReporterRegistry() = 0;
virtual ITestCaseRegistry& getTestCaseRegistry() = 0;
virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() = 0;
virtual size_t getGeneratorIndex( const std::string& fileInfo, size_t totalSize ) = 0;
virtual bool advanceGeneratorsForCurrentTest() = 0;
};
struct IMutableContext : IContext
{
virtual void setResultCapture( IResultCapture* resultCapture ) = 0;
virtual void setRunner( IRunner* runner ) = 0;
};
IContext& getCurrentContext();
IMutableContext& getCurrentMutableContext();
class Context : public IMutableContext {
Context(); Context();
Context( const Context& ); Context( const Context& );
void operator=( const Context& ); void operator=( const Context& );
static Context& me();
public: public: // friends
static void setRunner( IRunner* runner ); friend IContext& getCurrentContext() { return Context::getCurrent(); }
static void setResultCapture( IResultCapture* resultCapture ); friend IMutableContext& getCurrentMutableContext() { return Context::getCurrent(); }
static IResultCapture& getResultCapture();
static IReporterRegistry& getReporterRegistry(); public: // IContext
static ITestCaseRegistry& getTestCaseRegistry(); virtual IResultCapture& getResultCapture();
static IExceptionTranslatorRegistry& getExceptionTranslatorRegistry(); virtual IRunner& getRunner();
virtual IReporterRegistry& getReporterRegistry();
virtual ITestCaseRegistry& getTestCaseRegistry();
virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry();
virtual size_t getGeneratorIndex( const std::string& fileInfo, size_t totalSize );
virtual bool advanceGeneratorsForCurrentTest();
public: // IMutableContext
virtual void setResultCapture( IResultCapture* resultCapture );
virtual void setRunner( IRunner* runner );
public: // Statics
static std::streambuf* createStreamBuf( const std::string& streamName ); static std::streambuf* createStreamBuf( const std::string& streamName );
static IRunner& getRunner();
static size_t getGeneratorIndex( const std::string& fileInfo, size_t totalSize );
static bool advanceGeneratorsForCurrentTest();
static void cleanUp(); static void cleanUp();
private: private:
static Context& getCurrent();
static Context*& singleInstance(); static Context*& singleInstance();
GeneratorsForTest* findGeneratorsForCurrentTest(); GeneratorsForTest* findGeneratorsForCurrentTest();
GeneratorsForTest& getGeneratorsForCurrentTest(); GeneratorsForTest& getGeneratorsForCurrentTest();
@ -735,26 +763,13 @@ namespace Internal {
IsGreaterThanOrEqualTo IsGreaterThanOrEqualTo
}; };
template<Operator Op> template<Operator Op> struct OperatorTraits { static const char* getName(){ return "*error*"; } };
struct OperatorTraits{ static const char* getName(){ return "*error - unknown operator*"; } }; template<> struct OperatorTraits<IsEqualTo> { static const char* getName(){ return "=="; } };
template<> struct OperatorTraits<IsNotEqualTo> { static const char* getName(){ return "!="; } };
template<> template<> struct OperatorTraits<IsLessThan> { static const char* getName(){ return "<"; } };
struct OperatorTraits<IsEqualTo>{ static const char* getName(){ return "=="; } }; template<> struct OperatorTraits<IsGreaterThan> { static const char* getName(){ return ">"; } };
template<> struct OperatorTraits<IsLessThanOrEqualTo> { static const char* getName(){ return "<="; } };
template<> template<> struct OperatorTraits<IsGreaterThanOrEqualTo>{ static const char* getName(){ return ">="; } };
struct OperatorTraits<IsNotEqualTo>{ static const char* getName(){ return "!="; } };
template<>
struct OperatorTraits<IsLessThan>{ static const char* getName(){ return "<"; } };
template<>
struct OperatorTraits<IsGreaterThan>{ static const char* getName(){ return ">"; } };
template<>
struct OperatorTraits<IsLessThanOrEqualTo>{ static const char* getName(){ return "<="; } };
template<>
struct OperatorTraits<IsGreaterThanOrEqualTo>{ static const char* getName(){ return ">="; } };
// So the compare overloads can be operator agnostic we convey the operator as a template // So the compare overloads can be operator agnostic we convey the operator as a template
// enum, which is used to specialise an Evaluator for doing the comparison. // enum, which is used to specialise an Evaluator for doing the comparison.
@ -1314,11 +1329,11 @@ struct TestFailureException{};
class ScopedInfo { class ScopedInfo {
public: public:
ScopedInfo() : m_oss() { ScopedInfo() : m_oss() {
Context::getResultCapture().pushScopedInfo( this ); getCurrentContext().getResultCapture().pushScopedInfo( this );
} }
~ScopedInfo() { ~ScopedInfo() {
Context::getResultCapture().popScopedInfo( this ); getCurrentContext().getResultCapture().popScopedInfo( this );
} }
template<typename T> template<typename T>
@ -1342,7 +1357,7 @@ inline bool isTrue( bool value ){ return value; }
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_ACCEPT_EXPR( expr, stopOnFailure, originalExpr ) \ #define INTERNAL_CATCH_ACCEPT_EXPR( expr, stopOnFailure, originalExpr ) \
if( Catch::ResultAction::Value internal_catch_action = Catch::Context::getResultCapture().acceptExpression( expr ) ) \ if( Catch::ResultAction::Value internal_catch_action = Catch::getCurrentContext().getResultCapture().acceptExpression( expr ) ) \
{ \ { \
if( internal_catch_action == Catch::ResultAction::DebugFailed ) BreakIntoDebugger(); \ if( internal_catch_action == Catch::ResultAction::DebugFailed ) BreakIntoDebugger(); \
if( Catch::isTrue( stopOnFailure ) ) throw Catch::TestFailureException(); \ if( Catch::isTrue( stopOnFailure ) ) throw Catch::TestFailureException(); \
@ -1356,19 +1371,19 @@ inline bool isTrue( bool value ){ return value; }
}catch( Catch::TestFailureException& ){ \ }catch( Catch::TestFailureException& ){ \
throw; \ throw; \
} catch( ... ){ \ } catch( ... ){ \
INTERNAL_CATCH_ACCEPT_EXPR( ( Catch::ExpressionBuilder( CATCH_INTERNAL_LINEINFO, macroName, #expr ) << Catch::Context::getExceptionTranslatorRegistry().translateActiveException() ).setResultType( Catch::ResultWas::ThrewException ), false, expr ); \ INTERNAL_CATCH_ACCEPT_EXPR( ( Catch::ExpressionBuilder( CATCH_INTERNAL_LINEINFO, macroName, #expr ) << Catch::getCurrentContext().getExceptionTranslatorRegistry().translateActiveException() ).setResultType( Catch::ResultWas::ThrewException ), false, expr ); \
throw; \ throw; \
}}while( Catch::isTrue( false ) ) }}while( Catch::isTrue( false ) )
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_IF( expr, isNot, stopOnFailure, macroName ) \ #define INTERNAL_CATCH_IF( expr, isNot, stopOnFailure, macroName ) \
INTERNAL_CATCH_TEST( expr, isNot, stopOnFailure, macroName ); \ INTERNAL_CATCH_TEST( expr, isNot, stopOnFailure, macroName ); \
if( Catch::Context::getResultCapture().getLastResult()->ok() ) if( Catch::getCurrentContext().getResultCapture().getLastResult()->ok() )
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_ELSE( expr, isNot, stopOnFailure, macroName ) \ #define INTERNAL_CATCH_ELSE( expr, isNot, stopOnFailure, macroName ) \
INTERNAL_CATCH_TEST( expr, isNot, stopOnFailure, macroName ); \ INTERNAL_CATCH_TEST( expr, isNot, stopOnFailure, macroName ); \
if( !Catch::Context::getResultCapture().getLastResult()->ok() ) if( !Catch::getCurrentContext().getResultCapture().getLastResult()->ok() )
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_NO_THROW( expr, stopOnFailure, macroName ) \ #define INTERNAL_CATCH_NO_THROW( expr, stopOnFailure, macroName ) \
@ -1379,7 +1394,7 @@ inline bool isTrue( bool value ){ return value; }
} \ } \
catch( ... ) \ catch( ... ) \
{ \ { \
INTERNAL_CATCH_ACCEPT_EXPR( ( Catch::ExpressionBuilder( CATCH_INTERNAL_LINEINFO, macroName, #expr ) << Catch::Context::getExceptionTranslatorRegistry().translateActiveException() ).setResultType( Catch::ResultWas::ThrewException ), stopOnFailure, false ); \ INTERNAL_CATCH_ACCEPT_EXPR( ( Catch::ExpressionBuilder( CATCH_INTERNAL_LINEINFO, macroName, #expr ) << Catch::getCurrentContext().getExceptionTranslatorRegistry().translateActiveException() ).setResultType( Catch::ResultWas::ThrewException ), stopOnFailure, false ); \
} }
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
@ -1403,12 +1418,12 @@ inline bool isTrue( bool value ){ return value; }
INTERNAL_CATCH_THROWS( expr, exceptionType, stopOnFailure, macroName ) \ INTERNAL_CATCH_THROWS( expr, exceptionType, stopOnFailure, macroName ) \
catch( ... ) \ catch( ... ) \
{ \ { \
INTERNAL_CATCH_ACCEPT_EXPR( ( Catch::ExpressionBuilder( CATCH_INTERNAL_LINEINFO, macroName, #expr ) << Catch::Context::getExceptionTranslatorRegistry().translateActiveException() ).setResultType( Catch::ResultWas::ThrewException ), stopOnFailure, false ); \ INTERNAL_CATCH_ACCEPT_EXPR( ( Catch::ExpressionBuilder( CATCH_INTERNAL_LINEINFO, macroName, #expr ) << Catch::getCurrentContext().getExceptionTranslatorRegistry().translateActiveException() ).setResultType( Catch::ResultWas::ThrewException ), stopOnFailure, false ); \
} }
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_MSG( reason, resultType, stopOnFailure, macroName ) \ #define INTERNAL_CATCH_MSG( reason, resultType, stopOnFailure, macroName ) \
Catch::Context::getResultCapture().acceptExpression( ( Catch::ExpressionBuilder( CATCH_INTERNAL_LINEINFO, macroName ) << reason ).setResultType( resultType ) ); Catch::getCurrentContext().getResultCapture().acceptExpression( ( Catch::ExpressionBuilder( CATCH_INTERNAL_LINEINFO, macroName ) << reason ).setResultType( resultType ) );
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_SCOPED_INFO( log ) \ #define INTERNAL_CATCH_SCOPED_INFO( log ) \
@ -1422,7 +1437,7 @@ inline bool isTrue( bool value ){ return value; }
}catch( Catch::TestFailureException& ){ \ }catch( Catch::TestFailureException& ){ \
throw; \ throw; \
} catch( ... ){ \ } catch( ... ){ \
INTERNAL_CATCH_ACCEPT_EXPR( ( Catch::ExpressionBuilder( CATCH_INTERNAL_LINEINFO, macroName, #arg " " #matcher ) << Catch::Context::getExceptionTranslatorRegistry().translateActiveException() ).setResultType( Catch::ResultWas::ThrewException ), false, false ); \ INTERNAL_CATCH_ACCEPT_EXPR( ( Catch::ExpressionBuilder( CATCH_INTERNAL_LINEINFO, macroName, #arg " " #matcher ) << Catch::getCurrentContext().getExceptionTranslatorRegistry().translateActiveException() ).setResultType( Catch::ResultWas::ThrewException ), false, false ); \
throw; \ throw; \
}}while( Catch::isTrue( false ) ) }}while( Catch::isTrue( false ) )
@ -1438,12 +1453,12 @@ namespace Catch {
const std::string& description, const std::string& description,
const SourceLineInfo& lineInfo ) const SourceLineInfo& lineInfo )
: m_name( name ), : m_name( name ),
m_sectionIncluded( Context::getResultCapture().sectionStarted( name, description, lineInfo, m_assertions ) ) m_sectionIncluded( getCurrentContext().getResultCapture().sectionStarted( name, description, lineInfo, m_assertions ) )
{} {}
~Section() { ~Section() {
if( m_sectionIncluded ) if( m_sectionIncluded )
Context::getResultCapture().sectionEnded( m_name, m_assertions ); getCurrentContext().getResultCapture().sectionEnded( m_name, m_assertions );
} }
// This indicates whether the section should be executed or not // This indicates whether the section should be executed or not
@ -1542,7 +1557,7 @@ public:
} }
operator T () const { operator T () const {
size_t overallIndex = Context::getGeneratorIndex( m_fileInfo, m_totalSize ); size_t overallIndex = getCurrentContext().getGeneratorIndex( m_fileInfo, m_totalSize );
typename std::vector<const IGenerator<T>*>::const_iterator it = m_composed.begin(); typename std::vector<const IGenerator<T>*>::const_iterator it = m_composed.begin();
typename std::vector<const IGenerator<T>*>::const_iterator itEnd = m_composed.end(); typename std::vector<const IGenerator<T>*>::const_iterator itEnd = m_composed.end();
@ -1687,7 +1702,7 @@ namespace Catch {
public: public:
template<typename T> template<typename T>
ExceptionTranslatorRegistrar( std::string(*translateFunction)( T& ) ) { ExceptionTranslatorRegistrar( std::string(*translateFunction)( T& ) ) {
Catch::Context::getExceptionTranslatorRegistry().registerTranslator getCurrentContext().getExceptionTranslatorRegistry().registerTranslator
( new ExceptionTranslator<T>( translateFunction ) ); ( new ExceptionTranslator<T>( translateFunction ) );
} }
}; };
@ -1779,6 +1794,84 @@ inline std::string toString<Detail::Approx>( const Detail::Approx& value ) {
} // end namespace Catch } // end namespace Catch
// #included from: internal/catch_matchers.hpp
namespace Catch {
namespace Matchers {
namespace Impl {
namespace StdString {
struct Contains {
Contains( const std::string& substr ) : m_substr( substr ){}
bool operator()( const std::string& str ) const
{
return str.find( m_substr ) != std::string::npos;
}
friend std::ostream& operator<<( std::ostream& os, const Contains& matcher )
{
os << "contains: \"" << matcher.m_substr << "\"";
return os;
}
std::string m_substr;
};
struct StartsWith {
StartsWith( const std::string& substr ) : m_substr( substr ){}
bool operator()( const std::string& str ) const
{
return str.find( m_substr ) == 0;
}
friend std::ostream& operator<<( std::ostream& os, const StartsWith& matcher )
{
os << "starts with: \"" << matcher.m_substr << "\"";
return os;
}
std::string m_substr;
};
struct EndsWith {
EndsWith( const std::string& substr ) : m_substr( substr ){}
bool operator()( const std::string& str ) const
{
return str.find( m_substr ) == str.size() - m_substr.size();
}
friend std::ostream& operator<<( std::ostream& os, const EndsWith& matcher )
{
os << "ends with: \"" << matcher.m_substr << "\"";
return os;
}
std::string m_substr;
};
} // namespace StdString
} // namespace Impl
inline Impl::StdString::Contains Contains( const std::string& substr ){ return Impl::StdString::Contains( substr ); }
inline Impl::StdString::StartsWith StartsWith( const std::string& substr ){ return Impl::StdString::StartsWith( substr ); }
inline Impl::StdString::EndsWith EndsWith( const std::string& substr ){ return Impl::StdString::EndsWith( substr ); }
} // namespace Matchers
using namespace Matchers;
} // namespace Catch
#ifdef __OBJC__
// #included from: internal/catch_objc.hpp
#import <Foundation/Foundation.h>
#import <objc/runtime.h>
#include <string>
// NB. Any general catch headers included here must be included
// in catch.hpp first to make sure they are included by the single
// header for non obj-usage
// #included from: internal/catch_test_case_info.hpp // #included from: internal/catch_test_case_info.hpp
#include <map> #include <map>
@ -1897,84 +1990,6 @@ namespace Catch {
}; };
} }
// #included from: internal/catch_matchers.hpp
namespace Catch {
namespace Matchers {
namespace Impl {
namespace StdString {
struct Contains {
Contains( const std::string& substr ) : m_substr( substr ){}
bool operator()( const std::string& str ) const
{
return str.find( m_substr ) != std::string::npos;
}
friend std::ostream& operator<<( std::ostream& os, const Contains& matcher )
{
os << "contains: \"" << matcher.m_substr << "\"";
return os;
}
std::string m_substr;
};
struct StartsWith {
StartsWith( const std::string& substr ) : m_substr( substr ){}
bool operator()( const std::string& str ) const
{
return str.find( m_substr ) == 0;
}
friend std::ostream& operator<<( std::ostream& os, const StartsWith& matcher )
{
os << "starts with: \"" << matcher.m_substr << "\"";
return os;
}
std::string m_substr;
};
struct EndsWith {
EndsWith( const std::string& substr ) : m_substr( substr ){}
bool operator()( const std::string& str ) const
{
return str.find( m_substr ) == str.size() - m_substr.size();
}
friend std::ostream& operator<<( std::ostream& os, const EndsWith& matcher )
{
os << "ends with: \"" << matcher.m_substr << "\"";
return os;
}
std::string m_substr;
};
} // namespace StdString
} // namespace Impl
inline Impl::StdString::Contains Contains( const std::string& substr ){ return Impl::StdString::Contains( substr ); }
inline Impl::StdString::StartsWith StartsWith( const std::string& substr ){ return Impl::StdString::StartsWith( substr ); }
inline Impl::StdString::EndsWith EndsWith( const std::string& substr ){ return Impl::StdString::EndsWith( substr ); }
} // namespace Matchers
using namespace Matchers;
} // namespace Catch
#ifdef __OBJC__
// #included from: internal/catch_objc.hpp
#import <Foundation/Foundation.h>
#import <objc/runtime.h>
#include <string>
// NB. Any general catch headers included here must be included
// in catch.hpp first to make sure they are included by the single
// header for non obj-usage
#ifdef __has_feature #ifdef __has_feature
#define CATCH_ARC_ENABLED __has_feature(objc_arc) #define CATCH_ARC_ENABLED __has_feature(objc_arc)
@ -2095,7 +2110,7 @@ namespace Catch {
std::string name = Detail::getAnnotation( cls, "Name", testCaseName ); std::string name = Detail::getAnnotation( cls, "Name", testCaseName );
std::string desc = Detail::getAnnotation( cls, "Description", testCaseName ); std::string desc = Detail::getAnnotation( cls, "Description", testCaseName );
Context::getTestCaseRegistry().registerTest( TestCaseInfo( new OcMethod( cls, selector ), name.c_str(), desc.c_str(), SourceLineInfo() ) ); getCurrentContext().getTestCaseRegistry().registerTest( TestCaseInfo( new OcMethod( cls, selector ), name.c_str(), desc.c_str(), SourceLineInfo() ) );
noTestMethods++; noTestMethods++;
} }
} }
@ -2314,7 +2329,7 @@ namespace Catch {
const char* name, const char* name,
const char* description, const char* description,
const SourceLineInfo& lineInfo ) { const SourceLineInfo& lineInfo ) {
Context::getTestCaseRegistry().registerTest( TestCaseInfo( testCase, name, description, lineInfo ) ); getCurrentContext().getTestCaseRegistry().registerTest( TestCaseInfo( testCase, name, description, lineInfo ) );
} }
} // end namespace Catch } // end namespace Catch
@ -2388,7 +2403,7 @@ namespace Catch {
void setReporter( const std::string& reporterName ) { void setReporter( const std::string& reporterName ) {
if( m_reporter.get() ) if( m_reporter.get() )
return setError( "Only one reporter may be specified" ); return setError( "Only one reporter may be specified" );
setReporter( Context::getReporterRegistry().create( reporterName, *this ) ); setReporter( getCurrentContext().getReporterRegistry().create( reporterName, *this ) );
} }
void addTestSpec( const std::string& testSpec ) { void addTestSpec( const std::string& testSpec ) {
@ -2433,7 +2448,7 @@ namespace Catch {
Ptr<IReporter> getReporter() { Ptr<IReporter> getReporter() {
if( !m_reporter.get() ) if( !m_reporter.get() )
const_cast<Config*>( this )->setReporter( Context::getReporterRegistry().create( "basic", *this ) ); const_cast<Config*>( this )->setReporter( getCurrentContext().getReporterRegistry().create( "basic", *this ) );
return m_reporter; return m_reporter;
} }
@ -2730,25 +2745,26 @@ namespace Catch {
public: public:
explicit Runner( Config& config ) explicit Runner( Config& config )
: m_runningTest( NULL ), : m_context( getCurrentMutableContext() ),
m_runningTest( NULL ),
m_config( config ), m_config( config ),
m_reporter( config.getReporter() ), m_reporter( config.getReporter() ),
m_prevRunner( &Context::getRunner() ), m_prevRunner( &m_context.getRunner() ),
m_prevResultCapture( &Context::getResultCapture() ) m_prevResultCapture( &m_context.getResultCapture() )
{ {
Context::setRunner( this ); m_context.setRunner( this );
Context::setResultCapture( this ); m_context.setResultCapture( this );
m_reporter->StartTesting(); m_reporter->StartTesting();
} }
~Runner() { ~Runner() {
m_reporter->EndTesting( m_totals ); m_reporter->EndTesting( m_totals );
Context::setRunner( m_prevRunner ); m_context.setRunner( m_prevRunner );
Context::setResultCapture( m_prevResultCapture ); m_context.setResultCapture( m_prevResultCapture );
} }
virtual void runAll( bool runHiddenTests = false ) { virtual void runAll( bool runHiddenTests = false ) {
std::vector<TestCaseInfo> allTests = Context::getTestCaseRegistry().getAllTests(); const std::vector<TestCaseInfo>& allTests = getCurrentContext().getTestCaseRegistry().getAllTests();
for( std::size_t i=0; i < allTests.size(); ++i ) { for( std::size_t i=0; i < allTests.size(); ++i ) {
if( runHiddenTests || !allTests[i].isHidden() ) if( runHiddenTests || !allTests[i].isHidden() )
runTest( allTests[i] ); runTest( allTests[i] );
@ -2758,7 +2774,7 @@ namespace Catch {
virtual std::size_t runMatching( const std::string& rawTestSpec ) { virtual std::size_t runMatching( const std::string& rawTestSpec ) {
TestSpec testSpec( rawTestSpec ); TestSpec testSpec( rawTestSpec );
std::vector<TestCaseInfo> allTests = Context::getTestCaseRegistry().getAllTests(); const std::vector<TestCaseInfo>& allTests = getCurrentContext().getTestCaseRegistry().getAllTests();
std::size_t testsRun = 0; std::size_t testsRun = 0;
for( std::size_t i=0; i < allTests.size(); ++i ) { for( std::size_t i=0; i < allTests.size(); ++i ) {
if( testSpec.matches( allTests[i].getName() ) ) { if( testSpec.matches( allTests[i].getName() ) ) {
@ -2788,7 +2804,7 @@ namespace Catch {
} }
while( m_runningTest->hasUntestedSections() ); while( m_runningTest->hasUntestedSections() );
} }
while( Context::advanceGeneratorsForCurrentTest() ); while( getCurrentContext().advanceGeneratorsForCurrentTest() );
delete m_runningTest; delete m_runningTest;
m_runningTest = NULL; m_runningTest = NULL;
@ -2925,13 +2941,14 @@ namespace Catch {
// This just means the test was aborted due to failure // This just means the test was aborted due to failure
} }
catch(...) { catch(...) {
acceptMessage( Catch::Context::getExceptionTranslatorRegistry().translateActiveException() ); acceptMessage( getCurrentContext().getExceptionTranslatorRegistry().translateActiveException() );
acceptResult( ResultWas::ThrewException ); acceptResult( ResultWas::ThrewException );
} }
m_info.clear(); m_info.clear();
} }
private: private:
IMutableContext& m_context;
RunningTest* m_runningTest; RunningTest* m_runningTest;
ResultInfoBuilder m_currentResult; ResultInfoBuilder m_currentResult;
ResultInfo m_lastResult; ResultInfo m_lastResult;
@ -2944,7 +2961,8 @@ namespace Catch {
IRunner* m_prevRunner; IRunner* m_prevRunner;
IResultCapture* m_prevResultCapture; IResultCapture* m_prevResultCapture;
}; };
}
} // end namespace Catch
// #included from: catch_generators_impl.hpp // #included from: catch_generators_impl.hpp
@ -3281,7 +3299,12 @@ namespace Catch {
m_exceptionTranslatorRegistry( new ExceptionTranslatorRegistry ) m_exceptionTranslatorRegistry( new ExceptionTranslatorRegistry )
{} {}
Context& Context::me() { Context*& Context::singleInstance() {
static Context* hub = NULL;
return hub;
}
Context& Context::getCurrent() {
Context*& hub = singleInstance(); Context*& hub = singleInstance();
if( !hub ) if( !hub )
hub = new Context(); hub = new Context();
@ -3294,37 +3317,32 @@ namespace Catch {
hub = NULL; hub = NULL;
} }
Context*& Context::singleInstance() {
static Context* hub = NULL;
return hub;
}
void Context::setRunner( IRunner* runner ) { void Context::setRunner( IRunner* runner ) {
me().m_runner = runner; m_runner = runner;
} }
void Context::setResultCapture( IResultCapture* resultCapture ) { void Context::setResultCapture( IResultCapture* resultCapture ) {
me().m_resultCapture = resultCapture; m_resultCapture = resultCapture;
} }
IResultCapture& Context::getResultCapture() { IResultCapture& Context::getResultCapture() {
return *me().m_resultCapture; return *m_resultCapture;
} }
IRunner& Context::getRunner() { IRunner& Context::getRunner() {
return *me().m_runner; return *m_runner;
} }
IReporterRegistry& Context::getReporterRegistry() { IReporterRegistry& Context::getReporterRegistry() {
return *me().m_reporterRegistry.get(); return *m_reporterRegistry.get();
} }
ITestCaseRegistry& Context::getTestCaseRegistry() { ITestCaseRegistry& Context::getTestCaseRegistry() {
return *me().m_testCaseRegistry.get(); return *m_testCaseRegistry.get();
} }
IExceptionTranslatorRegistry& Context::getExceptionTranslatorRegistry() { IExceptionTranslatorRegistry& Context::getExceptionTranslatorRegistry() {
return *me().m_exceptionTranslatorRegistry.get(); return *m_exceptionTranslatorRegistry.get();
} }
std::streambuf* Context::createStreamBuf( const std::string& streamName ) { std::streambuf* Context::createStreamBuf( const std::string& streamName ) {
@ -3336,7 +3354,7 @@ namespace Catch {
} }
GeneratorsForTest* Context::findGeneratorsForCurrentTest() { GeneratorsForTest* Context::findGeneratorsForCurrentTest() {
std::string testName = getResultCapture().getCurrentTestName(); std::string testName = getCurrentContext().getResultCapture().getCurrentTestName();
std::map<std::string, GeneratorsForTest*>::const_iterator it = std::map<std::string, GeneratorsForTest*>::const_iterator it =
m_generatorsByTestName.find( testName ); m_generatorsByTestName.find( testName );
@ -3348,7 +3366,7 @@ namespace Catch {
GeneratorsForTest& Context::getGeneratorsForCurrentTest() { GeneratorsForTest& Context::getGeneratorsForCurrentTest() {
GeneratorsForTest* generators = findGeneratorsForCurrentTest(); GeneratorsForTest* generators = findGeneratorsForCurrentTest();
if( !generators ) { if( !generators ) {
std::string testName = getResultCapture().getCurrentTestName(); std::string testName = getCurrentContext().getResultCapture().getCurrentTestName();
generators = new GeneratorsForTest(); generators = new GeneratorsForTest();
m_generatorsByTestName.insert( std::make_pair( testName, generators ) ); m_generatorsByTestName.insert( std::make_pair( testName, generators ) );
} }
@ -3356,13 +3374,13 @@ namespace Catch {
} }
size_t Context::getGeneratorIndex( const std::string& fileInfo, size_t totalSize ) { size_t Context::getGeneratorIndex( const std::string& fileInfo, size_t totalSize ) {
return me().getGeneratorsForCurrentTest() return getGeneratorsForCurrentTest()
.getGeneratorInfo( fileInfo, totalSize ) .getGeneratorInfo( fileInfo, totalSize )
.getCurrentIndex(); .getCurrentIndex();
} }
bool Context::advanceGeneratorsForCurrentTest() { bool Context::advanceGeneratorsForCurrentTest() {
GeneratorsForTest* generators = me().findGeneratorsForCurrentTest(); GeneratorsForTest* generators = findGeneratorsForCurrentTest();
return generators && generators->moveNext(); return generators && generators->moveNext();
} }
} }
@ -3547,10 +3565,11 @@ namespace Catch {
namespace Catch { namespace Catch {
inline int List( Config& config ) { inline int List( Config& config ) {
IContext& context = getCurrentContext();
if( config.listWhat() & Config::List::Reports ) { if( config.listWhat() & Config::List::Reports ) {
std::cout << "Available reports:\n"; std::cout << "Available reports:\n";
IReporterRegistry::FactoryMap::const_iterator it = Context::getReporterRegistry().getFactories().begin(); IReporterRegistry::FactoryMap::const_iterator it = context.getReporterRegistry().getFactories().begin();
IReporterRegistry::FactoryMap::const_iterator itEnd = Context::getReporterRegistry().getFactories().end(); IReporterRegistry::FactoryMap::const_iterator itEnd = context.getReporterRegistry().getFactories().end();
for(; it != itEnd; ++it ) { for(; it != itEnd; ++it ) {
// !TBD: consider listAs() // !TBD: consider listAs()
std::cout << "\t" << it->first << "\n\t\t'" << it->second->getDescription() << "'\n"; std::cout << "\t" << it->first << "\n\t\t'" << it->second->getDescription() << "'\n";
@ -3560,8 +3579,8 @@ namespace Catch {
if( config.listWhat() & Config::List::Tests ) { if( config.listWhat() & Config::List::Tests ) {
std::cout << "Available tests:\n"; std::cout << "Available tests:\n";
std::vector<TestCaseInfo>::const_iterator it = Context::getTestCaseRegistry().getAllTests().begin(); std::vector<TestCaseInfo>::const_iterator it = context.getTestCaseRegistry().getAllTests().begin();
std::vector<TestCaseInfo>::const_iterator itEnd = Context::getTestCaseRegistry().getAllTests().end(); std::vector<TestCaseInfo>::const_iterator itEnd = context.getTestCaseRegistry().getAllTests().end();
for(; it != itEnd; ++it ) { for(; it != itEnd; ++it ) {
// !TBD: consider listAs() // !TBD: consider listAs()
std::cout << "\t" << it->getName() << "\n\t\t '" << it->getDescription() << "'\n"; std::cout << "\t" << it->getName() << "\n\t\t '" << it->getDescription() << "'\n";
@ -3606,7 +3625,7 @@ namespace Catch {
public: public:
ReporterRegistrar( const std::string& name ) { ReporterRegistrar( const std::string& name ) {
Context::getReporterRegistry().registerReporter( name, new ReporterFactory() ); getCurrentContext().getReporterRegistry().registerReporter( name, new ReporterFactory() );
} }
}; };
} }
@ -4505,7 +4524,9 @@ namespace Catch {
config.getReporter()->EndGroup( *it, runner.getTotals() - prevTotals ); config.getReporter()->EndGroup( *it, runner.getTotals() - prevTotals );
} }
} }
return static_cast<int>( runner.getTotals().assertions.failed ); int result = static_cast<int>( runner.getTotals().assertions.failed );
Catch::Context::cleanUp();
return result;
} }
inline void showHelp( std::string exeName ) { inline void showHelp( std::string exeName ) {
@ -4530,25 +4551,25 @@ namespace Catch {
if( !config.getMessage().empty() ) { if( !config.getMessage().empty() ) {
std::cerr << config.getMessage() << std::endl; std::cerr << config.getMessage() << std::endl;
Catch::Context::cleanUp();
return (std::numeric_limits<int>::max)(); return (std::numeric_limits<int>::max)();
} }
// Handle help // Handle help
if( config.showHelp() ) { if( config.showHelp() ) {
showHelp( argv[0] ); showHelp( argv[0] );
Catch::Context::cleanUp();
return 0; return 0;
} }
return Main( config ); return Main( config );
} }
inline int Main( int argc, char* const argv[] ) { inline int Main( int argc, char* const argv[] ) {
Config config; Config config;
// !TBD: This doesn't always work, for some reason
// if( isDebuggerActive() ) // if( isDebuggerActive() )
// config.useStream( "debug" ); // config.useStream( "debug" );
int result = Main( argc, argv, config ); return Main( argc, argv, config );
Catch::Context::cleanUp();
return result;
} }
} // end namespace Catch } // end namespace Catch