Skip to content

Commit

Permalink
rename generic matcher to MatcherBaseGeneirc and restore MatcherBase …
Browse files Browse the repository at this point in the history
…for back compat
  • Loading branch information
Dvir Yitzchaki committed Feb 9, 2020
1 parent 3bc47ea commit 6cf1e3d
Show file tree
Hide file tree
Showing 19 changed files with 841 additions and 51 deletions.
4 changes: 2 additions & 2 deletions docs/matchers.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ 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<T>` - where `T` is the matcher class.
1. A matcher class, derived from `Catch::MatcherBaseGeneric<T>` - where `T` is the matcher class.
The constructor takes and stores any arguments needed (e.g. something to compare against) and you must
provide two methods: `match()` and `describe()`.
2. A simple builder function. This is what is actually called from the test code and allows overloading.
Expand All @@ -157,7 +157,7 @@ Here's an example for asserting that an integer falls within a given range
```c++
// The matcher class
class IntRange : public Catch::MatcherBase<IntRange> {
class IntRange : public Catch::MatcherBaseGeneric<IntRange> {
int m_begin, m_end;
public:
IntRange( int begin, int end ) : m_begin( begin ), m_end( end ) {}
Expand Down
2 changes: 1 addition & 1 deletion src/catch2/catch_capture_matchers.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ namespace Catch {
// 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<typename StringMatcher,
typename = typename std::enable_if<std::is_base_of<MatcherBase<StringMatcher>, StringMatcher>::value>::type>
typename = typename std::enable_if<std::is_base_of<MatcherBaseGeneric<StringMatcher>, StringMatcher>::value>::type>
void handleExceptionMatchExpr( AssertionHandler& handler, StringMatcher const& matcher, StringRef const& matcherString ) {
std::string exceptionMessage = Catch::translateActiveException();
MatchExpr<std::string const&, StringMatcher const&> expr( exceptionMessage, matcher, matcherString );
Expand Down
57 changes: 41 additions & 16 deletions src/catch2/catch_matchers.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@ namespace Matchers {
template<typename Matcher> struct MatchNotOf;

template<typename Derived>
class MatcherBase {
class MatcherBaseGeneric {
public:
MatcherBase() = default;
MatcherBase ( MatcherBase const& ) = default;
MatcherBase& operator = ( MatcherBase const& ) = delete;
MatcherBaseGeneric() = default;
MatcherBaseGeneric ( MatcherBaseGeneric const& ) = default;
MatcherBaseGeneric& operator = ( MatcherBaseGeneric const& ) = delete;
std::string toString() const;

template<typename Other>
Expand All @@ -44,17 +44,14 @@ namespace Matchers {
};

template<typename Derived>
std::string MatcherBase<Derived>::toString() const {
std::string MatcherBaseGeneric<Derived>::toString() const {
if( m_cachedToString.empty() )
m_cachedToString = derived().describe();
return m_cachedToString;
}

template<typename... Matchers>
using Tuple = std::tuple<typename std::add_lvalue_reference<typename std::add_const<Matchers>::type>::type ...>;

template<typename... Matchers>
struct MatchAllOf : MatcherBase<MatchAllOf<Matchers...>> {
struct MatchAllOf : MatcherBaseGeneric<MatchAllOf<Matchers...>> {
MatchAllOf( Matchers const &... matchers ) : m_matchers{matchers...}
{}

Expand Down Expand Up @@ -112,11 +109,11 @@ namespace Matchers {
return and_helper(other, makeIndexSequence<sizeof...(Matchers)>());
}

Tuple<Matchers...> m_matchers;
std::tuple<Matchers...> m_matchers;
};

template<typename... Matchers>
struct MatchAnyOf : MatcherBase<MatchAnyOf<Matchers...>> {
struct MatchAnyOf : MatcherBaseGeneric<MatchAnyOf<Matchers...>> {
MatchAnyOf( Matchers const &... matchers ) : m_matchers{matchers...}
{}

Expand Down Expand Up @@ -174,11 +171,11 @@ namespace Matchers {
return or_helper(other, makeIndexSequence<sizeof...(Matchers)>());
}

Tuple<Matchers...> m_matchers;
std::tuple<Matchers...> m_matchers;
};

template<typename Matcher>
struct MatchNotOf : MatcherBase<MatchNotOf<Matcher>> {
struct MatchNotOf : MatcherBaseGeneric<MatchNotOf<Matcher>> {

MatchNotOf( Matcher const& underlyingMatcher ) : m_underlyingMatcher( underlyingMatcher ) {}

Expand All @@ -195,26 +192,54 @@ namespace Matchers {

template<typename Derived>
template<typename Other>
MatchAllOf<Derived, Other> MatcherBase<Derived>::operator && ( Other const& other ) const {
MatchAllOf<Derived, Other> MatcherBaseGeneric<Derived>::operator && ( Other const& other ) const {
return {derived(), other};
}

template<typename Derived>
template<typename Other>
MatchAnyOf<Derived, Other> MatcherBase<Derived>::operator || ( Other const& other ) const {
MatchAnyOf<Derived, Other> MatcherBaseGeneric<Derived>::operator || ( Other const& other ) const {
return {derived(), other};
}

template<typename Derived>
MatchNotOf<Derived> MatcherBase<Derived>::operator ! () const {
MatchNotOf<Derived> MatcherBaseGeneric<Derived>::operator ! () const {
return {derived()};
}

template<typename Derived>
Derived const& operator ! (MatchNotOf<Derived> const& matcher) {
return matcher.m_underlyingMatcher;
}


template<typename ObjectT>
struct MatcherMethod {
virtual bool match( ObjectT const& arg ) const = 0;
};

#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<NSString*> {
virtual bool match( NSString* arg ) const = 0;
};
#endif

// for backward compatibility
template<typename T>
struct MatcherBase : MatcherBaseGeneric<MatcherBase<T>>, MatcherMethod<T> {
virtual ~MatcherBase() = default;
virtual std::string describe() const = 0;
};

} // namespace Impl

} // namespace Matchers

using namespace Matchers;
using Matchers::Impl::MatcherBaseGeneric;
using Matchers::Impl::MatcherBase;

} // namespace Catch
Expand Down
2 changes: 1 addition & 1 deletion src/catch2/catch_matchers_exception.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ namespace Catch {
namespace Matchers {
namespace Exception {

class ExceptionMessageMatcher : public MatcherBase<ExceptionMessageMatcher> {
class ExceptionMessageMatcher : public MatcherBaseGeneric<ExceptionMessageMatcher> {
std::string m_message;
public:

Expand Down
6 changes: 3 additions & 3 deletions src/catch2/catch_matchers_floating.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ namespace Matchers {

enum class FloatingPointKind : uint8_t;

struct WithinAbsMatcher : MatcherBase<WithinAbsMatcher> {
struct WithinAbsMatcher : MatcherBaseGeneric<WithinAbsMatcher> {
WithinAbsMatcher(double target, double margin);
bool match(double const& matchee) const;
std::string describe() const;
Expand All @@ -25,7 +25,7 @@ namespace Matchers {
double m_margin;
};

struct WithinUlpsMatcher : MatcherBase<WithinUlpsMatcher> {
struct WithinUlpsMatcher : MatcherBaseGeneric<WithinUlpsMatcher> {
WithinUlpsMatcher(double target, uint64_t ulps, FloatingPointKind baseType);
bool match(double const& matchee) const;
std::string describe() const;
Expand All @@ -41,7 +41,7 @@ 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<WithinRelMatcher> {
struct WithinRelMatcher : MatcherBaseGeneric<WithinRelMatcher> {
WithinRelMatcher(double target, double epsilon);
bool match(double const& matchee) const;
std::string describe() const;
Expand Down
14 changes: 11 additions & 3 deletions src/catch2/catch_matchers_generic.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,14 @@ namespace Detail {
}

template <typename Predicate>
class PredicateMatcher : public MatcherBase<PredicateMatcher<Predicate>> {
class PredicateMatcher : public MatcherBaseGeneric<PredicateMatcher<Predicate>> {
Predicate m_predicate;
std::string m_description;
public:

PredicateMatcher(Predicate&& elem, std::string const& descr)
:m_predicate(std::forward<Predicate>(elem)),
template<typename _Predicate = Predicate>
PredicateMatcher(_Predicate&& elem, std::string const& descr)
:m_predicate(std::forward<_Predicate>(elem)),
m_description(Detail::finalizeDescription(descr))
{}

Expand All @@ -51,6 +52,13 @@ class PredicateMatcher : public MatcherBase<PredicateMatcher<Predicate>> {
// The user has to explicitly specify type to the function, because
// inferring std::function<bool(T const&)> is hard (but possible) and
// requires a lot of TMP.
template<typename T, typename Pred>
Generic::PredicateMatcher<Pred> Predicate(Pred&& predicate, std::string const& description = "") {
static_assert(is_callable<Pred(T)>::value, "Predicate not callable with argument T");
static_assert(std::is_same<bool, FunctionReturnType<Pred, T>>::value, "Predicate does not return bool");
return Generic::PredicateMatcher<Pred>(std::forward<Pred>(predicate), description);
}

template<typename Pred>
Generic::PredicateMatcher<Pred> Predicate(Pred&& predicate, std::string const& description = "") {
return Generic::PredicateMatcher<Pred>(std::forward<Pred>(predicate), description);
Expand Down
4 changes: 2 additions & 2 deletions src/catch2/catch_matchers_string.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ namespace Matchers {
};

template<typename Derived>
struct StringMatcherBase : MatcherBase<Derived> {
struct StringMatcherBase : MatcherBaseGeneric<Derived> {
StringMatcherBase( std::string const& operation, CasedString const& comparator );
std::string describe() const ;

Expand Down Expand Up @@ -73,7 +73,7 @@ namespace Matchers {
bool match( std::string const& source ) const ;
};

struct RegexMatcher : MatcherBase<RegexMatcher> {
struct RegexMatcher : MatcherBaseGeneric<RegexMatcher> {
RegexMatcher( std::string regex, CaseSensitive::Choice caseSensitivity );
bool match( std::string const& matchee ) const ;
std::string describe() const ;
Expand Down
10 changes: 5 additions & 5 deletions src/catch2/catch_matchers_vector.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ namespace Matchers {

namespace Vector {
template<typename T>
struct ContainsElementMatcher : MatcherBase<ContainsElementMatcher<T>> {
struct ContainsElementMatcher : MatcherBaseGeneric<ContainsElementMatcher<T>> {

ContainsElementMatcher(T const &comparator) : m_comparator( comparator) {}

Expand All @@ -39,7 +39,7 @@ namespace Matchers {
};

template<typename T>
struct ContainsMatcher : MatcherBase<ContainsMatcher<T>> {
struct ContainsMatcher : MatcherBaseGeneric<ContainsMatcher<T>> {

ContainsMatcher(std::vector<T> const &comparator) : m_comparator( comparator ) {}

Expand Down Expand Up @@ -69,7 +69,7 @@ namespace Matchers {
};

template<typename T>
struct EqualsMatcher : MatcherBase<EqualsMatcher<T>> {
struct EqualsMatcher : MatcherBaseGeneric<EqualsMatcher<T>> {

EqualsMatcher(std::vector<T> const &comparator) : m_comparator( comparator ) {}

Expand All @@ -92,7 +92,7 @@ namespace Matchers {
};

template<typename T>
struct ApproxMatcher : MatcherBase<ApproxMatcher<T>> {
struct ApproxMatcher : MatcherBaseGeneric<ApproxMatcher<T>> {

ApproxMatcher(std::vector<T> const& comparator) : m_comparator( comparator ) {}

Expand Down Expand Up @@ -128,7 +128,7 @@ namespace Matchers {
};

template<typename T>
struct UnorderedEqualsMatcher : MatcherBase<UnorderedEqualsMatcher<T>> {
struct UnorderedEqualsMatcher : MatcherBaseGeneric<UnorderedEqualsMatcher<T>> {
UnorderedEqualsMatcher(std::vector<T> const& target) : m_target(target) {}
bool match(std::vector<T> const& vec) const {
// Note: This is a reimplementation of std::is_permutation,
Expand Down
2 changes: 1 addition & 1 deletion src/catch2/reporters/catch_reporter_teamcity.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ namespace Catch {

void skipTest( TestCaseInfo const& /* testInfo */ ) override {}

void nomatchingTestCases( std::string const& /* spec */ ) {}
void noMatchingTestCases( std::string const& /* spec */ ) {}

void testGroupStarting(GroupInfo const& groupInfo) override;
void testGroupEnded(TestGroupStats const& testGroupStats) override;
Expand Down
9 changes: 9 additions & 0 deletions tests/SelfTest/Baselines/automake.sw.approved.txt
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,12 @@ Nor would this
:test-result: PASS CAPTURE parses string and character constants
:test-result: PASS Capture and info messages
:test-result: PASS Character pretty printing
:test-result: PASS Combining MatchAllOf does not nest
:test-result: PASS Combining MatchAnyOf does not nest
:test-result: PASS Combining MatchNotOf does not nest
:test-result: PASS Combining generic and non-generic matchers
:test-result: PASS Combining generic matchers
:test-result: PASS Combining only templated matchers
:test-result: PASS Commas in various macros are allowed
:test-result: PASS Comparing function pointers
:test-result: PASS Comparison ops
Expand Down Expand Up @@ -127,10 +133,12 @@ Nor would this
:test-result: FAIL INFO gets logged on failure
:test-result: FAIL INFO gets logged on failure, even if captured before successful assertions
:test-result: FAIL INFO is reset for each loop
:test-result: PASS Immovable matchers can be used
:test-result: XFAIL Inequality checks that should fail
:test-result: PASS Inequality checks that should succeed
:test-result: PASS Less-than inequalities with different epsilons
:test-result: PASS ManuallyRegistered
:test-result: PASS Matchers are not moved or copied
:test-result: PASS Matchers can be (AllOf) composed with the && operator
:test-result: PASS Matchers can be (AnyOf) composed with the || operator
:test-result: PASS Matchers can be composed with both && and ||
Expand All @@ -147,6 +155,7 @@ Nor would this
:test-result: PASS Ordering comparison checks that should succeed
:test-result: PASS Our PCG implementation provides expected results for known seeds
:test-result: FAIL Output from all sections is reported
:test-result: PASS Overloaded comma or address-of operators are not used
:test-result: PASS Parse test names and tags
:test-result: PASS Pointers can be compared to null
:test-result: PASS Precision of floating point stringification can be set
Expand Down
Loading

0 comments on commit 6cf1e3d

Please sign in to comment.