First cut of -c/—section option for running specific sections

This commit is contained in:
Phil Nash 2017-01-12 17:10:38 +00:00
parent 4a04682e49
commit e7bcbb35c0
6 changed files with 117 additions and 69 deletions

View file

@ -19,11 +19,21 @@
namespace Catch {
namespace TestCaseTracking {
struct NameAndLocation {
std::string name;
SourceLineInfo location;
NameAndLocation( std::string const& _name, SourceLineInfo const& _location )
: name( _name ),
location( _location )
{}
};
struct ITracker : SharedImpl<> {
virtual ~ITracker();
// static queries
virtual std::string name() const = 0;
virtual NameAndLocation const& nameAndLocation() const = 0;
// dynamic queries
virtual bool isComplete() const = 0; // Successfully completed or failed
@ -39,7 +49,7 @@ namespace TestCaseTracking {
virtual void markAsNeedingAnotherRun() = 0;
virtual void addChild( Ptr<ITracker> const& child ) = 0;
virtual ITracker* findChild( std::string const& name ) = 0;
virtual ITracker* findChild( NameAndLocation const& nameAndLocation ) = 0;
virtual void openChild() = 0;
// Debug/ checking
@ -47,7 +57,7 @@ namespace TestCaseTracking {
virtual bool isIndexTracker() const = 0;
};
class TrackerContext {
class TrackerContext {
enum RunState {
NotStarted,
@ -110,30 +120,32 @@ namespace TestCaseTracking {
Failed
};
class TrackerHasName {
std::string m_name;
NameAndLocation m_nameAndLocation;
public:
TrackerHasName( std::string const& name ) : m_name( name ) {}
TrackerHasName( NameAndLocation const& nameAndLocation ) : m_nameAndLocation( nameAndLocation ) {}
bool operator ()( Ptr<ITracker> const& tracker ) {
return tracker->name() == m_name;
return
tracker->nameAndLocation().name == m_nameAndLocation.name &&
tracker->nameAndLocation().location == m_nameAndLocation.location;
}
};
typedef std::vector<Ptr<ITracker> > Children;
std::string m_name;
NameAndLocation m_nameAndLocation;
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 ),
TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent )
: m_nameAndLocation( nameAndLocation ),
m_ctx( ctx ),
m_parent( parent ),
m_runState( NotStarted )
{}
virtual ~TrackerBase();
virtual std::string name() const CATCH_OVERRIDE {
return m_name;
virtual NameAndLocation const& nameAndLocation() const CATCH_OVERRIDE {
return m_nameAndLocation;
}
virtual bool isComplete() const CATCH_OVERRIDE {
return m_runState == CompletedSuccessfully || m_runState == Failed;
@ -153,8 +165,8 @@ namespace TestCaseTracking {
m_children.push_back( child );
}
virtual ITracker* findChild( std::string const& name ) CATCH_OVERRIDE {
Children::const_iterator it = std::find_if( m_children.begin(), m_children.end(), TrackerHasName( name ) );
virtual ITracker* findChild( NameAndLocation const& nameAndLocation ) CATCH_OVERRIDE {
Children::const_iterator it = std::find_if( m_children.begin(), m_children.end(), TrackerHasName( nameAndLocation ) );
return( it != m_children.end() )
? it->get()
: CATCH_NULL;
@ -232,41 +244,65 @@ namespace TestCaseTracking {
};
class SectionTracker : public TrackerBase {
std::vector<std::string> m_filters;
public:
SectionTracker( std::string const& name, TrackerContext& ctx, ITracker* parent )
: TrackerBase( name, ctx, parent )
{}
SectionTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent )
: TrackerBase( nameAndLocation, ctx, parent )
{
if( parent ) {
while( !parent->isSectionTracker() )
parent = &parent->parent();
SectionTracker& parentSection = static_cast<SectionTracker&>( *parent );
addNextFilters( parentSection.m_filters );
}
}
virtual ~SectionTracker();
virtual bool isSectionTracker() const CATCH_OVERRIDE { return true; }
static SectionTracker& acquire( TrackerContext& ctx, std::string const& name ) {
static SectionTracker& acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation ) {
SectionTracker* section = CATCH_NULL;
ITracker& currentTracker = ctx.currentTracker();
if( ITracker* childTracker = currentTracker.findChild( name ) ) {
if( ITracker* childTracker = currentTracker.findChild( nameAndLocation ) ) {
assert( childTracker );
assert( childTracker->isSectionTracker() );
section = static_cast<SectionTracker*>( childTracker );
}
else {
section = new SectionTracker( name, ctx, &currentTracker );
section = new SectionTracker( nameAndLocation, ctx, &currentTracker );
currentTracker.addChild( section );
}
if( !ctx.completedCycle() && !section->isComplete() ) {
section->open();
}
if( !ctx.completedCycle() )
section->tryOpen();
return *section;
}
void tryOpen() {
if( !isComplete() && (m_filters.empty() || m_filters[0].empty() || m_filters[0] == m_nameAndLocation.name ) )
open();
}
void addInitialFilters( std::vector<std::string> const& filters ) {
if( !filters.empty() ) {
m_filters.push_back(""); // Root - should never be consulted
m_filters.push_back(""); // Test Case - not a section filter
std::copy( filters.begin(), filters.end(), std::back_inserter( m_filters ) );
}
}
void addNextFilters( std::vector<std::string> const& filters ) {
if( filters.size() > 1 )
std::copy( filters.begin()+1, filters.end(), std::back_inserter( m_filters ) );
}
};
class IndexTracker : public TrackerBase {
int m_size;
int m_index;
public:
IndexTracker( std::string const& name, TrackerContext& ctx, ITracker* parent, int size )
: TrackerBase( name, ctx, parent ),
IndexTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent, int size )
: TrackerBase( nameAndLocation, ctx, parent ),
m_size( size ),
m_index( -1 )
{}
@ -274,17 +310,17 @@ namespace TestCaseTracking {
virtual bool isIndexTracker() const CATCH_OVERRIDE { return true; }
static IndexTracker& acquire( TrackerContext& ctx, std::string const& name, int size ) {
static IndexTracker& acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation, int size ) {
IndexTracker* tracker = CATCH_NULL;
ITracker& currentTracker = ctx.currentTracker();
if( ITracker* childTracker = currentTracker.findChild( name ) ) {
if( ITracker* childTracker = currentTracker.findChild( nameAndLocation ) ) {
assert( childTracker );
assert( childTracker->isIndexTracker() );
tracker = static_cast<IndexTracker*>( childTracker );
}
else {
tracker = new IndexTracker( name, ctx, &currentTracker, size );
tracker = new IndexTracker( nameAndLocation, ctx, &currentTracker, size );
currentTracker.addChild( tracker );
}
@ -312,7 +348,7 @@ namespace TestCaseTracking {
};
inline ITracker& TrackerContext::startRun() {
m_rootTracker = new SectionTracker( "{root}", *this, CATCH_NULL );
m_rootTracker = new SectionTracker( NameAndLocation( "{root}", CATCH_INTERNAL_LINEINFO ), *this, CATCH_NULL );
m_currentTracker = CATCH_NULL;
m_runState = Executing;
return *m_rootTracker;