diff --git a/CMakeLists.txt b/CMakeLists.txt index 7946bc52..e0b782f0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -35,7 +35,7 @@ if(CMAKE_BINARY_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) endif() project(Catch2 - VERSION 3.14.0 # CML version placeholder, don't delete + VERSION 3.15.0 # CML version placeholder, don't delete LANGUAGES CXX HOMEPAGE_URL "https://github.com/catchorg/Catch2" DESCRIPTION "A modern, C++-native, unit test framework." diff --git a/docs/matchers.md b/docs/matchers.md index a57dc6d3..fa176ced 100644 --- a/docs/matchers.md +++ b/docs/matchers.md @@ -474,7 +474,7 @@ and new style matchers arbitrarily. ## Constexpr matchers -> Support for constexpr matchers was introduced in Catch2 vX.Y.Z +> Support for constexpr matchers was introduced in Catch2 3.15.0 When compiled for C++20, the new-style matchers (can) support `constexpr` matching, albeit not `constexpr` stringification. The matcher combinators diff --git a/docs/other-macros.md b/docs/other-macros.md index de7e4bc6..9faf5da2 100644 --- a/docs/other-macros.md +++ b/docs/other-macros.md @@ -93,7 +93,7 @@ TEST_CASE("STATIC_CHECK showcase", "[traits]") { * `STATIC_REQUIRE_THAT` and `STATIC_CHECK_THAT` -> `STATIC_REQUIRE_THAT` and `STATIC_CHECK_THAT` was introduced in Catch2 X.Y.Z +> `STATIC_REQUIRE_THAT` and `STATIC_CHECK_THAT` was introduced in Catch2 3.15.0 `STATIC_{REQUIRE,CHECK}_THAT` are analogous to `STATIC_{REQUIRE,CHECK}`, but for matchers. They are always defined, even if the current compiler diff --git a/docs/release-notes.md b/docs/release-notes.md index d2c4ce63..3df9e690 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -2,6 +2,7 @@ # Release notes **Contents**
+[3.15.0](#3150)
[3.14.0](#3140)
[3.13.0](#3130)
[3.12.0](#3120)
@@ -74,6 +75,22 @@ [Even Older versions](#even-older-versions)
+## 3.15.0 + +### Fixes +* Fixed ambiguous overload issue with `std::optional` in C++26. (#3095) + * Since `std::optional` was turned into a range, the partial specialization of `StringMaker` for range-like types and for `std::optional` were in conflict. + +### Improvements +* Simplified `CATCH_REGISTER_ENUM` internals for faster compilation and retrieval. +* Successful assertion are slightly (1-2%) faster. +* Generic (new-style) matchers support constexpr matching in C++20. + * Combining matchers requires C++26. + * Catch2-provided generic matchers are all constexpr enabled. +* Added `STATIC_REQUIRE_THAT` for compile-time matcher assertions. + * This requires the compiler to support enough `constexpr` for matchers, see above. + + ## 3.14.0 ### Fixes diff --git a/extras/catch_amalgamated.cpp b/extras/catch_amalgamated.cpp index b0c5c7ca..e851b09d 100644 --- a/extras/catch_amalgamated.cpp +++ b/extras/catch_amalgamated.cpp @@ -6,8 +6,8 @@ // SPDX-License-Identifier: BSL-1.0 -// Catch v3.14.0 -// Generated: 2026-04-05 15:03:01.631668 +// Catch v3.15.0 +// Generated: 2026-05-12 13:08:21.086523 // ---------------------------------------------------------- // This file is an amalgamation of multiple different files. // You probably shouldn't edit it directly. @@ -74,11 +74,11 @@ namespace Catch { samples.data(), samples.data() + samples.size() ); auto wrap_estimate = [](Estimate e) { - return Estimate { - FDuration(e.point), - FDuration(e.lower_bound), - FDuration(e.upper_bound), - e.confidence_interval, + return Estimate{ + FDuration( e.point ), + FDuration( e.lower_bound ), + FDuration( e.upper_bound ), + e.confidence_interval, }; }; std::vector samples2; @@ -147,7 +147,7 @@ namespace Catch { namespace Catch { namespace Benchmark { namespace Detail { - struct optimized_away_error : std::exception { + struct optimized_away_error final : std::exception { const char* what() const noexcept override; }; @@ -995,6 +995,7 @@ namespace Catch { + #include #include @@ -1007,7 +1008,7 @@ namespace Catch { m_messageId( builder.m_info.sequence ) { MessageInfo info( CATCH_MOVE( builder.m_info ) ); info.message = builder.m_stream.str(); - IResultCapture::pushScopedMessage( CATCH_MOVE( info ) ); + Detail::pushScopedMessage( CATCH_MOVE( info ) ); } ScopedMessage::ScopedMessage( ScopedMessage&& old ) noexcept: @@ -1016,7 +1017,7 @@ namespace Catch { } ScopedMessage::~ScopedMessage() { - if ( !m_moved ) { IResultCapture::popScopedMessage( m_messageId ); } + if ( !m_moved ) { Detail::popScopedMessage( m_messageId ); } } @@ -1088,7 +1089,7 @@ namespace Catch { assert( m_captured == m_messages.size() ); if ( m_isScoped ) { for ( auto const& message : m_messages ) { - IResultCapture::popScopedMessage( message.sequence ); + Detail::popScopedMessage( message.sequence ); } } } @@ -1097,9 +1098,9 @@ namespace Catch { assert( index < m_messages.size() ); m_messages[index].message += value; if ( m_isScoped ) { - IResultCapture::pushScopedMessage( CATCH_MOVE( m_messages[index] ) ); + Detail::pushScopedMessage( CATCH_MOVE( m_messages[index] ) ); } else { - IResultCapture::addUnscopedMessage( CATCH_MOVE( m_messages[index] ) ); + Detail::addUnscopedMessage( CATCH_MOVE( m_messages[index] ) ); } m_captured++; } @@ -1160,9 +1161,6 @@ namespace Catch { CATCH_INTERNAL_ERROR("Attempted to register active exception under CATCH_CONFIG_DISABLE_EXCEPTIONS!"); #endif } - IMutableEnumValuesRegistry& getMutableEnumValuesRegistry() override { - return m_enumValuesRegistry; - } private: TestRegistry m_testCaseRegistry; @@ -1170,7 +1168,6 @@ namespace Catch { ExceptionTranslatorRegistry m_exceptionTranslatorRegistry; TagAliasRegistry m_tagAliasRegistry; StartupExceptionRegistry m_exceptionRegistry; - Detail::EnumValuesRegistry m_enumValuesRegistry; }; } @@ -2397,7 +2394,7 @@ namespace Catch { } Version const& libraryVersion() { - static Version version( 3, 14, 0, "", 0 ); + static Version version( 3, 15, 0, "", 0 ); return version; } @@ -2686,13 +2683,17 @@ namespace Catch { namespace Catch { + void AssertionHandler::finishIncomplete() { + m_resultCapture.handleIncomplete( m_assertionInfo ); + } + AssertionHandler::AssertionHandler ( StringRef macroName, SourceLineInfo const& lineInfo, StringRef capturedExpression, ResultDisposition::Flags resultDisposition ) : m_assertionInfo{ macroName, lineInfo, capturedExpression, resultDisposition }, - m_resultCapture( getResultCapture() ) + m_resultCapture( static_cast(getResultCapture()) ) { m_resultCapture.notifyAssertionStarted( m_assertionInfo ); } @@ -4088,12 +4089,11 @@ namespace Catch { + #include namespace Catch { - IMutableEnumValuesRegistry::~IMutableEnumValuesRegistry() = default; - namespace Detail { namespace { @@ -4119,9 +4119,7 @@ namespace Catch { return parsed; } - EnumInfo::~EnumInfo() = default; - - StringRef EnumInfo::lookup( int value ) const { + StringRef EnumInfo::lookup( int64_t value ) const { for( auto const& valueToName : m_values ) { if( valueToName.first == value ) return valueToName.second; @@ -4129,25 +4127,20 @@ namespace Catch { return "{** unexpected enum value **}"_sr; } - Catch::Detail::unique_ptr makeEnumInfo( StringRef enumName, StringRef allValueNames, std::vector const& values ) { - auto enumInfo = Catch::Detail::make_unique(); - enumInfo->m_name = enumName; - enumInfo->m_values.reserve( values.size() ); + EnumInfo makeEnumInfo( StringRef enumName, StringRef allValueNames, std::vector const& values ) { + EnumInfo enumInfo; + enumInfo.m_name = enumName; + enumInfo.m_values.reserve( values.size() ); const auto valueNames = Catch::Detail::parseEnums( allValueNames ); assert( valueNames.size() == values.size() ); - std::size_t i = 0; - for( auto value : values ) - enumInfo->m_values.emplace_back(value, valueNames[i++]); + for (size_t i = 0; i < values.size(); ++i) { + enumInfo.m_values.emplace_back( values[i], valueNames[i] ); + } return enumInfo; } - EnumInfo const& EnumValuesRegistry::registerEnum( StringRef enumName, StringRef allValueNames, std::vector const& values ) { - m_enumInfos.push_back(makeEnumInfo(enumName, allValueNames, values)); - return *m_enumInfos.back(); - } - } // Detail } // Catch @@ -5072,7 +5065,7 @@ namespace Catch { namespace { //! A no-op implementation, used if no reporter wants output //! redirection. - class NoopRedirect : public OutputRedirect { + class NoopRedirect final : public OutputRedirect { void activateImpl() override {} void deactivateImpl() override {} std::string getStdout() override { return {}; } @@ -5109,7 +5102,7 @@ namespace Catch { * Redirects the `std::cout`, `std::cerr`, `std::clog` streams, * but does not touch the actual `stdout`/`stderr` file descriptors. */ - class StreamRedirect : public OutputRedirect { + class StreamRedirect final : public OutputRedirect { ReusableStringStream m_redirectedOut, m_redirectedErr; RedirectedStreamNew m_cout, m_cerr, m_clog; @@ -5220,7 +5213,7 @@ namespace Catch { * Works by replacing the file descriptors numbered 1 and 2 * with an open temporary file. */ - class FileRedirect : public OutputRedirect { + class FileRedirect final : public OutputRedirect { TempFile m_outFile, m_errFile; int m_originalOut = -1; int m_originalErr = -1; @@ -6136,6 +6129,25 @@ namespace Catch { } CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION + + void pushScopedMessage( MessageInfo&& message ) { + Detail::g_messageHolder().addScopedMessage( CATCH_MOVE( message ) ); + } + + void popScopedMessage( unsigned int messageId ) { + Detail::g_messageHolder().removeMessage( messageId ); + } + + void emplaceUnscopedMessage( MessageBuilder&& builder ) { + Detail::g_messageHolder().addUnscopedMessage( CATCH_MOVE( builder ) ); + } + + void addUnscopedMessage( MessageInfo&& message ) { + Detail::g_messageHolder().addUnscopedMessage( CATCH_MOVE( message ) ); + } + + bool lastAssertionPassed() { return Detail::g_lastAssertionPassed; } + } // namespace Detail RunContext::RunContext(IConfig const* _config, IEventListenerPtr&& reporter) @@ -6269,14 +6281,13 @@ namespace Catch { Detail::g_lastAssertionPassed = true; } else if (!result.succeeded()) { Detail::g_lastAssertionPassed = false; - if (result.isOk()) { - } - else if( m_activeTestCase->getTestCaseInfo().okToFail() ) // Read from a shared state established before the threads could start, this is fine + if (result.isOk()) {} + else if( m_activeTestCase->getTestCaseInfo().okToFail() ) { // Read from a shared state established before the threads could start, this is fine m_atomicAssertionCount.failedButOk++; - else + } else { m_atomicAssertionCount.failed++; - } - else { + } + } else { Detail::g_lastAssertionPassed = true; } @@ -6458,7 +6469,7 @@ namespace Catch { // and since IResultCapture::getLastResult is deprecated, // we will leave it as is, until it is finally removed. Detail::LockGuard _( m_assertionMutex ); - return &(*m_lastResult); + return &*m_lastResult; } void RunContext::exceptionEarlyReported() { @@ -6532,10 +6543,6 @@ namespace Catch { m_reporter->testRunEnded(TestRunStats(m_runInfo, m_totals, false)); } - bool RunContext::lastAssertionPassed() { - return Detail::g_lastAssertionPassed; - } - void RunContext::assertionPassedFastPath(SourceLineInfo lineInfo) { // We want to save the line info for better experience with unexpected assertions Detail::g_lastKnownLineInfo = lineInfo; @@ -6714,7 +6721,7 @@ namespace Catch { } void RunContext::populateReaction( AssertionReaction& reaction, - bool has_normal_disposition ) { + bool has_normal_disposition ) const { reaction.shouldDebugBreak = m_shouldDebugBreak; reaction.shouldThrow = aborting() || has_normal_disposition; } @@ -6765,22 +6772,6 @@ namespace Catch { } } - 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) { sharedRng().seed(config.rngSeed()); } @@ -7112,10 +7103,11 @@ namespace Catch { TagAlias const* TagAliasRegistry::find( std::string const& alias ) const { auto it = m_registry.find( alias ); - if( it != m_registry.end() ) - return &(it->second); - else + if ( it != m_registry.end() ) { + return &it->second; + } else { return nullptr; + } } std::string TagAliasRegistry::expandAliases( std::string const& unexpandedTestSpec ) const { @@ -7562,7 +7554,7 @@ namespace Catch { void throw_test_failure_exception() { #if !defined( CATCH_CONFIG_DISABLE_EXCEPTIONS ) - throw TestFailureException{}; + throw TestFailureException{}; //NOLINT(bugprone-std-exception-baseclass) #else CATCH_ERROR( "Test failure requires aborting test!" ); #endif @@ -7570,7 +7562,7 @@ namespace Catch { void throw_test_skip_exception() { #if !defined( CATCH_CONFIG_DISABLE_EXCEPTIONS ) - throw Catch::TestSkipException(); + throw Catch::TestSkipException(); //NOLINT(bugprone-std-exception-baseclass) #else CATCH_ERROR( "Explicitly skipping tests during runtime requires exceptions" ); #endif @@ -8674,13 +8666,13 @@ namespace Catch { namespace Matchers { std::string MatcherUntypedBase::toString() const { - if (m_cachedToString.empty()) { - m_cachedToString = describe(); - } - return m_cachedToString; + return describe(); } - MatcherUntypedBase::~MatcherUntypedBase() = default; + std::string MatcherUntypedBase::describe() const { + using namespace std::string_literals; + return "Undescribed matcher"s; + } } // namespace Matchers } // namespace Catch @@ -8701,14 +8693,6 @@ namespace Matchers { return sstr.str(); } - IsEmptyMatcher IsEmpty() { - return {}; - } - - HasSizeMatcher SizeIs(std::size_t sz) { - return HasSizeMatcher{ sz }; - } - } // end namespace Matchers } // end namespace Catch @@ -8962,17 +8946,13 @@ std::string Catch::Matchers::Detail::finalizeDescription(const std::string& desc namespace Catch { namespace Matchers { - std::string AllTrueMatcher::describe() const { return "contains only true"; } - AllTrueMatcher AllTrue() { return AllTrueMatcher{}; } + std::string AllTrueMatcher::describe() const { return "contains only true"; } std::string NoneTrueMatcher::describe() const { return "contains no true"; } - NoneTrueMatcher NoneTrue() { return NoneTrueMatcher{}; } - std::string AnyTrueMatcher::describe() const { return "contains at least one true"; } - AnyTrueMatcher AnyTrue() { return AnyTrueMatcher{}; } } // namespace Matchers } // namespace Catch @@ -9085,7 +9065,11 @@ namespace Matchers { namespace Catch { namespace Matchers { - MatcherGenericBase::~MatcherGenericBase() = default; + + std::string MatcherGenericBase::describe() const { + using namespace std::string_literals; + return "Undescribed generic matcher"s; + } namespace Detail { @@ -10108,9 +10092,8 @@ namespace Catch { bool operator()( Detail::unique_ptr const& node ) const { - return ( - ( node->stats.sectionInfo.name == m_other.name ) && - ( node->stats.sectionInfo.lineInfo == m_other.lineInfo ) ); + return node->stats.sectionInfo.name == m_other.name + && node->stats.sectionInfo.lineInfo == m_other.lineInfo; } void operator=( BySectionInfo const& ) = delete; @@ -10464,7 +10447,7 @@ namespace Catch { } // minimum whitespace to pad tag counts, possibly overwritten below - size_t maxTagCountLen = 2; + int maxTagCountLen = 2; // determine necessary padding for tag count column if ( ! tags.empty() ) { @@ -10479,7 +10462,7 @@ namespace Catch { // more padding necessary for 3+ digits if (maxTagCount >= 100) { auto numDigits = 1 + std::floor( std::log10( maxTagCount ) ); - maxTagCountLen = static_cast( numDigits ); + maxTagCountLen = static_cast( numDigits ); } } diff --git a/extras/catch_amalgamated.hpp b/extras/catch_amalgamated.hpp index ba6cf8ff..40fbf485 100644 --- a/extras/catch_amalgamated.hpp +++ b/extras/catch_amalgamated.hpp @@ -6,8 +6,8 @@ // SPDX-License-Identifier: BSL-1.0 -// Catch v3.14.0 -// Generated: 2026-04-05 15:03:01.150393 +// Catch v3.15.0 +// Generated: 2026-05-12 13:08:20.543985 // ---------------------------------------------------------- // This file is an amalgamation of multiple different files. // You probably shouldn't edit it directly. @@ -118,16 +118,24 @@ #endif // CATCH_PLATFORM_HPP_INCLUDED -#ifdef __cplusplus +#if (__cplusplus >= 201703L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) +# define CATCH_CPP17_OR_GREATER +#endif -# if (__cplusplus >= 201703L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) -# define CATCH_CPP17_OR_GREATER -# endif - -# if (__cplusplus >= 202002L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L) -# define CATCH_CPP20_OR_GREATER -# endif +#if (__cplusplus >= 202002L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L) +# define CATCH_CPP20_OR_GREATER +#endif +// Matchers are only constexpr-able in C++20 +#if defined( CATCH_CPP20_OR_GREATER ) && \ + defined( __cpp_constexpr_dynamic_alloc ) && \ + __cpp_constexpr_dynamic_alloc >= 201907L && \ + /* GCC < 13 define the feature macro, but compiler bugs stop us from using it */ \ + ( !defined( __GNUC__ ) || __GNUC__ >= 13 || defined(__clang__) ) +# define CATCH_INTERNAL_CONSTEXPR_MATCHERS_ENABLED +# define CATCH_DESTRUCTOR_CONSTEXPR constexpr +#else +# define CATCH_DESTRUCTOR_CONSTEXPR #endif // Only GCC compiler should be used in this block, so other compilers trying to @@ -1053,8 +1061,6 @@ namespace Catch { struct AssertionInfo; struct SectionInfo; struct SectionEndInfo; - struct MessageInfo; - struct MessageBuilder; struct Counts; struct AssertionReaction; struct SourceLineInfo; @@ -1094,11 +1100,6 @@ namespace Catch { virtual void benchmarkEnded( BenchmarkStats<> const& stats ) = 0; virtual void benchmarkFailed( StringRef error ) = 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; virtual void handleExpr @@ -1124,9 +1125,6 @@ namespace Catch { ResultWas::OfType resultType, AssertionReaction &reaction ) = 0; - - virtual bool lastAssertionPassed() = 0; - // Deprecated, do not use: virtual std::string getCurrentTestName() const = 0; virtual const AssertionResult* getLastResult() const = 0; @@ -1231,7 +1229,7 @@ namespace Catch { class IStream; struct PathFilter; - class IConfig : public Detail::NonCopyable { + class IConfig : Detail::NonCopyable { public: virtual ~IConfig(); @@ -1319,7 +1317,6 @@ namespace Catch { virtual void registerTranslator( Detail::unique_ptr&& translator ) = 0; virtual void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) = 0; virtual void registerStartupException() noexcept = 0; - virtual IMutableEnumValuesRegistry& getMutableEnumValuesRegistry() = 0; }; IRegistryHub const& getRegistryHub(); @@ -1681,7 +1678,7 @@ namespace Catch { callable& operator=(callable&&) = default; }; template - struct model : public callable { + struct model final : public callable { model(Fun&& fun_) : fun(CATCH_MOVE(fun_)) {} model(Fun const& fun_) : fun(fun_) {} @@ -2469,45 +2466,46 @@ namespace Catch { #endif // CATCH_VOID_TYPE_HPP_INCLUDED -#ifndef CATCH_INTERFACES_ENUM_VALUES_REGISTRY_HPP_INCLUDED -#define CATCH_INTERFACES_ENUM_VALUES_REGISTRY_HPP_INCLUDED +#ifndef CATCH_ENUM_INFO_HPP_INCLUDED +#define CATCH_ENUM_INFO_HPP_INCLUDED +#include +#include #include namespace Catch { - namespace Detail { + struct EnumInfo { StringRef m_name; - std::vector> m_values; + std::vector> m_values; - ~EnumInfo(); - - StringRef lookup( int value ) const; + StringRef lookup( int64_t value ) const; }; - } // namespace Detail - class IMutableEnumValuesRegistry { - public: - virtual ~IMutableEnumValuesRegistry(); // = default; - - virtual Detail::EnumInfo const& registerEnum( StringRef enumName, StringRef allEnums, std::vector const& values ) = 0; - - template - Detail::EnumInfo const& registerEnum( StringRef enumName, StringRef allEnums, std::initializer_list values ) { - static_assert(sizeof(int) >= sizeof(E), "Cannot serialize enum to int"); - std::vector intValues; + EnumInfo makeEnumInfo( StringRef enumName, + StringRef allValueNames, + std::vector const& values ); + template + Detail::EnumInfo makeEnumInfo( StringRef enumName, + StringRef allEnums, + std::initializer_list values ) { + static_assert( sizeof( int64_t ) >= sizeof( E ), + "Cannot serialize enum to int64_t" ); + std::vector intValues; intValues.reserve( values.size() ); - for( auto enumValue : values ) - intValues.push_back( static_cast( enumValue ) ); - return registerEnum( enumName, allEnums, intValues ); + for ( auto enumValue : values ) + intValues.push_back( static_cast( enumValue ) ); + return makeEnumInfo( enumName, allEnums, intValues ); } - }; -} // Catch + std::vector parseEnums( StringRef enums ); -#endif // CATCH_INTERFACES_ENUM_VALUES_REGISTRY_HPP_INCLUDED + } // namespace Detail +} // namespace Catch + +#endif // CATCH_ENUM_INFO_HPP_INCLUDED #ifdef CATCH_CONFIG_CPP17_STRING_VIEW #include @@ -2872,7 +2870,10 @@ namespace Catch { } #endif // CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER -#if defined(CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER) && defined(CATCH_CONFIG_CPP17_OPTIONAL) +#if defined( CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER ) && \ + defined( CATCH_CONFIG_CPP17_OPTIONAL ) && \ + /* P3168 turned optional into a range, making this ambigous with the range support */ \ + !defined( __cpp_lib_optional_range_support ) #include namespace Catch { template @@ -3119,16 +3120,21 @@ struct ratio_string { }; } - -#define INTERNAL_CATCH_REGISTER_ENUM( enumName, ... ) \ -namespace Catch { \ - template<> struct StringMaker { \ - static std::string convert( enumName value ) { \ - static const auto& enumInfo = ::Catch::getMutableRegistryHub().getMutableEnumValuesRegistry().registerEnum( #enumName, #__VA_ARGS__, { __VA_ARGS__ } ); \ - return static_cast(enumInfo.lookup( static_cast( value ) )); \ - } \ - }; \ -} +#define INTERNAL_CATCH_REGISTER_ENUM( enumName, ... ) \ + namespace Catch { \ + template <> \ + struct StringMaker { \ + static std::string convert( enumName value ) { \ + CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ + CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + static const auto enumInfo = ::Catch::Detail::makeEnumInfo( \ + #enumName, #__VA_ARGS__, { __VA_ARGS__ } ); \ + CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \ + return static_cast( \ + enumInfo.lookup( static_cast( value ) ) ); \ + } \ + }; \ + } #define CATCH_REGISTER_ENUM( enumName, ... ) INTERNAL_CATCH_REGISTER_ENUM( enumName, __VA_ARGS__ ) @@ -4049,9 +4055,21 @@ namespace Catch { #include namespace Catch { + struct MessageInfo; + struct MessageBuilder; + + namespace Detail { + // The message state affecting functions have to be defined in + // the TU where the thread-local message holders are defined. + // Currently this is catch_run_context.cpp + + void pushScopedMessage( MessageInfo&& message ); + void popScopedMessage( unsigned int messageId ); + void addUnscopedMessage( MessageInfo&& message ); + void emplaceUnscopedMessage( MessageBuilder&& builder ); + } // namespace Detail struct SourceLineInfo; - class IResultCapture; struct MessageStream { @@ -4141,7 +4159,7 @@ namespace Catch { /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_UNSCOPED_INFO( macroName, log ) \ - Catch::IResultCapture::emplaceUnscopedMessage( Catch::MessageBuilder( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log ) + Catch::Detail::emplaceUnscopedMessage( Catch::MessageBuilder( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log ) #if defined(CATCH_CONFIG_PREFIX_MESSAGES) && !defined(CATCH_CONFIG_DISABLE) @@ -5430,7 +5448,7 @@ namespace Catch { void formatReconstructedExpression( std::ostream &os, std::string const& lhs, StringRef op, std::string const& rhs ); template - class BinaryExpr : public ITransientExpression { + class BinaryExpr final : public ITransientExpression { LhsT m_lhs; StringRef m_op; RhsT m_rhs; @@ -5506,7 +5524,7 @@ namespace Catch { }; template - class UnaryExpr : public ITransientExpression { + class UnaryExpr final : public ITransientExpression { LhsT m_lhs; void streamReconstructedExpression( std::ostream &os ) const override { @@ -5707,6 +5725,8 @@ namespace Catch { namespace Catch { + class RunContext; + struct AssertionReaction { bool shouldDebugBreak = false; bool shouldThrow = false; @@ -5717,7 +5737,12 @@ namespace Catch { AssertionInfo m_assertionInfo; AssertionReaction m_reaction; bool m_completed = false; - IResultCapture& m_resultCapture; + // Since all uses are hidden in the .cpp file, we can directly use + // the final type and avoid going through virtual dispatch, without + // massive compilation time overhead. + RunContext& m_resultCapture; + + void finishIncomplete(); public: AssertionHandler @@ -5726,9 +5751,9 @@ namespace Catch { StringRef capturedExpression, ResultDisposition::Flags resultDisposition ); ~AssertionHandler() { - if ( !m_completed ) { - m_resultCapture.handleIncomplete( m_assertionInfo ); - } + // We want the common fast path inlinable, and the virtual + // dispatch in a function in single TU. + if ( !m_completed ) { finishIncomplete(); } } @@ -5771,6 +5796,13 @@ namespace Catch { #endif // CATCH_PREPROCESSOR_INTERNAL_STRINGIFY_HPP_INCLUDED +namespace Catch { + namespace Detail { + // Defined in catch_run_context.cpp, where the thread-local data lives. + bool lastAssertionPassed(); + } +} + // We need this suppression to leak, because it took until GCC 10 // for the front end to handle local suppression via _Pragma properly #if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC) && __GNUC__ <= 9 @@ -5813,12 +5845,12 @@ namespace Catch { /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_IF( macroName, resultDisposition, ... ) \ INTERNAL_CATCH_TEST( macroName, resultDisposition, __VA_ARGS__ ); \ - if( Catch::getResultCapture().lastAssertionPassed() ) + if( Catch::Detail::lastAssertionPassed() ) /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_ELSE( macroName, resultDisposition, ... ) \ INTERNAL_CATCH_TEST( macroName, resultDisposition, __VA_ARGS__ ); \ - if( !Catch::getResultCapture().lastAssertionPassed() ) + if( !Catch::Detail::lastAssertionPassed() ) /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_NO_THROW( macroName, resultDisposition, ... ) \ @@ -6101,7 +6133,7 @@ namespace Catch { namespace Catch { template -class TestInvokerAsMethod : public ITestInvoker { +class TestInvokerAsMethod final : public ITestInvoker { void (C::*m_testAsMethod)(); public: constexpr TestInvokerAsMethod( void ( C::*testAsMethod )() ) noexcept: @@ -6121,7 +6153,7 @@ Detail::unique_ptr makeTestInvoker( void (C::*testAsMethod)() ) { } template -class TestInvokerFixture : public ITestInvoker { +class TestInvokerFixture final : public ITestInvoker { void ( C::*m_testAsMethod )() const; Detail::unique_ptr m_fixture = nullptr; @@ -6196,7 +6228,7 @@ struct AutoReg : Detail::NonCopyable { namespace Catch { namespace Detail { struct DummyUse { - DummyUse( void ( * )( int ), Catch::NameAndTags const& ); + DummyUse( void ( * )( int ), Catch::NameAndTags const& ) noexcept; }; } // namespace Detail } // namespace Catch @@ -7433,7 +7465,7 @@ namespace Catch { class ExceptionTranslatorRegistrar { template - class ExceptionTranslator : public IExceptionTranslator { + class ExceptionTranslator final : public IExceptionTranslator { public: constexpr ExceptionTranslator( std::string(*translateFunction)( T const& ) ) @@ -7537,7 +7569,7 @@ namespace Catch { #define CATCH_VERSION_MACROS_HPP_INCLUDED #define CATCH_VERSION_MAJOR 3 -#define CATCH_VERSION_MINOR 14 +#define CATCH_VERSION_MINOR 15 #define CATCH_VERSION_PATCH 0 #endif // CATCH_VERSION_MACROS_HPP_INCLUDED @@ -9842,34 +9874,6 @@ namespace Catch { #endif // CATCH_ENFORCE_HPP_INCLUDED -#ifndef CATCH_ENUM_VALUES_REGISTRY_HPP_INCLUDED -#define CATCH_ENUM_VALUES_REGISTRY_HPP_INCLUDED - - -#include - -namespace Catch { - - namespace Detail { - - Catch::Detail::unique_ptr makeEnumInfo( StringRef enumName, StringRef allValueNames, std::vector const& values ); - - class EnumValuesRegistry : public IMutableEnumValuesRegistry { - - std::vector> m_enumInfos; - - EnumInfo const& registerEnum( StringRef enumName, StringRef allValueNames, std::vector const& values) override; - }; - - std::vector parseEnums( StringRef enums ); - - } // Detail - -} // Catch - -#endif // CATCH_ENUM_VALUES_REGISTRY_HPP_INCLUDED - - #ifndef CATCH_ERRNO_GUARD_HPP_INCLUDED #define CATCH_ERRNO_GUARD_HPP_INCLUDED @@ -9900,7 +9904,7 @@ namespace Catch { namespace Catch { - class ExceptionTranslatorRegistry : public IExceptionTranslatorRegistry { + class ExceptionTranslatorRegistry final : public IExceptionTranslatorRegistry { public: ~ExceptionTranslatorRegistry() override; void registerTranslator( Detail::unique_ptr&& translator ); @@ -10952,8 +10956,6 @@ namespace Catch { void handleFatalErrorCondition( StringRef message ) override; - bool lastAssertionPassed() override; - public: // !TBD We need to do this another way! bool aborting() const; @@ -10975,7 +10977,7 @@ namespace Catch { ITransientExpression const *expr, bool negated ); - void populateReaction( AssertionReaction& reaction, bool has_normal_disposition ); + void populateReaction( AssertionReaction& reaction, bool has_normal_disposition ) const; // Creates dummy info for unexpected exceptions/fatal errors, // where we do not have the access to one, but we still need @@ -11067,7 +11069,7 @@ namespace Catch { template - class Singleton : SingletonImplT, public ISingleton { + class Singleton final : SingletonImplT, public ISingleton { static auto getInternal() -> Singleton* { static Singleton* s_instance = nullptr; @@ -11198,7 +11200,7 @@ namespace Catch { namespace Catch { struct SourceLineInfo; - class TagAliasRegistry : public ITagAliasRegistry { + class TagAliasRegistry final : public ITagAliasRegistry { public: ~TagAliasRegistry() override; TagAlias const* find( std::string const& alias ) const override; @@ -11258,7 +11260,7 @@ namespace Catch { std::vector filterTests( std::vector const& testCases, TestSpec const& testSpec, IConfig const& config ); std::vector const& getAllTestCasesSorted( IConfig const& config ); - class TestRegistry : public ITestCaseRegistry { + class TestRegistry final : public ITestCaseRegistry { public: void registerTest( Detail::unique_ptr testInfo, Detail::unique_ptr testInvoker ); @@ -11897,7 +11899,7 @@ namespace Catch { #endif template - class MatchExpr : public ITransientExpression { + class MatchExpr final : public ITransientExpression { ArgT && m_arg; MatcherT const& m_matcher; public: @@ -11984,10 +11986,10 @@ namespace Matchers { class MatcherUntypedBase { public: - MatcherUntypedBase() = default; + constexpr MatcherUntypedBase() = default; - MatcherUntypedBase(MatcherUntypedBase const&) = default; - MatcherUntypedBase(MatcherUntypedBase&&) = default; + constexpr MatcherUntypedBase(MatcherUntypedBase const&) = default; + constexpr MatcherUntypedBase(MatcherUntypedBase&&) = default; MatcherUntypedBase& operator = (MatcherUntypedBase const&) = delete; MatcherUntypedBase& operator = (MatcherUntypedBase&&) = delete; @@ -11995,9 +11997,9 @@ namespace Matchers { std::string toString() const; protected: - virtual ~MatcherUntypedBase(); // = default; - virtual std::string describe() const = 0; - mutable std::string m_cachedToString; + CATCH_DESTRUCTOR_CONSTEXPR virtual ~MatcherUntypedBase() = default; + //! Should be overridden, but we provide default "undescribed" impl + virtual std::string describe() const; }; @@ -12179,6 +12181,19 @@ namespace Matchers { #define CATCH_CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CATCH_CHECK_THAT", matcher, Catch::ResultDisposition::ContinueOnFailure, arg ) #define CATCH_REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CATCH_REQUIRE_THAT", matcher, Catch::ResultDisposition::Normal, arg ) + #if !defined(CATCH_CONFIG_RUNTIME_STATIC_REQUIRE) + #define CATCH_STATIC_REQUIRE_THAT( arg, matcher ) \ + static_assert( ( matcher ).match( arg ), #matcher ".match( " #arg " )"); \ + CATCH_SUCCEED( #matcher ".match( " #arg " )" ) + #define CATCH_STATIC_CHECK_THAT( arg, matcher ) \ + static_assert( ( matcher ).match( arg ), #matcher ".match( " #arg " )"); \ + CATCH_SUCCEED( #matcher ".match( " #arg " )" ) + #else + #define CATCH_STATIC_REQUIRE_THAT( arg, matcher ) CATCH_REQUIRE_THAT( arg, matcher ) + #define CATCH_STATIC_CHECK_THAT( arg, matcher ) CATCH_CHECK_THAT( arg, matcher ) + #endif + + #elif defined(CATCH_CONFIG_PREFIX_ALL) && defined(CATCH_CONFIG_DISABLE) #define CATCH_REQUIRE_THROWS_WITH( expr, matcher ) (void)(0) @@ -12190,6 +12205,9 @@ namespace Matchers { #define CATCH_CHECK_THAT( arg, matcher ) (void)(0) #define CATCH_REQUIRE_THAT( arg, matcher ) (void)(0) + #define CATCH_STATIC_REQUIRE_THAT( arg, matcher ) (void)(0) + #define CATCH_STATIC_CHECK_THAT( arg, matcher ) (void)(0) + #elif !defined(CATCH_CONFIG_PREFIX_ALL) && !defined(CATCH_CONFIG_DISABLE) #define REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "REQUIRE_THROWS_WITH", Catch::ResultDisposition::Normal, matcher, expr ) @@ -12201,6 +12219,19 @@ namespace Matchers { #define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CHECK_THAT", matcher, Catch::ResultDisposition::ContinueOnFailure, arg ) #define REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "REQUIRE_THAT", matcher, Catch::ResultDisposition::Normal, arg ) + #if !defined(CATCH_CONFIG_RUNTIME_STATIC_REQUIRE) + #define STATIC_REQUIRE_THAT( arg, matcher ) \ + static_assert( ( matcher ).match( arg ), #matcher ".match( " #arg " )"); \ + SUCCEED( #matcher ".match( " #arg " )" ) + #define STATIC_CHECK_THAT( arg, matcher ) \ + static_assert( ( matcher ).match( arg ), #matcher ".match( " #arg " )"); \ + SUCCEED( #matcher ".match( " #arg " )" ) + #else + #define STATIC_REQUIRE_THAT( arg, matcher ) REQUIRE_THAT( arg, matcher ) + #define STATIC_CHECK_THAT( arg, matcher ) CHECK_THAT( arg, matcher ) + #endif + + #elif !defined(CATCH_CONFIG_PREFIX_ALL) && defined(CATCH_CONFIG_DISABLE) #define REQUIRE_THROWS_WITH( expr, matcher ) (void)(0) @@ -12212,6 +12243,9 @@ namespace Matchers { #define CHECK_THAT( arg, matcher ) (void)(0) #define REQUIRE_THAT( arg, matcher ) (void)(0) + #define STATIC_REQUIRE_THAT( arg, matcher ) (void)(0) + #define STATIC_CHECK_THAT( arg, matcher ) (void)(0) + #endif // end of user facing macro declarations #endif // CATCH_MATCHERS_HPP_INCLUDED @@ -12234,12 +12268,12 @@ namespace Matchers { namespace Catch { namespace Matchers { class MatcherGenericBase : public MatcherUntypedBase { + std::string describe() const override; public: - MatcherGenericBase() = default; - ~MatcherGenericBase() override; // = default; + constexpr MatcherGenericBase() = default; - MatcherGenericBase(MatcherGenericBase const&) = default; - MatcherGenericBase(MatcherGenericBase&&) = default; + constexpr MatcherGenericBase(MatcherGenericBase const&) = default; + constexpr MatcherGenericBase(MatcherGenericBase&&) = default; MatcherGenericBase& operator=(MatcherGenericBase const&) = delete; MatcherGenericBase& operator=(MatcherGenericBase&&) = delete; @@ -12248,7 +12282,9 @@ namespace Matchers { namespace Detail { template - std::array array_cat(std::array && lhs, std::array && rhs) { + constexpr std::array + array_cat( std::array&& lhs, + std::array&& rhs ) { std::array arr{}; std::copy_n(lhs.begin(), N, arr.begin()); std::copy_n(rhs.begin(), M, arr.begin() + N); @@ -12256,7 +12292,8 @@ namespace Matchers { } template - std::array array_cat(std::array && lhs, void const* rhs) { + constexpr std::array + array_cat( std::array&& lhs, void const* rhs ) { std::array arr{}; std::copy_n(lhs.begin(), N, arr.begin()); arr[N] = rhs; @@ -12264,7 +12301,8 @@ namespace Matchers { } template - std::array array_cat(void const* lhs, std::array && rhs) { + constexpr std::array + array_cat( void const* lhs, std::array&& rhs ) { std::array arr{ {lhs} }; std::copy_n(rhs.begin(), N, arr.begin() + 1); return arr; @@ -12287,23 +12325,31 @@ namespace Matchers { template - bool match_all_of(Arg&&, std::array const&, std::index_sequence<>) { + constexpr bool match_all_of( Arg&&, + std::array const&, + std::index_sequence<> ) { return true; } template - bool match_all_of(Arg&& arg, std::array const& matchers, std::index_sequence) { + constexpr bool match_all_of( Arg&& arg, + std::array const& matchers, + std::index_sequence ) { return static_cast(matchers[Idx])->match(arg) && match_all_of(arg, matchers, std::index_sequence{}); } template - bool match_any_of(Arg&&, std::array const&, std::index_sequence<>) { + constexpr bool match_any_of( Arg&&, + std::array const&, + std::index_sequence<> ) { return false; } template - bool match_any_of(Arg&& arg, std::array const& matchers, std::index_sequence) { + constexpr bool match_any_of( Arg&& arg, + std::array const& matchers, + std::index_sequence ) { return static_cast(matchers[Idx])->match(arg) || match_any_of(arg, matchers, std::index_sequence{}); } @@ -12324,15 +12370,18 @@ namespace Matchers { public: MatchAllOfGeneric(MatchAllOfGeneric const&) = delete; MatchAllOfGeneric& operator=(MatchAllOfGeneric const&) = delete; - MatchAllOfGeneric(MatchAllOfGeneric&&) = default; - MatchAllOfGeneric& operator=(MatchAllOfGeneric&&) = default; + constexpr MatchAllOfGeneric( MatchAllOfGeneric&& ) = default; + constexpr MatchAllOfGeneric& operator=(MatchAllOfGeneric&&) = default; - MatchAllOfGeneric(MatcherTs const&... matchers CATCH_ATTR_LIFETIMEBOUND) + constexpr MatchAllOfGeneric( + MatcherTs const&... matchers CATCH_ATTR_LIFETIMEBOUND ) : m_matchers{ {std::addressof(matchers)...} } {} - explicit MatchAllOfGeneric(std::array matchers) : m_matchers{matchers} {} + constexpr explicit MatchAllOfGeneric( + std::array matchers ): + m_matchers{ matchers } {} template - bool match(Arg&& arg) const { + constexpr bool match( Arg&& arg ) const { return match_all_of(arg, m_matchers, std::index_sequence_for{}); } @@ -12348,7 +12397,7 @@ namespace Matchers { //! Avoids type nesting for `GenericAllOf && GenericAllOf` case template - friend + constexpr friend MatchAllOfGeneric operator && ( MatchAllOfGeneric&& lhs CATCH_ATTR_LIFETIMEBOUND, MatchAllOfGeneric&& rhs CATCH_ATTR_LIFETIMEBOUND ) { @@ -12357,7 +12406,8 @@ namespace Matchers { //! Avoids type nesting for `GenericAllOf && some matcher` case template - friend std::enable_if_t, + constexpr friend std::enable_if_t< + is_matcher_v, MatchAllOfGeneric> operator && ( MatchAllOfGeneric&& lhs CATCH_ATTR_LIFETIMEBOUND, MatcherRHS const& rhs CATCH_ATTR_LIFETIMEBOUND ) { @@ -12366,7 +12416,8 @@ namespace Matchers { //! Avoids type nesting for `some matcher && GenericAllOf` case template - friend std::enable_if_t, + constexpr friend std::enable_if_t< + is_matcher_v, MatchAllOfGeneric> operator && ( MatcherLHS const& lhs CATCH_ATTR_LIFETIMEBOUND, MatchAllOfGeneric&& rhs CATCH_ATTR_LIFETIMEBOUND ) { @@ -12380,15 +12431,18 @@ namespace Matchers { public: MatchAnyOfGeneric(MatchAnyOfGeneric const&) = delete; MatchAnyOfGeneric& operator=(MatchAnyOfGeneric const&) = delete; - MatchAnyOfGeneric(MatchAnyOfGeneric&&) = default; - MatchAnyOfGeneric& operator=(MatchAnyOfGeneric&&) = default; + constexpr MatchAnyOfGeneric( MatchAnyOfGeneric&& ) = default; + constexpr MatchAnyOfGeneric& operator=(MatchAnyOfGeneric&&) = default; - MatchAnyOfGeneric(MatcherTs const&... matchers CATCH_ATTR_LIFETIMEBOUND) + constexpr MatchAnyOfGeneric( + MatcherTs const&... matchers CATCH_ATTR_LIFETIMEBOUND ) : m_matchers{ {std::addressof(matchers)...} } {} - explicit MatchAnyOfGeneric(std::array matchers) : m_matchers{matchers} {} + constexpr explicit MatchAnyOfGeneric( + std::array matchers ): + m_matchers{ matchers } {} template - bool match(Arg&& arg) const { + constexpr bool match( Arg&& arg ) const { return match_any_of(arg, m_matchers, std::index_sequence_for{}); } @@ -12404,7 +12458,8 @@ namespace Matchers { //! Avoids type nesting for `GenericAnyOf || GenericAnyOf` case template - friend MatchAnyOfGeneric operator || ( + constexpr friend MatchAnyOfGeneric + operator||( MatchAnyOfGeneric&& lhs CATCH_ATTR_LIFETIMEBOUND, MatchAnyOfGeneric&& rhs CATCH_ATTR_LIFETIMEBOUND ) { return MatchAnyOfGeneric{array_cat(CATCH_MOVE(lhs.m_matchers), CATCH_MOVE(rhs.m_matchers))}; @@ -12412,7 +12467,8 @@ namespace Matchers { //! Avoids type nesting for `GenericAnyOf || some matcher` case template - friend std::enable_if_t, + constexpr friend std::enable_if_t< + is_matcher_v, MatchAnyOfGeneric> operator || ( MatchAnyOfGeneric&& lhs CATCH_ATTR_LIFETIMEBOUND, MatcherRHS const& rhs CATCH_ATTR_LIFETIMEBOUND ) { @@ -12421,7 +12477,8 @@ namespace Matchers { //! Avoids type nesting for `some matcher || GenericAnyOf` case template - friend std::enable_if_t, + constexpr friend std::enable_if_t< + is_matcher_v, MatchAnyOfGeneric> operator || ( MatcherLHS const& lhs CATCH_ATTR_LIFETIMEBOUND, MatchAnyOfGeneric&& rhs CATCH_ATTR_LIFETIMEBOUND) { @@ -12437,14 +12494,15 @@ namespace Matchers { public: MatchNotOfGeneric(MatchNotOfGeneric const&) = delete; MatchNotOfGeneric& operator=(MatchNotOfGeneric const&) = delete; - MatchNotOfGeneric(MatchNotOfGeneric&&) = default; - MatchNotOfGeneric& operator=(MatchNotOfGeneric&&) = default; + constexpr MatchNotOfGeneric( MatchNotOfGeneric&& ) = default; + constexpr MatchNotOfGeneric& operator=(MatchNotOfGeneric&&) = default; - explicit MatchNotOfGeneric(MatcherT const& matcher CATCH_ATTR_LIFETIMEBOUND) + constexpr explicit MatchNotOfGeneric( + MatcherT const& matcher CATCH_ATTR_LIFETIMEBOUND ) : m_matcher{matcher} {} template - bool match(Arg&& arg) const { + constexpr bool match( Arg&& arg ) const { return !m_matcher.match(arg); } @@ -12453,7 +12511,7 @@ namespace Matchers { } //! Negating negation can just unwrap and return underlying matcher - friend MatcherT const& + constexpr friend MatcherT const& operator!( MatchNotOfGeneric const& matcher CATCH_ATTR_LIFETIMEBOUND ) { return matcher.m_matcher; @@ -12464,14 +12522,18 @@ namespace Matchers { // compose only generic matchers template - std::enable_if_t, Detail::MatchAllOfGeneric> + constexpr std::enable_if_t< + Detail::are_generic_matchers_v, + Detail::MatchAllOfGeneric> operator&&( MatcherLHS const& lhs CATCH_ATTR_LIFETIMEBOUND, MatcherRHS const& rhs CATCH_ATTR_LIFETIMEBOUND ) { return { lhs, rhs }; } template - std::enable_if_t, Detail::MatchAnyOfGeneric> + constexpr std::enable_if_t< + Detail::are_generic_matchers_v, + Detail::MatchAnyOfGeneric> operator||( MatcherLHS const& lhs CATCH_ATTR_LIFETIMEBOUND, MatcherRHS const& rhs CATCH_ATTR_LIFETIMEBOUND ) { return { lhs, rhs }; @@ -12479,7 +12541,8 @@ namespace Matchers { //! Wrap provided generic matcher in generic negator template - std::enable_if_t, Detail::MatchNotOfGeneric> + constexpr std::enable_if_t, + Detail::MatchNotOfGeneric> operator!( MatcherT const& matcher CATCH_ATTR_LIFETIMEBOUND ) { return Detail::MatchNotOfGeneric{matcher}; } @@ -12525,7 +12588,7 @@ namespace Catch { class IsEmptyMatcher final : public MatcherGenericBase { public: template - bool match(RangeLike&& rng) const { + constexpr bool match(RangeLike&& rng) const { #if defined(CATCH_CONFIG_POLYFILL_NONMEMBER_CONTAINER_ACCESS) using Catch::Detail::empty; #else @@ -12540,12 +12603,12 @@ namespace Catch { class HasSizeMatcher final : public MatcherGenericBase { std::size_t m_target_size; public: - explicit HasSizeMatcher(std::size_t target_size): + constexpr explicit HasSizeMatcher(std::size_t target_size): m_target_size(target_size) {} template - bool match(RangeLike&& rng) const { + constexpr bool match(RangeLike&& rng) const { #if defined(CATCH_CONFIG_POLYFILL_NONMEMBER_CONTAINER_ACCESS) using Catch::Detail::size; #else @@ -12561,12 +12624,12 @@ namespace Catch { class SizeMatchesMatcher final : public MatcherGenericBase { Matcher m_matcher; public: - explicit SizeMatchesMatcher(Matcher m): + constexpr explicit SizeMatchesMatcher(Matcher m): m_matcher(CATCH_MOVE(m)) {} template - bool match(RangeLike&& rng) const { + constexpr bool match(RangeLike&& rng) const { #if defined(CATCH_CONFIG_POLYFILL_NONMEMBER_CONTAINER_ACCESS) using Catch::Detail::size; #else @@ -12582,11 +12645,13 @@ namespace Catch { //! Creates a matcher that accepts empty ranges/containers - IsEmptyMatcher IsEmpty(); + inline CATCH_DESTRUCTOR_CONSTEXPR IsEmptyMatcher IsEmpty() { return {}; } //! Creates a matcher that accepts ranges/containers with specific size - HasSizeMatcher SizeIs(std::size_t sz); + inline CATCH_DESTRUCTOR_CONSTEXPR HasSizeMatcher SizeIs( std::size_t sz ) { + return HasSizeMatcher{ sz }; + } template - std::enable_if_t, + constexpr std::enable_if_t, SizeMatchesMatcher> SizeIs(Matcher&& m) { return SizeMatchesMatcher{CATCH_FORWARD(m)}; } @@ -12613,7 +12678,7 @@ namespace Catch { Equality m_eq; public: template - ContainsElementMatcher(T2&& target, Equality2&& predicate): + constexpr ContainsElementMatcher(T2&& target, Equality2&& predicate): m_desired(CATCH_FORWARD(target)), m_eq(CATCH_FORWARD(predicate)) {} @@ -12623,7 +12688,7 @@ namespace Catch { } template - bool match( RangeLike&& rng ) const { + constexpr bool match( RangeLike&& rng ) const { for ( auto&& elem : rng ) { if ( m_eq( elem, m_desired ) ) { return true; } } @@ -12639,12 +12704,12 @@ namespace Catch { // Note that we do a copy+move to avoid having to SFINAE this // constructor (and also avoid some perfect forwarding failure // cases) - ContainsMatcherMatcher(Matcher matcher): + constexpr ContainsMatcherMatcher(Matcher matcher): m_matcher(CATCH_MOVE(matcher)) {} template - bool match(RangeLike&& rng) const { + constexpr bool match(RangeLike&& rng) const { for (auto&& elem : rng) { if (m_matcher.match(elem)) { return true; @@ -12664,14 +12729,14 @@ namespace Catch { * Uses `std::equal_to` to do the comparison */ template - std::enable_if_t, + constexpr std::enable_if_t, ContainsElementMatcher>> Contains(T&& elem) { return { CATCH_FORWARD(elem), std::equal_to<>{} }; } //! Creates a matcher that checks whether a range contains element matching a matcher template - std::enable_if_t, + constexpr std::enable_if_t, ContainsMatcherMatcher> Contains(Matcher&& matcher) { return { CATCH_FORWARD(matcher) }; } @@ -12682,7 +12747,7 @@ namespace Catch { * Uses `eq` to do the comparisons, the element is provided on the rhs */ template - ContainsElementMatcher Contains(T&& elem, Equality&& eq) { + constexpr ContainsElementMatcher Contains(T&& elem, Equality&& eq) { return { CATCH_FORWARD(elem), CATCH_FORWARD(eq) }; } @@ -12897,7 +12962,7 @@ namespace Catch { class AllMatchMatcher final : public MatcherGenericBase { Matcher m_matcher; public: - AllMatchMatcher(Matcher matcher): + constexpr AllMatchMatcher(Matcher matcher): m_matcher(CATCH_MOVE(matcher)) {} @@ -12906,7 +12971,7 @@ namespace Catch { } template - bool match(RangeLike&& rng) const { + constexpr bool match(RangeLike&& rng) const { for (auto&& elem : rng) { if (!m_matcher.match(elem)) { return false; @@ -12921,7 +12986,7 @@ namespace Catch { class NoneMatchMatcher final : public MatcherGenericBase { Matcher m_matcher; public: - NoneMatchMatcher(Matcher matcher): + constexpr NoneMatchMatcher(Matcher matcher): m_matcher(CATCH_MOVE(matcher)) {} @@ -12930,7 +12995,7 @@ namespace Catch { } template - bool match(RangeLike&& rng) const { + constexpr bool match(RangeLike&& rng) const { for (auto&& elem : rng) { if (m_matcher.match(elem)) { return false; @@ -12945,7 +13010,7 @@ namespace Catch { class AnyMatchMatcher final : public MatcherGenericBase { Matcher m_matcher; public: - AnyMatchMatcher(Matcher matcher): + constexpr AnyMatchMatcher(Matcher matcher): m_matcher(CATCH_MOVE(matcher)) {} @@ -12954,7 +13019,7 @@ namespace Catch { } template - bool match(RangeLike&& rng) const { + constexpr bool match(RangeLike&& rng) const { for (auto&& elem : rng) { if (m_matcher.match(elem)) { return true; @@ -12970,7 +13035,7 @@ namespace Catch { std::string describe() const override; template - bool match(RangeLike&& rng) const { + constexpr bool match(RangeLike&& rng) const { for (auto&& elem : rng) { if (!elem) { return false; @@ -12986,7 +13051,7 @@ namespace Catch { std::string describe() const override; template - bool match(RangeLike&& rng) const { + constexpr bool match(RangeLike&& rng) const { for (auto&& elem : rng) { if (elem) { return false; @@ -13002,7 +13067,7 @@ namespace Catch { std::string describe() const override; template - bool match(RangeLike&& rng) const { + constexpr bool match(RangeLike&& rng) const { for (auto&& elem : rng) { if (elem) { return true; @@ -13012,32 +13077,35 @@ namespace Catch { } }; - // Creates a matcher that checks whether all elements in a range match a matcher + //! Creates a matcher that checks whether all elements in a range match a matcher template - AllMatchMatcher AllMatch(Matcher&& matcher) { + constexpr AllMatchMatcher AllMatch(Matcher&& matcher) { return { CATCH_FORWARD(matcher) }; } - // Creates a matcher that checks whether no element in a range matches a matcher. + //! Creates a matcher that checks whether no element in a range matches a matcher. template - NoneMatchMatcher NoneMatch(Matcher&& matcher) { + constexpr NoneMatchMatcher NoneMatch(Matcher&& matcher) { return { CATCH_FORWARD(matcher) }; } - // Creates a matcher that checks whether any element in a range matches a matcher. + //! Creates a matcher that checks whether any element in a range matches a matcher. template - AnyMatchMatcher AnyMatch(Matcher&& matcher) { + constexpr AnyMatchMatcher AnyMatch(Matcher&& matcher) { return { CATCH_FORWARD(matcher) }; } - // Creates a matcher that checks whether all elements in a range are true - AllTrueMatcher AllTrue(); + //! Creates a matcher that checks whether all elements in a range are true + inline CATCH_DESTRUCTOR_CONSTEXPR + AllTrueMatcher AllTrue() { return AllTrueMatcher{}; } - // Creates a matcher that checks whether no element in a range is true - NoneTrueMatcher NoneTrue(); + //! Creates a matcher that checks whether no element in a range is true + inline CATCH_DESTRUCTOR_CONSTEXPR + NoneTrueMatcher NoneTrue() { return NoneTrueMatcher{}; } - // Creates a matcher that checks whether any element in a range is true - AnyTrueMatcher AnyTrue(); + //! Creates a matcher that checks whether any element in a range is true + inline CATCH_DESTRUCTOR_CONSTEXPR + AnyTrueMatcher AnyTrue() { return AnyTrueMatcher{}; } } } diff --git a/meson.build b/meson.build index 1b315e17..2e390b52 100644 --- a/meson.build +++ b/meson.build @@ -8,7 +8,7 @@ project( 'catch2', 'cpp', - version: '3.14.0', # CML version placeholder, don't delete + version: '3.15.0', # CML version placeholder, don't delete license: 'BSL-1.0', meson_version: '>=0.54.1', ) diff --git a/src/catch2/catch_version.cpp b/src/catch2/catch_version.cpp index 403db2eb..eb385fe2 100644 --- a/src/catch2/catch_version.cpp +++ b/src/catch2/catch_version.cpp @@ -36,7 +36,7 @@ namespace Catch { } Version const& libraryVersion() { - static Version version( 3, 14, 0, "", 0 ); + static Version version( 3, 15, 0, "", 0 ); return version; } diff --git a/src/catch2/catch_version_macros.hpp b/src/catch2/catch_version_macros.hpp index 4b288c60..41fc51af 100644 --- a/src/catch2/catch_version_macros.hpp +++ b/src/catch2/catch_version_macros.hpp @@ -9,7 +9,7 @@ #define CATCH_VERSION_MACROS_HPP_INCLUDED #define CATCH_VERSION_MAJOR 3 -#define CATCH_VERSION_MINOR 14 +#define CATCH_VERSION_MINOR 15 #define CATCH_VERSION_PATCH 0 #endif // CATCH_VERSION_MACROS_HPP_INCLUDED