diff --git a/CMakeLists.txt b/CMakeLists.txt index 84929314..4d497cc6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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." diff --git a/docs/command-line.md b/docs/command-line.md index fbc4609d..9a2b9e13 100644 --- a/docs/command-line.md +++ b/docs/command-line.md @@ -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 @@ -540,7 +540,7 @@ Prints the command line arguments to stdout
-g, --generator-index <index in generator>
-p, --path-filter <path filter spec>
-> 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 diff --git a/docs/deprecations.md b/docs/deprecations.md index 149f33b3..99fef27f 100644 --- a/docs/deprecations.md +++ b/docs/deprecations.md @@ -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 diff --git a/docs/filtering-execution-path.md b/docs/filtering-execution-path.md index a3dd675b..fad02624 100644 --- a/docs/filtering-execution-path.md +++ b/docs/filtering-execution-path.md @@ -1,7 +1,7 @@ # 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
@@ -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 diff --git a/docs/generators.md b/docs/generators.md index 5db2941b..b6ea0db2 100644 --- a/docs/generators.md +++ b/docs/generators.md @@ -132,7 +132,7 @@ a test case, > `IteratorGenerator` was introduced in Catch2 2.10.0. -> `ConcatGenerator` was introduced in Catch2 X.Y.Z +> `ConcatGenerator` 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`. diff --git a/docs/logging.md b/docs/logging.md index 371c80ad..fc3a7aca 100644 --- a/docs/logging.md +++ b/docs/logging.md @@ -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, diff --git a/docs/release-notes.md b/docs/release-notes.md index 35a76774..3060f1ab 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -2,6 +2,7 @@ # Release notes **Contents**
+[3.13.0](#3130)
[3.12.0](#3120)
[3.11.0](#3110)
[3.10.0](#3100)
@@ -72,6 +73,32 @@ [Even Older versions](#even-older-versions)
+## 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 diff --git a/extras/catch_amalgamated.cpp b/extras/catch_amalgamated.cpp index a4406d0c..adafc64b 100644 --- a/extras/catch_amalgamated.cpp +++ b/extras/catch_amalgamated.cpp @@ -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 const& Config::getTestsOrTags() const { return m_data.testsOrTags; } - std::vector const& Config::getSectionsToRun() const { return m_data.sectionsToRun; } + std::vector const& Config::getPathFilters() const { return m_data.pathFilters; } + bool Config::useNewFilterBehaviour() const { return m_data.useNewPathFilteringBehaviour; } std::vector 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(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::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 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(config.warnings | WarnAbout::UnmatchedTestSpec); return ParserResult::ok( ParseResultType::Matched ); + } else if ( warning == "InfiniteGenerators" ) { + config.warnings = static_cast(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( *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( *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(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( 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( - CATCH_MOVE(nameAndLoc), m_trackerContext, ¤tTracker ); + auto newTracker = + Catch::Detail::make_unique( + CATCH_MOVE( nameAndLoc ), + m_trackerContext, + ¤tTracker, + 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( *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 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 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; } diff --git a/extras/catch_amalgamated.hpp b/extras/catch_amalgamated.hpp index 00fc3ee1..6de74f80 100644 --- a/extras/catch_amalgamated.hpp +++ b/extras/catch_amalgamated.hpp @@ -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 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 const& getSectionsToRun() const = 0; + virtual std::vector 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 + +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 reporterSpecifications; std::vector testsOrTags; - std::vector sectionsToRun; + std::vector pathFilters; + bool useNewPathFilteringBehaviour = false; std::string prematureExitGuardFilePath; }; @@ -3820,7 +3860,8 @@ namespace Catch { getProcessedReporterSpecs() const; std::vector const& getTestsOrTags() const override; - std::vector const& getSectionsToRun() const override; + std::vector 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 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; @@ -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 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 @@ -7681,6 +7767,15 @@ namespace Detail { "specialization, use SingleValue Generator instead."); std::vector 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 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 > @@ -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 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&& generator): m_generator(CATCH_MOVE(generator)), @@ -7870,6 +7986,8 @@ namespace Generators { } return success; } + + bool isFinite() const override { return true; } }; template @@ -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 @@ -7981,25 +8106,30 @@ namespace Generators { GeneratorWrapper m_generator; Func m_function; // To avoid returning dangling reference, we have to save the values - T m_cache; + mutable Optional m_cache; + + void skipToNthElementImpl( std::size_t n ) override { + m_generator.skipToNthElement( n ); + m_cache.reset(); + } + public: template MapGenerator(F2&& function, GeneratorWrapper&& 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 > @@ -8021,7 +8151,6 @@ namespace Generators { std::vector m_chunk; size_t m_chunk_size; GeneratorWrapper m_generator; - bool m_used_up = false; public: ChunkGenerator(size_t size, GeneratorWrapper 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 @@ -8059,6 +8190,56 @@ namespace Generators { ); } + template + class ConcatGenerator final : public IGenerator { + std::vector> m_generators; + size_t m_current_generator = 0; + + void InsertGenerators( GeneratorWrapper&& gen ) { + m_generators.push_back( CATCH_MOVE( gen ) ); + } + + template + void InsertGenerators( GeneratorWrapper&& gen, Generators&&... gens ) { + m_generators.push_back( CATCH_MOVE( gen ) ); + InsertGenerators( CATCH_MOVE( gens )... ); + } + + public: + template + 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 + GeneratorWrapper cat( GeneratorWrapper&& generator, + Generators&&... generators ) { + return GeneratorWrapper( + Catch::Detail::make_unique>( + 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 @@ -8739,6 +8922,7 @@ public: m_current_number = m_dist(m_rng); return true; } + bool isFinite() const override { return false; } }; template @@ -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 @@ -8847,6 +9033,8 @@ public: ++m_current; return m_current != m_elems.size(); } + + bool isFinite() const override { return true; } }; template 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 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( -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( -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 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 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 const& filters ); - void addNextFilters( std::vector const& filters ); - //! Returns filters active in this tracker - std::vector const& getFilters() const { return m_filters; } //! Returns whitespace-trimmed name of the tracked section StringRef trimmedName() const; }; diff --git a/meson.build b/meson.build index 8a50e339..0997e56d 100644 --- a/meson.build +++ b/meson.build @@ -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', ) diff --git a/src/catch2/catch_version.cpp b/src/catch2/catch_version.cpp index 3b558a37..6e2b7ae1 100644 --- a/src/catch2/catch_version.cpp +++ b/src/catch2/catch_version.cpp @@ -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; } diff --git a/src/catch2/catch_version_macros.hpp b/src/catch2/catch_version_macros.hpp index b78f9cfd..33d318a9 100644 --- a/src/catch2/catch_version_macros.hpp +++ b/src/catch2/catch_version_macros.hpp @@ -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