Files
Catch2/src/catch2/internal/catch_test_case_tracker.cpp
T

235 lines
7.2 KiB
C++
Raw Normal View History

// Copyright Catch2 Authors
// Distributed under the Boost Software License, Version 1.0.
2022-10-28 11:22:53 +02:00
// (See accompanying file LICENSE.txt or copy at
// https://www.boost.org/LICENSE_1_0.txt)
// SPDX-License-Identifier: BSL-1.0
2020-03-30 10:34:21 +02:00
#include <catch2/internal/catch_test_case_tracker.hpp>
2017-07-19 10:13:47 +02:00
2020-03-30 10:34:21 +02:00
#include <catch2/internal/catch_enforce.hpp>
#include <catch2/internal/catch_string_manip.hpp>
#include <catch2/internal/catch_move_and_forward.hpp>
2017-07-19 10:13:47 +02:00
#include <algorithm>
2018-04-18 14:59:10 +02:00
#include <cassert>
2017-07-19 10:13:47 +02:00
2017-09-07 16:51:33 +02:00
#if defined(__clang__)
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wexit-time-destructors"
#endif
2017-07-19 10:13:47 +02:00
namespace Catch {
namespace TestCaseTracking {
2023-01-27 22:12:57 +01:00
NameAndLocation::NameAndLocation( std::string&& _name, SourceLineInfo const& _location )
: name( CATCH_MOVE(_name) ),
2017-07-19 10:13:47 +02:00
location( _location )
{}
2017-09-07 16:51:33 +02:00
ITracker::~ITracker() = default;
2021-06-17 23:51:25 +02:00
void ITracker::markAsNeedingAnotherRun() {
m_runState = NeedsAnotherRun;
}
void ITracker::addChild( ITrackerPtr&& child ) {
m_children.push_back( CATCH_MOVE(child) );
2020-07-27 19:53:54 +02:00
}
ITracker* ITracker::findChild( NameAndLocationRef const& nameAndLocation ) {
2020-07-27 19:53:54 +02:00
auto it = std::find_if(
m_children.begin(),
m_children.end(),
[&nameAndLocation]( ITrackerPtr const& tracker ) {
2023-01-27 22:12:57 +01:00
return tracker->nameAndLocation() == nameAndLocation;
2020-07-27 19:53:54 +02:00
} );
return ( it != m_children.end() ) ? it->get() : nullptr;
2020-07-27 19:53:54 +02:00
}
bool ITracker::isSectionTracker() const { return false; }
bool ITracker::isGeneratorTracker() const { return false; }
2020-07-27 19:53:54 +02:00
2021-06-17 23:51:25 +02:00
bool ITracker::isOpen() const {
return m_runState != NotStarted && !isComplete();
}
bool ITracker::hasStarted() const { return m_runState != NotStarted; }
void ITracker::openChild() {
if (m_runState != ExecutingChildren) {
m_runState = ExecutingChildren;
if (m_parent) {
m_parent->openChild();
}
}
}
2017-07-19 10:13:47 +02:00
ITracker& TrackerContext::startRun() {
using namespace std::string_literals;
m_rootTracker = Catch::Detail::make_unique<SectionTracker>(
NameAndLocation( "{root}"s, CATCH_INTERNAL_LINEINFO ),
*this,
nullptr );
2017-07-19 10:13:47 +02:00
m_currentTracker = nullptr;
m_runState = Executing;
return *m_rootTracker;
}
void TrackerContext::completeCycle() {
m_runState = CompletedCycle;
}
bool TrackerContext::completedCycle() const {
return m_runState == CompletedCycle;
}
void TrackerContext::setCurrentTracker( ITracker* tracker ) {
m_currentTracker = tracker;
}
2023-01-27 22:12:57 +01:00
TrackerBase::TrackerBase( NameAndLocation&& nameAndLocation, TrackerContext& ctx, ITracker* parent ):
ITracker(CATCH_MOVE(nameAndLocation), parent),
2021-06-09 22:09:00 +02:00
m_ctx( ctx )
2017-07-19 10:13:47 +02:00
{}
bool TrackerBase::isComplete() const {
return m_runState == CompletedSuccessfully || m_runState == Failed;
}
void TrackerBase::open() {
m_runState = Executing;
moveToThis();
if( m_parent )
m_parent->openChild();
}
void TrackerBase::close() {
// Close any still open children (e.g. generators)
while( &m_ctx.currentTracker() != this )
m_ctx.currentTracker().close();
switch( m_runState ) {
case NeedsAnotherRun:
2017-07-25 17:16:28 +02:00
break;
2017-07-19 10:13:47 +02:00
case Executing:
m_runState = CompletedSuccessfully;
break;
case ExecutingChildren:
if( std::all_of(m_children.begin(), m_children.end(), [](ITrackerPtr const& t){ return t->isComplete(); }) )
2017-07-19 10:13:47 +02:00
m_runState = CompletedSuccessfully;
break;
case NotStarted:
case CompletedSuccessfully:
case Failed:
CATCH_INTERNAL_ERROR( "Illogical state: " << m_runState );
default:
CATCH_INTERNAL_ERROR( "Unknown state: " << m_runState );
}
moveToParent();
m_ctx.completeCycle();
}
void TrackerBase::fail() {
m_runState = Failed;
if( m_parent )
m_parent->markAsNeedingAnotherRun();
moveToParent();
m_ctx.completeCycle();
}
void TrackerBase::moveToParent() {
assert( m_parent );
m_ctx.setCurrentTracker( m_parent );
}
void TrackerBase::moveToThis() {
m_ctx.setCurrentTracker( this );
}
2023-01-27 22:12:57 +01:00
SectionTracker::SectionTracker( NameAndLocation&& nameAndLocation, TrackerContext& ctx, ITracker* parent )
: TrackerBase( CATCH_MOVE(nameAndLocation), ctx, parent ),
m_trimmed_name(trim(StringRef(ITracker::nameAndLocation().name)))
2017-07-19 10:13:47 +02:00
{
if( parent ) {
2023-01-27 22:12:57 +01:00
while ( !parent->isSectionTracker() ) {
parent = parent->parent();
2023-01-27 22:12:57 +01:00
}
2017-07-19 10:13:47 +02:00
SectionTracker& parentSection = static_cast<SectionTracker&>( *parent );
addNextFilters( parentSection.m_filters );
}
}
bool SectionTracker::isComplete() const {
bool complete = true;
if (m_filters.empty()
|| m_filters[0].empty()
|| std::find(m_filters.begin(), m_filters.end(), m_trimmed_name) != m_filters.end()) {
complete = TrackerBase::isComplete();
}
return complete;
}
2017-07-19 10:13:47 +02:00
bool SectionTracker::isSectionTracker() const { return true; }
SectionTracker& SectionTracker::acquire( TrackerContext& ctx, NameAndLocationRef const& nameAndLocation ) {
2023-01-27 22:12:57 +01:00
SectionTracker* tracker;
2017-07-19 10:13:47 +02:00
ITracker& currentTracker = ctx.currentTracker();
if ( ITracker* childTracker =
currentTracker.findChild( nameAndLocation ) ) {
2017-07-19 10:13:47 +02:00
assert( childTracker );
assert( childTracker->isSectionTracker() );
2023-01-27 22:12:57 +01:00
tracker = static_cast<SectionTracker*>( childTracker );
} else {
2023-01-27 22:12:57 +01:00
auto newTracker = Catch::Detail::make_unique<SectionTracker>(
NameAndLocation{ static_cast<std::string>(nameAndLocation.name),
nameAndLocation.location },
ctx,
&currentTracker );
tracker = newTracker.get();
currentTracker.addChild( CATCH_MOVE( newTracker ) );
2017-07-19 10:13:47 +02:00
}
2023-01-27 22:12:57 +01:00
if ( !ctx.completedCycle() ) {
tracker->tryOpen();
}
return *tracker;
2017-07-19 10:13:47 +02:00
}
void SectionTracker::tryOpen() {
if( !isComplete() )
2017-07-19 10:13:47 +02:00
open();
}
void SectionTracker::addInitialFilters( std::vector<std::string> const& filters ) {
if( !filters.empty() ) {
m_filters.reserve( m_filters.size() + filters.size() + 2 );
m_filters.emplace_back(StringRef{}); // Root - should never be consulted
m_filters.emplace_back(StringRef{}); // Test Case - not a section filter
2017-07-19 10:13:47 +02:00
m_filters.insert( m_filters.end(), filters.begin(), filters.end() );
}
}
void SectionTracker::addNextFilters( std::vector<StringRef> const& filters ) {
2017-07-19 10:13:47 +02:00
if( filters.size() > 1 )
m_filters.insert( m_filters.end(), filters.begin()+1, filters.end() );
2017-07-19 10:13:47 +02:00
}
StringRef SectionTracker::trimmedName() const {
return m_trimmed_name;
}
2017-07-19 10:13:47 +02:00
} // namespace TestCaseTracking
} // namespace Catch
2017-09-07 16:51:33 +02:00
#if defined(__clang__)
# pragma clang diagnostic pop
#endif