2020-08-30 15:43:45 +02:00
|
|
|
|
|
|
|
|
// 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
|
2020-08-30 15:43:45 +02:00
|
|
|
// 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>
|
2021-08-13 14:16:30 +02:00
|
|
|
#include <catch2/internal/catch_move_and_forward.hpp>
|
2017-08-01 18:46:33 +02:00
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-04 22:57:34 +01:00
|
|
|
void ITracker::addChild( ITrackerPtr&& child ) {
|
2021-08-13 14:16:30 +02:00
|
|
|
m_children.push_back( CATCH_MOVE(child) );
|
2020-07-27 19:53:54 +02:00
|
|
|
}
|
|
|
|
|
|
2023-02-19 23:53:34 +01: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
|
|
|
} );
|
2020-12-04 21:37:19 +01:00
|
|
|
return ( it != m_children.end() ) ? it->get() : nullptr;
|
2020-07-27 19:53:54 +02:00
|
|
|
}
|
|
|
|
|
|
2021-06-10 00:02:40 +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() {
|
2020-07-27 20:08:44 +02:00
|
|
|
using namespace std::string_literals;
|
2020-12-04 22:57:34 +01:00
|
|
|
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:
|
2019-06-29 18:02:28 +02:00
|
|
|
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 ),
|
2023-02-20 00:12:54 +01:00
|
|
|
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() ) {
|
2021-06-09 22:01:49 +02:00
|
|
|
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 );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-07 16:40:23 +01:00
|
|
|
bool SectionTracker::isComplete() const {
|
|
|
|
|
bool complete = true;
|
|
|
|
|
|
2020-07-04 17:45:30 +02:00
|
|
|
if (m_filters.empty()
|
2021-09-09 11:04:34 +02:00
|
|
|
|| m_filters[0].empty()
|
2019-09-09 11:30:45 +02:00
|
|
|
|| std::find(m_filters.begin(), m_filters.end(), m_trimmed_name) != m_filters.end()) {
|
2019-01-07 16:40:23 +01:00
|
|
|
complete = TrackerBase::isComplete();
|
2019-09-09 11:30:45 +02:00
|
|
|
}
|
2019-01-07 16:40:23 +01:00
|
|
|
return complete;
|
|
|
|
|
}
|
|
|
|
|
|
2017-07-19 10:13:47 +02:00
|
|
|
bool SectionTracker::isSectionTracker() const { return true; }
|
|
|
|
|
|
2023-02-19 23:53:34 +01:00
|
|
|
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();
|
2020-12-04 21:37:19 +01:00
|
|
|
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 );
|
2020-12-04 21:37:19 +01:00
|
|
|
} 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,
|
|
|
|
|
¤tTracker );
|
|
|
|
|
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() {
|
2019-09-09 11:30:45 +02:00
|
|
|
if( !isComplete() )
|
2017-07-19 10:13:47 +02:00
|
|
|
open();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SectionTracker::addInitialFilters( std::vector<std::string> const& filters ) {
|
|
|
|
|
if( !filters.empty() ) {
|
2019-09-09 11:30:45 +02:00
|
|
|
m_filters.reserve( m_filters.size() + filters.size() + 2 );
|
2021-09-09 11:04:34 +02:00
|
|
|
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() );
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-09-09 11:04:34 +02:00
|
|
|
void SectionTracker::addNextFilters( std::vector<StringRef> const& filters ) {
|
2017-07-19 10:13:47 +02:00
|
|
|
if( filters.size() > 1 )
|
2019-09-09 11:30:45 +02:00
|
|
|
m_filters.insert( m_filters.end(), filters.begin()+1, filters.end() );
|
2017-07-19 10:13:47 +02:00
|
|
|
}
|
|
|
|
|
|
2021-09-09 11:04:34 +02:00
|
|
|
StringRef SectionTracker::trimmedName() const {
|
2020-10-22 14:20:47 +02:00
|
|
|
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
|