[upstream_utils] Update catch2 to 3.15.0 (#8955)

This commit is contained in:
Peter Johnson
2026-06-05 20:34:20 -07:00
committed by GitHub
parent 96fb033deb
commit 88d8369751
48 changed files with 363 additions and 320 deletions

View File

@@ -14,7 +14,7 @@
namespace Catch { namespace Catch {
namespace Benchmark { namespace Benchmark {
namespace Detail { namespace Detail {
struct optimized_away_error : std::exception { struct optimized_away_error final : std::exception {
const char* what() const noexcept override; const char* what() const noexcept override;
}; };

View File

@@ -5,8 +5,8 @@
// https://www.boost.org/LICENSE_1_0.txt) // https://www.boost.org/LICENSE_1_0.txt)
// SPDX-License-Identifier: BSL-1.0 // SPDX-License-Identifier: BSL-1.0
#include <catch2/catch_message.hpp> #include <catch2/catch_message.hpp>
#include <catch2/interfaces/catch_interfaces_capture.hpp>
#include <catch2/internal/catch_enforce.hpp> #include <catch2/internal/catch_enforce.hpp>
#include <catch2/internal/catch_move_and_forward.hpp> #include <catch2/internal/catch_move_and_forward.hpp>
@@ -22,7 +22,7 @@ namespace Catch {
m_messageId( builder.m_info.sequence ) { m_messageId( builder.m_info.sequence ) {
MessageInfo info( CATCH_MOVE( builder.m_info ) ); MessageInfo info( CATCH_MOVE( builder.m_info ) );
info.message = builder.m_stream.str(); info.message = builder.m_stream.str();
IResultCapture::pushScopedMessage( CATCH_MOVE( info ) ); Detail::pushScopedMessage( CATCH_MOVE( info ) );
} }
ScopedMessage::ScopedMessage( ScopedMessage&& old ) noexcept: ScopedMessage::ScopedMessage( ScopedMessage&& old ) noexcept:
@@ -31,7 +31,7 @@ namespace Catch {
} }
ScopedMessage::~ScopedMessage() { ScopedMessage::~ScopedMessage() {
if ( !m_moved ) { IResultCapture::popScopedMessage( m_messageId ); } if ( !m_moved ) { Detail::popScopedMessage( m_messageId ); }
} }
@@ -103,7 +103,7 @@ namespace Catch {
assert( m_captured == m_messages.size() ); assert( m_captured == m_messages.size() );
if ( m_isScoped ) { if ( m_isScoped ) {
for ( auto const& message : m_messages ) { for ( auto const& message : m_messages ) {
IResultCapture::popScopedMessage( message.sequence ); Detail::popScopedMessage( message.sequence );
} }
} }
} }
@@ -112,9 +112,9 @@ namespace Catch {
assert( index < m_messages.size() ); assert( index < m_messages.size() );
m_messages[index].message += value; m_messages[index].message += value;
if ( m_isScoped ) { if ( m_isScoped ) {
IResultCapture::pushScopedMessage( CATCH_MOVE( m_messages[index] ) ); Detail::pushScopedMessage( CATCH_MOVE( m_messages[index] ) );
} else { } else {
IResultCapture::addUnscopedMessage( CATCH_MOVE( m_messages[index] ) ); Detail::addUnscopedMessage( CATCH_MOVE( m_messages[index] ) );
} }
m_captured++; m_captured++;
} }

View File

@@ -15,7 +15,6 @@
#include <catch2/internal/catch_tag_alias_registry.hpp> #include <catch2/internal/catch_tag_alias_registry.hpp>
#include <catch2/internal/catch_startup_exception_registry.hpp> #include <catch2/internal/catch_startup_exception_registry.hpp>
#include <catch2/internal/catch_singletons.hpp> #include <catch2/internal/catch_singletons.hpp>
#include <catch2/internal/catch_enum_values_registry.hpp>
#include <catch2/catch_test_case_info.hpp> #include <catch2/catch_test_case_info.hpp>
#include <catch2/internal/catch_noncopyable.hpp> #include <catch2/internal/catch_noncopyable.hpp>
#include <catch2/interfaces/catch_interfaces_reporter_factory.hpp> #include <catch2/interfaces/catch_interfaces_reporter_factory.hpp>
@@ -72,9 +71,6 @@ namespace Catch {
CATCH_INTERNAL_ERROR("Attempted to register active exception under CATCH_CONFIG_DISABLE_EXCEPTIONS!"); CATCH_INTERNAL_ERROR("Attempted to register active exception under CATCH_CONFIG_DISABLE_EXCEPTIONS!");
#endif #endif
} }
IMutableEnumValuesRegistry& getMutableEnumValuesRegistry() override {
return m_enumValuesRegistry;
}
private: private:
TestRegistry m_testCaseRegistry; TestRegistry m_testCaseRegistry;
@@ -82,7 +78,6 @@ namespace Catch {
ExceptionTranslatorRegistry m_exceptionTranslatorRegistry; ExceptionTranslatorRegistry m_exceptionTranslatorRegistry;
TagAliasRegistry m_tagAliasRegistry; TagAliasRegistry m_tagAliasRegistry;
StartupExceptionRegistry m_exceptionRegistry; StartupExceptionRegistry m_exceptionRegistry;
Detail::EnumValuesRegistry m_enumValuesRegistry;
}; };
} }

View File

@@ -21,6 +21,7 @@
#include <catch2/reporters/catch_reporter_multi.hpp> #include <catch2/reporters/catch_reporter_multi.hpp>
#include <catch2/internal/catch_reporter_registry.hpp> #include <catch2/internal/catch_reporter_registry.hpp>
#include <catch2/interfaces/catch_interfaces_reporter_factory.hpp> #include <catch2/interfaces/catch_interfaces_reporter_factory.hpp>
#include <catch2/interfaces/catch_interfaces_registry_hub.hpp>
#include <catch2/internal/catch_move_and_forward.hpp> #include <catch2/internal/catch_move_and_forward.hpp>
#include <catch2/internal/catch_stdstreams.hpp> #include <catch2/internal/catch_stdstreams.hpp>
#include <catch2/internal/catch_istream.hpp> #include <catch2/internal/catch_istream.hpp>

View File

@@ -36,7 +36,7 @@ namespace Catch {
} }
Version const& libraryVersion() { Version const& libraryVersion() {
static Version version( 3, 14, 0, "", 0 ); static Version version( 3, 15, 0, "", 0 );
return version; return version;
} }

View File

