mirror of
https://github.com/catchorg/Catch2.git
synced 2024-11-22 13:26:10 +01:00
Internal linkage for generator trackers
This commit is contained in:
parent
72f3ce4db5
commit
3c8fb6bbb2
@ -26,135 +26,143 @@
|
|||||||
namespace Catch {
|
namespace Catch {
|
||||||
|
|
||||||
namespace Generators {
|
namespace Generators {
|
||||||
struct GeneratorTracker : TestCaseTracking::TrackerBase, IGeneratorTracker {
|
namespace {
|
||||||
GeneratorBasePtr m_generator;
|
struct GeneratorTracker : TestCaseTracking::TrackerBase,
|
||||||
|
IGeneratorTracker {
|
||||||
|
GeneratorBasePtr m_generator;
|
||||||
|
|
||||||
GeneratorTracker( TestCaseTracking::NameAndLocation&& nameAndLocation, TrackerContext& ctx, ITracker* parent )
|
GeneratorTracker(
|
||||||
: TrackerBase( CATCH_MOVE(nameAndLocation), ctx, parent )
|
TestCaseTracking::NameAndLocation&& nameAndLocation,
|
||||||
{}
|
TrackerContext& ctx,
|
||||||
~GeneratorTracker() override;
|
ITracker* parent ):
|
||||||
|
TrackerBase( CATCH_MOVE( nameAndLocation ), ctx, parent ) {}
|
||||||
|
~GeneratorTracker() override;
|
||||||
|
|
||||||
static GeneratorTracker* acquire( TrackerContext& ctx, TestCaseTracking::NameAndLocationRef const& nameAndLocation ) {
|
static GeneratorTracker*
|
||||||
GeneratorTracker* tracker;
|
acquire( TrackerContext& ctx,
|
||||||
|
TestCaseTracking::NameAndLocationRef const&
|
||||||
|
nameAndLocation ) {
|
||||||
|
GeneratorTracker* tracker;
|
||||||
|
|
||||||
ITracker& currentTracker = ctx.currentTracker();
|
ITracker& currentTracker = ctx.currentTracker();
|
||||||
// Under specific circumstances, the generator we want
|
// Under specific circumstances, the generator we want
|
||||||
// to acquire is also the current tracker. If this is
|
// to acquire is also the current tracker. If this is
|
||||||
// the case, we have to avoid looking through current
|
// the case, we have to avoid looking through current
|
||||||
// tracker's children, and instead return the current
|
// tracker's children, and instead return the current
|
||||||
// tracker.
|
// tracker.
|
||||||
// A case where this check is important is e.g.
|
// A case where this check is important is e.g.
|
||||||
// for (int i = 0; i < 5; ++i) {
|
// for (int i = 0; i < 5; ++i) {
|
||||||
// int n = GENERATE(1, 2);
|
// int n = GENERATE(1, 2);
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// without it, the code above creates 5 nested generators.
|
// without it, the code above creates 5 nested generators.
|
||||||
if ( currentTracker.nameAndLocation() == nameAndLocation ) {
|
if ( currentTracker.nameAndLocation() == nameAndLocation ) {
|
||||||
auto thisTracker =
|
auto thisTracker = currentTracker.parent()->findChild(
|
||||||
currentTracker.parent()->findChild( nameAndLocation );
|
nameAndLocation );
|
||||||
assert( thisTracker );
|
assert( thisTracker );
|
||||||
assert( thisTracker->isGeneratorTracker() );
|
assert( thisTracker->isGeneratorTracker() );
|
||||||
tracker = static_cast<GeneratorTracker*>( thisTracker );
|
tracker = static_cast<GeneratorTracker*>( thisTracker );
|
||||||
} else if ( ITracker* childTracker =
|
} else if ( ITracker* childTracker =
|
||||||
currentTracker.findChild( nameAndLocation ) ) {
|
currentTracker.findChild(
|
||||||
assert( childTracker );
|
nameAndLocation ) ) {
|
||||||
assert( childTracker->isGeneratorTracker() );
|
assert( childTracker );
|
||||||
tracker = static_cast<GeneratorTracker*>( childTracker );
|
assert( childTracker->isGeneratorTracker() );
|
||||||
} else {
|
tracker =
|
||||||
return nullptr;
|
static_cast<GeneratorTracker*>( childTracker );
|
||||||
|
} else {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( !tracker->isComplete() ) { tracker->open(); }
|
||||||
|
|
||||||
|
return tracker;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( !tracker->isComplete() ) {
|
// TrackerBase interface
|
||||||
tracker->open();
|
bool isGeneratorTracker() const override { return true; }
|
||||||
|
auto hasGenerator() const -> bool override {
|
||||||
|
return !!m_generator;
|
||||||
}
|
}
|
||||||
|
void close() override {
|
||||||
return tracker;
|
TrackerBase::close();
|
||||||
}
|
// If a generator has a child (it is followed by a section)
|
||||||
|
// and none of its children have started, then we must wait
|
||||||
// TrackerBase interface
|
// until later to start consuming its values.
|
||||||
bool isGeneratorTracker() const override { return true; }
|
// This catches cases where `GENERATE` is placed between two
|
||||||
auto hasGenerator() const -> bool override {
|
// `SECTION`s.
|
||||||
return !!m_generator;
|
// **The check for m_children.empty cannot be removed**.
|
||||||
}
|
// doing so would break `GENERATE` _not_ followed by
|
||||||
void close() override {
|
// `SECTION`s.
|
||||||
TrackerBase::close();
|
const bool should_wait_for_child = [&]() {
|
||||||
// If a generator has a child (it is followed by a section)
|
// No children -> nobody to wait for
|
||||||
// and none of its children have started, then we must wait
|
if ( m_children.empty() ) { return false; }
|
||||||
// until later to start consuming its values.
|
// If at least one child started executing, don't wait
|
||||||
// This catches cases where `GENERATE` is placed between two
|
if ( std::find_if(
|
||||||
// `SECTION`s.
|
m_children.begin(),
|
||||||
// **The check for m_children.empty cannot be removed**.
|
m_children.end(),
|
||||||
// doing so would break `GENERATE` _not_ followed by `SECTION`s.
|
[]( TestCaseTracking::ITrackerPtr const&
|
||||||
const bool should_wait_for_child = [&]() {
|
tracker ) {
|
||||||
// No children -> nobody to wait for
|
return tracker->hasStarted();
|
||||||
if ( m_children.empty() ) {
|
} ) != m_children.end() ) {
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
// If at least one child started executing, don't wait
|
|
||||||
if ( std::find_if(
|
|
||||||
m_children.begin(),
|
|
||||||
m_children.end(),
|
|
||||||
[]( TestCaseTracking::ITrackerPtr const& tracker ) {
|
|
||||||
return tracker->hasStarted();
|
|
||||||
} ) != m_children.end() ) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// No children have started. We need to check if they _can_
|
|
||||||
// start, and thus we should wait for them, or they cannot
|
|
||||||
// start (due to filters), and we shouldn't wait for them
|
|
||||||
ITracker* parent = m_parent;
|
|
||||||
// This is safe: there is always at least one section
|
|
||||||
// tracker in a test case tracking tree
|
|
||||||
while ( !parent->isSectionTracker() ) {
|
|
||||||
parent = parent->parent();
|
|
||||||
}
|
|
||||||
assert( parent &&
|
|
||||||
"Missing root (test case) level section" );
|
|
||||||
|
|
||||||
auto const& parentSection =
|
|
||||||
static_cast<SectionTracker const&>( *parent );
|
|
||||||
auto const& filters = parentSection.getFilters();
|
|
||||||
// No filters -> no restrictions on running sections
|
|
||||||
if ( filters.empty() ) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
for ( auto const& child : m_children ) {
|
|
||||||
if ( child->isSectionTracker() &&
|
|
||||||
std::find(
|
|
||||||
filters.begin(),
|
|
||||||
filters.end(),
|
|
||||||
static_cast<SectionTracker const&>( *child )
|
|
||||||
.trimmedName() ) != filters.end() ) {
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// No children have started. We need to check if they
|
||||||
|
// _can_ start, and thus we should wait for them, or
|
||||||
|
// they cannot start (due to filters), and we shouldn't
|
||||||
|
// wait for them
|
||||||
|
ITracker* parent = m_parent;
|
||||||
|
// This is safe: there is always at least one section
|
||||||
|
// tracker in a test case tracking tree
|
||||||
|
while ( !parent->isSectionTracker() ) {
|
||||||
|
parent = parent->parent();
|
||||||
|
}
|
||||||
|
assert( parent &&
|
||||||
|
"Missing root (test case) level section" );
|
||||||
|
|
||||||
|
auto const& parentSection =
|
||||||
|
static_cast<SectionTracker const&>( *parent );
|
||||||
|
auto const& filters = parentSection.getFilters();
|
||||||
|
// No filters -> no restrictions on running sections
|
||||||
|
if ( filters.empty() ) { return true; }
|
||||||
|
|
||||||
|
for ( auto const& child : m_children ) {
|
||||||
|
if ( child->isSectionTracker() &&
|
||||||
|
std::find( filters.begin(),
|
||||||
|
filters.end(),
|
||||||
|
static_cast<SectionTracker const&>(
|
||||||
|
*child )
|
||||||
|
.trimmedName() ) !=
|
||||||
|
filters.end() ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}();
|
||||||
|
|
||||||
|
// This check is a bit tricky, because m_generator->next()
|
||||||
|
// has a side-effect, where it consumes generator's current
|
||||||
|
// value, but we do not want to invoke the side-effect if
|
||||||
|
// this generator is still waiting for any child to start.
|
||||||
|
assert( m_generator && "Tracker without generator" );
|
||||||
|
if ( should_wait_for_child ||
|
||||||
|
( m_runState == CompletedSuccessfully &&
|
||||||
|
m_generator->countedNext() ) ) {
|
||||||
|
m_children.clear();
|
||||||
|
m_runState = Executing;
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
}();
|
|
||||||
|
|
||||||
// This check is a bit tricky, because m_generator->next()
|
|
||||||
// has a side-effect, where it consumes generator's current
|
|
||||||
// value, but we do not want to invoke the side-effect if
|
|
||||||
// this generator is still waiting for any child to start.
|
|
||||||
assert( m_generator && "Tracker without generator" );
|
|
||||||
if ( should_wait_for_child ||
|
|
||||||
( m_runState == CompletedSuccessfully &&
|
|
||||||
m_generator->countedNext() ) ) {
|
|
||||||
m_children.clear();
|
|
||||||
m_runState = Executing;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// IGeneratorTracker interface
|
// IGeneratorTracker interface
|
||||||
auto getGenerator() const -> GeneratorBasePtr const& override {
|
auto getGenerator() const -> GeneratorBasePtr const& override {
|
||||||
return m_generator;
|
return m_generator;
|
||||||
}
|
}
|
||||||
void setGenerator( GeneratorBasePtr&& generator ) override {
|
void setGenerator( GeneratorBasePtr&& generator ) override {
|
||||||
m_generator = CATCH_MOVE( generator );
|
m_generator = CATCH_MOVE( generator );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
GeneratorTracker::~GeneratorTracker() = default;
|
GeneratorTracker::~GeneratorTracker() = default;
|
||||||
|
} // namespace
|
||||||
}
|
}
|
||||||
|
|
||||||
RunContext::RunContext(IConfig const* _config, IEventListenerPtr&& reporter)
|
RunContext::RunContext(IConfig const* _config, IEventListenerPtr&& reporter)
|
||||||
|
Loading…
Reference in New Issue
Block a user