From b3fb4b9feafcd8d91c5cb510a4775143fdbef02f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Ho=C5=99e=C5=88ovsk=C3=BD?= Date: Tue, 30 Sep 2025 10:54:31 +0200 Subject: [PATCH] v3.11.0 --- CMakeLists.txt | 2 +- docs/ci-and-misc.md | 2 +- docs/command-line.md | 2 +- docs/release-notes.md | 23 +++ extras/catch_amalgamated.cpp | 268 ++++++++++++++++++---------- extras/catch_amalgamated.hpp | 76 ++++---- meson.build | 2 +- src/catch2/catch_version.cpp | 2 +- src/catch2/catch_version_macros.hpp | 2 +- 9 files changed, 243 insertions(+), 136 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 37c48ca5..918927c4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -35,7 +35,7 @@ if(CMAKE_BINARY_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) endif() project(Catch2 - VERSION 3.10.0 # CML version placeholder, don't delete + VERSION 3.11.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/ci-and-misc.md b/docs/ci-and-misc.md index 1b57a912..879a15fc 100644 --- a/docs/ci-and-misc.md +++ b/docs/ci-and-misc.md @@ -73,7 +73,7 @@ test execution. Specifically it understands > Support for `TESTBRIDGE_TEST_ONLY` and sharding was introduced in Catch2 3.2.0 -> Support for `TEST_PREMATURE_EXIT_FILE` and `TEST_RANDOM_SEED` was introduced in Catch2 X.Y.Z +> Support for `TEST_PREMATURE_EXIT_FILE` and `TEST_RANDOM_SEED` was introduced in Catch2 3.11.0 This integration is enabled via either a [compile time configuration option](configuration.md#bazel-support), or via `BAZEL_TEST` environment diff --git a/docs/command-line.md b/docs/command-line.md index 651efd01..690dcaaa 100644 --- a/docs/command-line.md +++ b/docs/command-line.md @@ -653,7 +653,7 @@ Verbosity defaults to _normal_. ## Create file to guard against silent early termination
--premature-exit-guard-file <path>
-> Introduced in Catch2 X.Y.Z +> Introduced in Catch2 3.11.0 Tells Catch2 to create an empty file at specified path before the tests start, and delete it after the tests finish. If the file is present after diff --git a/docs/release-notes.md b/docs/release-notes.md index 54711742..9da1a2e1 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -2,6 +2,7 @@ # Release notes **Contents**
+[3.11.0](#3110)
[3.10.0](#3100)
[3.9.1](#391)
[3.9.0](#390)
@@ -70,6 +71,28 @@ [Even Older versions](#even-older-versions)
+## 3.11.0 + +### Fixes +* Fixed building on non-desktop GDK platforms (#3029) +* Fixed message macros being susceptible to race in specific scenario (#3031) +* Catch2's SEH filter will call the previously installed filter after reporting the error (#3033) + +### Improvements +* Handling of scoped messages (e.g. `CAPTURE`) is a bit faster. +* Better out-of-the-box support for QNX (#2953) +* Improved performance of assertions by up-to 10% + * Release mode assertion fast-path sees the biggest improvement. +* Faster processing of non-escaped strings in `--invisibles` mode. +* Added support for Bazel's `TEST_RANDOM_SEED` env var (#3021) +* Added support for Bazel's `TEST_PREMATURE_EXIT_FILE` env var (#3020) + * This creates a file that is deleted if the tests exit normally, but stays around if the process dies unexpectedly. + * This functionality is also exposed through CLI as `--premature-exit-guard-file` + +### Miscellaneous +* **[Tuple.app](https://tuple.app/catch2) has sponsored Catch2** + + ## 3.10.0 ### Fixes diff --git a/extras/catch_amalgamated.cpp b/extras/catch_amalgamated.cpp index c85f39b3..892d637d 100644 --- a/extras/catch_amalgamated.cpp +++ b/extras/catch_amalgamated.cpp @@ -6,8 +6,8 @@ // SPDX-License-Identifier: BSL-1.0 -// Catch v3.10.0 -// Generated: 2025-08-24 16:18:04.775778 +// Catch v3.11.0 +// Generated: 2025-09-30 10:49:12.549018 // ---------------------------------------------------------- // This file is an amalgamation of multiple different files. // You probably shouldn't edit it directly. @@ -825,6 +825,8 @@ namespace Catch { m_data.reporterSpecifications.push_back( std::move( *parsed ) ); } + // Reading bazel env vars can change some parts of the config data, + // so we have to process the bazel env before acting on the config. if ( enableBazelEnvSupport() ) { readBazelEnvVars(); } @@ -889,6 +891,8 @@ namespace Catch { bool Config::showHelp() const { return m_data.showHelp; } + std::string const& Config::getExitGuardFilePath() const { return m_data.prematureExitGuardFilePath; } + // IConfig interface bool Config::allowThrows() const { return !m_data.noThrow; } StringRef Config::name() const { return m_data.name.empty() ? m_data.processName : m_data.name; } @@ -950,6 +954,26 @@ namespace Catch { m_data.shardCount = bazelShardOptions->shardCount; } } + + const auto bazelExitGuardFile = Detail::getEnv( "TEST_PREMATURE_EXIT_FILE" ); + if (bazelExitGuardFile) { + m_data.prematureExitGuardFilePath = bazelExitGuardFile; + } + + const auto bazelRandomSeed = Detail::getEnv( "TEST_RANDOM_SEED" ); + if ( bazelRandomSeed ) { + auto parsedSeed = parseUInt( bazelRandomSeed, 0 ); + if ( !parsedSeed ) { + // Currently we handle issues with parsing other Bazel Env + // options by warning and ignoring the issue. So we do the + // same for random seed option. + Catch::cerr() + << "Warning: could not parse 'TEST_RANDOM_SEED' ('" + << bazelRandomSeed << "') as proper seed.\n"; + } else { + m_data.rngSeed = *parsedSeed; + } + } } } // end namespace Catch @@ -975,28 +999,26 @@ namespace Catch { ScopedMessage::ScopedMessage( MessageBuilder&& builder ): - m_info( CATCH_MOVE(builder.m_info) ) { - m_info.message = builder.m_stream.str(); - getResultCapture().pushScopedMessage( m_info ); + m_messageId( builder.m_info.sequence ) { + MessageInfo info( CATCH_MOVE( builder.m_info ) ); + info.message = builder.m_stream.str(); + IResultCapture::pushScopedMessage( CATCH_MOVE( info ) ); } ScopedMessage::ScopedMessage( ScopedMessage&& old ) noexcept: - m_info( CATCH_MOVE( old.m_info ) ) { + m_messageId( old.m_messageId ) { old.m_moved = true; } ScopedMessage::~ScopedMessage() { - if ( !m_moved ){ - getResultCapture().popScopedMessage(m_info); - } + if ( !m_moved ) { IResultCapture::popScopedMessage( m_messageId ); } } Capturer::Capturer( StringRef macroName, SourceLineInfo const& lineInfo, ResultWas::OfType resultType, - StringRef names ): - m_resultCapture( getResultCapture() ) { + StringRef names ) { auto trimmed = [&] (size_t start, size_t end) { while (names[start] == ',' || isspace(static_cast(names[start]))) { ++start; @@ -1042,8 +1064,8 @@ namespace Catch { case ',': if (start != pos && openings.empty()) { m_messages.emplace_back(macroName, lineInfo, resultType); - m_messages.back().message = static_cast(trimmed(start, pos)); - m_messages.back().message += " := "; + m_messages.back().message += trimmed(start, pos); + m_messages.back().message += " := "_sr; start = pos; } break; @@ -1052,20 +1074,20 @@ namespace Catch { } assert(openings.empty() && "Mismatched openings"); m_messages.emplace_back(macroName, lineInfo, resultType); - m_messages.back().message = static_cast(trimmed(start, names.size() - 1)); - m_messages.back().message += " := "; + m_messages.back().message += trimmed(start, names.size() - 1); + m_messages.back().message += " := "_sr; } Capturer::~Capturer() { assert( m_captured == m_messages.size() ); - for ( size_t i = 0; i < m_captured; ++i ) { - m_resultCapture.popScopedMessage( m_messages[i] ); + 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; - m_resultCapture.pushScopedMessage( m_messages[index] ); + IResultCapture::pushScopedMessage( CATCH_MOVE( m_messages[index] ) ); m_captured++; } @@ -1149,7 +1171,6 @@ namespace Catch { } void cleanUp() { cleanupSingletons(); - cleanUpContext(); } std::string translateActiveException() { return getRegistryHub().getExceptionTranslatorRegistry().translateActiveException(); @@ -1161,6 +1182,8 @@ namespace Catch { #include +#include +#include #include #include #include @@ -1275,6 +1298,50 @@ namespace Catch { } } + // Creates empty file at path. The path must be writable, we do not + // try to create directories in path because that's hard in C++14. + void setUpGuardFile( std::string const& guardFilePath ) { + if ( !guardFilePath.empty() ) { +#if defined( _MSC_VER ) + std::FILE* file = nullptr; + if ( fopen_s( &file, guardFilePath.c_str(), "w" ) ) { + char msgBuffer[100]; + const auto err = errno; + std::string errMsg; + if ( !strerror_s( msgBuffer, err ) ) { + errMsg = msgBuffer; + } else { + errMsg = "Could not translate errno to a string"; + } + +#else + std::FILE* file = std::fopen( guardFilePath.c_str(), "w" ); + if ( !file ) { + const auto err = errno; + const char* errMsg = std::strerror( err ); +#endif + + CATCH_RUNTIME_ERROR( "Could not open the exit guard file '" + << guardFilePath << "' because '" + << errMsg << "' (" << err << ')' ); + } + const int ret = std::fclose( file ); + CATCH_ENFORCE( + ret == 0, + "Error when closing the exit guard file: " << ret ); + } + } + + // Removes file at path. Assuming we created it in setUpGuardFile. + void tearDownGuardFile( std::string const& guardFilePath ) { + if ( !guardFilePath.empty() ) { + const int ret = std::remove( guardFilePath.c_str() ); + CATCH_ENFORCE( + ret == 0, + "Error when removing the exit guard file: " << ret ); + } + } + } // anon namespace Session::Session() { @@ -1393,6 +1460,7 @@ namespace Catch { static_cast(std::getchar()); } int exitCode = runInternal(); + if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeExit ) != 0 ) { Catch::cout() << "...waiting for enter/ return before exiting, with code: " << exitCode << '\n' << std::flush; static_cast(std::getchar()); @@ -1433,6 +1501,10 @@ namespace Catch { CATCH_TRY { config(); // Force config to be constructed + // We need to retrieve potential Bazel config with the full Config + // constructor, so we have to create the guard file after it is created. + setUpGuardFile( m_config->getExitGuardFilePath() ); + seedRng( *m_config ); if (m_configData.filenamesAsTags) { @@ -1462,9 +1534,12 @@ namespace Catch { TestGroup tests { CATCH_MOVE(reporter), m_config.get() }; auto const totals = tests.execute(); + // If we got here, running the tests finished normally-enough. + // They might've failed, but that would've been reported elsewhere. + tearDownGuardFile( m_config->getExitGuardFilePath() ); + if ( tests.hadUnmatchedTestSpecs() && m_config->warnAboutUnmatchedTestSpecs() ) { - // UnmatchedTestSpecExitCode return UnmatchedTestSpecExitCode; } @@ -1974,35 +2049,35 @@ namespace Detail { std::string ret; // This is enough for the "don't escape invisibles" case, and a good // lower bound on the "escape invisibles" case. - ret.reserve(string.size() + 2); + ret.reserve( string.size() + 2 ); - if (!escapeInvisibles) { + if ( !escapeInvisibles ) { ret += '"'; ret += string; ret += '"'; return ret; } + size_t last_start = 0; + auto write_to = [&]( size_t idx ) { + if ( last_start < idx ) { + ret += string.substr( last_start, idx - last_start ); + } + last_start = idx + 1; + }; + ret += '"'; - for (char c : string) { - switch (c) { - case '\r': - ret.append("\\r"); - break; - case '\n': - ret.append("\\n"); - break; - case '\t': - ret.append("\\t"); - break; - case '\f': - ret.append("\\f"); - break; - default: - ret.push_back(c); - break; + for ( size_t i = 0; i < string.size(); ++i ) { + const char c = string[i]; + if ( c == '\r' || c == '\n' || c == '\t' || c == '\f' ) { + write_to( i ); + if ( c == '\r' ) { ret.append( "\\r" ); } + if ( c == '\n' ) { ret.append( "\\n" ); } + if ( c == '\t' ) { ret.append( "\\t" ); } + if ( c == '\f' ) { ret.append( "\\f" ); } } } + write_to( string.size() ); ret += '"'; return ret; @@ -2279,7 +2354,7 @@ namespace Catch { } Version const& libraryVersion() { - static Version version( 3, 10, 0, "", 0 ); + static Version version( 3, 11, 0, "", 0 ); return version; } @@ -2367,8 +2442,14 @@ namespace Catch { namespace Catch { + namespace Detail { + void missingCaptureInstance() { + CATCH_INTERNAL_ERROR( "No result capture instance" ); + } + } // namespace Detail + IResultCapture::~IResultCapture() = default; -} +} // namespace Catch @@ -3361,6 +3442,9 @@ namespace Catch { | Opt( config.allowZeroTests ) ["--allow-running-no-tests"] ( "Treat 'No tests run' as a success" ) + | Opt( config.prematureExitGuardFilePath, "path" ) + ["--premature-exit-guard-file"] + ( "create a file before running tests and delete it during clean exit" ) | Arg( config.testsOrTags, "test name|pattern|tags" ) ( "which test or tests to use" ); @@ -3515,7 +3599,11 @@ namespace { #endif // Windows/ ANSI/ None -#if defined( CATCH_PLATFORM_LINUX ) || defined( CATCH_PLATFORM_MAC ) || defined( __GLIBC__ ) || defined(__FreeBSD__) +#if defined( CATCH_PLATFORM_LINUX ) \ + || defined( CATCH_PLATFORM_MAC ) \ + || defined( __GLIBC__ ) \ + || defined( __FreeBSD__ ) \ + || defined( CATCH_PLATFORM_QNX ) # define CATCH_INTERNAL_HAS_ISATTY # include #endif @@ -3639,20 +3727,10 @@ namespace Catch { namespace Catch { - Context* Context::currentContext = nullptr; - - void cleanUpContext() { - delete Context::currentContext; - Context::currentContext = nullptr; - } - void Context::createContext() { - currentContext = new Context(); - } + Context Context::currentContext; Context& getCurrentMutableContext() { - if ( !Context::currentContext ) { Context::createContext(); } - // NOLINTNEXTLINE(clang-analyzer-core.uninitialized.UndefReturn) - return *Context::currentContext; + return Context::currentContext; } SimplePcg32& sharedRng() { @@ -3757,7 +3835,7 @@ namespace Catch { #endif } // namespace Catch -#elif defined(CATCH_PLATFORM_LINUX) +#elif defined(CATCH_PLATFORM_LINUX) || defined(CATCH_PLATFORM_QNX) #include #include @@ -4091,23 +4169,27 @@ namespace Catch { { EXCEPTION_INT_DIVIDE_BY_ZERO, "Divide by zero error" }, }; + // Since we do not support multiple instantiations, we put these + // into global variables and rely on cleaning them up in outlined + // constructors/destructors + static LPTOP_LEVEL_EXCEPTION_FILTER previousTopLevelExceptionFilter = nullptr; + + static LONG CALLBACK topLevelExceptionFilter(PEXCEPTION_POINTERS ExceptionInfo) { for (auto const& def : signalDefs) { if (ExceptionInfo->ExceptionRecord->ExceptionCode == def.id) { reportFatal(def.name); } } - // If its not an exception we care about, pass it along. + // If a filter was previously registered, invoke it + if (previousTopLevelExceptionFilter) { + return previousTopLevelExceptionFilter(ExceptionInfo); + } + // Otherwise, pass along all exceptions. // This stops us from eating debugger breaks etc. return EXCEPTION_CONTINUE_SEARCH; } - // Since we do not support multiple instantiations, we put these - // into global variables and rely on cleaning them up in outlined - // constructors/destructors - static LPTOP_LEVEL_EXCEPTION_FILTER previousTopLevelExceptionFilter = nullptr; - - // For MSVC, we reserve part of the stack memory for handling // memory overflow structured exception. FatalConditionHandler::FatalConditionHandler() { @@ -5565,6 +5647,7 @@ ReporterSpec::ReporterSpec( #include #include +#include #include namespace Catch { @@ -5576,16 +5659,16 @@ namespace Catch { std::ostringstream m_referenceStream; // Used for copy state/ flags from Detail::Mutex m_mutex; - auto add() -> std::size_t { + auto add() -> std::pair { Detail::LockGuard _( m_mutex ); if( m_unused.empty() ) { m_streams.push_back( Detail::make_unique() ); - return m_streams.size()-1; + return { m_streams.size()-1, m_streams.back().get() }; } else { auto index = m_unused.back(); m_unused.pop_back(); - return index; + return { index, m_streams[index].get() }; } } @@ -5599,10 +5682,10 @@ namespace Catch { } }; - ReusableStringStream::ReusableStringStream() - : m_index( Singleton::getMutable().add() ), - m_oss( Singleton::getMutable().m_streams[m_index].get() ) - {} + ReusableStringStream::ReusableStringStream() { + std::tie( m_index, m_oss ) = + Singleton::getMutable().add(); + } ReusableStringStream::~ReusableStringStream() { static_cast( m_oss )->str(""); @@ -6085,28 +6168,6 @@ namespace Catch { m_reporter->benchmarkFailed( error ); } - void RunContext::pushScopedMessage( MessageInfo const& message ) { - Detail::g_messages.push_back( message ); - } - - 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. - Detail::g_messages.erase( - std::find_if( Detail::g_messages.begin(), - Detail::g_messages.end(), - [id = message.sequence]( MessageInfo const& msg ) { - return msg.sequence == id; - } ) ); - } - - void RunContext::emplaceUnscopedMessage( MessageBuilder&& builder ) { - Detail::g_messageScopes.emplace_back( CATCH_MOVE(builder) ); - } - std::string RunContext::getCurrentTestName() const { return m_activeTestCase ? m_activeTestCase->getTestCaseInfo().name @@ -6433,11 +6494,26 @@ namespace Catch { } } - IResultCapture& getResultCapture() { - if (auto* capture = getCurrentContext().getResultCapture()) - return *capture; - else - CATCH_INTERNAL_ERROR("No result capture instance"); + void IResultCapture::pushScopedMessage( MessageInfo&& message ) { + Detail::g_messages.push_back( CATCH_MOVE( message ) ); + } + + void IResultCapture::popScopedMessage( unsigned int messageId ) { + // 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. + Detail::g_messages.erase( std::find_if( Detail::g_messages.begin(), + Detail::g_messages.end(), + [=]( MessageInfo const& msg ) { + return msg.sequence == + messageId; + } ) ); + } + + void IResultCapture::emplaceUnscopedMessage( MessageBuilder&& builder ) { + Detail::g_messageScopes.emplace_back( CATCH_MOVE( builder ) ); } void seedRng(IConfig const& config) { diff --git a/extras/catch_amalgamated.hpp b/extras/catch_amalgamated.hpp index a67743b3..d5eb1bb7 100644 --- a/extras/catch_amalgamated.hpp +++ b/extras/catch_amalgamated.hpp @@ -6,8 +6,8 @@ // SPDX-License-Identifier: BSL-1.0 -// Catch v3.10.0 -// Generated: 2025-08-24 16:18:04.055916 +// Catch v3.11.0 +// Generated: 2025-09-30 10:49:11.225746 // ---------------------------------------------------------- // This file is an amalgamation of multiple different files. // You probably shouldn't edit it directly. @@ -101,6 +101,9 @@ #elif defined(linux) || defined(__linux) || defined(__linux__) # define CATCH_PLATFORM_LINUX +#elif defined(__QNX__) +# define CATCH_PLATFORM_QNX + #elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) || defined(__MINGW32__) # define CATCH_PLATFORM_WINDOWS @@ -308,13 +311,17 @@ # endif // Universal Windows platform does not support SEH -// Or console colours (or console at all...) -# if defined(CATCH_PLATFORM_WINDOWS_UWP) -# define CATCH_INTERNAL_CONFIG_NO_COLOUR_WIN32 -# else +# if !defined(CATCH_PLATFORM_WINDOWS_UWP) # define CATCH_INTERNAL_CONFIG_WINDOWS_SEH # endif +// Only some Windows platform families support the console +# if defined(WINAPI_FAMILY_PARTITION) +# if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) +# define CATCH_INTERNAL_CONFIG_NO_COLOUR_WIN32 +# endif +# endif + // MSVC traditional preprocessor needs some workaround for __VA_ARGS__ // _MSVC_TRADITIONAL == 0 means new conformant preprocessor // _MSVC_TRADITIONAL == 1 means old traditional non-conformant preprocessor @@ -564,11 +571,9 @@ namespace Catch { IConfig const* m_config = nullptr; IResultCapture* m_resultCapture = nullptr; - CATCH_EXPORT static Context* currentContext; + CATCH_EXPORT static Context currentContext; friend Context& getCurrentMutableContext(); friend Context const& getCurrentContext(); - static void createContext(); - friend void cleanUpContext(); public: constexpr IResultCapture* getResultCapture() const { @@ -579,21 +584,14 @@ namespace Catch { m_resultCapture = resultCapture; } constexpr void setConfig( IConfig const* config ) { m_config = config; } - }; Context& getCurrentMutableContext(); inline Context const& getCurrentContext() { - // We duplicate the logic from `getCurrentMutableContext` here, - // to avoid paying the call overhead in debug mode. - if ( !Context::currentContext ) { Context::createContext(); } - // NOLINTNEXTLINE(clang-analyzer-core.uninitialized.UndefReturn) - return *Context::currentContext; + return Context::currentContext; } - void cleanUpContext(); - class SimplePcg32; SimplePcg32& sharedRng(); } @@ -1069,10 +1067,9 @@ namespace Catch { virtual void benchmarkEnded( BenchmarkStats<> const& stats ) = 0; virtual void benchmarkFailed( StringRef error ) = 0; - virtual void pushScopedMessage( MessageInfo const& message ) = 0; - virtual void popScopedMessage( MessageInfo const& message ) = 0; - - virtual void emplaceUnscopedMessage( MessageBuilder&& builder ) = 0; + static void pushScopedMessage( MessageInfo&& message ); + static void popScopedMessage( unsigned int messageId ); + static void emplaceUnscopedMessage( MessageBuilder&& builder ); virtual void handleFatalErrorCondition( StringRef message ) = 0; @@ -1108,7 +1105,18 @@ namespace Catch { virtual void exceptionEarlyReported() = 0; }; - IResultCapture& getResultCapture(); + namespace Detail { + [[noreturn]] + void missingCaptureInstance(); + } + inline IResultCapture& getResultCapture() { + if (auto* capture = getCurrentContext().getResultCapture()) { + return *capture; + } else { + Detail::missingCaptureInstance(); + } + } + } #endif // CATCH_INTERFACES_CAPTURE_HPP_INCLUDED @@ -3800,6 +3808,8 @@ namespace Catch { std::vector testsOrTags; std::vector sectionsToRun; + + std::string prematureExitGuardFilePath; }; @@ -3827,6 +3837,8 @@ namespace Catch { bool showHelp() const; + std::string const& getExitGuardFilePath() const; + // IConfig interface bool allowThrows() const override; StringRef name() const override; @@ -3961,6 +3973,7 @@ namespace Catch { std::string message; SourceLineInfo lineInfo; ResultWas::OfType type; + // 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" ) @@ -4020,13 +4033,12 @@ namespace Catch { ScopedMessage( ScopedMessage&& old ) noexcept; ~ScopedMessage(); - MessageInfo m_info; + unsigned int m_messageId; bool m_moved = false; }; class Capturer { std::vector m_messages; - IResultCapture& m_resultCapture; size_t m_captured = 0; public: Capturer( StringRef macroName, SourceLineInfo const& lineInfo, ResultWas::OfType resultType, StringRef names ); @@ -4074,7 +4086,7 @@ namespace Catch { /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_UNSCOPED_INFO( macroName, log ) \ - Catch::getResultCapture().emplaceUnscopedMessage( Catch::MessageBuilder( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log ) + Catch::IResultCapture::emplaceUnscopedMessage( Catch::MessageBuilder( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log ) #if defined(CATCH_CONFIG_PREFIX_MESSAGES) && !defined(CATCH_CONFIG_DISABLE) @@ -7466,7 +7478,7 @@ namespace Catch { #define CATCH_VERSION_MACROS_HPP_INCLUDED #define CATCH_VERSION_MAJOR 3 -#define CATCH_VERSION_MINOR 10 +#define CATCH_VERSION_MINOR 11 #define CATCH_VERSION_PATCH 0 #endif // CATCH_VERSION_MACROS_HPP_INCLUDED @@ -7882,8 +7894,9 @@ namespace Generators { class FilterGenerator final : public IGenerator { GeneratorWrapper m_generator; Predicate m_predicate; + static_assert(!std::is_reference::value, "This would most likely result in a dangling reference"); public: - template + template FilterGenerator(P&& pred, GeneratorWrapper&& generator): m_generator(CATCH_MOVE(generator)), m_predicate(CATCH_FORWARD(pred)) @@ -7915,7 +7928,7 @@ namespace Generators { template GeneratorWrapper filter(Predicate&& pred, GeneratorWrapper&& generator) { - return GeneratorWrapper(Catch::Detail::make_unique>(CATCH_FORWARD(pred), CATCH_MOVE(generator))); + return GeneratorWrapper(Catch::Detail::make_unique::type>>(CATCH_FORWARD(pred), CATCH_MOVE(generator))); } template @@ -9555,7 +9568,7 @@ namespace Catch { #define CATCH_TRAP() __asm__(".inst 0xde01") #endif -#elif defined(CATCH_PLATFORM_LINUX) +#elif defined(CATCH_PLATFORM_LINUX) || defined(CATCH_PLATFORM_QNX) // If we can use inline assembler, do it because this allows us to break // directly at the location of the failing check instead of breaking inside // raise() called from it, i.e. one stack frame below. @@ -10718,11 +10731,6 @@ namespace Catch { void benchmarkEnded( BenchmarkStats<> const& stats ) override; void benchmarkFailed( StringRef error ) override; - void pushScopedMessage( MessageInfo const& message ) override; - void popScopedMessage( MessageInfo const& message ) override; - - void emplaceUnscopedMessage( MessageBuilder&& builder ) override; - std::string getCurrentTestName() const override; const AssertionResult* getLastResult() const override; diff --git a/meson.build b/meson.build index 4c284a95..16b38796 100644 --- a/meson.build +++ b/meson.build @@ -8,7 +8,7 @@ project( 'catch2', 'cpp', - version: '3.10.0', # CML version placeholder, don't delete + version: '3.11.0', # CML version placeholder, don't delete license: 'BSL-1.0', meson_version: '>=0.54.1', ) diff --git a/src/catch2/catch_version.cpp b/src/catch2/catch_version.cpp index e5b16197..39b0c0be 100644 --- a/src/catch2/catch_version.cpp +++ b/src/catch2/catch_version.cpp @@ -36,7 +36,7 @@ namespace Catch { } Version const& libraryVersion() { - static Version version( 3, 10, 0, "", 0 ); + static Version version( 3, 11, 0, "", 0 ); return version; } diff --git a/src/catch2/catch_version_macros.hpp b/src/catch2/catch_version_macros.hpp index 881eb076..630f5b0e 100644 --- a/src/catch2/catch_version_macros.hpp +++ b/src/catch2/catch_version_macros.hpp @@ -9,7 +9,7 @@ #define CATCH_VERSION_MACROS_HPP_INCLUDED #define CATCH_VERSION_MAJOR 3 -#define CATCH_VERSION_MINOR 10 +#define CATCH_VERSION_MINOR 11 #define CATCH_VERSION_PATCH 0 #endif // CATCH_VERSION_MACROS_HPP_INCLUDED