From 8e72d177708aa292a04b1c3eb20cb0717e3ca8df Mon Sep 17 00:00:00 2001 From: Tyler Veness Date: Sat, 11 Apr 2026 13:51:34 -0700 Subject: [PATCH] [upstream_utils] Upgrade to Catch2 3.14.0 (#8757) --- thirdparty/catch2/extras/CatchAddTests.cmake | 1 + .../main/native/cpp/catch2/catch_config.cpp | 37 ++- .../main/native/cpp/catch2/catch_message.cpp | 38 ++- .../native/cpp/catch2/catch_registry_hub.cpp | 1 - .../main/native/cpp/catch2/catch_session.cpp | 56 +++- .../main/native/cpp/catch2/catch_tostring.cpp | 68 +++-- .../main/native/cpp/catch2/catch_version.cpp | 2 +- .../catch2/generators/catch_generators.cpp | 10 - .../generators/catch_generators_random.cpp | 5 + .../generators/catch_generators_throw.cpp | 24 ++ .../interfaces/catch_interfaces_capture.cpp | 9 +- .../catch_interfaces_generatortracker.cpp | 29 ++ .../cpp/catch2/internal/catch_commandline.cpp | 68 ++++- .../catch2/internal/catch_console_colour.cpp | 8 +- .../cpp/catch2/internal/catch_context.cpp | 15 +- .../cpp/catch2/internal/catch_debugger.cpp | 2 +- .../catch_fatal_condition_handler.cpp | 18 +- .../catch2/internal/catch_message_info.cpp | 14 +- .../internal/catch_reusable_string_stream.cpp | 15 +- .../cpp/catch2/internal/catch_run_context.cpp | 273 +++++++++++++----- .../internal/catch_test_case_tracker.cpp | 62 ++-- .../cpp/catch2/internal/catch_textflow.cpp | 19 ++ .../reporters/catch_reporter_common_base.cpp | 6 +- .../reporters/catch_reporter_helpers.cpp | 21 +- .../catch2/reporters/catch_reporter_junit.cpp | 123 ++++---- .../detail/catch_benchmark_stats.hpp | 1 + .../detail/catch_benchmark_stats_fwd.hpp | 10 +- .../main/native/include/catch2/catch_all.hpp | 3 + .../native/include/catch2/catch_config.hpp | 12 +- .../native/include/catch2/catch_message.hpp | 43 +-- .../native/include/catch2/catch_tostring.hpp | 83 ++---- .../include/catch2/catch_user_config.hpp | 10 +- .../include/catch2/catch_version_macros.hpp | 2 +- .../catch2/generators/catch_generators.hpp | 33 ++- .../generators/catch_generators_adapters.hpp | 97 ++++++- .../generators/catch_generators_all.hpp | 1 + .../generators/catch_generators_random.hpp | 3 + .../generators/catch_generators_range.hpp | 4 + .../generators/catch_generators_throw.hpp | 23 ++ .../interfaces/catch_interfaces_capture.hpp | 22 +- .../interfaces/catch_interfaces_config.hpp | 8 +- .../catch_interfaces_generatortracker.hpp | 27 +- .../internal/catch_compiler_capabilities.hpp | 29 +- .../include/catch2/internal/catch_context.hpp | 13 +- .../catch2/internal/catch_debugger.hpp | 2 +- .../internal/catch_deprecation_macro.hpp | 4 +- .../catch2/internal/catch_jsonwriter.hpp | 13 +- .../catch2/internal/catch_lifetimebound.hpp | 24 ++ .../catch2/internal/catch_message_info.hpp | 7 +- .../catch2/internal/catch_path_filter.hpp | 33 +++ .../catch2/internal/catch_platform.hpp | 3 + .../catch2/internal/catch_run_context.hpp | 5 - .../catch2/internal/catch_string_manip.hpp | 7 +- .../catch2/internal/catch_stringref.hpp | 13 +- .../internal/catch_test_case_tracker.hpp | 39 ++- .../catch2/internal/catch_thread_local.hpp | 19 ++ .../catch2/internal/catch_thread_support.hpp | 12 +- .../catch2/internal/catch_unique_name.hpp | 13 + .../catch2/internal/catch_xmlwriter.hpp | 7 +- .../catch2/matchers/catch_matchers.hpp | 32 +- .../matchers/catch_matchers_templated.hpp | 58 ++-- .../reporters/catch_reporter_helpers.hpp | 8 +- .../catch2/reporters/catch_reporter_junit.hpp | 2 +- upstream_utils/catch2.py | 2 +- 64 files changed, 1177 insertions(+), 474 deletions(-) create mode 100644 thirdparty/catch2/src/main/native/cpp/catch2/generators/catch_generators_throw.cpp create mode 100644 thirdparty/catch2/src/main/native/include/catch2/generators/catch_generators_throw.hpp create mode 100644 thirdparty/catch2/src/main/native/include/catch2/internal/catch_lifetimebound.hpp create mode 100644 thirdparty/catch2/src/main/native/include/catch2/internal/catch_path_filter.hpp create mode 100644 thirdparty/catch2/src/main/native/include/catch2/internal/catch_thread_local.hpp diff --git a/thirdparty/catch2/extras/CatchAddTests.cmake b/thirdparty/catch2/extras/CatchAddTests.cmake index 90fbd5e313..4c27f479ec 100644 --- a/thirdparty/catch2/extras/CatchAddTests.cmake +++ b/thirdparty/catch2/extras/CatchAddTests.cmake @@ -146,6 +146,7 @@ function(catch_discover_tests_impl) # Exit early if no tests are detected if(num_tests STREQUAL "0") + file(WRITE "${_CTEST_FILE}" "") return() endif() diff --git a/thirdparty/catch2/src/main/native/cpp/catch2/catch_config.cpp b/thirdparty/catch2/src/main/native/cpp/catch2/catch_config.cpp index 352c1f424a..b4584f3cc5 100644 --- a/thirdparty/catch2/src/main/native/cpp/catch2/catch_config.cpp +++ b/thirdparty/catch2/src/main/native/cpp/catch2/catch_config.cpp @@ -92,6 +92,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 @@ -101,9 +105,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() ) { @@ -119,6 +120,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(); } @@ -167,7 +170,8 @@ namespace Catch { bool Config::listListeners() const { return m_data.listListeners; } std::vector const& Config::getTestsOrTags() const { return m_data.testsOrTags; } - std::vector const& Config::getSectionsToRun() const { return m_data.sectionsToRun; } + std::vector const& Config::getPathFilters() const { return m_data.pathFilters; } + bool Config::useNewFilterBehaviour() const { return m_data.useNewPathFilteringBehaviour; } std::vector const& Config::getReporterSpecs() const { return m_data.reporterSpecifications; @@ -183,6 +187,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; } @@ -193,6 +199,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; } @@ -244,6 +253,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 diff --git a/thirdparty/catch2/src/main/native/cpp/catch2/catch_message.cpp b/thirdparty/catch2/src/main/native/cpp/catch2/catch_message.cpp index 9cb0167ffe..870651e382 100644 --- a/thirdparty/catch2/src/main/native/cpp/catch2/catch_message.cpp +++ b/thirdparty/catch2/src/main/native/cpp/catch2/catch_message.cpp @@ -19,28 +19,28 @@ 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, + bool isScoped): + m_isScoped(isScoped) { auto trimmed = [&] (size_t start, size_t end) { while (names[start] == ',' || isspace(static_cast(names[start]))) { ++start; @@ -86,8 +86,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; @@ -96,20 +96,26 @@ 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] ); + 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; - m_resultCapture.pushScopedMessage( m_messages[index] ); + if ( m_isScoped ) { + IResultCapture::pushScopedMessage( CATCH_MOVE( m_messages[index] ) ); + } else { + IResultCapture::addUnscopedMessage( CATCH_MOVE( m_messages[index] ) ); + } m_captured++; } diff --git a/thirdparty/catch2/src/main/native/cpp/catch2/catch_registry_hub.cpp b/thirdparty/catch2/src/main/native/cpp/catch2/catch_registry_hub.cpp index 3a594678ba..925468faa1 100644 --- a/thirdparty/catch2/src/main/native/cpp/catch2/catch_registry_hub.cpp +++ b/thirdparty/catch2/src/main/native/cpp/catch2/catch_registry_hub.cpp @@ -96,7 +96,6 @@ namespace Catch { } void cleanUp() { cleanupSingletons(); - cleanUpContext(); } std::string translateActiveException() { return getRegistryHub().getExceptionTranslatorRegistry().translateActiveException(); diff --git a/thirdparty/catch2/src/main/native/cpp/catch2/catch_session.cpp b/thirdparty/catch2/src/main/native/cpp/catch2/catch_session.cpp index 7542447b9f..042b7f4d3a 100644 --- a/thirdparty/catch2/src/main/native/cpp/catch2/catch_session.cpp +++ b/thirdparty/catch2/src/main/native/cpp/catch2/catch_session.cpp @@ -26,6 +26,8 @@ #include #include +#include +#include #include #include #include @@ -140,6 +142,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() { @@ -258,6 +304,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()); @@ -298,6 +345,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) { @@ -327,9 +378,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; } diff --git a/thirdparty/catch2/src/main/native/cpp/catch2/catch_tostring.cpp b/thirdparty/catch2/src/main/native/cpp/catch2/catch_tostring.cpp index 4d80b17357..dad6241071 100644 --- a/thirdparty/catch2/src/main/native/cpp/catch2/catch_tostring.cpp +++ b/thirdparty/catch2/src/main/native/cpp/catch2/catch_tostring.cpp @@ -57,39 +57,69 @@ namespace Detail { } } // end unnamed namespace + std::size_t catch_strnlen( const char* str, std::size_t n ) { + auto ret = std::char_traits::find( str, n, '\0' ); + if ( ret != nullptr ) { return static_cast( ret - str ); } + return n; + } + + std::string formatTimeT(std::time_t time) { +#ifdef _MSC_VER + std::tm timeInfo = {}; + const auto err = gmtime_s( &timeInfo, &time ); + if ( err ) { + return "gmtime from provided timepoint has failed. This " + "happens e.g. with pre-1970 dates using Microsoft libc"; + } +#else + std::tm* timeInfo = std::gmtime( &time ); +#endif + + auto const timeStampSize = sizeof( "2017-01-16T17:06:45Z" ); + char timeStamp[timeStampSize]; + const char* const fmt = "%Y-%m-%dT%H:%M:%SZ"; + +#ifdef _MSC_VER + std::strftime( timeStamp, timeStampSize, fmt, &timeInfo ); +#else + std::strftime( timeStamp, timeStampSize, fmt, timeInfo ); +#endif + return std::string( timeStamp, timeStampSize - 1 ); + } + std::string convertIntoString(StringRef string, bool escapeInvisibles) { 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; diff --git a/thirdparty/catch2/src/main/native/cpp/catch2/catch_version.cpp b/thirdparty/catch2/src/main/native/cpp/catch2/catch_version.cpp index e5b16197c5..403db2ebc6 100644 --- a/thirdparty/catch2/src/main/native/cpp/catch2/catch_version.cpp +++ b/thirdparty/catch2/src/main/native/cpp/catch2/catch_version.cpp @@ -36,7 +36,7 @@ namespace Catch { } Version const& libraryVersion() { - static Version version( 3, 10, 0, "", 0 ); + static Version version( 3, 14, 0, "", 0 ); return version; } diff --git a/thirdparty/catch2/src/main/native/cpp/catch2/generators/catch_generators.cpp b/thirdparty/catch2/src/main/native/cpp/catch2/generators/catch_generators.cpp index 3514e9f632..f7927eee86 100644 --- a/thirdparty/catch2/src/main/native/cpp/catch2/generators/catch_generators.cpp +++ b/thirdparty/catch2/src/main/native/cpp/catch2/generators/catch_generators.cpp @@ -7,8 +7,6 @@ // SPDX-License-Identifier: BSL-1.0 #include -#include -#include #include namespace Catch { @@ -17,14 +15,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 ) { diff --git a/thirdparty/catch2/src/main/native/cpp/catch2/generators/catch_generators_random.cpp b/thirdparty/catch2/src/main/native/cpp/catch2/generators/catch_generators_random.cpp index 00a8e634f7..d5163c16ca 100644 --- a/thirdparty/catch2/src/main/native/cpp/catch2/generators/catch_generators_random.cpp +++ b/thirdparty/catch2/src/main/native/cpp/catch2/generators/catch_generators_random.cpp @@ -37,5 +37,10 @@ namespace Catch { m_current_number = m_pimpl->dist( m_pimpl->rng ); return true; } + + bool RandomFloatingGenerator::isFinite() const { + return false; + } + } // namespace Generators } // namespace Catch diff --git a/thirdparty/catch2/src/main/native/cpp/catch2/generators/catch_generators_throw.cpp b/thirdparty/catch2/src/main/native/cpp/catch2/generators/catch_generators_throw.cpp new file mode 100644 index 0000000000..e7eda22522 --- /dev/null +++ b/thirdparty/catch2/src/main/native/cpp/catch2/generators/catch_generators_throw.cpp @@ -0,0 +1,24 @@ + +// Copyright Catch2 Authors +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE.txt or copy at +// https://www.boost.org/LICENSE_1_0.txt) + +// SPDX-License-Identifier: BSL-1.0 + +#include +#include +#include + +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 diff --git a/thirdparty/catch2/src/main/native/cpp/catch2/interfaces/catch_interfaces_capture.cpp b/thirdparty/catch2/src/main/native/cpp/catch2/interfaces/catch_interfaces_capture.cpp index 9b40ee5d69..492c5bd9ad 100644 --- a/thirdparty/catch2/src/main/native/cpp/catch2/interfaces/catch_interfaces_capture.cpp +++ b/thirdparty/catch2/src/main/native/cpp/catch2/interfaces/catch_interfaces_capture.cpp @@ -7,7 +7,14 @@ // SPDX-License-Identifier: BSL-1.0 #include +#include namespace Catch { + namespace Detail { + void missingCaptureInstance() { + CATCH_INTERNAL_ERROR( "No result capture instance" ); + } + } // namespace Detail + IResultCapture::~IResultCapture() = default; -} +} // namespace Catch diff --git a/thirdparty/catch2/src/main/native/cpp/catch2/interfaces/catch_interfaces_generatortracker.cpp b/thirdparty/catch2/src/main/native/cpp/catch2/interfaces/catch_interfaces_generatortracker.cpp index e9fa5ddac2..8442be4ecd 100644 --- a/thirdparty/catch2/src/main/native/cpp/catch2/interfaces/catch_interfaces_generatortracker.cpp +++ b/thirdparty/catch2/src/main/native/cpp/catch2/interfaces/catch_interfaces_generatortracker.cpp @@ -7,6 +7,8 @@ // SPDX-License-Identifier: BSL-1.0 #include +#include + #include namespace Catch { @@ -21,6 +23,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(); @@ -28,5 +55,7 @@ namespace Catch { return m_stringReprCache; } + bool GeneratorUntypedBase::isFinite() const { return true; } + } // namespace Generators } // namespace Catch diff --git a/thirdparty/catch2/src/main/native/cpp/catch2/internal/catch_commandline.cpp b/thirdparty/catch2/src/main/native/cpp/catch2/internal/catch_commandline.cpp index 212f17745a..4ce4239724 100644 --- a/thirdparty/catch2/src/main/native/cpp/catch2/internal/catch_commandline.cpp +++ b/thirdparty/catch2/src/main/native/cpp/catch2/internal/catch_commandline.cpp @@ -32,6 +32,9 @@ namespace Catch { } else if ( warning == "UnmatchedTestSpec" ) { config.warnings = static_cast(config.warnings | WarnAbout::UnmatchedTestSpec); return ParserResult::ok( ParseResultType::Matched ); + } else if ( warning == "InfiniteGenerators" ) { + config.warnings = static_cast(config.warnings | WarnAbout::InfiniteGenerator); + return ParserResult::ok( ParseResultType::Matched ); } return ParserResult ::runtimeError( @@ -189,6 +192,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 ); @@ -200,6 +216,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 ) @@ -245,9 +298,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" ) @@ -265,7 +324,7 @@ namespace Catch { ( "list all listeners" ) | Opt( setTestOrder, "decl|lex|rand" ) ["--order"] - ( "test case order (defaults to decl)" ) + ( "test case order (defaults to rand)" ) | Opt( setRngSeed, "'time'|'random-device'|number" ) ["--rng-seed"] ( "set a specific seed for random numbers" ) @@ -281,7 +340,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" ) @@ -305,6 +364,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" ); diff --git a/thirdparty/catch2/src/main/native/cpp/catch2/internal/catch_console_colour.cpp b/thirdparty/catch2/src/main/native/cpp/catch2/internal/catch_console_colour.cpp index 514fc6b6b1..0c9ef54617 100644 --- a/thirdparty/catch2/src/main/native/cpp/catch2/internal/catch_console_colour.cpp +++ b/thirdparty/catch2/src/main/native/cpp/catch2/internal/catch_console_colour.cpp @@ -161,7 +161,13 @@ 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__ ) \ + /* PlayStation platform does not have `isatty()` */ \ + && !defined(CATCH_PLATFORM_PLAYSTATION)) \ + || defined( CATCH_PLATFORM_QNX ) # define CATCH_INTERNAL_HAS_ISATTY # include #endif diff --git a/thirdparty/catch2/src/main/native/cpp/catch2/internal/catch_context.cpp b/thirdparty/catch2/src/main/native/cpp/catch2/internal/catch_context.cpp index 8acf1eda62..5389de318b 100644 --- a/thirdparty/catch2/src/main/native/cpp/catch2/internal/catch_context.cpp +++ b/thirdparty/catch2/src/main/native/cpp/catch2/internal/catch_context.cpp @@ -6,25 +6,14 @@ // SPDX-License-Identifier: BSL-1.0 #include -#include #include 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() { diff --git a/thirdparty/catch2/src/main/native/cpp/catch2/internal/catch_debugger.cpp b/thirdparty/catch2/src/main/native/cpp/catch2/internal/catch_debugger.cpp index bd3be17289..da22c7fd6b 100644 --- a/thirdparty/catch2/src/main/native/cpp/catch2/internal/catch_debugger.cpp +++ b/thirdparty/catch2/src/main/native/cpp/catch2/internal/catch_debugger.cpp @@ -69,7 +69,7 @@ #endif } // namespace Catch -#elif defined(CATCH_PLATFORM_LINUX) +#elif defined(CATCH_PLATFORM_LINUX) || defined(CATCH_PLATFORM_QNX) #include #include diff --git a/thirdparty/catch2/src/main/native/cpp/catch2/internal/catch_fatal_condition_handler.cpp b/thirdparty/catch2/src/main/native/cpp/catch2/internal/catch_fatal_condition_handler.cpp index 26f894d6be..3dfa138348 100644 --- a/thirdparty/catch2/src/main/native/cpp/catch2/internal/catch_fatal_condition_handler.cpp +++ b/thirdparty/catch2/src/main/native/cpp/catch2/internal/catch_fatal_condition_handler.cpp @@ -86,23 +86,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() { diff --git a/thirdparty/catch2/src/main/native/cpp/catch2/internal/catch_message_info.cpp b/thirdparty/catch2/src/main/native/cpp/catch2/internal/catch_message_info.cpp index bc887abfd1..9f8690a424 100644 --- a/thirdparty/catch2/src/main/native/cpp/catch2/internal/catch_message_info.cpp +++ b/thirdparty/catch2/src/main/native/cpp/catch2/internal/catch_message_info.cpp @@ -7,20 +7,24 @@ // SPDX-License-Identifier: BSL-1.0 #include +#include namespace Catch { + namespace { + // Messages are owned by their individual threads, so the counter should + // be thread-local as well. Alternative consideration: atomic counter, + // so threads don't share IDs and things are easier to debug. + static CATCH_INTERNAL_THREAD_LOCAL unsigned int messageIDCounter = 0; + } + MessageInfo::MessageInfo( StringRef _macroName, SourceLineInfo const& _lineInfo, ResultWas::OfType _type ) : macroName( _macroName ), lineInfo( _lineInfo ), type( _type ), - sequence( ++globalCount ) + sequence( ++messageIDCounter ) {} - // Messages are owned by their individual threads, so the counter should be thread-local as well. - // Alternative consideration: atomic, so threads don't share IDs and things are easier to debug. - thread_local unsigned int MessageInfo::globalCount = 0; - } // end namespace Catch diff --git a/thirdparty/catch2/src/main/native/cpp/catch2/internal/catch_reusable_string_stream.cpp b/thirdparty/catch2/src/main/native/cpp/catch2/internal/catch_reusable_string_stream.cpp index a2dd5a6350..875da4dab1 100644 --- a/thirdparty/catch2/src/main/native/cpp/catch2/internal/catch_reusable_string_stream.cpp +++ b/thirdparty/catch2/src/main/native/cpp/catch2/internal/catch_reusable_string_stream.cpp @@ -12,6 +12,7 @@ #include #include +#include #include namespace Catch { @@ -23,16 +24,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() }; } } @@ -46,10 +47,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(""); diff --git a/thirdparty/catch2/src/main/native/cpp/catch2/internal/catch_run_context.cpp b/thirdparty/catch2/src/main/native/cpp/catch2/internal/catch_run_context.cpp index d1cec82c88..fd4b7a3846 100644 --- a/thirdparty/catch2/src/main/native/cpp/catch2/internal/catch_run_context.cpp +++ b/thirdparty/catch2/src/main/native/cpp/catch2/internal/catch_run_context.cpp @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -19,8 +20,12 @@ #include #include #include +#include #include +#include +#include #include +#include #include #include @@ -32,12 +37,51 @@ 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) { + // We want the semantics of `SKIP()`, but we inline it + // to avoid issues with conditionally prefixed macros + INTERNAL_CATCH_MSG( + "SKIP", + Catch::ResultWas::ExplicitSkip, + Catch::ResultDisposition::Normal, + "" ); + Catch::Detail::Unreachable(); + } + // '*' 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, @@ -81,9 +125,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) @@ -112,29 +153,24 @@ namespace Catch { // _can_ start, and thus we should wait for them, or // they cannot start (due to filters), and we shouldn't // wait for them - ITracker* parent = m_parent; - // This is safe: there is always at least one section - // tracker in a test case tracking tree - while ( !parent->isSectionTracker() ) { - parent = parent->parent(); + + // No filters left -> no restrictions on running sections + size_t childDepth = 1 + (m_newStyleFilters ? m_allTrackerDepth : m_sectionOnlyDepth); + if ( childDepth >= m_filterRef->size() ) { + return true; } - assert( parent && - "Missing root (test case) level section" ); - - auto const& parentSection = - static_cast( *parent ); - auto const& filters = parentSection.getFilters(); - // No filters -> no restrictions on running sections - if ( filters.empty() ) { return true; } + // If we are using the new style filters, we need to check + // whether the successive filter is for section or a generator. + if ( m_newStyleFilters + && (*m_filterRef)[childDepth].type != PathFilter::For::Section ) { + return false; + } + // Look for any child section that could match the remaining filters for ( auto const& child : m_children ) { if ( child->isSectionTracker() && - std::find( filters.begin(), - filters.end(), - static_cast( - *child ) - .trimmedName() ) != - filters.end() ) { + static_cast( *child ) + .trimmedName() == StringRef((*m_filterRef)[childDepth].filter) ) { return true; } } @@ -146,9 +182,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; } @@ -158,9 +195,6 @@ namespace Catch { auto getGenerator() const -> GeneratorBasePtr const& override { return m_generator; } - void setGenerator( GeneratorBasePtr&& generator ) override { - m_generator = CATCH_MOVE( generator ); - } }; } // namespace } @@ -177,27 +211,101 @@ namespace Catch { // 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. + // + // Note that we also don't want non-trivial the thread-local variables + // below be initialized for every thread, only for those that touch + // Catch2. To make this work with both GCC/Clang and MSVC, we have to + // make them thread-local magic statics. (Class-level statics have the + // desired semantics on GCC, but not on MSVC). // This is used for the "if" part of CHECKED_IF/CHECKED_ELSE - static thread_local bool g_lastAssertionPassed = false; + static CATCH_INTERNAL_THREAD_LOCAL bool g_lastAssertionPassed = 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)); + static CATCH_INTERNAL_THREAD_LOCAL SourceLineInfo + g_lastKnownLineInfo( "DummyLocation", static_cast( -1 ) ); // 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; + static CATCH_INTERNAL_THREAD_LOCAL bool g_clearMessageScopes = false; + + + // Holds the data for both scoped and unscoped messages together, + // to avoid issues where their lifetimes start in wrong order, + // and then are destroyed in wrong order. + class MessageHolder { + // The actual message vector passed to the reporters + std::vector messages; + // IDs of messages from UNSCOPED_X macros, which we have to + // remove manually. + std::vector unscoped_ids; + + public: + // We do not need to special-case the unscoped messages when + // 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) { + MessageInfo info( CATCH_MOVE( builder.m_info ) ); + info.message = builder.m_stream.str(); + addUnscopedMessage( CATCH_MOVE( info ) ); + } + + void addScopedMessage(MessageInfo&& info) { + messages.push_back( CATCH_MOVE( info ) ); + } + + std::vector const& getMessages() const { + return messages; + } + + void removeMessage( 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 improvement is tiny, and we would have to hand-write + // the loop to avoid terrible codegen of reverse iterators + // in debug mode. + auto iter = + std::find_if( messages.begin(), + messages.end(), + [messageId]( MessageInfo const& msg ) { + return msg.sequence == messageId; + } ); + assert( iter != messages.end() && + "Trying to remove non-existent message." ); + messages.erase( iter ); + } + + void removeUnscopedMessages() { + for ( const auto messageId : unscoped_ids ) { + removeMessage( messageId ); + } + unscoped_ids.clear(); + g_clearMessageScopes = false; + } + + void repairUnscopedMessageInvariant() { + if ( g_clearMessageScopes ) { removeUnscopedMessages(); } + g_clearMessageScopes = false; + } + }; CATCH_INTERNAL_START_WARNINGS_SUPPRESSION CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS - // Actual messages to be provided to the reporter - static thread_local std::vector g_messages; - - // Owners for the UNSCOPED_X information macro - static thread_local std::vector g_messageScopes; + static MessageHolder& g_messageHolder() { + static CATCH_INTERNAL_THREAD_LOCAL MessageHolder value; + return value; + } CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION } // namespace Detail @@ -214,6 +322,13 @@ namespace Catch { { getCurrentMutableContext().setResultCapture( this ); m_reporter->testRunStarting(m_runInfo); + + // TODO: HACK! + // We need to make sure the underlying cache is initialized + // while we are guaranteed to be running in a single thread, + // because the initialization is not thread-safe. + ReusableStringStream rss; + (void)rss; } RunContext::~RunContext() { @@ -233,7 +348,8 @@ namespace Catch { ITracker& rootTracker = m_trackerContext.startRun(); assert(rootTracker.isSectionTracker()); - static_cast(rootTracker).addInitialFilters(m_config->getSectionsToRun()); + rootTracker.setFilters( &m_config->getPathFilters(), + m_config->useNewFilterBehaviour() ); // We intentionally only seed the internal RNG once per test case, // before it is first invoked. The reason for that is a complex @@ -336,21 +452,19 @@ namespace Catch { Detail::g_lastAssertionPassed = true; } - if ( Detail::g_clearMessageScopes ) { - Detail::g_messageScopes.clear(); - Detail::g_clearMessageScopes = false; - } + auto& msgHolder = Detail::g_messageHolder(); + msgHolder.repairUnscopedMessageInvariant(); // From here, we are touching shared state and need mutex. Detail::LockGuard lock( m_assertionMutex ); { auto _ = scopedDeactivate( *m_outputRedirect ); updateTotalsFromAtomics(); - m_reporter->assertionEnded( AssertionStats( result, Detail::g_messages, m_totals ) ); + m_reporter->assertionEnded( AssertionStats( result, msgHolder.getMessages(), m_totals ) ); } if ( result.getResultType() != ResultWas::Warning ) { - Detail::g_messageScopes.clear(); + msgHolder.removeUnscopedMessages(); } // Reset working state. assertion info will be reset after @@ -407,18 +521,32 @@ 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() ) { + // We want the semantics of `FAIL()`, but we inline it + // to avoid issues with conditionally prefixed macros + INTERNAL_CATCH_MSG( "FAIL", + Catch::ResultWas::ExplicitFailure, + Catch::ResultDisposition::Normal, + "GENERATE() would run infinitely" ); + } + auto nameAndLoc = TestCaseTracking::NameAndLocation( static_cast( generatorName ), lineInfo ); auto& currentTracker = m_trackerContext.currentTracker(); assert( currentTracker.nameAndLocation() != nameAndLoc && "Trying to create tracker for a generator that already has one" ); - auto newTracker = Catch::Detail::make_unique( - CATCH_MOVE(nameAndLoc), m_trackerContext, ¤tTracker ); + auto newTracker = + Catch::Detail::make_unique( + CATCH_MOVE( nameAndLoc ), + m_trackerContext, + ¤tTracker, + CATCH_MOVE( generator ) ); auto ret = newTracker.get(); currentTracker.addChild( CATCH_MOVE( newTracker ) ); - ret->setGenerator( CATCH_MOVE( generator ) ); ret->open(); return ret; } @@ -483,28 +611,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 @@ -661,10 +767,10 @@ namespace Catch { m_testCaseTracker->close(); handleUnfinishedSections(); - Detail::g_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? - Detail::g_messages.clear(); + auto& msgHolder = Detail::g_messageHolder(); + msgHolder.removeUnscopedMessages(); + assert( msgHolder.getMessages().empty() && + "There should be no leftover messages after the test ends" ); SectionStats testCaseSectionStats(CATCH_MOVE(testCaseSection), assertions, duration, missingAssertions); m_reporter->sectionEnded(testCaseSectionStats); @@ -831,11 +937,20 @@ 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_messageHolder().addScopedMessage( CATCH_MOVE( message ) ); + } + + void IResultCapture::popScopedMessage( unsigned int messageId ) { + Detail::g_messageHolder().removeMessage( messageId ); + } + + void IResultCapture::emplaceUnscopedMessage( MessageBuilder&& builder ) { + Detail::g_messageHolder().addUnscopedMessage( CATCH_MOVE( builder ) ); + } + + void IResultCapture::addUnscopedMessage( MessageInfo&& message ) { + Detail::g_messageHolder().addUnscopedMessage( CATCH_MOVE( message ) ); } void seedRng(IConfig const& config) { diff --git a/thirdparty/catch2/src/main/native/cpp/catch2/internal/catch_test_case_tracker.cpp b/thirdparty/catch2/src/main/native/cpp/catch2/internal/catch_test_case_tracker.cpp index 1470b91c67..05bfff8e19 100644 --- a/thirdparty/catch2/src/main/native/cpp/catch2/internal/catch_test_case_tracker.cpp +++ b/thirdparty/catch2/src/main/native/cpp/catch2/internal/catch_test_case_tracker.cpp @@ -8,8 +8,9 @@ #include #include -#include #include +#include +#include #include #include @@ -27,6 +28,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; @@ -159,25 +171,32 @@ namespace TestCaseTracking { : TrackerBase( CATCH_MOVE(nameAndLocation), ctx, parent ), m_trimmed_name(trim(StringRef(ITracker::nameAndLocation().name))) { - if( parent ) { - while ( !parent->isSectionTracker() ) { - parent = parent->parent(); - } - - SectionTracker& parentSection = static_cast( *parent ); - addNextFilters( parentSection.m_filters ); + if( m_parent ) { + ++m_sectionOnlyDepth; } } bool SectionTracker::isComplete() const { - bool complete = true; - - if (m_filters.empty() - || m_filters[0].empty() - || std::find(m_filters.begin(), m_filters.end(), m_trimmed_name) != m_filters.end()) { - 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; } @@ -213,19 +232,6 @@ namespace TestCaseTracking { open(); } - void SectionTracker::addInitialFilters( std::vector const& filters ) { - if( !filters.empty() ) { - m_filters.reserve( m_filters.size() + filters.size() + 2 ); - m_filters.emplace_back(StringRef{}); // Root - should never be consulted - m_filters.emplace_back(StringRef{}); // Test Case - not a section filter - m_filters.insert( m_filters.end(), filters.begin(), filters.end() ); - } - } - void SectionTracker::addNextFilters( std::vector const& filters ) { - if( filters.size() > 1 ) - m_filters.insert( m_filters.end(), filters.begin()+1, filters.end() ); - } - StringRef SectionTracker::trimmedName() const { return m_trimmed_name; } diff --git a/thirdparty/catch2/src/main/native/cpp/catch2/internal/catch_textflow.cpp b/thirdparty/catch2/src/main/native/cpp/catch2/internal/catch_textflow.cpp index 1c21d20e56..3979048f37 100644 --- a/thirdparty/catch2/src/main/native/cpp/catch2/internal/catch_textflow.cpp +++ b/thirdparty/catch2/src/main/native/cpp/catch2/internal/catch_textflow.cpp @@ -26,6 +26,10 @@ namespace { return std::memchr( chars, c, sizeof( chars ) - 1 ) != nullptr; } + bool isUtf8ContinuationByte( char c ) { + return ( static_cast( c ) & 0xC0 ) == 0x80; + } + } // namespace namespace Catch { @@ -52,6 +56,11 @@ namespace Catch { if ( it != m_string.end() ) { ++m_size; ++it; + // Skip UTF-8 continuation bytes + while ( it != m_string.end() && + isUtf8ContinuationByte( *it ) ) { + ++it; + } } } } @@ -114,6 +123,11 @@ namespace Catch { void AnsiSkippingString::const_iterator::advance() { assert( m_it != m_string->end() ); m_it++; + // Skip UTF-8 continuation bytes + while ( m_it != m_string->end() && + isUtf8ContinuationByte( *m_it ) ) { + m_it++; + } tryParseAnsiEscapes(); } @@ -133,6 +147,11 @@ namespace Catch { assert( *m_it == '\033' ); m_it--; } + // Skip back over UTF-8 continuation bytes to the leading byte + while ( isUtf8ContinuationByte( *m_it ) ) { + assert( m_it != m_string->begin() ); + m_it--; + } } static bool isBoundary( AnsiSkippingString const& line, diff --git a/thirdparty/catch2/src/main/native/cpp/catch2/reporters/catch_reporter_common_base.cpp b/thirdparty/catch2/src/main/native/cpp/catch2/reporters/catch_reporter_common_base.cpp index a1ca76a0f8..0a3671e127 100644 --- a/thirdparty/catch2/src/main/native/cpp/catch2/reporters/catch_reporter_common_base.cpp +++ b/thirdparty/catch2/src/main/native/cpp/catch2/reporters/catch_reporter_common_base.cpp @@ -26,12 +26,12 @@ namespace Catch { void ReporterBase::listReporters( std::vector const& descriptions ) { - defaultListReporters(m_stream, descriptions, m_config->verbosity()); + defaultListReporters( m_stream, descriptions, m_config->verbosity() ); } void ReporterBase::listListeners( std::vector const& descriptions ) { - defaultListListeners( m_stream, descriptions ); + defaultListListeners( m_stream, descriptions, m_config->verbosity() ); } void ReporterBase::listTests(std::vector const& tests) { @@ -43,7 +43,7 @@ namespace Catch { } void ReporterBase::listTags(std::vector const& tags) { - defaultListTags( m_stream, tags, m_config->hasTestFilters() ); + defaultListTags( m_stream, tags, m_config->hasTestFilters(), m_config->verbosity() ); } } // namespace Catch diff --git a/thirdparty/catch2/src/main/native/cpp/catch2/reporters/catch_reporter_helpers.cpp b/thirdparty/catch2/src/main/native/cpp/catch2/reporters/catch_reporter_helpers.cpp index c710ac43ce..6fa68a3c2a 100644 --- a/thirdparty/catch2/src/main/native/cpp/catch2/reporters/catch_reporter_helpers.cpp +++ b/thirdparty/catch2/src/main/native/cpp/catch2/reporters/catch_reporter_helpers.cpp @@ -143,7 +143,15 @@ namespace Catch { } void defaultListListeners( std::ostream& out, - std::vector const& descriptions ) { + std::vector const& descriptions, + Verbosity verbosity ) { + if ( verbosity == Verbosity::Quiet ) { + for ( auto const& desc : descriptions ) { + out << desc.name << '\n'; + } + return; + } + out << "Registered listeners:\n"; if(descriptions.empty()) { @@ -176,7 +184,14 @@ namespace Catch { void defaultListTags( std::ostream& out, std::vector const& tags, - bool isFiltered ) { + bool isFiltered, + Verbosity verbosity ) { + if (verbosity == Verbosity::Quiet) { + for (auto const& tagCount : tags) { + out << tagCount.all() << '\n'; + } + return; + } if ( isFiltered ) { out << "Tags for matching test cases:\n"; } else { @@ -195,7 +210,7 @@ namespace Catch { return lhs.count < rhs.count; } ) ->count; - + // more padding necessary for 3+ digits if (maxTagCount >= 100) { auto numDigits = 1 + std::floor( std::log10( maxTagCount ) ); diff --git a/thirdparty/catch2/src/main/native/cpp/catch2/reporters/catch_reporter_junit.cpp b/thirdparty/catch2/src/main/native/cpp/catch2/reporters/catch_reporter_junit.cpp index df34f17bbe..00b4587610 100644 --- a/thirdparty/catch2/src/main/native/cpp/catch2/reporters/catch_reporter_junit.cpp +++ b/thirdparty/catch2/src/main/native/cpp/catch2/reporters/catch_reporter_junit.cpp @@ -241,70 +241,77 @@ namespace Catch { void JunitReporter::writeAssertions( SectionNode const& sectionNode ) { for (auto const& assertionOrBenchmark : sectionNode.assertionsAndBenchmarks) { if (assertionOrBenchmark.isAssertion()) { - writeAssertion(assertionOrBenchmark.asAssertion()); + // JUnit XML format supports only 1 error/failure/skip + // assertion elements per test case + if (writeAssertion(assertionOrBenchmark.asAssertion())) { + break; + } } } } - void JunitReporter::writeAssertion( AssertionStats const& stats ) { + bool JunitReporter::writeAssertion( AssertionStats const& stats ) { AssertionResult const& result = stats.assertionResult; - if ( !result.isOk() || - result.getResultType() == ResultWas::ExplicitSkip ) { - std::string elementName; - switch( result.getResultType() ) { - case ResultWas::ThrewException: - case ResultWas::FatalErrorCondition: - elementName = "error"; - break; - case ResultWas::ExplicitFailure: - case ResultWas::ExpressionFailed: - case ResultWas::DidntThrowException: - elementName = "failure"; - break; - case ResultWas::ExplicitSkip: - elementName = "skipped"; - break; - // We should never see these here: - case ResultWas::Info: - case ResultWas::Warning: - case ResultWas::Ok: - case ResultWas::Unknown: - case ResultWas::FailureBit: - case ResultWas::Exception: - elementName = "internalError"; - break; - } - - XmlWriter::ScopedElement e = xml.scopedElement( elementName ); - - xml.writeAttribute( "message"_sr, result.getExpression() ); - xml.writeAttribute( "type"_sr, result.getTestMacroName() ); - - ReusableStringStream rss; - if ( result.getResultType() == ResultWas::ExplicitSkip ) { - rss << "SKIPPED\n"; - } else { - rss << "FAILED" << ":\n"; - if (result.hasExpression()) { - rss << " "; - rss << result.getExpressionInMacro(); - rss << '\n'; - } - if (result.hasExpandedExpression()) { - rss << "with expansion:\n"; - rss << TextFlow::Column(result.getExpandedExpression()).indent(2) << '\n'; - } - } - - if( result.hasMessage() ) - rss << result.getMessage() << '\n'; - for( auto const& msg : stats.infoMessages ) - if( msg.type == ResultWas::Info ) - rss << msg.message << '\n'; - - rss << "at " << result.getSourceInfo(); - xml.writeText( rss.str(), XmlFormatting::Newline ); + if ( result.isOk() && + result.getResultType() != ResultWas::ExplicitSkip ) { + return false; } + std::string elementName; + switch ( result.getResultType() ) { + case ResultWas::ThrewException: + case ResultWas::FatalErrorCondition: + elementName = "error"; + break; + case ResultWas::ExplicitFailure: + case ResultWas::ExpressionFailed: + case ResultWas::DidntThrowException: + elementName = "failure"; + break; + case ResultWas::ExplicitSkip: + elementName = "skipped"; + break; + // We should never see these here: + case ResultWas::Info: + case ResultWas::Warning: + case ResultWas::Ok: + case ResultWas::Unknown: + case ResultWas::FailureBit: + case ResultWas::Exception: + elementName = "internalError"; + break; + } + + XmlWriter::ScopedElement e = xml.scopedElement( elementName ); + + xml.writeAttribute( "message"_sr, result.getExpression() ); + xml.writeAttribute( "type"_sr, result.getTestMacroName() ); + + ReusableStringStream rss; + if ( result.getResultType() == ResultWas::ExplicitSkip ) { + rss << "SKIPPED\n"; + } else { + rss << "FAILED:\n"; + if ( result.hasExpression() ) { + rss << " "; + rss << result.getExpressionInMacro(); + rss << '\n'; + } + if ( result.hasExpandedExpression() ) { + rss << "with expansion:\n"; + rss << TextFlow::Column( result.getExpandedExpression() ) + .indent( 2 ) + << '\n'; + } + } + + if ( result.hasMessage() ) { rss << result.getMessage() << '\n'; } + for ( auto const& msg : stats.infoMessages ) { + if ( msg.type == ResultWas::Info ) { rss << msg.message << '\n'; } + } + + rss << "at " << result.getSourceInfo(); + xml.writeText( rss.str(), XmlFormatting::Newline ); + return true; } } // end namespace Catch diff --git a/thirdparty/catch2/src/main/native/include/catch2/benchmark/detail/catch_benchmark_stats.hpp b/thirdparty/catch2/src/main/native/include/catch2/benchmark/detail/catch_benchmark_stats.hpp index 3633bc9f93..e4893aaa2e 100644 --- a/thirdparty/catch2/src/main/native/include/catch2/benchmark/detail/catch_benchmark_stats.hpp +++ b/thirdparty/catch2/src/main/native/include/catch2/benchmark/detail/catch_benchmark_stats.hpp @@ -8,6 +8,7 @@ #ifndef CATCH_BENCHMARK_STATS_HPP_INCLUDED #define CATCH_BENCHMARK_STATS_HPP_INCLUDED +#include #include #include // The fwd decl & default specialization needs to be seen by VS2017 before diff --git a/thirdparty/catch2/src/main/native/include/catch2/benchmark/detail/catch_benchmark_stats_fwd.hpp b/thirdparty/catch2/src/main/native/include/catch2/benchmark/detail/catch_benchmark_stats_fwd.hpp index 2ccc25d582..fb9cf684eb 100644 --- a/thirdparty/catch2/src/main/native/include/catch2/benchmark/detail/catch_benchmark_stats_fwd.hpp +++ b/thirdparty/catch2/src/main/native/include/catch2/benchmark/detail/catch_benchmark_stats_fwd.hpp @@ -8,14 +8,16 @@ #ifndef CATCH_BENCHMARK_STATS_FWD_HPP_INCLUDED #define CATCH_BENCHMARK_STATS_FWD_HPP_INCLUDED -#include - namespace Catch { + namespace Detail { + struct DummyTemplateArgPlaceholder; + } + // 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 - template + // we can prevent multiple declarations in dependencies + template struct BenchmarkStats; } // end namespace Catch diff --git a/thirdparty/catch2/src/main/native/include/catch2/catch_all.hpp b/thirdparty/catch2/src/main/native/include/catch2/catch_all.hpp index 2417d8567e..97226dd115 100644 --- a/thirdparty/catch2/src/main/native/include/catch2/catch_all.hpp +++ b/thirdparty/catch2/src/main/native/include/catch2/catch_all.hpp @@ -79,6 +79,7 @@ #include #include #include +#include #include #include #include @@ -88,6 +89,7 @@ #include #include #include +#include #include #include #include @@ -121,6 +123,7 @@ #include #include #include +#include #include #include #include diff --git a/thirdparty/catch2/src/main/native/include/catch2/catch_config.hpp b/thirdparty/catch2/src/main/native/include/catch2/catch_config.hpp index b7b1315ebf..c3fea5616c 100644 --- a/thirdparty/catch2/src/main/native/include/catch2/catch_config.hpp +++ b/thirdparty/catch2/src/main/native/include/catch2/catch_config.hpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -86,7 +87,10 @@ namespace Catch { std::vector reporterSpecifications; std::vector testsOrTags; - std::vector sectionsToRun; + std::vector pathFilters; + bool useNewPathFilteringBehaviour = false; + + std::string prematureExitGuardFilePath; }; @@ -107,19 +111,23 @@ namespace Catch { getProcessedReporterSpecs() const; std::vector const& getTestsOrTags() const override; - std::vector const& getSectionsToRun() const override; + std::vector const& getPathFilters() const override; + bool useNewFilterBehaviour() const override; TestSpec const& testSpec() const override; bool hasTestFilters() const override; bool showHelp() const; + std::string const& getExitGuardFilePath() const; + // IConfig interface bool allowThrows() const override; StringRef name() const override; 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; diff --git a/thirdparty/catch2/src/main/native/include/catch2/catch_message.hpp b/thirdparty/catch2/src/main/native/include/catch2/catch_message.hpp index 0a738341c2..9e868516a2 100644 --- a/thirdparty/catch2/src/main/native/include/catch2/catch_message.hpp +++ b/thirdparty/catch2/src/main/native/include/catch2/catch_message.hpp @@ -57,16 +57,16 @@ 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; + 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; @@ -98,11 +98,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__ ) /////////////////////////////////////////////////////////////////////////////// @@ -111,7 +112,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) @@ -119,28 +120,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 diff --git a/thirdparty/catch2/src/main/native/include/catch2/catch_tostring.hpp b/thirdparty/catch2/src/main/native/include/catch2/catch_tostring.hpp index 41f89413c4..b005212f83 100644 --- a/thirdparty/catch2/src/main/native/include/catch2/catch_tostring.hpp +++ b/thirdparty/catch2/src/main/native/include/catch2/catch_tostring.hpp @@ -8,7 +8,7 @@ #ifndef CATCH_TOSTRING_HPP_INCLUDED #define CATCH_TOSTRING_HPP_INCLUDED - +#include #include #include #include @@ -40,13 +40,9 @@ namespace Catch { namespace Detail { - inline std::size_t catch_strnlen(const char *str, std::size_t n) { - auto ret = std::char_traits::find(str, n, '\0'); - if (ret != nullptr) { - return static_cast(ret - str); - } - return n; - } + std::size_t catch_strnlen(const char *str, std::size_t n); + + std::string formatTimeT( std::time_t time ); constexpr StringRef unprintableString = "{?}"_sr; @@ -411,44 +407,38 @@ namespace Catch { // Separate std::tuple specialization #if defined(CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER) -#include +# include +# include namespace Catch { namespace Detail { - template< - typename Tuple, - std::size_t N = 0, - bool = (N < std::tuple_size::value) - > - struct TupleElementPrinter { - static void print(const Tuple& tuple, std::ostream& os) { - os << (N ? ", " : " ") - << ::Catch::Detail::stringify(std::get(tuple)); - TupleElementPrinter::print(tuple, os); - } - }; + template + void PrintTuple( const Tuple& tuple, + std::ostream& os, + std::index_sequence ) { + // 1 + Account for when the tuple is empty + char a[1 + sizeof...( Is )] = { + ( ( os << ( Is ? ", " : " " ) + << ::Catch::Detail::stringify( std::get( tuple ) ) ), + '\0' )... }; + (void)a; + } - template< - typename Tuple, - std::size_t N - > - struct TupleElementPrinter { - static void print(const Tuple&, std::ostream&) {} - }; + } // namespace Detail - } - - - template + template struct StringMaker> { - static std::string convert(const std::tuple& tuple) { + static std::string convert( const std::tuple& tuple ) { ReusableStringStream rss; rss << '{'; - Detail::TupleElementPrinter>::print(tuple, rss.get()); + Detail::PrintTuple( + tuple, + rss.get(), + std::make_index_sequence{} ); rss << " }"; return rss.str(); } }; -} +} // namespace Catch #endif // CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER #if defined(CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER) && defined(CATCH_CONFIG_CPP17_VARIANT) @@ -635,28 +625,7 @@ struct ratio_string { const auto systemish = std::chrono::time_point_cast< std::chrono::system_clock::duration>( time_point ); const auto as_time_t = std::chrono::system_clock::to_time_t( systemish ); - -#ifdef _MSC_VER - std::tm timeInfo = {}; - const auto err = gmtime_s( &timeInfo, &as_time_t ); - if ( err ) { - return "gmtime from provided timepoint has failed. This " - "happens e.g. with pre-1970 dates using Microsoft libc"; - } -#else - std::tm* timeInfo = std::gmtime( &as_time_t ); -#endif - - auto const timeStampSize = sizeof("2017-01-16T17:06:45Z"); - char timeStamp[timeStampSize]; - const char * const fmt = "%Y-%m-%dT%H:%M:%SZ"; - -#ifdef _MSC_VER - std::strftime(timeStamp, timeStampSize, fmt, &timeInfo); -#else - std::strftime(timeStamp, timeStampSize, fmt, timeInfo); -#endif - return std::string(timeStamp, timeStampSize - 1); + return ::Catch::Detail::formatTimeT( as_time_t ); } }; } diff --git a/thirdparty/catch2/src/main/native/include/catch2/catch_user_config.hpp b/thirdparty/catch2/src/main/native/include/catch2/catch_user_config.hpp index f23204761d..a8e9cf9c85 100644 --- a/thirdparty/catch2/src/main/native/include/catch2/catch_user_config.hpp +++ b/thirdparty/catch2/src/main/native/include/catch2/catch_user_config.hpp @@ -196,12 +196,12 @@ #endif -// #undef CATCH_CONFIG_EXPERIMENTAL_THREAD_SAFE_ASSERTIONS -// #undef CATCH_CONFIG_NO_EXPERIMENTAL_THREAD_SAFE_ASSERTIONS +// #undef CATCH_CONFIG_THREAD_SAFE_ASSERTIONS +// #undef CATCH_CONFIG_NO_THREAD_SAFE_ASSERTIONS -#if defined( CATCH_CONFIG_EXPERIMENTAL_THREAD_SAFE_ASSERTIONS ) && \ - defined( CATCH_CONFIG_NO_EXPERIMENTAL_THREAD_SAFE_ASSERTIONS ) -# error Cannot force EXPERIMENTAL_THREAD_SAFE_ASSERTIONS to both ON and OFF +#if defined( CATCH_CONFIG_THREAD_SAFE_ASSERTIONS ) && \ + defined( CATCH_CONFIG_NO_THREAD_SAFE_ASSERTIONS ) +# error Cannot force THREAD_SAFE_ASSERTIONS to both ON and OFF #endif diff --git a/thirdparty/catch2/src/main/native/include/catch2/catch_version_macros.hpp b/thirdparty/catch2/src/main/native/include/catch2/catch_version_macros.hpp index 881eb07658..4b288c603d 100644 --- a/thirdparty/catch2/src/main/native/include/catch2/catch_version_macros.hpp +++ b/thirdparty/catch2/src/main/native/include/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 14 #define CATCH_VERSION_PATCH 0 #endif // CATCH_VERSION_MACROS_HPP_INCLUDED diff --git a/thirdparty/catch2/src/main/native/include/catch2/generators/catch_generators.hpp b/thirdparty/catch2/src/main/native/include/catch2/generators/catch_generators.hpp index 0f35a9968a..afb39f865b 100644 --- a/thirdparty/catch2/src/main/native/include/catch2/generators/catch_generators.hpp +++ b/thirdparty/catch2/src/main/native/include/catch2/generators/catch_generators.hpp @@ -9,6 +9,7 @@ #define CATCH_GENERATORS_HPP_INCLUDED #include +#include #include #include #include @@ -22,14 +23,6 @@ namespace Catch { namespace Generators { -namespace Detail { - - //! Throws GeneratorException with the provided message - [[noreturn]] - void throw_generator_exception(char const * msg); - -} // end namespace detail - template class IGenerator : public GeneratorUntypedBase { std::string stringifyImpl() const override { @@ -64,6 +57,9 @@ namespace Detail { bool next() { return m_generator->countedNext(); } + + bool isFinite() const { return m_generator->isFinite(); } + void skipToNthElement( size_t n ) { m_generator->skipToNthElement(n); } }; @@ -84,6 +80,8 @@ namespace Detail { bool next() override { return false; } + + bool isFinite() const override { return true; } }; template @@ -93,6 +91,15 @@ namespace Detail { "specialization, use SingleValue Generator instead."); std::vector m_values; size_t m_idx = 0; + + void skipToNthElementImpl( std::size_t n ) override { + if ( n >= m_values.size() ) { + Detail::throw_generator_exception( + "Coud not jump to Nth element: not enough elements" ); + } + m_idx = n; + } + public: FixedValuesGenerator( std::initializer_list values ) : m_values( values ) {} @@ -103,6 +110,8 @@ namespace Detail { ++m_idx; return m_idx < m_values.size(); } + + bool isFinite() const override { return true; } }; template > @@ -167,6 +176,14 @@ namespace Detail { } return m_current < m_generators.size(); } + + bool isFinite() const override { + for (auto const& gen : m_generators) { + if (!gen.isFinite()) { return false; + } + } + return true; + } }; diff --git a/thirdparty/catch2/src/main/native/include/catch2/generators/catch_generators_adapters.hpp b/thirdparty/catch2/src/main/native/include/catch2/generators/catch_generators_adapters.hpp index f623bd296a..7e21671af7 100644 --- a/thirdparty/catch2/src/main/native/include/catch2/generators/catch_generators_adapters.hpp +++ b/thirdparty/catch2/src/main/native/include/catch2/generators/catch_generators_adapters.hpp @@ -11,6 +11,7 @@ #include #include #include +#include #include @@ -22,6 +23,17 @@ namespace Generators { GeneratorWrapper m_generator; size_t m_returned = 0; size_t m_target; + + void skipToNthElementImpl( std::size_t n ) override { + if ( n >= m_target ) { + Detail::throw_generator_exception( + "Coud not jump to Nth element: not enough elements" ); + } + + m_generator.skipToNthElement( n ); + m_returned = n; + } + public: TakeGenerator(size_t target, GeneratorWrapper&& generator): m_generator(CATCH_MOVE(generator)), @@ -46,6 +58,8 @@ namespace Generators { } return success; } + + bool isFinite() const override { return true; } }; template @@ -87,6 +101,8 @@ namespace Generators { while (!m_predicate(m_generator.get()) && (success = m_generator.next()) == true); return success; } + + bool isFinite() const override { return m_generator.isFinite(); } }; @@ -111,6 +127,9 @@ namespace Generators { m_target_repeats(repeats) { assert(m_target_repeats > 0 && "Repeat generator must repeat at least once"); + if (!m_generator.isFinite()) { + Detail::throw_generator_exception( "Cannot repeat infinite generator" ); + } } T const& get() const override { @@ -144,6 +163,8 @@ namespace Generators { } return m_current_repeat < m_target_repeats; } + + bool isFinite() const override { return m_generator.isFinite(); } }; template @@ -157,25 +178,30 @@ namespace Generators { GeneratorWrapper m_generator; Func m_function; // To avoid returning dangling reference, we have to save the values - T m_cache; + mutable Optional m_cache; + + void skipToNthElementImpl( std::size_t n ) override { + m_generator.skipToNthElement( n ); + m_cache.reset(); + } + public: template MapGenerator(F2&& function, GeneratorWrapper&& generator) : m_generator(CATCH_MOVE(generator)), - m_function(CATCH_FORWARD(function)), - m_cache(m_function(m_generator.get())) + m_function(CATCH_FORWARD(function)) {} T const& get() const override { - return m_cache; + if ( !m_cache ) { m_cache = m_function( m_generator.get() ); } + return *m_cache; } bool next() override { - const auto success = m_generator.next(); - if (success) { - m_cache = m_function(m_generator.get()); - } - return success; + m_cache.reset(); + return m_generator.next(); } + + bool isFinite() const override { return m_generator.isFinite(); } }; template > @@ -197,7 +223,6 @@ namespace Generators { std::vector m_chunk; size_t m_chunk_size; GeneratorWrapper m_generator; - bool m_used_up = false; public: ChunkGenerator(size_t size, GeneratorWrapper generator) : m_chunk_size(size), m_generator(CATCH_MOVE(generator)) @@ -226,6 +251,8 @@ namespace Generators { } return true; } + + bool isFinite() const override { return m_generator.isFinite(); } }; template @@ -235,6 +262,56 @@ namespace Generators { ); } + template + class ConcatGenerator final : public IGenerator { + std::vector> m_generators; + size_t m_current_generator = 0; + + void InsertGenerators( GeneratorWrapper&& gen ) { + m_generators.push_back( CATCH_MOVE( gen ) ); + } + + template + void InsertGenerators( GeneratorWrapper&& gen, Generators&&... gens ) { + m_generators.push_back( CATCH_MOVE( gen ) ); + InsertGenerators( CATCH_MOVE( gens )... ); + } + + public: + template + ConcatGenerator( Generators&&... generators ) { + InsertGenerators( CATCH_MOVE( generators )... ); + } + + T const& get() const override { + return m_generators[m_current_generator].get(); + } + bool next() override { + const bool success = m_generators[m_current_generator].next(); + if ( success ) { return true; } + + // If current generator is used up, we have to move to the next one + ++m_current_generator; + return m_current_generator < m_generators.size(); + } + + bool isFinite() const override { + for ( auto const& gen : m_generators ) { + if ( !gen.isFinite() ) { return false; } + } + return true; + } + }; + + template + GeneratorWrapper cat( GeneratorWrapper&& generator, + Generators&&... generators ) { + return GeneratorWrapper( + Catch::Detail::make_unique>( + CATCH_MOVE( generator ), CATCH_MOVE( generators )... ) ); + } + + } // namespace Generators } // namespace Catch diff --git a/thirdparty/catch2/src/main/native/include/catch2/generators/catch_generators_all.hpp b/thirdparty/catch2/src/main/native/include/catch2/generators/catch_generators_all.hpp index c12d314e83..e612185825 100644 --- a/thirdparty/catch2/src/main/native/include/catch2/generators/catch_generators_all.hpp +++ b/thirdparty/catch2/src/main/native/include/catch2/generators/catch_generators_all.hpp @@ -26,5 +26,6 @@ #include #include #include +#include #endif // CATCH_GENERATORS_ALL_HPP_INCLUDED diff --git a/thirdparty/catch2/src/main/native/include/catch2/generators/catch_generators_random.hpp b/thirdparty/catch2/src/main/native/include/catch2/generators/catch_generators_random.hpp index 712835619e..e028736004 100644 --- a/thirdparty/catch2/src/main/native/include/catch2/generators/catch_generators_random.hpp +++ b/thirdparty/catch2/src/main/native/include/catch2/generators/catch_generators_random.hpp @@ -42,6 +42,7 @@ public: m_current_number = m_dist(m_rng); return true; } + bool isFinite() const override { return false; } }; template <> @@ -59,6 +60,7 @@ public: bool next() override; ~RandomFloatingGenerator() override; // = default + bool isFinite() const override; }; template @@ -80,6 +82,7 @@ public: m_current_number = m_dist(m_rng); return true; } + bool isFinite() const override { return false; } }; template diff --git a/thirdparty/catch2/src/main/native/include/catch2/generators/catch_generators_range.hpp b/thirdparty/catch2/src/main/native/include/catch2/generators/catch_generators_range.hpp index 55d673c236..62739b2350 100644 --- a/thirdparty/catch2/src/main/native/include/catch2/generators/catch_generators_range.hpp +++ b/thirdparty/catch2/src/main/native/include/catch2/generators/catch_generators_range.hpp @@ -48,6 +48,8 @@ public: m_current += m_step; return (m_positive) ? (m_current < m_end) : (m_current > m_end); } + + bool isFinite() const override { return true; } }; template @@ -87,6 +89,8 @@ public: ++m_current; return m_current != m_elems.size(); } + + bool isFinite() const override { return true; } }; template +#include #include #include #include @@ -62,10 +63,10 @@ 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 addUnscopedMessage( MessageInfo&& message ); + static void emplaceUnscopedMessage( MessageBuilder&& builder ); virtual void handleFatalErrorCondition( StringRef message ) = 0; @@ -101,7 +102,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 diff --git a/thirdparty/catch2/src/main/native/include/catch2/interfaces/catch_interfaces_config.hpp b/thirdparty/catch2/src/main/native/include/catch2/interfaces/catch_interfaces_config.hpp index 82a298dbc7..139d2c1e34 100644 --- a/thirdparty/catch2/src/main/native/include/catch2/interfaces/catch_interfaces_config.hpp +++ b/thirdparty/catch2/src/main/native/include/catch2/interfaces/catch_interfaces_config.hpp @@ -29,6 +29,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 { @@ -60,6 +62,7 @@ namespace Catch { class TestSpec; class IStream; + struct PathFilter; class IConfig : public Detail::NonCopyable { public: @@ -71,6 +74,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; @@ -84,7 +88,9 @@ namespace Catch { virtual unsigned int shardCount() const = 0; virtual unsigned int shardIndex() const = 0; virtual ColourMode defaultColourMode() const = 0; - virtual std::vector const& getSectionsToRun() const = 0; + virtual std::vector const& getPathFilters() const = 0; + virtual bool useNewFilterBehaviour() const = 0; + virtual Verbosity verbosity() const = 0; virtual bool skipBenchmarks() const = 0; diff --git a/thirdparty/catch2/src/main/native/include/catch2/interfaces/catch_interfaces_generatortracker.hpp b/thirdparty/catch2/src/main/native/include/catch2/interfaces/catch_interfaces_generatortracker.hpp index d70cb593be..2b2d7c0e83 100644 --- a/thirdparty/catch2/src/main/native/include/catch2/interfaces/catch_interfaces_generatortracker.hpp +++ b/thirdparty/catch2/src/main/native/include/catch2/interfaces/catch_interfaces_generatortracker.hpp @@ -35,6 +35,15 @@ namespace Catch { //! Customization point for `currentElementAsString` virtual std::string stringifyImpl() const = 0; + /** + * Customization point for skipping to the n-th element + * + * Defaults to successively calling `countedNext`. If there + * are not enough elements to reach the nth one, will throw + * an error. + */ + virtual void skipToNthElementImpl( std::size_t n ); + public: GeneratorUntypedBase() = default; // Generation of copy ops is deprecated (and Clang will complain) @@ -58,6 +67,13 @@ namespace Catch { std::size_t currentElementIndex() const { return m_currentElementIndex; } + /** + * Moves the generator forward **to** the n-th element + * + * Cannot move backwards. Can stay in place. + */ + void skipToNthElement( std::size_t n ); + /** * Returns generator's current element as user-friendly string. * @@ -72,6 +88,15 @@ namespace Catch { * comes first. */ StringRef currentElementAsString() const; + + /** + * Returns true if calls to `next` will eventually return false + * + * Note that for backwards compatibility this is currently defaulted + * to return `true`, but in the future all generators will have to + * provide their own implementation. + */ + virtual bool isFinite() const; }; using GeneratorBasePtr = Catch::Detail::unique_ptr; @@ -80,9 +105,7 @@ namespace Catch { class IGeneratorTracker { public: virtual ~IGeneratorTracker(); // = default; - virtual auto hasGenerator() const -> bool = 0; virtual auto getGenerator() const -> Generators::GeneratorBasePtr const& = 0; - virtual void setGenerator( Generators::GeneratorBasePtr&& generator ) = 0; }; } // namespace Catch diff --git a/thirdparty/catch2/src/main/native/include/catch2/internal/catch_compiler_capabilities.hpp b/thirdparty/catch2/src/main/native/include/catch2/internal/catch_compiler_capabilities.hpp index 4cf1d652ae..2bbee6bc61 100644 --- a/thirdparty/catch2/src/main/native/include/catch2/internal/catch_compiler_capabilities.hpp +++ b/thirdparty/catch2/src/main/native/include/catch2/internal/catch_compiler_capabilities.hpp @@ -110,10 +110,15 @@ # define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \ _Pragma( "clang diagnostic ignored \"-Wc++20-extensions\"" ) # else -# define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS +# define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \ _Pragma( "clang diagnostic ignored \"-Wgnu-zero-variadic-macro-arguments\"" ) # endif +# if ( __clang_major__ >= 22 ) +# define CATCH_INTERNAL_SUPPRESS_COUNTER_WARNINGS \ + _Pragma( "clang diagnostic ignored \"-Wc2y-extensions\"" ) +# endif + # define CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \ _Pragma( "clang diagnostic ignored \"-Wunused-template\"" ) @@ -208,7 +213,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. @@ -219,14 +224,23 @@ __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 -// 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 @@ -420,6 +434,9 @@ #if !defined( CATCH_INTERNAL_SUPPRESS_SHADOW_WARNINGS ) # define CATCH_INTERNAL_SUPPRESS_SHADOW_WARNINGS #endif +#if !defined( CATCH_INTERNAL_SUPPRESS_COUNTER_WARNINGS ) +# define CATCH_INTERNAL_SUPPRESS_COUNTER_WARNINGS +#endif #if defined(__APPLE__) && defined(__apple_build_version__) && (__clang_major__ < 10) # undef CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS diff --git a/thirdparty/catch2/src/main/native/include/catch2/internal/catch_context.hpp b/thirdparty/catch2/src/main/native/include/catch2/internal/catch_context.hpp index 4d8a5da1b6..0b89632c29 100644 --- a/thirdparty/catch2/src/main/native/include/catch2/internal/catch_context.hpp +++ b/thirdparty/catch2/src/main/native/include/catch2/internal/catch_context.hpp @@ -19,11 +19,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 { @@ -34,21 +32,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(); } diff --git a/thirdparty/catch2/src/main/native/include/catch2/internal/catch_debugger.hpp b/thirdparty/catch2/src/main/native/include/catch2/internal/catch_debugger.hpp index 515ec76375..997f44062c 100644 --- a/thirdparty/catch2/src/main/native/include/catch2/internal/catch_debugger.hpp +++ b/thirdparty/catch2/src/main/native/include/catch2/internal/catch_debugger.hpp @@ -49,7 +49,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. diff --git a/thirdparty/catch2/src/main/native/include/catch2/internal/catch_deprecation_macro.hpp b/thirdparty/catch2/src/main/native/include/catch2/internal/catch_deprecation_macro.hpp index 7834882b76..7712e20de8 100644 --- a/thirdparty/catch2/src/main/native/include/catch2/internal/catch_deprecation_macro.hpp +++ b/thirdparty/catch2/src/main/native/include/catch2/internal/catch_deprecation_macro.hpp @@ -11,9 +11,9 @@ #include #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 diff --git a/thirdparty/catch2/src/main/native/include/catch2/internal/catch_jsonwriter.hpp b/thirdparty/catch2/src/main/native/include/catch2/internal/catch_jsonwriter.hpp index 23b56d13a0..8b3d2bc198 100644 --- a/thirdparty/catch2/src/main/native/include/catch2/internal/catch_jsonwriter.hpp +++ b/thirdparty/catch2/src/main/native/include/catch2/internal/catch_jsonwriter.hpp @@ -8,6 +8,7 @@ #ifndef CATCH_JSONWRITER_HPP_INCLUDED #define CATCH_JSONWRITER_HPP_INCLUDED +#include #include #include @@ -27,8 +28,8 @@ namespace Catch { class JsonValueWriter { public: - JsonValueWriter( std::ostream& os ); - JsonValueWriter( std::ostream& os, std::uint64_t indent_level ); + JsonValueWriter( std::ostream& os CATCH_ATTR_LIFETIMEBOUND ); + JsonValueWriter( std::ostream& os CATCH_ATTR_LIFETIMEBOUND, std::uint64_t indent_level ); JsonObjectWriter writeObject() &&; JsonArrayWriter writeArray() &&; @@ -62,8 +63,8 @@ namespace Catch { class JsonObjectWriter { public: - JsonObjectWriter( std::ostream& os ); - JsonObjectWriter( std::ostream& os, std::uint64_t indent_level ); + JsonObjectWriter( std::ostream& os CATCH_ATTR_LIFETIMEBOUND ); + JsonObjectWriter( std::ostream& os CATCH_ATTR_LIFETIMEBOUND, std::uint64_t indent_level ); JsonObjectWriter( JsonObjectWriter&& source ) noexcept; JsonObjectWriter& operator=( JsonObjectWriter&& source ) = delete; @@ -81,8 +82,8 @@ namespace Catch { class JsonArrayWriter { public: - JsonArrayWriter( std::ostream& os ); - JsonArrayWriter( std::ostream& os, std::uint64_t indent_level ); + JsonArrayWriter( std::ostream& os CATCH_ATTR_LIFETIMEBOUND ); + JsonArrayWriter( std::ostream& os CATCH_ATTR_LIFETIMEBOUND, std::uint64_t indent_level ); JsonArrayWriter( JsonArrayWriter&& source ) noexcept; JsonArrayWriter& operator=( JsonArrayWriter&& source ) = delete; diff --git a/thirdparty/catch2/src/main/native/include/catch2/internal/catch_lifetimebound.hpp b/thirdparty/catch2/src/main/native/include/catch2/internal/catch_lifetimebound.hpp new file mode 100644 index 0000000000..8114dc70eb --- /dev/null +++ b/thirdparty/catch2/src/main/native/include/catch2/internal/catch_lifetimebound.hpp @@ -0,0 +1,24 @@ + +// Copyright Catch2 Authors +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE.txt or copy at +// https://www.boost.org/LICENSE_1_0.txt) + +// SPDX-License-Identifier: BSL-1.0 + +#ifndef CATCH_LIFETIMEBOUND_HPP_INCLUDED +#define CATCH_LIFETIMEBOUND_HPP_INCLUDED + +#if !defined( __has_cpp_attribute ) +# define CATCH_ATTR_LIFETIMEBOUND +#elif __has_cpp_attribute( msvc::lifetimebound ) +# define CATCH_ATTR_LIFETIMEBOUND [[msvc::lifetimebound]] +#elif __has_cpp_attribute( clang::lifetimebound ) +# define CATCH_ATTR_LIFETIMEBOUND [[clang::lifetimebound]] +#elif __has_cpp_attribute( lifetimebound ) +# define CATCH_ATTR_LIFETIMEBOUND [[lifetimebound]] +#else +# define CATCH_ATTR_LIFETIMEBOUND +#endif + +#endif // CATCH_LIFETIMEBOUND_HPP_INCLUDED diff --git a/thirdparty/catch2/src/main/native/include/catch2/internal/catch_message_info.hpp b/thirdparty/catch2/src/main/native/include/catch2/internal/catch_message_info.hpp index bd686d6d59..72f4516b23 100644 --- a/thirdparty/catch2/src/main/native/include/catch2/internal/catch_message_info.hpp +++ b/thirdparty/catch2/src/main/native/include/catch2/internal/catch_message_info.hpp @@ -26,18 +26,17 @@ 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" ) + 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; } - private: - static thread_local unsigned int globalCount; }; } // end namespace Catch diff --git a/thirdparty/catch2/src/main/native/include/catch2/internal/catch_path_filter.hpp b/thirdparty/catch2/src/main/native/include/catch2/internal/catch_path_filter.hpp new file mode 100644 index 0000000000..9040efeca8 --- /dev/null +++ b/thirdparty/catch2/src/main/native/include/catch2/internal/catch_path_filter.hpp @@ -0,0 +1,33 @@ + +// Copyright Catch2 Authors +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE.txt or copy at +// https://www.boost.org/LICENSE_1_0.txt) + +// SPDX-License-Identifier: BSL-1.0 +#ifndef CATCH_PATH_FILTER_HPP_INCLUDED +#define CATCH_PATH_FILTER_HPP_INCLUDED + +#include + +#include + +namespace Catch { + + struct PathFilter { + enum class For { + Section, + Generator, + }; + PathFilter( For type_, std::string filter_ ): + type( type_ ), filter( CATCH_MOVE( filter_ ) ) {} + + For type; + std::string filter; + + friend bool operator==( PathFilter const& lhs, PathFilter const& rhs ); + }; + +} // end namespace Catch + +#endif // CATCH_PATH_FILTER_HPP_INCLUDED diff --git a/thirdparty/catch2/src/main/native/include/catch2/internal/catch_platform.hpp b/thirdparty/catch2/src/main/native/include/catch2/internal/catch_platform.hpp index b653a58c5e..ba4717f023 100644 --- a/thirdparty/catch2/src/main/native/include/catch2/internal/catch_platform.hpp +++ b/thirdparty/catch2/src/main/native/include/catch2/internal/catch_platform.hpp @@ -25,6 +25,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 diff --git a/thirdparty/catch2/src/main/native/include/catch2/internal/catch_run_context.hpp b/thirdparty/catch2/src/main/native/include/catch2/internal/catch_run_context.hpp index 39aca522fe..dee851e046 100644 --- a/thirdparty/catch2/src/main/native/include/catch2/internal/catch_run_context.hpp +++ b/thirdparty/catch2/src/main/native/include/catch2/internal/catch_run_context.hpp @@ -94,11 +94,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/thirdparty/catch2/src/main/native/include/catch2/internal/catch_string_manip.hpp b/thirdparty/catch2/src/main/native/include/catch2/internal/catch_string_manip.hpp index dc0c552c4a..4251f83d85 100644 --- a/thirdparty/catch2/src/main/native/include/catch2/internal/catch_string_manip.hpp +++ b/thirdparty/catch2/src/main/native/include/catch2/internal/catch_string_manip.hpp @@ -8,6 +8,7 @@ #ifndef CATCH_STRING_MANIP_HPP_INCLUDED #define CATCH_STRING_MANIP_HPP_INCLUDED +#include #include #include @@ -28,10 +29,10 @@ namespace Catch { //! Returns a new string without whitespace at the start/end std::string trim( std::string const& str ); //! Returns a substring of the original ref without whitespace. Beware lifetimes! - StringRef trim(StringRef ref); + StringRef trim( StringRef ref CATCH_ATTR_LIFETIMEBOUND ); // !!! Be aware, returns refs into original string - make sure original string outlives them - std::vector splitStringRef( StringRef str, char delimiter ); + std::vector splitStringRef( StringRef str CATCH_ATTR_LIFETIMEBOUND, char delimiter ); bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ); /** @@ -49,7 +50,7 @@ namespace Catch { StringRef m_label; public: - constexpr pluralise(std::uint64_t count, StringRef label): + constexpr pluralise(std::uint64_t count, StringRef label CATCH_ATTR_LIFETIMEBOUND): m_count(count), m_label(label) {} diff --git a/thirdparty/catch2/src/main/native/include/catch2/internal/catch_stringref.hpp b/thirdparty/catch2/src/main/native/include/catch2/internal/catch_stringref.hpp index 421ce71292..e70925bcd0 100644 --- a/thirdparty/catch2/src/main/native/include/catch2/internal/catch_stringref.hpp +++ b/thirdparty/catch2/src/main/native/include/catch2/internal/catch_stringref.hpp @@ -8,11 +8,12 @@ #ifndef CATCH_STRINGREF_HPP_INCLUDED #define CATCH_STRINGREF_HPP_INCLUDED +#include + #include #include #include #include - #include namespace Catch { @@ -36,14 +37,16 @@ namespace Catch { public: // construction constexpr StringRef() noexcept = default; - StringRef( char const* rawChars ) noexcept; + StringRef( char const* rawChars CATCH_ATTR_LIFETIMEBOUND ) noexcept; - constexpr StringRef( char const* rawChars, size_type size ) noexcept + constexpr StringRef( char const* rawChars CATCH_ATTR_LIFETIMEBOUND, + size_type size ) noexcept : m_start( rawChars ), m_size( size ) {} - StringRef( std::string const& stdString ) noexcept + StringRef( + std::string const& stdString CATCH_ATTR_LIFETIMEBOUND ) noexcept : m_start( stdString.c_str() ), m_size( stdString.size() ) {} @@ -89,7 +92,7 @@ namespace Catch { } // Returns the current start pointer. May not be null-terminated. - constexpr char const* data() const noexcept { + constexpr char const* data() const noexcept CATCH_ATTR_LIFETIMEBOUND { return m_start; } diff --git a/thirdparty/catch2/src/main/native/include/catch2/internal/catch_test_case_tracker.hpp b/thirdparty/catch2/src/main/native/include/catch2/internal/catch_test_case_tracker.hpp index 50278c910f..48700e9918 100644 --- a/thirdparty/catch2/src/main/native/include/catch2/internal/catch_test_case_tracker.hpp +++ b/thirdparty/catch2/src/main/native/include/catch2/internal/catch_test_case_tracker.hpp @@ -8,6 +8,7 @@ #ifndef CATCH_TEST_CASE_TRACKER_HPP_INCLUDED #define CATCH_TEST_CASE_TRACKER_HPP_INCLUDED +#include #include #include #include @@ -16,6 +17,9 @@ #include namespace Catch { + +struct PathFilter; + namespace TestCaseTracking { struct NameAndLocation { @@ -48,7 +52,7 @@ namespace TestCaseTracking { StringRef name; SourceLineInfo location; - constexpr NameAndLocationRef( StringRef name_, + constexpr NameAndLocationRef( StringRef name_ CATCH_ATTR_LIFETIMEBOUND, SourceLineInfo location_ ): name( name_ ), location( location_ ) {} @@ -91,12 +95,23 @@ namespace TestCaseTracking { Children m_children; CycleState m_runState = NotStarted; - public: - ITracker( NameAndLocation&& nameAndLoc, ITracker* parent ): - m_nameAndLocation( CATCH_MOVE(nameAndLoc) ), - m_parent( parent ) - {} + // Members for path filtering + std::vector const* m_filterRef = nullptr; + // Note: There are 2 dummy section trackers (root, test-case) before + // the first "real" section tracker can be encountered. We start + // the default tracker at -2, so that the first "real" section + // tracker overflows to index 0. + // Nesting depth of this tracker, used to decide which new-style filter applies. + size_t m_allTrackerDepth = static_cast( -2 ); + // Nesting depth of sections (inc. this tracker), used for old-style filters. + // Must be updated by the section tracker on its own. + size_t m_sectionOnlyDepth = static_cast( -2 ); + // Transitory: Remove once we remove backwards compatibility with old-style (v3.x) filters + bool m_newStyleFilters = false; + + public: + ITracker( NameAndLocation&& nameAndLoc, ITracker* parent ); // static queries NameAndLocation const& nameAndLocation() const { @@ -122,6 +137,11 @@ namespace TestCaseTracking { //! Returns true iff tracker has started bool hasStarted() const; + void setFilters( std::vector const* filters, bool newStyleFilters ) { + m_filterRef = filters; + m_newStyleFilters = newStyleFilters; + } + // actions virtual void close() = 0; // Successfully complete virtual void fail() = 0; @@ -207,8 +227,7 @@ namespace TestCaseTracking { void moveToThis(); }; - class SectionTracker : public TrackerBase { - std::vector m_filters; + class SectionTracker final : public TrackerBase { // Note that lifetime-wise we piggy back off the name stored in the `ITracker` parent`. // Currently it allocates owns the name, so this is safe. If it is later refactored // to not own the name, the name still has to outlive the `ITracker` parent, so @@ -225,10 +244,6 @@ namespace TestCaseTracking { void tryOpen(); - void addInitialFilters( std::vector const& filters ); - void addNextFilters( std::vector const& filters ); - //! Returns filters active in this tracker - std::vector const& getFilters() const { return m_filters; } //! Returns whitespace-trimmed name of the tracked section StringRef trimmedName() const; }; diff --git a/thirdparty/catch2/src/main/native/include/catch2/internal/catch_thread_local.hpp b/thirdparty/catch2/src/main/native/include/catch2/internal/catch_thread_local.hpp new file mode 100644 index 0000000000..83213a44cd --- /dev/null +++ b/thirdparty/catch2/src/main/native/include/catch2/internal/catch_thread_local.hpp @@ -0,0 +1,19 @@ + +// Copyright Catch2 Authors +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE.txt or copy at +// https://www.boost.org/LICENSE_1_0.txt) + +// SPDX-License-Identifier: BSL-1.0 +#ifndef CATCH_THREAD_LOCAL_HPP_INCLUDED +#define CATCH_THREAD_LOCAL_HPP_INCLUDED + +#include + +#if defined( CATCH_CONFIG_THREAD_SAFE_ASSERTIONS ) +#define CATCH_INTERNAL_THREAD_LOCAL thread_local +#else +#define CATCH_INTERNAL_THREAD_LOCAL +#endif + +#endif // CATCH_THREAD_LOCAL_HPP_INCLUDED diff --git a/thirdparty/catch2/src/main/native/include/catch2/internal/catch_thread_support.hpp b/thirdparty/catch2/src/main/native/include/catch2/internal/catch_thread_support.hpp index c15980b7ec..5d76ea3208 100644 --- a/thirdparty/catch2/src/main/native/include/catch2/internal/catch_thread_support.hpp +++ b/thirdparty/catch2/src/main/native/include/catch2/internal/catch_thread_support.hpp @@ -10,7 +10,7 @@ #include -#if defined( CATCH_CONFIG_EXPERIMENTAL_THREAD_SAFE_ASSERTIONS ) +#if defined( CATCH_CONFIG_THREAD_SAFE_ASSERTIONS ) # include # include #endif @@ -19,14 +19,14 @@ namespace Catch { namespace Detail { -#if defined( CATCH_CONFIG_EXPERIMENTAL_THREAD_SAFE_ASSERTIONS ) +#if defined( CATCH_CONFIG_THREAD_SAFE_ASSERTIONS ) using Mutex = std::mutex; using LockGuard = std::lock_guard; struct AtomicCounts { - std::atomic passed = 0; - std::atomic failed = 0; - std::atomic failedButOk = 0; - std::atomic skipped = 0; + std::atomic passed{ 0 }; + std::atomic failed{ 0 }; + std::atomic failedButOk{ 0 }; + std::atomic skipped{ 0 }; }; #else // ^^ Use actual mutex, lock and atomics // vv Dummy implementations for single-thread performance diff --git a/thirdparty/catch2/src/main/native/include/catch2/internal/catch_unique_name.hpp b/thirdparty/catch2/src/main/native/include/catch2/internal/catch_unique_name.hpp index c6e1c2caac..b8c08fa232 100644 --- a/thirdparty/catch2/src/main/native/include/catch2/internal/catch_unique_name.hpp +++ b/thirdparty/catch2/src/main/native/include/catch2/internal/catch_unique_name.hpp @@ -8,9 +8,22 @@ #ifndef CATCH_UNIQUE_NAME_HPP_INCLUDED #define CATCH_UNIQUE_NAME_HPP_INCLUDED +#include #include + +// Fixme: Clang 22 has an annoying bug where the localized suppression +// below does not actually suppress the extension warning from +// using __COUNTER__, so we have to leak the suppression for the +// whole TU. Hopefully Clang 23 fixes this before full release. +// As AppleClang does its own thing version-wise, we ignore it +// completely. +#if defined( __clang__ ) && ( __clang_major__ >= 22 ) && !defined( __APPLE__ ) +CATCH_INTERNAL_SUPPRESS_COUNTER_WARNINGS +#endif + #define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line #define INTERNAL_CATCH_UNIQUE_NAME_LINE( name, line ) INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) + #ifdef CATCH_CONFIG_COUNTER # define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __COUNTER__ ) #else diff --git a/thirdparty/catch2/src/main/native/include/catch2/internal/catch_xmlwriter.hpp b/thirdparty/catch2/src/main/native/include/catch2/internal/catch_xmlwriter.hpp index 22b42c5c8f..0b549cd776 100644 --- a/thirdparty/catch2/src/main/native/include/catch2/internal/catch_xmlwriter.hpp +++ b/thirdparty/catch2/src/main/native/include/catch2/internal/catch_xmlwriter.hpp @@ -8,6 +8,7 @@ #ifndef CATCH_XMLWRITER_HPP_INCLUDED #define CATCH_XMLWRITER_HPP_INCLUDED +#include #include #include @@ -43,7 +44,7 @@ namespace Catch { public: enum ForWhat { ForTextNodes, ForAttributes }; - constexpr XmlEncode( StringRef str, ForWhat forWhat = ForTextNodes ): + constexpr XmlEncode( StringRef str CATCH_ATTR_LIFETIMEBOUND, ForWhat forWhat = ForTextNodes ): m_str( str ), m_forWhat( forWhat ) {} @@ -61,7 +62,7 @@ namespace Catch { class ScopedElement { public: - ScopedElement( XmlWriter* writer, XmlFormatting fmt ); + ScopedElement( XmlWriter* writer CATCH_ATTR_LIFETIMEBOUND, XmlFormatting fmt ); ScopedElement( ScopedElement&& other ) noexcept; ScopedElement& operator=( ScopedElement&& other ) noexcept; @@ -93,7 +94,7 @@ namespace Catch { XmlFormatting m_fmt; }; - XmlWriter( std::ostream& os ); + XmlWriter( std::ostream& os CATCH_ATTR_LIFETIMEBOUND ); ~XmlWriter(); XmlWriter( XmlWriter const& ) = delete; diff --git a/thirdparty/catch2/src/main/native/include/catch2/matchers/catch_matchers.hpp b/thirdparty/catch2/src/main/native/include/catch2/matchers/catch_matchers.hpp index 3d996c39f2..90ed333854 100644 --- a/thirdparty/catch2/src/main/native/include/catch2/matchers/catch_matchers.hpp +++ b/thirdparty/catch2/src/main/native/include/catch2/matchers/catch_matchers.hpp @@ -10,6 +10,7 @@ #include #include +#include #include #include @@ -79,11 +80,15 @@ namespace Matchers { return description; } - friend MatchAllOf operator&& (MatchAllOf&& lhs, MatcherBase const& rhs) { + friend MatchAllOf operator&&( MatchAllOf&& lhs, + MatcherBase const& rhs + CATCH_ATTR_LIFETIMEBOUND ) { lhs.m_matchers.push_back(&rhs); return CATCH_MOVE(lhs); } - friend MatchAllOf operator&& (MatcherBase const& lhs, MatchAllOf&& rhs) { + friend MatchAllOf + operator&&( MatcherBase const& lhs CATCH_ATTR_LIFETIMEBOUND, + MatchAllOf&& rhs ) { rhs.m_matchers.insert(rhs.m_matchers.begin(), &lhs); return CATCH_MOVE(rhs); } @@ -131,11 +136,15 @@ namespace Matchers { return description; } - friend MatchAnyOf operator|| (MatchAnyOf&& lhs, MatcherBase const& rhs) { + friend MatchAnyOf operator||( MatchAnyOf&& lhs, + MatcherBase const& rhs + CATCH_ATTR_LIFETIMEBOUND ) { lhs.m_matchers.push_back(&rhs); return CATCH_MOVE(lhs); } - friend MatchAnyOf operator|| (MatcherBase const& lhs, MatchAnyOf&& rhs) { + friend MatchAnyOf + operator||( MatcherBase const& lhs CATCH_ATTR_LIFETIMEBOUND, + MatchAnyOf&& rhs ) { rhs.m_matchers.insert(rhs.m_matchers.begin(), &lhs); return CATCH_MOVE(rhs); } @@ -155,7 +164,8 @@ namespace Matchers { MatcherBase const& m_underlyingMatcher; public: - explicit MatchNotOf( MatcherBase const& underlyingMatcher ): + explicit MatchNotOf( MatcherBase const& underlyingMatcher + CATCH_ATTR_LIFETIMEBOUND ): m_underlyingMatcher( underlyingMatcher ) {} @@ -171,16 +181,22 @@ namespace Matchers { } // namespace Detail template - Detail::MatchAllOf operator&& (MatcherBase const& lhs, MatcherBase const& rhs) { + Detail::MatchAllOf + operator&&( MatcherBase const& lhs CATCH_ATTR_LIFETIMEBOUND, + MatcherBase const& rhs CATCH_ATTR_LIFETIMEBOUND ) { return Detail::MatchAllOf{} && lhs && rhs; } + template - Detail::MatchAnyOf operator|| (MatcherBase const& lhs, MatcherBase const& rhs) { + Detail::MatchAnyOf + operator||( MatcherBase const& lhs CATCH_ATTR_LIFETIMEBOUND, + MatcherBase const& rhs CATCH_ATTR_LIFETIMEBOUND ) { return Detail::MatchAnyOf{} || lhs || rhs; } template - Detail::MatchNotOf operator! (MatcherBase const& matcher) { + Detail::MatchNotOf + operator!( MatcherBase const& matcher CATCH_ATTR_LIFETIMEBOUND ) { return Detail::MatchNotOf{ matcher }; } diff --git a/thirdparty/catch2/src/main/native/include/catch2/matchers/catch_matchers_templated.hpp b/thirdparty/catch2/src/main/native/include/catch2/matchers/catch_matchers_templated.hpp index fc9fcb2bd5..0cd4016365 100644 --- a/thirdparty/catch2/src/main/native/include/catch2/matchers/catch_matchers_templated.hpp +++ b/thirdparty/catch2/src/main/native/include/catch2/matchers/catch_matchers_templated.hpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -114,7 +115,8 @@ namespace Matchers { MatchAllOfGeneric(MatchAllOfGeneric&&) = default; MatchAllOfGeneric& operator=(MatchAllOfGeneric&&) = default; - MatchAllOfGeneric(MatcherTs const&... matchers) : m_matchers{ {std::addressof(matchers)...} } {} + MatchAllOfGeneric(MatcherTs const&... matchers CATCH_ATTR_LIFETIMEBOUND) + : m_matchers{ {std::addressof(matchers)...} } {} explicit MatchAllOfGeneric(std::array matchers) : m_matchers{matchers} {} template @@ -136,8 +138,8 @@ namespace Matchers { template friend MatchAllOfGeneric operator && ( - MatchAllOfGeneric&& lhs, - MatchAllOfGeneric&& rhs) { + MatchAllOfGeneric&& lhs CATCH_ATTR_LIFETIMEBOUND, + MatchAllOfGeneric&& rhs CATCH_ATTR_LIFETIMEBOUND ) { return MatchAllOfGeneric{array_cat(CATCH_MOVE(lhs.m_matchers), CATCH_MOVE(rhs.m_matchers))}; } @@ -145,8 +147,8 @@ namespace Matchers { template friend std::enable_if_t, MatchAllOfGeneric> operator && ( - MatchAllOfGeneric&& lhs, - MatcherRHS const& rhs) { + MatchAllOfGeneric&& lhs CATCH_ATTR_LIFETIMEBOUND, + MatcherRHS const& rhs CATCH_ATTR_LIFETIMEBOUND ) { return MatchAllOfGeneric{array_cat(CATCH_MOVE(lhs.m_matchers), static_cast(&rhs))}; } @@ -154,8 +156,8 @@ namespace Matchers { template friend std::enable_if_t, MatchAllOfGeneric> operator && ( - MatcherLHS const& lhs, - MatchAllOfGeneric&& rhs) { + MatcherLHS const& lhs CATCH_ATTR_LIFETIMEBOUND, + MatchAllOfGeneric&& rhs CATCH_ATTR_LIFETIMEBOUND ) { return MatchAllOfGeneric{array_cat(static_cast(std::addressof(lhs)), CATCH_MOVE(rhs.m_matchers))}; } }; @@ -169,7 +171,8 @@ namespace Matchers { MatchAnyOfGeneric(MatchAnyOfGeneric&&) = default; MatchAnyOfGeneric& operator=(MatchAnyOfGeneric&&) = default; - MatchAnyOfGeneric(MatcherTs const&... matchers) : m_matchers{ {std::addressof(matchers)...} } {} + MatchAnyOfGeneric(MatcherTs const&... matchers CATCH_ATTR_LIFETIMEBOUND) + : m_matchers{ {std::addressof(matchers)...} } {} explicit MatchAnyOfGeneric(std::array matchers) : m_matchers{matchers} {} template @@ -190,8 +193,8 @@ namespace Matchers { //! Avoids type nesting for `GenericAnyOf || GenericAnyOf` case template friend MatchAnyOfGeneric operator || ( - MatchAnyOfGeneric&& lhs, - MatchAnyOfGeneric&& rhs) { + MatchAnyOfGeneric&& lhs CATCH_ATTR_LIFETIMEBOUND, + MatchAnyOfGeneric&& rhs CATCH_ATTR_LIFETIMEBOUND ) { return MatchAnyOfGeneric{array_cat(CATCH_MOVE(lhs.m_matchers), CATCH_MOVE(rhs.m_matchers))}; } @@ -199,8 +202,8 @@ namespace Matchers { template friend std::enable_if_t, MatchAnyOfGeneric> operator || ( - MatchAnyOfGeneric&& lhs, - MatcherRHS const& rhs) { + MatchAnyOfGeneric&& lhs CATCH_ATTR_LIFETIMEBOUND, + MatcherRHS const& rhs CATCH_ATTR_LIFETIMEBOUND ) { return MatchAnyOfGeneric{array_cat(CATCH_MOVE(lhs.m_matchers), static_cast(std::addressof(rhs)))}; } @@ -208,8 +211,8 @@ namespace Matchers { template friend std::enable_if_t, MatchAnyOfGeneric> operator || ( - MatcherLHS const& lhs, - MatchAnyOfGeneric&& rhs) { + MatcherLHS const& lhs CATCH_ATTR_LIFETIMEBOUND, + MatchAnyOfGeneric&& rhs CATCH_ATTR_LIFETIMEBOUND) { return MatchAnyOfGeneric{array_cat(static_cast(std::addressof(lhs)), CATCH_MOVE(rhs.m_matchers))}; } }; @@ -225,7 +228,8 @@ namespace Matchers { MatchNotOfGeneric(MatchNotOfGeneric&&) = default; MatchNotOfGeneric& operator=(MatchNotOfGeneric&&) = default; - explicit MatchNotOfGeneric(MatcherT const& matcher) : m_matcher{matcher} {} + explicit MatchNotOfGeneric(MatcherT const& matcher CATCH_ATTR_LIFETIMEBOUND) + : m_matcher{matcher} {} template bool match(Arg&& arg) const { @@ -237,7 +241,9 @@ namespace Matchers { } //! Negating negation can just unwrap and return underlying matcher - friend MatcherT const& operator ! (MatchNotOfGeneric const& matcher) { + friend MatcherT const& + operator!( MatchNotOfGeneric const& matcher + CATCH_ATTR_LIFETIMEBOUND ) { return matcher.m_matcher; } }; @@ -247,20 +253,22 @@ namespace Matchers { // compose only generic matchers template std::enable_if_t, Detail::MatchAllOfGeneric> - operator && (MatcherLHS const& lhs, MatcherRHS const& rhs) { + operator&&( MatcherLHS const& lhs CATCH_ATTR_LIFETIMEBOUND, + MatcherRHS const& rhs CATCH_ATTR_LIFETIMEBOUND ) { return { lhs, rhs }; } template std::enable_if_t, Detail::MatchAnyOfGeneric> - operator || (MatcherLHS const& lhs, MatcherRHS const& rhs) { + operator||( MatcherLHS const& lhs CATCH_ATTR_LIFETIMEBOUND, + MatcherRHS const& rhs CATCH_ATTR_LIFETIMEBOUND ) { return { lhs, rhs }; } //! Wrap provided generic matcher in generic negator template std::enable_if_t, Detail::MatchNotOfGeneric> - operator ! (MatcherT const& matcher) { + operator!( MatcherT const& matcher CATCH_ATTR_LIFETIMEBOUND ) { return Detail::MatchNotOfGeneric{matcher}; } @@ -268,25 +276,29 @@ namespace Matchers { // compose mixed generic and non-generic matchers template std::enable_if_t, Detail::MatchAllOfGeneric>> - operator && (MatcherLHS const& lhs, MatcherBase const& rhs) { + operator&&( MatcherLHS const& lhs CATCH_ATTR_LIFETIMEBOUND, + MatcherBase const& rhs CATCH_ATTR_LIFETIMEBOUND ) { return { lhs, rhs }; } template std::enable_if_t, Detail::MatchAllOfGeneric, MatcherRHS>> - operator && (MatcherBase const& lhs, MatcherRHS const& rhs) { + operator&&( MatcherBase const& lhs CATCH_ATTR_LIFETIMEBOUND, + MatcherRHS const& rhs CATCH_ATTR_LIFETIMEBOUND ) { return { lhs, rhs }; } template std::enable_if_t, Detail::MatchAnyOfGeneric>> - operator || (MatcherLHS const& lhs, MatcherBase const& rhs) { + operator||( MatcherLHS const& lhs CATCH_ATTR_LIFETIMEBOUND, + MatcherBase const& rhs CATCH_ATTR_LIFETIMEBOUND ) { return { lhs, rhs }; } template std::enable_if_t, Detail::MatchAnyOfGeneric, MatcherRHS>> - operator || (MatcherBase const& lhs, MatcherRHS const& rhs) { + operator||( MatcherBase const& lhs CATCH_ATTR_LIFETIMEBOUND, + MatcherRHS const& rhs CATCH_ATTR_LIFETIMEBOUND ) { return { lhs, rhs }; } diff --git a/thirdparty/catch2/src/main/native/include/catch2/reporters/catch_reporter_helpers.hpp b/thirdparty/catch2/src/main/native/include/catch2/reporters/catch_reporter_helpers.hpp index 316cb4048a..469888884a 100644 --- a/thirdparty/catch2/src/main/native/include/catch2/reporters/catch_reporter_helpers.hpp +++ b/thirdparty/catch2/src/main/native/include/catch2/reporters/catch_reporter_helpers.hpp @@ -55,7 +55,8 @@ namespace Catch { * format */ void defaultListListeners( std::ostream& out, - std::vector const& descriptions ); + std::vector const& descriptions, + Verbosity verbosity ); /** * Lists tag information to the provided stream in user-friendly format @@ -64,7 +65,10 @@ namespace Catch { * bases. The output should be backwards compatible with the output of * Catch2 v2 binaries. */ - void defaultListTags( std::ostream& out, std::vector const& tags, bool isFiltered ); + void defaultListTags( std::ostream& out, + std::vector const& tags, + bool isFiltered, + Verbosity verbosity ); /** * Lists test case information to the provided stream in user-friendly diff --git a/thirdparty/catch2/src/main/native/include/catch2/reporters/catch_reporter_junit.hpp b/thirdparty/catch2/src/main/native/include/catch2/reporters/catch_reporter_junit.hpp index 7cb53c25b5..a265f78a82 100644 --- a/thirdparty/catch2/src/main/native/include/catch2/reporters/catch_reporter_junit.hpp +++ b/thirdparty/catch2/src/main/native/include/catch2/reporters/catch_reporter_junit.hpp @@ -41,7 +41,7 @@ namespace Catch { bool testOkToFail ); void writeAssertions(SectionNode const& sectionNode); - void writeAssertion(AssertionStats const& stats); + bool writeAssertion(AssertionStats const& stats); XmlWriter xml; Timer suiteTimer; diff --git a/upstream_utils/catch2.py b/upstream_utils/catch2.py index 5d7e36572e..165a71e31c 100755 --- a/upstream_utils/catch2.py +++ b/upstream_utils/catch2.py @@ -49,7 +49,7 @@ def copy_upstream_src(wpilib_root: Path): def main(): name = "catch2" url = "https://github.com/catchorg/Catch2.git" - tag = "v3.10.0" + tag = "v3.14.0" patch_options = { "ignore_whitespace": True,