diff options
author | kosak <kosak@google.com> | 2014-11-17 01:47:54 +0000 |
---|---|---|
committer | kosak <kosak@google.com> | 2014-11-17 01:47:54 +0000 |
commit | 506340a66b7814b741b4b4a032ca4b059086f1bb (patch) | |
tree | 2be6603b2f5817a7b57897ecf2bf8231b6eb3b58 | |
parent | d370f85b0236b9d4ee9be91b4ae812f6bf6bb0dd (diff) | |
download | googletest-506340a66b7814b741b4b4a032ca4b059086f1bb.tar.gz googletest-506340a66b7814b741b4b4a032ca4b059086f1bb.tar.bz2 googletest-506340a66b7814b741b4b4a032ca4b059086f1bb.zip |
Generate relational matchers (Eq,Lt, etc) with CRTP instead of macro.
-rw-r--r-- | include/gmock/gmock-matchers.h | 255 | ||||
-rw-r--r-- | test/gmock-matchers_test.cc | 4 |
2 files changed, 166 insertions, 93 deletions
diff --git a/include/gmock/gmock-matchers.h b/include/gmock/gmock-matchers.h index 703dfe9b..75432bdb 100644 --- a/include/gmock/gmock-matchers.h +++ b/include/gmock/gmock-matchers.h @@ -199,6 +199,31 @@ class StringMatchResultListener : public MatchResultListener { namespace internal { +struct AnyEq { + template <typename A, typename B> + bool operator()(const A& a, const B& b) const { return a == b; } +}; +struct AnyNe { + template <typename A, typename B> + bool operator()(const A& a, const B& b) const { return a != b; } +}; +struct AnyLt { + template <typename A, typename B> + bool operator()(const A& a, const B& b) const { return a < b; } +}; +struct AnyGt { + template <typename A, typename B> + bool operator()(const A& a, const B& b) const { return a > b; } +}; +struct AnyLe { + template <typename A, typename B> + bool operator()(const A& a, const B& b) const { return a <= b; } +}; +struct AnyGe { + template <typename A, typename B> + bool operator()(const A& a, const B& b) const { return a >= b; } +}; + // A match result listener that ignores the explanation. class DummyMatchResultListener : public MatchResultListener { public: @@ -862,55 +887,90 @@ class AnythingMatcher { // used to match an int, a short, a double, etc). Therefore we use // a template type conversion operator in the implementation. // -// We define this as a macro in order to eliminate duplicated source -// code. -// // The following template definition assumes that the Rhs parameter is // a "bare" type (i.e. neither 'const T' nor 'T&'). -#define GMOCK_IMPLEMENT_COMPARISON_MATCHER_( \ - name, op, relation, negated_relation) \ - template <typename Rhs> class name##Matcher { \ - public: \ - explicit name##Matcher(const Rhs& rhs) : rhs_(rhs) {} \ - template <typename Lhs> \ - operator Matcher<Lhs>() const { \ - return MakeMatcher(new Impl<Lhs>(rhs_)); \ - } \ - private: \ - template <typename Lhs> \ - class Impl : public MatcherInterface<Lhs> { \ - public: \ - explicit Impl(const Rhs& rhs) : rhs_(rhs) {} \ - virtual bool MatchAndExplain(\ - Lhs lhs, MatchResultListener* /* listener */) const { \ - return lhs op rhs_; \ - } \ - virtual void DescribeTo(::std::ostream* os) const { \ - *os << relation " "; \ - UniversalPrint(rhs_, os); \ - } \ - virtual void DescribeNegationTo(::std::ostream* os) const { \ - *os << negated_relation " "; \ - UniversalPrint(rhs_, os); \ - } \ - private: \ - Rhs rhs_; \ - GTEST_DISALLOW_ASSIGN_(Impl); \ - }; \ - Rhs rhs_; \ - GTEST_DISALLOW_ASSIGN_(name##Matcher); \ - } - -// Implements Eq(v), Ge(v), Gt(v), Le(v), Lt(v), and Ne(v) -// respectively. -GMOCK_IMPLEMENT_COMPARISON_MATCHER_(Eq, ==, "is equal to", "isn't equal to"); -GMOCK_IMPLEMENT_COMPARISON_MATCHER_(Ge, >=, "is >=", "isn't >="); -GMOCK_IMPLEMENT_COMPARISON_MATCHER_(Gt, >, "is >", "isn't >"); -GMOCK_IMPLEMENT_COMPARISON_MATCHER_(Le, <=, "is <=", "isn't <="); -GMOCK_IMPLEMENT_COMPARISON_MATCHER_(Lt, <, "is <", "isn't <"); -GMOCK_IMPLEMENT_COMPARISON_MATCHER_(Ne, !=, "isn't equal to", "is equal to"); +template <typename D, typename Rhs, typename Op> +class ComparisonBase { + public: + explicit ComparisonBase(const Rhs& rhs) : rhs_(rhs) {} + template <typename Lhs> + operator Matcher<Lhs>() const { + return MakeMatcher(new Impl<Lhs>(rhs_)); + } -#undef GMOCK_IMPLEMENT_COMPARISON_MATCHER_ + private: + template <typename Lhs> + class Impl : public MatcherInterface<Lhs> { + public: + explicit Impl(const Rhs& rhs) : rhs_(rhs) {} + virtual bool MatchAndExplain( + Lhs lhs, MatchResultListener* /* listener */) const { + return Op()(lhs, rhs_); + } + virtual void DescribeTo(::std::ostream* os) const { + *os << D::Desc() << " "; + UniversalPrint(rhs_, os); + } + virtual void DescribeNegationTo(::std::ostream* os) const { + *os << D::NegatedDesc() << " "; + UniversalPrint(rhs_, os); + } + private: + Rhs rhs_; + GTEST_DISALLOW_ASSIGN_(Impl); + }; + Rhs rhs_; + GTEST_DISALLOW_ASSIGN_(ComparisonBase); +}; + +template <typename Rhs> +class EqMatcher : public ComparisonBase<EqMatcher<Rhs>, Rhs, AnyEq> { + public: + explicit EqMatcher(const Rhs& rhs) + : ComparisonBase<EqMatcher<Rhs>, Rhs, AnyEq>(rhs) { } + static const char* Desc() { return "is equal to"; } + static const char* NegatedDesc() { return "isn't equal to"; } +}; +template <typename Rhs> +class NeMatcher : public ComparisonBase<NeMatcher<Rhs>, Rhs, AnyNe> { + public: + explicit NeMatcher(const Rhs& rhs) + : ComparisonBase<NeMatcher<Rhs>, Rhs, AnyNe>(rhs) { } + static const char* Desc() { return "isn't equal to"; } + static const char* NegatedDesc() { return "is equal to"; } +}; +template <typename Rhs> +class LtMatcher : public ComparisonBase<LtMatcher<Rhs>, Rhs, AnyLt> { + public: + explicit LtMatcher(const Rhs& rhs) + : ComparisonBase<LtMatcher<Rhs>, Rhs, AnyLt>(rhs) { } + static const char* Desc() { return "is <"; } + static const char* NegatedDesc() { return "isn't <"; } +}; +template <typename Rhs> +class GtMatcher : public ComparisonBase<GtMatcher<Rhs>, Rhs, AnyGt> { + public: + explicit GtMatcher(const Rhs& rhs) + : ComparisonBase<GtMatcher<Rhs>, Rhs, AnyGt>(rhs) { } + static const char* Desc() { return "is >"; } + static const char* NegatedDesc() { return "isn't >"; } +}; +template <typename Rhs> +class LeMatcher : public ComparisonBase<LeMatcher<Rhs>, Rhs, AnyLe> { + public: + explicit LeMatcher(const Rhs& rhs) + : ComparisonBase<LeMatcher<Rhs>, Rhs, AnyLe>(rhs) { } + static const char* Desc() { return "is <="; } + static const char* NegatedDesc() { return "isn't <="; } +}; +template <typename Rhs> +class GeMatcher : public ComparisonBase<GeMatcher<Rhs>, Rhs, AnyGe> { + public: + explicit GeMatcher(const Rhs& rhs) + : ComparisonBase<GeMatcher<Rhs>, Rhs, AnyGe>(rhs) { } + static const char* Desc() { return "is >="; } + static const char* NegatedDesc() { return "isn't >="; } +}; // Implements the polymorphic IsNull() matcher, which matches any raw or smart // pointer that is NULL. @@ -1309,51 +1369,64 @@ class MatchesRegexMatcher { // used to match a tuple<int, short>, a tuple<const long&, double>, // etc). Therefore we use a template type conversion operator in the // implementation. -// -// We define this as a macro in order to eliminate duplicated source -// code. -#define GMOCK_IMPLEMENT_COMPARISON2_MATCHER_(name, op, relation) \ - class name##2Matcher { \ - public: \ - template <typename T1, typename T2> \ - operator Matcher< ::testing::tuple<T1, T2> >() const { \ - return MakeMatcher(new Impl< ::testing::tuple<T1, T2> >); \ - } \ - template <typename T1, typename T2> \ - operator Matcher<const ::testing::tuple<T1, T2>&>() const { \ - return MakeMatcher(new Impl<const ::testing::tuple<T1, T2>&>); \ - } \ - private: \ - template <typename Tuple> \ - class Impl : public MatcherInterface<Tuple> { \ - public: \ - virtual bool MatchAndExplain( \ - Tuple args, \ - MatchResultListener* /* listener */) const { \ - return ::testing::get<0>(args) op ::testing::get<1>(args); \ - } \ - virtual void DescribeTo(::std::ostream* os) const { \ - *os << "are " relation; \ - } \ - virtual void DescribeNegationTo(::std::ostream* os) const { \ - *os << "aren't " relation; \ - } \ - }; \ - } - -// Implements Eq(), Ge(), Gt(), Le(), Lt(), and Ne() respectively. -GMOCK_IMPLEMENT_COMPARISON2_MATCHER_(Eq, ==, "an equal pair"); -GMOCK_IMPLEMENT_COMPARISON2_MATCHER_( - Ge, >=, "a pair where the first >= the second"); -GMOCK_IMPLEMENT_COMPARISON2_MATCHER_( - Gt, >, "a pair where the first > the second"); -GMOCK_IMPLEMENT_COMPARISON2_MATCHER_( - Le, <=, "a pair where the first <= the second"); -GMOCK_IMPLEMENT_COMPARISON2_MATCHER_( - Lt, <, "a pair where the first < the second"); -GMOCK_IMPLEMENT_COMPARISON2_MATCHER_(Ne, !=, "an unequal pair"); - -#undef GMOCK_IMPLEMENT_COMPARISON2_MATCHER_ +template <typename D, typename Op> +class PairMatchBase { + public: + template <typename T1, typename T2> + operator Matcher< ::testing::tuple<T1, T2> >() const { + return MakeMatcher(new Impl< ::testing::tuple<T1, T2> >); + } + template <typename T1, typename T2> + operator Matcher<const ::testing::tuple<T1, T2>&>() const { + return MakeMatcher(new Impl<const ::testing::tuple<T1, T2>&>); + } + + private: + static ::std::ostream& GetDesc(::std::ostream& os) { // NOLINT + return os << D::Desc(); + } + + template <typename Tuple> + class Impl : public MatcherInterface<Tuple> { + public: + virtual bool MatchAndExplain( + Tuple args, + MatchResultListener* /* listener */) const { + return Op()(::testing::get<0>(args), ::testing::get<1>(args)); + } + virtual void DescribeTo(::std::ostream* os) const { + *os << "are " << GetDesc; + } + virtual void DescribeNegationTo(::std::ostream* os) const { + *os << "aren't " << GetDesc; + } + }; +}; + +class Eq2Matcher : public PairMatchBase<Eq2Matcher, AnyEq> { + public: + static const char* Desc() { return "an equal pair"; } +}; +class Ne2Matcher : public PairMatchBase<Ne2Matcher, AnyNe> { + public: + static const char* Desc() { return "an unequal pair"; } +}; +class Lt2Matcher : public PairMatchBase<Lt2Matcher, AnyLt> { + public: + static const char* Desc() { return "a pair where the first < the second"; } +}; +class Gt2Matcher : public PairMatchBase<Gt2Matcher, AnyGt> { + public: + static const char* Desc() { return "a pair where the first > the second"; } +}; +class Le2Matcher : public PairMatchBase<Le2Matcher, AnyLe> { + public: + static const char* Desc() { return "a pair where the first <= the second"; } +}; +class Ge2Matcher : public PairMatchBase<Ge2Matcher, AnyGe> { + public: + static const char* Desc() { return "a pair where the first >= the second"; } +}; // Implements the Not(...) matcher for a particular argument type T. // We do not nest it inside the NotMatcher class template, as that diff --git a/test/gmock-matchers_test.cc b/test/gmock-matchers_test.cc index c5476223..cb588470 100644 --- a/test/gmock-matchers_test.cc +++ b/test/gmock-matchers_test.cc @@ -607,11 +607,11 @@ TEST(MatcherCastTest, FromSameType) { EXPECT_FALSE(m2.Matches(1)); } -// Implicitly convertible form any type. +// Implicitly convertible from any type. struct ConvertibleFromAny { ConvertibleFromAny(int a_value) : value(a_value) {} template <typename T> - ConvertibleFromAny(const T& a_value) : value(-1) { + ConvertibleFromAny(const T& /*a_value*/) : value(-1) { ADD_FAILURE() << "Conversion constructor called"; } int value; |