First cut of -c/—section option for running specific sections
diff --git a/include/internal/catch_commandline.hpp b/include/internal/catch_commandline.hpp
index 89eced3..adee52b 100644
--- a/include/internal/catch_commandline.hpp
+++ b/include/internal/catch_commandline.hpp
@@ -23,6 +23,7 @@
config.abortAfter = x;
}
inline void addTestOrTags( ConfigData& config, std::string const& _testSpec ) { config.testsOrTags.push_back( _testSpec ); }
+ inline void addSectionToRun( ConfigData& config, std::string const& sectionName ) { config.sectionsToRun.push_back( sectionName ); }
inline void addReporterName( ConfigData& config, std::string const& _reporterName ) { config.reporterNames.push_back( _reporterName ); }
inline void addWarning( ConfigData& config, std::string const& _warning ) {
@@ -176,6 +177,10 @@
.describe( "adds a tag for the filename" )
.bind( &ConfigData::filenamesAsTags );
+ cli["-c"]["--section"]
+ .describe( "specify section to run" )
+ .bind( &addSectionToRun, "section name" );
+
// Less common commands which don't have a short form
cli["--list-test-names-only"]
.describe( "list all/matching test cases names only" )
diff --git a/include/internal/catch_config.hpp b/include/internal/catch_config.hpp
index 72b0f6c..7d7887a 100644
--- a/include/internal/catch_config.hpp
+++ b/include/internal/catch_config.hpp
@@ -74,6 +74,7 @@
std::vector<std::string> reporterNames;
std::vector<std::string> testsOrTags;
+ std::vector<std::string> sectionsToRun;
};
@@ -115,7 +116,8 @@
bool shouldDebugBreak() const { return m_data.shouldDebugBreak; }
- std::vector<std::string> getReporterNames() const { return m_data.reporterNames; }
+ std::vector<std::string> const& getReporterNames() const { return m_data.reporterNames; }
+ std::vector<std::string> const& getSectionsToRun() const CATCH_OVERRIDE { return m_data.sectionsToRun; }
int abortAfter() const { return m_data.abortAfter; }
diff --git a/include/internal/catch_interfaces_config.h b/include/internal/catch_interfaces_config.h
index 17914b4..768550b 100644
--- a/include/internal/catch_interfaces_config.h
+++ b/include/internal/catch_interfaces_config.h
@@ -62,6 +62,8 @@
virtual RunTests::InWhatOrder runOrder() const = 0;
virtual unsigned int rngSeed() const = 0;
virtual UseColour::YesOrNo useColour() const = 0;
+ virtual std::vector<std::string> const& getSectionsToRun() const = 0;
+
};
}
diff --git a/include/internal/catch_run_context.hpp b/include/internal/catch_run_context.hpp
index d37bdba..e458afc 100644
--- a/include/internal/catch_run_context.hpp
+++ b/include/internal/catch_run_context.hpp
@@ -97,10 +97,11 @@
do {
- m_trackerContext.startRun();
+ ITracker& rootTracker = m_trackerContext.startRun();
+ dynamic_cast<SectionTracker&>( rootTracker ).addInitialFilters( m_config->getSectionsToRun() );
do {
m_trackerContext.startCycle();
- m_testCaseTracker = &SectionTracker::acquire( m_trackerContext, testInfo.name );
+ m_testCaseTracker = &SectionTracker::acquire( m_trackerContext, TestCaseTracking::NameAndLocation( testInfo.name, testInfo.lineInfo ) );
runCurrentTest( redirectedCout, redirectedCerr );
}
while( !m_testCaseTracker->isSuccessfullyCompleted() && !aborting() );
@@ -155,10 +156,7 @@
Counts& assertions
)
{
- std::ostringstream oss;
- oss << sectionInfo.name << "@" << sectionInfo.lineInfo;
-
- ITracker& sectionTracker = SectionTracker::acquire( m_trackerContext, oss.str() );
+ ITracker& sectionTracker = SectionTracker::acquire( m_trackerContext, TestCaseTracking::NameAndLocation( sectionInfo.name, sectionInfo.lineInfo ) );
if( !sectionTracker.isOpen() )
return false;
m_activeSections.push_back( §ionTracker );
diff --git a/include/internal/catch_test_case_tracker.hpp b/include/internal/catch_test_case_tracker.hpp
index 3973e7b..d2b14a2 100644
--- a/include/internal/catch_test_case_tracker.hpp
+++ b/include/internal/catch_test_case_tracker.hpp
@@ -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 @@
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 @@
virtual bool isIndexTracker() const = 0;
};
- class TrackerContext {
+ class TrackerContext {
enum RunState {
NotStarted,
@@ -110,30 +120,32 @@
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 @@
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 @@
};
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, ¤tTracker );
+ section = new SectionTracker( nameAndLocation, ctx, ¤tTracker );
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 @@
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, ¤tTracker, size );
+ tracker = new IndexTracker( nameAndLocation, ctx, ¤tTracker, size );
currentTracker.addChild( tracker );
}
@@ -312,7 +348,7 @@
};
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;
diff --git a/projects/SelfTest/PartTrackerTests.cpp b/projects/SelfTest/PartTrackerTests.cpp
index 2925635..45f4cf1 100644
--- a/projects/SelfTest/PartTrackerTests.cpp
+++ b/projects/SelfTest/PartTrackerTests.cpp
@@ -36,16 +36,21 @@
// REQUIRE( C_A_T_C_H_Context().i() == 42 );
//}
+Catch::TestCaseTracking::NameAndLocation makeNAL( std::string const& name ) {
+ return Catch::TestCaseTracking::NameAndLocation( name, Catch::SourceLineInfo() );
+}
+
TEST_CASE( "Tracker", "" ) {
TrackerContext ctx;
ctx.startRun();
ctx.startCycle();
- ITracker& testCase = SectionTracker::acquire( ctx, "Testcase" );
+
+ ITracker& testCase = SectionTracker::acquire( ctx, makeNAL( "Testcase" ) );
REQUIRE( testCase.isOpen() );
- ITracker& s1 = SectionTracker::acquire( ctx, "S1" );
+ ITracker& s1 = SectionTracker::acquire( ctx, makeNAL( "S1" ) );
REQUIRE( s1.isOpen() );
SECTION( "successfully close one section", "" ) {
@@ -70,10 +75,10 @@
SECTION( "re-enter after failed section", "" ) {
ctx.startCycle();
- ITracker& testCase2 = SectionTracker::acquire( ctx, "Testcase" );
+ ITracker& testCase2 = SectionTracker::acquire( ctx, makeNAL( "Testcase" ) );
REQUIRE( testCase2.isOpen() );
- ITracker& s1b = SectionTracker::acquire( ctx, "S1" );
+ ITracker& s1b = SectionTracker::acquire( ctx, makeNAL( "S1" ) );
REQUIRE( s1b.isOpen() == false );
testCase2.close();
@@ -83,13 +88,13 @@
}
SECTION( "re-enter after failed section and find next section", "" ) {
ctx.startCycle();
- ITracker& testCase2 = SectionTracker::acquire( ctx, "Testcase" );
+ ITracker& testCase2 = SectionTracker::acquire( ctx, makeNAL( "Testcase" ) );
REQUIRE( testCase2.isOpen() );
- ITracker& s1b = SectionTracker::acquire( ctx, "S1" );
+ ITracker& s1b = SectionTracker::acquire( ctx, makeNAL( "S1" ) );
REQUIRE( s1b.isOpen() == false );
- ITracker& s2 = SectionTracker::acquire( ctx, "S2" );
+ ITracker& s2 = SectionTracker::acquire( ctx, makeNAL( "S2" ) );
REQUIRE( s2.isOpen() );
s2.close();
@@ -104,7 +109,7 @@
SECTION( "successfully close one section, then find another", "" ) {
s1.close();
- ITracker& s2 = SectionTracker::acquire( ctx, "S2" );
+ ITracker& s2 = SectionTracker::acquire( ctx, makeNAL( "S2" ) );
REQUIRE( s2.isOpen() == false );
testCase.close();
@@ -112,13 +117,13 @@
SECTION( "Re-enter - skips S1 and enters S2", "" ) {
ctx.startCycle();
- ITracker& testCase2 = SectionTracker::acquire( ctx, "Testcase" );
+ ITracker& testCase2 = SectionTracker::acquire( ctx, makeNAL( "Testcase" ) );
REQUIRE( testCase2.isOpen() );
- ITracker& s1b = SectionTracker::acquire( ctx, "S1" );
+ ITracker& s1b = SectionTracker::acquire( ctx, makeNAL( "S1" ) );
REQUIRE( s1b.isOpen() == false );
- ITracker& s2b = SectionTracker::acquire( ctx, "S2" );
+ ITracker& s2b = SectionTracker::acquire( ctx, makeNAL( "S2" ) );
REQUIRE( s2b.isOpen() );
REQUIRE( ctx.completedCycle() == false );
@@ -145,13 +150,13 @@
// Need a final cycle
ctx.startCycle();
- ITracker& testCase3 = SectionTracker::acquire( ctx, "Testcase" );
+ ITracker& testCase3 = SectionTracker::acquire( ctx, makeNAL( "Testcase" ) );
REQUIRE( testCase3.isOpen() );
- ITracker& s1c = SectionTracker::acquire( ctx, "S1" );
+ ITracker& s1c = SectionTracker::acquire( ctx, makeNAL( "S1" ) );
REQUIRE( s1c.isOpen() == false );
- ITracker& s2c = SectionTracker::acquire( ctx, "S2" );
+ ITracker& s2c = SectionTracker::acquire( ctx, makeNAL( "S2" ) );
REQUIRE( s2c.isOpen() == false );
testCase3.close();
@@ -161,7 +166,7 @@
}
SECTION( "open a nested section", "" ) {
- ITracker& s2 = SectionTracker::acquire( ctx, "S2" );
+ ITracker& s2 = SectionTracker::acquire( ctx, makeNAL( "S2" ) );
REQUIRE( s2.isOpen() );
s2.close();
@@ -177,7 +182,7 @@
}
SECTION( "start a generator", "" ) {
- IndexTracker& g1 = IndexTracker::acquire( ctx, "G1", 2 );
+ IndexTracker& g1 = IndexTracker::acquire( ctx, makeNAL( "G1" ), 2 );
REQUIRE( g1.isOpen() );
REQUIRE( g1.index() == 0 );
@@ -193,14 +198,14 @@
SECTION( "Re-enter for second generation", "" ) {
ctx.startCycle();
- ITracker& testCase2 = SectionTracker::acquire( ctx, "Testcase" );
+ ITracker& testCase2 = SectionTracker::acquire( ctx, makeNAL( "Testcase" ) );
REQUIRE( testCase2.isOpen() );
- ITracker& s1b = SectionTracker::acquire( ctx, "S1" );
+ ITracker& s1b = SectionTracker::acquire( ctx, makeNAL( "S1" ) );
REQUIRE( s1b.isOpen() );
- IndexTracker& g1b = IndexTracker::acquire( ctx, "G1", 2 );
+ IndexTracker& g1b = IndexTracker::acquire( ctx, makeNAL( "G1" ), 2 );
REQUIRE( g1b.isOpen() );
REQUIRE( g1b.index() == 1 );
@@ -214,7 +219,7 @@
}
}
SECTION( "Start a new inner section", "" ) {
- ITracker& s2 = SectionTracker::acquire( ctx, "S2" );
+ ITracker& s2 = SectionTracker::acquire( ctx, makeNAL( "S2" ) );
REQUIRE( s2.isOpen() );
s2.close();
@@ -228,19 +233,19 @@
SECTION( "Re-enter for second generation", "" ) {
ctx.startCycle();
- ITracker& testCase2 = SectionTracker::acquire( ctx, "Testcase" );
+ ITracker& testCase2 = SectionTracker::acquire( ctx, makeNAL( "Testcase" ) );
REQUIRE( testCase2.isOpen() );
- ITracker& s1b = SectionTracker::acquire( ctx, "S1" );
+ ITracker& s1b = SectionTracker::acquire( ctx, makeNAL( "S1" ) );
REQUIRE( s1b.isOpen() );
// generator - next value
- IndexTracker& g1b = IndexTracker::acquire( ctx, "G1", 2 );
+ IndexTracker& g1b = IndexTracker::acquire( ctx, makeNAL( "G1" ), 2 );
REQUIRE( g1b.isOpen() );
REQUIRE( g1b.index() == 1 );
// inner section again
- ITracker& s2b = SectionTracker::acquire( ctx, "S2" );
+ ITracker& s2b = SectionTracker::acquire( ctx, makeNAL( "S2" ) );
REQUIRE( s2b.isOpen() );
s2b.close();
@@ -256,7 +261,7 @@
}
SECTION( "Fail an inner section", "" ) {
- ITracker& s2 = SectionTracker::acquire( ctx, "S2" );
+ ITracker& s2 = SectionTracker::acquire( ctx, makeNAL( "S2" ) );
REQUIRE( s2.isOpen() );
s2.fail();
@@ -271,19 +276,19 @@
SECTION( "Re-enter for second generation", "" ) {
ctx.startCycle();
- ITracker& testCase2 = SectionTracker::acquire( ctx, "Testcase" );
+ ITracker& testCase2 = SectionTracker::acquire( ctx, makeNAL( "Testcase" ) );
REQUIRE( testCase2.isOpen() );
- ITracker& s1b = SectionTracker::acquire( ctx, "S1" );
+ ITracker& s1b = SectionTracker::acquire( ctx, makeNAL( "S1" ) );
REQUIRE( s1b.isOpen() );
// generator - still same value
- IndexTracker& g1b = IndexTracker::acquire( ctx, "G1", 2 );
+ IndexTracker& g1b = IndexTracker::acquire( ctx, makeNAL( "G1" ), 2 );
REQUIRE( g1b.isOpen() );
REQUIRE( g1b.index() == 0 );
// inner section again - this time won't open
- ITracker& s2b = SectionTracker::acquire( ctx, "S2" );
+ ITracker& s2b = SectionTracker::acquire( ctx, makeNAL( "S2" ) );
REQUIRE( s2b.isOpen() == false );
s1b.close();
@@ -295,19 +300,19 @@
// Another cycle - now should complete
ctx.startCycle();
- ITracker& testCase3 = SectionTracker::acquire( ctx, "Testcase" );
+ ITracker& testCase3 = SectionTracker::acquire( ctx, makeNAL( "Testcase" ) );
REQUIRE( testCase3.isOpen() );
- ITracker& s1c = SectionTracker::acquire( ctx, "S1" );
+ ITracker& s1c = SectionTracker::acquire( ctx, makeNAL( "S1" ) );
REQUIRE( s1c.isOpen() );
// generator - now next value
- IndexTracker& g1c = IndexTracker::acquire( ctx, "G1", 2 );
+ IndexTracker& g1c = IndexTracker::acquire( ctx, makeNAL( "G1" ), 2 );
REQUIRE( g1c.isOpen() );
REQUIRE( g1c.index() == 1 );
// inner section - now should open again
- ITracker& s2c = SectionTracker::acquire( ctx, "S2" );
+ ITracker& s2c = SectionTracker::acquire( ctx, makeNAL( "S2" ) );
REQUIRE( s2c.isOpen() );
s2c.close();