@@ -6,21 +6,28 @@
// SPDX-License-Identifier: BSL-1.0 // SPDX-License-Identifier: BSL-1.0
#include <catch2/internal/catch_assertion_handler.hpp> #include <catch2/internal/catch_assertion_handler.hpp>
#include <catch2/interfaces/catch_interfaces_capture.hpp>
#include <catch2/interfaces/catch_interfaces_config.hpp> #include <catch2/interfaces/catch_interfaces_config.hpp>
#include <catch2/interfaces/catch_interfaces_registry_hub.hpp>
#include <catch2/internal/catch_context.hpp> #include <catch2/internal/catch_context.hpp>
#include <catch2/internal/catch_debugger.hpp> #include <catch2/internal/catch_debugger.hpp>
#include <catch2/internal/catch_run_context.hpp>
#include <catch2/internal/catch_test_failure_exception.hpp> #include <catch2/internal/catch_test_failure_exception.hpp>
#include <catch2/matchers/catch_matchers_string.hpp> #include <catch2/matchers/catch_matchers_string.hpp>
namespace Catch { namespace Catch {
void AssertionHandler::finishIncomplete() {
m_resultCapture.handleIncomplete( m_assertionInfo );
}
AssertionHandler::AssertionHandler AssertionHandler::AssertionHandler
( StringRef macroName, ( StringRef macroName,
SourceLineInfo const& lineInfo, SourceLineInfo const& lineInfo,
StringRef capturedExpression, StringRef capturedExpression,
ResultDisposition::Flags resultDisposition ) ResultDisposition::Flags resultDisposition )
: m_assertionInfo{ macroName, lineInfo, capturedExpression, resultDisposition }, : m_assertionInfo{ macroName, lineInfo, capturedExpression, resultDisposition },
m_resultCapture( getResultCapture() ) m_resultCapture( static_cast<RunContext&>(getResultCapture()) )
{ {
m_resultCapture.notifyAssertionStarted( m_assertionInfo ); m_resultCapture.notifyAssertionStarted( m_assertionInfo );
} }

View File

@@ -5,15 +5,14 @@
// https://www.boost.org/LICENSE_1_0.txt) // https://www.boost.org/LICENSE_1_0.txt)
// SPDX-License-Identifier: BSL-1.0 // SPDX-License-Identifier: BSL-1.0
#include <catch2/internal/catch_enum_values_registry.hpp>
#include <catch2/internal/catch_enum_info.hpp>
#include <catch2/internal/catch_string_manip.hpp> #include <catch2/internal/catch_string_manip.hpp>
#include <cassert> #include <cassert>
namespace Catch { namespace Catch {
IMutableEnumValuesRegistry::~IMutableEnumValuesRegistry() = default;
namespace Detail { namespace Detail {
namespace { namespace {
@@ -39,9 +38,7 @@ namespace Catch {
return parsed; return parsed;
} }
EnumInfo::~EnumInfo() = default; StringRef EnumInfo::lookup( int64_t value ) const {
StringRef EnumInfo::lookup( int value ) const {
for( auto const& valueToName : m_values ) { for( auto const& valueToName : m_values ) {
if( valueToName.first == value ) if( valueToName.first == value )
return valueToName.second; return valueToName.second;
@@ -49,23 +46,18 @@ namespace Catch {
return "{** unexpected enum value **}"_sr; return "{** unexpected enum value **}"_sr;
} }
Catch::Detail::unique_ptr<EnumInfo> makeEnumInfo( StringRef enumName, StringRef allValueNames, std::vector<int> const& values ) { EnumInfo makeEnumInfo( StringRef enumName, StringRef allValueNames, std::vector<int64_t> const& values ) {
auto enumInfo = Catch::Detail::make_unique<EnumInfo>(); EnumInfo enumInfo;
enumInfo->m_name = enumName; enumInfo.m_name = enumName;
enumInfo->m_values.reserve( values.size() ); enumInfo.m_values.reserve( values.size() );
const auto valueNames = Catch::Detail::parseEnums( allValueNames ); const auto valueNames = Catch::Detail::parseEnums( allValueNames );
assert( valueNames.size() == values.size() ); assert( valueNames.size() == values.size() );
std::size_t i = 0; for (size_t i = 0; i < values.size(); ++i) {
for( auto value : values ) enumInfo.m_values.emplace_back( values[i], valueNames[i] );
enumInfo->m_values.emplace_back(value, valueNames[i++]);
return enumInfo;
} }
EnumInfo const& EnumValuesRegistry::registerEnum( StringRef enumName, StringRef allValueNames, std::vector<int> const& values ) { return enumInfo;
m_enumInfos.push_back(makeEnumInfo(enumName, allValueNames, values));
return *m_enumInfos.back();
} }
} // Detail } // Detail

View File

@@ -33,7 +33,7 @@ namespace Catch {
namespace { namespace {
//! A no-op implementation, used if no reporter wants output //! A no-op implementation, used if no reporter wants output
//! redirection. //! redirection.
class NoopRedirect : public OutputRedirect { class NoopRedirect final : public OutputRedirect {
void activateImpl() override {} void activateImpl() override {}
void deactivateImpl() override {} void deactivateImpl() override {}
std::string getStdout() override { return {}; } std::string getStdout() override { return {}; }
@@ -70,7 +70,7 @@ namespace Catch {
* Redirects the `std::cout`, `std::cerr`, `std::clog` streams, * Redirects the `std::cout`, `std::cerr`, `std::clog` streams,
* but does not touch the actual `stdout`/`stderr` file descriptors. * but does not touch the actual `stdout`/`stderr` file descriptors.
*/ */
class StreamRedirect : public OutputRedirect { class StreamRedirect final : public OutputRedirect {
ReusableStringStream m_redirectedOut, m_redirectedErr; ReusableStringStream m_redirectedOut, m_redirectedErr;
RedirectedStreamNew m_cout, m_cerr, m_clog; RedirectedStreamNew m_cout, m_cerr, m_clog;
@@ -181,7 +181,7 @@ namespace Catch {
* Works by replacing the file descriptors numbered 1 and 2 * Works by replacing the file descriptors numbered 1 and 2
* with an open temporary file. * with an open temporary file.
*/ */
class FileRedirect : public OutputRedirect { class FileRedirect final : public OutputRedirect {
TempFile m_outFile, m_errFile; TempFile m_outFile, m_errFile;
int m_originalOut = -1; int m_originalOut = -1;
int m_originalErr = -1; int m_originalErr = -1;

View File

@@ -11,6 +11,7 @@
#include <catch2/generators/catch_generators_throw.hpp> #include <catch2/generators/catch_generators_throw.hpp>
#include <catch2/interfaces/catch_interfaces_config.hpp> #include <catch2/interfaces/catch_interfaces_config.hpp>
#include <catch2/interfaces/catch_interfaces_generatortracker.hpp> #include <catch2/interfaces/catch_interfaces_generatortracker.hpp>
#include <catch2/interfaces/catch_interfaces_registry_hub.hpp>
#include <catch2/interfaces/catch_interfaces_reporter.hpp> #include <catch2/interfaces/catch_interfaces_reporter.hpp>
#include <catch2/internal/catch_compiler_capabilities.hpp> #include <catch2/internal/catch_compiler_capabilities.hpp>
#include <catch2/internal/catch_context.hpp> #include <catch2/internal/catch_context.hpp>
@@ -308,6 +309,25 @@ namespace Catch {
} }
CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION 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 } // namespace Detail
RunContext::RunContext(IConfig const* _config, IEventListenerPtr&& reporter) RunContext::RunContext(IConfig const* _config, IEventListenerPtr&& reporter)
@@ -441,14 +461,13 @@ namespace Catch {
Detail::g_lastAssertionPassed = true; Detail::g_lastAssertionPassed = true;
} else if (!result.succeeded()) { } else if (!result.succeeded()) {
Detail::g_lastAssertionPassed = false; Detail::g_lastAssertionPassed = false;
if (result.isOk()) { if (result.isOk()) {}
} else if( m_activeTestCase->getTestCaseInfo().okToFail() ) { // Read from a shared state established before the threads could start, this is fine
else if( m_activeTestCase->getTestCaseInfo().okToFail() ) // Read from a shared state established before the threads could start, this is fine
m_atomicAssertionCount.failedButOk++; m_atomicAssertionCount.failedButOk++;
else } else {
m_atomicAssertionCount.failed++; m_atomicAssertionCount.failed++;
} }
else { } else {
Detail::g_lastAssertionPassed = true; Detail::g_lastAssertionPassed = true;
} }
@@ -630,7 +649,7 @@ namespace Catch {
// and since IResultCapture::getLastResult is deprecated, // and since IResultCapture::getLastResult is deprecated,
// we will leave it as is, until it is finally removed. // we will leave it as is, until it is finally removed.
Detail::LockGuard _( m_assertionMutex ); Detail::LockGuard _( m_assertionMutex );
return &(*m_lastResult); return &*m_lastResult;
} }
void RunContext::exceptionEarlyReported() { void RunContext::exceptionEarlyReported() {
@@ -704,10 +723,6 @@ namespace Catch {
m_reporter->testRunEnded(TestRunStats(m_runInfo, m_totals, false)); m_reporter->testRunEnded(TestRunStats(m_runInfo, m_totals, false));
} }
bool RunContext::lastAssertionPassed() {
return Detail::g_lastAssertionPassed;
}
void RunContext::assertionPassedFastPath(SourceLineInfo lineInfo) { void RunContext::assertionPassedFastPath(SourceLineInfo lineInfo) {
// We want to save the line info for better experience with unexpected assertions // We want to save the line info for better experience with unexpected assertions
Detail::g_lastKnownLineInfo = lineInfo; Detail::g_lastKnownLineInfo = lineInfo;
@@ -886,7 +901,7 @@ namespace Catch {
} }
void RunContext::populateReaction( AssertionReaction& reaction, void RunContext::populateReaction( AssertionReaction& reaction,
bool has_normal_disposition ) { bool has_normal_disposition ) const {
reaction.shouldDebugBreak = m_shouldDebugBreak; reaction.shouldDebugBreak = m_shouldDebugBreak;
reaction.shouldThrow = aborting() || has_normal_disposition; reaction.shouldThrow = aborting() || has_normal_disposition;
} }
@@ -937,22 +952,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) { void seedRng(IConfig const& config) {
sharedRng().seed(config.rngSeed()); sharedRng().seed(config.rngSeed());
} }

View File

@@ -16,11 +16,12 @@ namespace Catch {
TagAlias const* TagAliasRegistry::find( std::string const& alias ) const { TagAlias const* TagAliasRegistry::find( std::string const& alias ) const {
auto it = m_registry.find( alias ); auto it = m_registry.find( alias );
if( it != m_registry.end() ) if ( it != m_registry.end() ) {
return &(it->second); return &it->second;
else } else {
return nullptr; return nullptr;
} }
}
std::string TagAliasRegistry::expandAliases( std::string const& unexpandedTestSpec ) const { std::string TagAliasRegistry::expandAliases( std::string const& unexpandedTestSpec ) const {
std::string expandedTestSpec = unexpandedTestSpec; std::string expandedTestSpec = unexpandedTestSpec;

View File

@@ -14,7 +14,7 @@ namespace Catch {
void throw_test_failure_exception() { void throw_test_failure_exception() {
#if !defined( CATCH_CONFIG_DISABLE_EXCEPTIONS ) #if !defined( CATCH_CONFIG_DISABLE_EXCEPTIONS )
throw TestFailureException{}; throw TestFailureException{}; //NOLINT(bugprone-std-exception-baseclass)
#else #else
CATCH_ERROR( "Test failure requires aborting test!" ); CATCH_ERROR( "Test failure requires aborting test!" );
#endif #endif
@@ -22,7 +22,7 @@ namespace Catch {
void throw_test_skip_exception() { void throw_test_skip_exception() {
#if !defined( CATCH_CONFIG_DISABLE_EXCEPTIONS ) #if !defined( CATCH_CONFIG_DISABLE_EXCEPTIONS )
throw Catch::TestSkipException(); throw Catch::TestSkipException(); //NOLINT(bugprone-std-exception-baseclass)
#else #else
CATCH_ERROR( "Explicitly skipping tests during runtime requires exceptions" ); CATCH_ERROR( "Explicitly skipping tests during runtime requires exceptions" );
#endif #endif

View File

@@ -13,13 +13,13 @@ namespace Catch {
namespace Matchers { namespace Matchers {
std::string MatcherUntypedBase::toString() const { std::string MatcherUntypedBase::toString() const {
if (m_cachedToString.empty()) { return describe();
m_cachedToString = describe();
}
return m_cachedToString;
} }
MatcherUntypedBase::~MatcherUntypedBase() = default; std::string MatcherUntypedBase::describe() const {
using namespace std::string_literals;
return "Undescribed matcher"s;
}
} // namespace Matchers } // namespace Matchers
} // namespace Catch } // namespace Catch

View File

@@ -22,13 +22,5 @@ namespace Matchers {
return sstr.str(); return sstr.str();
} }
IsEmptyMatcher IsEmpty() {
return {};
}
HasSizeMatcher SizeIs(std::size_t sz) {
return HasSizeMatcher{ sz };
}
} // end namespace Matchers } // end namespace Matchers
} // end namespace Catch } // end namespace Catch

View File

@@ -9,16 +9,12 @@
namespace Catch { namespace Catch {
namespace Matchers { 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"; } std::string NoneTrueMatcher::describe() const { return "contains no true"; }
NoneTrueMatcher NoneTrue() { return NoneTrueMatcher{}; }
std::string AnyTrueMatcher::describe() const { return "contains at least one true"; } std::string AnyTrueMatcher::describe() const { return "contains at least one true"; }
AnyTrueMatcher AnyTrue() { return AnyTrueMatcher{}; }
} // namespace Matchers } // namespace Matchers
} // namespace Catch } // namespace Catch

View File

@@ -9,7 +9,11 @@
namespace Catch { namespace Catch {
namespace Matchers { namespace Matchers {
MatcherGenericBase::~MatcherGenericBase() = default;
std::string MatcherGenericBase::describe() const {
using namespace std::string_literals;
return "Undescribed generic matcher"s;
}
namespace Detail { namespace Detail {

View File

@@ -20,9 +20,8 @@ namespace Catch {
bool operator()( bool operator()(
Detail::unique_ptr<CumulativeReporterBase::SectionNode> const& Detail::unique_ptr<CumulativeReporterBase::SectionNode> const&
node ) const { node ) const {
return ( return node->stats.sectionInfo.name == m_other.name
( node->stats.sectionInfo.name == m_other.name ) && && node->stats.sectionInfo.lineInfo == m_other.lineInfo;
( node->stats.sectionInfo.lineInfo == m_other.lineInfo ) );
} }
void operator=( BySectionInfo const& ) = delete; void operator=( BySectionInfo const& ) = delete;

View File

@@ -199,7 +199,7 @@ namespace Catch {
} }
// minimum whitespace to pad tag counts, possibly overwritten below // minimum whitespace to pad tag counts, possibly overwritten below
size_t maxTagCountLen = 2; int maxTagCountLen = 2;
// determine necessary padding for tag count column // determine necessary padding for tag count column
if ( ! tags.empty() ) { if ( ! tags.empty() ) {
@@ -214,7 +214,7 @@ namespace Catch {
// more padding necessary for 3+ digits // more padding necessary for 3+ digits
if (maxTagCount >= 100) { if (maxTagCount >= 100) {
auto numDigits = 1 + std::floor( std::log10( maxTagCount ) ); auto numDigits = 1 + std::floor( std::log10( maxTagCount ) );
maxTagCountLen = static_cast<size_t>( numDigits ); maxTagCountLen = static_cast<int>( numDigits );
} }
} }

View File

@@ -41,7 +41,7 @@ namespace Catch {
callable& operator=(callable&&) = default; callable& operator=(callable&&) = default;
}; };
template <typename Fun> template <typename Fun>
struct model : public callable { struct model final : public callable {
model(Fun&& fun_) : fun(CATCH_MOVE(fun_)) {} model(Fun&& fun_) : fun(CATCH_MOVE(fun_)) {}
model(Fun const& fun_) : fun(fun_) {} model(Fun const& fun_) : fun(fun_) {}

View File

@@ -68,7 +68,7 @@
#include <catch2/internal/catch_decomposer.hpp> #include <catch2/internal/catch_decomposer.hpp>
#include <catch2/internal/catch_deprecation_macro.hpp> #include <catch2/internal/catch_deprecation_macro.hpp>
#include <catch2/internal/catch_enforce.hpp> #include <catch2/internal/catch_enforce.hpp>
#include <catch2/internal/catch_enum_values_registry.hpp> #include <catch2/internal/catch_enum_info.hpp>
#include <catch2/internal/catch_errno_guard.hpp> #include <catch2/internal/catch_errno_guard.hpp>
#include <catch2/internal/catch_exception_translator_registry.hpp> #include <catch2/internal/catch_exception_translator_registry.hpp>
#include <catch2/internal/catch_fatal_condition_handler.hpp> #include <catch2/internal/catch_fatal_condition_handler.hpp>

View File

@@ -13,16 +13,28 @@
#include <catch2/internal/catch_reusable_string_stream.hpp> #include <catch2/internal/catch_reusable_string_stream.hpp>
#include <catch2/internal/catch_stream_end_stop.hpp> #include <catch2/internal/catch_stream_end_stop.hpp>
#include <catch2/internal/catch_message_info.hpp> #include <catch2/internal/catch_message_info.hpp>
#include <catch2/internal/catch_move_and_forward.hpp>
#include <catch2/catch_tostring.hpp> #include <catch2/catch_tostring.hpp>
#include <catch2/interfaces/catch_interfaces_capture.hpp>
#include <string> #include <string>
#include <vector> #include <vector>
namespace Catch { 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; struct SourceLineInfo;
class IResultCapture;
struct MessageStream { struct MessageStream {
@@ -112,7 +124,7 @@ namespace Catch {
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_UNSCOPED_INFO( macroName, log ) \ #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) #if defined(CATCH_CONFIG_PREFIX_MESSAGES) && !defined(CATCH_CONFIG_DISABLE)

View File

@@ -18,7 +18,8 @@
#include <catch2/internal/catch_config_wchar.hpp> #include <catch2/internal/catch_config_wchar.hpp>
#include <catch2/internal/catch_reusable_string_stream.hpp> #include <catch2/internal/catch_reusable_string_stream.hpp>
#include <catch2/internal/catch_void_type.hpp> #include <catch2/internal/catch_void_type.hpp>
#include <catch2/interfaces/catch_interfaces_enum_values_registry.hpp> #include <catch2/internal/catch_enum_info.hpp>
#include <catch2/internal/catch_stringref.hpp>
#ifdef CATCH_CONFIG_CPP17_STRING_VIEW #ifdef CATCH_CONFIG_CPP17_STRING_VIEW
#include <string_view> #include <string_view>
@@ -383,7 +384,10 @@ namespace Catch {
} }
#endif // CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER #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 <optional> #include <optional>
namespace Catch { namespace Catch {
template<typename T> template<typename T>
@@ -630,14 +634,18 @@ struct ratio_string<std::milli> {
}; };
} }
#include <catch2/interfaces/catch_interfaces_registry_hub.hpp>
#define INTERNAL_CATCH_REGISTER_ENUM( enumName, ... ) \ #define INTERNAL_CATCH_REGISTER_ENUM( enumName, ... ) \
namespace Catch { \ namespace Catch { \
template<> struct StringMaker<enumName> { \ template <> \
struct StringMaker<enumName> { \
static std::string convert( enumName value ) { \ static std::string convert( enumName value ) { \
static const auto& enumInfo = ::Catch::getMutableRegistryHub().getMutableEnumValuesRegistry().registerEnum( #enumName, #__VA_ARGS__, { __VA_ARGS__ } ); \ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
return static_cast<std::string>(enumInfo.lookup( static_cast<int>( value ) )); \ 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<std::string>( \
enumInfo.lookup( static_cast<int64_t>( value ) ) ); \
} \ } \
}; \ }; \
} }

View File

@@ -22,7 +22,7 @@ namespace Catch {
class ExceptionTranslatorRegistrar { class ExceptionTranslatorRegistrar {
template<typename T> template<typename T>
class ExceptionTranslator : public IExceptionTranslator { class ExceptionTranslator final : public IExceptionTranslator {
public: public:
constexpr ExceptionTranslator( std::string(*translateFunction)( T const& ) ) constexpr ExceptionTranslator( std::string(*translateFunction)( T const& ) )

View File

@@ -9,7 +9,7 @@
#define CATCH_VERSION_MACROS_HPP_INCLUDED #define CATCH_VERSION_MACROS_HPP_INCLUDED
#define CATCH_VERSION_MAJOR 3 #define CATCH_VERSION_MAJOR 3
#define CATCH_VERSION_MINOR 14 #define CATCH_VERSION_MINOR 15
#define CATCH_VERSION_PATCH 0 #define CATCH_VERSION_PATCH 0
#endif // CATCH_VERSION_MACROS_HPP_INCLUDED #endif // CATCH_VERSION_MACROS_HPP_INCLUDED

View File

@@ -24,7 +24,6 @@
#include <catch2/interfaces/catch_interfaces_capture.hpp> #include <catch2/interfaces/catch_interfaces_capture.hpp>
#include <catch2/interfaces/catch_interfaces_config.hpp> #include <catch2/interfaces/catch_interfaces_config.hpp>
#include <catch2/interfaces/catch_interfaces_enum_values_registry.hpp>
#include <catch2/interfaces/catch_interfaces_exception.hpp> #include <catch2/interfaces/catch_interfaces_exception.hpp>
#include <catch2/interfaces/catch_interfaces_generatortracker.hpp> #include <catch2/interfaces/catch_interfaces_generatortracker.hpp>
#include <catch2/interfaces/catch_interfaces_registry_hub.hpp> #include <catch2/interfaces/catch_interfaces_registry_hub.hpp>

View File

@@ -22,8 +22,6 @@ namespace Catch {
struct AssertionInfo; struct AssertionInfo;
struct SectionInfo; struct SectionInfo;
struct SectionEndInfo; struct SectionEndInfo;
struct MessageInfo;
struct MessageBuilder;
struct Counts; struct Counts;
struct AssertionReaction; struct AssertionReaction;
struct SourceLineInfo; struct SourceLineInfo;
@@ -63,11 +61,6 @@ namespace Catch {
virtual void benchmarkEnded( BenchmarkStats<> const& stats ) = 0; virtual void benchmarkEnded( BenchmarkStats<> const& stats ) = 0;
virtual void benchmarkFailed( StringRef error ) = 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 handleFatalErrorCondition( StringRef message ) = 0;
virtual void handleExpr virtual void handleExpr
@@ -93,9 +86,6 @@ namespace Catch {
ResultWas::OfType resultType, ResultWas::OfType resultType,
AssertionReaction &reaction ) = 0; AssertionReaction &reaction ) = 0;
virtual bool lastAssertionPassed() = 0;
// Deprecated, do not use: // Deprecated, do not use:
virtual std::string getCurrentTestName() const = 0; virtual std::string getCurrentTestName() const = 0;
virtual const AssertionResult* getLastResult() const = 0; virtual const AssertionResult* getLastResult() const = 0;

View File

@@ -64,7 +64,7 @@ namespace Catch {
class IStream; class IStream;
struct PathFilter; struct PathFilter;
class IConfig : public Detail::NonCopyable { class IConfig : Detail::NonCopyable {
public: public:
virtual ~IConfig(); virtual ~IConfig();

View File

@@ -1,47 +0,0 @@
// 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_INTERFACES_ENUM_VALUES_REGISTRY_HPP_INCLUDED
#define CATCH_INTERFACES_ENUM_VALUES_REGISTRY_HPP_INCLUDED
#include <catch2/internal/catch_stringref.hpp>
#include <vector>
namespace Catch {
namespace Detail {
struct EnumInfo {
StringRef m_name;
std::vector<std::pair<int, StringRef>> m_values;
~EnumInfo();
StringRef lookup( int value ) const;
};
} // namespace Detail
class IMutableEnumValuesRegistry {
public:
virtual ~IMutableEnumValuesRegistry(); // = default;
virtual Detail::EnumInfo const& registerEnum( StringRef enumName, StringRef allEnums, std::vector<int> const& values ) = 0;
template<typename E>
Detail::EnumInfo const& registerEnum( StringRef enumName, StringRef allEnums, std::initializer_list<E> values ) {
static_assert(sizeof(int) >= sizeof(E), "Cannot serialize enum to int");
std::vector<int> intValues;
intValues.reserve( values.size() );
for( auto enumValue : values )
intValues.push_back( static_cast<int>( enumValue ) );
return registerEnum( enumName, allEnums, intValues );
}
};
} // Catch
#endif // CATCH_INTERFACES_ENUM_VALUES_REGISTRY_HPP_INCLUDED

View File

@@ -53,7 +53,6 @@ namespace Catch {
virtual void registerTranslator( Detail::unique_ptr<IExceptionTranslator>&& translator ) = 0; virtual void registerTranslator( Detail::unique_ptr<IExceptionTranslator>&& translator ) = 0;
virtual void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) = 0; virtual void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) = 0;
virtual void registerStartupException() noexcept = 0; virtual void registerStartupException() noexcept = 0;
virtual IMutableEnumValuesRegistry& getMutableEnumValuesRegistry() = 0;
}; };
IRegistryHub const& getRegistryHub(); IRegistryHub const& getRegistryHub();

View File

@@ -10,12 +10,13 @@
#include <catch2/catch_assertion_info.hpp> #include <catch2/catch_assertion_info.hpp>
#include <catch2/internal/catch_decomposer.hpp> #include <catch2/internal/catch_decomposer.hpp>
#include <catch2/interfaces/catch_interfaces_capture.hpp>
#include <string> #include <string>
namespace Catch { namespace Catch {
class RunContext;
struct AssertionReaction { struct AssertionReaction {
bool shouldDebugBreak = false; bool shouldDebugBreak = false;
bool shouldThrow = false; bool shouldThrow = false;
@@ -26,7 +27,12 @@ namespace Catch {
AssertionInfo m_assertionInfo; AssertionInfo m_assertionInfo;
AssertionReaction m_reaction; AssertionReaction m_reaction;
bool m_completed = false; 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: public:
AssertionHandler AssertionHandler
@@ -35,9 +41,9 @@ namespace Catch {
StringRef capturedExpression, StringRef capturedExpression,
ResultDisposition::Flags resultDisposition ); ResultDisposition::Flags resultDisposition );
~AssertionHandler() { ~AssertionHandler() {
if ( !m_completed ) { // We want the common fast path inlinable, and the virtual
m_resultCapture.handleIncomplete( m_assertionInfo ); // dispatch in a function in single TU.
} if ( !m_completed ) { finishIncomplete(); }
} }

View File

@@ -27,8 +27,6 @@
#include <catch2/internal/catch_platform.hpp> #include <catch2/internal/catch_platform.hpp>
#include <catch2/catch_user_config.hpp> #include <catch2/catch_user_config.hpp>
#ifdef __cplusplus
#if (__cplusplus >= 201703L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) #if (__cplusplus >= 201703L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)
# define CATCH_CPP17_OR_GREATER # define CATCH_CPP17_OR_GREATER
#endif #endif
@@ -37,6 +35,16 @@
# define CATCH_CPP20_OR_GREATER # define CATCH_CPP20_OR_GREATER
#endif #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 #endif
// Only GCC compiler should be used in this block, so other compilers trying to // Only GCC compiler should be used in this block, so other compilers trying to

View File

@@ -193,7 +193,7 @@ namespace Catch {
void formatReconstructedExpression( std::ostream &os, std::string const& lhs, StringRef op, std::string const& rhs ); void formatReconstructedExpression( std::ostream &os, std::string const& lhs, StringRef op, std::string const& rhs );
template<typename LhsT, typename RhsT> template<typename LhsT, typename RhsT>
class BinaryExpr : public ITransientExpression { class BinaryExpr final : public ITransientExpression {
LhsT m_lhs; LhsT m_lhs;
StringRef m_op; StringRef m_op;
RhsT m_rhs; RhsT m_rhs;
@@ -269,7 +269,7 @@ namespace Catch {
}; };
template<typename LhsT> template<typename LhsT>
class UnaryExpr : public ITransientExpression { class UnaryExpr final : public ITransientExpression {
LhsT m_lhs; LhsT m_lhs;
void streamReconstructedExpression( std::ostream &os ) const override { void streamReconstructedExpression( std::ostream &os ) const override {

View File

@@ -0,0 +1,48 @@
// 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_ENUM_INFO_HPP_INCLUDED
#define CATCH_ENUM_INFO_HPP_INCLUDED
#include <catch2/internal/catch_stringref.hpp>
#include <cstdint>
#include <utility>
#include <vector>
namespace Catch {
namespace Detail {
struct EnumInfo {
StringRef m_name;
std::vector<std::pair<int64_t, StringRef>> m_values;
StringRef lookup( int64_t value ) const;
};
EnumInfo makeEnumInfo( StringRef enumName,
StringRef allValueNames,
std::vector<int64_t> const& values );
template <typename E>
Detail::EnumInfo makeEnumInfo( StringRef enumName,
StringRef allEnums,
std::initializer_list<E> values ) {
static_assert( sizeof( int64_t ) >= sizeof( E ),
"Cannot serialize enum to int64_t" );
std::vector<int64_t> intValues;
intValues.reserve( values.size() );
for ( auto enumValue : values )
intValues.push_back( static_cast<int64_t>( enumValue ) );
return makeEnumInfo( enumName, allEnums, intValues );
}
std::vector<StringRef> parseEnums( StringRef enums );
} // namespace Detail
} // namespace Catch
#endif // CATCH_ENUM_INFO_HPP_INCLUDED

View File

@@ -1,36 +0,0 @@
// 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_ENUM_VALUES_REGISTRY_HPP_INCLUDED
#define CATCH_ENUM_VALUES_REGISTRY_HPP_INCLUDED
#include <catch2/interfaces/catch_interfaces_enum_values_registry.hpp>
#include <catch2/internal/catch_unique_ptr.hpp>
#include <catch2/internal/catch_stringref.hpp>
#include <vector>
namespace Catch {
namespace Detail {
Catch::Detail::unique_ptr<EnumInfo> makeEnumInfo( StringRef enumName, StringRef allValueNames, std::vector<int> const& values );
class EnumValuesRegistry : public IMutableEnumValuesRegistry {
std::vector<Catch::Detail::unique_ptr<EnumInfo>> m_enumInfos;
EnumInfo const& registerEnum( StringRef enumName, StringRef allValueNames, std::vector<int> const& values) override;
};
std::vector<StringRef> parseEnums( StringRef enums );
} // Detail
} // Catch
#endif // CATCH_ENUM_VALUES_REGISTRY_HPP_INCLUDED

View File

@@ -15,7 +15,7 @@
namespace Catch { namespace Catch {
class ExceptionTranslatorRegistry : public IExceptionTranslatorRegistry { class ExceptionTranslatorRegistry final : public IExceptionTranslatorRegistry {
public: public:
~ExceptionTranslatorRegistry() override; ~ExceptionTranslatorRegistry() override;
void registerTranslator( Detail::unique_ptr<IExceptionTranslator>&& translator ); void registerTranslator( Detail::unique_ptr<IExceptionTranslator>&& translator );

View File

@@ -102,8 +102,6 @@ namespace Catch {
void handleFatalErrorCondition( StringRef message ) override; void handleFatalErrorCondition( StringRef message ) override;
bool lastAssertionPassed() override;
public: public:
// !TBD We need to do this another way! // !TBD We need to do this another way!
bool aborting() const; bool aborting() const;
@@ -125,7 +123,7 @@ namespace Catch {
ITransientExpression const *expr, ITransientExpression const *expr,
bool negated ); 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, // Creates dummy info for unexpected exceptions/fatal errors,
// where we do not have the access to one, but we still need // where we do not have the access to one, but we still need

View File

@@ -20,7 +20,7 @@ namespace Catch {
template<typename SingletonImplT, typename InterfaceT = SingletonImplT, typename MutableInterfaceT = InterfaceT> template<typename SingletonImplT, typename InterfaceT = SingletonImplT, typename MutableInterfaceT = InterfaceT>
class Singleton : SingletonImplT, public ISingleton { class Singleton final : SingletonImplT, public ISingleton {
static auto getInternal() -> Singleton* { static auto getInternal() -> Singleton* {
static Singleton* s_instance = nullptr; static Singleton* s_instance = nullptr;

View File

@@ -17,7 +17,7 @@
namespace Catch { namespace Catch {
struct SourceLineInfo; struct SourceLineInfo;
class TagAliasRegistry : public ITagAliasRegistry { class TagAliasRegistry final : public ITagAliasRegistry {
public: public:
~TagAliasRegistry() override; ~TagAliasRegistry() override;
TagAlias const* find( std::string const& alias ) const override; TagAlias const* find( std::string const& alias ) const override;

View File

@@ -28,7 +28,7 @@ namespace Catch {
std::vector<TestCaseHandle> filterTests( std::vector<TestCaseHandle> const& testCases, TestSpec const& testSpec, IConfig const& config ); std::vector<TestCaseHandle> filterTests( std::vector<TestCaseHandle> const& testCases, TestSpec const& testSpec, IConfig const& config );
std::vector<TestCaseHandle> const& getAllTestCasesSorted( IConfig const& config ); std::vector<TestCaseHandle> const& getAllTestCasesSorted( IConfig const& config );
class TestRegistry : public ITestCaseRegistry { class TestRegistry final : public ITestCaseRegistry {
public: public:
void registerTest( Detail::unique_ptr<TestCaseInfo> testInfo, Detail::unique_ptr<ITestInvoker> testInvoker ); void registerTest( Detail::unique_ptr<TestCaseInfo> testInfo, Detail::unique_ptr<ITestInvoker> testInvoker );

View File

@@ -11,10 +11,16 @@
#include <catch2/catch_user_config.hpp> #include <catch2/catch_user_config.hpp>
#include <catch2/internal/catch_assertion_handler.hpp> #include <catch2/internal/catch_assertion_handler.hpp>
#include <catch2/internal/catch_preprocessor_internal_stringify.hpp> #include <catch2/internal/catch_preprocessor_internal_stringify.hpp>
#include <catch2/interfaces/catch_interfaces_capture.hpp>
#include <catch2/internal/catch_stringref.hpp> #include <catch2/internal/catch_stringref.hpp>
#include <catch2/internal/catch_source_line_info.hpp> #include <catch2/internal/catch_source_line_info.hpp>
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 // We need this suppression to leak, because it took until GCC 10
// for the front end to handle local suppression via _Pragma properly // for the front end to handle local suppression via _Pragma properly
#if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC) && __GNUC__ <= 9 #if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC) && __GNUC__ <= 9
@@ -57,12 +63,12 @@
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_IF( macroName, resultDisposition, ... ) \ #define INTERNAL_CATCH_IF( macroName, resultDisposition, ... ) \
INTERNAL_CATCH_TEST( macroName, resultDisposition, __VA_ARGS__ ); \ INTERNAL_CATCH_TEST( macroName, resultDisposition, __VA_ARGS__ ); \
if( Catch::getResultCapture().lastAssertionPassed() ) if( Catch::Detail::lastAssertionPassed() )
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_ELSE( macroName, resultDisposition, ... ) \ #define INTERNAL_CATCH_ELSE( macroName, resultDisposition, ... ) \
INTERNAL_CATCH_TEST( macroName, resultDisposition, __VA_ARGS__ ); \ INTERNAL_CATCH_TEST( macroName, resultDisposition, __VA_ARGS__ ); \
if( !Catch::getResultCapture().lastAssertionPassed() ) if( !Catch::Detail::lastAssertionPassed() )
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_NO_THROW( macroName, resultDisposition, ... ) \ #define INTERNAL_CATCH_NO_THROW( macroName, resultDisposition, ... ) \

View File

@@ -29,7 +29,7 @@
namespace Catch { namespace Catch {
template<typename C> template<typename C>
class TestInvokerAsMethod : public ITestInvoker { class TestInvokerAsMethod final : public ITestInvoker {
void (C::*m_testAsMethod)(); void (C::*m_testAsMethod)();
public: public:
constexpr TestInvokerAsMethod( void ( C::*testAsMethod )() ) noexcept: constexpr TestInvokerAsMethod( void ( C::*testAsMethod )() ) noexcept:
@@ -49,7 +49,7 @@ Detail::unique_ptr<ITestInvoker> makeTestInvoker( void (C::*testAsMethod)() ) {
} }
template <typename C> template <typename C>
class TestInvokerFixture : public ITestInvoker { class TestInvokerFixture final : public ITestInvoker {
void ( C::*m_testAsMethod )() const; void ( C::*m_testAsMethod )() const;
Detail::unique_ptr<C> m_fixture = nullptr; Detail::unique_ptr<C> m_fixture = nullptr;
@@ -124,7 +124,7 @@ struct AutoReg : Detail::NonCopyable {
namespace Catch { namespace Catch {
namespace Detail { namespace Detail {
struct DummyUse { struct DummyUse {
DummyUse( void ( * )( int ), Catch::NameAndTags const& ); DummyUse( void ( * )( int ), Catch::NameAndTags const& ) noexcept;
}; };
} // namespace Detail } // namespace Detail
} // namespace Catch } // namespace Catch

View File

@@ -20,10 +20,10 @@ namespace Matchers {
class MatcherUntypedBase { class MatcherUntypedBase {
public: public:
MatcherUntypedBase() = default; constexpr MatcherUntypedBase() = default;
MatcherUntypedBase(MatcherUntypedBase const&) = default; constexpr MatcherUntypedBase(MatcherUntypedBase const&) = default;
MatcherUntypedBase(MatcherUntypedBase&&) = default; constexpr MatcherUntypedBase(MatcherUntypedBase&&) = default;
MatcherUntypedBase& operator = (MatcherUntypedBase const&) = delete; MatcherUntypedBase& operator = (MatcherUntypedBase const&) = delete;
MatcherUntypedBase& operator = (MatcherUntypedBase&&) = delete; MatcherUntypedBase& operator = (MatcherUntypedBase&&) = delete;
@@ -31,9 +31,9 @@ namespace Matchers {
std::string toString() const; std::string toString() const;
protected: protected:
virtual ~MatcherUntypedBase(); // = default; CATCH_DESTRUCTOR_CONSTEXPR virtual ~MatcherUntypedBase() = default;
virtual std::string describe() const = 0; //! Should be overridden, but we provide default "undescribed" impl
mutable std::string m_cachedToString; virtual std::string describe() const;
}; };
@@ -215,6 +215,19 @@ namespace Matchers {
#define CATCH_CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CATCH_CHECK_THAT", matcher, Catch::ResultDisposition::ContinueOnFailure, arg ) #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 ) #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) #elif defined(CATCH_CONFIG_PREFIX_ALL) && defined(CATCH_CONFIG_DISABLE)
#define CATCH_REQUIRE_THROWS_WITH( expr, matcher ) (void)(0) #define CATCH_REQUIRE_THROWS_WITH( expr, matcher ) (void)(0)
@@ -226,6 +239,9 @@ namespace Matchers {
#define CATCH_CHECK_THAT( arg, matcher ) (void)(0) #define CATCH_CHECK_THAT( arg, matcher ) (void)(0)
#define CATCH_REQUIRE_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) #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 ) #define REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "REQUIRE_THROWS_WITH", Catch::ResultDisposition::Normal, matcher, expr )
@@ -237,6 +253,19 @@ namespace Matchers {
#define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CHECK_THAT", matcher, Catch::ResultDisposition::ContinueOnFailure, arg ) #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 ) #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) #elif !defined(CATCH_CONFIG_PREFIX_ALL) && defined(CATCH_CONFIG_DISABLE)
#define REQUIRE_THROWS_WITH( expr, matcher ) (void)(0) #define REQUIRE_THROWS_WITH( expr, matcher ) (void)(0)
@@ -248,6 +277,9 @@ namespace Matchers {
#define CHECK_THAT( arg, matcher ) (void)(0) #define CHECK_THAT( arg, matcher ) (void)(0)
#define REQUIRE_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 // end of user facing macro declarations
#endif // CATCH_MATCHERS_HPP_INCLUDED #endif // CATCH_MATCHERS_HPP_INCLUDED

View File

@@ -18,7 +18,7 @@ namespace Catch {
class IsEmptyMatcher final : public MatcherGenericBase { class IsEmptyMatcher final : public MatcherGenericBase {
public: public:
template <typename RangeLike> template <typename RangeLike>
bool match(RangeLike&& rng) const { constexpr bool match(RangeLike&& rng) const {
#if defined(CATCH_CONFIG_POLYFILL_NONMEMBER_CONTAINER_ACCESS) #if defined(CATCH_CONFIG_POLYFILL_NONMEMBER_CONTAINER_ACCESS)
using Catch::Detail::empty; using Catch::Detail::empty;
#else #else
@@ -33,12 +33,12 @@ namespace Catch {
class HasSizeMatcher final : public MatcherGenericBase { class HasSizeMatcher final : public MatcherGenericBase {
std::size_t m_target_size; std::size_t m_target_size;
public: public:
explicit HasSizeMatcher(std::size_t target_size): constexpr explicit HasSizeMatcher(std::size_t target_size):
m_target_size(target_size) m_target_size(target_size)
{} {}
template <typename RangeLike> template <typename RangeLike>
bool match(RangeLike&& rng) const { constexpr bool match(RangeLike&& rng) const {
#if defined(CATCH_CONFIG_POLYFILL_NONMEMBER_CONTAINER_ACCESS) #if defined(CATCH_CONFIG_POLYFILL_NONMEMBER_CONTAINER_ACCESS)
using Catch::Detail::size; using Catch::Detail::size;
#else #else
@@ -54,12 +54,12 @@ namespace Catch {
class SizeMatchesMatcher final : public MatcherGenericBase { class SizeMatchesMatcher final : public MatcherGenericBase {
Matcher m_matcher; Matcher m_matcher;
public: public:
explicit SizeMatchesMatcher(Matcher m): constexpr explicit SizeMatchesMatcher(Matcher m):
m_matcher(CATCH_MOVE(m)) m_matcher(CATCH_MOVE(m))
{} {}
template <typename RangeLike> template <typename RangeLike>
bool match(RangeLike&& rng) const { constexpr bool match(RangeLike&& rng) const {
#if defined(CATCH_CONFIG_POLYFILL_NONMEMBER_CONTAINER_ACCESS) #if defined(CATCH_CONFIG_POLYFILL_NONMEMBER_CONTAINER_ACCESS)
using Catch::Detail::size; using Catch::Detail::size;
#else #else
@@ -75,11 +75,13 @@ namespace Catch {
//! Creates a matcher that accepts empty ranges/containers //! 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 //! 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 <typename Matcher> template <typename Matcher>
std::enable_if_t<Detail::is_matcher_v<Matcher>, constexpr std::enable_if_t<Detail::is_matcher_v<Matcher>,
SizeMatchesMatcher<Matcher>> SizeIs(Matcher&& m) { SizeMatchesMatcher<Matcher>> SizeIs(Matcher&& m) {
return SizeMatchesMatcher<Matcher>{CATCH_FORWARD(m)}; return SizeMatchesMatcher<Matcher>{CATCH_FORWARD(m)};
} }

View File

@@ -23,7 +23,7 @@ namespace Catch {
Equality m_eq; Equality m_eq;
public: public:
template <typename T2, typename Equality2> template <typename T2, typename Equality2>
ContainsElementMatcher(T2&& target, Equality2&& predicate): constexpr ContainsElementMatcher(T2&& target, Equality2&& predicate):
m_desired(CATCH_FORWARD(target)), m_desired(CATCH_FORWARD(target)),
m_eq(CATCH_FORWARD(predicate)) m_eq(CATCH_FORWARD(predicate))
{} {}
@@ -33,7 +33,7 @@ namespace Catch {
} }
template <typename RangeLike> template <typename RangeLike>
bool match( RangeLike&& rng ) const { constexpr bool match( RangeLike&& rng ) const {
for ( auto&& elem : rng ) { for ( auto&& elem : rng ) {
if ( m_eq( elem, m_desired ) ) { return true; } if ( m_eq( elem, m_desired ) ) { return true; }
} }
@@ -49,12 +49,12 @@ namespace Catch {
// Note that we do a copy+move to avoid having to SFINAE this // Note that we do a copy+move to avoid having to SFINAE this
// constructor (and also avoid some perfect forwarding failure // constructor (and also avoid some perfect forwarding failure
// cases) // cases)
ContainsMatcherMatcher(Matcher matcher): constexpr ContainsMatcherMatcher(Matcher matcher):
m_matcher(CATCH_MOVE(matcher)) m_matcher(CATCH_MOVE(matcher))
{} {}
template <typename RangeLike> template <typename RangeLike>
bool match(RangeLike&& rng) const { constexpr bool match(RangeLike&& rng) const {
for (auto&& elem : rng) { for (auto&& elem : rng) {
if (m_matcher.match(elem)) { if (m_matcher.match(elem)) {
return true; return true;
@@ -74,14 +74,14 @@ namespace Catch {
* Uses `std::equal_to` to do the comparison * Uses `std::equal_to` to do the comparison
*/ */
template <typename T> template <typename T>
std::enable_if_t<!Detail::is_matcher_v<T>, constexpr std::enable_if_t<!Detail::is_matcher_v<T>,
ContainsElementMatcher<T, std::equal_to<>>> Contains(T&& elem) { ContainsElementMatcher<T, std::equal_to<>>> Contains(T&& elem) {
return { CATCH_FORWARD(elem), std::equal_to<>{} }; return { CATCH_FORWARD(elem), std::equal_to<>{} };
} }
//! Creates a matcher that checks whether a range contains element matching a matcher //! Creates a matcher that checks whether a range contains element matching a matcher
template <typename Matcher> template <typename Matcher>
std::enable_if_t<Detail::is_matcher_v<Matcher>, constexpr std::enable_if_t<Detail::is_matcher_v<Matcher>,
ContainsMatcherMatcher<Matcher>> Contains(Matcher&& matcher) { ContainsMatcherMatcher<Matcher>> Contains(Matcher&& matcher) {
return { CATCH_FORWARD(matcher) }; return { CATCH_FORWARD(matcher) };
} }
@@ -92,7 +92,7 @@ namespace Catch {
* Uses `eq` to do the comparisons, the element is provided on the rhs * Uses `eq` to do the comparisons, the element is provided on the rhs
*/ */
template <typename T, typename Equality> template <typename T, typename Equality>
ContainsElementMatcher<T, Equality> Contains(T&& elem, Equality&& eq) { constexpr ContainsElementMatcher<T, Equality> Contains(T&& elem, Equality&& eq) {
return { CATCH_FORWARD(elem), CATCH_FORWARD(eq) }; return { CATCH_FORWARD(elem), CATCH_FORWARD(eq) };
} }

View File

@@ -18,7 +18,7 @@ namespace Catch {
class AllMatchMatcher final : public MatcherGenericBase { class AllMatchMatcher final : public MatcherGenericBase {
Matcher m_matcher; Matcher m_matcher;
public: public:
AllMatchMatcher(Matcher matcher): constexpr AllMatchMatcher(Matcher matcher):
m_matcher(CATCH_MOVE(matcher)) m_matcher(CATCH_MOVE(matcher))
{} {}
@@ -27,7 +27,7 @@ namespace Catch {
} }
template <typename RangeLike> template <typename RangeLike>
bool match(RangeLike&& rng) const { constexpr bool match(RangeLike&& rng) const {
for (auto&& elem : rng) { for (auto&& elem : rng) {
if (!m_matcher.match(elem)) { if (!m_matcher.match(elem)) {
return false; return false;
@@ -42,7 +42,7 @@ namespace Catch {
class NoneMatchMatcher final : public MatcherGenericBase { class NoneMatchMatcher final : public MatcherGenericBase {
Matcher m_matcher; Matcher m_matcher;
public: public:
NoneMatchMatcher(Matcher matcher): constexpr NoneMatchMatcher(Matcher matcher):
m_matcher(CATCH_MOVE(matcher)) m_matcher(CATCH_MOVE(matcher))
{} {}
@@ -51,7 +51,7 @@ namespace Catch {
} }
template <typename RangeLike> template <typename RangeLike>
bool match(RangeLike&& rng) const { constexpr bool match(RangeLike&& rng) const {
for (auto&& elem : rng) { for (auto&& elem : rng) {
if (m_matcher.match(elem)) { if (m_matcher.match(elem)) {
return false; return false;
@@ -66,7 +66,7 @@ namespace Catch {
class AnyMatchMatcher final : public MatcherGenericBase { class AnyMatchMatcher final : public MatcherGenericBase {
Matcher m_matcher; Matcher m_matcher;
public: public:
AnyMatchMatcher(Matcher matcher): constexpr AnyMatchMatcher(Matcher matcher):
m_matcher(CATCH_MOVE(matcher)) m_matcher(CATCH_MOVE(matcher))
{} {}
@@ -75,7 +75,7 @@ namespace Catch {
} }
template <typename RangeLike> template <typename RangeLike>
bool match(RangeLike&& rng) const { constexpr bool match(RangeLike&& rng) const {
for (auto&& elem : rng) { for (auto&& elem : rng) {
if (m_matcher.match(elem)) { if (m_matcher.match(elem)) {
return true; return true;
@@ -91,7 +91,7 @@ namespace Catch {
std::string describe() const override; std::string describe() const override;
template <typename RangeLike> template <typename RangeLike>
bool match(RangeLike&& rng) const { constexpr bool match(RangeLike&& rng) const {
for (auto&& elem : rng) { for (auto&& elem : rng) {
if (!elem) { if (!elem) {
return false; return false;
@@ -107,7 +107,7 @@ namespace Catch {
std::string describe() const override; std::string describe() const override;
template <typename RangeLike> template <typename RangeLike>
bool match(RangeLike&& rng) const { constexpr bool match(RangeLike&& rng) const {
for (auto&& elem : rng) { for (auto&& elem : rng) {
if (elem) { if (elem) {
return false; return false;
@@ -123,7 +123,7 @@ namespace Catch {
std::string describe() const override; std::string describe() const override;
template <typename RangeLike> template <typename RangeLike>
bool match(RangeLike&& rng) const { constexpr bool match(RangeLike&& rng) const {
for (auto&& elem : rng) { for (auto&& elem : rng) {
if (elem) { if (elem) {
return true; return true;
@@ -133,32 +133,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 <typename Matcher> template <typename Matcher>
AllMatchMatcher<Matcher> AllMatch(Matcher&& matcher) { constexpr AllMatchMatcher<Matcher> AllMatch(Matcher&& matcher) {
return { CATCH_FORWARD(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 <typename Matcher> template <typename Matcher>
NoneMatchMatcher<Matcher> NoneMatch(Matcher&& matcher) { constexpr NoneMatchMatcher<Matcher> NoneMatch(Matcher&& matcher) {
return { CATCH_FORWARD(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 <typename Matcher> template <typename Matcher>
AnyMatchMatcher<Matcher> AnyMatch(Matcher&& matcher) { constexpr AnyMatchMatcher<Matcher> AnyMatch(Matcher&& matcher) {
return { CATCH_FORWARD(matcher) }; return { CATCH_FORWARD(matcher) };
} }
// Creates a matcher that checks whether all elements in a range are true //! Creates a matcher that checks whether all elements in a range are true
AllTrueMatcher AllTrue(); inline CATCH_DESTRUCTOR_CONSTEXPR
AllTrueMatcher AllTrue() { return AllTrueMatcher{}; }
// Creates a matcher that checks whether no element in a range is true //! Creates a matcher that checks whether no element in a range is true
NoneTrueMatcher NoneTrue(); inline CATCH_DESTRUCTOR_CONSTEXPR
NoneTrueMatcher NoneTrue() { return NoneTrueMatcher{}; }
// Creates a matcher that checks whether any element in a range is true //! Creates a matcher that checks whether any element in a range is true
AnyTrueMatcher AnyTrue(); inline CATCH_DESTRUCTOR_CONSTEXPR
AnyTrueMatcher AnyTrue() { return AnyTrueMatcher{}; }
} }
} }

View File

@@ -22,12 +22,12 @@
namespace Catch { namespace Catch {
namespace Matchers { namespace Matchers {
class MatcherGenericBase : public MatcherUntypedBase { class MatcherGenericBase : public MatcherUntypedBase {
std::string describe() const override;
public: public:
MatcherGenericBase() = default; constexpr MatcherGenericBase() = default;
~MatcherGenericBase() override; // = default;
MatcherGenericBase(MatcherGenericBase const&) = default; constexpr MatcherGenericBase(MatcherGenericBase const&) = default;
MatcherGenericBase(MatcherGenericBase&&) = default; constexpr MatcherGenericBase(MatcherGenericBase&&) = default;
MatcherGenericBase& operator=(MatcherGenericBase const&) = delete; MatcherGenericBase& operator=(MatcherGenericBase const&) = delete;
MatcherGenericBase& operator=(MatcherGenericBase&&) = delete; MatcherGenericBase& operator=(MatcherGenericBase&&) = delete;
@@ -36,7 +36,9 @@ namespace Matchers {
namespace Detail { namespace Detail {
template<std::size_t N, std::size_t M> template<std::size_t N, std::size_t M>
std::array<void const*, N + M> array_cat(std::array<void const*, N> && lhs, std::array<void const*, M> && rhs) { constexpr std::array<void const*, N + M>
array_cat( std::array<void const*, N>&& lhs,
std::array<void const*, M>&& rhs ) {
std::array<void const*, N + M> arr{}; std::array<void const*, N + M> arr{};
std::copy_n(lhs.begin(), N, arr.begin()); std::copy_n(lhs.begin(), N, arr.begin());
std::copy_n(rhs.begin(), M, arr.begin() + N); std::copy_n(rhs.begin(), M, arr.begin() + N);
@@ -44,7 +46,8 @@ namespace Matchers {
} }
template<std::size_t N> template<std::size_t N>
std::array<void const*, N+1> array_cat(std::array<void const*, N> && lhs, void const* rhs) { constexpr std::array<void const*, N + 1>
array_cat( std::array<void const*, N>&& lhs, void const* rhs ) {
std::array<void const*, N+1> arr{}; std::array<void const*, N+1> arr{};
std::copy_n(lhs.begin(), N, arr.begin()); std::copy_n(lhs.begin(), N, arr.begin());
arr[N] = rhs; arr[N] = rhs;
@@ -52,7 +55,8 @@ namespace Matchers {
} }
template<std::size_t N> template<std::size_t N>
std::array<void const*, N+1> array_cat(void const* lhs, std::array<void const*, N> && rhs) { constexpr std::array<void const*, N + 1>
array_cat( void const* lhs, std::array<void const*, N>&& rhs ) {
std::array<void const*, N + 1> arr{ {lhs} }; std::array<void const*, N + 1> arr{ {lhs} };
std::copy_n(rhs.begin(), N, arr.begin() + 1); std::copy_n(rhs.begin(), N, arr.begin() + 1);
return arr; return arr;
@@ -75,23 +79,31 @@ namespace Matchers {
template<std::size_t N, typename Arg> template<std::size_t N, typename Arg>
bool match_all_of(Arg&&, std::array<void const*, N> const&, std::index_sequence<>) { constexpr bool match_all_of( Arg&&,
std::array<void const*, N> const&,
std::index_sequence<> ) {
return true; return true;
} }
template<typename T, typename... MatcherTs, std::size_t N, typename Arg, std::size_t Idx, std::size_t... Indices> template<typename T, typename... MatcherTs, std::size_t N, typename Arg, std::size_t Idx, std::size_t... Indices>
bool match_all_of(Arg&& arg, std::array<void const*, N> const& matchers, std::index_sequence<Idx, Indices...>) { constexpr bool match_all_of( Arg&& arg,
std::array<void const*, N> const& matchers,
std::index_sequence<Idx, Indices...> ) {
return static_cast<T const*>(matchers[Idx])->match(arg) && match_all_of<MatcherTs...>(arg, matchers, std::index_sequence<Indices...>{}); return static_cast<T const*>(matchers[Idx])->match(arg) && match_all_of<MatcherTs...>(arg, matchers, std::index_sequence<Indices...>{});
} }
template<std::size_t N, typename Arg> template<std::size_t N, typename Arg>
bool match_any_of(Arg&&, std::array<void const*, N> const&, std::index_sequence<>) { constexpr bool match_any_of( Arg&&,
std::array<void const*, N> const&,
std::index_sequence<> ) {
return false; return false;
} }
template<typename T, typename... MatcherTs, std::size_t N, typename Arg, std::size_t Idx, std::size_t... Indices> template<typename T, typename... MatcherTs, std::size_t N, typename Arg, std::size_t Idx, std::size_t... Indices>
bool match_any_of(Arg&& arg, std::array<void const*, N> const& matchers, std::index_sequence<Idx, Indices...>) { constexpr bool match_any_of( Arg&& arg,
std::array<void const*, N> const& matchers,
std::index_sequence<Idx, Indices...> ) {
return static_cast<T const*>(matchers[Idx])->match(arg) || match_any_of<MatcherTs...>(arg, matchers, std::index_sequence<Indices...>{}); return static_cast<T const*>(matchers[Idx])->match(arg) || match_any_of<MatcherTs...>(arg, matchers, std::index_sequence<Indices...>{});
} }
@@ -112,15 +124,18 @@ namespace Matchers {
public: public:
MatchAllOfGeneric(MatchAllOfGeneric const&) = delete; MatchAllOfGeneric(MatchAllOfGeneric const&) = delete;
MatchAllOfGeneric& operator=(MatchAllOfGeneric const&) = delete; MatchAllOfGeneric& operator=(MatchAllOfGeneric const&) = delete;
MatchAllOfGeneric(MatchAllOfGeneric&&) = default; constexpr MatchAllOfGeneric( MatchAllOfGeneric&& ) = default;
MatchAllOfGeneric& operator=(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)...} } {} : m_matchers{ {std::addressof(matchers)...} } {}
explicit MatchAllOfGeneric(std::array<void const*, sizeof...(MatcherTs)> matchers) : m_matchers{matchers} {} constexpr explicit MatchAllOfGeneric(
std::array<void const*, sizeof...( MatcherTs )> matchers ):
m_matchers{ matchers } {}
template<typename Arg> template<typename Arg>
bool match(Arg&& arg) const { constexpr bool match( Arg&& arg ) const {
return match_all_of<MatcherTs...>(arg, m_matchers, std::index_sequence_for<MatcherTs...>{}); return match_all_of<MatcherTs...>(arg, m_matchers, std::index_sequence_for<MatcherTs...>{});
} }
@@ -136,7 +151,7 @@ namespace Matchers {
//! Avoids type nesting for `GenericAllOf && GenericAllOf` case //! Avoids type nesting for `GenericAllOf && GenericAllOf` case
template<typename... MatchersRHS> template<typename... MatchersRHS>
friend constexpr friend
MatchAllOfGeneric<MatcherTs..., MatchersRHS...> operator && ( MatchAllOfGeneric<MatcherTs..., MatchersRHS...> operator && (
MatchAllOfGeneric<MatcherTs...>&& lhs CATCH_ATTR_LIFETIMEBOUND, MatchAllOfGeneric<MatcherTs...>&& lhs CATCH_ATTR_LIFETIMEBOUND,
MatchAllOfGeneric<MatchersRHS...>&& rhs CATCH_ATTR_LIFETIMEBOUND ) { MatchAllOfGeneric<MatchersRHS...>&& rhs CATCH_ATTR_LIFETIMEBOUND ) {
@@ -145,7 +160,8 @@ namespace Matchers {
//! Avoids type nesting for `GenericAllOf && some matcher` case //! Avoids type nesting for `GenericAllOf && some matcher` case
template<typename MatcherRHS> template<typename MatcherRHS>
friend std::enable_if_t<is_matcher_v<MatcherRHS>, constexpr friend std::enable_if_t<
is_matcher_v<MatcherRHS>,
MatchAllOfGeneric<MatcherTs..., MatcherRHS>> operator && ( MatchAllOfGeneric<MatcherTs..., MatcherRHS>> operator && (
MatchAllOfGeneric<MatcherTs...>&& lhs CATCH_ATTR_LIFETIMEBOUND, MatchAllOfGeneric<MatcherTs...>&& lhs CATCH_ATTR_LIFETIMEBOUND,
MatcherRHS const& rhs CATCH_ATTR_LIFETIMEBOUND ) { MatcherRHS const& rhs CATCH_ATTR_LIFETIMEBOUND ) {
@@ -154,7 +170,8 @@ namespace Matchers {
//! Avoids type nesting for `some matcher && GenericAllOf` case //! Avoids type nesting for `some matcher && GenericAllOf` case
template<typename MatcherLHS> template<typename MatcherLHS>
friend std::enable_if_t<is_matcher_v<MatcherLHS>, constexpr friend std::enable_if_t<
is_matcher_v<MatcherLHS>,
MatchAllOfGeneric<MatcherLHS, MatcherTs...>> operator && ( MatchAllOfGeneric<MatcherLHS, MatcherTs...>> operator && (
MatcherLHS const& lhs CATCH_ATTR_LIFETIMEBOUND, MatcherLHS const& lhs CATCH_ATTR_LIFETIMEBOUND,
MatchAllOfGeneric<MatcherTs...>&& rhs CATCH_ATTR_LIFETIMEBOUND ) { MatchAllOfGeneric<MatcherTs...>&& rhs CATCH_ATTR_LIFETIMEBOUND ) {
@@ -168,15 +185,18 @@ namespace Matchers {
public: public:
MatchAnyOfGeneric(MatchAnyOfGeneric const&) = delete; MatchAnyOfGeneric(MatchAnyOfGeneric const&) = delete;
MatchAnyOfGeneric& operator=(MatchAnyOfGeneric const&) = delete; MatchAnyOfGeneric& operator=(MatchAnyOfGeneric const&) = delete;
MatchAnyOfGeneric(MatchAnyOfGeneric&&) = default; constexpr MatchAnyOfGeneric( MatchAnyOfGeneric&& ) = default;
MatchAnyOfGeneric& operator=(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)...} } {} : m_matchers{ {std::addressof(matchers)...} } {}
explicit MatchAnyOfGeneric(std::array<void const*, sizeof...(MatcherTs)> matchers) : m_matchers{matchers} {} constexpr explicit MatchAnyOfGeneric(
std::array<void const*, sizeof...( MatcherTs )> matchers ):
m_matchers{ matchers } {}
template<typename Arg> template<typename Arg>
bool match(Arg&& arg) const { constexpr bool match( Arg&& arg ) const {
return match_any_of<MatcherTs...>(arg, m_matchers, std::index_sequence_for<MatcherTs...>{}); return match_any_of<MatcherTs...>(arg, m_matchers, std::index_sequence_for<MatcherTs...>{});
} }
@@ -192,7 +212,8 @@ namespace Matchers {
//! Avoids type nesting for `GenericAnyOf || GenericAnyOf` case //! Avoids type nesting for `GenericAnyOf || GenericAnyOf` case
template<typename... MatchersRHS> template<typename... MatchersRHS>
friend MatchAnyOfGeneric<MatcherTs..., MatchersRHS...> operator || ( constexpr friend MatchAnyOfGeneric<MatcherTs..., MatchersRHS...>
operator||(
MatchAnyOfGeneric<MatcherTs...>&& lhs CATCH_ATTR_LIFETIMEBOUND, MatchAnyOfGeneric<MatcherTs...>&& lhs CATCH_ATTR_LIFETIMEBOUND,
MatchAnyOfGeneric<MatchersRHS...>&& rhs CATCH_ATTR_LIFETIMEBOUND ) { MatchAnyOfGeneric<MatchersRHS...>&& rhs CATCH_ATTR_LIFETIMEBOUND ) {
return MatchAnyOfGeneric<MatcherTs..., MatchersRHS...>{array_cat(CATCH_MOVE(lhs.m_matchers), CATCH_MOVE(rhs.m_matchers))}; return MatchAnyOfGeneric<MatcherTs..., MatchersRHS...>{array_cat(CATCH_MOVE(lhs.m_matchers), CATCH_MOVE(rhs.m_matchers))};
@@ -200,7 +221,8 @@ namespace Matchers {
//! Avoids type nesting for `GenericAnyOf || some matcher` case //! Avoids type nesting for `GenericAnyOf || some matcher` case
template<typename MatcherRHS> template<typename MatcherRHS>
friend std::enable_if_t<is_matcher_v<MatcherRHS>, constexpr friend std::enable_if_t<
is_matcher_v<MatcherRHS>,
MatchAnyOfGeneric<MatcherTs..., MatcherRHS>> operator || ( MatchAnyOfGeneric<MatcherTs..., MatcherRHS>> operator || (
MatchAnyOfGeneric<MatcherTs...>&& lhs CATCH_ATTR_LIFETIMEBOUND, MatchAnyOfGeneric<MatcherTs...>&& lhs CATCH_ATTR_LIFETIMEBOUND,
MatcherRHS const& rhs CATCH_ATTR_LIFETIMEBOUND ) { MatcherRHS const& rhs CATCH_ATTR_LIFETIMEBOUND ) {
@@ -209,7 +231,8 @@ namespace Matchers {
//! Avoids type nesting for `some matcher || GenericAnyOf` case //! Avoids type nesting for `some matcher || GenericAnyOf` case
template<typename MatcherLHS> template<typename MatcherLHS>
friend std::enable_if_t<is_matcher_v<MatcherLHS>, constexpr friend std::enable_if_t<
is_matcher_v<MatcherLHS>,
MatchAnyOfGeneric<MatcherLHS, MatcherTs...>> operator || ( MatchAnyOfGeneric<MatcherLHS, MatcherTs...>> operator || (
MatcherLHS const& lhs CATCH_ATTR_LIFETIMEBOUND, MatcherLHS const& lhs CATCH_ATTR_LIFETIMEBOUND,
MatchAnyOfGeneric<MatcherTs...>&& rhs CATCH_ATTR_LIFETIMEBOUND) { MatchAnyOfGeneric<MatcherTs...>&& rhs CATCH_ATTR_LIFETIMEBOUND) {
@@ -225,14 +248,15 @@ namespace Matchers {
public: public:
MatchNotOfGeneric(MatchNotOfGeneric const&) = delete; MatchNotOfGeneric(MatchNotOfGeneric const&) = delete;
MatchNotOfGeneric& operator=(MatchNotOfGeneric const&) = delete; MatchNotOfGeneric& operator=(MatchNotOfGeneric const&) = delete;
MatchNotOfGeneric(MatchNotOfGeneric&&) = default; constexpr MatchNotOfGeneric( MatchNotOfGeneric&& ) = default;
MatchNotOfGeneric& operator=(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} {} : m_matcher{matcher} {}
template<typename Arg> template<typename Arg>
bool match(Arg&& arg) const { constexpr bool match( Arg&& arg ) const {
return !m_matcher.match(arg); return !m_matcher.match(arg);
} }
@@ -241,7 +265,7 @@ namespace Matchers {
} }
//! Negating negation can just unwrap and return underlying matcher //! Negating negation can just unwrap and return underlying matcher
friend MatcherT const& constexpr friend MatcherT const&
operator!( MatchNotOfGeneric<MatcherT> const& matcher operator!( MatchNotOfGeneric<MatcherT> const& matcher
CATCH_ATTR_LIFETIMEBOUND ) { CATCH_ATTR_LIFETIMEBOUND ) {
return matcher.m_matcher; return matcher.m_matcher;
@@ -252,14 +276,18 @@ namespace Matchers {
// compose only generic matchers // compose only generic matchers
template<typename MatcherLHS, typename MatcherRHS> template<typename MatcherLHS, typename MatcherRHS>
std::enable_if_t<Detail::are_generic_matchers_v<MatcherLHS, MatcherRHS>, Detail::MatchAllOfGeneric<MatcherLHS, MatcherRHS>> constexpr std::enable_if_t<
Detail::are_generic_matchers_v<MatcherLHS, MatcherRHS>,
Detail::MatchAllOfGeneric<MatcherLHS, MatcherRHS>>
operator&&( MatcherLHS const& lhs CATCH_ATTR_LIFETIMEBOUND, operator&&( MatcherLHS const& lhs CATCH_ATTR_LIFETIMEBOUND,
MatcherRHS const& rhs CATCH_ATTR_LIFETIMEBOUND ) { MatcherRHS const& rhs CATCH_ATTR_LIFETIMEBOUND ) {
return { lhs, rhs }; return { lhs, rhs };
} }
template<typename MatcherLHS, typename MatcherRHS> template<typename MatcherLHS, typename MatcherRHS>
std::enable_if_t<Detail::are_generic_matchers_v<MatcherLHS, MatcherRHS>, Detail::MatchAnyOfGeneric<MatcherLHS, MatcherRHS>> constexpr std::enable_if_t<
Detail::are_generic_matchers_v<MatcherLHS, MatcherRHS>,
Detail::MatchAnyOfGeneric<MatcherLHS, MatcherRHS>>
operator||( MatcherLHS const& lhs CATCH_ATTR_LIFETIMEBOUND, operator||( MatcherLHS const& lhs CATCH_ATTR_LIFETIMEBOUND,
MatcherRHS const& rhs CATCH_ATTR_LIFETIMEBOUND ) { MatcherRHS const& rhs CATCH_ATTR_LIFETIMEBOUND ) {
return { lhs, rhs }; return { lhs, rhs };
@@ -267,7 +295,8 @@ namespace Matchers {
//! Wrap provided generic matcher in generic negator //! Wrap provided generic matcher in generic negator
template<typename MatcherT> template<typename MatcherT>
std::enable_if_t<Detail::is_generic_matcher_v<MatcherT>, Detail::MatchNotOfGeneric<MatcherT>> constexpr std::enable_if_t<Detail::is_generic_matcher_v<MatcherT>,
Detail::MatchNotOfGeneric<MatcherT>>
operator!( MatcherT const& matcher CATCH_ATTR_LIFETIMEBOUND ) { operator!( MatcherT const& matcher CATCH_ATTR_LIFETIMEBOUND ) {
return Detail::MatchNotOfGeneric<MatcherT>{matcher}; return Detail::MatchNotOfGeneric<MatcherT>{matcher};
} }

View File

@@ -29,7 +29,7 @@ namespace Catch {
#endif #endif
template<typename ArgT, typename MatcherT> template<typename ArgT, typename MatcherT>
class MatchExpr : public ITransientExpression { class MatchExpr final : public ITransientExpression {
ArgT && m_arg; ArgT && m_arg;
MatcherT const& m_matcher; MatcherT const& m_matcher;
public: public:

View File

@@ -49,7 +49,7 @@ def copy_upstream_src(wpilib_root: Path):
def main(): def main():
name = "catch2" name = "catch2"
url = "https://github.com/catchorg/Catch2.git" url = "https://github.com/catchorg/Catch2.git"
tag = "v3.14.0" tag = "v3.15.0"
patch_options = { patch_options = {
"ignore_whitespace": True, "ignore_whitespace": True,