Update to allow all self tests to be run and to allow running with tags

This commit is contained in:
Malcolm Noyes 2013-12-09 14:18:35 +00:00
parent dd8c13a9e1
commit 36cb967220
21 changed files with 1402 additions and 843 deletions

View File

@ -19,6 +19,7 @@
#if (_MANAGED == 1) || (_M_CEE == 1) // detect CLR #if (_MANAGED == 1) || (_M_CEE == 1) // detect CLR
#define INTERNAL_CATCH_VS_MANAGED #define INTERNAL_CATCH_VS_MANAGED
#define INTERNAL_CATCH_INLINE inline
#else #else
#if defined(_WINDLL) #if defined(_WINDLL)
@ -26,6 +27,7 @@
// It's possible that this is not enough for someone so allow it to be overridden... // It's possible that this is not enough for someone so allow it to be overridden...
#if !defined( CATCH_CONFIG_MAIN ) && !defined( CATCH_CONFIG_RUNNER ) #if !defined( CATCH_CONFIG_MAIN ) && !defined( CATCH_CONFIG_RUNNER )
#define INTERNAL_CATCH_VS_NATIVE #define INTERNAL_CATCH_VS_NATIVE
#define INTERNAL_CATCH_INLINE inline
#endif #endif
#endif #endif
@ -52,7 +54,6 @@
#endif #endif
#if defined(INTERNAL_CATCH_VS_MANAGED) || defined(INTERNAL_CATCH_VS_NATIVE) #if defined(INTERNAL_CATCH_VS_MANAGED) || defined(INTERNAL_CATCH_VS_NATIVE)
#define INTERNAL_CATCH_INLINE inline
#ifdef INTERNAL_CATCH_VS_MANAGED #ifdef INTERNAL_CATCH_VS_MANAGED
#include "internal/catch_vs_managed_impl.hpp" #include "internal/catch_vs_managed_impl.hpp"
#else // INTERNAL_CATCH_VS_MANAGED #else // INTERNAL_CATCH_VS_MANAGED
@ -203,6 +204,16 @@
#define THEN( desc ) SECTION( " Then: " desc, "" ) #define THEN( desc ) SECTION( " Then: " desc, "" )
#define AND_THEN( desc ) SECTION( " And: " desc, "" ) #define AND_THEN( desc ) SECTION( " And: " desc, "" )
#if defined(INTERNAL_CATCH_VS_MANAGED) || defined(INTERNAL_CATCH_VS_NATIVE)
#define CATCH_MAP_CATEGORY_TO_TAG( Category, Tag ) INTERNAL_CATCH_MAP_CATEGORY_TO_TAG( Category, Tag )
#define CATCH_CONFIG_SHOW_SUCCESS( v ) CATCH_INTERNAL_CONFIG_SHOW_SUCCESS( v )
#define CATCH_CONFIG_WARN_MISSING_ASSERTIONS( v ) CATCH_INTERNAL_CONFIG_WARN_MISSING_ASSERTIONS( v )
#else
#define CATCH_MAP_CATEGORY_TO_TAG( Category, Tag )
#define CATCH_CONFIG_SHOW_SUCCESS( v )
#define CATCH_CONFIG_WARN_MISSING_ASSERTIONS( v )
#endif
using Catch::Detail::Approx; using Catch::Detail::Approx;
#ifdef __clang__ #ifdef __clang__

View File

