// Copyright Catch2 Authors // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // https://www.boost.org/LICENSE_1_0.txt) // SPDX-License-Identifier: BSL-1.0 #ifndef CATCH_MATCHERS_HPP_INCLUDED #define CATCH_MATCHERS_HPP_INCLUDED #include #include #include #include namespace Catch { namespace Matchers { class MatcherUntypedBase { public: MatcherUntypedBase() = default; MatcherUntypedBase(MatcherUntypedBase const&) = default; MatcherUntypedBase(MatcherUntypedBase&&) = default; MatcherUntypedBase& operator = (MatcherUntypedBase const&) = delete; MatcherUntypedBase& operator = (MatcherUntypedBase&&) = delete; std::string toString() const; protected: virtual ~MatcherUntypedBase(); // = default; virtual std::string describe() const = 0; mutable std::string m_cachedToString; }; 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) { lhs.m_matchers.push_back(&rhs); return CATCH_MOVE(lhs); } friend MatchAllOf operator&& (MatcherBase const& lhs, 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) { lhs.m_matchers.push_back(&rhs); return CATCH_MOVE(lhs); } friend MatchAnyOf operator|| (MatcherBase const& lhs, 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 ): 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, MatcherBase const& rhs) { return Detail::MatchAllOf{} && lhs && rhs; } template Detail::MatchAnyOf operator|| (MatcherBase const& lhs, MatcherBase const& rhs) { return Detail::MatchAnyOf{} || lhs || rhs; } template Detail::MatchNotOf operator! (MatcherBase const& matcher) { 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 ) #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) #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 ) #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) #endif // end of user facing macro declarations #endif // CATCH_MATCHERS_HPP_INCLUDED