v1.2.1-develop.15

- includes all new section tracker
This commit is contained in:
Phil Nash 2015-11-03 08:00:43 +00:00
parent 4636be9744
commit 7e34619f03
3 changed files with 410 additions and 220 deletions

View File

@ -1,6 +1,6 @@
![catch logo](catch-logo-small.png) ![catch logo](catch-logo-small.png)
*v1.2.1-develop.14* *v1.2.1-develop.15*
Build status (on Travis CI) [![Build Status](https://travis-ci.org/philsquared/Catch.png)](https://travis-ci.org/philsquared/Catch) Build status (on Travis CI) [![Build Status](https://travis-ci.org/philsquared/Catch.png)](https://travis-ci.org/philsquared/Catch)

View File

@ -37,7 +37,7 @@ namespace Catch {
return os; return os;
} }
Version libraryVersion( 1, 2, 1, "develop", 14 ); Version libraryVersion( 1, 2, 1, "develop", 15 );
} }

View File

@ -1,6 +1,6 @@
/* /*
* Catch v1.2.1-develop.14 * Catch v1.2.1-develop.15
* Generated: 2015-09-27 03:27:04.922060 * Generated: 2015-11-03 08:00:19.120246
* ---------------------------------------------------------- * ----------------------------------------------------------
* This file has been merged from multiple headers. Please don't edit it directly * This file has been merged from multiple headers. Please don't edit it directly
* Copyright (c) 2012 Two Blue Cubes Ltd. All rights reserved. * Copyright (c) 2012 Two Blue Cubes Ltd. All rights reserved.
@ -35,6 +35,7 @@
# pragma clang diagnostic ignored "-Wc++98-compat" # pragma clang diagnostic ignored "-Wc++98-compat"
# pragma clang diagnostic ignored "-Wc++98-compat-pedantic" # pragma clang diagnostic ignored "-Wc++98-compat-pedantic"
# pragma clang diagnostic ignored "-Wswitch-enum" # pragma clang diagnostic ignored "-Wswitch-enum"
# pragma clang diagnostic ignored "-Wcovered-switch-default"
# endif # endif
#elif defined __GNUC__ #elif defined __GNUC__
# pragma GCC diagnostic ignored "-Wvariadic-macros" # pragma GCC diagnostic ignored "-Wvariadic-macros"
@ -3287,28 +3288,59 @@ namespace Catch {
// #included from: catch_stream.h // #included from: catch_stream.h
#define TWOBLUECUBES_CATCH_STREAM_H_INCLUDED #define TWOBLUECUBES_CATCH_STREAM_H_INCLUDED
#include <streambuf> // #included from: catch_streambuf.h
#define TWOBLUECUBES_CATCH_STREAMBUF_H_INCLUDED
#ifdef __clang__ #include <streambuf>
#pragma clang diagnostic ignored "-Wpadded"
#endif
namespace Catch { namespace Catch {
class Stream { class StreamBufBase : public std::streambuf {
public: public:
Stream(); virtual ~StreamBufBase() CATCH_NOEXCEPT;
Stream( std::streambuf* _streamBuf, bool _isOwned );
void release();
std::streambuf* streamBuf;
private:
bool isOwned;
}; };
}
#include <streambuf>
#include <ostream>
#include <fstream>
namespace Catch {
std::ostream& cout(); std::ostream& cout();
std::ostream& cerr(); std::ostream& cerr();
struct IStream {
virtual ~IStream() CATCH_NOEXCEPT;
virtual std::ostream& stream() const = 0;
};
class FileStream : public IStream {
mutable std::ofstream m_ofs;
public:
FileStream( std::string const& filename );
public: // IStream
virtual std::ostream& stream() const CATCH_OVERRIDE;
};
class CoutStream : public IStream {
mutable std::ostream m_os;
public:
CoutStream();
public: // IStream
virtual std::ostream& stream() const CATCH_OVERRIDE;
};
class DebugOutStream : public IStream {
std::auto_ptr<StreamBufBase> m_streamBuf;
mutable std::ostream m_os;
public:
DebugOutStream();
public: // IStream
virtual std::ostream& stream() const CATCH_OVERRIDE;
};
} }
#include <memory> #include <memory>
@ -3382,12 +3414,11 @@ namespace Catch {
public: public:
Config() Config()
: m_os( Catch::cout().rdbuf() )
{} {}
Config( ConfigData const& data ) Config( ConfigData const& data )
: m_data( data ), : m_data( data ),
m_os( Catch::cout().rdbuf() ) m_stream( openStream() )
{ {
if( !data.testsOrTags.empty() ) { if( !data.testsOrTags.empty() ) {
TestSpecParser parser( ITagAliasRegistry::get() ); TestSpecParser parser( ITagAliasRegistry::get() );
@ -3398,12 +3429,6 @@ namespace Catch {
} }
virtual ~Config() { virtual ~Config() {
m_os.rdbuf( Catch::cout().rdbuf() );
m_stream.release();
}
void setFilename( std::string const& filename ) {
m_data.outputFilename = filename;
} }
std::string const& getFilename() const { std::string const& getFilename() const {
@ -3419,17 +3444,6 @@ namespace Catch {
bool shouldDebugBreak() const { return m_data.shouldDebugBreak; } bool shouldDebugBreak() const { return m_data.shouldDebugBreak; }
void setStreamBuf( std::streambuf* buf ) {
m_os.rdbuf( buf ? buf : Catch::cout().rdbuf() );
}
void useStream( std::string const& streamName ) {
Stream stream = createStream( streamName );
setStreamBuf( stream.streamBuf );
m_stream.release();
m_stream = stream;
}
std::vector<std::string> getReporterNames() const { return m_data.reporterNames; } std::vector<std::string> getReporterNames() const { return m_data.reporterNames; }
int abortAfter() const { return m_data.abortAfter; } int abortAfter() const { return m_data.abortAfter; }
@ -3441,7 +3455,7 @@ namespace Catch {
// IConfig interface // IConfig interface
virtual bool allowThrows() const { return !m_data.noThrow; } virtual bool allowThrows() const { return !m_data.noThrow; }
virtual std::ostream& stream() const { return m_os; } virtual std::ostream& stream() const { return m_stream->stream(); }
virtual std::string name() const { return m_data.name.empty() ? m_data.processName : m_data.name; } virtual std::string name() const { return m_data.name.empty() ? m_data.processName : m_data.name; }
virtual bool includeSuccessfulResults() const { return m_data.showSuccessfulTests; } virtual bool includeSuccessfulResults() const { return m_data.showSuccessfulTests; }
virtual bool warnAboutMissingAssertions() const { return m_data.warnings & WarnAbout::NoAssertions; } virtual bool warnAboutMissingAssertions() const { return m_data.warnings & WarnAbout::NoAssertions; }
@ -3451,10 +3465,22 @@ namespace Catch {
virtual bool forceColour() const { return m_data.forceColour; } virtual bool forceColour() const { return m_data.forceColour; }
private: private:
IStream const* openStream() {
if( m_data.outputFilename.empty() )
return new CoutStream();
else if( m_data.outputFilename[0] == '%' ) {
if( m_data.outputFilename == "%debug" )
return new DebugOutStream();
else
throw std::domain_error( "Unrecognised stream: " + m_data.outputFilename );
}
else
return new FileStream( m_data.outputFilename );
}
ConfigData m_data; ConfigData m_data;
Stream m_stream; std::auto_ptr<IStream const> m_stream;
mutable std::ostream m_os;
TestSpec m_testSpec; TestSpec m_testSpec;
}; };
@ -4726,18 +4752,18 @@ namespace Catch {
namespace Catch namespace Catch
{ {
struct ReporterConfig { struct ReporterConfig {
explicit ReporterConfig( Ptr<IConfig> const& _fullConfig ) explicit ReporterConfig( Ptr<IConfig const> const& _fullConfig )
: m_stream( &_fullConfig->stream() ), m_fullConfig( _fullConfig ) {} : m_stream( &_fullConfig->stream() ), m_fullConfig( _fullConfig ) {}
ReporterConfig( Ptr<IConfig> const& _fullConfig, std::ostream& _stream ) ReporterConfig( Ptr<IConfig const> const& _fullConfig, std::ostream& _stream )
: m_stream( &_stream ), m_fullConfig( _fullConfig ) {} : m_stream( &_stream ), m_fullConfig( _fullConfig ) {}
std::ostream& stream() const { return *m_stream; } std::ostream& stream() const { return *m_stream; }
Ptr<IConfig> fullConfig() const { return m_fullConfig; } Ptr<IConfig const> fullConfig() const { return m_fullConfig; }
private: private:
std::ostream* m_stream; std::ostream* m_stream;
Ptr<IConfig> m_fullConfig; Ptr<IConfig const> m_fullConfig;
}; };
struct ReporterPreferences { struct ReporterPreferences {
@ -4959,7 +4985,7 @@ namespace Catch
typedef std::vector<Ptr<IReporterFactory> > Listeners; typedef std::vector<Ptr<IReporterFactory> > Listeners;
virtual ~IReporterRegistry(); virtual ~IReporterRegistry();
virtual IStreamingReporter* create( std::string const& name, Ptr<IConfig> const& config ) const = 0; virtual IStreamingReporter* create( std::string const& name, Ptr<IConfig const> const& config ) const = 0;
virtual FactoryMap const& getFactories() const = 0; virtual FactoryMap const& getFactories() const = 0;
virtual Listeners const& getListeners() const = 0; virtual Listeners const& getListeners() const = 0;
}; };
@ -5136,137 +5162,300 @@ namespace Catch {
#include <map> #include <map>
#include <string> #include <string>
#include <assert.h> #include <assert.h>
#include <vector>
namespace Catch { namespace Catch {
namespace SectionTracking { namespace TestCaseTracking {
class TrackedSection { struct ITracker : SharedImpl<> {
virtual ~ITracker();
typedef std::map<std::string, TrackedSection> TrackedSections; // static queries
virtual std::string name() const = 0;
// dynamic queries
virtual bool isComplete() const = 0; // Successfully completed or failed
virtual bool isSuccessfullyCompleted() const = 0;
virtual bool isOpen() const = 0; // Started but not complete
virtual bool hasChildren() const = 0;
virtual ITracker& parent() = 0;
// actions
virtual void close() = 0; // Successfully complete
virtual void fail() = 0;
virtual void markAsNeedingAnotherRun() = 0;
virtual void addChild( Ptr<ITracker> const& child ) = 0;
virtual ITracker* findChild( std::string const& name ) = 0;
virtual void openChild() = 0;
};
class TrackerContext {
public:
enum RunState { enum RunState {
NotStarted, NotStarted,
Executing, Executing,
ExecutingChildren, CompletedCycle
Completed
}; };
TrackedSection( std::string const& name, TrackedSection* parent ) Ptr<ITracker> m_rootTracker;
: m_name( name ), m_runState( NotStarted ), m_parent( parent ) ITracker* m_currentTracker;
RunState m_runState;
public:
static TrackerContext& instance() {
static TrackerContext s_instance;
return s_instance;
}
TrackerContext()
: m_currentTracker( CATCH_NULL ),
m_runState( NotStarted )
{} {}
RunState runState() const { return m_runState; } ITracker& startRun();
TrackedSection* findChild( std::string const& childName ); void endRun() {
TrackedSection* acquireChild( std::string const& childName ); m_rootTracker.reset();
m_currentTracker = CATCH_NULL;
m_runState = NotStarted;
}
void enter() { void startCycle() {
if( m_runState == NotStarted ) m_currentTracker = m_rootTracker.get();
m_runState = Executing; m_runState = Executing;
} }
void leave(); void completeCycle() {
m_runState = CompletedCycle;
TrackedSection* getParent() {
return m_parent;
} }
bool hasChildren() const {
bool completedCycle() const {
return m_runState == CompletedCycle;
}
ITracker& currentTracker() {
return *m_currentTracker;
}
void setCurrentTracker( ITracker* tracker ) {
m_currentTracker = tracker;
}
};
class TrackerBase : public ITracker {
protected:
enum CycleState {
NotStarted,
Executing,
ExecutingChildren,
NeedsAnotherRun,
CompletedSuccessfully,
Failed
};
class TrackerHasName {
std::string m_name;
public:
TrackerHasName( std::string const& name ) : m_name( name ) {}
bool operator ()( Ptr<ITracker> const& tracker ) {
return tracker->name() == m_name;
}
};
typedef std::vector<Ptr<ITracker> > Children;
std::string m_name;
TrackerContext& m_ctx;
ITracker* m_parent;
Children m_children;
CycleState m_runState;
public:
TrackerBase( std::string const& name, TrackerContext& ctx, ITracker* parent )
: m_name( name ),
m_ctx( ctx ),
m_parent( parent ),
m_runState( NotStarted )
{}
virtual ~TrackerBase();
virtual std::string name() const CATCH_OVERRIDE {
return m_name;
}
virtual bool isComplete() const CATCH_OVERRIDE {
return m_runState == CompletedSuccessfully || m_runState == Failed;
}
virtual bool isSuccessfullyCompleted() const CATCH_OVERRIDE {
return m_runState == CompletedSuccessfully;
}
virtual bool isOpen() const CATCH_OVERRIDE {
return m_runState != NotStarted && !isComplete();
}
virtual bool hasChildren() const CATCH_OVERRIDE {
return !m_children.empty(); return !m_children.empty();
} }
private: virtual void addChild( Ptr<ITracker> const& child ) CATCH_OVERRIDE {
std::string m_name; m_children.push_back( child );
RunState m_runState; }
TrackedSections m_children;
TrackedSection* m_parent;
};
inline TrackedSection* TrackedSection::findChild( std::string const& childName ) { virtual ITracker* findChild( std::string const& name ) CATCH_OVERRIDE {
TrackedSections::iterator it = m_children.find( childName ); Children::const_iterator it = std::find_if( m_children.begin(), m_children.end(), TrackerHasName( name ) );
return it != m_children.end() return( it != m_children.end() )
? &it->second ? it->get()
: CATCH_NULL; : CATCH_NULL;
} }
inline TrackedSection* TrackedSection::acquireChild( std::string const& childName ) { virtual ITracker& parent() CATCH_OVERRIDE {
if( TrackedSection* child = findChild( childName ) ) assert( m_parent ); // Should always be non-null except for root
return child; return *m_parent;
m_children.insert( std::make_pair( childName, TrackedSection( childName, this ) ) );
return findChild( childName );
} }
inline void TrackedSection::leave() {
for( TrackedSections::const_iterator it = m_children.begin(), itEnd = m_children.end(); virtual void openChild() CATCH_OVERRIDE {
it != itEnd; if( m_runState != ExecutingChildren ) {
++it )
if( it->second.runState() != Completed ) {
m_runState = ExecutingChildren; m_runState = ExecutingChildren;
return; if( m_parent )
m_parent->openChild();
} }
m_runState = Completed; }
void open() {
m_runState = Executing;
moveToThis();
if( m_parent )
m_parent->openChild();
} }
class TestCaseTracker { virtual void close() CATCH_OVERRIDE {
// Close any still open children (e.g. generators)
while( &m_ctx.currentTracker() != this )
m_ctx.currentTracker().close();
switch( m_runState ) {
case NotStarted:
case CompletedSuccessfully:
case Failed:
throw std::logic_error( "Illogical state" );
case NeedsAnotherRun:
break;;
case Executing:
m_runState = CompletedSuccessfully;
break;
case ExecutingChildren:
if( m_children.empty() || m_children.back()->isComplete() )
m_runState = CompletedSuccessfully;
break;
default:
throw std::logic_error( "Unexpected state" );
}
moveToParent();
m_ctx.completeCycle();
}
virtual void fail() CATCH_OVERRIDE {
m_runState = Failed;
if( m_parent )
m_parent->markAsNeedingAnotherRun();
moveToParent();
m_ctx.completeCycle();
}
virtual void markAsNeedingAnotherRun() CATCH_OVERRIDE {
m_runState = NeedsAnotherRun;
}
private:
void moveToParent() {
assert( m_parent );
m_ctx.setCurrentTracker( m_parent );
}
void moveToThis() {
m_ctx.setCurrentTracker( this );
}
};
class SectionTracker : public TrackerBase {
public: public:
TestCaseTracker( std::string const& testCaseName ) SectionTracker( std::string const& name, TrackerContext& ctx, ITracker* parent )
: m_testCase( testCaseName, CATCH_NULL ), : TrackerBase( name, ctx, parent )
m_currentSection( &m_testCase ),
m_completedASectionThisRun( false )
{} {}
virtual ~SectionTracker();
bool enterSection( std::string const& name ) { static SectionTracker& acquire( TrackerContext& ctx, std::string const& name ) {
TrackedSection* child = m_currentSection->acquireChild( name ); SectionTracker* section = CATCH_NULL;
if( m_completedASectionThisRun || child->runState() == TrackedSection::Completed )
return false;
m_currentSection = child; ITracker& currentTracker = ctx.currentTracker();
m_currentSection->enter(); if( ITracker* childTracker = currentTracker.findChild( name ) ) {
return true; section = dynamic_cast<SectionTracker*>( childTracker );
assert( section );
} }
void leaveSection() { else {
m_currentSection->leave(); section = new SectionTracker( name, ctx, &currentTracker );
m_currentSection = m_currentSection->getParent(); currentTracker.addChild( section );
assert( m_currentSection != CATCH_NULL );
m_completedASectionThisRun = true;
} }
if( !ctx.completedCycle() && !section->isComplete() ) {
bool currentSectionHasChildren() const { section->open();
return m_currentSection->hasChildren();
} }
bool isCompleted() const { return *section;
return m_testCase.runState() == TrackedSection::Completed;
} }
};
class Guard { class IndexTracker : public TrackerBase {
int m_size;
int m_index;
public: public:
Guard( TestCaseTracker& tracker ) : m_tracker( tracker ) { IndexTracker( std::string const& name, TrackerContext& ctx, ITracker* parent, int size )
m_tracker.enterTestCase(); : TrackerBase( name, ctx, parent ),
m_size( size ),
m_index( -1 )
{}
virtual ~IndexTracker();
static IndexTracker& acquire( TrackerContext& ctx, std::string const& name, int size ) {
IndexTracker* tracker = CATCH_NULL;
ITracker& currentTracker = ctx.currentTracker();
if( ITracker* childTracker = currentTracker.findChild( name ) ) {
tracker = dynamic_cast<IndexTracker*>( childTracker );
assert( tracker );
} }
~Guard() { else {
m_tracker.leaveTestCase(); tracker = new IndexTracker( name, ctx, &currentTracker, size );
currentTracker.addChild( tracker );
}
if( !ctx.completedCycle() && !tracker->isComplete() ) {
if( tracker->m_runState != ExecutingChildren && tracker->m_runState != NeedsAnotherRun )
tracker->moveNext();
tracker->open();
}
return *tracker;
}
int index() const { return m_index; }
void moveNext() {
m_index++;
m_children.clear();
}
virtual void close() CATCH_OVERRIDE {
TrackerBase::close();
if( m_runState == CompletedSuccessfully && m_index < m_size-1 )
m_runState = Executing;
} }
private:
Guard( Guard const& );
void operator = ( Guard const& );
TestCaseTracker& m_tracker;
}; };
private: inline ITracker& TrackerContext::startRun() {
void enterTestCase() { m_rootTracker = new SectionTracker( "{root}", *this, CATCH_NULL );
m_currentSection = &m_testCase; m_currentTracker = CATCH_NULL;
m_completedASectionThisRun = false; m_runState = Executing;
m_testCase.enter(); return *m_rootTracker;
}
void leaveTestCase() {
m_testCase.leave();
} }
TrackedSection m_testCase; } // namespace TestCaseTracking
TrackedSection* m_currentSection;
bool m_completedASectionThisRun;
};
} // namespace SectionTracking using TestCaseTracking::ITracker;
using TestCaseTracking::TrackerContext;
using SectionTracking::TestCaseTracker; using TestCaseTracking::SectionTracker;
using TestCaseTracking::IndexTracker;
} // namespace Catch } // namespace Catch
@ -5387,10 +5576,7 @@ namespace Catch {
m_context( getCurrentMutableContext() ), m_context( getCurrentMutableContext() ),
m_activeTestCase( CATCH_NULL ), m_activeTestCase( CATCH_NULL ),
m_config( _config ), m_config( _config ),
m_reporter( reporter ), m_reporter( reporter )
m_prevRunner( m_context.getRunner() ),
m_prevResultCapture( m_context.getResultCapture() ),
m_prevConfig( m_context.getConfig() )
{ {
m_context.setRunner( this ); m_context.setRunner( this );
m_context.setConfig( m_config ); m_context.setConfig( m_config );
@ -5400,10 +5586,6 @@ namespace Catch {
virtual ~RunContext() { virtual ~RunContext() {
m_reporter->testRunEnded( TestRunStats( m_runInfo, m_totals, aborting() ) ); m_reporter->testRunEnded( TestRunStats( m_runInfo, m_totals, aborting() ) );
m_context.setRunner( m_prevRunner );
m_context.setConfig( Ptr<IConfig const>() );
m_context.setResultCapture( m_prevResultCapture );
m_context.setConfig( m_prevConfig );
} }
void testGroupStarting( std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount ) { void testGroupStarting( std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount ) {
@ -5424,14 +5606,17 @@ namespace Catch {
m_reporter->testCaseStarting( testInfo ); m_reporter->testCaseStarting( testInfo );
m_activeTestCase = &testCase; m_activeTestCase = &testCase;
m_testCaseTracker = TestCaseTracker( testInfo.name );
do { do {
m_trackerContext.startRun();
do { do {
m_trackerContext.startCycle();
m_testCaseTracker = &SectionTracker::acquire( m_trackerContext, testInfo.name );
runCurrentTest( redirectedCout, redirectedCerr ); runCurrentTest( redirectedCout, redirectedCerr );
} }
while( !m_testCaseTracker->isCompleted() && !aborting() ); while( !m_testCaseTracker->isSuccessfullyCompleted() && !aborting() );
} }
// !TBD: deprecated - this will be replaced by indexed trackers
while( getCurrentContext().advanceGeneratorsForCurrentTest() && !aborting() ); while( getCurrentContext().advanceGeneratorsForCurrentTest() && !aborting() );
Totals deltaTotals = m_totals.delta( prevTotals ); Totals deltaTotals = m_totals.delta( prevTotals );
@ -5443,7 +5628,7 @@ namespace Catch {
aborting() ) ); aborting() ) );
m_activeTestCase = CATCH_NULL; m_activeTestCase = CATCH_NULL;
m_testCaseTracker.reset(); m_testCaseTracker = CATCH_NULL;
return deltaTotals; return deltaTotals;
} }
@ -5478,8 +5663,10 @@ namespace Catch {
std::ostringstream oss; std::ostringstream oss;
oss << sectionInfo.name << "@" << sectionInfo.lineInfo; oss << sectionInfo.name << "@" << sectionInfo.lineInfo;
if( !m_testCaseTracker->enterSection( oss.str() ) ) ITracker& sectionTracker = SectionTracker::acquire( m_trackerContext, oss.str() );
if( !sectionTracker.isOpen() )
return false; return false;
m_activeSections.push_back( &sectionTracker );
m_lastAssertionInfo.lineInfo = sectionInfo.lineInfo; m_lastAssertionInfo.lineInfo = sectionInfo.lineInfo;
@ -5490,9 +5677,11 @@ namespace Catch {
return true; return true;
} }
bool testForMissingAssertions( Counts& assertions ) { bool testForMissingAssertions( Counts& assertions ) {
if( assertions.total() != 0 || if( assertions.total() != 0 )
!m_config->warnAboutMissingAssertions() || return false;
m_testCaseTracker->currentSectionHasChildren() ) if( m_config->warnAboutMissingAssertions() )
return false;
if( m_trackerContext.currentTracker().hasChildren() )
return false; return false;
m_totals.assertions.failed++; m_totals.assertions.failed++;
assertions.failed++; assertions.failed++;
@ -5503,13 +5692,22 @@ namespace Catch {
Counts assertions = m_totals.assertions - endInfo.prevAssertions; Counts assertions = m_totals.assertions - endInfo.prevAssertions;
bool missingAssertions = testForMissingAssertions( assertions ); bool missingAssertions = testForMissingAssertions( assertions );
m_testCaseTracker->leaveSection(); if( !m_activeSections.empty() ) {
m_activeSections.back()->close();
m_activeSections.pop_back();
}
m_reporter->sectionEnded( SectionStats( endInfo.sectionInfo, assertions, endInfo.durationInSeconds, missingAssertions ) ); m_reporter->sectionEnded( SectionStats( endInfo.sectionInfo, assertions, endInfo.durationInSeconds, missingAssertions ) );
m_messages.clear(); m_messages.clear();
} }
virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) { virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) {
if( m_unfinishedSections.empty() )
m_activeSections.back()->fail();
else
m_activeSections.back()->close();
m_activeSections.pop_back();
m_unfinishedSections.push_back( endInfo ); m_unfinishedSections.push_back( endInfo );
} }
@ -5578,7 +5776,6 @@ namespace Catch {
double duration = 0; 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 );
seedRng( *m_config ); seedRng( *m_config );
@ -5600,6 +5797,7 @@ namespace Catch {
catch(...) { catch(...) {
makeUnexpectedResultBuilder().useActiveException(); makeUnexpectedResultBuilder().useActiveException();
} }
m_testCaseTracker->close();
handleUnfinishedSections(); handleUnfinishedSections();
m_messages.clear(); m_messages.clear();
@ -5645,18 +5843,18 @@ namespace Catch {
TestRunInfo m_runInfo; TestRunInfo m_runInfo;
IMutableContext& m_context; IMutableContext& m_context;
TestCase const* m_activeTestCase; TestCase const* m_activeTestCase;
Option<TestCaseTracker> m_testCaseTracker; ITracker* m_testCaseTracker;
ITracker* m_currentSectionTracker;
AssertionResult m_lastResult; AssertionResult m_lastResult;
Ptr<IConfig const> m_config; Ptr<IConfig const> m_config;
Totals m_totals; Totals m_totals;
Ptr<IStreamingReporter> m_reporter; Ptr<IStreamingReporter> m_reporter;
std::vector<MessageInfo> m_messages; std::vector<MessageInfo> m_messages;
IRunner* m_prevRunner;
IResultCapture* m_prevResultCapture;
Ptr<IConfig const> m_prevConfig;
AssertionInfo m_lastAssertionInfo; AssertionInfo m_lastAssertionInfo;
std::vector<SectionEndInfo> m_unfinishedSections; std::vector<SectionEndInfo> m_unfinishedSections;
std::vector<ITracker*> m_activeSections;
TrackerContext m_trackerContext;
}; };
IResultCapture& getResultCapture() { IResultCapture& getResultCapture() {
@ -5726,7 +5924,7 @@ namespace Catch {
reporter = addReporter( reporter, createReporter( *it, config ) ); reporter = addReporter( reporter, createReporter( *it, config ) );
return reporter; return reporter;
} }
Ptr<IStreamingReporter> addListeners( Ptr<IConfig> const& config, Ptr<IStreamingReporter> reporters ) { Ptr<IStreamingReporter> addListeners( Ptr<IConfig const> const& config, Ptr<IStreamingReporter> reporters ) {
IReporterRegistry::Listeners listeners = getRegistryHub().getReporterRegistry().getListeners(); IReporterRegistry::Listeners listeners = getRegistryHub().getReporterRegistry().getListeners();
for( IReporterRegistry::Listeners::const_iterator it = listeners.begin(), itEnd = listeners.end(); for( IReporterRegistry::Listeners::const_iterator it = listeners.begin(), itEnd = listeners.end();
it != itEnd; it != itEnd;
@ -5735,27 +5933,14 @@ namespace Catch {
return reporters; return reporters;
} }
void openStreamInto( Ptr<Config> const& config, std::ofstream& ofs ) {
// Open output file, if specified
if( !config->getFilename().empty() ) {
ofs.open( config->getFilename().c_str() );
if( ofs.fail() ) {
std::ostringstream oss;
oss << "Unable to open file: '" << config->getFilename() << "'";
throw std::domain_error( oss.str() );
}
config->setStreamBuf( ofs.rdbuf() );
}
}
Totals runTests( Ptr<Config> const& config ) { Totals runTests( Ptr<Config> const& config ) {
std::ofstream ofs; Ptr<IConfig const> iconfig = config.get();
openStreamInto( config, ofs );
Ptr<IStreamingReporter> reporter = makeReporter( config );
reporter = addListeners( config.get(), reporter );
RunContext context( config.get(), reporter ); Ptr<IStreamingReporter> reporter = makeReporter( config );
reporter = addListeners( iconfig, reporter );
RunContext context( iconfig, reporter );
Totals totals; Totals totals;
@ -5765,17 +5950,17 @@ namespace Catch {
if( !testSpec.hasFilters() ) if( !testSpec.hasFilters() )
testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "~[.]" ).testSpec(); // All not hidden tests testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "~[.]" ).testSpec(); // All not hidden tests
std::vector<TestCase> const& allTestCases = getAllTestCasesSorted( *config ); std::vector<TestCase> const& allTestCases = getAllTestCasesSorted( *iconfig );
for( std::vector<TestCase>::const_iterator it = allTestCases.begin(), itEnd = allTestCases.end(); for( std::vector<TestCase>::const_iterator it = allTestCases.begin(), itEnd = allTestCases.end();
it != itEnd; it != itEnd;
++it ) { ++it ) {
if( !context.aborting() && matchTest( *it, testSpec, *config ) ) if( !context.aborting() && matchTest( *it, testSpec, *iconfig ) )
totals += context.runTest( *it ); totals += context.runTest( *it );
else else
reporter->skipTest( *it ); reporter->skipTest( *it );
} }
context.testGroupEnded( config->name(), totals, 1, 1 ); context.testGroupEnded( iconfig->name(), totals, 1, 1 );
return totals; return totals;
} }
@ -6094,7 +6279,7 @@ namespace Catch {
virtual ~ReporterRegistry() CATCH_OVERRIDE {} virtual ~ReporterRegistry() CATCH_OVERRIDE {}
virtual IStreamingReporter* create( std::string const& name, Ptr<IConfig> const& config ) const CATCH_OVERRIDE { virtual IStreamingReporter* create( std::string const& name, Ptr<IConfig const> const& config ) const CATCH_OVERRIDE {
FactoryMap::const_iterator it = m_factories.find( name ); FactoryMap::const_iterator it = m_factories.find( name );
if( it == m_factories.end() ) if( it == m_factories.end() )
return CATCH_NULL; return CATCH_NULL;
@ -6283,19 +6468,6 @@ namespace Catch {
// #included from: catch_stream.hpp // #included from: catch_stream.hpp
#define TWOBLUECUBES_CATCH_STREAM_HPP_INCLUDED #define TWOBLUECUBES_CATCH_STREAM_HPP_INCLUDED
// #included from: catch_streambuf.h
#define TWOBLUECUBES_CATCH_STREAMBUF_H_INCLUDED
#include <streambuf>
namespace Catch {
class StreamBufBase : public std::streambuf {
public:
virtual ~StreamBufBase() CATCH_NOEXCEPT;
};
}
#include <stdexcept> #include <stdexcept>
#include <cstdio> #include <cstdio>
#include <iostream> #include <iostream>
@ -6340,6 +6512,19 @@ namespace Catch {
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
FileStream::FileStream( std::string const& filename ) {
m_ofs.open( filename.c_str() );
if( m_ofs.fail() ) {
std::ostringstream oss;
oss << "Unable to open file: '" << filename << "'";
throw std::domain_error( oss.str() );
}
}
std::ostream& FileStream::stream() const {
return m_ofs;
}
struct OutputDebugWriter { struct OutputDebugWriter {
void operator()( std::string const&str ) { void operator()( std::string const&str ) {
@ -6347,20 +6532,23 @@ namespace Catch {
} }
}; };
Stream::Stream() DebugOutStream::DebugOutStream()
: streamBuf( CATCH_NULL ), isOwned( false ) : m_streamBuf( new StreamBufImpl<OutputDebugWriter>() ),
m_os( m_streamBuf.get() )
{} {}
Stream::Stream( std::streambuf* _streamBuf, bool _isOwned ) std::ostream& DebugOutStream::stream() const {
: streamBuf( _streamBuf ), isOwned( _isOwned ) return m_os;
{}
void Stream::release() {
if( isOwned ) {
delete streamBuf;
streamBuf = CATCH_NULL;
isOwned = false;
} }
// Store the streambuf from cout up-front because
// cout may get redirected when running tests
CoutStream::CoutStream()
: m_os( Catch::cout().rdbuf() )
{}
std::ostream& CoutStream::stream() const {
return m_os;
} }
#ifndef CATCH_CONFIG_NOSTDOUT // If you #define this you must implement this functions #ifndef CATCH_CONFIG_NOSTDOUT // If you #define this you must implement this functions
@ -6455,14 +6643,6 @@ namespace Catch {
return getCurrentMutableContext(); return getCurrentMutableContext();
} }
Stream createStream( std::string const& streamName ) {
if( streamName == "stdout" ) return Stream( Catch::cout().rdbuf(), false );
if( streamName == "stderr" ) return Stream( Catch::cerr().rdbuf(), false );
if( streamName == "debug" ) return Stream( new StreamBufImpl<OutputDebugWriter>, true );
throw std::domain_error( "Unknown stream: " + streamName );
}
void cleanUpContext() { void cleanUpContext() {
delete currentContext; delete currentContext;
currentContext = CATCH_NULL; currentContext = CATCH_NULL;
@ -7011,7 +7191,7 @@ namespace Catch {
return os; return os;
} }
Version libraryVersion( 1, 2, 1, "develop", 14 ); Version libraryVersion( 1, 2, 1, "develop", 15 );
} }
@ -8076,7 +8256,7 @@ namespace Catch {
// It can optionally be overridden in the derived class. // It can optionally be overridden in the derived class.
} }
Ptr<IConfig> m_config; Ptr<IConfig const> m_config;
std::ostream& stream; std::ostream& stream;
LazyStat<TestRunInfo> currentTestRunInfo; LazyStat<TestRunInfo> currentTestRunInfo;
@ -8214,7 +8394,7 @@ namespace Catch {
virtual void skipTest( TestCaseInfo const& ) CATCH_OVERRIDE {} virtual void skipTest( TestCaseInfo const& ) CATCH_OVERRIDE {}
Ptr<IConfig> m_config; Ptr<IConfig const> m_config;
std::ostream& stream; std::ostream& stream;
std::vector<AssertionStats> m_assertions; std::vector<AssertionStats> m_assertions;
std::vector<std::vector<Ptr<SectionNode> > > m_sections; std::vector<std::vector<Ptr<SectionNode> > > m_sections;
@ -9689,8 +9869,11 @@ namespace Catch {
} // end namespace Catch } // end namespace Catch
namespace Catch { namespace Catch {
// These are all here to avoid warnings about not having any out of line
// virtual methods
NonCopyable::~NonCopyable() {} NonCopyable::~NonCopyable() {}
IShared::~IShared() {} IShared::~IShared() {}
IStream::~IStream() CATCH_NOEXCEPT {}
StreamBufBase::~StreamBufBase() CATCH_NOEXCEPT {} StreamBufBase::~StreamBufBase() CATCH_NOEXCEPT {}
IContext::~IContext() {} IContext::~IContext() {}
IResultCapture::~IResultCapture() {} IResultCapture::~IResultCapture() {}
@ -9736,6 +9919,13 @@ namespace Catch {
Matchers::Impl::StdString::EndsWith::~EndsWith() {} Matchers::Impl::StdString::EndsWith::~EndsWith() {}
void Config::dummy() {} void Config::dummy() {}
namespace TestCaseTracking {
ITracker::~ITracker() {}
TrackerBase::~TrackerBase() {}
SectionTracker::~SectionTracker() {}
IndexTracker::~IndexTracker() {}
}
} }
#ifdef __clang__ #ifdef __clang__