@ -108,6 +108,8 @@ namespace Catch {
std::set<TestCase> m_testsAlreadyRun; std::set<TestCase> m_testsAlreadyRun;
}; };
#if !defined(INTERNAL_CATCH_VS_MANAGED) && !defined(INTERNAL_CATCH_VS_NATIVE)
class Session { class Session {
static bool alreadyInstantiated; static bool alreadyInstantiated;
@ -232,6 +234,8 @@ namespace Catch {
bool Session::alreadyInstantiated = false; bool Session::alreadyInstantiated = false;
#endif // !VS_MANAGED && !VS_NATIVE
} // end namespace Catch } // end namespace Catch
#endif // TWOBLUECUBES_CATCH_RUNNER_HPP_INCLUDED #endif // TWOBLUECUBES_CATCH_RUNNER_HPP_INCLUDED

View File

@ -56,11 +56,7 @@ namespace Catch {
.setResultType( matcher.match( arg ) ); .setResultType( matcher.match( arg ) );
} }
#if defined(INTERNAL_CATCH_VS_MANAGED) struct TestFailureException{};
// TestFailureException not defined for CLR
#else // detect CLR
struct TestFailureException{};
#endif
} // end namespace Catch } // end namespace Catch
@ -70,7 +66,6 @@ struct TestFailureException{};
#if !defined(INTERNAL_CATCH_VS_MANAGED) && !defined(INTERNAL_CATCH_VS_NATIVE) #if !defined(INTERNAL_CATCH_VS_MANAGED) && !defined(INTERNAL_CATCH_VS_NATIVE)
// normal Catch // normal Catch
#define INTERNAL_CATCH_TEST_FAILURE_EXCEPTION const Catch::TestFailureException&
#define INTERNAL_CATCH_TEST_THROW_FAILURE throw Catch::TestFailureException(); #define INTERNAL_CATCH_TEST_THROW_FAILURE throw Catch::TestFailureException();
#else // VS integration #else // VS integration
@ -84,10 +79,9 @@ struct TestFailureException{};
std::stringstream _sf; \ std::stringstream _sf; \
_sf << r->getExpressionInMacro().c_str() << ", " << r->getMessage().c_str(); \ _sf << r->getExpressionInMacro().c_str() << ", " << r->getMessage().c_str(); \
std::string fail = _sf.str(); \ std::string fail = _sf.str(); \
Assert::Fail(Catch::convert_string_to_managed(fail)); \ Assert::Fail(Catch::convert_string_for_assert(fail)); \
} }
#define INTERNAL_CATCH_TEST_FAILURE_EXCEPTION AssertFailedException^
#else #else
#if defined(INTERNAL_CATCH_VS_NATIVE) #if defined(INTERNAL_CATCH_VS_NATIVE)
@ -106,8 +100,6 @@ struct TestFailureException{};
Assert::Fail(ws2.c_str(), &li); \ Assert::Fail(ws2.c_str(), &li); \
} }
#define INTERNAL_CATCH_TEST_FAILURE_EXCEPTION const Catch::TestFailureException&
#endif // INTERNAL_CATCH_VS_MANAGED #endif // INTERNAL_CATCH_VS_MANAGED
#endif // detect CLR #endif // detect CLR
@ -119,7 +111,7 @@ struct TestFailureException{};
if( Catch::ResultAction::Value internal_catch_action = Catch::getResultCapture().acceptExpression( evaluatedExpr, INTERNAL_CATCH_ASSERTIONINFO_NAME ) ) { \ if( Catch::ResultAction::Value internal_catch_action = Catch::getResultCapture().acceptExpression( evaluatedExpr, INTERNAL_CATCH_ASSERTIONINFO_NAME ) ) { \
if( internal_catch_action & Catch::ResultAction::Debug ) BreakIntoDebugger(); \ if( internal_catch_action & Catch::ResultAction::Debug ) BreakIntoDebugger(); \
if( internal_catch_action & Catch::ResultAction::Abort ) { INTERNAL_CATCH_TEST_THROW_FAILURE } \ if( internal_catch_action & Catch::ResultAction::Abort ) { INTERNAL_CATCH_TEST_THROW_FAILURE } \
if( !Catch::shouldContinueOnFailure( resultDisposition ) ) { INTERNAL_CATCH_TEST_THROW_FAILURE } \ if( !Catch::shouldContinueOnFailure( resultDisposition ) ) { throw Catch::TestFailureException(); } \
Catch::isTrue( false && originalExpr ); \ Catch::isTrue( false && originalExpr ); \
} }
@ -133,7 +125,7 @@ struct TestFailureException{};
INTERNAL_CATCH_ACCEPT_INFO( #expr, macroName, resultDisposition ); \ INTERNAL_CATCH_ACCEPT_INFO( #expr, macroName, resultDisposition ); \
try { \ try { \
INTERNAL_CATCH_ACCEPT_EXPR( ( Catch::ExpressionDecomposer()->*expr ).endExpression( resultDisposition ), resultDisposition, expr ); \ INTERNAL_CATCH_ACCEPT_EXPR( ( Catch::ExpressionDecomposer()->*expr ).endExpression( resultDisposition ), resultDisposition, expr ); \
} catch( INTERNAL_CATCH_TEST_FAILURE_EXCEPTION ) { \ } catch( const Catch::TestFailureException& ) { \
throw; \ throw; \
} catch( ... ) { \ } catch( ... ) { \
INTERNAL_CATCH_ACCEPT_EXPR( Catch::ExpressionResultBuilder( Catch::ResultWas::ThrewException ) << Catch::translateActiveException(), \ INTERNAL_CATCH_ACCEPT_EXPR( Catch::ExpressionResultBuilder( Catch::ResultWas::ThrewException ) << Catch::translateActiveException(), \
@ -172,7 +164,7 @@ struct TestFailureException{};
INTERNAL_CATCH_ACCEPT_EXPR( Catch::ExpressionResultBuilder( Catch::ResultWas::DidntThrowException ), resultDisposition, false ); \ INTERNAL_CATCH_ACCEPT_EXPR( Catch::ExpressionResultBuilder( Catch::ResultWas::DidntThrowException ), resultDisposition, false ); \
} \ } \
} \ } \
catch( INTERNAL_CATCH_TEST_FAILURE_EXCEPTION ) { \ catch( const Catch::TestFailureException& ) { \
throw; \ throw; \
} \ } \
catch( exceptionType ) { \ catch( exceptionType ) { \
@ -216,7 +208,7 @@ struct TestFailureException{};
INTERNAL_CATCH_ACCEPT_INFO( #arg " " #matcher, macroName, resultDisposition ); \ INTERNAL_CATCH_ACCEPT_INFO( #arg " " #matcher, macroName, resultDisposition ); \
try { \ try { \
INTERNAL_CATCH_ACCEPT_EXPR( ( Catch::expressionResultBuilderFromMatcher( ::Catch::Matchers::matcher, arg, #matcher ) ), resultDisposition, false ); \ INTERNAL_CATCH_ACCEPT_EXPR( ( Catch::expressionResultBuilderFromMatcher( ::Catch::Matchers::matcher, arg, #matcher ) ), resultDisposition, false ); \
} catch( INTERNAL_CATCH_TEST_FAILURE_EXCEPTION ) { \ } catch( const Catch::TestFailureException& ) { \
throw; \ throw; \
} catch( ... ) { \ } catch( ... ) { \
INTERNAL_CATCH_ACCEPT_EXPR( ( Catch::ExpressionResultBuilder( Catch::ResultWas::ThrewException ) << Catch::translateActiveException() ), \ INTERNAL_CATCH_ACCEPT_EXPR( ( Catch::ExpressionResultBuilder( Catch::ResultWas::ThrewException ) << Catch::translateActiveException() ), \

View File

@ -22,6 +22,138 @@
#define CATCH_CONFIG_CONSOLE_WIDTH 80 #define CATCH_CONFIG_CONSOLE_WIDTH 80
#endif #endif
namespace CatchOverrides {
class ConfigGuard
{
public:
ConfigGuard()
: origConfig(Catch::getCurrentContext().getConfig())
{}
~ConfigGuard()
{
Catch::getCurrentMutableContext().setConfig(origConfig);
}
const Catch::Ptr<Catch::IConfig const>& value() const {return origConfig;}
private:
ConfigGuard(const ConfigGuard&);
ConfigGuard& operator=(const ConfigGuard&);
const Catch::Ptr<Catch::IConfig const> origConfig;
};
template <typename T>
class Config
{
typedef std::map<int, bool> LineData;
typedef std::map<std::string, LineData> FileLineData;
public:
bool includeSuccessfulResults(const std::string& file, int c) const
{
bool result(false);
FileLineData::const_iterator it = showSuccessfulTestsData.find(file);
if( it != showSuccessfulTestsData.end() )
{
for( LineData::const_iterator lineIt = it->second.begin(); lineIt != it->second.end(); ++lineIt )
{
if( c <= lineIt->first )
break;
result = lineIt->second;
}
}
return result;
}
void insertSuccessfulResults(const std::string& file, int c, bool v)
{
FileLineData::iterator it = showSuccessfulTestsData.find(file);
if( it == showSuccessfulTestsData.end() )
{
LineData tmp;
tmp.insert(std::make_pair(c,v));
showSuccessfulTestsData.insert(std::make_pair(file, tmp));
}
else
{
it->second.insert(std::make_pair(c,v));
}
}
bool warnAboutMissingAssertions(const std::string& file, int c) const
{
bool result(false);
FileLineData::const_iterator it = missingAssertionData.find(file);
if( it != missingAssertionData.end() )
{
for( LineData::const_iterator lineIt = it->second.begin(); lineIt != it->second.end(); ++lineIt )
{
if( c <= lineIt->first )
break;
result = lineIt->second;
}
}
return result;
}
void insertMissingAssertions(const std::string& file, int c, bool v)
{
FileLineData::iterator it = missingAssertionData.find(file);
if( it == missingAssertionData.end() )
{
LineData tmp;
tmp.insert(std::make_pair(c,v));
missingAssertionData.insert(std::make_pair(file, tmp));
}
else
{
it->second.insert(std::make_pair(c,v));
}
}
static Config<T>& instance()
{
if( !s_instance )
{
s_instance = new Config<T>();
}
return *s_instance;
}
private:
FileLineData showSuccessfulTestsData;
FileLineData missingAssertionData;
static Config<T>* s_instance;
};
template <typename T>
Config<T>* Config<T>::s_instance = NULL;
template <typename T>
struct ConfigReset
{
ConfigReset( const std::string& file, int c )
{
Config<T>::instance().insertSuccessfulResults(file, c, false);
Config<T>::instance().insertMissingAssertions(file, c, false);
}
};
template <typename T>
struct ConfigShowSuccessfulTests
{
template <typename U>
ConfigShowSuccessfulTests( const std::string& file, int c, U v )
{
Config<T>::instance().insertSuccessfulResults(file, c, v ? true : false);
}
};
template <typename T>
struct ConfigWarnMissingAssertions
{
template <typename U>
ConfigWarnMissingAssertions( const std::string& file, int c, U v )
{
Config<T>::instance().insertMissingAssertions(file, c, v ? true : false);
}
};
}
namespace Catch { namespace Catch {
struct ConfigData { struct ConfigData {
@ -40,6 +172,21 @@ namespace Catch {
showDurations( ShowDurations::DefaultForReporter ) showDurations( ShowDurations::DefaultForReporter )
{} {}
explicit ConfigData(const IConfig* other)
: listTests( false ),
listTags( false ),
listReporters( false ),
showSuccessfulTests( other ? other->includeSuccessfulResults() : false ),
shouldDebugBreak( false ),
noThrow( other ? !other->allowThrows() : false ),
showHelp( false ),
abortAfter( -1 ),
verbosity( Verbosity::Normal ),
warnings( other ? (other->warnAboutMissingAssertions() ? WarnAbout::NoAssertions : WarnAbout::Nothing) : WarnAbout::Nothing ),
showDurations( other ? other->showDurations() : ShowDurations::DefaultForReporter ),
name( other ? other->name() : std::string() )
{}
bool listTests; bool listTests;
bool listTags; bool listTags;
bool listReporters; bool listReporters;

View File

@ -12,10 +12,6 @@
namespace Catch { namespace Catch {
namespace Detail {
struct IColourImpl;
}
struct Colour { struct Colour {
enum Code { enum Code {
None = 0, None = 0,
@ -53,12 +49,6 @@ namespace Catch {
// Use constructed object for RAII guard // Use constructed object for RAII guard
Colour( Code _colourCode ); Colour( Code _colourCode );
~Colour(); ~Colour();
// Use static method for one-shot changes
static void use( Code _colourCode );
private:
static Detail::IColourImpl* impl;
}; };
} // end namespace Catch } // end namespace Catch

View File

@ -10,13 +10,6 @@
#include "catch_console_colour.hpp" #include "catch_console_colour.hpp"
namespace Catch { namespace Detail {
struct IColourImpl {
virtual ~IColourImpl() {}
virtual void use( Colour::Code _colourCode ) = 0;
};
}}
#if defined ( CATCH_PLATFORM_WINDOWS ) ///////////////////////////////////////// #if defined ( CATCH_PLATFORM_WINDOWS ) /////////////////////////////////////////
#ifndef NOMINMAX #ifndef NOMINMAX
@ -32,7 +25,7 @@ namespace Catch { namespace Detail {
namespace Catch { namespace Catch {
namespace { namespace {
class Win32ColourImpl : public Detail::IColourImpl { class Win32ColourImpl {
public: public:
Win32ColourImpl() : stdoutHandle( GetStdHandle(STD_OUTPUT_HANDLE) ) Win32ColourImpl() : stdoutHandle( GetStdHandle(STD_OUTPUT_HANDLE) )
{ {
@ -41,7 +34,7 @@ namespace {
originalAttributes = csbiInfo.wAttributes; originalAttributes = csbiInfo.wAttributes;
} }
virtual void use( Colour::Code _colourCode ) { void use( Colour::Code _colourCode ) {
switch( _colourCode ) { switch( _colourCode ) {
case Colour::None: return setTextAttribute( originalAttributes ); case Colour::None: return setTextAttribute( originalAttributes );
case Colour::White: return setTextAttribute( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE ); case Colour::White: return setTextAttribute( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE );
@ -73,7 +66,7 @@ namespace {
return true; return true;
} }
Win32ColourImpl platformColourImpl; typedef Win32ColourImpl PlatformColourImpl;
} // end anon namespace } // end anon namespace
} // end namespace Catch } // end namespace Catch
@ -89,9 +82,9 @@ namespace {
// Thanks to Adam Strzelecki for original contribution // Thanks to Adam Strzelecki for original contribution
// (http://github.com/nanoant) // (http://github.com/nanoant)
// https://github.com/philsquared/Catch/pull/131 // https://github.com/philsquared/Catch/pull/131
class PosixColourImpl : public Detail::IColourImpl { class PosixColourImpl {
public: public:
virtual void use( Colour::Code _colourCode ) { void use( Colour::Code _colourCode ) {
switch( _colourCode ) { switch( _colourCode ) {
case Colour::None: case Colour::None:
case Colour::White: return setColour( "[0m" ); case Colour::White: return setColour( "[0m" );
@ -120,7 +113,7 @@ namespace {
return isatty( fileno(stdout) ); return isatty( fileno(stdout) );
} }
PosixColourImpl platformColourImpl; typedef PosixColourImpl PlatformColourImpl;
} // end anon namespace } // end anon namespace
} // end namespace Catch } // end namespace Catch
@ -129,24 +122,24 @@ namespace {
namespace Catch { namespace Catch {
namespace { template <typename Impl>
struct NoColourImpl : Detail::IColourImpl { struct ColourChange
void use( Colour::Code ) {} {
}; static Impl impl;
NoColourImpl noColourImpl; static const bool shouldUseColour;
static const bool shouldUseColour = shouldUseColourForPlatform() && };
!isDebuggerActive(); template <typename Impl>
} Impl ColourChange<Impl>::impl;
template <typename Impl>
const bool ColourChange<Impl>::shouldUseColour = shouldUseColourForPlatform() &&
!isDebuggerActive();;
Colour::Colour( Code _colourCode ){ use( _colourCode ); } INTERNAL_CATCH_INLINE Colour::Colour( Code _colourCode ) {
Colour::~Colour(){ use( None ); } if( ColourChange<PlatformColourImpl>::shouldUseColour ) ColourChange<PlatformColourImpl>::impl.use( _colourCode );
void Colour::use( Code _colourCode ) { }
impl->use( _colourCode ); INTERNAL_CATCH_INLINE Colour::~Colour() {
if( ColourChange<PlatformColourImpl>::shouldUseColour ) ColourChange<PlatformColourImpl>::impl.use( Colour::None );
} }
Detail::IColourImpl* Colour::impl = shouldUseColour
? static_cast<Detail::IColourImpl*>( &platformColourImpl )
: static_cast<Detail::IColourImpl*>( &noColourImpl );
} // end namespace Catch } // end namespace Catch

View File

@ -15,9 +15,10 @@
namespace Catch { namespace Catch {
template <typename Runner, typename ResultCapture>
class Context : public IMutableContext { class Context : public IMutableContext {
Context() : m_config( NULL ), m_runner( NULL ), m_resultCapture( NULL ) {} Context() : m_config( NULL ), m_runner( &nullRunner ), m_resultCapture( &nullResultCapture ) {}
Context( Context const& ); Context( Context const& );
void operator=( Context const& ); void operator=( Context const& );
@ -81,15 +82,28 @@ namespace Catch {
IRunner* m_runner; IRunner* m_runner;
IResultCapture* m_resultCapture; IResultCapture* m_resultCapture;
std::map<std::string, IGeneratorsForTest*> m_generatorsByTestName; std::map<std::string, IGeneratorsForTest*> m_generatorsByTestName;
static ResultCapture nullResultCapture;
static Runner nullRunner;
public:
static Context* currentContext;
}; };
namespace { template <typename Runner, typename ResultCapture>
ResultCapture Context<Runner, ResultCapture>::nullResultCapture;
template <typename Runner, typename ResultCapture>
Runner Context<Runner, ResultCapture>::nullRunner;
template <typename Runner, typename ResultCapture>
Context<Runner,ResultCapture>* Context<Runner, ResultCapture>::currentContext = NULL;
/*namespace {
Context* currentContext = NULL; Context* currentContext = NULL;
} }*/
typedef Context<NullRunner, NullResultCapture> DefaultContext;
INTERNAL_CATCH_INLINE IMutableContext& getCurrentMutableContext() { INTERNAL_CATCH_INLINE IMutableContext& getCurrentMutableContext() {
if( !currentContext ) if( !DefaultContext::currentContext )
currentContext = new Context(); DefaultContext::currentContext = new DefaultContext();
return *currentContext; return *DefaultContext::currentContext;
} }
INTERNAL_CATCH_INLINE IContext& getCurrentContext() { INTERNAL_CATCH_INLINE IContext& getCurrentContext() {
return getCurrentMutableContext(); return getCurrentMutableContext();
@ -104,8 +118,8 @@ namespace Catch {
} }
INTERNAL_CATCH_INLINE void cleanUpContext() { INTERNAL_CATCH_INLINE void cleanUpContext() {
delete currentContext; delete DefaultContext::currentContext;
currentContext = NULL; DefaultContext::currentContext = NULL;
} }
} }

View File

@ -41,6 +41,23 @@ namespace Catch {
virtual std::string getCurrentTestName() const = 0; virtual std::string getCurrentTestName() const = 0;
virtual const AssertionResult* getLastResult() const = 0; virtual const AssertionResult* getLastResult() const = 0;
}; };
struct NullResultCapture : public IResultCapture {
virtual void assertionEnded( AssertionResult const& ) {}
virtual bool sectionStarted( SectionInfo const& ,
Counts& ) {return false;}
virtual void sectionEnded( SectionInfo const& , Counts const& , double ) {}
virtual void pushScopedMessage( MessageInfo const& ) {}
virtual void popScopedMessage( MessageInfo const& ) {}
virtual bool shouldDebugBreak() const {return false;}
virtual ResultAction::Value acceptExpression( ExpressionResultBuilder const& , AssertionInfo const& ) {return ResultAction::Abort;}
virtual std::string getCurrentTestName() const {return std::string();}
virtual const AssertionResult* getLastResult() const {return NULL;}
};
} }
#endif // TWOBLUECUBES_CATCH_INTERFACES_CAPTURE_H_INCLUDED #endif // TWOBLUECUBES_CATCH_INTERFACES_CAPTURE_H_INCLUDED

View File

@ -18,6 +18,10 @@ namespace Catch {
struct IRunner { struct IRunner {
virtual ~IRunner(); virtual ~IRunner();
}; };
struct NullRunner : public IRunner
{
};
} }
#endif // TWOBLUECUBES_CATCH_INTERFACES_RUNNER_H_INCLUDED #endif // TWOBLUECUBES_CATCH_INTERFACES_RUNNER_H_INCLUDED

View File

@ -48,7 +48,6 @@ namespace Catch {
}; };
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
class RunContext : public IResultCapture, public IRunner { class RunContext : public IResultCapture, public IRunner {
RunContext( RunContext const& ); RunContext( RunContext const& );
@ -105,18 +104,16 @@ namespace Catch {
} }
Totals runTest( TestCase const& testCase ) { Totals runTest( TestCase const& testCase ) {
Totals prevTotals = m_totals;
std::string redirectedCout; std::string redirectedCout;
std::string redirectedCerr; std::string redirectedCerr;
TestCaseInfo testInfo = testCase.getTestCaseInfo(); TestCaseInfo testInfo = testCase.getTestCaseInfo();
m_reporter->testCaseStarting( testInfo ); UnwindTestCaseOnCompletion finaliser(*this, m_totals, m_reporter, testInfo, redirectedCout, redirectedCerr);
m_activeTestCase = &testCase; m_activeTestCase = &testCase;
m_testCaseTracker = TestCaseTracker( testInfo.name ); m_testCaseTracker = TestCaseTracker( testInfo.name );
do { do {
do { do {
runCurrentTest( redirectedCout, redirectedCerr ); runCurrentTest( redirectedCout, redirectedCerr );
@ -125,18 +122,10 @@ namespace Catch {
} }
while( getCurrentContext().advanceGeneratorsForCurrentTest() && !aborting() ); while( getCurrentContext().advanceGeneratorsForCurrentTest() && !aborting() );
Totals deltaTotals = m_totals.delta( prevTotals );
m_totals.testCases += deltaTotals.testCases;
m_reporter->testCaseEnded( TestCaseStats( testInfo,
deltaTotals,
redirectedCout,
redirectedCerr,
aborting() ) );
m_activeTestCase = NULL; m_activeTestCase = NULL;
m_testCaseTracker.reset(); m_testCaseTracker.reset();
return deltaTotals; return finaliser.report();
} }
Ptr<IConfig const> config() const { Ptr<IConfig const> config() const {
@ -194,12 +183,7 @@ namespace Catch {
return true; return true;
} }
virtual void sectionEnded( SectionInfo const& info, Counts const& prevAssertions, double _durationInSeconds ) { void unwindSection(SectionInfo const& info, Counts const& prevAssertions, double _durationInSeconds ) {
if( std::uncaught_exception() ) {
m_unfinishedSections.push_back( UnfinishedSections( info, prevAssertions, _durationInSeconds ) );
return;
}
Counts assertions = m_totals.assertions - prevAssertions; Counts assertions = m_totals.assertions - prevAssertions;
bool missingAssertions = testForMissingAssertions( assertions ); bool missingAssertions = testForMissingAssertions( assertions );
@ -209,6 +193,15 @@ namespace Catch {
m_messages.clear(); m_messages.clear();
} }
virtual void sectionEnded( SectionInfo const& info, Counts const& prevAssertions, double _durationInSeconds ) {
if( std::uncaught_exception() ) {
m_unfinishedSections.push_back( UnfinishedSections( info, prevAssertions, _durationInSeconds ) );
return;
}
unwindSection(info, prevAssertions, _durationInSeconds);
}
virtual void pushScopedMessage( MessageInfo const& message ) { virtual void pushScopedMessage( MessageInfo const& message ) {
m_messages.push_back( message ); m_messages.push_back( message );
} }
@ -257,16 +250,13 @@ namespace Catch {
void runCurrentTest( std::string& redirectedCout, std::string& redirectedCerr ) { void runCurrentTest( std::string& redirectedCout, std::string& redirectedCerr ) {
TestCaseInfo const& testCaseInfo = m_activeTestCase->getTestCaseInfo(); TestCaseInfo const& testCaseInfo = m_activeTestCase->getTestCaseInfo();
SectionInfo testCaseSection( testCaseInfo.name, testCaseInfo.description, testCaseInfo.lineInfo );
m_reporter->sectionStarting( testCaseSection ); UnwindSectionOnCompletion finaliser(*this, m_totals, m_reporter, testCaseInfo, m_unfinishedSections, m_messages);
Counts prevAssertions = m_totals.assertions;
double duration = 0;
try { try {
m_lastAssertionInfo = AssertionInfo( "TEST_CASE", testCaseInfo.lineInfo, "", ResultDisposition::Normal ); m_lastAssertionInfo = AssertionInfo( "TEST_CASE", testCaseInfo.lineInfo, "", ResultDisposition::Normal );
TestCaseTracker::Guard guard( *m_testCaseTracker ); TestCaseTracker::Guard guard( *m_testCaseTracker );
Timer timer; finaliser.startTimer();
timer.start();
if( m_reporter->getPreferences().shouldRedirectStdOut ) { if( m_reporter->getPreferences().shouldRedirectStdOut ) {
StreamRedirect coutRedir( std::cout, redirectedCout ); StreamRedirect coutRedir( std::cout, redirectedCout );
StreamRedirect cerrRedir( std::cerr, redirectedCerr ); StreamRedirect cerrRedir( std::cerr, redirectedCerr );
@ -275,38 +265,16 @@ namespace Catch {
else { else {
m_activeTestCase->invoke(); m_activeTestCase->invoke();
} }
duration = timer.getElapsedSeconds(); finaliser.stopTimer();
} }
#ifdef INTERNAL_CATCH_VS_MANAGED // detect CLR catch( const Catch::TestFailureException& ) {
catch(AssertFailedException^) {
if( aborting() )
throw; // CLR always rethrows - stop on first assert
}
#else
catch( INTERNAL_CATCH_TEST_FAILURE_EXCEPTION ) {
// This just means the test was aborted due to failure // This just means the test was aborted due to failure
} }
#endif
catch(...) { catch(...) {
ExpressionResultBuilder exResult( ResultWas::ThrewException ); ExpressionResultBuilder exResult( ResultWas::ThrewException );
exResult << translateActiveException(); exResult << translateActiveException();
actOnCurrentResult( exResult.buildResult( m_lastAssertionInfo ) ); actOnCurrentResult( exResult.buildResult( m_lastAssertionInfo ) );
} }
// If sections ended prematurely due to an exception we stored their
// infos here so we can tear them down outside the unwind process.
for( std::vector<UnfinishedSections>::const_iterator it = m_unfinishedSections.begin(),
itEnd = m_unfinishedSections.end();
it != itEnd;
++it )
sectionEnded( it->info, it->prevAssertions, it->durationInSeconds );
m_unfinishedSections.clear();
m_messages.clear();
Counts assertions = m_totals.assertions - prevAssertions;
bool missingAssertions = testForMissingAssertions( assertions );
SectionStats testCaseSectionStats( testCaseSection, assertions, duration, missingAssertions );
m_reporter->sectionEnded( testCaseSectionStats );
} }
private: private:
@ -320,6 +288,111 @@ namespace Catch {
double durationInSeconds; double durationInSeconds;
}; };
class UnwindSectionOnCompletion
{
public:
UnwindSectionOnCompletion(RunContext& context, Totals& totals, Ptr<IStreamingReporter>& reporter, TestCaseInfo const& testCaseInfo,
std::vector<UnfinishedSections>& unfinishedSections, std::vector<MessageInfo>& messages)
: m_context(context)
, m_totals(totals)
, m_reporter(reporter)
, m_testCaseSection( testCaseInfo.name, testCaseInfo.description, testCaseInfo.lineInfo )
, m_unfinishedSections(unfinishedSections)
, m_messages(messages)
, m_duration(0.0)
{
m_prevAssertions = m_totals.assertions;
m_reporter->sectionStarting( m_testCaseSection );
}
~UnwindSectionOnCompletion()
{
// If sections ended prematurely due to an exception we stored their
// infos here so we can tear them down.
for( std::vector<UnfinishedSections>::const_iterator it = m_unfinishedSections.begin(),
itEnd = m_unfinishedSections.end();
it != itEnd;
++it ) {
m_context.unwindSection( it->info, it->prevAssertions, it->durationInSeconds );
}
m_unfinishedSections.clear();
m_messages.clear();
Counts assertions = m_totals.assertions - m_prevAssertions;
bool missingAssertions = m_context.testForMissingAssertions( assertions );
SectionStats testCaseSectionStats( m_testCaseSection, assertions, m_duration, missingAssertions );
m_reporter->sectionEnded( testCaseSectionStats );
}
void startTimer()
{
m_timer.start();
}
void stopTimer()
{
m_duration = m_timer.getElapsedSeconds();
}
private:
// non-copyable
UnwindSectionOnCompletion(const UnwindSectionOnCompletion&);
UnwindSectionOnCompletion& operator=(const UnwindSectionOnCompletion&);
RunContext& m_context;
Totals& m_totals;
Ptr<IStreamingReporter>& m_reporter;
SectionInfo m_testCaseSection;
std::vector<UnfinishedSections>& m_unfinishedSections;
std::vector<MessageInfo>& m_messages;
Timer m_timer;
Counts m_prevAssertions;
double m_duration;
};
class UnwindTestCaseOnCompletion
{
public:
UnwindTestCaseOnCompletion(RunContext& context, Totals& totals, Ptr<IStreamingReporter>& reporter, TestCaseInfo& testInfo,
std::string& redirectedCout, std::string& redirectedCerr)
: m_context(context), m_totals(totals), m_reporter(reporter), m_testInfo(testInfo)
, m_redirectedCout(redirectedCout), m_redirectedCerr(redirectedCerr)
, m_reported(false)
{
m_prevTotals = m_totals;
m_reporter->testCaseStarting( m_testInfo );
}
~UnwindTestCaseOnCompletion()
{
if( !m_reported )
{
report();
}
}
Totals report()
{
m_reported = true;
Totals deltaTotals = m_totals.delta( m_prevTotals );
m_totals.testCases += deltaTotals.testCases;
m_reporter->testCaseEnded( TestCaseStats( m_testInfo,
deltaTotals,
m_redirectedCout,
m_redirectedCerr,
m_context.aborting() ) );
return deltaTotals;
}
private:
// non-copyable
UnwindTestCaseOnCompletion(const UnwindTestCaseOnCompletion&);
UnwindTestCaseOnCompletion& operator=(const UnwindTestCaseOnCompletion&);
RunContext& m_context;
Totals& m_totals;
Ptr<IStreamingReporter>& m_reporter;
TestCaseInfo& m_testInfo;
std::string& m_redirectedCout;
std::string& m_redirectedCerr;
bool m_reported;
Totals m_prevTotals;
};
TestRunInfo m_runInfo; TestRunInfo m_runInfo;
IMutableContext& m_context; IMutableContext& m_context;
TestCase const* m_activeTestCase; TestCase const* m_activeTestCase;

View File

@ -24,15 +24,25 @@ namespace Catch {
namespace { namespace {
#ifdef CATCH_PLATFORM_WINDOWS #ifdef CATCH_PLATFORM_WINDOWS
template <typename T>
struct CounterDefaults
{
static T hz;
static T hzo;
};
template <typename T>
T CounterDefaults<T>::hz = 0;
template <typename T>
T CounterDefaults<T>::hzo = 0;
INTERNAL_CATCH_INLINE uint64_t getCurrentTicks() { INTERNAL_CATCH_INLINE uint64_t getCurrentTicks() {
static uint64_t hz=0, hzo=0; if (!CounterDefaults<uint64_t>::hz) {
if (!hz) { QueryPerformanceFrequency((LARGE_INTEGER*)&CounterDefaults<uint64_t>::hz);
QueryPerformanceFrequency((LARGE_INTEGER*)&hz); QueryPerformanceCounter((LARGE_INTEGER*)&CounterDefaults<uint64_t>::hzo);
QueryPerformanceCounter((LARGE_INTEGER*)&hzo);
} }
uint64_t t; uint64_t t;
QueryPerformanceCounter((LARGE_INTEGER*)&t); QueryPerformanceCounter((LARGE_INTEGER*)&t);
return ((t-hzo)*1000000)/hz; return ((t-CounterDefaults<uint64_t>::hzo)*1000000)/CounterDefaults<uint64_t>::hz;
} }
#else #else
INTERNAL_CATCH_INLINE uint64_t getCurrentTicks() { INTERNAL_CATCH_INLINE uint64_t getCurrentTicks() {

View File

@ -95,7 +95,11 @@ struct StringMaker<T*> {
if( !p ) if( !p )
return INTERNAL_CATCH_STRINGIFY( NULL ); return INTERNAL_CATCH_STRINGIFY( NULL );
std::ostringstream oss; std::ostringstream oss;
#ifdef _MSC_VER
oss << "0x" << p;
#else
oss << p; oss << p;
#endif
return oss.str(); return oss.str();
} }
}; };

View File

@ -18,7 +18,7 @@ using namespace System::Collections::Generic;
using namespace Microsoft::VisualStudio::TestTools::UnitTesting; using namespace Microsoft::VisualStudio::TestTools::UnitTesting;
namespace Catch { namespace Catch {
inline String^ convert_string_to_managed(const std::string& s) inline String^ convert_string_for_assert(const std::string& s)
{ {
String^ result = gcnew String(s.c_str()); String^ result = gcnew String(s.c_str());
return result; return result;
@ -26,71 +26,12 @@ namespace Catch {
} }
#include "internal/catch_timer.hpp"
#include "internal/catch_reporter_registrars.hpp" #include "internal/catch_reporter_registrars.hpp"
#include "reporters/catch_vs_reporter.hpp" #include "reporters/catch_vs_reporter.hpp"
#include "catch_registry_hub.hpp" #include "catch_registry_hub.hpp"
#include "internal/catch_timer.hpp"
//#define OLD (1) #include "internal/catch_console_colour_impl.hpp"
#ifdef OLD #include "catch_runner.hpp"
namespace Catch {
class ExceptionRegistryHub : public IRegistryHub, public IMutableRegistryHub {
ExceptionRegistryHub( ExceptionRegistryHub const& );
void operator=( ExceptionRegistryHub const& );
public: // IRegistryHub
ExceptionRegistryHub() {
}
virtual IReporterRegistry const& getReporterRegistry() const {
throw std::runtime_error("can't do this for Visual Studio tests!");
}
virtual ITestCaseRegistry const& getTestCaseRegistry() const {
throw std::runtime_error("can't do this for Visual Studio tests!");
}
virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() {
return m_exceptionTranslatorRegistry;
}
public: // IMutableRegistryHub
virtual void registerReporter( std::string const&, IReporterFactory* ) {
throw std::runtime_error("can't do this for Visual Studio tests!");
}
virtual void registerTest( TestCase const& ) {
throw std::runtime_error("can't do this for Visual Studio tests!");
}
virtual void registerTranslator( const IExceptionTranslator* translator ) {
m_exceptionTranslatorRegistry.registerTranslator( translator );
}
private:
ExceptionTranslatorRegistry m_exceptionTranslatorRegistry;
};
template <typename T>
struct GlobalRegistryHub
{
static T*& instance()
{
if( !theRegistryHub )
theRegistryHub = new T();
return theRegistryHub;
}
static T* theRegistryHub;
};
template <typename T>
T* GlobalRegistryHub<T>::theRegistryHub = NULL;
INTERNAL_CATCH_INLINE IMutableRegistryHub& getMutableRegistryHub() {
return *GlobalRegistryHub<ExceptionRegistryHub>::instance();
}
INTERNAL_CATCH_INLINE std::string translateActiveException() {
return GlobalRegistryHub<ExceptionRegistryHub>::instance()->getExceptionTranslatorRegistry().translateActiveException();
}
}
#endif // OLD
namespace Catch { namespace Catch {
inline NonCopyable::~NonCopyable() {} inline NonCopyable::~NonCopyable() {}
@ -113,16 +54,10 @@ namespace Catch {
inline TestCaseStats::~TestCaseStats() {} inline TestCaseStats::~TestCaseStats() {}
inline TestGroupStats::~TestGroupStats() {} inline TestGroupStats::~TestGroupStats() {}
inline TestRunStats::~TestRunStats() {} inline TestRunStats::~TestRunStats() {}
//CumulativeReporterBase::SectionNode::~SectionNode() {}
//CumulativeReporterBase::~CumulativeReporterBase() {}
//StreamingReporterBase::~StreamingReporterBase() {}
//ConsoleReporter::~ConsoleReporter() {}
inline IRunner::~IRunner() {} inline IRunner::~IRunner() {}
inline IMutableContext::~IMutableContext() {} inline IMutableContext::~IMutableContext() {}
inline IConfig::~IConfig() {} inline IConfig::~IConfig() {}
//XmlReporter::~XmlReporter() {}
//JunitReporter::~JunitReporter() {}
inline TestRegistry::~TestRegistry() {} inline TestRegistry::~TestRegistry() {}
inline FreeFunctionTestCase::~FreeFunctionTestCase() {} inline FreeFunctionTestCase::~FreeFunctionTestCase() {}
inline IGeneratorInfo::~IGeneratorInfo() {} inline IGeneratorInfo::~IGeneratorInfo() {}
@ -137,8 +72,6 @@ namespace Catch {
inline Matchers::Impl::StdString::EndsWith::~EndsWith() {} inline Matchers::Impl::StdString::EndsWith::~EndsWith() {}
inline void Config::dummy() {} inline void Config::dummy() {}
//INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( "xml", XmlReporter )
} }
#endif #endif

View File

@ -16,71 +16,55 @@ using Microsoft::VisualStudio::CppUnitTestFramework::Logger;
using Microsoft::VisualStudio::CppUnitTestFramework::Assert; using Microsoft::VisualStudio::CppUnitTestFramework::Assert;
using Microsoft::VisualStudio::CppUnitTestFramework::__LineInfo; using Microsoft::VisualStudio::CppUnitTestFramework::__LineInfo;
#define INTERNAL_CATCH_INLINE inline
#include <cvt/wstring> #include <cvt/wstring>
#include <codecvt> #include <codecvt>
#include "internal/catch_timer.hpp" #include "internal/catch_reporter_registrars.hpp"
#include "internal/catch_vs_test_registry.hpp"
#include "reporters/catch_vs_reporter.hpp" #include "reporters/catch_vs_reporter.hpp"
#include "catch_registry_hub.hpp"
#include "internal/catch_timer.hpp"
#include "internal/catch_console_colour_impl.hpp"
#include "catch_runner.hpp"
namespace Catch { namespace Catch {
inline NonCopyable::~NonCopyable() {}
inline IShared::~IShared() {}
inline StreamBufBase::~StreamBufBase() throw() {}
inline IContext::~IContext() {}
inline IResultCapture::~IResultCapture() {}
inline ITestCase::~ITestCase() {}
inline ITestCaseRegistry::~ITestCaseRegistry() {}
inline IRegistryHub::~IRegistryHub() {}
inline IMutableRegistryHub::~IMutableRegistryHub() {}
inline IExceptionTranslator::~IExceptionTranslator() {}
inline IExceptionTranslatorRegistry::~IExceptionTranslatorRegistry() {}
inline IReporter::~IReporter() {}
inline IReporterFactory::~IReporterFactory() {}
inline IReporterRegistry::~IReporterRegistry() {}
inline IStreamingReporter::~IStreamingReporter() {}
inline AssertionStats::~AssertionStats() {}
inline SectionStats::~SectionStats() {}
inline TestCaseStats::~TestCaseStats() {}
inline TestGroupStats::~TestGroupStats() {}
inline TestRunStats::~TestRunStats() {}
class ExceptionRegistryHub : public IRegistryHub, public IMutableRegistryHub { inline IRunner::~IRunner() {}
inline IMutableContext::~IMutableContext() {}
inline IConfig::~IConfig() {}
inline TestRegistry::~TestRegistry() {}
inline FreeFunctionTestCase::~FreeFunctionTestCase() {}
inline IGeneratorInfo::~IGeneratorInfo() {}
inline IGeneratorsForTest::~IGeneratorsForTest() {}
inline TagParser::~TagParser() {}
inline TagExtracter::~TagExtracter() {}
inline TagExpressionParser::~TagExpressionParser() {}
ExceptionRegistryHub( ExceptionRegistryHub const& ); inline Matchers::Impl::StdString::Equals::~Equals() {}
void operator=( ExceptionRegistryHub const& ); inline Matchers::Impl::StdString::Contains::~Contains() {}
inline Matchers::Impl::StdString::StartsWith::~StartsWith() {}
public: // IRegistryHub inline Matchers::Impl::StdString::EndsWith::~EndsWith() {}
ExceptionRegistryHub() {
}
virtual IReporterRegistry const& getReporterRegistry() const {
throw std::runtime_error("can't do this for Visual Studio tests!");
}
virtual ITestCaseRegistry const& getTestCaseRegistry() const {
throw std::runtime_error("can't do this for Visual Studio tests!");
}
virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() {
return m_exceptionTranslatorRegistry;
}
public: // IMutableRegistryHub
virtual void registerReporter( std::string const&, IReporterFactory* ) {
throw std::runtime_error("can't do this for Visual Studio tests!");
}
virtual void registerTest( TestCase const& ) {
throw std::runtime_error("can't do this for Visual Studio tests!");
}
virtual void registerTranslator( const IExceptionTranslator* translator ) {
m_exceptionTranslatorRegistry.registerTranslator( translator );
}
private:
ExceptionTranslatorRegistry m_exceptionTranslatorRegistry;
};
template <typename T>
struct GlobalRegistryHub
{
static T& instance()
{
if( !theRegistryHub )
theRegistryHub = new T();
return *theRegistryHub;
}
static T* theRegistryHub;
};
template <typename T>
T* GlobalRegistryHub<T>::theRegistryHub = NULL;
INTERNAL_CATCH_INLINE IMutableRegistryHub& getMutableRegistryHub() {
return GlobalRegistryHub<ExceptionRegistryHub>::instance();
}
INTERNAL_CATCH_INLINE std::string translateActiveException() {
return GlobalRegistryHub<ExceptionRegistryHub>::instance().getExceptionTranslatorRegistry().translateActiveException();
}
inline void Config::dummy() {}
} }
#endif // INTERNAL_CATCH_VS_NATIVE #endif // INTERNAL_CATCH_VS_NATIVE

View File

@ -63,7 +63,7 @@ private:
typedef void(*TestFunction)(); typedef void(*TestFunction)();
struct NameAndDesc { struct NameAndDesc {
#if (_MANAGED == 1) || (_M_CEE == 1) // detect CLR #ifdef INTERNAL_CATCH_VS_MANAGED
NameAndDesc( const char* _name = "", const char* _description= "" ) NameAndDesc( const char* _name = "", const char* _description= "" )
: name( _name ), description( _description ) : name( _name ), description( _description )
{} {}
@ -74,14 +74,35 @@ struct NameAndDesc {
NameAndDesc( const wchar_t* _name, const char* _description= "" ) NameAndDesc( const wchar_t* _name, const char* _description= "" )
: name(), description( _description ) : name(), description( _description )
{ {
stdext::cvt::wstring_convert<std::codecvt_utf8<wchar_t> > conv1; assignName(_name);
name = conv1.to_bytes(_name);
} }
NameAndDesc( const wchar_t* _name, int ) NameAndDesc( const wchar_t* _name, int )
: name(), description( "" ) : name(), description( "" )
{
assignName(_name);
}
void assignName(const wchar_t* _name)
{ {
stdext::cvt::wstring_convert<std::codecvt_utf8<wchar_t> > conv1; stdext::cvt::wstring_convert<std::codecvt_utf8<wchar_t> > conv1;
name = conv1.to_bytes(_name); std::string tmp = conv1.to_bytes(_name);
if( tmp.empty() )
{
name = tmp;
}
else
{
std::string::iterator startIter = tmp.begin();
if(*startIter == '\"')
{
++startIter;
}
std::string::reverse_iterator endIter = tmp.rbegin();
if(*endIter == '\"')
{
++endIter;
}
name.assign(startIter, endIter.base());
}
} }
#endif #endif
@ -120,7 +141,7 @@ private:
} // end namespace Catch } // end namespace Catch
#if (_MANAGED == 1) || (_M_CEE == 1) // detect CLR #ifdef INTERNAL_CATCH_VS_MANAGED
#define CATCH_INTERNAL_HANDLE_EMPTY_PARAM2( name ) name##"" #define CATCH_INTERNAL_HANDLE_EMPTY_PARAM2( name ) name##""
#define CATCH_INTERNAL_HANDLE_EMPTY_PARAM(...) CATCH_INTERNAL_HANDLE_EMPTY_PARAM2( INTERNAL_CATCH_SPLIT_ARGS_2(__VA_ARGS__) ) #define CATCH_INTERNAL_HANDLE_EMPTY_PARAM(...) CATCH_INTERNAL_HANDLE_EMPTY_PARAM2( INTERNAL_CATCH_SPLIT_ARGS_2(__VA_ARGS__) )
@ -147,7 +168,7 @@ private:
#define CATCH_INTERNAL_NAMESPACE( Ext ) #define CATCH_INTERNAL_NAMESPACE( Ext )
#define INTERNAL_CATCH_TEST_METHOD( Method, UniqueExt, Name, Desc ) \ #define INTERNAL_CATCH_TEST_METHOD( Count, UniqueExt, Name, Desc ) \
public: \ public: \
[TestMethod] \ [TestMethod] \
[Description( CATCH_INTERNAL_HANDLE_EMPTY_PARAM(Name) )] \ [Description( CATCH_INTERNAL_HANDLE_EMPTY_PARAM(Name) )] \
@ -155,22 +176,24 @@ private:
void INTERNAL_CATCH_UNIQUE_NAME_LINE( C_A_T_C_H___M_E_T_H_O_D___, UniqueExt) () \ void INTERNAL_CATCH_UNIQUE_NAME_LINE( C_A_T_C_H___M_E_T_H_O_D___, UniqueExt) () \
{ \ { \
Catch::NameAndDesc name_desc( CATCH_INTERNAL_HANDLE_EMPTY_PARAM(Name), Desc ); \ Catch::NameAndDesc name_desc( CATCH_INTERNAL_HANDLE_EMPTY_PARAM(Name), Desc ); \
CATCH_INTERNAL_RUN_SINGLE_TEST( Method ); \ CATCH_INTERNAL_RUN_SINGLE_TEST(Count); \
} }
#define INTERNAL_CATCH_TEST_CLASS_METHOD( Method, UniqueExt, Name, Desc ) \ #define BEGIN_INTERNAL_CATCH_BATCH_METHOD( Tags, UniqueExt ) \
public: \ public: \
[TestMethod] \ [TestMethod] \
[Description( CATCH_INTERNAL_HANDLE_EMPTY_PARAM(Name) )] \ [TestCategory( CATCH_INTERNAL_HANDLE_EMPTY_PARAM(Tags) )] \
[TestProperty( "Description", CATCH_INTERNAL_HANDLE_EMPTY_PARAM(Name) )] \ [Description( CATCH_INTERNAL_HANDLE_EMPTY_PARAM(Tags) )] \
void INTERNAL_CATCH_UNIQUE_NAME_LINE( C_A_T_C_H___M_E_T_H_O_D___, UniqueExt) () \ [TestProperty( "Description", CATCH_INTERNAL_HANDLE_EMPTY_PARAM(Tags) )] \
{ \ void INTERNAL_CATCH_UNIQUE_NAME_LINE( C_A_T_C_H___M_E_T_H_O_D___, UniqueExt) ()
Catch::NameAndDesc name_desc( CATCH_INTERNAL_HANDLE_EMPTY_PARAM(Name), Desc ); \
CATCH_INTERNAL_RUN_SINGLE_CLASS_TEST( Method ); \
}
#define CHECK_FOR_TEST_CASE_CLASH #define CHECK_FOR_TEST_CASE_CLASH
#define INTERNAL_CATCH_MAP_CATEGORY_TO_TAG( Category, Tag ) \
INTERNAL_CATCH_MAP_CATEGORY_TO_TAG2( #Category, Tag, __COUNTER__ )
#define FAIL_STRING( str ) _T( str )
#else // detect CLR #else // detect CLR
// Native tests // Native tests
@ -186,108 +209,161 @@ private:
#define TEST_IMPL_2(tuple) TEST_IMPL2 tuple #define TEST_IMPL_2(tuple) TEST_IMPL2 tuple
#define TEST_IMPL2( INTERNAL_CATCH_SPLIT_ARG_1,INTERNAL_CATCH_SPLIT_ARG_2,N,...) L#INTERNAL_CATCH_SPLIT_ARG_1 #define TEST_IMPL2( INTERNAL_CATCH_SPLIT_ARG_1,INTERNAL_CATCH_SPLIT_ARG_2,N,...) L#INTERNAL_CATCH_SPLIT_ARG_1
#define CATCH_INTERNAL_HANDLE_EMPTY_PARAM(...) CATCH_INTERNAL_HANDLE_EMPTY_PARAM_IMPL( (__VA_ARGS__, 2, 1) ) #define CATCH_INTERNAL_HANDLE_EMPTY_PARAM(...) CATCH_INTERNAL_HANDLE_EMPTY_PARAM_IMPLW( (__VA_ARGS__, 2, 1) )
#define CATCH_INTERNAL_HANDLE_EMPTY_PARAM_IMPL(tuple) CATCH_INTERNAL_HANDLE_EMPTY_PARAM_IMPL2 tuple
#define CATCH_INTERNAL_HANDLE_EMPTY_PARAM_IMPL2( INTERNAL_CATCH_SPLIT_ARG_1,INTERNAL_CATCH_SPLIT_ARG_2,N,...) #INTERNAL_CATCH_SPLIT_ARG_1
#define CATCH_INTERNAL_HANDLE_EMPTY_PARAMW(...) CATCH_INTERNAL_HANDLE_EMPTY_PARAM_IMPLW( (__VA_ARGS__, 2, 1) )
#define CATCH_INTERNAL_HANDLE_EMPTY_PARAM_IMPLW(tuple) CATCH_INTERNAL_HANDLE_EMPTY_PARAM_IMPL2W tuple #define CATCH_INTERNAL_HANDLE_EMPTY_PARAM_IMPLW(tuple) CATCH_INTERNAL_HANDLE_EMPTY_PARAM_IMPL2W tuple
#define CATCH_INTERNAL_HANDLE_EMPTY_PARAM_IMPL2W( INTERNAL_CATCH_SPLIT_ARG_1,INTERNAL_CATCH_SPLIT_ARG_2,N,...) L#INTERNAL_CATCH_SPLIT_ARG_1 #define CATCH_INTERNAL_HANDLE_EMPTY_PARAM_IMPL2W( INTERNAL_CATCH_SPLIT_ARG_1,INTERNAL_CATCH_SPLIT_ARG_2,N,...) L#INTERNAL_CATCH_SPLIT_ARG_1
#define INTERNAL_CATCH_TEST_METHOD( Method, UniqueExt, Name, Desc ) \ #define INTERNAL_CATCH_TEST_METHOD( Count, UniqueExt, Name, Desc ) \
public: \ public: \
BEGIN_TEST_METHOD_ATTRIBUTE( INTERNAL_CATCH_UNIQUE_NAME_LINE( C_A_T_C_H___M_E_T_H_O_D___, UniqueExt) ) \ BEGIN_TEST_METHOD_ATTRIBUTE( INTERNAL_CATCH_UNIQUE_NAME_LINE( C_A_T_C_H___M_E_T_H_O_D___, UniqueExt) ) \
TEST_OWNER( CATCH_INTERNAL_HANDLE_EMPTY_PARAMW(Name) ) \ TEST_OWNER( CATCH_INTERNAL_HANDLE_EMPTY_PARAM(Name) ) \
TEST_DESCRIPTION( CATCH_INTERNAL_HANDLE_EMPTY_PARAMW(Name) ) \ TEST_DESCRIPTION( CATCH_INTERNAL_HANDLE_EMPTY_PARAM(Name) ) \
END_TEST_METHOD_ATTRIBUTE() \ END_TEST_METHOD_ATTRIBUTE() \
TEST_METHOD( INTERNAL_CATCH_UNIQUE_NAME_LINE( C_A_T_C_H___M_E_T_H_O_D___, UniqueExt) ) \ TEST_METHOD( INTERNAL_CATCH_UNIQUE_NAME_LINE( C_A_T_C_H___M_E_T_H_O_D___, UniqueExt) ) \
{ \ { \
Catch::NameAndDesc name_desc(CATCH_INTERNAL_HANDLE_EMPTY_PARAMW(Name), Desc ); \ Catch::NameAndDesc name_desc(CATCH_INTERNAL_HANDLE_EMPTY_PARAM(Name), Desc ); \
CATCH_INTERNAL_RUN_SINGLE_TEST( Method ); \ CATCH_INTERNAL_RUN_SINGLE_TEST(Count); \
} }
#define INTERNAL_CATCH_TEST_CLASS_METHOD( Method, UniqueExt, Name, Desc ) \ #define BEGIN_INTERNAL_CATCH_BATCH_METHOD( Tags, UniqueExt ) \
public: \ public: \
BEGIN_TEST_METHOD_ATTRIBUTE( INTERNAL_CATCH_UNIQUE_NAME_LINE( C_A_T_C_H___M_E_T_H_O_D___, UniqueExt) ) \ BEGIN_TEST_METHOD_ATTRIBUTE( INTERNAL_CATCH_UNIQUE_NAME_LINE( C_A_T_C_H___M_E_T_H_O_D___, UniqueExt) ) \
TEST_OWNER( CATCH_INTERNAL_HANDLE_EMPTY_PARAMW(Name) ) \ TEST_OWNER( CATCH_INTERNAL_HANDLE_EMPTY_PARAM(Tags) ) \
TEST_DESCRIPTION( CATCH_INTERNAL_HANDLE_EMPTY_PARAMW(Name) ) \ TEST_DESCRIPTION( CATCH_INTERNAL_HANDLE_EMPTY_PARAM(Tags) ) \
END_TEST_METHOD_ATTRIBUTE() \ END_TEST_METHOD_ATTRIBUTE() \
TEST_METHOD( INTERNAL_CATCH_UNIQUE_NAME_LINE( C_A_T_C_H___M_E_T_H_O_D___, UniqueExt) ) \ TEST_METHOD( INTERNAL_CATCH_UNIQUE_NAME_LINE( C_A_T_C_H___M_E_T_H_O_D___, UniqueExt) )
{ \
Catch::NameAndDesc name_desc( CATCH_INTERNAL_HANDLE_EMPTY_PARAMW(Name), Desc ); \
CATCH_INTERNAL_RUN_SINGLE_CLASS_TEST( Method ); \
}
#define CHECK_FOR_TEST_CASE_CLASH void INTERNAL_CATCH_UNIQUE_NAME_LINE( if_you_get_this_error_you_have_a_test_case_name_clash_please_put_a_namespace_around_the_test_case_at_line_, __LINE__ )() {} #define CHECK_FOR_TEST_CASE_CLASH void INTERNAL_CATCH_UNIQUE_NAME_LINE( if_you_get_this_error_you_have_a_test_case_name_clash_please_put_a_namespace_around_the_test_case_at_line_, __LINE__ )() {}
#define INTERNAL_CATCH_MAP_CATEGORY_TO_TAG( Category, Tag ) \
INTERNAL_CATCH_MAP_CATEGORY_TO_TAG2( Category, Tag, __COUNTER__ )
#define FAIL_STRING( str ) WIDEN( str )
#endif // detect CLR #endif // detect CLR
#define INTERNAL_CATCH_CONCAT_LINE_COUNTER INTERNAL_CATCH_UNIQUE_NAME_LINE( INTERNAL_CATCH_UNIQUE_NAME_LINE( __LINE__, _ ), __COUNTER__ ) #define INTERNAL_CATCH_CONCAT_LINE_COUNTER( count ) INTERNAL_CATCH_UNIQUE_NAME_LINE( INTERNAL_CATCH_UNIQUE_NAME_LINE( __LINE__, _ ), count )
#define CATCH_INTERNAL_RUN_SINGLE_TEST( Method ) \ #define CATCH_INTERNAL_CONFIG_SHOW_SUCCESS2( v, Count ) \
{ Catch::ConfigData cd; \ namespace { CatchOverrides::ConfigShowSuccessfulTests<Catch::IConfig const*> INTERNAL_CATCH_UNIQUE_NAME_LINE( C_A_T_C_H_____O_V_E_R_R_I_D_E____, INTERNAL_CATCH_CONCAT_LINE_COUNTER( Count ) )(__FILE__, Count, v); }
#define CATCH_INTERNAL_CONFIG_WARN_MISSING_ASSERTIONS2( v, Count ) \
namespace { CatchOverrides::ConfigWarnMissingAssertions<Catch::IConfig const*> INTERNAL_CATCH_UNIQUE_NAME_LINE( C_A_T_C_H_____O_V_E_R_R_I_D_E____, INTERNAL_CATCH_CONCAT_LINE_COUNTER( Count ) )(__FILE__, Count, v); }
#define CATCH_INTERNAL_CONFIG_SHOW_SUCCESS( v ) \
CATCH_INTERNAL_CONFIG_SHOW_SUCCESS2( v, __COUNTER__)
#define CATCH_INTERNAL_CONFIG_WARN_MISSING_ASSERTIONS( v ) \
CATCH_INTERNAL_CONFIG_WARN_MISSING_ASSERTIONS2( v, __COUNTER__)
#define CATCH_INTERNAL_RUN_SINGLE_TEST( Count ) \
{ CatchOverrides::ConfigGuard cg; \
Catch::ConfigData cd(cg.value().get()); \
cd.name = name_desc.name; \ cd.name = name_desc.name; \
cd.abortAfter = 1; \ cd.abortAfter = 1; \
cd.showSuccessfulTests = CatchOverrides::Config<Catch::IConfig const*>::instance().includeSuccessfulResults(__FILE__, Count ); \
cd.warnings = (CatchOverrides::Config<Catch::IConfig const*>::instance().warnAboutMissingAssertions(__FILE__, Count ) ? Catch::WarnAbout::NoAssertions : Catch::WarnAbout::Nothing); \
Catch::Ptr<Catch::Config> config(new Catch::Config(cd)); \ Catch::Ptr<Catch::Config> config(new Catch::Config(cd)); \
Catch::MSTestReporter* rep = new Catch::MSTestReporter(config.get()); \ Catch::MSTestReporter* rep = new Catch::MSTestReporter(config.get()); \
Catch::RunContext tr(config.get(), rep); \ Catch::RunContext tr(config.get(), rep); \
std::vector<Catch::TestCase> testCase = Catch::getRegistryHub().getTestCaseRegistry().getMatchingTestCases(name_desc.name); \ std::vector<Catch::TestCase> testCase = Catch::getRegistryHub().getTestCaseRegistry().getMatchingTestCases(name_desc.name); \
if( testCase.empty() ) Assert::Fail("No tests match"); \ if( testCase.empty() ) Assert::Fail(FAIL_STRING("No tests match")); \
if( testCase.size() > 1 ) Assert::Fail("More than one test with the same name"); \ if( testCase.size() > 1 ) Assert::Fail(FAIL_STRING("More than one test with the same name")); \
tr.runTest(*testCase.begin()); \ Catch::Totals totals = tr.runTest(*testCase.begin()); \
if( totals.assertions.failed > 0 ) { \
INTERNAL_CATCH_TEST_THROW_FAILURE \
} \
} }
#define CATCH_INTERNAL_RUN_SINGLE_CLASS_TEST( ClassMethod ) \ #define INTERNAL_CATCH_TESTCASE2( Count, Name, Desc ) \
{ Catch::ConfigData cd; \
cd.name = name_desc.name; \
cd.abortAfter = 1; \
Catch::Ptr<Catch::Config> config(new Catch::Config(cd)); \
Catch::MSTestReporter* rep = new Catch::MSTestReporter(config.get()); \
Catch::RunContext tr(config.get(), rep); \
std::vector<Catch::TestCase> testCase = Catch::getRegistryHub().getTestCaseRegistry().getMatchingTestCases(name_desc.name); \
if( testCase.empty() ) Assert::Fail("No tests match"); \
if( testCase.size() > 1 ) Assert::Fail("More than one test with the same name"); \
tr.runTest(*testCase.begin()); \
}
#define INTERNAL_CATCH_TESTCASE2( UniqueExt, Name, Desc ) \
CHECK_FOR_TEST_CASE_CLASH \ CHECK_FOR_TEST_CASE_CLASH \
static void INTERNAL_CATCH_UNIQUE_NAME_LINE( C_A_T_C_H____T_E_S_T____, UniqueExt )(); \ static void INTERNAL_CATCH_UNIQUE_NAME_LINE( C_A_T_C_H____T_E_S_T____, INTERNAL_CATCH_CONCAT_LINE_COUNTER( Count ) )(); \
namespace CATCH_INTERNAL_NAMESPACE( UniqueExt ) { \ namespace CATCH_INTERNAL_NAMESPACE( INTERNAL_CATCH_CONCAT_LINE_COUNTER( Count ) ) { \
Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( & INTERNAL_CATCH_UNIQUE_NAME_LINE( C_A_T_C_H____T_E_S_T____, UniqueExt ), CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc(Name, Desc) ); \ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( & INTERNAL_CATCH_UNIQUE_NAME_LINE( C_A_T_C_H____T_E_S_T____, INTERNAL_CATCH_CONCAT_LINE_COUNTER( Count ) ), CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc(CATCH_INTERNAL_HANDLE_EMPTY_PARAM(Name), Desc) ); \
INTERNAL_CATCH_CLASS_DEFINITION( INTERNAL_CATCH_UNIQUE_NAME_LINE( C_A_T_C_H____T_E_S_T____C_L_A_S_S___, UniqueExt ) ) \ CatchOverrides::ConfigReset<Catch::IConfig const*> INTERNAL_CATCH_UNIQUE_NAME_LINE( C_A_T_C_H____T_E_S_T____C_O_N_F_I_G___, INTERNAL_CATCH_CONCAT_LINE_COUNTER( Count ) )(__FILE__, Count); \
INTERNAL_CATCH_CLASS_DEFINITION( INTERNAL_CATCH_UNIQUE_NAME_LINE( C_A_T_C_H____T_E_S_T____C_L_A_S_S___, INTERNAL_CATCH_CONCAT_LINE_COUNTER( Count ) ) ) \
{ \ { \
INTERNAL_CATCH_CLASS_CONTEXT \ INTERNAL_CATCH_CLASS_CONTEXT \
INTERNAL_CATCH_TEST_METHOD( INTERNAL_CATCH_UNIQUE_NAME_LINE( C_A_T_C_H____T_E_S_T____, UniqueExt ), UniqueExt, Name, Desc ) \ INTERNAL_CATCH_TEST_METHOD( Count, INTERNAL_CATCH_CONCAT_LINE_COUNTER( Count ), Name, Desc ) \
}; \ }; \
} \ } \
void INTERNAL_CATCH_UNIQUE_NAME_LINE( C_A_T_C_H____T_E_S_T____, UniqueExt )() void INTERNAL_CATCH_UNIQUE_NAME_LINE( C_A_T_C_H____T_E_S_T____, INTERNAL_CATCH_CONCAT_LINE_COUNTER( Count ) )()
#define INTERNAL_CATCH_METHOD_AS_TEST_CASE2( QualifiedMethod, UniqueExt, Name, Desc ) \ #define INTERNAL_CATCH_METHOD_AS_TEST_CASE2( QualifiedMethod, Count, Name, Desc ) \
CHECK_FOR_TEST_CASE_CLASH \ CHECK_FOR_TEST_CASE_CLASH \
namespace CATCH_INTERNAL_NAMESPACE( UniqueExt ) { \ namespace CATCH_INTERNAL_NAMESPACE( INTERNAL_CATCH_CONCAT_LINE_COUNTER( Count ) ) { \
Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( & QualifiedMethod, "&" # QualifiedMethod, Catch::NameAndDesc(Name, Desc), CATCH_INTERNAL_LINEINFO ); \ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( & QualifiedMethod, "&" # QualifiedMethod, Catch::NameAndDesc(CATCH_INTERNAL_HANDLE_EMPTY_PARAM(Name), Desc), CATCH_INTERNAL_LINEINFO ); \
INTERNAL_CATCH_CLASS_DEFINITION( INTERNAL_CATCH_UNIQUE_NAME_LINE( C_A_T_C_H____T_E_S_T____C_L_A_S_S___, UniqueExt ) ) \ CatchOverrides::ConfigReset<Catch::IConfig const*> INTERNAL_CATCH_UNIQUE_NAME_LINE( C_A_T_C_H____T_E_S_T____C_O_N_F_I_G___, INTERNAL_CATCH_CONCAT_LINE_COUNTER( Count ) )(__FILE__, Count); \
INTERNAL_CATCH_CLASS_DEFINITION( INTERNAL_CATCH_UNIQUE_NAME_LINE( C_A_T_C_H____T_E_S_T____C_L_A_S_S___, INTERNAL_CATCH_CONCAT_LINE_COUNTER( Count ) ) ) \
{ \ { \
INTERNAL_CATCH_CLASS_CONTEXT \ INTERNAL_CATCH_CLASS_CONTEXT \
INTERNAL_CATCH_TEST_CLASS_METHOD( QualifiedMethod, UniqueExt, Name, Desc ) \ INTERNAL_CATCH_TEST_METHOD( Count, INTERNAL_CATCH_CONCAT_LINE_COUNTER( Count ), Name, Desc ) \
}; \ }; \
}; };
#define INTERNAL_CATCH_TEST_CASE_METHOD2( ClassName, UniqueExt, TestName, Desc ) \ #define INTERNAL_CATCH_TEST_CASE_METHOD2( ClassName, Count, TestName, Desc ) \
CHECK_FOR_TEST_CASE_CLASH \ CHECK_FOR_TEST_CASE_CLASH \
struct INTERNAL_CATCH_UNIQUE_NAME_LINE( C_A_T_C_H____T_E_S_T____, UniqueExt ) : ClassName { \ struct INTERNAL_CATCH_UNIQUE_NAME_LINE( C_A_T_C_H____T_E_S_T____, INTERNAL_CATCH_CONCAT_LINE_COUNTER( Count ) ) : ClassName { \
void test(); \ void test(); \
static void invoke() { INTERNAL_CATCH_UNIQUE_NAME_LINE( C_A_T_C_H____T_E_S_T____, UniqueExt ) tmp; tmp.test(); } \ static void invoke() { INTERNAL_CATCH_UNIQUE_NAME_LINE( C_A_T_C_H____T_E_S_T____, INTERNAL_CATCH_CONCAT_LINE_COUNTER( Count ) ) tmp; tmp.test(); } \
}; \ }; \
namespace CATCH_INTERNAL_NAMESPACE( UniqueExt ) { \ namespace CATCH_INTERNAL_NAMESPACE( INTERNAL_CATCH_CONCAT_LINE_COUNTER( Count ) ) { \
Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( & INTERNAL_CATCH_UNIQUE_NAME_LINE( C_A_T_C_H____T_E_S_T____, UniqueExt )::invoke, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc(TestName, Desc) ); \ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( & INTERNAL_CATCH_UNIQUE_NAME_LINE( C_A_T_C_H____T_E_S_T____, INTERNAL_CATCH_CONCAT_LINE_COUNTER( Count ) )::invoke, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc(CATCH_INTERNAL_HANDLE_EMPTY_PARAM(TestName), Desc) ); \
INTERNAL_CATCH_CLASS_DEFINITION( INTERNAL_CATCH_UNIQUE_NAME_LINE( C_A_T_C_H____T_E_S_T____C_L_A_S_S___, UniqueExt ) ) \ CatchOverrides::ConfigReset<Catch::IConfig const*> INTERNAL_CATCH_UNIQUE_NAME_LINE( C_A_T_C_H____T_E_S_T____C_O_N_F_I_G___, INTERNAL_CATCH_CONCAT_LINE_COUNTER( Count ) )(__FILE__, Count); \
INTERNAL_CATCH_CLASS_DEFINITION( INTERNAL_CATCH_UNIQUE_NAME_LINE( C_A_T_C_H____T_E_S_T____C_L_A_S_S___, INTERNAL_CATCH_CONCAT_LINE_COUNTER( Count ) ) ) \
{ \ { \
INTERNAL_CATCH_CLASS_CONTEXT \ INTERNAL_CATCH_CLASS_CONTEXT \
INTERNAL_CATCH_TEST_METHOD( INTERNAL_CATCH_UNIQUE_NAME_LINE( C_A_T_C_H____T_E_S_T____, UniqueExt )::invoke, UniqueExt, TestName, Desc ) \ INTERNAL_CATCH_TEST_METHOD( Count, INTERNAL_CATCH_CONCAT_LINE_COUNTER( Count ), TestName, Desc ) \
}; \ }; \
} \ } \
void INTERNAL_CATCH_UNIQUE_NAME_LINE( C_A_T_C_H____T_E_S_T____, UniqueExt )::test() void INTERNAL_CATCH_UNIQUE_NAME_LINE( C_A_T_C_H____T_E_S_T____, INTERNAL_CATCH_CONCAT_LINE_COUNTER( Count ) )::test()
#if defined(INTERNAL_CATCH_VS_MANAGED)
#define INTERNAL_CATCH_TEST_REPORT_BATCH_FAILURE( count ) \
{ \
std::stringstream _sf; \
_sf << count << " assertions failed - check output for results."; \
std::string fail = _sf.str(); \
Assert::Fail(Catch::convert_string_for_assert(fail)); \
}
#else
#define INTERNAL_CATCH_TEST_REPORT_BATCH_FAILURE( count ) \
{ \
std::wstringstream _s; \
_s << count << " assertions failed - check output for results."; \
std::wstring ws = _s.str(); \
Assert::Fail(ws.c_str()); \
}
#endif
#define INTERNAL_CATCH_MAP_CATEGORY_TO_TAG2( Category, Tag, Count ) \
CHECK_FOR_TEST_CASE_CLASH \
namespace CATCH_INTERNAL_NAMESPACE( INTERNAL_CATCH_CONCAT_LINE_COUNTER( Count ) ) { \
CatchOverrides::ConfigReset<Catch::IConfig const*> INTERNAL_CATCH_UNIQUE_NAME_LINE( C_A_T_C_H____T_E_S_T____C_O_N_F_I_G___, INTERNAL_CATCH_CONCAT_LINE_COUNTER( Count ) )(__FILE__, Count); \
INTERNAL_CATCH_CLASS_DEFINITION( INTERNAL_CATCH_UNIQUE_NAME_LINE( C_A_T_C_H____T_E_S_T____C_L_A_S_S___, INTERNAL_CATCH_CONCAT_LINE_COUNTER( Count ) ) ) \
{ \
INTERNAL_CATCH_CLASS_CONTEXT \
BEGIN_INTERNAL_CATCH_BATCH_METHOD( Category, INTERNAL_CATCH_CONCAT_LINE_COUNTER( Count ) ) \
{ \
Catch::ConfigData cd; \
cd.showSuccessfulTests = CatchOverrides::Config<Catch::IConfig const*>::instance().includeSuccessfulResults(__FILE__, Count ); \
cd.warnings = (CatchOverrides::Config<Catch::IConfig const*>::instance().warnAboutMissingAssertions(__FILE__, Count ) ? Catch::WarnAbout::NoAssertions : Catch::WarnAbout::Nothing); \
cd.reporterName = "vs_reporter"; \
cd.name = "Batch run using tag : " Tag; \
cd.testsOrTags.push_back( Tag ); \
Catch::Ptr<Catch::Config> config(new Catch::Config(cd)); \
Catch::ReporterRegistrar<Catch::MSTestReporter> reporterReg("vs_reporter"); \
Catch::Runner runner(config); \
Catch::Totals totals = runner.runTests(); \
if( totals.assertions.failed > 0 ) { \
INTERNAL_CATCH_TEST_REPORT_BATCH_FAILURE(totals.assertions.failed) \
} \
} \
}; \
}
//#undef CATCH_CONFIG_VARIADIC_MACROS //#undef CATCH_CONFIG_VARIADIC_MACROS
@ -301,29 +377,29 @@ private:
#define INTERNAL_CATCH_SPLIT_TAGS_IMPL_(INTERNAL_CATCH_SPLIT_ARG_1,INTERNAL_CATCH_SPLIT_ARG_2,N,...) INTERNAL_CATCH_SPLIT_ARG_2 #define INTERNAL_CATCH_SPLIT_TAGS_IMPL_(INTERNAL_CATCH_SPLIT_ARG_1,INTERNAL_CATCH_SPLIT_ARG_2,N,...) INTERNAL_CATCH_SPLIT_ARG_2
#define INTERNAL_CATCH_TESTCASE( ... ) \ #define INTERNAL_CATCH_TESTCASE( ... ) \
INTERNAL_CATCH_TESTCASE2( INTERNAL_CATCH_CONCAT_LINE_COUNTER, INTERNAL_CATCH_SPLIT_ARGS_2(__VA_ARGS__), INTERNAL_CATCH_SPLIT_TAGS(__VA_ARGS__) ) INTERNAL_CATCH_TESTCASE2( __COUNTER__ , INTERNAL_CATCH_SPLIT_ARGS_2(__VA_ARGS__), INTERNAL_CATCH_SPLIT_TAGS(__VA_ARGS__) )
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, ... ) \ #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, ... ) \
INTERNAL_CATCH_METHOD_AS_TEST_CASE2( QualifiedMethod, INTERNAL_CATCH_CONCAT_LINE_COUNTER, INTERNAL_CATCH_SPLIT_ARGS_2(__VA_ARGS__), INTERNAL_CATCH_SPLIT_TAGS(__VA_ARGS__) ) INTERNAL_CATCH_METHOD_AS_TEST_CASE2( QualifiedMethod, __COUNTER__, INTERNAL_CATCH_SPLIT_ARGS_2(__VA_ARGS__), INTERNAL_CATCH_SPLIT_TAGS(__VA_ARGS__) )
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, ... )\ #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, ... )\
INTERNAL_CATCH_TEST_CASE_METHOD2(ClassName, INTERNAL_CATCH_CONCAT_LINE_COUNTER, INTERNAL_CATCH_SPLIT_ARGS_2(__VA_ARGS__), INTERNAL_CATCH_SPLIT_TAGS(__VA_ARGS__) ) INTERNAL_CATCH_TEST_CASE_METHOD2(ClassName, __COUNTER__, INTERNAL_CATCH_SPLIT_ARGS_2(__VA_ARGS__), INTERNAL_CATCH_SPLIT_TAGS(__VA_ARGS__) )
#else #else
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_TESTCASE( Name, Desc ) \ #define INTERNAL_CATCH_TESTCASE( Name, Desc ) \
INTERNAL_CATCH_TESTCASE2( INTERNAL_CATCH_CONCAT_LINE_COUNTER, Name, Desc ) INTERNAL_CATCH_TESTCASE2( __COUNTER__ , Name, Desc )
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, Name, Desc ) \ #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, Name, Desc ) \
INTERNAL_CATCH_METHOD_AS_TEST_CASE2( QualifiedMethod, INTERNAL_CATCH_CONCAT_LINE_COUNTER, Name, Desc ) INTERNAL_CATCH_METHOD_AS_TEST_CASE2( QualifiedMethod, __COUNTER__, Name, Desc )
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, TestName, Desc )\ #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, TestName, Desc )\
INTERNAL_CATCH_TEST_CASE_METHOD2(ClassName, INTERNAL_CATCH_CONCAT_LINE_COUNTER, TestName, Desc ) INTERNAL_CATCH_TEST_CASE_METHOD2(ClassName, __COUNTER__, TestName, Desc )
#endif #endif

View File

@ -49,18 +49,24 @@ namespace Catch {
MSTestReporter( ReporterConfig const& _config ) MSTestReporter( ReporterConfig const& _config )
: m_config( _config.fullConfig() ), : m_config( _config.fullConfig() ),
m_headerPrinted( false ), m_headerPrinted( false ),
m_atLeastOneTestCasePrinted( false ) m_atLeastOneTestCasePrinted( false ),
m_failed(0)
{} {}
MSTestReporter( Ptr<IConfig> const& _fullConfig ) MSTestReporter( Ptr<IConfig> const& _fullConfig )
: m_config( _fullConfig ), : m_config( _fullConfig ),
m_headerPrinted( false ), m_headerPrinted( false ),
m_atLeastOneTestCasePrinted( false ) m_atLeastOneTestCasePrinted( false ),
m_failed(0)
{} {}
virtual ~MSTestReporter() { virtual ~MSTestReporter() {
if( m_atLeastOneTestCasePrinted ) { if( m_atLeastOneTestCasePrinted ) {
write_output_message(stream.str()); write_output_message(stream.str());
/*if( m_failed )
{
Assert::IsTrue(false, L"At least one test failed - examine output for failures.");
}*/
} }
} }
@ -126,9 +132,6 @@ namespace Catch {
write_output_message(_testCaseStats.stdErr); write_output_message(_testCaseStats.stdErr);
write_output_message(getDoubleDashes()); write_output_message(getDoubleDashes());
} }
if( _testCaseStats.totals.assertions.failed ) {
Assert::IsTrue(false, L"At least one test failed - examine output for CHECK failures.");
}
m_headerPrinted = false; m_headerPrinted = false;
currentTestCaseInfo.reset(); currentTestCaseInfo.reset();
assert( m_sectionStack.empty() ); assert( m_sectionStack.empty() );
@ -147,6 +150,7 @@ namespace Catch {
printTotalsDivider(); printTotalsDivider();
printTotals( _testRunStats.totals ); printTotals( _testRunStats.totals );
stream << "\r\n" << "\r\n"; stream << "\r\n" << "\r\n";
m_failed = _testRunStats.totals.testCases.failed;
currentTestCaseInfo.reset(); currentTestCaseInfo.reset();
currentGroupInfo.reset(); currentGroupInfo.reset();
currentTestRunInfo.reset(); currentTestRunInfo.reset();
@ -454,6 +458,7 @@ namespace Catch {
std::vector<SectionInfo> m_sectionStack; std::vector<SectionInfo> m_sectionStack;
bool m_headerPrinted; bool m_headerPrinted;
bool m_atLeastOneTestCasePrinted; bool m_atLeastOneTestCasePrinted;
size_t m_failed;
}; };
} // end namespace Catch } // end namespace Catch

View File

@ -0,0 +1,187 @@
/*
* Created by Phil on 22/10/2010.
* Copyright 2010 Two Blue Cubes Ltd
*
* 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)
*/
#include "catch.hpp"
#include "internal/catch_text.h"
#include "internal/catch_console_colour.hpp"
namespace AllTestsRunner {
class NullStreamingReporter : public Catch::SharedImpl<Catch::IStreamingReporter> {
public:
virtual ~NullStreamingReporter();
static std::string getDescription() {
return "null reporter";
}
private: // IStreamingReporter
virtual Catch::ReporterPreferences getPreferences() const {
return Catch::ReporterPreferences();
}
virtual void noMatchingTestCases( std::string const& ) {}
virtual void testRunStarting( Catch::TestRunInfo const& ) {}
virtual void testGroupStarting( Catch::GroupInfo const& ) {}
virtual void testCaseStarting( Catch::TestCaseInfo const& ) {}
virtual void sectionStarting( Catch::SectionInfo const& ) {}
virtual void assertionStarting( Catch::AssertionInfo const& ) {}
virtual bool assertionEnded( Catch::AssertionStats const& ) { return false; }
virtual void sectionEnded( Catch::SectionStats const& ) {}
virtual void testCaseEnded( Catch::TestCaseStats const& ) {}
virtual void testGroupEnded( Catch::TestGroupStats const& ) {}
virtual void testRunEnded( Catch::TestRunStats const& ) {}
};
class EmbeddedRunner {
public:
EmbeddedRunner() : m_reporter( new NullStreamingReporter() ) {}
Catch::Totals runMatching( const std::string& rawTestSpec,
std::size_t groupIndex,
std::size_t groupsCount,
const std::string& reporter = "console" );
private:
Catch::Ptr<Catch::IStreamingReporter> m_reporter;
};
class MetaTestRunner {
public:
struct Expected { enum Result {
ToSucceed,
ToFail
}; };
MetaTestRunner( Expected::Result expectedResult, std::size_t groupIndex, std::size_t groupsCount )
: m_expectedResult( expectedResult ),
m_groupIndex( groupIndex ),
m_groupsCount( groupsCount )
{}
static void runMatching( const std::string& testSpec,
Expected::Result expectedResult,
std::size_t groupIndex,
std::size_t groupsCount ) {
forEach( Catch::getRegistryHub().getTestCaseRegistry().getMatchingTestCases( testSpec ),
MetaTestRunner( expectedResult, groupIndex, groupsCount ) );
}
void operator()( const Catch::TestCase& testCase ) {
std::string name;
Catch::Totals totals;
{
EmbeddedRunner runner;
name = testCase.getTestCaseInfo().name;
totals = runner.runMatching( name, m_groupIndex, m_groupsCount );
}
switch( m_expectedResult ) {
case Expected::ToSucceed:
if( totals.assertions.failed > 0 ) {
FAIL( "Expected test case '"
<< name
<< "' to succeed but there was/ were "
<< totals.assertions.failed << " failure(s)" );
}
else {
SUCCEED( "Tests passed, as expected" );
}
break;
case Expected::ToFail:
if( totals.assertions.failed == 0 ) {
FAIL( "Expected test case '"
<< name
<< "' to fail but there was/ were "
<< totals.assertions.passed << " success(es)" );
}
else {
SUCCEED( "Tests failed, as expected" );
}
break;
}
}
private:
Expected::Result m_expectedResult;
std::size_t m_groupIndex;
std::size_t m_groupsCount;
};
NullStreamingReporter::~NullStreamingReporter() {}
Catch::Totals EmbeddedRunner::runMatching( const std::string& rawTestSpec, std::size_t groupIndex, std::size_t groupsCount, const std::string& ) {
std::ostringstream oss;
Catch::Ptr<Catch::Config> config = new Catch::Config();
config->setStreamBuf( oss.rdbuf() );
Catch::Totals totals;
// Scoped because RunContext doesn't report EndTesting until its destructor
{
Catch::RunContext runner( config.get(), m_reporter.get() );
totals = runner.runMatching( rawTestSpec, groupIndex, groupsCount );
}
return totals;
}
TEST_CASE( "Run all failing and succeeding tests", "[vsall]" ) {
///////////////////////////////////////////////////////////////////////////
SECTION( "selftest/expected result",
"Tests do what they claim" ) {
#ifdef _UNICODE
std::cout << "using Unicode..." << std::endl;
#else
std::cout << "using Mbcs..." << std::endl;
#endif
SECTION( "selftest/expected result/failing tests",
"Tests in the 'failing' branch fail" ) {
std::cout << "Tests in the 'failing' branch fail" << std::endl;
MetaTestRunner::runMatching( "./failing/*", MetaTestRunner::Expected::ToFail, 0, 2 );
}
SECTION( "selftest/expected result/succeeding tests",
"Tests in the 'succeeding' branch succeed" ) {
std::cout << "Tests in the 'succeeding' branch succeed" << std::endl;
MetaTestRunner::runMatching( "./succeeding/*", MetaTestRunner::Expected::ToSucceed, 1, 2 );
}
}
///////////////////////////////////////////////////////////////////////////
SECTION( "selftest/test counts",
"Number of test cases that run is fixed" ) {
EmbeddedRunner runner;
SECTION( "selftest/test counts/succeeding tests",
"Number of 'succeeding' tests is fixed" ) {
std::cout << "Number of 'succeeding' tests is fixed" << std::endl;
Catch::Totals totals = runner.runMatching( "./succeeding/*", 0, 2 );
CHECK( totals.assertions.passed == 298 );
CHECK( totals.assertions.failed == 0 );
}
SECTION( "selftest/test counts/failing tests",
"Number of 'failing' tests is fixed" ) {
std::cout << "Number of 'failing' tests is fixed" << std::endl;
Catch::Totals totals = runner.runMatching( "./failing/*", 1, 2 );
CHECK( totals.assertions.passed == 2 );
CHECK( totals.assertions.failed == 77 );
}
}
}
#if defined(INTERNAL_CATCH_VS_MANAGED) || defined(INTERNAL_CATCH_VS_NATIVE)
CATCH_MAP_CATEGORY_TO_TAG(all, "[vsall]");
#endif
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,110 @@
/*
* Created by Phil on 22/10/2010.
* Copyright 2010 Two Blue Cubes Ltd
*
* 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)
*/
#include "catch.hpp"
#if defined(INTERNAL_CATCH_VS_MANAGED) || defined(INTERNAL_CATCH_VS_NATIVE)
namespace VisualStudioTests
{
class UniqueTestsFixture {
private:
static int uniqueID;
public:
UniqueTestsFixture() { }
protected:
int getID() {
return ++uniqueID;
}
};
int UniqueTestsFixture::uniqueID = 0;
TEST_CASE("M00", "[m_off]")
{
bool show = Catch::getCurrentContext().getConfig()->includeSuccessfulResults();
REQUIRE(!show);
}
CATCH_CONFIG_SHOW_SUCCESS(true)
TEST_CASE("M01", "[m_on]")
{
bool show = Catch::getCurrentContext().getConfig()->includeSuccessfulResults();
REQUIRE(show);
}
TEST_CASE("M02", "[m_off]")
{
bool show = Catch::getCurrentContext().getConfig()->includeSuccessfulResults();
REQUIRE(!show);
}
TEST_CASE_METHOD(UniqueTestsFixture, "M10", "[m_off]")
{
bool show = Catch::getCurrentContext().getConfig()->includeSuccessfulResults();
REQUIRE(!show);
getID();
}
CATCH_CONFIG_WARN_MISSING_ASSERTIONS(true)
CATCH_CONFIG_SHOW_SUCCESS(true)
TEST_CASE_METHOD(UniqueTestsFixture, "M11", "[m_on]")
{
bool show = Catch::getCurrentContext().getConfig()->includeSuccessfulResults();
REQUIRE(show);
getID();
}
CATCH_CONFIG_WARN_MISSING_ASSERTIONS(true)
CATCH_CONFIG_SHOW_SUCCESS(true)
TEST_CASE_METHOD(UniqueTestsFixture, "M99", "[m_on]")
{
bool show = Catch::getCurrentContext().getConfig()->includeSuccessfulResults();
REQUIRE(show);
WARN("Warning message");
getID();
}
TEST_CASE_METHOD(UniqueTestsFixture, "M12", "[m_off]")
{
bool show = Catch::getCurrentContext().getConfig()->includeSuccessfulResults();
REQUIRE(!show);
getID();
}
class ConfigTest
{
public:
void run1()
{
bool show = Catch::getCurrentContext().getConfig()->includeSuccessfulResults();
REQUIRE(!show);
}
void run2()
{
bool show = Catch::getCurrentContext().getConfig()->includeSuccessfulResults();
REQUIRE(show);
}
void run3()
{
bool show = Catch::getCurrentContext().getConfig()->includeSuccessfulResults();
REQUIRE(!show);
}
};
METHOD_AS_TEST_CASE(ConfigTest::run1,"M20", "[m_off]");
CATCH_CONFIG_SHOW_SUCCESS(true)
METHOD_AS_TEST_CASE(ConfigTest::run2,"M21", "[m_on]");
METHOD_AS_TEST_CASE(ConfigTest::run3,"M22", "[m_off]");
CATCH_MAP_CATEGORY_TO_TAG(vstestsCheckOutputOff, "[m_off]");
CATCH_CONFIG_SHOW_SUCCESS(true)
CATCH_MAP_CATEGORY_TO_TAG(vstestsCheckOutputOn, "[m_on]");
CATCH_MAP_CATEGORY_TO_TAG(vstestsCheckOutputOff2, "[m_off]");
}
#endif

View File

@ -6,7 +6,9 @@
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*/ */
#if !defined(_WINDLL)
#define CATCH_CONFIG_MAIN #define CATCH_CONFIG_MAIN
#endif
#include "catch_self_test.hpp" #include "catch_self_test.hpp"
namespace Catch{ namespace Catch{

View File

@ -4,8 +4,6 @@ SOURCES = ApproxTests.cpp \
ExceptionTests.cpp \ ExceptionTests.cpp \
GeneratorTests.cpp \ GeneratorTests.cpp \
MessageTests.cpp \ MessageTests.cpp \
MessageInstantiationTests1.cpp \
MessageInstantiationTests2.cpp \
MiscTests.cpp \ MiscTests.cpp \
TestMain.cpp \ TestMain.cpp \
TrickyTests.cpp \ TrickyTests.cpp \