Read-only mirrors. Development, issues and pull requests are on GitHub.

summaryrefslogtreecommitdiffhomepage
path: root/extras
diff options
context:
space:
mode:
authorMartin Hořeňovský2026-02-15 22:55:48 +0100
committerMartin Hořeňovský2026-02-15 22:55:48 +0100
commit29c9844f688acb27c87338c39cd186ebfe41aa19 (patch)
tree82526279e11e38f055605e0dcdbfc04ebfe63752 /extras
parent56024c04e42172d53a1672b9af6a538afdb79801 (diff)
downloadcatch3-3.13.0.tar.gz
v3.13.0v3.13.0
Diffstat (limited to 'extras')
-rw-r--r--extras/catch_amalgamated.cpp324
-rw-r--r--extras/catch_amalgamated.hpp320
2 files changed, 505 insertions, 139 deletions
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<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();
- }
- 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; }
+ // 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;
+ }
+ // 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,13 +6071,16 @@ namespace Catch {
// we only keep around the raw msg ids.
~MessageHolder() = default;
+ void addUnscopedMessage( MessageInfo&& info ) {
+ repairUnscopedMessageInvariant();
+ unscoped_ids.push_back( info.sequence );
+ messages.push_back( CATCH_MOVE( info ) );
+ }
void addUnscopedMessage(MessageBuilder&& builder) {
- 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 ) );
+ addUnscopedMessage( CATCH_MOVE( info ) );
}
void addScopedMessage(MessageInfo&& 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;
}
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 <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]]