From 3bc47ea8fc0c767672f8e41103984ccebcdad438 Mon Sep 17 00:00:00 2001 From: Dvir Yitzchaki Date: Wed, 27 Feb 2019 23:01:57 +0200 Subject: [PATCH] CRTP matchers, Closes #1553 --- .gitignore | 3 + docs/matchers.md | 10 +- src/CMakeLists.txt | 2 - src/catch2/catch_capture_matchers.cpp | 24 -- src/catch2/catch_capture_matchers.h | 24 +- src/catch2/catch_common.h | 17 ++ src/catch2/catch_matchers.cpp | 28 -- src/catch2/catch_matchers.h | 250 +++++++++++------- src/catch2/catch_matchers_exception.hpp | 6 +- src/catch2/catch_matchers_floating.h | 18 +- src/catch2/catch_matchers_generic.hpp | 21 +- src/catch2/catch_matchers_string.cpp | 18 -- src/catch2/catch_matchers_string.h | 49 +++- src/catch2/catch_matchers_vector.h | 30 +-- src/catch2/catch_objc.hpp | 18 +- src/catch2/reporters/catch_reporter_tap.hpp | 2 +- .../reporters/catch_reporter_teamcity.hpp | 2 +- tests/ExtraTests/X01-PrefixedMacros.cpp | 4 +- .../Baselines/automake.sw.approved.txt | 1 + .../Baselines/compact.sw.approved.txt | 11 +- .../Baselines/console.std.approved.txt | 4 +- .../Baselines/console.sw.approved.txt | 25 +- .../SelfTest/Baselines/junit.sw.approved.txt | 3 +- .../Baselines/sonarqube.sw.approved.txt | 1 + tests/SelfTest/Baselines/tap.sw.approved.txt | 14 +- .../Baselines/teamcity.sw.approved.txt | 2 + tests/SelfTest/Baselines/xml.sw.approved.txt | 25 +- tests/SelfTest/UsageTests/Matchers.tests.cpp | 27 +- 28 files changed, 354 insertions(+), 285 deletions(-) delete mode 100644 src/catch2/catch_capture_matchers.cpp delete mode 100644 src/catch2/catch_matchers.cpp diff --git a/.gitignore b/.gitignore index f017e9e09f..588044080c 100644 --- a/.gitignore +++ b/.gitignore @@ -28,3 +28,6 @@ Build cmake-build-* benchmark-dir .conan/test_package/build +_*/ +.vscode/ +.history/ diff --git a/docs/matchers.md b/docs/matchers.md index bdb7dac473..91fff807b2 100644 --- a/docs/matchers.md +++ b/docs/matchers.md @@ -147,9 +147,9 @@ REQUIRE_THROWS_MATCHES(throwsDerivedException(), DerivedException, Message("De It's easy to provide your own matchers to extend Catch or just to work with your own types. You need to provide two things: -1. A matcher class, derived from `Catch::MatcherBase` - where `T` is the type being tested. +1. A matcher class, derived from `Catch::MatcherBase` - where `T` is the matcher class. The constructor takes and stores any arguments needed (e.g. something to compare against) and you must -override two methods: `match()` and `describe()`. +provide two methods: `match()` and `describe()`. 2. A simple builder function. This is what is actually called from the test code and allows overloading. Here's an example for asserting that an integer falls within a given range @@ -157,13 +157,13 @@ Here's an example for asserting that an integer falls within a given range ```c++ // The matcher class -class IntRange : public Catch::MatcherBase { +class IntRange : public Catch::MatcherBase { int m_begin, m_end; public: IntRange( int begin, int end ) : m_begin( begin ), m_end( end ) {} // Performs the test for this matcher - bool match( int const& i ) const override { + bool match( int const& i ) const { return i >= m_begin && i <= m_end; } @@ -171,7 +171,7 @@ public: // include any provided data (the begin/ end in this case) and // be written as if it were stating a fact (in the output it will be // preceded by the value under test). - virtual std::string describe() const override { + std::string describe() const { std::ostringstream ss; ss << "is between " << m_begin << " and " << m_end; return ss.str(); diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5ccdeb69a6..9c48bd1981 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -129,7 +129,6 @@ set(IMPL_SOURCES ${SOURCES_DIR}/catch_approx.cpp ${SOURCES_DIR}/catch_assertionhandler.cpp ${SOURCES_DIR}/catch_assertionresult.cpp - ${SOURCES_DIR}/catch_capture_matchers.cpp ${SOURCES_DIR}/catch_commandline.cpp ${SOURCES_DIR}/catch_common.cpp ${SOURCES_DIR}/catch_config.cpp @@ -153,7 +152,6 @@ set(IMPL_SOURCES ${SOURCES_DIR}/catch_interfaces_testcase.cpp ${SOURCES_DIR}/catch_list.cpp ${SOURCES_DIR}/catch_leak_detector.cpp - ${SOURCES_DIR}/catch_matchers.cpp ${SOURCES_DIR}/catch_matchers_exception.cpp ${SOURCES_DIR}/catch_matchers_floating.cpp ${SOURCES_DIR}/catch_matchers_generic.cpp diff --git a/src/catch2/catch_capture_matchers.cpp b/src/catch2/catch_capture_matchers.cpp deleted file mode 100644 index ad51baca45..0000000000 --- a/src/catch2/catch_capture_matchers.cpp +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Created by Phil on 9/8/2017. - * Copyright 2017 Two Blue Cubes Ltd. All rights reserved. - * - * Distributed under the Boost Software License, Version 1.0. (See accompanying - * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - */ -#include -#include - -namespace Catch { - - using StringMatcher = Matchers::Impl::MatcherBase; - - // This is the general overload that takes a any string matcher - // There is another overload, in catch_assertionhandler.h/.cpp, that only takes a string and infers - // the Equals matcher (so the header does not mention matchers) - void handleExceptionMatchExpr( AssertionHandler& handler, StringMatcher const& matcher, StringRef const& matcherString ) { - std::string exceptionMessage = Catch::translateActiveException(); - MatchExpr expr( exceptionMessage, matcher, matcherString ); - handler.handleExpr( expr ); - } - -} // namespace Catch diff --git a/src/catch2/catch_capture_matchers.h b/src/catch2/catch_capture_matchers.h index 3f883a3914..d9945005cf 100644 --- a/src/catch2/catch_capture_matchers.h +++ b/src/catch2/catch_capture_matchers.h @@ -11,18 +11,19 @@ #include #include #include +#include namespace Catch { template class MatchExpr : public ITransientExpression { - ArgT const& m_arg; + ArgT m_arg; MatcherT m_matcher; StringRef m_matcherString; public: - MatchExpr( ArgT const& arg, MatcherT const& matcher, StringRef const& matcherString ) + MatchExpr( ArgT arg, MatcherT const& matcher, StringRef const& matcherString ) : ITransientExpression{ true, matcher.match( arg ) }, - m_arg( arg ), + m_arg( std::forward(arg) ), m_matcher( matcher ), m_matcherString( matcherString ) {} @@ -37,13 +38,20 @@ namespace Catch { } }; - using StringMatcher = Matchers::Impl::MatcherBase; - - void handleExceptionMatchExpr( AssertionHandler& handler, StringMatcher const& matcher, StringRef const& matcherString ); + // This is the general overload that takes a any string matcher + // There is another overload, in catch_assertionhandler.h/.cpp, that only takes a string and infers + // the Equals matcher (so the header does not mention matchers) + template, StringMatcher>::value>::type> + void handleExceptionMatchExpr( AssertionHandler& handler, StringMatcher const& matcher, StringRef const& matcherString ) { + std::string exceptionMessage = Catch::translateActiveException(); + MatchExpr expr( exceptionMessage, matcher, matcherString ); + handler.handleExpr( expr ); + } template - auto makeMatchExpr( ArgT const& arg, MatcherT const& matcher, StringRef const& matcherString ) -> MatchExpr { - return MatchExpr( arg, matcher, matcherString ); + auto makeMatchExpr( ArgT && arg, MatcherT const& matcher, StringRef const& matcherString ) -> MatchExpr { + return MatchExpr( std::forward(arg), matcher, matcherString ); } } // namespace Catch diff --git a/src/catch2/catch_common.h b/src/catch2/catch_common.h index 392576d6c0..827e1591c4 100644 --- a/src/catch2/catch_common.h +++ b/src/catch2/catch_common.h @@ -80,6 +80,23 @@ namespace Catch { T const& operator + ( T const& value, StreamEndStop ) { return value; } + + // backported index_sequnce + template + struct indexSequence + { }; + + template + struct indexSequenceHelper : public indexSequenceHelper + { }; + + template + struct indexSequenceHelper<0U, Next ... > + { using type = indexSequence; }; + + template + using makeIndexSequence = typename indexSequenceHelper::type; + } #define CATCH_INTERNAL_LINEINFO \ diff --git a/src/catch2/catch_matchers.cpp b/src/catch2/catch_matchers.cpp deleted file mode 100644 index df2807964d..0000000000 --- a/src/catch2/catch_matchers.cpp +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Created by Phil Nash on 19/07/2017. - * - * Distributed under the Boost Software License, Version 1.0. (See accompanying - * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - */ - -#include - -namespace Catch { -namespace Matchers { - namespace Impl { - - std::string MatcherUntypedBase::toString() const { - if( m_cachedToString.empty() ) - m_cachedToString = describe(); - return m_cachedToString; - } - - MatcherUntypedBase::~MatcherUntypedBase() = default; - - } // namespace Impl -} // namespace Matchers - -using namespace Matchers; -using Matchers::Impl::MatcherBase; - -} // namespace Catch diff --git a/src/catch2/catch_matchers.h b/src/catch2/catch_matchers.h index 78d9e84e81..67926d6437 100644 --- a/src/catch2/catch_matchers.h +++ b/src/catch2/catch_matchers.h @@ -11,153 +11,203 @@ #include #include -#include +#include namespace Catch { namespace Matchers { namespace Impl { - template struct MatchAllOf; - template struct MatchAnyOf; - template struct MatchNotOf; + template struct MatchAllOf; + template struct MatchAnyOf; + template struct MatchNotOf; - class MatcherUntypedBase { + template + class MatcherBase { public: - MatcherUntypedBase() = default; - MatcherUntypedBase ( MatcherUntypedBase const& ) = default; - MatcherUntypedBase& operator = ( MatcherUntypedBase const& ) = delete; + MatcherBase() = default; + MatcherBase ( MatcherBase const& ) = default; + MatcherBase& operator = ( MatcherBase const& ) = delete; std::string toString() const; + template + MatchAllOf operator && ( Other const& other ) const; + + template + MatchAnyOf operator || ( Other const& other ) const; + + MatchNotOf operator ! () const; + + Derived const& derived() const { return static_cast(*this); } + protected: - virtual ~MatcherUntypedBase(); - virtual std::string describe() const = 0; mutable std::string m_cachedToString; }; -#ifdef __clang__ -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wnon-virtual-dtor" -#endif + template + std::string MatcherBase::toString() const { + if( m_cachedToString.empty() ) + m_cachedToString = derived().describe(); + return m_cachedToString; + } - template - struct MatcherMethod { - virtual bool match( ObjectT const& arg ) const = 0; - }; + template + using Tuple = std::tuple::type>::type ...>; -#if defined(__OBJC__) - // Hack to fix Catch GH issue #1661. Could use id for generic Object support. - // use of const for Object pointers is very uncommon and under ARC it causes some kind of signature mismatch that breaks compilation - template<> - struct MatcherMethod { - virtual bool match( NSString* arg ) const = 0; - }; -#endif + template + struct MatchAllOf : MatcherBase> { + MatchAllOf( Matchers const &... matchers ) : m_matchers{matchers...} + {} -#ifdef __clang__ -# pragma clang diagnostic pop -#endif + template + bool match_helper( ArgT && ) const { + return true; + } - template - struct MatcherBase : MatcherUntypedBase, MatcherMethod { + template + bool match_helper( ArgT && arg, Matcher &&matcher, Rest &&... rest ) const { + if (!matcher.match(std::forward(arg))) { + return false; + } + return match_helper(std::forward(arg), std::forward(rest)...); + } - MatchAllOf operator && ( MatcherBase const& other ) const; - MatchAnyOf operator || ( MatcherBase const& other ) const; - MatchNotOf operator ! () const; - }; + template + bool match_impl( ArgT && arg, indexSequence) const { + return match_helper(std::forward(arg), std::get(m_matchers)...); + } - template - struct MatchAllOf : MatcherBase { - bool match( ArgT const& arg ) const override { - for( auto matcher : m_matchers ) { - if (!matcher->match(arg)) - return false; - } - return true; + template + bool match( ArgT && arg ) const { + return match_impl(std::forward(arg), makeIndexSequence{}); } - std::string describe() const override { + + std::string describe_helper() const { return {}; } + + template + std::string describe_helper( Matcher &&matcher, Rest &&... rest ) const { + return " and " + matcher.describe() + describe_helper(std::forward(rest)...); + } + + template + std::string describe_impl( indexSequence) const { + // remove first and + return describe_helper(std::get(m_matchers)...).substr(5); + } + + std::string describe() const { 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 += " )"; + description.reserve( 4 + sizeof...(Matchers)*32 ); + description += "( " + describe_impl(makeIndexSequence{}) + " )"; return description; } - MatchAllOf& operator && ( MatcherBase const& other ) { - m_matchers.push_back( &other ); - return *this; + template + MatchAllOf and_helper(Other const &other, indexSequence) { + return {std::get(m_matchers)..., other}; + } + + template + MatchAllOf operator && ( Other const& other ) { + return and_helper(other, makeIndexSequence()); } - std::vector const*> m_matchers; + Tuple m_matchers; }; - template - struct MatchAnyOf : MatcherBase { - - bool match( ArgT const& arg ) const override { - for( auto matcher : m_matchers ) { - if (matcher->match(arg)) - return true; - } - return false; + + template + struct MatchAnyOf : MatcherBase> { + MatchAnyOf( Matchers const &... matchers ) : m_matchers{matchers...} + {} + + template + bool match_helper( ArgT && ) const { + return false; + } + + template + bool match_helper( ArgT && arg, Matcher &&matcher, Rest &&... rest ) const { + if (matcher.match(std::forward(arg))) { + return true; + } + + return match_helper(std::forward(arg), std::forward(rest)...); + } + + template + bool match_impl( ArgT && arg, indexSequence) const { + return match_helper(std::forward(arg), std::get(m_matchers)...); } - std::string describe() const override { + + template + bool match( ArgT && arg ) const { + return match_impl(std::forward(arg), makeIndexSequence{}); + } + + std::string describe_helper() const { return {}; } + + template + std::string describe_helper( Matcher &&matcher, Rest &&... rest ) const { + return " or " + matcher.describe() + describe_helper(std::forward(rest)...); + } + + template + std::string describe_impl( indexSequence) const { + // remove first or + return describe_helper(std::get(m_matchers)...).substr(4); + } + + std::string describe() const { 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 += " )"; + description.reserve( 4 + sizeof...(Matchers)*32 ); + description += "( " + describe_impl(makeIndexSequence{}) + " )"; return description; } - MatchAnyOf& operator || ( MatcherBase const& other ) { - m_matchers.push_back( &other ); - return *this; + template + MatchAnyOf or_helper(Other const &other, indexSequence) { + return {std::get(m_matchers)..., other}; + } + + template + MatchAnyOf operator || ( Other const& other ) { + return or_helper(other, makeIndexSequence()); } - std::vector const*> m_matchers; + Tuple m_matchers; }; - template - struct MatchNotOf : MatcherBase { + template + struct MatchNotOf : MatcherBase> { - MatchNotOf( MatcherBase const& underlyingMatcher ) : m_underlyingMatcher( underlyingMatcher ) {} + MatchNotOf( Matcher const& underlyingMatcher ) : m_underlyingMatcher( underlyingMatcher ) {} - bool match( ArgT const& arg ) const override { - return !m_underlyingMatcher.match( arg ); + template + bool match( ArgT && arg ) const { + return !m_underlyingMatcher.match( std::forward(arg) ); } - std::string describe() const override { + std::string describe() const { return "not " + m_underlyingMatcher.toString(); } - MatcherBase const& m_underlyingMatcher; + Matcher const& m_underlyingMatcher; }; - template - MatchAllOf MatcherBase::operator && ( MatcherBase const& other ) const { - return MatchAllOf() && *this && other; + template + template + MatchAllOf MatcherBase::operator && ( Other const& other ) const { + return {derived(), other}; } - template - MatchAnyOf MatcherBase::operator || ( MatcherBase const& other ) const { - return MatchAnyOf() || *this || other; + + template + template + MatchAnyOf MatcherBase::operator || ( Other const& other ) const { + return {derived(), other}; } - template - MatchNotOf MatcherBase::operator ! () const { - return MatchNotOf( *this ); + + template + MatchNotOf MatcherBase::operator ! () const { + return {derived()}; } } // namespace Impl diff --git a/src/catch2/catch_matchers_exception.hpp b/src/catch2/catch_matchers_exception.hpp index b0f3d32d67..dc30542d3d 100644 --- a/src/catch2/catch_matchers_exception.hpp +++ b/src/catch2/catch_matchers_exception.hpp @@ -13,7 +13,7 @@ namespace Catch { namespace Matchers { namespace Exception { -class ExceptionMessageMatcher : public MatcherBase { +class ExceptionMessageMatcher : public MatcherBase { std::string m_message; public: @@ -21,9 +21,9 @@ class ExceptionMessageMatcher : public MatcherBase { m_message(message) {} - bool match(std::exception const& ex) const override; + bool match(std::exception const& ex) const; - std::string describe() const override; + std::string describe() const; }; } // namespace Exception diff --git a/src/catch2/catch_matchers_floating.h b/src/catch2/catch_matchers_floating.h index dc1bebe040..0bf8e7e650 100644 --- a/src/catch2/catch_matchers_floating.h +++ b/src/catch2/catch_matchers_floating.h @@ -16,19 +16,19 @@ namespace Matchers { enum class FloatingPointKind : uint8_t; - struct WithinAbsMatcher : MatcherBase { + struct WithinAbsMatcher : MatcherBase { WithinAbsMatcher(double target, double margin); - bool match(double const& matchee) const override; - std::string describe() const override; + bool match(double const& matchee) const; + std::string describe() const; private: double m_target; double m_margin; }; - struct WithinUlpsMatcher : MatcherBase { + struct WithinUlpsMatcher : MatcherBase { WithinUlpsMatcher(double target, uint64_t ulps, FloatingPointKind baseType); - bool match(double const& matchee) const override; - std::string describe() const override; + bool match(double const& matchee) const; + std::string describe() const; private: double m_target; uint64_t m_ulps; @@ -41,10 +41,10 @@ namespace Matchers { // |lhs - rhs| <= epsilon * max(fabs(lhs), fabs(rhs)), then we get // the same result if we do this for floats, as if we do this for // doubles that were promoted from floats. - struct WithinRelMatcher : MatcherBase { + struct WithinRelMatcher : MatcherBase { WithinRelMatcher(double target, double epsilon); - bool match(double const& matchee) const override; - std::string describe() const override; + bool match(double const& matchee) const; + std::string describe() const; private: double m_target; double m_epsilon; diff --git a/src/catch2/catch_matchers_generic.hpp b/src/catch2/catch_matchers_generic.hpp index d39d1bbed8..a85955bd69 100644 --- a/src/catch2/catch_matchers_generic.hpp +++ b/src/catch2/catch_matchers_generic.hpp @@ -22,8 +22,8 @@ namespace Detail { std::string finalizeDescription(const std::string& desc); } -template -class PredicateMatcher : public MatcherBase { +template +class PredicateMatcher : public MatcherBase> { Predicate m_predicate; std::string m_description; public: @@ -33,11 +33,14 @@ class PredicateMatcher : public MatcherBase { m_description(Detail::finalizeDescription(descr)) {} - bool match( T const& item ) const override { - return m_predicate(item); + template + bool match( ArgT && item ) const { + static_assert(is_callable::value, "Predicate not callable with argument T"); + static_assert(std::is_same>::value, "Predicate does not return bool"); + return m_predicate(std::forward(item)); } - std::string describe() const override { + std::string describe() const { return m_description; } }; @@ -48,11 +51,9 @@ class PredicateMatcher : public MatcherBase { // The user has to explicitly specify type to the function, because // inferring std::function is hard (but possible) and // requires a lot of TMP. - template - Generic::PredicateMatcher Predicate(Pred&& predicate, std::string const& description = "") { - static_assert(is_callable::value, "Predicate not callable with argument T"); - static_assert(std::is_same>::value, "Predicate does not return bool"); - return Generic::PredicateMatcher(std::forward(predicate), description); + template + Generic::PredicateMatcher Predicate(Pred&& predicate, std::string const& description = "") { + return Generic::PredicateMatcher(std::forward(predicate), description); } } // namespace Matchers diff --git a/src/catch2/catch_matchers_string.cpp b/src/catch2/catch_matchers_string.cpp index 024cf54919..cc96040ba0 100644 --- a/src/catch2/catch_matchers_string.cpp +++ b/src/catch2/catch_matchers_string.cpp @@ -32,24 +32,6 @@ namespace Matchers { : std::string(); } - - StringMatcherBase::StringMatcherBase( std::string const& operation, CasedString const& comparator ) - : m_comparator( comparator ), - m_operation( operation ) { - } - - std::string StringMatcherBase::describe() const { - std::string description; - description.reserve(5 + m_operation.size() + m_comparator.m_str.size() + - m_comparator.caseSensitivitySuffix().size()); - description += m_operation; - description += ": \""; - description += m_comparator.m_str; - description += "\""; - description += m_comparator.caseSensitivitySuffix(); - return description; - } - EqualsMatcher::EqualsMatcher( CasedString const& comparator ) : StringMatcherBase( "equals", comparator ) {} bool EqualsMatcher::match( std::string const& source ) const { diff --git a/src/catch2/catch_matchers_string.h b/src/catch2/catch_matchers_string.h index 075a7e9498..51ac62223a 100644 --- a/src/catch2/catch_matchers_string.h +++ b/src/catch2/catch_matchers_string.h @@ -27,42 +27,63 @@ namespace Matchers { std::string m_str; }; - struct StringMatcherBase : MatcherBase { + template + struct StringMatcherBase : MatcherBase { StringMatcherBase( std::string const& operation, CasedString const& comparator ); - std::string describe() const override; + std::string describe() const ; CasedString m_comparator; std::string m_operation; }; - struct EqualsMatcher : StringMatcherBase { + + template + StringMatcherBase::StringMatcherBase( std::string const& operation, CasedString const& comparator ) + : m_comparator( comparator ), + m_operation( operation ) { + } + + template + std::string StringMatcherBase::describe() const { + std::string description; + description.reserve(5 + m_operation.size() + m_comparator.m_str.size() + + m_comparator.caseSensitivitySuffix().size()); + description += m_operation; + description += ": \""; + description += m_comparator.m_str; + description += "\""; + description += m_comparator.caseSensitivitySuffix(); + return description; + } + + struct EqualsMatcher : StringMatcherBase { EqualsMatcher( CasedString const& comparator ); - bool match( std::string const& source ) const override; + bool match( std::string const& source ) const ; }; - struct ContainsMatcher : StringMatcherBase { + struct ContainsMatcher : StringMatcherBase { ContainsMatcher( CasedString const& comparator ); - bool match( std::string const& source ) const override; + bool match( std::string const& source ) const ; }; - struct StartsWithMatcher : StringMatcherBase { + struct StartsWithMatcher : StringMatcherBase { StartsWithMatcher( CasedString const& comparator ); - bool match( std::string const& source ) const override; + bool match( std::string const& source ) const ; }; - struct EndsWithMatcher : StringMatcherBase { + struct EndsWithMatcher : StringMatcherBase { EndsWithMatcher( CasedString const& comparator ); - bool match( std::string const& source ) const override; + bool match( std::string const& source ) const ; }; - struct RegexMatcher : MatcherBase { + struct RegexMatcher : MatcherBase { RegexMatcher( std::string regex, CaseSensitive::Choice caseSensitivity ); - bool match( std::string const& matchee ) const override; - std::string describe() const override; + bool match( std::string const& matchee ) const ; + std::string describe() const ; private: std::string m_regex; CaseSensitive::Choice m_caseSensitivity; }; - } // namespace StdString + } // namespace StdString` // The following functions create the actual matcher objects. diff --git a/src/catch2/catch_matchers_vector.h b/src/catch2/catch_matchers_vector.h index 86fb2214c5..c4e1fd2284 100644 --- a/src/catch2/catch_matchers_vector.h +++ b/src/catch2/catch_matchers_vector.h @@ -18,11 +18,11 @@ namespace Matchers { namespace Vector { template - struct ContainsElementMatcher : MatcherBase> { + struct ContainsElementMatcher : MatcherBase> { ContainsElementMatcher(T const &comparator) : m_comparator( comparator) {} - bool match(std::vector const &v) const override { + bool match(std::vector const &v) const { for (auto const& el : v) { if (el == m_comparator) { return true; @@ -31,7 +31,7 @@ namespace Matchers { return false; } - std::string describe() const override { + std::string describe() const { return "Contains: " + ::Catch::Detail::stringify( m_comparator ); } @@ -39,11 +39,11 @@ namespace Matchers { }; template - struct ContainsMatcher : MatcherBase> { + struct ContainsMatcher : MatcherBase> { ContainsMatcher(std::vector const &comparator) : m_comparator( comparator ) {} - bool match(std::vector const &v) const override { + bool match(std::vector const &v) const { // !TBD: see note in EqualsMatcher if (m_comparator.size() > v.size()) return false; @@ -61,7 +61,7 @@ namespace Matchers { } return true; } - std::string describe() const override { + std::string describe() const { return "Contains: " + ::Catch::Detail::stringify( m_comparator ); } @@ -69,11 +69,11 @@ namespace Matchers { }; template - struct EqualsMatcher : MatcherBase> { + struct EqualsMatcher : MatcherBase> { EqualsMatcher(std::vector const &comparator) : m_comparator( comparator ) {} - bool match(std::vector const &v) const override { + bool match(std::vector const &v) const { // !TBD: This currently works if all elements can be compared using != // - a more general approach would be via a compare template that defaults // to using !=. but could be specialised for, e.g. std::vector etc @@ -85,18 +85,18 @@ namespace Matchers { return false; return true; } - std::string describe() const override { + std::string describe() const { return "Equals: " + ::Catch::Detail::stringify( m_comparator ); } std::vector const& m_comparator; }; template - struct ApproxMatcher : MatcherBase> { + struct ApproxMatcher : MatcherBase> { ApproxMatcher(std::vector const& comparator) : m_comparator( comparator ) {} - bool match(std::vector const &v) const override { + bool match(std::vector const &v) const { if (m_comparator.size() != v.size()) return false; for (std::size_t i = 0; i < v.size(); ++i) @@ -104,7 +104,7 @@ namespace Matchers { return false; return true; } - std::string describe() const override { + std::string describe() const { return "is approx: " + ::Catch::Detail::stringify( m_comparator ); } template ::value>> @@ -128,9 +128,9 @@ namespace Matchers { }; template - struct UnorderedEqualsMatcher : MatcherBase> { + struct UnorderedEqualsMatcher : MatcherBase> { UnorderedEqualsMatcher(std::vector const& target) : m_target(target) {} - bool match(std::vector const& vec) const override { + bool match(std::vector const& vec) const { // Note: This is a reimplementation of std::is_permutation, // because I don't want to include inside the common path if (m_target.size() != vec.size()) { @@ -139,7 +139,7 @@ namespace Matchers { return std::is_permutation(m_target.begin(), m_target.end(), vec.begin()); } - std::string describe() const override { + std::string describe() const { return "UnorderedEquals: " + ::Catch::Detail::stringify(m_target); } private: diff --git a/src/catch2/catch_objc.hpp b/src/catch2/catch_objc.hpp index 6484e321e5..159fd97dd0 100644 --- a/src/catch2/catch_objc.hpp +++ b/src/catch2/catch_objc.hpp @@ -108,14 +108,14 @@ namespace Catch { namespace Impl { namespace NSStringMatchers { - struct StringHolder : MatcherBase{ + struct StringHolder : MatcherBase{ StringHolder( NSString* substr ) : m_substr( [substr copy] ){} StringHolder( StringHolder const& other ) : m_substr( [other.m_substr copy] ){} StringHolder() { arcSafeRelease( m_substr ); } - bool match( NSString* str ) const override { + bool match( NSString* str ) const { return false; } @@ -125,12 +125,12 @@ namespace Catch { struct Equals : StringHolder { Equals( NSString* substr ) : StringHolder( substr ){} - bool match( NSString* str ) const override { + bool match( NSString* str ) const { return (str != nil || m_substr == nil ) && [str isEqualToString:m_substr]; } - std::string describe() const override { + std::string describe() const { return "equals string: " + Catch::Detail::stringify( m_substr ); } }; @@ -143,7 +143,7 @@ namespace Catch { [str rangeOfString:m_substr].location != NSNotFound; } - std::string describe() const override { + std::string describe() const { return "contains string: " + Catch::Detail::stringify( m_substr ); } }; @@ -151,24 +151,24 @@ namespace Catch { struct StartsWith : StringHolder { StartsWith( NSString* substr ) : StringHolder( substr ){} - bool match( NSString* str ) const override { + bool match( NSString* str ) const { return (str != nil || m_substr == nil ) && [str rangeOfString:m_substr].location == 0; } - std::string describe() const override { + std::string describe() const { return "starts with: " + Catch::Detail::stringify( m_substr ); } }; struct EndsWith : StringHolder { EndsWith( NSString* substr ) : StringHolder( substr ){} - bool match( NSString* str ) const override { + bool match( NSString* str ) const { return (str != nil || m_substr == nil ) && [str rangeOfString:m_substr].location == [str length] - [m_substr length]; } - std::string describe() const override { + std::string describe() const { return "ends with: " + Catch::Detail::stringify( m_substr ); } }; diff --git a/src/catch2/reporters/catch_reporter_tap.hpp b/src/catch2/reporters/catch_reporter_tap.hpp index 1ede76fb2c..aee33aea6e 100644 --- a/src/catch2/reporters/catch_reporter_tap.hpp +++ b/src/catch2/reporters/catch_reporter_tap.hpp @@ -24,7 +24,7 @@ namespace Catch { return m_reporterPrefs; } - void noMatchingTestCases(std::string const& spec) override; + void noMatchingTestCases(std::string const& spec); void assertionStarting( AssertionInfo const& ) override {} diff --git a/src/catch2/reporters/catch_reporter_teamcity.hpp b/src/catch2/reporters/catch_reporter_teamcity.hpp index da54c69a7c..77d74f9747 100644 --- a/src/catch2/reporters/catch_reporter_teamcity.hpp +++ b/src/catch2/reporters/catch_reporter_teamcity.hpp @@ -33,7 +33,7 @@ namespace Catch { void skipTest( TestCaseInfo const& /* testInfo */ ) override {} - void noMatchingTestCases( std::string const& /* spec */ ) override {} + void nomatchingTestCases( std::string const& /* spec */ ) {} void testGroupStarting(GroupInfo const& groupInfo) override; void testGroupEnded(TestGroupStats const& testGroupStats) override; diff --git a/tests/ExtraTests/X01-PrefixedMacros.cpp b/tests/ExtraTests/X01-PrefixedMacros.cpp index 40b9897806..e7958bb4ca 100644 --- a/tests/ExtraTests/X01-PrefixedMacros.cpp +++ b/tests/ExtraTests/X01-PrefixedMacros.cpp @@ -26,7 +26,7 @@ CATCH_TEST_CASE("PrefixedMacros") { CATCH_REQUIRE_THROWS(this_throws()); CATCH_REQUIRE_THROWS_AS(this_throws(), std::runtime_error); CATCH_REQUIRE_THROWS_WITH(this_throws(), "Some msg"); - CATCH_REQUIRE_THROWS_MATCHES(this_throws(), std::runtime_error, Predicate([](std::runtime_error const&) { return true; })); + CATCH_REQUIRE_THROWS_MATCHES(this_throws(), std::runtime_error, Predicate([](std::runtime_error const&) { return true; })); CATCH_REQUIRE_NOTHROW(this_doesnt_throw()); CATCH_CHECK( 1 == 1 ); @@ -42,7 +42,7 @@ CATCH_TEST_CASE("PrefixedMacros") { CATCH_CHECK_THROWS(this_throws()); CATCH_CHECK_THROWS_AS(this_throws(), std::runtime_error); CATCH_CHECK_THROWS_WITH(this_throws(), "Some msg"); - CATCH_CHECK_THROWS_MATCHES(this_throws(), std::runtime_error, Predicate([](std::runtime_error const&) { return true; })); + CATCH_CHECK_THROWS_MATCHES(this_throws(), std::runtime_error, Predicate([](std::runtime_error const&) { return true; })); CATCH_CHECK_NOTHROW(this_doesnt_throw()); CATCH_REQUIRE_THAT("abcd", Equals("abcd")); diff --git a/tests/SelfTest/Baselines/automake.sw.approved.txt b/tests/SelfTest/Baselines/automake.sw.approved.txt index 035a92f2f2..7169655cf3 100644 --- a/tests/SelfTest/Baselines/automake.sw.approved.txt +++ b/tests/SelfTest/Baselines/automake.sw.approved.txt @@ -260,6 +260,7 @@ loose text artifact :test-result: FAIL more nested SECTION tests :test-result: PASS nested SECTION tests :test-result: PASS non streamable - with conv. op +:test-result: PASS non-const access :test-result: PASS non-copyable objects :test-result: PASS normal_cdf :test-result: PASS normal_quantile diff --git a/tests/SelfTest/Baselines/compact.sw.approved.txt b/tests/SelfTest/Baselines/compact.sw.approved.txt index 5f9e6a9fb0..b8ef5e8400 100644 --- a/tests/SelfTest/Baselines/compact.sw.approved.txt +++ b/tests/SelfTest/Baselines/compact.sw.approved.txt @@ -234,10 +234,10 @@ Approx.tests.cpp:: passed: 0 == Approx( dZero) for: 0 == Approx( 0. Approx.tests.cpp:: passed: 0 == Approx( dSmall ).margin( 0.001 ) for: 0 == Approx( 0.00001 ) Approx.tests.cpp:: passed: 1.234f == Approx( dMedium ) for: 1.234f == Approx( 1.234 ) Approx.tests.cpp:: passed: dMedium == Approx( 1.234f ) for: 1.234 == Approx( 1.2339999676 ) -Matchers.tests.cpp:: passed: 1, Predicate(alwaysTrue, "always true") for: 1 matches predicate: "always true" -Matchers.tests.cpp:: passed: 1, !Predicate(alwaysFalse, "always false") for: 1 not matches predicate: "always false" -Matchers.tests.cpp:: passed: "Hello olleH", Predicate( [] (std::string const& str) -> bool { return str.front() == str.back(); }, "First and last character should be equal") for: "Hello olleH" matches predicate: "First and last character should be equal" -Matchers.tests.cpp:: passed: "This wouldn't pass", !Predicate( [] (std::string const& str) -> bool { return str.front() == str.back(); } ) for: "This wouldn't pass" not matches undescribed predicate +Matchers.tests.cpp:: passed: 1, Predicate(alwaysTrue, "always true") for: 1 matches predicate: "always true" +Matchers.tests.cpp:: passed: 1, !Predicate(alwaysFalse, "always false") for: 1 not matches predicate: "always false" +Matchers.tests.cpp:: passed: "Hello olleH", Predicate( [] (std::string const& str) -> bool { return str.front() == str.back(); }, "First and last character should be equal") for: "Hello olleH" matches predicate: "First and last character should be equal" +Matchers.tests.cpp:: passed: "This wouldn't pass", !Predicate( [] (std::string const& str) -> bool { return str.front() == str.back(); } ) for: "This wouldn't pass" not matches undescribed predicate Tricky.tests.cpp:: passed: true Tricky.tests.cpp:: passed: true Tricky.tests.cpp:: passed: true @@ -1040,7 +1040,7 @@ ToStringGeneral.tests.cpp:: passed: str1.size() == 3 + 5 for: 8 == ToStringGeneral.tests.cpp:: passed: str2.size() == 3 + 10 for: 13 == 13 ToStringGeneral.tests.cpp:: passed: str1.size() == 2 + 5 for: 7 == 7 ToStringGeneral.tests.cpp:: passed: str2.size() == 2 + 15 for: 17 == 17 -Matchers.tests.cpp:: passed: "foo", Predicate([] (const char* const&) { return true; }) for: "foo" matches undescribed predicate +Matchers.tests.cpp:: passed: "foo", Predicate([] (const char* const&) { return true; }) for: "foo" matches undescribed predicate CmdLine.tests.cpp:: passed: result for: {?} CmdLine.tests.cpp:: passed: config.processName == "" for: "" == "" CmdLine.tests.cpp:: passed: result for: {?} @@ -1692,6 +1692,7 @@ Misc.tests.cpp:: passed: a != b for: 1 != 2 Misc.tests.cpp:: passed: b != a for: 2 != 1 Misc.tests.cpp:: passed: a != b for: 1 != 2 Tricky.tests.cpp:: passed: s == "7" for: "7" == "7" +Matchers.tests.cpp:: passed: s, Predicate([](S &s){ return s.value() == 42;}) for: {?} matches undescribed predicate Tricky.tests.cpp:: passed: ti == typeid(int) for: {?} == {?} InternalBenchmark.tests.cpp:: passed: normal_cdf(0.000000) == Approx(0.50000000000000000) for: 0.5 == Approx( 0.5 ) InternalBenchmark.tests.cpp:: passed: normal_cdf(1.000000) == Approx(0.84134474606854293) for: 0.8413447461 == Approx( 0.8413447461 ) diff --git a/tests/SelfTest/Baselines/console.std.approved.txt b/tests/SelfTest/Baselines/console.std.approved.txt index 140a0b8a1b..b5dd9229f0 100644 --- a/tests/SelfTest/Baselines/console.std.approved.txt +++ b/tests/SelfTest/Baselines/console.std.approved.txt @@ -1380,6 +1380,6 @@ due to unexpected exception with message: Why would you throw a std::string? =============================================================================== -test cases: 320 | 246 passed | 70 failed | 4 failed as expected -assertions: 1776 | 1624 passed | 131 failed | 21 failed as expected +test cases: 321 | 247 passed | 70 failed | 4 failed as expected +assertions: 1777 | 1625 passed | 131 failed | 21 failed as expected diff --git a/tests/SelfTest/Baselines/console.sw.approved.txt b/tests/SelfTest/Baselines/console.sw.approved.txt index ea8481d2cf..b6c2d54521 100644 --- a/tests/SelfTest/Baselines/console.sw.approved.txt +++ b/tests/SelfTest/Baselines/console.sw.approved.txt @@ -1862,12 +1862,12 @@ Matchers.tests.cpp: ............................................................................... Matchers.tests.cpp:: PASSED: - REQUIRE_THAT( 1, Predicate(alwaysTrue, "always true") ) + REQUIRE_THAT( 1, Predicate(alwaysTrue, "always true") ) with expansion: 1 matches predicate: "always true" Matchers.tests.cpp:: PASSED: - REQUIRE_THAT( 1, !Predicate(alwaysFalse, "always false") ) + REQUIRE_THAT( 1, !Predicate(alwaysFalse, "always false") ) with expansion: 1 not matches predicate: "always false" @@ -1879,12 +1879,12 @@ Matchers.tests.cpp: ............................................................................... Matchers.tests.cpp:: PASSED: - REQUIRE_THAT( "Hello olleH", Predicate( [] (std::string const& str) -> bool { return str.front() == str.back(); }, "First and last character should be equal") ) + REQUIRE_THAT( "Hello olleH", Predicate( [] (std::string const& str) -> bool { return str.front() == str.back(); }, "First and last character should be equal") ) with expansion: "Hello olleH" matches predicate: "First and last character should be equal" Matchers.tests.cpp:: PASSED: - REQUIRE_THAT( "This wouldn't pass", !Predicate( [] (std::string const& str) -> bool { return str.front() == str.back(); } ) ) + REQUIRE_THAT( "This wouldn't pass", !Predicate( [] (std::string const& str) -> bool { return str.front() == str.back(); } ) ) with expansion: "This wouldn't pass" not matches undescribed predicate @@ -7457,7 +7457,7 @@ Matchers.tests.cpp: ............................................................................... Matchers.tests.cpp:: PASSED: - REQUIRE_THAT( "foo", Predicate([] (const char* const&) { return true; }) ) + REQUIRE_THAT( "foo", Predicate([] (const char* const&) { return true; }) ) with expansion: "foo" matches undescribed predicate @@ -12420,6 +12420,17 @@ Tricky.tests.cpp:: PASSED: with expansion: "7" == "7" +------------------------------------------------------------------------------- +non-const access +------------------------------------------------------------------------------- +Matchers.tests.cpp: +............................................................................... + +Matchers.tests.cpp:: PASSED: + REQUIRE_THAT( s, Predicate([](S &s){ return s.value() == 42;}) ) +with expansion: + {?} matches undescribed predicate + ------------------------------------------------------------------------------- non-copyable objects ------------------------------------------------------------------------------- @@ -13960,6 +13971,6 @@ Misc.tests.cpp: Misc.tests.cpp:: PASSED: =============================================================================== -test cases: 320 | 230 passed | 86 failed | 4 failed as expected -assertions: 1793 | 1624 passed | 148 failed | 21 failed as expected +test cases: 321 | 231 passed | 86 failed | 4 failed as expected +assertions: 1794 | 1625 passed | 148 failed | 21 failed as expected diff --git a/tests/SelfTest/Baselines/junit.sw.approved.txt b/tests/SelfTest/Baselines/junit.sw.approved.txt index 336b7a79c5..59e1200f2c 100644 --- a/tests/SelfTest/Baselines/junit.sw.approved.txt +++ b/tests/SelfTest/Baselines/junit.sw.approved.txt @@ -1,7 +1,7 @@ - + @@ -1564,6 +1564,7 @@ Misc.tests.cpp: + diff --git a/tests/SelfTest/Baselines/sonarqube.sw.approved.txt b/tests/SelfTest/Baselines/sonarqube.sw.approved.txt index b54c147bb3..09ed3f70b2 100644 --- a/tests/SelfTest/Baselines/sonarqube.sw.approved.txt +++ b/tests/SelfTest/Baselines/sonarqube.sw.approved.txt @@ -1200,6 +1200,7 @@ with expansion: Matchers.tests.cpp: + diff --git a/tests/SelfTest/Baselines/tap.sw.approved.txt b/tests/SelfTest/Baselines/tap.sw.approved.txt index 1e679cec1c..aef42abe3e 100644 --- a/tests/SelfTest/Baselines/tap.sw.approved.txt +++ b/tests/SelfTest/Baselines/tap.sw.approved.txt @@ -467,13 +467,13 @@ ok {test-number} - 1.234f == Approx( dMedium ) for: 1.234f == Approx( 1.234 ) # Approximate comparisons with mixed numeric types ok {test-number} - dMedium == Approx( 1.234f ) for: 1.234 == Approx( 1.2339999676 ) # Arbitrary predicate matcher -ok {test-number} - 1, Predicate(alwaysTrue, "always true") for: 1 matches predicate: "always true" +ok {test-number} - 1, Predicate(alwaysTrue, "always true") for: 1 matches predicate: "always true" # Arbitrary predicate matcher -ok {test-number} - 1, !Predicate(alwaysFalse, "always false") for: 1 not matches predicate: "always false" +ok {test-number} - 1, !Predicate(alwaysFalse, "always false") for: 1 not matches predicate: "always false" # Arbitrary predicate matcher -ok {test-number} - "Hello olleH", Predicate( [] (std::string const& str) -> bool { return str.front() == str.back(); }, "First and last character should be equal") for: "Hello olleH" matches predicate: "First and last character should be equal" +ok {test-number} - "Hello olleH", Predicate( [] (std::string const& str) -> bool { return str.front() == str.back(); }, "First and last character should be equal") for: "Hello olleH" matches predicate: "First and last character should be equal" # Arbitrary predicate matcher -ok {test-number} - "This wouldn't pass", !Predicate( [] (std::string const& str) -> bool { return str.front() == str.back(); } ) for: "This wouldn't pass" not matches undescribed predicate +ok {test-number} - "This wouldn't pass", !Predicate( [] (std::string const& str) -> bool { return str.front() == str.back(); } ) for: "This wouldn't pass" not matches undescribed predicate # Assertions then sections ok {test-number} - true # Assertions then sections @@ -2003,7 +2003,7 @@ ok {test-number} - str1.size() == 2 + 5 for: 7 == 7 # Precision of floating point stringification can be set ok {test-number} - str2.size() == 2 + 15 for: 17 == 17 # Predicate matcher can accept const char* -ok {test-number} - "foo", Predicate([] (const char* const&) { return true; }) for: "foo" matches undescribed predicate +ok {test-number} - "foo", Predicate([] (const char* const&) { return true; }) for: "foo" matches undescribed predicate # Process can be configured on command line ok {test-number} - result for: {?} # Process can be configured on command line @@ -3214,6 +3214,8 @@ ok {test-number} - b != a for: 2 != 1 ok {test-number} - a != b for: 1 != 2 # non streamable - with conv. op ok {test-number} - s == "7" for: "7" == "7" +# non-const access +ok {test-number} - s, Predicate([](S &s){ return s.value() == 42;}) for: {?} matches undescribed predicate # non-copyable objects ok {test-number} - ti == typeid(int) for: {?} == {?} # normal_cdf @@ -3578,5 +3580,5 @@ ok {test-number} - q3 == 23. for: 23.0 == 23.0 ok {test-number} - # xmlentitycheck ok {test-number} - -1..1785 +1..1786 diff --git a/tests/SelfTest/Baselines/teamcity.sw.approved.txt b/tests/SelfTest/Baselines/teamcity.sw.approved.txt index 76d6218306..fe61882124 100644 --- a/tests/SelfTest/Baselines/teamcity.sw.approved.txt +++ b/tests/SelfTest/Baselines/teamcity.sw.approved.txt @@ -656,6 +656,8 @@ Misc.tests.cpp:|nexpression failed|n REQUIRE( a == b )|nwith expan ##teamcity[testFinished name='nested SECTION tests' duration="{duration}"] ##teamcity[testStarted name='non streamable - with conv. op'] ##teamcity[testFinished name='non streamable - with conv. op' duration="{duration}"] +##teamcity[testStarted name='non-const access'] +##teamcity[testFinished name='non-const access' duration="{duration}"] ##teamcity[testStarted name='non-copyable objects'] ##teamcity[testFinished name='non-copyable objects' duration="{duration}"] ##teamcity[testStarted name='normal_cdf'] diff --git a/tests/SelfTest/Baselines/xml.sw.approved.txt b/tests/SelfTest/Baselines/xml.sw.approved.txt index a27f88e582..60bbaa6187 100644 --- a/tests/SelfTest/Baselines/xml.sw.approved.txt +++ b/tests/SelfTest/Baselines/xml.sw.approved.txt @@ -2078,7 +2078,7 @@ Nor would this
- 1, Predicate<int>(alwaysTrue, "always true") + 1, Predicate(alwaysTrue, "always true") 1 matches predicate: "always true" @@ -2086,7 +2086,7 @@ Nor would this - 1, !Predicate<int>(alwaysFalse, "always false") + 1, !Predicate(alwaysFalse, "always false") 1 not matches predicate: "always false" @@ -2097,7 +2097,7 @@ Nor would this
- "Hello olleH", Predicate<std::string>( [] (std::string const& str) -> bool { return str.front() == str.back(); }, "First and last character should be equal") + "Hello olleH", Predicate( [] (std::string const& str) -> bool { return str.front() == str.back(); }, "First and last character should be equal") "Hello olleH" matches predicate: "First and last character should be equal" @@ -2105,7 +2105,7 @@ Nor would this - "This wouldn't pass", !Predicate<std::string>( [] (std::string const& str) -> bool { return str.front() == str.back(); } ) + "This wouldn't pass", !Predicate( [] (std::string const& str) -> bool { return str.front() == str.back(); } ) "This wouldn't pass" not matches undescribed predicate @@ -9398,7 +9398,7 @@ Nor would this - "foo", Predicate<const char*>([] (const char* const&) { return true; }) + "foo", Predicate([] (const char* const&) { return true; }) "foo" matches undescribed predicate @@ -15046,6 +15046,17 @@ loose text artifact + + + + s, Predicate([](S &s){ return s.value() == 42;}) + + + {?} matches undescribed predicate + + + + @@ -16841,7 +16852,7 @@ loose text artifact
- + - + diff --git a/tests/SelfTest/UsageTests/Matchers.tests.cpp b/tests/SelfTest/UsageTests/Matchers.tests.cpp index 0efc922158..0da3d85a67 100644 --- a/tests/SelfTest/UsageTests/Matchers.tests.cpp +++ b/tests/SelfTest/UsageTests/Matchers.tests.cpp @@ -76,16 +76,16 @@ namespace { namespace MatchersTests { throw DerivedException{}; } - class ExceptionMatcher : public Catch::MatcherBase { + class ExceptionMatcher : public Catch::MatcherBase { int m_expected; public: ExceptionMatcher(int i) : m_expected(i) {} - bool match(SpecialException const &se) const override { + bool match(SpecialException const &se) const { return se.i == m_expected; } - std::string describe() const override { + std::string describe() const { std::ostringstream ss; ss << "special exception has value of " << m_expected; return ss.str(); @@ -478,18 +478,18 @@ namespace { namespace MatchersTests { TEST_CASE("Arbitrary predicate matcher", "[matchers][generic]") { SECTION("Function pointer") { - REQUIRE_THAT(1, Predicate(alwaysTrue, "always true")); - REQUIRE_THAT(1, !Predicate(alwaysFalse, "always false")); + REQUIRE_THAT(1, Predicate(alwaysTrue, "always true")); + REQUIRE_THAT(1, !Predicate(alwaysFalse, "always false")); } SECTION("Lambdas + different type") { REQUIRE_THAT("Hello olleH", - Predicate( + Predicate( [] (std::string const& str) -> bool { return str.front() == str.back(); }, "First and last character should be equal") ); REQUIRE_THAT("This wouldn't pass", - !Predicate( + !Predicate( [] (std::string const& str) -> bool { return str.front() == str.back(); } ) ); @@ -506,7 +506,7 @@ namespace { namespace MatchersTests { } TEST_CASE("Predicate matcher can accept const char*", "[matchers][compilation]") { - REQUIRE_THAT("foo", Predicate([] (const char* const&) { return true; })); + REQUIRE_THAT("foo", Predicate([] (const char* const&) { return true; })); } TEST_CASE("Vector Approx matcher", "[matchers][approx][vector]") { @@ -554,6 +554,17 @@ namespace { namespace MatchersTests { REQUIRE_THROWS_MATCHES(throwsSpecialException(2), SpecialException, Message("SpecialException::what")); } + TEST_CASE("non-const access") { + struct S{ + int value() { + return 42; + } + }; + + S s; + REQUIRE_THAT(s, Predicate([](S &s){ return s.value() == 42;})); + } + } } // namespace MatchersTests #ifdef __clang__