This commit is contained in:
Martin Hořeňovský
2026-02-15 22:55:48 +01:00
parent 56024c04e4
commit 29c9844f68
12 changed files with 550 additions and 157 deletions
+1 -1
View File
@@ -35,7 +35,7 @@ if(CMAKE_BINARY_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
endif()
project(Catch2
VERSION 3.12.0 # CML version placeholder, don't delete
VERSION 3.13.0 # CML version placeholder, don't delete
LANGUAGES CXX
HOMEPAGE_URL "https://github.com/catchorg/Catch2"
DESCRIPTION "A modern, C++-native, unit test framework."
+2 -2
View File
@@ -365,7 +365,7 @@ There are currently two warnings implemented:
> `UnmatchedTestSpec` was introduced in Catch2 3.0.1.
> `InfiniteGenerators` was introduced in Catch2 vX.Y.Z
> `InfiniteGenerators` was introduced in Catch2 3.13.0
<a id="reporting-timings"></a>
@@ -540,7 +540,7 @@ Prints the command line arguments to stdout
<pre>-g, --generator-index &lt;index in generator&gt;</pre>
<pre>-p, --path-filter &lt;path filter spec&gt;</pre>
> The generator and generic path filtering was added in Catch2 vX.Y.Z
> The generator and generic path filtering was added in Catch2 3.13.0
These arguments allow you to run specific section(s) in a test case, or
only get specific element from a generator. All the variants form a shared
+2 -2
View File
@@ -50,7 +50,7 @@ want to keep doing so in the future, mark the mutated members as `mutable`.
### Section-only filtering with `-c/--section`
> Deprecated in Catch2 vX.Y.Z
> Deprecated in Catch2 3.13.0
Currently, if you use only `-c/--section` parameters to decide which
sections to enter, the filtering ignores generators completely. In the
@@ -63,7 +63,7 @@ means that generators are taken into account.
#### Defaulted `UntypedGeneratorBase::isFinite()`
> Deprecated in Catch2 vX.Y.Z
> Deprecated in Catch2 3.13.0
The `UntypedGeneratorBase` currently provides a default implementation
for `isFinite` that always returns `true`. This was done to keep backwards
+3 -3
View File
@@ -1,7 +1,7 @@
<a id="top"></a>
# How to run specific section/generator
> The generator and generic path filtering was added in Catch2 vX.Y.Z
> The generator and generic path filtering was added in Catch2 3.13.0
Catch2 supports picking specific path through a test case by filtering
sections and generator indices to run through. This is done by using one
@@ -33,7 +33,7 @@ things:
## Old behaviour
> The old behaviour was deprecated in Catch2 vX.Y.Z
> The old behaviour was deprecated in Catch2 3.13.0
```
-c, --section <section name>
@@ -119,7 +119,7 @@ TEST_CASE( "qux" ) {
## New behaviour
> The new behaviour was introduced in Catch2 vX.Y.Z
> The new behaviour was introduced in Catch2 3.13.0
```
-g, --generator-index <index in generator>
+4 -4
View File
@@ -132,7 +132,7 @@ a test case,
> `IteratorGenerator<T>` was introduced in Catch2 2.10.0.
> `ConcatGenerator<T>` was introduced in Catch2 X.Y.Z
> `ConcatGenerator<T>` was introduced in Catch2 3.13.0
The generators also have associated helper functions that infer their
type, making their usage much nicer. These are
@@ -159,7 +159,7 @@ type, making their usage much nicer. These are
> `range()` for floating point numbers has been introduced in Catch2 2.11.0
> `cat` has been introduced in Catch2 X.Y.Z
> `cat` has been introduced in Catch2 3.13.0
And can be used as shown in the example below to create a generator
that returns 100 odd random number:
@@ -288,9 +288,9 @@ struct IGenerator : GeneratorUntypedBase {
};
```
> `skipToNthElementImpl` was added in Catch2 vX.Y.Z
> `skipToNthElementImpl` was added in Catch2 3.13.0
> `isFinite` was added in Catch2 vX.Y.Z
> `isFinite` was added in Catch2 3.13.0
However, to be able to use your custom generator inside `GENERATE`, it
will need to be wrapped inside a `GeneratorWrapper<T>`.
+2 -2
View File
@@ -30,7 +30,7 @@ started" as the extra info.
> `UNSCOPED_INFO` was [introduced](https://github.com/catchorg/Catch2/issues/1522) in Catch2 2.7.0.
> `UNSCOPED_CAPTURE` was introduced in Catch2 X.Y.Z.
> `UNSCOPED_CAPTURE` was introduced in Catch2 3.13.0.
The `UNSCOPED_X` macros are similar to their plain `X` macro counterparts,
with two key differences:
@@ -137,7 +137,7 @@ AS `FAIL`, but does not abort the test
**UNSCOPED_CAPTURE(** _expression1_, _expression2_, ... **)**
> `UNSCOPED_CAPTURE` was introduced in Catch2 X.Y.Z.
> `UNSCOPED_CAPTURE` was introduced in Catch2 3.13.0.
Sometimes you just want to log a value of variable, or expression. For
convenience, we provide the `CAPTURE` macro, that can take a variable,
+27
View File
@@ -2,6 +2,7 @@
# Release notes
**Contents**<br>
[3.13.0](#3130)<br>
[3.12.0](#3120)<br>
[3.11.0](#3110)<br>
[3.10.0](#3100)<br>
@@ -72,6 +73,32 @@
[Even Older versions](#even-older-versions)<br>
## 3.13.0
### Fixes
* `--benchmark-samples 0` no longer hard crashes (#3056)
* The CLI validation fails instead.
* Fixed warning suppression macros being doubly defined when using Clang on Windows (#3060)
### Improvements
* Suppressed static analysis 26426 diagnostic for MSVC (#3057)
* Renamed the internal deprecation macro from `DEPRECATED` to `CATCH_DEPRECATED` to avoid conflicts (#3058)
* Added `UNSCOPED_CAPTURE` macro (#2954)
* Added `ConcatGenerator` to combine multiple separate generator into one
* The short form is `cat`
* Generators can now jump forward to nth element efficiently
* Custom generators that can jump forward efficiently should override `skipToNthElementImpl`
* Generators can declare themselves infinite
* The generator base defaults to declaring itself finite for backwards compatibility
* Custom generators should override `isFinite()` to return the proper value
* Added `--warn InfiniteGenerators` to error out on `GENERATE` being given an infinite generator
* Extended options for section filtering from CLI to include generators
* The user can specify which element from the generator to use in the test case
* See documentation for how the new filters work and how they can be specified
* `MapGenerator` only calls the mapping function if the output will be used
## 3.12.0
### Fixes
+245 -81
View File
@@ -6,8 +6,8 @@
// SPDX-License-Identifier: BSL-1.0
// Catch v3.12.0
// Generated: 2025-12-28 22:27:25.828797
// Catch v3.13.0
// Generated: 2026-02-15 22:55:00.269529
// ----------------------------------------------------------
// This file is an amalgamation of multiple different files.
// You probably shouldn't edit it directly.
@@ -798,6 +798,10 @@ namespace Catch {
lhs.customOptions == rhs.customOptions;
}
bool operator==( PathFilter const& lhs, PathFilter const& rhs ) {
return lhs.type == rhs.type && lhs.filter == rhs.filter;
}
Config::Config( ConfigData const& data ):
m_data( data ) {
// We need to trim filter specs to avoid trouble with superfluous
@@ -807,9 +811,6 @@ namespace Catch {
for (auto& elem : m_data.testsOrTags) {
elem = trim(elem);
}
for (auto& elem : m_data.sectionsToRun) {
elem = trim(elem);
}
// Insert the default reporter if user hasn't asked for a specific one
if ( m_data.reporterSpecifications.empty() ) {
@@ -875,7 +876,8 @@ namespace Catch {
bool Config::listListeners() const { return m_data.listListeners; }
std::vector<std::string> const& Config::getTestsOrTags() const { return m_data.testsOrTags; }
std::vector<std::string> const& Config::getSectionsToRun() const { return m_data.sectionsToRun; }
std::vector<PathFilter> const& Config::getPathFilters() const { return m_data.pathFilters; }
bool Config::useNewFilterBehaviour() const { return m_data.useNewPathFilteringBehaviour; }
std::vector<ReporterSpec> const& Config::getReporterSpecs() const {
return m_data.reporterSpecifications;
@@ -903,6 +905,9 @@ namespace Catch {
bool Config::warnAboutUnmatchedTestSpecs() const {
return !!( m_data.warnings & WarnAbout::UnmatchedTestSpec );
}
bool Config::warnAboutInfiniteGenerators() const {
return !!( m_data.warnings & WarnAbout::InfiniteGenerator );
}
bool Config::zeroTestsCountAsSuccess() const { return m_data.allowZeroTests; }
ShowDurations Config::showDurations() const { return m_data.showDurations; }
double Config::minDuration() const { return m_data.minDuration; }
@@ -1018,7 +1023,9 @@ namespace Catch {
Capturer::Capturer( StringRef macroName,
SourceLineInfo const& lineInfo,
ResultWas::OfType resultType,
StringRef names ) {
StringRef names,
bool isScoped):
m_isScoped(isScoped) {
auto trimmed = [&] (size_t start, size_t end) {
while (names[start] == ',' || isspace(static_cast<unsigned char>(names[start]))) {
++start;
@@ -1079,15 +1086,21 @@ namespace Catch {
}
Capturer::~Capturer() {
assert( m_captured == m_messages.size() );
for (auto const& message : m_messages) {
IResultCapture::popScopedMessage( message.sequence );
if ( m_isScoped ) {
for ( auto const& message : m_messages ) {
IResultCapture::popScopedMessage( message.sequence );
}
}
}
void Capturer::captureValue( size_t index, std::string const& value ) {
assert( index < m_messages.size() );
m_messages[index].message += value;
IResultCapture::pushScopedMessage( CATCH_MOVE( m_messages[index] ) );
if ( m_isScoped ) {
IResultCapture::pushScopedMessage( CATCH_MOVE( m_messages[index] ) );
} else {
IResultCapture::addUnscopedMessage( CATCH_MOVE( m_messages[index] ) );
}
m_captured++;
}
@@ -2384,7 +2397,7 @@ namespace Catch {
}
Version const& libraryVersion() {
static Version version( 3, 12, 0, "", 0 );
static Version version( 3, 13, 0, "", 0 );
return version;
}
@@ -2410,14 +2423,6 @@ namespace Catch {
namespace Generators {
namespace Detail {
[[noreturn]]
void throw_generator_exception(char const* msg) {
Catch::throw_exception(GeneratorException{ msg });
}
} // end namespace Detail
GeneratorUntypedBase::~GeneratorUntypedBase() = default;
IGeneratorTracker* acquireGeneratorTracker(StringRef generatorName, SourceLineInfo const& lineInfo ) {
@@ -2465,6 +2470,27 @@ namespace Catch {
m_current_number = m_pimpl->dist( m_pimpl->rng );
return true;
}
bool RandomFloatingGenerator<long double>::isFinite() const {
return false;
}
} // namespace Generators
} // namespace Catch
namespace Catch {
namespace Generators {
namespace Detail {
[[noreturn]]
void throw_generator_exception( char const* msg ) {
Catch::throw_exception( GeneratorException{ msg } );
}
} // namespace Detail
} // namespace Generators
} // namespace Catch
@@ -2498,6 +2524,7 @@ namespace Catch {
#include <string>
namespace Catch {
@@ -2512,6 +2539,31 @@ namespace Catch {
return ret;
}
void GeneratorUntypedBase::skipToNthElementImpl( std::size_t n ) {
for ( size_t i = m_currentElementIndex; i < n; ++i ) {
bool isValid = next();
if ( !isValid ) {
Detail::throw_generator_exception(
"Coud not jump to Nth element: not enough elements" );
}
}
}
void GeneratorUntypedBase::skipToNthElement( std::size_t n ) {
if ( n < m_currentElementIndex ) {
Detail::throw_generator_exception(
"Tried to jump generator backwards" );
}
if ( n == m_currentElementIndex ) { return; }
skipToNthElementImpl(n);
// Fixup tracking after moving the generator forward
// * Ensure that the correct element index is set after skipping
// * Invalidate cache
m_currentElementIndex = n;
m_stringReprCache.clear();
}
StringRef GeneratorUntypedBase::currentElementAsString() const {
if ( m_stringReprCache.empty() ) {
m_stringReprCache = stringifyImpl();
@@ -2519,6 +2571,8 @@ namespace Catch {
return m_stringReprCache;
}
bool GeneratorUntypedBase::isFinite() const { return true; }
} // namespace Generators
} // namespace Catch
@@ -3199,6 +3253,9 @@ namespace Catch {
} else if ( warning == "UnmatchedTestSpec" ) {
config.warnings = static_cast<WarnAbout::What>(config.warnings | WarnAbout::UnmatchedTestSpec);
return ParserResult::ok( ParseResultType::Matched );
} else if ( warning == "InfiniteGenerators" ) {
config.warnings = static_cast<WarnAbout::What>(config.warnings | WarnAbout::InfiniteGenerator);
return ParserResult::ok( ParseResultType::Matched );
}
return ParserResult ::runtimeError(
@@ -3356,6 +3413,19 @@ namespace Catch {
config.shardCount = *parsedCount;
return ParserResult::ok( ParseResultType::Matched );
};
auto const setBenchmarkSamples = [&]( std::string const& samples ) {
auto parsedSamples = parseUInt( samples );
if ( !parsedSamples ) {
return ParserResult::runtimeError(
"Could not parse '" + samples + "' as benchmark samples" );
}
if ( *parsedSamples == 0 ) {
return ParserResult::runtimeError(
"Benchmark samples must be greater than 0" );
}
config.benchmarkSamples = *parsedSamples;
return ParserResult::ok( ParseResultType::Matched );
};
auto const setShardIndex = [&](std::string const& shardIndex) {
auto parsedIndex = parseUInt( shardIndex );
@@ -3367,6 +3437,43 @@ namespace Catch {
return ParserResult::ok( ParseResultType::Matched );
};
auto const setSectionFilter = [&]( std::string const& sectionFilter ) {
config.pathFilters.emplace_back( PathFilter::For::Section, trim(sectionFilter) );
return ParserResult::ok( ParseResultType::Matched );
};
auto const setGeneratorFilter = [&]( std::string const& generatorFilter ) {
if (generatorFilter != "*") {
// TODO: avoid re-parsing the index?
auto parsedIndex = parseUInt( generatorFilter );
if ( !parsedIndex ) {
return ParserResult::runtimeError( "Could not parse '" +
generatorFilter +
"' as generator index" );
}
}
config.useNewPathFilteringBehaviour = true;
config.pathFilters.emplace_back( PathFilter::For::Generator, trim(generatorFilter) );
return ParserResult::ok( ParseResultType::Matched );
};
// Copy-capturing other `setFoo` functions enables calling them later,
// as the config ref remains valid, but the local lambda vars won't.
auto const setPathFilter = [=, &config]( std::string const& pathFilter ) {
config.useNewPathFilteringBehaviour = true;
if ( pathFilter.size() < 3 ) {
return ParserResult::runtimeError(
"Path filter '" + pathFilter + "' is too short" );
}
if ( startsWith( pathFilter, "g:" ) ) {
return setGeneratorFilter( pathFilter.substr( 2 ) );
}
if ( startsWith( pathFilter, "c:" ) ) {
return setSectionFilter( pathFilter.substr( 2 ) );
}
return ParserResult::runtimeError( "Path filter '" + pathFilter +
"' has unknown type prefix" );
};
auto cli
= ExeName( config.processName )
| Help( config.showHelp )
@@ -3412,9 +3519,15 @@ namespace Catch {
| Opt( config.filenamesAsTags )
["-#"]["--filenames-as-tags"]
( "adds a tag for the filename" )
| Opt( config.sectionsToRun, "section name" )
| Opt( accept_many, setSectionFilter, "section name" )
["-c"]["--section"]
( "specify section to run" )
| Opt( accept_many, setGeneratorFilter, "index spec" )
["-g"]["--generator-index"]
( "specify generator elements to try" )
| Opt( accept_many, setPathFilter, "path filter spec" )
["-p"]["--path-filter"]
( "qualified path filter" )
| Opt( setVerbosity, "quiet|normal|high" )
["-v"]["--verbosity"]
( "set output verbosity" )
@@ -3448,7 +3561,7 @@ namespace Catch {
| Opt( config.skipBenchmarks)
["--skip-benchmarks"]
( "disable running benchmarks")
| Opt( config.benchmarkSamples, "samples" )
| Opt( setBenchmarkSamples, "samples" )
["--benchmark-samples"]
( "number of samples to collect (default: 100)" )
| Opt( config.benchmarkResamples, "resamples" )
@@ -5752,12 +5865,46 @@ namespace Catch {
struct GeneratorTracker final : TestCaseTracking::TrackerBase,
IGeneratorTracker {
GeneratorBasePtr m_generator;
// Filtered generator has moved to specific index due to
// a filter, it needs special handling of `countedNext()`
bool m_isFiltered = false;
GeneratorTracker(
TestCaseTracking::NameAndLocation&& nameAndLocation,
TrackerContext& ctx,
ITracker* parent ):
TrackerBase( CATCH_MOVE( nameAndLocation ), ctx, parent ) {}
ITracker* parent,
GeneratorBasePtr&& generator ):
TrackerBase( CATCH_MOVE( nameAndLocation ), ctx, parent ),
m_generator( CATCH_MOVE( generator ) ) {
assert( m_generator &&
"Cannot create tracker without generator" );
// Handle potential filter and move forward here...
// Old style filters do not affect generators at all
if (m_newStyleFilters && m_allTrackerDepth < m_filterRef->size()) {
auto const& filter =
( *m_filterRef )[m_allTrackerDepth];
// Generator cannot be un-entered the way a section
// can be, so the tracker has to throw for a wrong
// filter to stop the execution flow.
if (filter.type == PathFilter::For::Section) {
// TBD: Explicit SKIP, or new exception that says
// "don't continue", but doesn't show in totals?
SKIP();
}
// '*' is the wildcard for "all elements in generator"
// used for filtering sections below the generator, but
// not the generator itself.
if ( filter.filter != "*" ) {
m_isFiltered = true;
// TBD: We assume that the filter was validated as
// number during parsing. We should pass it
// as number from the CLI parser.
size_t targetIndex = std::stoul( filter.filter );
m_generator->skipToNthElement( targetIndex );
}
}
}
static GeneratorTracker*
acquire( TrackerContext& ctx,
@@ -5801,9 +5948,6 @@ namespace Catch {
// TrackerBase interface
bool isGeneratorTracker() const override { return true; }
auto hasGenerator() const -> bool override {
return !!m_generator;
}
void close() override {
TrackerBase::close();
// If a generator has a child (it is followed by a section)
@@ -5832,25 +5976,24 @@ namespace Catch {
// _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();
// No filters left -> no restrictions on running sections
size_t childDepth = 1 + (m_newStyleFilters ? m_allTrackerDepth : m_sectionOnlyDepth);
if ( childDepth >= m_filterRef->size() ) {
return true;
}
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; }
// If we are using the new style filters, we need to check
// whether the successive filter is for section or a generator.
if ( m_newStyleFilters
&& (*m_filterRef)[childDepth].type != PathFilter::For::Section ) {
return false;
}
// Look for any child section that could match the remaining filters
for ( auto const& child : m_children ) {
if ( child->isSectionTracker() &&
static_cast<SectionTracker const&>( *child )
.trimmedName() == filters[0] ) {
.trimmedName() == StringRef((*m_filterRef)[childDepth].filter) ) {
return true;
}
}
@@ -5862,9 +6005,10 @@ namespace Catch {
// 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() ) ) {
if ( should_wait_for_child
|| ( m_runState == CompletedSuccessfully
&& !m_isFiltered // filtered generators cannot meaningfully move forward, as they would get past the filter
&& m_generator->countedNext() ) ) {
m_children.clear();
m_runState = Executing;
}
@@ -5874,9 +6018,6 @@ namespace Catch {
auto getGenerator() const -> GeneratorBasePtr const& override {
return m_generator;
}
void setGenerator( GeneratorBasePtr&& generator ) override {
m_generator = CATCH_MOVE( generator );
}
};
} // namespace
}
@@ -5930,15 +6071,18 @@ namespace Catch {
// we only keep around the raw msg ids.
~MessageHolder() = default;
void addUnscopedMessage(MessageBuilder&& builder) {
void addUnscopedMessage( MessageInfo&& info ) {
repairUnscopedMessageInvariant();
MessageInfo info( CATCH_MOVE( builder.m_info ) );
info.message = builder.m_stream.str();
unscoped_ids.push_back( info.sequence );
messages.push_back( CATCH_MOVE( info ) );
}
void addUnscopedMessage(MessageBuilder&& builder) {
MessageInfo info( CATCH_MOVE( builder.m_info ) );
info.message = builder.m_stream.str();
addUnscopedMessage( CATCH_MOVE( info ) );
}
void addScopedMessage(MessageInfo&& info) {
messages.push_back( CATCH_MOVE( info ) );
}
@@ -6027,7 +6171,8 @@ namespace Catch {
ITracker& rootTracker = m_trackerContext.startRun();
assert(rootTracker.isSectionTracker());
static_cast<SectionTracker&>(rootTracker).addInitialFilters(m_config->getSectionsToRun());
rootTracker.setFilters( &m_config->getPathFilters(),
m_config->useNewFilterBehaviour() );
// We intentionally only seed the internal RNG once per test case,
// before it is first invoked. The reason for that is a complex
@@ -6199,18 +6344,28 @@ namespace Catch {
SourceLineInfo lineInfo,
Generators::GeneratorBasePtr&& generator ) {
// TBD: Do we want to avoid the warning if the generator is filtered?
if ( m_config->warnAboutInfiniteGenerators() &&
!generator->isFinite() ) {
// TBD: Would it be better to expand this macro inline?
FAIL( "GENERATE() would run infinitely" );
}
auto nameAndLoc = TestCaseTracking::NameAndLocation( static_cast<std::string>( generatorName ), lineInfo );
auto& currentTracker = m_trackerContext.currentTracker();
assert(
currentTracker.nameAndLocation() != nameAndLoc &&
"Trying to create tracker for a generator that already has one" );
auto newTracker = Catch::Detail::make_unique<Generators::GeneratorTracker>(
CATCH_MOVE(nameAndLoc), m_trackerContext, &currentTracker );
auto newTracker =
Catch::Detail::make_unique<Generators::GeneratorTracker>(
CATCH_MOVE( nameAndLoc ),
m_trackerContext,
&currentTracker,
CATCH_MOVE( generator ) );
auto ret = newTracker.get();
currentTracker.addChild( CATCH_MOVE( newTracker ) );
ret->setGenerator( CATCH_MOVE( generator ) );
ret->open();
return ret;
}
@@ -6613,6 +6768,10 @@ namespace Catch {
Detail::g_messageHolder().addUnscopedMessage( CATCH_MOVE( builder ) );
}
void IResultCapture::addUnscopedMessage( MessageInfo&& message ) {
Detail::g_messageHolder().addUnscopedMessage( CATCH_MOVE( message ) );
}
void seedRng(IConfig const& config) {
sharedRng().seed(config.rngSeed());
}
@@ -7171,6 +7330,17 @@ namespace TestCaseTracking {
location( _location )
{}
ITracker::ITracker( NameAndLocation&& nameAndLoc, ITracker* parent ):
m_nameAndLocation( CATCH_MOVE( nameAndLoc ) ), m_parent( parent ) {
if ( m_parent ) {
m_allTrackerDepth = m_parent->m_allTrackerDepth + 1;
// We leave section trackers to bump themselves up, as
// we cannot use `isSectionTracker` in constructor
m_sectionOnlyDepth = m_parent->m_sectionOnlyDepth;
m_filterRef = m_parent->m_filterRef;
m_newStyleFilters = m_parent->m_newStyleFilters;
}
}
ITracker::~ITracker() = default;
@@ -7303,25 +7473,32 @@ namespace TestCaseTracking {
: TrackerBase( CATCH_MOVE(nameAndLocation), ctx, parent ),
m_trimmed_name(trim(StringRef(ITracker::nameAndLocation().name)))
{
if( parent ) {
while ( !parent->isSectionTracker() ) {
parent = parent->parent();
}
SectionTracker& parentSection = static_cast<SectionTracker&>( *parent );
addNextFilters( parentSection.m_filters );
if( m_parent ) {
++m_sectionOnlyDepth;
}
}
bool SectionTracker::isComplete() const {
bool complete = true;
if ( m_filters.empty()
|| m_filters[0].empty()
|| m_filters[0] == m_trimmed_name ) {
complete = TrackerBase::isComplete();
// If there are active filters AND we do not pass them,
// the section is always "completed"
const size_t filterIndex =
m_newStyleFilters ? m_allTrackerDepth : m_sectionOnlyDepth;
if ( filterIndex < m_filterRef->size() ) {
// There is active filter, check it
// 1) New style filter must explicitly target section
if ( m_newStyleFilters && ( *m_filterRef )[filterIndex].type !=
PathFilter::For::Section ) {
return true;
}
// 2) Both style filters must match the trimmed name exactly
if ( m_trimmed_name !=
StringRef( ( *m_filterRef )[filterIndex].filter ) ) {
return true;
}
}
return complete;
// Otherwise we delegate to the generic processing
return TrackerBase::isComplete();
}
bool SectionTracker::isSectionTracker() const { return true; }
@@ -7357,19 +7534,6 @@ namespace TestCaseTracking {
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
m_filters.insert( m_filters.end(), filters.begin(), filters.end() );
}
}
void SectionTracker::addNextFilters( std::vector<StringRef> const& filters ) {
if( filters.size() > 1 )
m_filters.insert( m_filters.end(), filters.begin()+1, filters.end() );
}
StringRef SectionTracker::trimmedName() const {
return m_trimmed_name;
}
+261 -59
View File
@@ -6,8 +6,8 @@
// SPDX-License-Identifier: BSL-1.0
// Catch v3.12.0
// Generated: 2025-12-28 22:27:25.408132
// Catch v3.13.0
// Generated: 2026-02-15 22:54:59.817776
// ----------------------------------------------------------
// This file is an amalgamation of multiple different files.
// You probably shouldn't edit it directly.
@@ -299,7 +299,7 @@
////////////////////////////////////////////////////////////////////////////////
// Visual C++
#if defined(_MSC_VER)
#if defined(_MSC_VER) && !defined(__clang__)
// We want to defer to nvcc-specific warning suppression if we are compiled
// with nvcc masquerading for MSVC.
@@ -310,6 +310,11 @@
__pragma( warning( pop ) )
# endif
// Suppress MSVC C++ Core Guidelines checker warning 26426:
// "Global initializer calls a non-constexpr function (i.22)"
# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
__pragma( warning( disable : 26426 ) )
// Universal Windows platform does not support SEH
# if !defined(CATCH_PLATFORM_WINDOWS_UWP)
# define CATCH_INTERNAL_CONFIG_WINDOWS_SEH
@@ -1033,7 +1038,7 @@ namespace Catch {
// We cannot forward declare the type with default template argument
// multiple times, so it is split out into a separate header so that
// we can prevent multiple declarations in dependees
// we can prevent multiple declarations in dependencies
template <typename Duration = Benchmark::FDuration>
struct BenchmarkStats;
@@ -1090,6 +1095,7 @@ namespace Catch {
static void pushScopedMessage( MessageInfo&& message );
static void popScopedMessage( unsigned int messageId );
static void addUnscopedMessage( MessageInfo&& message );
static void emplaceUnscopedMessage( MessageBuilder&& builder );
virtual void handleFatalErrorCondition( StringRef message ) = 0;
@@ -1189,6 +1195,8 @@ namespace Catch {
NoAssertions = 0x01,
//! A command line test spec matched no test cases
UnmatchedTestSpec = 0x02,
//! The resulting generator in GENERATE is infinite
InfiniteGenerator = 0x04,
}; };
enum class ShowDurations {
@@ -1220,6 +1228,7 @@ namespace Catch {
class TestSpec;
class IStream;
struct PathFilter;
class IConfig : public Detail::NonCopyable {
public:
@@ -1231,6 +1240,7 @@ namespace Catch {
virtual bool shouldDebugBreak() const = 0;
virtual bool warnAboutMissingAssertions() const = 0;
virtual bool warnAboutUnmatchedTestSpecs() const = 0;
virtual bool warnAboutInfiniteGenerators() const = 0;
virtual bool zeroTestsCountAsSuccess() const = 0;
virtual int abortAfter() const = 0;
virtual bool showInvisibles() const = 0;
@@ -1244,7 +1254,9 @@ namespace Catch {
virtual unsigned int shardCount() const = 0;
virtual unsigned int shardIndex() const = 0;
virtual ColourMode defaultColourMode() const = 0;
virtual std::vector<std::string> const& getSectionsToRun() const = 0;
virtual std::vector<PathFilter> const& getPathFilters() const = 0;
virtual bool useNewFilterBehaviour() const = 0;
virtual Verbosity verbosity() const = 0;
virtual bool skipBenchmarks() const = 0;
@@ -3630,6 +3642,33 @@ namespace Catch {
#endif // CATCH_OPTIONAL_HPP_INCLUDED
#ifndef CATCH_PATH_FILTER_HPP_INCLUDED
#define CATCH_PATH_FILTER_HPP_INCLUDED
#include <string>
namespace Catch {
struct PathFilter {
enum class For {
Section,
Generator,
};
PathFilter( For type_, std::string filter_ ):
type( type_ ), filter( CATCH_MOVE( filter_ ) ) {}
For type;
std::string filter;
friend bool operator==( PathFilter const& lhs, PathFilter const& rhs );
};
} // end namespace Catch
#endif // CATCH_PATH_FILTER_HPP_INCLUDED
#ifndef CATCH_RANDOM_SEED_GENERATION_HPP_INCLUDED
#define CATCH_RANDOM_SEED_GENERATION_HPP_INCLUDED
@@ -3797,7 +3836,8 @@ namespace Catch {
std::vector<ReporterSpec> reporterSpecifications;
std::vector<std::string> testsOrTags;
std::vector<std::string> sectionsToRun;
std::vector<PathFilter> pathFilters;
bool useNewPathFilteringBehaviour = false;
std::string prematureExitGuardFilePath;
};
@@ -3820,7 +3860,8 @@ namespace Catch {
getProcessedReporterSpecs() const;
std::vector<std::string> const& getTestsOrTags() const override;
std::vector<std::string> const& getSectionsToRun() const override;
std::vector<PathFilter> const& getPathFilters() const override;
bool useNewFilterBehaviour() const override;
TestSpec const& testSpec() const override;
bool hasTestFilters() const override;
@@ -3835,6 +3876,7 @@ namespace Catch {
bool includeSuccessfulResults() const override;
bool warnAboutMissingAssertions() const override;
bool warnAboutUnmatchedTestSpecs() const override;
bool warnAboutInfiniteGenerators() const override;
bool zeroTestsCountAsSuccess() const override;
ShowDurations showDurations() const override;
double minDuration() const override;
@@ -3943,9 +3985,9 @@ namespace Catch {
#if !defined( CATCH_CONFIG_NO_DEPRECATION_ANNOTATIONS )
# define DEPRECATED( msg ) [[deprecated( msg )]]
# define CATCH_DEPRECATED( msg ) [[deprecated( msg )]]
#else
# define DEPRECATED( msg )
# define CATCH_DEPRECATED( msg )
#endif
#endif // CATCH_DEPRECATION_MACRO_HPP_INCLUDED
@@ -3966,11 +4008,11 @@ namespace Catch {
// The "ID" of the message, used to know when to remove it from reporter context.
unsigned int sequence;
DEPRECATED( "Explicitly use the 'sequence' member instead" )
CATCH_DEPRECATED( "Explicitly use the 'sequence' member instead" )
bool operator == (MessageInfo const& other) const {
return sequence == other.sequence;
}
DEPRECATED( "Explicitly use the 'sequence' member instead" )
CATCH_DEPRECATED( "Explicitly use the 'sequence' member instead" )
bool operator < (MessageInfo const& other) const {
return sequence < other.sequence;
}
@@ -4028,8 +4070,9 @@ namespace Catch {
class Capturer {
std::vector<MessageInfo> m_messages;
size_t m_captured = 0;
bool m_isScoped = false;
public:
Capturer( StringRef macroName, SourceLineInfo const& lineInfo, ResultWas::OfType resultType, StringRef names );
Capturer( StringRef macroName, SourceLineInfo const& lineInfo, ResultWas::OfType resultType, StringRef names, bool isScoped );
Capturer(Capturer const&) = delete;
Capturer& operator=(Capturer const&) = delete;
@@ -4061,11 +4104,12 @@ namespace Catch {
} while( false )
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_CAPTURE( varName, macroName, ... ) \
Catch::Capturer varName( macroName##_catch_sr, \
CATCH_INTERNAL_LINEINFO, \
Catch::ResultWas::Info, \
#__VA_ARGS__##_catch_sr ); \
#define INTERNAL_CATCH_CAPTURE( varName, macroName, scopedCapture, ... ) \
Catch::Capturer varName( macroName##_catch_sr, \
CATCH_INTERNAL_LINEINFO, \
Catch::ResultWas::Info, \
#__VA_ARGS__##_catch_sr, \
scopedCapture ); \
varName.captureValues( 0, __VA_ARGS__ )
///////////////////////////////////////////////////////////////////////////////
@@ -4082,28 +4126,32 @@ namespace Catch {
#define CATCH_INFO( msg ) INTERNAL_CATCH_INFO( "CATCH_INFO", msg )
#define CATCH_UNSCOPED_INFO( msg ) INTERNAL_CATCH_UNSCOPED_INFO( "CATCH_UNSCOPED_INFO", msg )
#define CATCH_WARN( msg ) INTERNAL_CATCH_MSG( "CATCH_WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg )
#define CATCH_CAPTURE( ... ) INTERNAL_CATCH_CAPTURE( INTERNAL_CATCH_UNIQUE_NAME(capturer), "CATCH_CAPTURE", __VA_ARGS__ )
#define CATCH_CAPTURE( ... ) INTERNAL_CATCH_CAPTURE( INTERNAL_CATCH_UNIQUE_NAME(capturer), "CATCH_CAPTURE", true, __VA_ARGS__ )
#define CATCH_UNSCOPED_CAPTURE( ... ) INTERNAL_CATCH_CAPTURE( INTERNAL_CATCH_UNIQUE_NAME(capturer), "CATCH_UNSCOPED_CAPTURE", false, __VA_ARGS__ )
#elif defined(CATCH_CONFIG_PREFIX_MESSAGES) && defined(CATCH_CONFIG_DISABLE)
#define CATCH_INFO( msg ) (void)(0)
#define CATCH_UNSCOPED_INFO( msg ) (void)(0)
#define CATCH_WARN( msg ) (void)(0)
#define CATCH_CAPTURE( ... ) (void)(0)
#define CATCH_INFO( msg ) (void)(0)
#define CATCH_UNSCOPED_INFO( msg ) (void)(0)
#define CATCH_WARN( msg ) (void)(0)
#define CATCH_CAPTURE( ... ) (void)(0)
#define CATCH_UNSCOPED_CAPTURE( ... ) (void)(0)
#elif !defined(CATCH_CONFIG_PREFIX_MESSAGES) && !defined(CATCH_CONFIG_DISABLE)
#define INFO( msg ) INTERNAL_CATCH_INFO( "INFO", msg )
#define UNSCOPED_INFO( msg ) INTERNAL_CATCH_UNSCOPED_INFO( "UNSCOPED_INFO", msg )
#define WARN( msg ) INTERNAL_CATCH_MSG( "WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg )
#define CAPTURE( ... ) INTERNAL_CATCH_CAPTURE( INTERNAL_CATCH_UNIQUE_NAME(capturer), "CAPTURE", __VA_ARGS__ )
#define CAPTURE( ... ) INTERNAL_CATCH_CAPTURE( INTERNAL_CATCH_UNIQUE_NAME(capturer), "CAPTURE", true, __VA_ARGS__ )
#define UNSCOPED_CAPTURE( ... ) INTERNAL_CATCH_CAPTURE( INTERNAL_CATCH_UNIQUE_NAME(capturer), "UNSCOPED_CAPTURE", false, __VA_ARGS__ )
#elif !defined(CATCH_CONFIG_PREFIX_MESSAGES) && defined(CATCH_CONFIG_DISABLE)
#define INFO( msg ) (void)(0)
#define UNSCOPED_INFO( msg ) (void)(0)
#define WARN( msg ) (void)(0)
#define CAPTURE( ... ) (void)(0)
#define INFO( msg ) (void)(0)
#define UNSCOPED_INFO( msg ) (void)(0)
#define WARN( msg ) (void)(0)
#define CAPTURE( ... ) (void)(0)
#define UNSCOPED_CAPTURE( ... ) (void)(0)
#endif // end of user facing macro declarations
@@ -7466,7 +7514,7 @@ namespace Catch {
#define CATCH_VERSION_MACROS_HPP_INCLUDED
#define CATCH_VERSION_MAJOR 3
#define CATCH_VERSION_MINOR 12
#define CATCH_VERSION_MINOR 13
#define CATCH_VERSION_PATCH 0
#endif // CATCH_VERSION_MACROS_HPP_INCLUDED
@@ -7521,6 +7569,24 @@ namespace Catch {
#ifndef CATCH_GENERATORS_THROW_HPP_INCLUDED
#define CATCH_GENERATORS_THROW_HPP_INCLUDED
namespace Catch {
namespace Generators {
namespace Detail {
//! Throws GeneratorException with the provided message
[[noreturn]]
void throw_generator_exception( char const* msg );
} // namespace Detail
} // namespace Generators
} // namespace Catch
#endif // CATCH_GENERATORS_THROW_HPP_INCLUDED
#ifndef CATCH_INTERFACES_GENERATORTRACKER_HPP_INCLUDED
#define CATCH_INTERFACES_GENERATORTRACKER_HPP_INCLUDED
@@ -7549,6 +7615,15 @@ namespace Catch {
//! Customization point for `currentElementAsString`
virtual std::string stringifyImpl() const = 0;
/**
* Customization point for skipping to the n-th element
*
* Defaults to successively calling `countedNext`. If there
* are not enough elements to reach the nth one, will throw
* an error.
*/
virtual void skipToNthElementImpl( std::size_t n );
public:
GeneratorUntypedBase() = default;
// Generation of copy ops is deprecated (and Clang will complain)
@@ -7572,6 +7647,13 @@ namespace Catch {
std::size_t currentElementIndex() const { return m_currentElementIndex; }
/**
* Moves the generator forward **to** the n-th element
*
* Cannot move backwards. Can stay in place.
*/
void skipToNthElement( std::size_t n );
/**
* Returns generator's current element as user-friendly string.
*
@@ -7586,6 +7668,15 @@ namespace Catch {
* comes first.
*/
StringRef currentElementAsString() const;
/**
* Returns true if calls to `next` will eventually return false
*
* Note that for backwards compatibility this is currently defaulted
* to return `true`, but in the future all generators will have to
* provide their own implementation.
*/
virtual bool isFinite() const;
};
using GeneratorBasePtr = Catch::Detail::unique_ptr<GeneratorUntypedBase>;
@@ -7594,9 +7685,7 @@ namespace Catch {
class IGeneratorTracker {
public:
virtual ~IGeneratorTracker(); // = default;
virtual auto hasGenerator() const -> bool = 0;
virtual auto getGenerator() const -> Generators::GeneratorBasePtr const& = 0;
virtual void setGenerator( Generators::GeneratorBasePtr&& generator ) = 0;
};
} // namespace Catch
@@ -7610,14 +7699,6 @@ namespace Catch {
namespace Generators {
namespace Detail {
//! Throws GeneratorException with the provided message
[[noreturn]]
void throw_generator_exception(char const * msg);
} // end namespace detail
template<typename T>
class IGenerator : public GeneratorUntypedBase {
std::string stringifyImpl() const override {
@@ -7652,6 +7733,9 @@ namespace Detail {
bool next() {
return m_generator->countedNext();
}
bool isFinite() const { return m_generator->isFinite(); }
void skipToNthElement( size_t n ) { m_generator->skipToNthElement(n); }
};
@@ -7672,6 +7756,8 @@ namespace Detail {
bool next() override {
return false;
}
bool isFinite() const override { return true; }
};
template<typename T>
@@ -7681,6 +7767,15 @@ namespace Detail {
"specialization, use SingleValue Generator instead.");
std::vector<T> m_values;
size_t m_idx = 0;
void skipToNthElementImpl( std::size_t n ) override {
if ( n >= m_values.size() ) {
Detail::throw_generator_exception(
"Coud not jump to Nth element: not enough elements" );
}
m_idx = n;
}
public:
FixedValuesGenerator( std::initializer_list<T> values ) : m_values( values ) {}
@@ -7691,6 +7786,8 @@ namespace Detail {
++m_idx;
return m_idx < m_values.size();
}
bool isFinite() const override { return true; }
};
template <typename T, typename DecayedT = std::decay_t<T>>
@@ -7755,6 +7852,14 @@ namespace Detail {
}
return m_current < m_generators.size();
}
bool isFinite() const override {
for (auto const& gen : m_generators) {
if (!gen.isFinite()) { return false;
}
}
return true;
}
};
@@ -7846,6 +7951,17 @@ namespace Generators {
GeneratorWrapper<T> m_generator;
size_t m_returned = 0;
size_t m_target;
void skipToNthElementImpl( std::size_t n ) override {
if ( n >= m_target ) {
Detail::throw_generator_exception(
"Coud not jump to Nth element: not enough elements" );
}
m_generator.skipToNthElement( n );
m_returned = n;
}
public:
TakeGenerator(size_t target, GeneratorWrapper<T>&& generator):
m_generator(CATCH_MOVE(generator)),
@@ -7870,6 +7986,8 @@ namespace Generators {
}
return success;
}
bool isFinite() const override { return true; }
};
template <typename T>
@@ -7911,6 +8029,8 @@ namespace Generators {
while (!m_predicate(m_generator.get()) && (success = m_generator.next()) == true);
return success;
}
bool isFinite() const override { return m_generator.isFinite(); }
};
@@ -7935,6 +8055,9 @@ namespace Generators {
m_target_repeats(repeats)
{
assert(m_target_repeats > 0 && "Repeat generator must repeat at least once");
if (!m_generator.isFinite()) {
Detail::throw_generator_exception( "Cannot repeat infinite generator" );
}
}
T const& get() const override {
@@ -7968,6 +8091,8 @@ namespace Generators {
}
return m_current_repeat < m_target_repeats;
}
bool isFinite() const override { return m_generator.isFinite(); }
};
template <typename T>
@@ -7981,25 +8106,30 @@ namespace Generators {
GeneratorWrapper<U> m_generator;
Func m_function;
// To avoid returning dangling reference, we have to save the values
T m_cache;
mutable Optional<T> m_cache;
void skipToNthElementImpl( std::size_t n ) override {
m_generator.skipToNthElement( n );
m_cache.reset();
}
public:
template <typename F2 = Func>
MapGenerator(F2&& function, GeneratorWrapper<U>&& generator) :
m_generator(CATCH_MOVE(generator)),
m_function(CATCH_FORWARD(function)),
m_cache(m_function(m_generator.get()))
m_function(CATCH_FORWARD(function))
{}
T const& get() const override {
return m_cache;
if ( !m_cache ) { m_cache = m_function( m_generator.get() ); }
return *m_cache;
}
bool next() override {
const auto success = m_generator.next();
if (success) {
m_cache = m_function(m_generator.get());
}
return success;
m_cache.reset();
return m_generator.next();
}
bool isFinite() const override { return m_generator.isFinite(); }
};
template <typename Func, typename U, typename T = FunctionReturnType<Func, U>>
@@ -8021,7 +8151,6 @@ namespace Generators {
std::vector<T> m_chunk;
size_t m_chunk_size;
GeneratorWrapper<T> m_generator;
bool m_used_up = false;
public:
ChunkGenerator(size_t size, GeneratorWrapper<T> generator) :
m_chunk_size(size), m_generator(CATCH_MOVE(generator))
@@ -8050,6 +8179,8 @@ namespace Generators {
}
return true;
}
bool isFinite() const override { return m_generator.isFinite(); }
};
template <typename T>
@@ -8059,6 +8190,56 @@ namespace Generators {
);
}
template <typename T>
class ConcatGenerator final : public IGenerator<T> {
std::vector<GeneratorWrapper<T>> m_generators;
size_t m_current_generator = 0;
void InsertGenerators( GeneratorWrapper<T>&& gen ) {
m_generators.push_back( CATCH_MOVE( gen ) );
}
template <typename... Generators>
void InsertGenerators( GeneratorWrapper<T>&& gen, Generators&&... gens ) {
m_generators.push_back( CATCH_MOVE( gen ) );
InsertGenerators( CATCH_MOVE( gens )... );
}
public:
template <typename... Generators>
ConcatGenerator( Generators&&... generators ) {
InsertGenerators( CATCH_MOVE( generators )... );
}
T const& get() const override {
return m_generators[m_current_generator].get();
}
bool next() override {
const bool success = m_generators[m_current_generator].next();
if ( success ) { return true; }
// If current generator is used up, we have to move to the next one
++m_current_generator;
return m_current_generator < m_generators.size();
}
bool isFinite() const override {
for ( auto const& gen : m_generators ) {
if ( !gen.isFinite() ) { return false; }
}
return true;
}
};
template <typename T, typename... Generators>
GeneratorWrapper<T> cat( GeneratorWrapper<T>&& generator,
Generators&&... generators ) {
return GeneratorWrapper<T>(
Catch::Detail::make_unique<ConcatGenerator<T>>(
CATCH_MOVE( generator ), CATCH_MOVE( generators )... ) );
}
} // namespace Generators
} // namespace Catch
@@ -8701,6 +8882,7 @@ public:
m_current_number = m_dist(m_rng);
return true;
}
bool isFinite() const override { return false; }
};
template <>
@@ -8718,6 +8900,7 @@ public:
bool next() override;
~RandomFloatingGenerator() override; // = default
bool isFinite() const override;
};
template <typename Integer>
@@ -8739,6 +8922,7 @@ public:
m_current_number = m_dist(m_rng);
return true;
}
bool isFinite() const override { return false; }
};
template <typename T>
@@ -8808,6 +8992,8 @@ public:
m_current += m_step;
return (m_positive) ? (m_current < m_end) : (m_current > m_end);
}
bool isFinite() const override { return true; }
};
template <typename T>
@@ -8847,6 +9033,8 @@ public:
++m_current;
return m_current != m_elems.size();
}
bool isFinite() const override { return true; }
};
template <typename InputIterator,
@@ -10378,6 +10566,9 @@ namespace Catch {
#include <vector>
namespace Catch {
struct PathFilter;
namespace TestCaseTracking {
struct NameAndLocation {
@@ -10453,12 +10644,23 @@ namespace TestCaseTracking {
Children m_children;
CycleState m_runState = NotStarted;
public:
ITracker( NameAndLocation&& nameAndLoc, ITracker* parent ):
m_nameAndLocation( CATCH_MOVE(nameAndLoc) ),
m_parent( parent )
{}
// Members for path filtering
std::vector<PathFilter> const* m_filterRef = nullptr;
// Note: There are 2 dummy section trackers (root, test-case) before
// the first "real" section tracker can be encountered. We start
// the default tracker at -2, so that the first "real" section
// tracker overflows to index 0.
// Nesting depth of this tracker, used to decide which new-style filter applies.
size_t m_allTrackerDepth = static_cast<size_t>( -2 );
// Nesting depth of sections (inc. this tracker), used for old-style filters.
// Must be updated by the section tracker on its own.
size_t m_sectionOnlyDepth = static_cast<size_t>( -2 );
// Transitory: Remove once we remove backwards compatibility with old-style (v3.x) filters
bool m_newStyleFilters = false;
public:
ITracker( NameAndLocation&& nameAndLoc, ITracker* parent );
// static queries
NameAndLocation const& nameAndLocation() const {
@@ -10484,6 +10686,11 @@ namespace TestCaseTracking {
//! Returns true iff tracker has started
bool hasStarted() const;
void setFilters( std::vector<PathFilter> const* filters, bool newStyleFilters ) {
m_filterRef = filters;
m_newStyleFilters = newStyleFilters;
}
// actions
virtual void close() = 0; // Successfully complete
virtual void fail() = 0;
@@ -10569,8 +10776,7 @@ namespace TestCaseTracking {
void moveToThis();
};
class SectionTracker : public TrackerBase {
std::vector<StringRef> m_filters;
class SectionTracker final : public TrackerBase {
// Note that lifetime-wise we piggy back off the name stored in the `ITracker` parent`.
// Currently it allocates owns the name, so this is safe. If it is later refactored
// to not own the name, the name still has to outlive the `ITracker` parent, so
@@ -10587,10 +10793,6 @@ namespace TestCaseTracking {
void tryOpen();
void addInitialFilters( std::vector<std::string> const& filters );
void addNextFilters( std::vector<StringRef> const& filters );
//! Returns filters active in this tracker
std::vector<StringRef> const& getFilters() const { return m_filters; }
//! Returns whitespace-trimmed name of the tracked section
StringRef trimmedName() const;
};
+1 -1
View File
@@ -8,7 +8,7 @@
project(
'catch2',
'cpp',
version: '3.12.0', # CML version placeholder, don't delete
version: '3.13.0', # CML version placeholder, don't delete
license: 'BSL-1.0',
meson_version: '>=0.54.1',
)
+1 -1
View File
@@ -36,7 +36,7 @@ namespace Catch {
}
Version const& libraryVersion() {
static Version version( 3, 12, 0, "", 0 );
static Version version( 3, 13, 0, "", 0 );
return version;
}
+1 -1
View File
@@ -9,7 +9,7 @@
#define CATCH_VERSION_MACROS_HPP_INCLUDED
#define CATCH_VERSION_MAJOR 3
#define CATCH_VERSION_MINOR 12
#define CATCH_VERSION_MINOR 13
#define CATCH_VERSION_PATCH 0
#endif // CATCH_VERSION_MACROS_HPP_INCLUDED