// 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 #pragma once #include #include #include #include #include namespace Catch { namespace Matchers { class MatcherUntypedBase { public: constexpr MatcherUntypedBase() = default; constexpr MatcherUntypedBase(MatcherUntypedBase const&) = default; constexpr MatcherUntypedBase(MatcherUntypedBase&&) = default; MatcherUntypedBase& operator = (MatcherUntypedBase const&) = delete; MatcherUntypedBase& operator = (MatcherUntypedBase&&) = delete; std::string toString() const; protected: CATCH_DESTRUCTOR_CONSTEXPR virtual ~MatcherUntypedBase() = default; //! Should be overridden, but we provide default "undescribed" impl virtual std::string describe() const; }; template class MatcherBase : public MatcherUntypedBase { public: virtual bool match( T const& arg ) const = 0; }; namespace Detail { template class MatchAllOf final : public MatcherBase { std::vector const*> m_matchers; public: MatchAllOf() = default; MatchAllOf(MatchAllOf const&) = delete; MatchAllOf& operator=(MatchAllOf const&) = delete; MatchAllOf(MatchAllOf&&) = default; MatchAllOf& operator=(MatchAllOf&&) = default; bool match( ArgT const& arg ) const override { for( auto matcher : m_matchers ) { if (!matcher->match(arg)) return false; } return true; } std::string describe() const override { std::string description; description.reserve( 4 + m_matchers.size()*32 ); description += "( "; bool first = true; for( auto matcher : m_matchers ) { if( first ) first = false; else description += " and "; description += matcher->toString(); } description += " )"; return description; } friend MatchAllOf operator&&( MatchAllOf&& lhs, MatcherBase const& rhs CATCH_ATTR_LIFETIMEBOUND ) { lhs.m_matchers.push_back(&rhs); return CATCH_MOVE(lhs); } friend MatchAllOf operator&&( MatcherBase const& lhs CATCH_ATTR_LIFETIMEBOUND, MatchAllOf&& rhs ) { rhs.m_matchers.insert(rhs.m_matchers.begin(), &lhs); return CATCH_MOVE(rhs); } }; //! lvalue overload is intentionally deleted, users should //! not be trying to compose stored composition matchers template MatchAllOf operator&& (MatchAllOf const& lhs, MatcherBase const& rhs) = delete; //! lvalue overload is intentionally deleted, users should //! not be trying to compose stored composition matchers template MatchAllOf operator&& (MatcherBase const& lhs, MatchAllOf const& rhs) = delete; template class MatchAnyOf final : public MatcherBase { std::vector const*> m_matchers; public: MatchAnyOf() = default; MatchAnyOf(MatchAnyOf const&) = delete; MatchAnyOf& operator=(MatchAnyOf const&) = delete; MatchAnyOf(MatchAnyOf&&) = default; MatchAnyOf& operator=(MatchAnyOf&&) = default; bool match( ArgT const& arg ) const override { for( auto matcher : m_matchers ) { if (matcher->match(arg)) return true; } return false; } std::string describe() const override { std::string description; description.reserve( 4 + m_matchers.size()*32 ); description += "( "; bool first = true; for( auto matcher : m_matchers ) { if( first ) first = false; else description += " or "; description += matcher->toString(); } description += " )"; return description; } friend MatchAnyOf operator||( MatchAnyOf&& lhs, MatcherBase const& rhs CATCH_ATTR_LIFETIMEBOUND ) { lhs.m_matchers.push_back(&rhs); return CATCH_MOVE(lhs); } friend MatchAnyOf operator||( MatcherBase const& lhs CATCH_ATTR_LIFETIMEBOUND, MatchAnyOf&& rhs ) { rhs.m_matchers.insert(rhs.m_matchers.begin(), &lhs); return CATCH_MOVE(rhs); } }; //! lvalue overload is intentionally deleted, users should //! not be trying to compose stored composition matchers template MatchAnyOf operator|| (MatchAnyOf const& lhs, MatcherBase const& rhs) = delete; //! lvalue overload is intentionally deleted, users should //! not be trying to compose stored composition matchers template MatchAnyOf operator|| (MatcherBase const& lhs, MatchAnyOf const& rhs) = delete; template class MatchNotOf final : public MatcherBase { MatcherBase const& m_underlyingMatcher; public: explicit MatchNotOf( MatcherBase const& underlyingMatcher CATCH_ATTR_LIFETIMEBOUND ): m_underlyingMatcher( underlyingMatcher ) {} bool match( ArgT const& arg ) const override { return !m_underlyingMatcher.match( arg ); } std::string describe() const override { return "not " + m_underlyingMatcher.toString(); } }; } // namespace Detail template Detail::MatchAllOf operator&&( MatcherBase const& lhs CATCH_ATTR_LIFETIMEBOUND, MatcherBase const& rhs CATCH_ATTR_LIFETIMEBOUND ) { return Detail::MatchAllOf{} && lhs && rhs; } template Detail::MatchAnyOf operator||( MatcherBase const& lhs CATCH_ATTR_LIFETIMEBOUND, MatcherBase const& rhs CATCH_ATTR_LIFETIMEBOUND ) { return Detail::MatchAnyOf{} || lhs || rhs; } template Detail::MatchNotOf operator!( MatcherBase const& matcher CATCH_ATTR_LIFETIMEBOUND ) { return Detail::MatchNotOf{ matcher }; } } // namespace Matchers } // namespace Catch #if defined(CATCH_CONFIG_PREFIX_ALL) && !defined(CATCH_CONFIG_DISABLE) #define CATCH_REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "CATCH_REQUIRE_THROWS_WITH", Catch::ResultDisposition::Normal, matcher, expr ) #define CATCH_REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "CATCH_REQUIRE_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::Normal, matcher, expr ) #define CATCH_CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "CATCH_CHECK_THROWS_WITH", Catch::ResultDisposition::ContinueOnFailure, matcher, expr ) #define CATCH_CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "CATCH_CHECK_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::ContinueOnFailure, matcher, expr ) #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) #define CATCH_REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) (void)(0) #define CATCH_CHECK_THROWS_WITH( expr, matcher ) (void)(0) #define CATCH_CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) (void)(0) #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 ) #define REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "REQUIRE_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::Normal, matcher, expr ) #define CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "CHECK_THROWS_WITH", Catch::ResultDisposition::ContinueOnFailure, matcher, expr ) #define CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "CHECK_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::ContinueOnFailure, matcher, expr ) #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) #define REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) (void)(0) #define CHECK_THROWS_WITH( expr, matcher ) (void)(0) #define CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) (void)(0) #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