diff --git a/CMakeLists.txt b/CMakeLists.txt
index bdc6c30c..1676ee79 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -34,7 +34,7 @@ if(CMAKE_BINARY_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
endif()
project(Catch2
- VERSION 3.8.1 # CML version placeholder, don't delete
+ VERSION 3.9.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 6096802e..73b94f6c 100644
--- a/docs/command-line.md
+++ b/docs/command-line.md
@@ -413,7 +413,7 @@ Tests are sorted by their name, their tags are ignored.
### rand
Randomized order. The default order.
-> Randomized order has been made default in Catch2 X.Y.Z
+> Randomized order has been made default in Catch2 3.9.0
The order is dependent on Catch2's random seed (see
[`--rng-seed`](#rng-seed)), and is subset invariant. What this means
diff --git a/docs/configuration.md b/docs/configuration.md
index c54776ad..f63a6d41 100644
--- a/docs/configuration.md
+++ b/docs/configuration.md
@@ -268,7 +268,7 @@ namespace Catch {
## Disabling deprecation warnings
-> Introduced in Catch2 X.Y.Z
+> Introduced in Catch2 3.9.0
Catch2 has started using the C++ macro `[[deprecated]]` to mark things
that are deprecated and should not be used any more. If you need to
@@ -318,7 +318,7 @@ are not meant to be runnable, only "scannable".
## Experimental thread safety
-> Introduced in Catch2 X.Y.Z
+> Introduced in Catch2 3.9.0
Catch2 can optionally support thread-safe assertions, that means, multiple
user-spawned threads can use the assertion macros at the same time. Due
diff --git a/docs/release-notes.md b/docs/release-notes.md
index fd0559bd..b8b973c9 100644
--- a/docs/release-notes.md
+++ b/docs/release-notes.md
@@ -2,6 +2,7 @@
# Release notes
**Contents**
+[3.9.0](#390)
[3.8.1](#381)
[3.8.0](#380)
[3.7.1](#371)
@@ -67,6 +68,45 @@
[Even Older versions](#even-older-versions)
+## 3.9.0
+
+### Improvements
+* **Added experimental opt-in support for thread safe assertions**
+ * Read the documentation for full details
+* **The default test run order has been changed to random**
+* Passing assertions are significantly faster when the reporter does not ask for `assertionEnded` events on passing assertions.
+ * This is the default behaviour of e.g. Console or Compact reporter
+ * Simple `REQUIRE(true)` is 60% faster in Release and 80% faster in Debug build configuration
+ * Simple `REQUIRE_NOTHROW` is 230% faster in Release and 430% faster in Debug build configuration
+ * Simple `REQUIRE_THROWS` is ~3% faster in Release and 20% faster in Debug build configuration (throwing introduces enough overhead that the optimizations inside Catch2 are mostly irrelevant)
+* Small (2-5%) improvement if the reporter asks for `assertionEnded` events for passing assertions.
+* The exit code constants are part of the Session API. (#2955, #2976)
+* Suppressed unsigned integer overflow checking in locations with intended overflow (#2965)
+* Reporters flush output after writing metadata, e.g. rng seed (#2964)
+* Added unreachable after `FAIL` and `SKIP` macros (#2941)
+ * This allows the compiler to understand that the execution does not continue past the macro, and avoids warnings.
+* Added fast path for `assertionStarting` event when no reporter requires it
+ * For backwards compatibility, this fast path is opt-in
+ * A reporter can opt in by changing its `ReporterPreferences::shouldReportAllAssertionStarts`
+* Improved last seen source location tracking to be more precise
+ * This is used when reporting unexpected exceptions from tests
+
+### Fixes
+* Fixed formatting of tags with more than 100 tests in the default `--list-tags` output (#2963)
+* Fixed Clang-Tidy's `readability-static-accessed-through-instance` in tests
+* Fixed most of Clang-Tidy's `cppcoreguidelines-avoid-non-const-global-variables` (#2582)
+* The lifetime of scoped messages now strictly obeys their scope (#1759, #2019, #2959)
+ * Previously Catch2 would try to keep them around during unexpected exception, to provide helpful context.
+ * The amount of surprises the irregularities caused was not worth the occasional utility provided.
+* `TEMPLATE_TEST_CASE_SIG` can handle signatures consisting of only types (#2680, #2995)
+* Moved `catch_test_run_info.hpp` up from `internal/` subfolder into the main one (#2972)
+
+### Miscellaneous
+* pkg-config files are now generated at install time (#2979)
+ * This fixes missing debug suffix in library names
+ * This fixes install prefix mismatch between build config and actuall installation
+
+
## 3.8.1
### Fixes
diff --git a/docs/reporters.md b/docs/reporters.md
index c600130c..d42648cf 100644
--- a/docs/reporters.md
+++ b/docs/reporters.md
@@ -169,7 +169,7 @@ Currently there are three customization options:
`assertionStarting` events. Most reporters do not, and opting out
explicitly enables a fast-path in Catch2's handling of assertions.
-> `shouldReportAllAssertionStarts` was introduced in Catch2 X.Y.Z
+> `shouldReportAllAssertionStarts` was introduced in Catch2 3.9.0
### Per-reporter configuration
diff --git a/docs/thread-safety.md b/docs/thread-safety.md
index 218246e6..c3f610f0 100644
--- a/docs/thread-safety.md
+++ b/docs/thread-safety.md
@@ -8,7 +8,7 @@
[Fatal errors and multiple threads](#fatal-errors-and-multiple-threads)
[Performance overhead](#performance-overhead)
-> Thread safe assertions were introduced in Catch2 X.Y.Z
+> Thread safe assertions were introduced in Catch2 3.9.0
Thread safety in Catch2 is currently limited to all the assertion macros.
Interacting with benchmark macros, message macros (e.g. `INFO` or `CAPTURE`),
diff --git a/extras/catch_amalgamated.cpp b/extras/catch_amalgamated.cpp
index b979eb24..3a9cd757 100644
--- a/extras/catch_amalgamated.cpp
+++ b/extras/catch_amalgamated.cpp
@@ -6,8 +6,8 @@
// SPDX-License-Identifier: BSL-1.0
-// Catch v3.8.1
-// Generated: 2025-04-08 12:33:19.863332
+// Catch v3.9.0
+// Generated: 2025-07-24 22:00:25.173359
// ----------------------------------------------------------
// This file is an amalgamation of multiple different files.
// You probably shouldn't edit it directly.
@@ -986,7 +986,7 @@ namespace Catch {
}
ScopedMessage::~ScopedMessage() {
- if ( !uncaught_exceptions() && !m_moved ){
+ if ( !m_moved ){
getResultCapture().popScopedMessage(m_info);
}
}
@@ -1056,11 +1056,9 @@ namespace Catch {
m_messages.back().message += " := ";
}
Capturer::~Capturer() {
- if ( !uncaught_exceptions() ){
- assert( m_captured == m_messages.size() );
- for( size_t i = 0; i < m_captured; ++i )
- m_resultCapture.popScopedMessage( m_messages[i] );
- }
+ assert( m_captured == m_messages.size() );
+ for ( size_t i = 0; i < m_captured; ++i )
+ m_resultCapture.popScopedMessage( m_messages[i] );
}
void Capturer::captureValue( size_t index, std::string const& value ) {
@@ -1161,7 +1159,6 @@ namespace Catch {
-#include
#include
#include
#include
@@ -1170,14 +1167,6 @@ namespace Catch {
namespace Catch {
namespace {
- static constexpr int TestFailureExitCode = 42;
- static constexpr int UnspecifiedErrorExitCode = 1;
- static constexpr int AllTestsSkippedExitCode = 4;
- static constexpr int NoTestsRunExitCode = 2;
- static constexpr int UnmatchedTestSpecExitCode = 3;
- static constexpr int InvalidTestSpecExitCode = 5;
-
-
IEventListenerPtr createReporter(std::string const& reporterName, ReporterConfig&& config) {
auto reporter = Catch::getRegistryHub().getReporterRegistry().create(reporterName, CATCH_MOVE(config));
CATCH_ENFORCE(reporter, "No reporter registered with name: '" << reporterName << '\'');
@@ -1935,7 +1924,6 @@ namespace Catch {
-#include
#include
namespace Catch {
@@ -2283,7 +2271,7 @@ namespace Catch {
}
Version const& libraryVersion() {
- static Version version( 3, 8, 1, "", 0 );
+ static Version version( 3, 9, 0, "", 0 );
return version;
}
@@ -4088,7 +4076,7 @@ namespace Catch {
// There is no 1-1 mapping between signals and windows exceptions.
// Windows can easily distinguish between SO and SigSegV,
// but SigInt, SigTerm, etc are handled differently.
- static SignalDefs signalDefs[] = {
+ static constexpr SignalDefs signalDefs[] = {
{ EXCEPTION_ILLEGAL_INSTRUCTION, "SIGILL - Illegal instruction signal" },
{ EXCEPTION_STACK_OVERFLOW, "SIGSEGV - Stack overflow" },
{ EXCEPTION_ACCESS_VIOLATION, "SIGSEGV - Segmentation violation signal" },
@@ -4159,7 +4147,7 @@ namespace Catch {
const char* name;
};
- static SignalDefs signalDefs[] = {
+ static constexpr SignalDefs signalDefs[] = {
{ SIGINT, "SIGINT - Terminal interrupt signal" },
{ SIGILL, "SIGILL - Illegal instruction signal" },
{ SIGFPE, "SIGFPE - Floating point error signal" },
@@ -4323,8 +4311,6 @@ namespace Catch {
#include
#include
-#include
-#include
namespace Catch {
@@ -4765,7 +4751,7 @@ namespace Catch {
namespace Catch {
CATCH_INTERNAL_START_WARNINGS_SUPPRESSION
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS
- static LeakDetector leakDetector;
+ static const LeakDetector leakDetector;
CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
}
@@ -5216,6 +5202,12 @@ namespace Catch {
+#if defined( __clang__ )
+# define CATCH2_CLANG_NO_SANITIZE_INTEGER \
+ __attribute__( ( no_sanitize( "unsigned-integer-overflow" ) ) )
+#else
+# define CATCH2_CLANG_NO_SANITIZE_INTEGER
+#endif
namespace Catch {
namespace {
@@ -5225,6 +5217,7 @@ namespace {
#pragma warning(disable:4146) // we negate uint32 during the rotate
#endif
// Safe rotr implementation thanks to John Regehr
+ CATCH2_CLANG_NO_SANITIZE_INTEGER
uint32_t rotate_right(uint32_t val, uint32_t count) {
const uint32_t mask = 31;
count &= mask;
@@ -5258,6 +5251,7 @@ namespace {
}
}
+ CATCH2_CLANG_NO_SANITIZE_INTEGER
SimplePcg32::result_type SimplePcg32::operator()() {
// prepare the output value
const uint32_t xorshifted = static_cast(((m_state >> 18u) ^ m_state) >> 27u);
@@ -5742,23 +5736,55 @@ namespace Catch {
} // namespace
}
+ namespace Detail {
+ // Assertions are owned by the thread that is executing them.
+ // This allows for lock-free progress in common cases where we
+ // do not need to send the assertion events to the reporter.
+ // This also implies that messages are owned by their respective
+ // threads, and should not be shared across different threads.
+ //
+ // For simplicity, we disallow messages in multi-threaded contexts,
+ // but in the future we can enable them under this logic.
+ //
+ // This implies that various pieces of metadata referring to last
+ // assertion result/source location/message handling, etc
+ // should also be thread local. For now we just use naked globals
+ // below, in the future we will want to allocate piece of memory
+ // from heap, to avoid consuming too much thread-local storage.
+
+ // This is used for the "if" part of CHECKED_IF/CHECKED_ELSE
+ static thread_local bool g_lastAssertionPassed = false;
+ // Should we clear message scopes before sending off the messages to
+ // reporter? Set in `assertionPassedFastPath` to avoid doing the full
+ // clear there for performance reasons.
+ static thread_local bool g_clearMessageScopes = false;
+ // This is the source location for last encountered macro. It is
+ // used to provide the users with more precise location of error
+ // when an unexpected exception/fatal error happens.
+ static thread_local SourceLineInfo g_lastKnownLineInfo("DummyLocation", static_cast(-1));
+ }
+
RunContext::RunContext(IConfig const* _config, IEventListenerPtr&& reporter)
: m_runInfo(_config->name()),
m_config(_config),
m_reporter(CATCH_MOVE(reporter)),
- m_lastAssertionInfo{ StringRef(), SourceLineInfo("",0), StringRef(), ResultDisposition::Normal },
m_outputRedirect( makeOutputRedirect( m_reporter->getPreferences().shouldRedirectStdOut ) ),
- m_includeSuccessfulResults( m_config->includeSuccessfulResults() || m_reporter->getPreferences().shouldReportAllAssertions )
+ m_abortAfterXFailedAssertions( m_config->abortAfter() ),
+ m_reportAssertionStarting( m_reporter->getPreferences().shouldReportAllAssertionStarts ),
+ m_includeSuccessfulResults( m_config->includeSuccessfulResults() || m_reporter->getPreferences().shouldReportAllAssertions ),
+ m_shouldDebugBreak( m_config->shouldDebugBreak() )
{
getCurrentMutableContext().setResultCapture( this );
m_reporter->testRunStarting(m_runInfo);
}
RunContext::~RunContext() {
+ updateTotalsFromAtomics();
m_reporter->testRunEnded(TestRunStats(m_runInfo, m_totals, aborting()));
}
Totals RunContext::runTest(TestCaseHandle const& testCase) {
+ updateTotalsFromAtomics();
const Totals prevTotals = m_totals;
auto const& testInfo = testCase.getTestCaseInfo();
@@ -5813,6 +5839,7 @@ namespace Catch {
m_reporter->testCasePartialStarting(testInfo, testRuns);
+ updateTotalsFromAtomics();
const auto beforeRunTotals = m_totals;
runCurrentTest();
std::string oneRunCout = m_outputRedirect->getStdout();
@@ -5821,6 +5848,7 @@ namespace Catch {
redirectedCout += oneRunCout;
redirectedCerr += oneRunCerr;
+ updateTotalsFromAtomics();
const auto singleRunTotals = m_totals.delta(beforeRunTotals);
auto statsForOneRun = TestCaseStats(testInfo, singleRunTotals, CATCH_MOVE(oneRunCout), CATCH_MOVE(oneRunCerr), aborting());
m_reporter->testCasePartialEnded(statsForOneRun, testRuns);
@@ -5850,27 +5878,35 @@ namespace Catch {
void RunContext::assertionEnded(AssertionResult&& result) {
+ Detail::g_lastKnownLineInfo = result.m_info.lineInfo;
if (result.getResultType() == ResultWas::Ok) {
- m_totals.assertions.passed++;
- m_lastAssertionPassed = true;
+ m_atomicAssertionCount.passed++;
+ Detail::g_lastAssertionPassed = true;
} else if (result.getResultType() == ResultWas::ExplicitSkip) {
- m_totals.assertions.skipped++;
- m_lastAssertionPassed = true;
+ m_atomicAssertionCount.skipped++;
+ Detail::g_lastAssertionPassed = true;
} else if (!result.succeeded()) {
- m_lastAssertionPassed = false;
+ Detail::g_lastAssertionPassed = false;
if (result.isOk()) {
}
- else if( m_activeTestCase->getTestCaseInfo().okToFail() )
- m_totals.assertions.failedButOk++;
+ else if( m_activeTestCase->getTestCaseInfo().okToFail() ) // Read from a shared state established before the threads could start, this is fine
+ m_atomicAssertionCount.failedButOk++;
else
- m_totals.assertions.failed++;
+ m_atomicAssertionCount.failed++;
}
else {
- m_lastAssertionPassed = true;
+ Detail::g_lastAssertionPassed = true;
}
+ // From here, we are touching shared state and need mutex.
+ Detail::LockGuard lock( m_assertionMutex );
{
+ if ( Detail::g_clearMessageScopes ) {
+ m_messageScopes.clear();
+ Detail::g_clearMessageScopes = false;
+ }
auto _ = scopedDeactivate( *m_outputRedirect );
+ updateTotalsFromAtomics();
m_reporter->assertionEnded( AssertionStats( result, m_messages, m_totals ) );
}
@@ -5882,15 +5918,13 @@ namespace Catch {
// populateReaction is run if it is needed
m_lastResult = CATCH_MOVE( result );
}
- void RunContext::resetAssertionInfo() {
- m_lastAssertionInfo.macroName = StringRef();
- m_lastAssertionInfo.capturedExpression = "{Unknown expression after the reported line}"_sr;
- m_lastAssertionInfo.resultDisposition = ResultDisposition::Normal;
- }
void RunContext::notifyAssertionStarted( AssertionInfo const& info ) {
- auto _ = scopedDeactivate( *m_outputRedirect );
- m_reporter->assertionStarting( info );
+ if (m_reportAssertionStarting) {
+ Detail::LockGuard lock( m_assertionMutex );
+ auto _ = scopedDeactivate( *m_outputRedirect );
+ m_reporter->assertionStarting( info );
+ }
}
bool RunContext::sectionStarted( StringRef sectionName,
@@ -5906,13 +5940,14 @@ namespace Catch {
m_activeSections.push_back(§ionTracker);
SectionInfo sectionInfo( sectionLineInfo, static_cast(sectionName) );
- m_lastAssertionInfo.lineInfo = sectionInfo.lineInfo;
+ Detail::g_lastKnownLineInfo = sectionLineInfo;
{
auto _ = scopedDeactivate( *m_outputRedirect );
m_reporter->sectionStarting( sectionInfo );
}
+ updateTotalsFromAtomics();
assertions = m_totals.assertions;
return true;
@@ -5920,12 +5955,11 @@ namespace Catch {
IGeneratorTracker*
RunContext::acquireGeneratorTracker( StringRef generatorName,
SourceLineInfo const& lineInfo ) {
- using namespace Generators;
- GeneratorTracker* tracker = GeneratorTracker::acquire(
+ auto* tracker = Generators::GeneratorTracker::acquire(
m_trackerContext,
TestCaseTracking::NameAndLocationRef(
generatorName, lineInfo ) );
- m_lastAssertionInfo.lineInfo = lineInfo;
+ Detail::g_lastKnownLineInfo = lineInfo;
return tracker;
}
@@ -5938,7 +5972,7 @@ namespace Catch {
auto& currentTracker = m_trackerContext.currentTracker();
assert(
currentTracker.nameAndLocation() != nameAndLoc &&
- "Trying to create tracker for a genreator that already has one" );
+ "Trying to create tracker for a generator that already has one" );
auto newTracker = Catch::Detail::make_unique(
CATCH_MOVE(nameAndLoc), m_trackerContext, ¤tTracker );
@@ -5957,12 +5991,13 @@ namespace Catch {
return false;
if (m_trackerContext.currentTracker().hasChildren())
return false;
- m_totals.assertions.failed++;
+ m_atomicAssertionCount.failed++;
assertions.failed++;
return true;
}
void RunContext::sectionEnded(SectionEndInfo&& endInfo) {
+ updateTotalsFromAtomics();
Counts assertions = m_totals.assertions - endInfo.prevAssertions;
bool missingAssertions = testForMissingAssertions(assertions);
@@ -5979,9 +6014,6 @@ namespace Catch {
endInfo.durationInSeconds,
missingAssertions ) );
}
-
- m_messages.clear();
- m_messageScopes.clear();
}
void RunContext::sectionEndedEarly(SectionEndInfo&& endInfo) {
@@ -6016,8 +6048,18 @@ namespace Catch {
m_messages.push_back(message);
}
- void RunContext::popScopedMessage(MessageInfo const & message) {
- m_messages.erase(std::remove(m_messages.begin(), m_messages.end(), message), m_messages.end());
+ void RunContext::popScopedMessage( MessageInfo const& message ) {
+ // Note: On average, it would probably be better to look for the message
+ // backwards. However, we do not expect to have to deal with more
+ // messages than low single digits, so the optimization is tiny,
+ // and we would have to hand-write the loop to avoid terrible
+ // codegen of reverse iterators in debug mode.
+ m_messages.erase(
+ std::find_if( m_messages.begin(),
+ m_messages.end(),
+ [id = message.sequence]( MessageInfo const& msg ) {
+ return msg.sequence == id;
+ } ) );
}
void RunContext::emplaceUnscopedMessage( MessageBuilder&& builder ) {
@@ -6031,6 +6073,18 @@ namespace Catch {
}
const AssertionResult * RunContext::getLastResult() const {
+ // m_lastResult is updated inside the assertion slow-path, under
+ // a mutex, so the read needs to happen under mutex as well.
+
+ // TBD: The last result only makes sense if it is a thread-local
+ // thing, because the answer is different per thread, like
+ // last line info, whether last assertion passed, and so on.
+ //
+ // However, the last result was also never updated in the
+ // assertion fast path, so it was always somewhat broken,
+ // and since IResultCapture::getLastResult is deprecated,
+ // we will leave it as is, until it is finally removed.
+ Detail::LockGuard _( m_assertionMutex );
return &(*m_lastResult);
}
@@ -6039,28 +6093,44 @@ namespace Catch {
}
void RunContext::handleFatalErrorCondition( StringRef message ) {
- // TODO: scoped deactivate here? Just give up and do best effort?
- // the deactivation can break things further, OTOH so can the
- // capture
- auto _ = scopedDeactivate( *m_outputRedirect );
+ // We lock only when touching the reporters directly, to avoid
+ // deadlocks when we call into other functions that also want
+ // to lock the mutex before touching reporters.
+ //
+ // This does mean that we allow other threads to run while handling
+ // a fatal error, but this is all a best effort attempt anyway.
+ {
+ Detail::LockGuard lock( m_assertionMutex );
+ // TODO: scoped deactivate here? Just give up and do best effort?
+ // the deactivation can break things further, OTOH so can the
+ // capture
+ auto _ = scopedDeactivate( *m_outputRedirect );
- // First notify reporter that bad things happened
- m_reporter->fatalErrorEncountered( message );
+ // First notify reporter that bad things happened
+ m_reporter->fatalErrorEncountered( message );
+ }
// Don't rebuild the result -- the stringification itself can cause more fatal errors
// Instead, fake a result data.
AssertionResultData tempResult( ResultWas::FatalErrorCondition, { false } );
tempResult.message = static_cast(message);
- AssertionResult result(m_lastAssertionInfo, CATCH_MOVE(tempResult));
+ AssertionResult result( makeDummyAssertionInfo(),
+ CATCH_MOVE( tempResult ) );
assertionEnded(CATCH_MOVE(result) );
- resetAssertionInfo();
+
+
+ // At this point we touch sections/test cases from this thread
+ // to try and end them. Technically that is not supported when
+ // using multiple threads, but the worst thing that can happen
+ // is that the process aborts harder :-D
+ Detail::LockGuard lock( m_assertionMutex );
// Best effort cleanup for sections that have not been destructed yet
// Since this is a fatal error, we have not had and won't have the opportunity to destruct them properly
while (!m_activeSections.empty()) {
- auto nl = m_activeSections.back()->nameAndLocation();
- SectionEndInfo endInfo{ SectionInfo(CATCH_MOVE(nl.location), CATCH_MOVE(nl.name)), {}, 0.0 };
+ auto const& nl = m_activeSections.back()->nameAndLocation();
+ SectionEndInfo endInfo{ SectionInfo(nl.location, nl.name), {}, 0.0 };
sectionEndedEarly(CATCH_MOVE(endInfo));
}
handleUnfinishedSections();
@@ -6085,32 +6155,44 @@ namespace Catch {
std::string(),
false));
m_totals.testCases.failed++;
+ updateTotalsFromAtomics();
m_reporter->testRunEnded(TestRunStats(m_runInfo, m_totals, false));
}
bool RunContext::lastAssertionPassed() {
- return m_lastAssertionPassed;
+ return Detail::g_lastAssertionPassed;
}
- void RunContext::assertionPassed() {
- m_lastAssertionPassed = true;
- ++m_totals.assertions.passed;
- resetAssertionInfo();
- m_messageScopes.clear();
+ void RunContext::assertionPassedFastPath(SourceLineInfo lineInfo) {
+ // We want to save the line info for better experience with unexpected assertions
+ Detail::g_lastKnownLineInfo = lineInfo;
+ ++m_atomicAssertionCount.passed;
+ Detail::g_lastAssertionPassed = true;
+ Detail::g_clearMessageScopes = true;
+ }
+
+ void RunContext::updateTotalsFromAtomics() {
+ m_totals.assertions = Counts{
+ m_atomicAssertionCount.passed,
+ m_atomicAssertionCount.failed,
+ m_atomicAssertionCount.failedButOk,
+ m_atomicAssertionCount.skipped,
+ };
}
bool RunContext::aborting() const {
- return m_totals.assertions.failed >= static_cast(m_config->abortAfter());
+ return m_atomicAssertionCount.failed >= m_abortAfterXFailedAssertions;
}
void RunContext::runCurrentTest() {
auto const& testCaseInfo = m_activeTestCase->getTestCaseInfo();
SectionInfo testCaseSection(testCaseInfo.lineInfo, testCaseInfo.name);
m_reporter->sectionStarting(testCaseSection);
+ updateTotalsFromAtomics();
Counts prevAssertions = m_totals.assertions;
double duration = 0;
m_shouldReportUnexpected = true;
- m_lastAssertionInfo = { "TEST_CASE"_sr, testCaseInfo.lineInfo, StringRef(), ResultDisposition::Normal };
+ Detail::g_lastKnownLineInfo = testCaseInfo.lineInfo;
Timer timer;
CATCH_TRY {
@@ -6127,18 +6209,23 @@ namespace Catch {
} CATCH_CATCH_ALL {
// Under CATCH_CONFIG_FAST_COMPILE, unexpected exceptions under REQUIRE assertions
// are reported without translation at the point of origin.
- if( m_shouldReportUnexpected ) {
+ if ( m_shouldReportUnexpected ) {
AssertionReaction dummyReaction;
- handleUnexpectedInflightException( m_lastAssertionInfo, translateActiveException(), dummyReaction );
+ handleUnexpectedInflightException( makeDummyAssertionInfo(),
+ translateActiveException(),
+ dummyReaction );
}
}
+ updateTotalsFromAtomics();
Counts assertions = m_totals.assertions - prevAssertions;
bool missingAssertions = testForMissingAssertions(assertions);
m_testCaseTracker->close();
handleUnfinishedSections();
- m_messages.clear();
m_messageScopes.clear();
+ // TBD: At this point, m_messages should be empty. Do we want to
+ // assert that this is true, or keep the defensive clear call?
+ m_messages.clear();
SectionStats testCaseSectionStats(CATCH_MOVE(testCaseSection), assertions, duration, missingAssertions);
m_reporter->sectionEnded(testCaseSectionStats);
@@ -6179,7 +6266,7 @@ namespace Catch {
if( result ) {
if (!m_includeSuccessfulResults) {
- assertionPassed();
+ assertionPassedFastPath(info.lineInfo);
}
else {
reportExpr(info, ResultWas::Ok, &expr, negated);
@@ -6187,9 +6274,9 @@ namespace Catch {
}
else {
reportExpr(info, ResultWas::ExpressionFailed, &expr, negated );
- populateReaction( reaction );
+ populateReaction(
+ reaction, info.resultDisposition & ResultDisposition::Normal );
}
- resetAssertionInfo();
}
void RunContext::reportExpr(
AssertionInfo const &info,
@@ -6197,7 +6284,7 @@ namespace Catch {
ITransientExpression const *expr,
bool negated ) {
- m_lastAssertionInfo = info;
+ Detail::g_lastKnownLineInfo = info.lineInfo;
AssertionResultData data( resultType, LazyExpression( negated ) );
AssertionResult assertionResult{ info, CATCH_MOVE( data ) };
@@ -6212,24 +6299,25 @@ namespace Catch {
std::string&& message,
AssertionReaction& reaction
) {
- m_lastAssertionInfo = info;
+ Detail::g_lastKnownLineInfo = info.lineInfo;
AssertionResultData data( resultType, LazyExpression( false ) );
data.message = CATCH_MOVE( message );
- AssertionResult assertionResult{ m_lastAssertionInfo,
+ AssertionResult assertionResult{ info,
CATCH_MOVE( data ) };
const auto isOk = assertionResult.isOk();
assertionEnded( CATCH_MOVE(assertionResult) );
if ( !isOk ) {
- populateReaction( reaction );
+ populateReaction(
+ reaction, info.resultDisposition & ResultDisposition::Normal );
} else if ( resultType == ResultWas::ExplicitSkip ) {
// TODO: Need to handle this explicitly, as ExplicitSkip is
// considered "OK"
reaction.shouldSkip = true;
}
- resetAssertionInfo();
}
+
void RunContext::handleUnexpectedExceptionNotThrown(
AssertionInfo const& info,
AssertionReaction& reaction
@@ -6242,49 +6330,67 @@ namespace Catch {
std::string&& message,
AssertionReaction& reaction
) {
- m_lastAssertionInfo = info;
+ Detail::g_lastKnownLineInfo = info.lineInfo;
AssertionResultData data( ResultWas::ThrewException, LazyExpression( false ) );
data.message = CATCH_MOVE(message);
AssertionResult assertionResult{ info, CATCH_MOVE(data) };
assertionEnded( CATCH_MOVE(assertionResult) );
- populateReaction( reaction );
- resetAssertionInfo();
+ populateReaction( reaction,
+ info.resultDisposition & ResultDisposition::Normal );
}
- void RunContext::populateReaction( AssertionReaction& reaction ) {
- reaction.shouldDebugBreak = m_config->shouldDebugBreak();
- reaction.shouldThrow = aborting() || (m_lastAssertionInfo.resultDisposition & ResultDisposition::Normal);
+ void RunContext::populateReaction( AssertionReaction& reaction,
+ bool has_normal_disposition ) {
+ reaction.shouldDebugBreak = m_shouldDebugBreak;
+ reaction.shouldThrow = aborting() || has_normal_disposition;
+ }
+
+ AssertionInfo RunContext::makeDummyAssertionInfo() {
+ const bool testCaseJustStarted =
+ Detail::g_lastKnownLineInfo ==
+ m_activeTestCase->getTestCaseInfo().lineInfo;
+
+ return AssertionInfo{
+ testCaseJustStarted ? "TEST_CASE"_sr : StringRef(),
+ Detail::g_lastKnownLineInfo,
+ testCaseJustStarted ? StringRef() : "{Unknown expression after the reported line}"_sr,
+ ResultDisposition::Normal
+ };
}
void RunContext::handleIncomplete(
AssertionInfo const& info
) {
using namespace std::string_literals;
- m_lastAssertionInfo = info;
+ Detail::g_lastKnownLineInfo = info.lineInfo;
AssertionResultData data( ResultWas::ThrewException, LazyExpression( false ) );
data.message = "Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE"s;
AssertionResult assertionResult{ info, CATCH_MOVE( data ) };
assertionEnded( CATCH_MOVE(assertionResult) );
- resetAssertionInfo();
}
+
void RunContext::handleNonExpr(
AssertionInfo const &info,
ResultWas::OfType resultType,
AssertionReaction &reaction
) {
- m_lastAssertionInfo = info;
-
AssertionResultData data( resultType, LazyExpression( false ) );
AssertionResult assertionResult{ info, CATCH_MOVE( data ) };
const auto isOk = assertionResult.isOk();
- assertionEnded( CATCH_MOVE(assertionResult) );
- if ( !isOk ) { populateReaction( reaction ); }
- resetAssertionInfo();
- }
+ if ( isOk && !m_includeSuccessfulResults ) {
+ assertionPassedFastPath( info.lineInfo );
+ return;
+ }
+ assertionEnded( CATCH_MOVE(assertionResult) );
+ if ( !isOk ) {
+ populateReaction(
+ reaction, info.resultDisposition & ResultDisposition::Normal );
+ }
+ }
IResultCapture& getResultCapture() {
if (auto* capture = getCurrentContext().getResultCapture())
@@ -6516,7 +6622,7 @@ namespace Catch {
std::string origStr = CATCH_MOVE(str);
str.clear();
// There is at least one replacement, so reserve with the best guess
- // we can make without actually counting the number of occurences.
+ // we can make without actually counting the number of occurrences.
str.reserve(origStr.size() - replaceThis.size() + withThis.size());
do {
str.append(origStr, copyBegin, i-copyBegin );
@@ -6562,7 +6668,6 @@ namespace Catch {
#include
#include
#include
-#include
namespace Catch {
StringRef::StringRef( char const* rawChars ) noexcept
@@ -8877,7 +8982,8 @@ private:
<< m_config->testSpec()
<< '\n';
}
- m_stream << "RNG seed: " << getSeed() << '\n';
+ m_stream << "RNG seed: " << getSeed() << '\n'
+ << std::flush;
}
void CompactReporter::assertionEnded( AssertionStats const& _assertionStats ) {
@@ -9298,7 +9404,10 @@ ConsoleReporter::ConsoleReporter(ReporterConfig&& config):
{ "est run time high mean high std dev", 14, Justification::Right }
};
}
- }())) {}
+ }())) {
+ m_preferences.shouldReportAllAssertionStarts = false;
+}
+
ConsoleReporter::~ConsoleReporter() = default;
std::string ConsoleReporter::getDescription() {
@@ -9313,8 +9422,6 @@ void ConsoleReporter::reportInvalidTestSpec( StringRef arg ) {
m_stream << "Invalid Filter: " << arg << '\n';
}
-void ConsoleReporter::assertionStarting(AssertionInfo const&) {}
-
void ConsoleReporter::assertionEnded(AssertionStats const& _assertionStats) {
AssertionResult const& result = _assertionStats.assertionResult;
@@ -9426,7 +9533,8 @@ void ConsoleReporter::testRunStarting(TestRunInfo const& _testRunInfo) {
m_stream << m_colour->guardColour( Colour::BrightYellow ) << "Filters: "
<< m_config->testSpec() << '\n';
}
- m_stream << "Randomness seeded to: " << getSeed() << '\n';
+ m_stream << "Randomness seeded to: " << getSeed() << '\n'
+ << std::flush;
}
void ConsoleReporter::lazyPrint() {
@@ -9754,6 +9862,7 @@ namespace Catch {
#include
#include
+#include
#include
#include
#include
@@ -9917,9 +10026,29 @@ namespace Catch {
out << "All available tags:\n";
}
+ // minimum whitespace to pad tag counts, possibly overwritten below
+ size_t maxTagCountLen = 2;
+
+ // determine necessary padding for tag count column
+ if ( ! tags.empty() ) {
+ const auto maxTagCount =
+ std::max_element( tags.begin(),
+ tags.end(),
+ []( auto const& lhs, auto const& rhs ) {
+ return lhs.count < rhs.count;
+ } )
+ ->count;
+
+ // more padding necessary for 3+ digits
+ if (maxTagCount >= 100) {
+ auto numDigits = 1 + std::floor( std::log10( maxTagCount ) );
+ maxTagCountLen = static_cast( numDigits );
+ }
+ }
+
for ( auto const& tagCount : tags ) {
ReusableStringStream rss;
- rss << " " << std::setw( 2 ) << tagCount.count << " ";
+ rss << " " << std::setw( maxTagCountLen ) << tagCount.count << " ";
auto str = rss.str();
auto wrapper = TextFlow::Column( tagCount.all() )
.initialIndent( 0 )
@@ -10117,6 +10246,8 @@ namespace Catch {
// not, but for machine-parseable reporters I think the answer
// should be yes.
m_preferences.shouldReportAllAssertions = true;
+ // We only handle assertions when they end
+ m_preferences.shouldReportAllAssertionStarts = false;
m_objectWriters.emplace( m_stream );
m_writers.emplace( Writer::Object );
@@ -10346,7 +10477,6 @@ namespace Catch {
endObject();
}
- void JsonReporter::assertionStarting( AssertionInfo const& /*assertionInfo*/ ) {}
void JsonReporter::assertionEnded( AssertionStats const& assertionStats ) {
// TODO: There is lot of different things to handle here, but
// we can fill it in later, after we show that the basic
@@ -10513,6 +10643,7 @@ namespace Catch {
{
m_preferences.shouldRedirectStdOut = true;
m_preferences.shouldReportAllAssertions = false;
+ m_preferences.shouldReportAllAssertionStarts = false;
m_shouldStoreSuccesfulAssertions = false;
}
@@ -10743,6 +10874,8 @@ namespace Catch {
reporterish.getPreferences().shouldRedirectStdOut;
m_preferences.shouldReportAllAssertions |=
reporterish.getPreferences().shouldReportAllAssertions;
+ m_preferences.shouldReportAllAssertionStarts |=
+ reporterish.getPreferences().shouldReportAllAssertionStarts;
}
void MultiReporter::addListener( IEventListenerPtr&& listener ) {
@@ -11300,7 +11433,8 @@ namespace Catch {
if ( m_config->testSpec().hasFilters() ) {
m_stream << "# filters: " << m_config->testSpec() << '\n';
}
- m_stream << "# rng-seed: " << m_config->rngSeed() << '\n';
+ m_stream << "# rng-seed: " << m_config->rngSeed() << '\n'
+ << std::flush;
}
void TAPReporter::noMatchingTestCases( StringRef unmatchedSpec ) {
@@ -11514,6 +11648,7 @@ namespace Catch {
{
m_preferences.shouldRedirectStdOut = true;
m_preferences.shouldReportAllAssertions = true;
+ m_preferences.shouldReportAllAssertionStarts = false;
}
XmlReporter::~XmlReporter() = default;
@@ -11570,8 +11705,6 @@ namespace Catch {
}
}
- void XmlReporter::assertionStarting( AssertionInfo const& ) { }
-
void XmlReporter::assertionEnded( AssertionStats const& assertionStats ) {
AssertionResult const& result = assertionStats.assertionResult;
diff --git a/extras/catch_amalgamated.hpp b/extras/catch_amalgamated.hpp
index 7703e957..608a184b 100644
--- a/extras/catch_amalgamated.hpp
+++ b/extras/catch_amalgamated.hpp
@@ -6,8 +6,8 @@
// SPDX-License-Identifier: BSL-1.0
-// Catch v3.8.1
-// Generated: 2025-04-08 12:33:19.851017
+// Catch v3.9.0
+// Generated: 2025-07-24 22:00:24.654688
// ----------------------------------------------------------
// This file is an amalgamation of multiple different files.
// You probably shouldn't edit it directly.
@@ -1100,9 +1100,7 @@ namespace Catch {
AssertionReaction &reaction ) = 0;
-
virtual bool lastAssertionPassed() = 0;
- virtual void assertionPassed() = 0;
// Deprecated, do not use:
virtual std::string getCurrentTestName() const = 0;
@@ -1129,6 +1127,7 @@ namespace Catch {
//! Deriving classes become noncopyable and nonmovable
class NonCopyable {
+ public:
NonCopyable( NonCopyable const& ) = delete;
NonCopyable( NonCopyable&& ) = delete;
NonCopyable& operator=( NonCopyable const& ) = delete;
@@ -1144,7 +1143,6 @@ namespace Catch {
#endif // CATCH_NONCOPYABLE_HPP_INCLUDED
#include
-#include
#include
#include
@@ -1599,8 +1597,7 @@ namespace Catch {
namespace Benchmark {
namespace Detail {
template
- struct is_related
- : std::is_same, std::decay_t> {};
+ static constexpr bool is_related_v = std::is_same, std::decay_t>::value;
/// We need to reinvent std::function because every piece of code that might add overhead
/// in a measurement context needs to have consistent performance characteristics so that we
@@ -1641,7 +1638,7 @@ namespace Catch {
BenchmarkFunction();
template ::value, int> = 0>
+ std::enable_if_t, int> = 0>
BenchmarkFunction(Fun&& fun)
: f(new model>(CATCH_FORWARD(fun))) {}
@@ -1767,8 +1764,6 @@ namespace Catch {
#define CATCH_TIMING_HPP_INCLUDED
-#include
-
namespace Catch {
namespace Benchmark {
template
@@ -2167,7 +2162,7 @@ namespace Catch {
}
// sets lambda to be used in fun *and* executes benchmark!
- template ::value, int> = 0>
+ template , int> = 0>
Benchmark & operator=(Fun func) {
auto const* cfg = getCurrentContext().getConfig();
if (!cfg->skipBenchmarks()) {
@@ -2496,18 +2491,14 @@ namespace Catch {
return rawMemoryToString( &object, sizeof(object) );
}
- template
- class IsStreamInsertable {
- template
- static auto test(int)
- -> decltype(std::declval() << std::declval(), std::true_type());
+ template
+ static constexpr bool IsStreamInsertable_v = false;
- template
- static auto test(...)->std::false_type;
-
- public:
- static const bool value = decltype(test(0))::value;
- };
+ template
+ static constexpr bool IsStreamInsertable_v<
+ T,
+ decltype( void( std::declval() << std::declval() ) )> =
+ true;
template
std::string convertUnknownEnumToString( E e );
@@ -2552,7 +2543,7 @@ namespace Catch {
struct StringMaker {
template
static
- std::enable_if_t<::Catch::Detail::IsStreamInsertable::value, std::string>
+ std::enable_if_t<::Catch::Detail::IsStreamInsertable_v, std::string>
convert(const Fake& value) {
ReusableStringStream rss;
// NB: call using the function-like syntax to avoid ambiguity with
@@ -2563,7 +2554,7 @@ namespace Catch {
template
static
- std::enable_if_t::value, std::string>
+ std::enable_if_t, std::string>
convert( const Fake& value ) {
#if !defined(CATCH_CONFIG_FALLBACK_STRINGIFIER)
return Detail::convertUnstreamable(value);
@@ -2955,7 +2946,7 @@ namespace Catch {
}
template
- struct StringMaker::value && !::Catch::Detail::IsStreamInsertable::value>> {
+ struct StringMaker::value && !::Catch::Detail::IsStreamInsertable_v>> {
static std::string convert( R const& range ) {
return rangeToString( range );
}
@@ -3792,7 +3783,7 @@ namespace Catch {
WarnAbout::What warnings = WarnAbout::Nothing;
ShowDurations showDurations = ShowDurations::DefaultForReporter;
double minDuration = -1;
- TestRunOrder runOrder = TestRunOrder::Declared;
+ TestRunOrder runOrder = TestRunOrder::Randomized;
ColourMode defaultColourMode = ColourMode::PlatformDefault;
WaitForKeypress::When waitForKeypress = WaitForKeypress::Never;
@@ -3938,6 +3929,19 @@ namespace Catch {
#define CATCH_MESSAGE_INFO_HPP_INCLUDED
+
+#ifndef CATCH_DEPRECATION_MACRO_HPP_INCLUDED
+#define CATCH_DEPRECATION_MACRO_HPP_INCLUDED
+
+
+#if !defined( CATCH_CONFIG_NO_DEPRECATION_ANNOTATIONS )
+# define DEPRECATED( msg ) [[deprecated( msg )]]
+#else
+# define DEPRECATED( msg )
+#endif
+
+#endif // CATCH_DEPRECATION_MACRO_HPP_INCLUDED
+
#include
namespace Catch {
@@ -3953,9 +3957,11 @@ namespace Catch {
ResultWas::OfType type;
unsigned int sequence;
+ DEPRECATED( "Explicitly use the 'sequence' member instead" )
bool operator == (MessageInfo const& other) const {
return sequence == other.sequence;
}
+ DEPRECATED( "Explicitly use the 'sequence' member instead" )
bool operator < (MessageInfo const& other) const {
return sequence < other.sequence;
}
@@ -4237,15 +4243,13 @@ namespace Catch {
};
template
- struct is_unary_function : std::false_type {};
+ static constexpr bool is_unary_function_v = false;
template
- struct is_unary_function<
+ static constexpr bool is_unary_function_v<
F,
- Catch::Detail::void_t()( fake_arg() ) )
- >
- > : std::true_type {};
+ Catch::Detail::void_t()(
+ fake_arg() ) )>> = true;
// Traits for extracting arg and return type of lambdas (for single
// argument lambdas)
@@ -4678,14 +4682,14 @@ namespace Catch {
template ::value>>
+ !Detail::is_unary_function_v>>
ParserRefImpl( T& ref, StringRef hint ):
m_ref( std::make_shared>( ref ) ),
m_hint( hint ) {}
template ::value>>
+ Detail::is_unary_function_v>>
ParserRefImpl( LambdaT const& ref, StringRef hint ):
m_ref( std::make_shared>( ref ) ),
m_hint( hint ) {}
@@ -4752,7 +4756,7 @@ namespace Catch {
template ::value>>
+ Detail::is_unary_function_v>>
Opt( LambdaT const& ref, StringRef hint ):
ParserRefImpl( ref, hint ) {}
@@ -4762,7 +4766,7 @@ namespace Catch {
template ::value>>
+ !Detail::is_unary_function_v>>
Opt( T& ref, StringRef hint ):
ParserRefImpl( ref, hint ) {}
@@ -4932,6 +4936,14 @@ namespace Catch {
namespace Catch {
+ // TODO: Use C++17 `inline` variables
+ constexpr int UnspecifiedErrorExitCode = 1;
+ constexpr int NoTestsRunExitCode = 2;
+ constexpr int UnmatchedTestSpecExitCode = 3;
+ constexpr int AllTestsSkippedExitCode = 4;
+ constexpr int InvalidTestSpecExitCode = 5;
+ constexpr int TestFailureExitCode = 42;
+
class Session : Detail::NonCopyable {
public:
@@ -5016,7 +5028,7 @@ namespace Catch {
#define CATCH_REGISTER_TAG_ALIAS( alias, spec ) \
CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
- namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); } \
+ namespace{ const Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); } \
CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
#endif // CATCH_TAG_ALIAS_AUTOREGISTRAR_HPP_INCLUDED
@@ -5193,7 +5205,7 @@ namespace Detail {
* when the compiler handles `ExprLhs == b`, it also tries to resolve
* the overload set for `b == ExprLhs`.
*
- * To accomodate these use cases, decomposer ended up rather complex.
+ * To accommodate these use cases, decomposer ended up rather complex.
*
* 1) These types are handled by adding SFINAE overloads to our comparison
* operators, checking whether `T == U` are comparable with the given
@@ -5311,7 +5323,7 @@ namespace Catch {
public:
constexpr auto isBinaryExpression() const -> bool { return m_isBinaryExpression; }
constexpr auto getResult() const -> bool { return m_result; }
- //! This function **has** to be overriden by the derived class.
+ //! This function **has** to be overridden by the derived class.
virtual void streamReconstructedExpression( std::ostream& os ) const;
constexpr ITransientExpression( bool isBinaryExpression, bool result )
@@ -5912,7 +5924,7 @@ namespace Catch {
#else
// These section definitions imply that at most one section at one level
-// will be intered (because only one section's __LINE__ can be equal to
+// will be entered (because only one section's __LINE__ can be equal to
// the dummy `catchInternalSectionHint` variable from `TEST_CASE`).
namespace Catch {
@@ -6195,6 +6207,53 @@ static int catchInternalSectionHint = 0;
#endif // CATCH_TEST_REGISTRY_HPP_INCLUDED
+#ifndef CATCH_UNREACHABLE_HPP_INCLUDED
+#define CATCH_UNREACHABLE_HPP_INCLUDED
+
+/**\file
+ * Polyfill `std::unreachable`
+ *
+ * We need something like `std::unreachable` to tell the compiler that
+ * some macros, e.g. `FAIL` or `SKIP`, do not continue execution in normal
+ * manner, and should handle it as such, e.g. not warn if there is no return
+ * from non-void function after a `FAIL` or `SKIP`.
+ */
+
+#include
+
+#if defined( __cpp_lib_unreachable ) && __cpp_lib_unreachable > 202202L
+# include
+namespace Catch {
+ namespace Detail {
+ using Unreachable = std::unreachable;
+ }
+} // namespace Catch
+
+#else // vv If we do not have std::unreachable, we implement something similar
+
+namespace Catch {
+ namespace Detail {
+
+ [[noreturn]]
+ inline void Unreachable() noexcept {
+# if defined( NDEBUG )
+# if defined( _MSC_VER ) && !defined( __clang__ )
+ __assume( false );
+# elif defined( __GNUC__ )
+ __builtin_unreachable();
+# endif
+# endif // ^^ NDEBUG
+ std::terminate();
+ }
+
+ } // namespace Detail
+} // end namespace Catch
+
+#endif
+
+#endif // CATCH_UNREACHABLE_HPP_INCLUDED
+
+
// All of our user-facing macros support configuration toggle, that
// forces them to be defined prefixed with CATCH_. We also like to
// support another toggle that can minimize (disable) their implementation.
@@ -6226,10 +6285,16 @@ static int catchInternalSectionHint = 0;
#define CATCH_REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ )
#define CATCH_SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ )
#define CATCH_DYNAMIC_SECTION( ... ) INTERNAL_CATCH_DYNAMIC_SECTION( __VA_ARGS__ )
- #define CATCH_FAIL( ... ) INTERNAL_CATCH_MSG( "CATCH_FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ )
+ #define CATCH_FAIL( ... ) do { \
+ INTERNAL_CATCH_MSG("CATCH_FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ ); \
+ Catch::Detail::Unreachable(); \
+ } while ( false )
#define CATCH_FAIL_CHECK( ... ) INTERNAL_CATCH_MSG( "CATCH_FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
#define CATCH_SUCCEED( ... ) INTERNAL_CATCH_MSG( "CATCH_SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
- #define CATCH_SKIP( ... ) INTERNAL_CATCH_MSG( "SKIP", Catch::ResultWas::ExplicitSkip, Catch::ResultDisposition::Normal, __VA_ARGS__ )
+ #define CATCH_SKIP( ... ) do { \
+ INTERNAL_CATCH_MSG( "CATCH_SKIP", Catch::ResultWas::ExplicitSkip, Catch::ResultDisposition::Normal, __VA_ARGS__ ); \
+ Catch::Detail::Unreachable(); \
+ } while (false)
#if !defined(CATCH_CONFIG_RUNTIME_STATIC_REQUIRE)
@@ -6327,10 +6392,16 @@ static int catchInternalSectionHint = 0;
#define REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ )
#define SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ )
#define DYNAMIC_SECTION( ... ) INTERNAL_CATCH_DYNAMIC_SECTION( __VA_ARGS__ )
- #define FAIL( ... ) INTERNAL_CATCH_MSG( "FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ )
+ #define FAIL( ... ) do { \
+ INTERNAL_CATCH_MSG( "FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ ); \
+ Catch::Detail::Unreachable(); \
+ } while (false)
#define FAIL_CHECK( ... ) INTERNAL_CATCH_MSG( "FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
#define SUCCEED( ... ) INTERNAL_CATCH_MSG( "SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
- #define SKIP( ... ) INTERNAL_CATCH_MSG( "SKIP", Catch::ResultWas::ExplicitSkip, Catch::ResultDisposition::Normal, __VA_ARGS__ )
+ #define SKIP( ... ) do { \
+ INTERNAL_CATCH_MSG( "SKIP", Catch::ResultWas::ExplicitSkip, Catch::ResultDisposition::Normal, __VA_ARGS__ ); \
+ Catch::Detail::Unreachable(); \
+ } while (false)
#if !defined(CATCH_CONFIG_RUNTIME_STATIC_REQUIRE)
@@ -6424,6 +6495,15 @@ static int catchInternalSectionHint = 0;
#endif
+namespace Catch {
+ namespace Detail {
+ template
+ struct priority_tag : priority_tag {};
+ template <>
+ struct priority_tag<0> {};
+ }
+}
+
#define CATCH_RECURSION_LEVEL0(...) __VA_ARGS__
#define CATCH_RECURSION_LEVEL1(...) CATCH_RECURSION_LEVEL0(CATCH_RECURSION_LEVEL0(CATCH_RECURSION_LEVEL0(__VA_ARGS__)))
#define CATCH_RECURSION_LEVEL2(...) CATCH_RECURSION_LEVEL1(CATCH_RECURSION_LEVEL1(CATCH_RECURSION_LEVEL1(__VA_ARGS__)))
@@ -6483,10 +6563,10 @@ static int catchInternalSectionHint = 0;
#define INTERNAL_CATCH_MAKE_NAMESPACE(name) INTERNAL_CATCH_MAKE_NAMESPACE2(name)
#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
-#define INTERNAL_CATCH_MAKE_TYPE_LIST2(...) decltype(get_wrapper())
+#define INTERNAL_CATCH_MAKE_TYPE_LIST2(...) decltype(get_wrapper(Catch::Detail::priority_tag<1>{}))
#define INTERNAL_CATCH_MAKE_TYPE_LIST(...) INTERNAL_CATCH_MAKE_TYPE_LIST2(INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__))
#else
-#define INTERNAL_CATCH_MAKE_TYPE_LIST2(...) INTERNAL_CATCH_EXPAND_VARGS(decltype(get_wrapper()))
+#define INTERNAL_CATCH_MAKE_TYPE_LIST2(...) INTERNAL_CATCH_EXPAND_VARGS(decltype(get_wrapper(Catch::Detail::priority_tag<1>{})))
#define INTERNAL_CATCH_MAKE_TYPE_LIST(...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_MAKE_TYPE_LIST2(INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__)))
#endif
@@ -6509,11 +6589,11 @@ static int catchInternalSectionHint = 0;
#define INTERNAL_CATCH_TYPE_GEN\
template struct TypeList {};\
- template\
- constexpr auto get_wrapper() noexcept -> TypeList { return {}; }\
+ template\
+ constexpr auto get_wrapper(Catch::Detail::priority_tag<1>) noexcept -> TypeList { return {}; }\
template class...> struct TemplateTypeList{};\
template class...Cs>\
- constexpr auto get_wrapper() noexcept -> TemplateTypeList { return {}; }\
+ constexpr auto get_wrapper(Catch::Detail::priority_tag<1>) noexcept -> TemplateTypeList { return {}; }\
template\
struct append;\
template\
@@ -6543,10 +6623,10 @@ static int catchInternalSectionHint = 0;
#define INTERNAL_CATCH_NTTP_1(signature, ...)\
template struct Nttp{};\
template\
- constexpr auto get_wrapper() noexcept -> Nttp<__VA_ARGS__> { return {}; } \
+ constexpr auto get_wrapper(Catch::Detail::priority_tag<0>) noexcept -> Nttp<__VA_ARGS__> { return {}; } \
template class...> struct NttpTemplateTypeList{};\
template class...Cs>\
- constexpr auto get_wrapper() noexcept -> NttpTemplateTypeList { return {}; } \
+ constexpr auto get_wrapper(Catch::Detail::priority_tag<0>) noexcept -> NttpTemplateTypeList { return {}; } \
\
template< template class Container, template class List, INTERNAL_CATCH_REMOVE_PARENS(signature)>\
struct rewrap, List<__VA_ARGS__>> { using type = TypeList>; };\
@@ -6571,13 +6651,14 @@ static int catchInternalSectionHint = 0;
template\
static void TestName()
-#define INTERNAL_CATCH_NTTP_REGISTER0(TestFunc, signature)\
- template\
- void reg_test(TypeList, Catch::NameAndTags nameAndTags)\
+#define INTERNAL_CATCH_TYPES_REGISTER(TestFunc)\
+ template\
+ void reg_test(TypeList, Catch::NameAndTags nameAndTags)\
{\
- Catch::AutoReg( Catch::makeTestInvoker(&TestFunc), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), nameAndTags);\
+ Catch::AutoReg( Catch::makeTestInvoker(&TestFunc), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), nameAndTags);\
}
+#define INTERNAL_CATCH_NTTP_REGISTER0(TestFunc, signature, ...)
#define INTERNAL_CATCH_NTTP_REGISTER(TestFunc, signature, ...)\
template\
void reg_test(Nttp<__VA_ARGS__>, Catch::NameAndTags nameAndTags)\
@@ -6626,7 +6707,7 @@ static int catchInternalSectionHint = 0;
#define INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD(TestName, ...) INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD1, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD0)(TestName, __VA_ARGS__)
#define INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD(TestName, ClassName, ...) INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD1, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD0)(TestName, ClassName, __VA_ARGS__)
#define INTERNAL_CATCH_NTTP_REG_METHOD_GEN(TestName, ...) INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD0, INTERNAL_CATCH_NTTP_REGISTER_METHOD0)(TestName, __VA_ARGS__)
-#define INTERNAL_CATCH_NTTP_REG_GEN(TestFunc, ...) INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER0, INTERNAL_CATCH_NTTP_REGISTER0)(TestFunc, __VA_ARGS__)
+#define INTERNAL_CATCH_NTTP_REG_GEN(TestFunc, ...) INTERNAL_CATCH_TYPES_REGISTER(TestFunc) INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER0, INTERNAL_CATCH_NTTP_REGISTER0)(TestFunc, __VA_ARGS__)
#define INTERNAL_CATCH_DEFINE_SIG_TEST(TestName, ...) INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X,INTERNAL_CATCH_DEFINE_SIG_TEST_X,INTERNAL_CATCH_DEFINE_SIG_TEST1, INTERNAL_CATCH_DEFINE_SIG_TEST0)(TestName, __VA_ARGS__)
#define INTERNAL_CATCH_DECLARE_SIG_TEST(TestName, ...) INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_DECLARE_SIG_TEST_X,INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X,INTERNAL_CATCH_DECLARE_SIG_TEST_X,INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST1, INTERNAL_CATCH_DECLARE_SIG_TEST0)(TestName, __VA_ARGS__)
#define INTERNAL_CATCH_REMOVE_PARENS_GEN(...) INTERNAL_CATCH_VA_NARGS_IMPL(__VA_ARGS__, INTERNAL_CATCH_REMOVE_PARENS_11_ARG,INTERNAL_CATCH_REMOVE_PARENS_10_ARG,INTERNAL_CATCH_REMOVE_PARENS_9_ARG,INTERNAL_CATCH_REMOVE_PARENS_8_ARG,INTERNAL_CATCH_REMOVE_PARENS_7_ARG,INTERNAL_CATCH_REMOVE_PARENS_6_ARG,INTERNAL_CATCH_REMOVE_PARENS_5_ARG,INTERNAL_CATCH_REMOVE_PARENS_4_ARG,INTERNAL_CATCH_REMOVE_PARENS_3_ARG,INTERNAL_CATCH_REMOVE_PARENS_2_ARG,INTERNAL_CATCH_REMOVE_PARENS_1_ARG)(__VA_ARGS__)
@@ -6636,7 +6717,7 @@ static int catchInternalSectionHint = 0;
#define INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD(TestName, ...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD1, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD0)(TestName, __VA_ARGS__))
#define INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD(TestName, ClassName, ...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD1, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD0)(TestName, ClassName, __VA_ARGS__))
#define INTERNAL_CATCH_NTTP_REG_METHOD_GEN(TestName, ...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD0, INTERNAL_CATCH_NTTP_REGISTER_METHOD0)(TestName, __VA_ARGS__))
-#define INTERNAL_CATCH_NTTP_REG_GEN(TestFunc, ...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER0, INTERNAL_CATCH_NTTP_REGISTER0)(TestFunc, __VA_ARGS__))
+#define INTERNAL_CATCH_NTTP_REG_GEN(TestFunc, ...) INTERNAL_CATCH_TYPES_REGISTER(TestFunc) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER0, INTERNAL_CATCH_NTTP_REGISTER0)(TestFunc, __VA_ARGS__))
#define INTERNAL_CATCH_DEFINE_SIG_TEST(TestName, ...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X,INTERNAL_CATCH_DEFINE_SIG_TEST_X,INTERNAL_CATCH_DEFINE_SIG_TEST1, INTERNAL_CATCH_DEFINE_SIG_TEST0)(TestName, __VA_ARGS__))
#define INTERNAL_CATCH_DECLARE_SIG_TEST(TestName, ...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_DECLARE_SIG_TEST_X,INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X,INTERNAL_CATCH_DECLARE_SIG_TEST_X,INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST1, INTERNAL_CATCH_DECLARE_SIG_TEST0)(TestName, __VA_ARGS__))
#define INTERNAL_CATCH_REMOVE_PARENS_GEN(...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_VA_NARGS_IMPL(__VA_ARGS__, INTERNAL_CATCH_REMOVE_PARENS_11_ARG,INTERNAL_CATCH_REMOVE_PARENS_10_ARG,INTERNAL_CATCH_REMOVE_PARENS_9_ARG,INTERNAL_CATCH_REMOVE_PARENS_8_ARG,INTERNAL_CATCH_REMOVE_PARENS_7_ARG,INTERNAL_CATCH_REMOVE_PARENS_6_ARG,INTERNAL_CATCH_REMOVE_PARENS_5_ARG,INTERNAL_CATCH_REMOVE_PARENS_4_ARG,INTERNAL_CATCH_REMOVE_PARENS_3_ARG,INTERNAL_CATCH_REMOVE_PARENS_2_ARG,INTERNAL_CATCH_REMOVE_PARENS_1_ARG)(__VA_ARGS__))
@@ -6765,11 +6846,11 @@ static int catchInternalSectionHint = 0;
constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TmplTypes))};\
constexpr char const* types_list[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TypesList))};\
constexpr auto num_types = sizeof(types_list) / sizeof(types_list[0]);\
- (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestFuncName ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index / num_types]) + '<' + std::string(types_list[index % num_types]) + '>', Tags } ), index++)... };/* NOLINT */\
+ (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestFuncName ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index / num_types]) + '<' + types_list[index % num_types] + '>', Tags } ), index++)... };/* NOLINT */\
} \
}; \
- static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){ \
- using TestInit = typename create()), TypeList>::type; \
+ static const int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){ \
+ using TestInit = typename create(Catch::Detail::priority_tag<1>{})), TypeList>::type; \
TestInit t; \
t.reg_tests(); \
return 0; \
@@ -6814,7 +6895,7 @@ static int catchInternalSectionHint = 0;
(void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestFunc ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ Name " - " INTERNAL_CATCH_STRINGIZE(TmplList) " - " + std::to_string(index), Tags } ), index++)... };/* NOLINT */\
} \
};\
- static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){ \
+ static const int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){ \
using TestInit = typename convert::type; \
TestInit t; \
t.reg_tests(); \
@@ -6850,7 +6931,7 @@ static int catchInternalSectionHint = 0;
(void)expander{(reg_test(Types{}, #ClassName, Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index]), Tags } ), index++)... };/* NOLINT */ \
}\
};\
- static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\
+ static const int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\
TestNameClass();\
return 0;\
}();\
@@ -6897,11 +6978,11 @@ static int catchInternalSectionHint = 0;
constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TmplTypes))};\
constexpr char const* types_list[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TypesList))};\
constexpr auto num_types = sizeof(types_list) / sizeof(types_list[0]);\
- (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestName::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index / num_types]) + '<' + std::string(types_list[index % num_types]) + '>', Tags } ), index++)... };/* NOLINT */ \
+ (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestName::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index / num_types]) + '<' + types_list[index % num_types] + '>', Tags } ), index++)... };/* NOLINT */ \
}\
};\
- static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\
- using TestInit = typename create()), TypeList>::type;\
+ static const int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\
+ using TestInit = typename create(Catch::Detail::priority_tag<1>{})), TypeList>::type;\
TestInit t;\
t.reg_tests();\
return 0;\
@@ -6949,7 +7030,7 @@ static int catchInternalSectionHint = 0;
(void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestName::test ), CATCH_INTERNAL_LINEINFO, #ClassName##_catch_sr, Catch::NameAndTags{ Name " - " INTERNAL_CATCH_STRINGIZE(TmplList) " - " + std::to_string(index), Tags } ), index++)... };/* NOLINT */ \
}\
};\
- static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\
+ static const int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\
using TestInit = typename convert::type;\
TestInit t;\
t.reg_tests();\
@@ -7201,6 +7282,22 @@ namespace Catch {
#endif // CATCH_TEST_CASE_INFO_HPP_INCLUDED
+#ifndef CATCH_TEST_RUN_INFO_HPP_INCLUDED
+#define CATCH_TEST_RUN_INFO_HPP_INCLUDED
+
+
+namespace Catch {
+
+ struct TestRunInfo {
+ constexpr TestRunInfo(StringRef _name) : name(_name) {}
+ StringRef name;
+ };
+
+} // end namespace Catch
+
+#endif // CATCH_TEST_RUN_INFO_HPP_INCLUDED
+
+
#ifndef CATCH_TRANSLATE_EXCEPTION_HPP_INCLUDED
#define CATCH_TRANSLATE_EXCEPTION_HPP_INCLUDED
@@ -7288,7 +7385,7 @@ namespace Catch {
static std::string translatorName( signature ); \
CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
- namespace{ Catch::ExceptionTranslatorRegistrar INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionRegistrar )( &translatorName ); } \
+ namespace{ const Catch::ExceptionTranslatorRegistrar INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionRegistrar )( &translatorName ); } \
CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
static std::string translatorName( signature )
@@ -7349,8 +7446,8 @@ namespace Catch {
#define CATCH_VERSION_MACROS_HPP_INCLUDED
#define CATCH_VERSION_MAJOR 3
-#define CATCH_VERSION_MINOR 8
-#define CATCH_VERSION_PATCH 1
+#define CATCH_VERSION_MINOR 9
+#define CATCH_VERSION_PATCH 0
#endif // CATCH_VERSION_MACROS_HPP_INCLUDED
@@ -7391,7 +7488,7 @@ namespace Catch {
m_msg(msg)
{}
- const char* what() const noexcept override final;
+ const char* what() const noexcept final;
};
} // end namespace Catch
@@ -8778,26 +8875,9 @@ auto from_range(Container const& cnt) {
#define CATCH_INTERFACES_REPORTER_HPP_INCLUDED
-
-#ifndef CATCH_TEST_RUN_INFO_HPP_INCLUDED
-#define CATCH_TEST_RUN_INFO_HPP_INCLUDED
-
-
-namespace Catch {
-
- struct TestRunInfo {
- constexpr TestRunInfo(StringRef _name) : name(_name) {}
- StringRef name;
- };
-
-} // end namespace Catch
-
-#endif // CATCH_TEST_RUN_INFO_HPP_INCLUDED
-
#include