From ab5b77c179009b787d71ff934eaf4a0db6c24814 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Mon, 17 May 2010 19:32:48 +0000 Subject: [PATCH] Implements Pointwise(). --- include/gmock/gmock-generated-matchers.h | 32 +-- include/gmock/gmock-generated-matchers.h.pump | 5 +- include/gmock/gmock-matchers.h | 184 +++++++++++++--- test/gmock-generated-matchers_test.cc | 9 +- test/gmock-matchers_test.cc | 204 ++++++++++++++---- test/gmock_output_test_golden.txt | 6 +- 6 files changed, 344 insertions(+), 96 deletions(-) diff --git a/include/gmock/gmock-generated-matchers.h b/include/gmock/gmock-generated-matchers.h index 90f3750e..2790e06c 100644 --- a/include/gmock/gmock-generated-matchers.h +++ b/include/gmock/gmock-generated-matchers.h @@ -221,7 +221,7 @@ template { public: // ArgsTuple may have top-level const or reference modifiers. - typedef GTEST_REMOVE_CONST_(GTEST_REMOVE_REFERENCE_(ArgsTuple)) RawArgsTuple; + typedef GTEST_REMOVE_REFERENCE_AND_CONST_(ArgsTuple) RawArgsTuple; typedef typename internal::TupleFields::type SelectedArgs; typedef Matcher MonomorphicInnerMatcher; @@ -314,8 +314,7 @@ class ElementsAreMatcher1 { template operator Matcher() const { - typedef GTEST_REMOVE_CONST_(GTEST_REMOVE_REFERENCE_(Container)) - RawContainer; + typedef GTEST_REMOVE_REFERENCE_AND_CONST_(Container) RawContainer; typedef typename internal::StlContainerView::type::value_type Element; @@ -343,8 +342,7 @@ class ElementsAreMatcher2 { template operator Matcher() const { - typedef GTEST_REMOVE_CONST_(GTEST_REMOVE_REFERENCE_(Container)) - RawContainer; + typedef GTEST_REMOVE_REFERENCE_AND_CONST_(Container) RawContainer; typedef typename internal::StlContainerView::type::value_type Element; @@ -371,8 +369,7 @@ class ElementsAreMatcher3 { template operator Matcher() const { - typedef GTEST_REMOVE_CONST_(GTEST_REMOVE_REFERENCE_(Container)) - RawContainer; + typedef GTEST_REMOVE_REFERENCE_AND_CONST_(Container) RawContainer; typedef typename internal::StlContainerView::type::value_type Element; @@ -401,8 +398,7 @@ class ElementsAreMatcher4 { template operator Matcher() const { - typedef GTEST_REMOVE_CONST_(GTEST_REMOVE_REFERENCE_(Container)) - RawContainer; + typedef GTEST_REMOVE_REFERENCE_AND_CONST_(Container) RawContainer; typedef typename internal::StlContainerView::type::value_type Element; @@ -433,8 +429,7 @@ class ElementsAreMatcher5 { template operator Matcher() const { - typedef GTEST_REMOVE_CONST_(GTEST_REMOVE_REFERENCE_(Container)) - RawContainer; + typedef GTEST_REMOVE_REFERENCE_AND_CONST_(Container) RawContainer; typedef typename internal::StlContainerView::type::value_type Element; @@ -469,8 +464,7 @@ class ElementsAreMatcher6 { template operator Matcher() const { - typedef GTEST_REMOVE_CONST_(GTEST_REMOVE_REFERENCE_(Container)) - RawContainer; + typedef GTEST_REMOVE_REFERENCE_AND_CONST_(Container) RawContainer; typedef typename internal::StlContainerView::type::value_type Element; @@ -507,8 +501,7 @@ class ElementsAreMatcher7 { template operator Matcher() const { - typedef GTEST_REMOVE_CONST_(GTEST_REMOVE_REFERENCE_(Container)) - RawContainer; + typedef GTEST_REMOVE_REFERENCE_AND_CONST_(Container) RawContainer; typedef typename internal::StlContainerView::type::value_type Element; @@ -547,8 +540,7 @@ class ElementsAreMatcher8 { template operator Matcher() const { - typedef GTEST_REMOVE_CONST_(GTEST_REMOVE_REFERENCE_(Container)) - RawContainer; + typedef GTEST_REMOVE_REFERENCE_AND_CONST_(Container) RawContainer; typedef typename internal::StlContainerView::type::value_type Element; @@ -590,8 +582,7 @@ class ElementsAreMatcher9 { template operator Matcher() const { - typedef GTEST_REMOVE_CONST_(GTEST_REMOVE_REFERENCE_(Container)) - RawContainer; + typedef GTEST_REMOVE_REFERENCE_AND_CONST_(Container) RawContainer; typedef typename internal::StlContainerView::type::value_type Element; @@ -635,8 +626,7 @@ class ElementsAreMatcher10 { template operator Matcher() const { - typedef GTEST_REMOVE_CONST_(GTEST_REMOVE_REFERENCE_(Container)) - RawContainer; + typedef GTEST_REMOVE_REFERENCE_AND_CONST_(Container) RawContainer; typedef typename internal::StlContainerView::type::value_type Element; diff --git a/include/gmock/gmock-generated-matchers.h.pump b/include/gmock/gmock-generated-matchers.h.pump index 2f325b04..db498ec0 100644 --- a/include/gmock/gmock-generated-matchers.h.pump +++ b/include/gmock/gmock-generated-matchers.h.pump @@ -107,7 +107,7 @@ template class ArgsMatcherImpl : public MatcherInterface { public: // ArgsTuple may have top-level const or reference modifiers. - typedef GTEST_REMOVE_CONST_(GTEST_REMOVE_REFERENCE_(ArgsTuple)) RawArgsTuple; + typedef GTEST_REMOVE_REFERENCE_AND_CONST_(ArgsTuple) RawArgsTuple; typedef typename internal::TupleFields::type SelectedArgs; typedef Matcher MonomorphicInnerMatcher; @@ -200,8 +200,7 @@ class ElementsAreMatcher$i { template operator Matcher() const { - typedef GTEST_REMOVE_CONST_(GTEST_REMOVE_REFERENCE_(Container)) - RawContainer; + typedef GTEST_REMOVE_REFERENCE_AND_CONST_(Container) RawContainer; typedef typename internal::StlContainerView::type::value_type Element; diff --git a/include/gmock/gmock-matchers.h b/include/gmock/gmock-matchers.h index 7f84761e..2a42bf94 100644 --- a/include/gmock/gmock-matchers.h +++ b/include/gmock/gmock-matchers.h @@ -43,6 +43,7 @@ #include // NOLINT #include #include +#include #include #include @@ -427,8 +428,8 @@ class SafeMatcherCastImpl { cannot_convert_non_referentce_arg_to_reference); // In case both T and U are arithmetic types, enforce that the // conversion is not lossy. - typedef GTEST_REMOVE_CONST_(GTEST_REMOVE_REFERENCE_(T)) RawT; - typedef GTEST_REMOVE_CONST_(GTEST_REMOVE_REFERENCE_(U)) RawU; + typedef GTEST_REMOVE_REFERENCE_AND_CONST_(T) RawT; + typedef GTEST_REMOVE_REFERENCE_AND_CONST_(U) RawU; const bool kTIsOther = GMOCK_KIND_OF_(RawT) == internal::kOther; const bool kUIsOther = GMOCK_KIND_OF_(RawU) == internal::kOther; GTEST_COMPILE_ASSERT_( @@ -1095,38 +1096,46 @@ class MatchesRegexMatcher { // // We define this as a macro in order to eliminate duplicated source // code. -#define GMOCK_IMPLEMENT_COMPARISON2_MATCHER_(name, op) \ +#define GMOCK_IMPLEMENT_COMPARISON2_MATCHER_(name, op, relation) \ class name##2Matcher { \ public: \ + template \ + operator Matcher< ::std::tr1::tuple >() const { \ + return MakeMatcher(new Impl< ::std::tr1::tuple >); \ + } \ template \ operator Matcher&>() const { \ - return MakeMatcher(new Impl); \ + return MakeMatcher(new Impl&>); \ } \ private: \ - template \ - class Impl : public MatcherInterface&> { \ + template \ + class Impl : public MatcherInterface { \ public: \ virtual bool MatchAndExplain( \ - const ::std::tr1::tuple& args, \ + Tuple args, \ MatchResultListener* /* listener */) const { \ return ::std::tr1::get<0>(args) op ::std::tr1::get<1>(args); \ } \ virtual void DescribeTo(::std::ostream* os) const { \ - *os << "are a pair (x, y) where x " #op " y"; \ + *os << "are " relation; \ } \ virtual void DescribeNegationTo(::std::ostream* os) const { \ - *os << "are a pair (x, y) where x " #op " y is false"; \ + *os << "aren't " relation; \ } \ }; \ } // Implements Eq(), Ge(), Gt(), Le(), Lt(), and Ne() respectively. -GMOCK_IMPLEMENT_COMPARISON2_MATCHER_(Eq, ==); -GMOCK_IMPLEMENT_COMPARISON2_MATCHER_(Ge, >=); -GMOCK_IMPLEMENT_COMPARISON2_MATCHER_(Gt, >); -GMOCK_IMPLEMENT_COMPARISON2_MATCHER_(Le, <=); -GMOCK_IMPLEMENT_COMPARISON2_MATCHER_(Lt, <); -GMOCK_IMPLEMENT_COMPARISON2_MATCHER_(Ne, !=); +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_ @@ -1873,8 +1882,8 @@ class ContainerEqMatcher { explicit ContainerEqMatcher(const Container& rhs) : rhs_(View::Copy(rhs)) { // Makes sure the user doesn't instantiate this class template // with a const or reference type. - testing::StaticAssertTypeEq(); + (void)testing::StaticAssertTypeEq(); } void DescribeTo(::std::ostream* os) const { @@ -1945,11 +1954,121 @@ class ContainerEqMatcher { GTEST_DISALLOW_ASSIGN_(ContainerEqMatcher); }; +// Implements Pointwise(tuple_matcher, rhs_container). tuple_matcher +// must be able to be safely cast to Matcher >, where T1 and T2 are the types of elements in the LHS +// container and the RHS container respectively. +template +class PointwiseMatcher { + public: + typedef internal::StlContainerView RhsView; + typedef typename RhsView::type RhsStlContainer; + typedef typename RhsStlContainer::value_type RhsValue; + + // Like ContainerEq, we make a copy of rhs in case the elements in + // it are modified after this matcher is created. + PointwiseMatcher(const TupleMatcher& tuple_matcher, const RhsContainer& rhs) + : tuple_matcher_(tuple_matcher), rhs_(RhsView::Copy(rhs)) { + // Makes sure the user doesn't instantiate this class template + // with a const or reference type. + (void)testing::StaticAssertTypeEq(); + } + + template + operator Matcher() const { + return MakeMatcher(new Impl(tuple_matcher_, rhs_)); + } + + template + class Impl : public MatcherInterface { + public: + typedef internal::StlContainerView< + GTEST_REMOVE_REFERENCE_AND_CONST_(LhsContainer)> LhsView; + typedef typename LhsView::type LhsStlContainer; + typedef typename LhsView::const_reference LhsStlContainerReference; + typedef typename LhsStlContainer::value_type LhsValue; + // We pass the LHS value and the RHS value to the inner matcher by + // reference, as they may be expensive to copy. We must use tuple + // instead of pair here, as a pair cannot hold references (C++ 98, + // 20.2.2 [lib.pairs]). + typedef std::tr1::tuple InnerMatcherArg; + + Impl(const TupleMatcher& tuple_matcher, const RhsStlContainer& rhs) + // mono_tuple_matcher_ holds a monomorphic version of the tuple matcher. + : mono_tuple_matcher_(SafeMatcherCast(tuple_matcher)), + rhs_(rhs) {} + + virtual void DescribeTo(::std::ostream* os) const { + *os << "contains " << rhs_.size() + << " values, where each value and its corresponding value in "; + UniversalPrinter::Print(rhs_, os); + *os << " "; + mono_tuple_matcher_.DescribeTo(os); + } + virtual void DescribeNegationTo(::std::ostream* os) const { + *os << "doesn't contain exactly " << rhs_.size() + << " values, or contains a value x at some index i" + << " where x and the i-th value of "; + UniversalPrint(rhs_, os); + *os << " "; + mono_tuple_matcher_.DescribeNegationTo(os); + } + + virtual bool MatchAndExplain(LhsContainer lhs, + MatchResultListener* listener) const { + LhsStlContainerReference lhs_stl_container = LhsView::ConstReference(lhs); + const size_t actual_size = lhs_stl_container.size(); + if (actual_size != rhs_.size()) { + *listener << "which contains " << actual_size << " values"; + return false; + } + + typename LhsStlContainer::const_iterator left = lhs_stl_container.begin(); + typename RhsStlContainer::const_iterator right = rhs_.begin(); + for (size_t i = 0; i != actual_size; ++i, ++left, ++right) { + const InnerMatcherArg value_pair(*left, *right); + + if (listener->IsInterested()) { + StringMatchResultListener inner_listener; + if (!mono_tuple_matcher_.MatchAndExplain( + value_pair, &inner_listener)) { + *listener << "where the value pair ("; + UniversalPrint(*left, listener->stream()); + *listener << ", "; + UniversalPrint(*right, listener->stream()); + *listener << ") at index #" << i << " don't match"; + PrintIfNotEmpty(inner_listener.str(), listener->stream()); + return false; + } + } else { + if (!mono_tuple_matcher_.Matches(value_pair)) + return false; + } + } + + return true; + } + + private: + const Matcher mono_tuple_matcher_; + const RhsStlContainer rhs_; + + GTEST_DISALLOW_ASSIGN_(Impl); + }; + + private: + const TupleMatcher tuple_matcher_; + const RhsStlContainer rhs_; + + GTEST_DISALLOW_ASSIGN_(PointwiseMatcher); +}; + // Holds the logic common to ContainsMatcherImpl and EachMatcherImpl. template class QuantifierMatcherImpl : public MatcherInterface { public: - typedef GTEST_REMOVE_CONST_(GTEST_REMOVE_REFERENCE_(Container)) RawContainer; + typedef GTEST_REMOVE_REFERENCE_AND_CONST_(Container) RawContainer; typedef StlContainerView View; typedef typename View::type StlContainer; typedef typename View::const_reference StlContainerReference; @@ -2088,7 +2207,7 @@ class EachMatcher { template class KeyMatcherImpl : public MatcherInterface { public: - typedef GTEST_REMOVE_CONST_(GTEST_REMOVE_REFERENCE_(PairType)) RawPairType; + typedef GTEST_REMOVE_REFERENCE_AND_CONST_(PairType) RawPairType; typedef typename RawPairType::first_type KeyType; template @@ -2150,7 +2269,7 @@ class KeyMatcher { template class PairMatcherImpl : public MatcherInterface { public: - typedef GTEST_REMOVE_CONST_(GTEST_REMOVE_REFERENCE_(PairType)) RawPairType; + typedef GTEST_REMOVE_REFERENCE_AND_CONST_(PairType) RawPairType; typedef typename RawPairType::first_type FirstType; typedef typename RawPairType::second_type SecondType; @@ -2257,7 +2376,7 @@ class PairMatcher { template class ElementsAreMatcherImpl : public MatcherInterface { public: - typedef GTEST_REMOVE_CONST_(GTEST_REMOVE_REFERENCE_(Container)) RawContainer; + typedef GTEST_REMOVE_REFERENCE_AND_CONST_(Container) RawContainer; typedef internal::StlContainerView View; typedef typename View::type StlContainer; typedef typename View::const_reference StlContainerReference; @@ -2376,8 +2495,7 @@ class ElementsAreMatcher0 { template operator Matcher() const { - typedef GTEST_REMOVE_CONST_(GTEST_REMOVE_REFERENCE_(Container)) - RawContainer; + typedef GTEST_REMOVE_REFERENCE_AND_CONST_(Container) RawContainer; typedef typename internal::StlContainerView::type::value_type Element; @@ -2395,8 +2513,7 @@ class ElementsAreArrayMatcher { template operator Matcher() const { - typedef GTEST_REMOVE_CONST_(GTEST_REMOVE_REFERENCE_(Container)) - RawContainer; + typedef GTEST_REMOVE_REFERENCE_AND_CONST_(Container) RawContainer; typedef typename internal::StlContainerView::type::value_type Element; @@ -2900,6 +3017,23 @@ inline PolymorphicMatcher(rhs)); } +// Matches an STL-style container or a native array that contains the +// same number of elements as in rhs, where its i-th element and rhs's +// i-th element (as a pair) satisfy the given pair matcher, for all i. +// TupleMatcher must be able to be safely cast to Matcher >, where T1 and T2 are the types of elements in the +// LHS container and the RHS container respectively. +template +inline internal::PointwiseMatcher +Pointwise(const TupleMatcher& tuple_matcher, const Container& rhs) { + // This following line is for working around a bug in MSVC 8.0, + // which causes Container to be a const type sometimes. + typedef GTEST_REMOVE_CONST_(Container) RawContainer; + return internal::PointwiseMatcher( + tuple_matcher, rhs); +} + // Matches an STL-style container or a native array that contains at // least one element matching the given value or matcher. // diff --git a/test/gmock-generated-matchers_test.cc b/test/gmock-generated-matchers_test.cc index 12479af4..eebca8a0 100644 --- a/test/gmock-generated-matchers_test.cc +++ b/test/gmock-generated-matchers_test.cc @@ -192,7 +192,8 @@ TEST(ArgsTest, AcceptsTenTemplateArgs) { TEST(ArgsTest, DescirbesSelfCorrectly) { const Matcher > m = Args<2, 0>(Lt()); - EXPECT_EQ("are a tuple whose fields (#2, #0) are a pair (x, y) where x < y", + EXPECT_EQ("are a tuple whose fields (#2, #0) are a pair where " + "the first < the second", Describe(m)); } @@ -200,14 +201,14 @@ TEST(ArgsTest, DescirbesNestedArgsCorrectly) { const Matcher&> m = Args<0, 2, 3>(Args<2, 0>(Lt())); EXPECT_EQ("are a tuple whose fields (#0, #2, #3) are a tuple " - "whose fields (#2, #0) are a pair (x, y) where x < y", + "whose fields (#2, #0) are a pair where the first < the second", Describe(m)); } TEST(ArgsTest, DescribesNegationCorrectly) { const Matcher > m = Args<1, 0>(Gt()); - EXPECT_EQ("are a tuple whose fields (#1, #0) are a pair (x, y) " - "where x > y is false", + EXPECT_EQ("are a tuple whose fields (#1, #0) aren't a pair " + "where the first > the second", DescribeNegation(m)); } diff --git a/test/gmock-matchers_test.cc b/test/gmock-matchers_test.cc index a7c217d4..3b151dbd 100644 --- a/test/gmock-matchers_test.cc +++ b/test/gmock-matchers_test.cc @@ -61,13 +61,18 @@ bool SkipPrefix(const char* prefix, const char** pstr); namespace gmock_matchers_test { +using std::list; using std::make_pair; using std::map; using std::multimap; +using std::multiset; +using std::ostream; using std::pair; using std::set; using std::stringstream; +using std::tr1::get; using std::tr1::make_tuple; +using std::tr1::tuple; using std::vector; using testing::A; using testing::AllArgs; @@ -104,6 +109,7 @@ using testing::Not; using testing::NotNull; using testing::Pair; using testing::Pointee; +using testing::Pointwise; using testing::PolymorphicMatcher; using testing::Property; using testing::Ref; @@ -144,7 +150,7 @@ class GreaterThanMatcher : public MatcherInterface { public: explicit GreaterThanMatcher(int rhs) : rhs_(rhs) {} - virtual void DescribeTo(::std::ostream* os) const { + virtual void DescribeTo(ostream* os) const { *os << "is > " << rhs_; } @@ -189,9 +195,9 @@ string DescribeNegation(const Matcher& m) { // Returns the reason why x matches, or doesn't match, m. template string Explain(const MatcherType& m, const Value& x) { - stringstream ss; - m.ExplainMatchResultTo(x, &ss); - return ss.str(); + StringMatchResultListener listener; + ExplainMatchResult(m, x, &listener); + return listener.str(); } TEST(MatchResultListenerTest, StreamingWorks) { @@ -228,7 +234,7 @@ class EvenMatcherImpl : public MatcherInterface { return x % 2 == 0; } - virtual void DescribeTo(::std::ostream* os) const { + virtual void DescribeTo(ostream* os) const { *os << "is an even number"; } @@ -258,7 +264,7 @@ class NewEvenMatcherImpl : public MatcherInterface { return match; } - virtual void DescribeTo(::std::ostream* os) const { + virtual void DescribeTo(ostream* os) const { *os << "is an even number"; } }; @@ -375,9 +381,9 @@ class ReferencesBarOrIsZeroImpl { return p == &g_bar || x == 0; } - void DescribeTo(::std::ostream* os) const { *os << "g_bar or zero"; } + void DescribeTo(ostream* os) const { *os << "g_bar or zero"; } - void DescribeNegationTo(::std::ostream* os) const { + void DescribeNegationTo(ostream* os) const { *os << "doesn't reference g_bar and is not zero"; } }; @@ -408,9 +414,9 @@ TEST(MakePolymorphicMatcherTest, ConstructsMatcherUsingOldAPI) { class PolymorphicIsEvenImpl { public: - void DescribeTo(::std::ostream* os) const { *os << "is even"; } + void DescribeTo(ostream* os) const { *os << "is even"; } - void DescribeNegationTo(::std::ostream* os) const { + void DescribeNegationTo(ostream* os) const { *os << "is odd"; } @@ -1150,7 +1156,7 @@ TEST(KeyTest, SafelyCastsInnerMatcher) { } TEST(KeyTest, InsideContainsUsingMap) { - std::map container; + map container; container.insert(make_pair(1, 'a')); container.insert(make_pair(2, 'b')); container.insert(make_pair(4, 'c')); @@ -1159,7 +1165,7 @@ TEST(KeyTest, InsideContainsUsingMap) { } TEST(KeyTest, InsideContainsUsingMultimap) { - std::multimap container; + multimap container; container.insert(make_pair(1, 'a')); container.insert(make_pair(2, 'b')); container.insert(make_pair(4, 'c')); @@ -1268,7 +1274,7 @@ TEST(PairTest, SafelyCastsInnerMatchers) { } TEST(PairTest, InsideContainsUsingMap) { - std::map container; + map container; container.insert(make_pair(1, 'a')); container.insert(make_pair(2, 'b')); container.insert(make_pair(4, 'c')); @@ -1761,7 +1767,7 @@ TEST(Eq2Test, MatchesEqualArguments) { // Tests that Eq() describes itself properly. TEST(Eq2Test, CanDescribeSelf) { Matcher m = Eq(); - EXPECT_EQ("are a pair (x, y) where x == y", Describe(m)); + EXPECT_EQ("are an equal pair", Describe(m)); } // Tests that Ge() matches a 2-tuple where the first field >= the @@ -1776,7 +1782,7 @@ TEST(Ge2Test, MatchesGreaterThanOrEqualArguments) { // Tests that Ge() describes itself properly. TEST(Ge2Test, CanDescribeSelf) { Matcher m = Ge(); - EXPECT_EQ("are a pair (x, y) where x >= y", Describe(m)); + EXPECT_EQ("are a pair where the first >= the second", Describe(m)); } // Tests that Gt() matches a 2-tuple where the first field > the @@ -1791,7 +1797,7 @@ TEST(Gt2Test, MatchesGreaterThanArguments) { // Tests that Gt() describes itself properly. TEST(Gt2Test, CanDescribeSelf) { Matcher m = Gt(); - EXPECT_EQ("are a pair (x, y) where x > y", Describe(m)); + EXPECT_EQ("are a pair where the first > the second", Describe(m)); } // Tests that Le() matches a 2-tuple where the first field <= the @@ -1806,7 +1812,7 @@ TEST(Le2Test, MatchesLessThanOrEqualArguments) { // Tests that Le() describes itself properly. TEST(Le2Test, CanDescribeSelf) { Matcher m = Le(); - EXPECT_EQ("are a pair (x, y) where x <= y", Describe(m)); + EXPECT_EQ("are a pair where the first <= the second", Describe(m)); } // Tests that Lt() matches a 2-tuple where the first field < the @@ -1821,7 +1827,7 @@ TEST(Lt2Test, MatchesLessThanArguments) { // Tests that Lt() describes itself properly. TEST(Lt2Test, CanDescribeSelf) { Matcher m = Lt(); - EXPECT_EQ("are a pair (x, y) where x < y", Describe(m)); + EXPECT_EQ("are a pair where the first < the second", Describe(m)); } // Tests that Ne() matches a 2-tuple where the first field != the @@ -1836,7 +1842,7 @@ TEST(Ne2Test, MatchesUnequalArguments) { // Tests that Ne() describes itself properly. TEST(Ne2Test, CanDescribeSelf) { Matcher m = Ne(); - EXPECT_EQ("are a pair (x, y) where x != y", Describe(m)); + EXPECT_EQ("are an unequal pair", Describe(m)); } // Tests that Not(m) matches any value that doesn't match m. @@ -3338,11 +3344,11 @@ class DivisibleByImpl { return (n % divider_) == 0; } - void DescribeTo(::std::ostream* os) const { + void DescribeTo(ostream* os) const { *os << "is divisible by " << divider_; } - void DescribeNegationTo(::std::ostream* os) const { + void DescribeNegationTo(ostream* os) const { *os << "is not divisible by " << divider_; } @@ -3444,10 +3450,10 @@ template class ContainerEqTest : public testing::Test {}; typedef testing::Types< - std::set, - std::vector, - std::multiset, - std::list > + set, + vector, + multiset, + list > ContainerEqTestTypes; TYPED_TEST_CASE(ContainerEqTest, ContainerEqTestTypes); @@ -3515,9 +3521,9 @@ TYPED_TEST(ContainerEqTest, DuplicateDifference) { TEST(ContainerEqExtraTest, MultipleValuesMissing) { static const int vals[] = {1, 1, 2, 3, 5, 8}; static const int test_vals[] = {2, 1, 5}; - std::vector my_set(vals, vals + 6); - std::vector test_set(test_vals, test_vals + 3); - const Matcher > m = ContainerEq(my_set); + vector my_set(vals, vals + 6); + vector test_set(test_vals, test_vals + 3); + const Matcher > m = ContainerEq(my_set); EXPECT_FALSE(m.Matches(test_set)); EXPECT_EQ("which doesn't have these expected elements: 3, 8", Explain(m, test_set)); @@ -3528,9 +3534,9 @@ TEST(ContainerEqExtraTest, MultipleValuesMissing) { TEST(ContainerEqExtraTest, MultipleValuesAdded) { static const int vals[] = {1, 1, 2, 3, 5, 8}; static const int test_vals[] = {1, 2, 92, 3, 5, 8, 46}; - std::list my_set(vals, vals + 6); - std::list test_set(test_vals, test_vals + 7); - const Matcher&> m = ContainerEq(my_set); + list my_set(vals, vals + 6); + list test_set(test_vals, test_vals + 7); + const Matcher&> m = ContainerEq(my_set); EXPECT_FALSE(m.Matches(test_set)); EXPECT_EQ("which has these unexpected elements: 92, 46", Explain(m, test_set)); @@ -3540,9 +3546,9 @@ TEST(ContainerEqExtraTest, MultipleValuesAdded) { TEST(ContainerEqExtraTest, MultipleValuesAddedAndRemoved) { static const int vals[] = {1, 1, 2, 3, 5, 8}; static const int test_vals[] = {1, 2, 3, 92, 46}; - std::list my_set(vals, vals + 6); - std::list test_set(test_vals, test_vals + 5); - const Matcher > m = ContainerEq(my_set); + list my_set(vals, vals + 6); + list test_set(test_vals, test_vals + 5); + const Matcher > m = ContainerEq(my_set); EXPECT_FALSE(m.Matches(test_set)); EXPECT_EQ("which has these unexpected elements: 92, 46,\n" "and doesn't have these expected elements: 5, 8", @@ -3554,9 +3560,9 @@ TEST(ContainerEqExtraTest, MultipleValuesAddedAndRemoved) { TEST(ContainerEqExtraTest, MultiSetOfIntDuplicateDifference) { static const int vals[] = {1, 1, 2, 3, 5, 8}; static const int test_vals[] = {1, 2, 3, 5, 8}; - std::vector my_set(vals, vals + 6); - std::vector test_set(test_vals, test_vals + 5); - const Matcher > m = ContainerEq(my_set); + vector my_set(vals, vals + 6); + vector test_set(test_vals, test_vals + 5); + const Matcher > m = ContainerEq(my_set); EXPECT_TRUE(m.Matches(my_set)); EXPECT_FALSE(m.Matches(test_set)); // There is nothing to report when both sets contain all the same values. @@ -3566,15 +3572,15 @@ TEST(ContainerEqExtraTest, MultiSetOfIntDuplicateDifference) { // Tests that ContainerEq works for non-trivial associative containers, // like maps. TEST(ContainerEqExtraTest, WorksForMaps) { - std::map my_map; + map my_map; my_map[0] = "a"; my_map[1] = "b"; - std::map test_map; + map test_map; test_map[0] = "aa"; test_map[1] = "b"; - const Matcher&> m = ContainerEq(my_map); + const Matcher&> m = ContainerEq(my_map); EXPECT_TRUE(m.Matches(my_map)); EXPECT_FALSE(m.Matches(test_map)); @@ -4072,5 +4078,123 @@ TEST(EachTest, WorksForNativeArrayAsTuple) { EXPECT_THAT(make_tuple(pointer, 2), Not(Each(Gt(1)))); } +// For testing Pointwise(). +class IsHalfOfMatcher { + public: + template + bool MatchAndExplain(const tuple& a_pair, + MatchResultListener* listener) const { + if (get<0>(a_pair) == get<1>(a_pair)/2) { + *listener << "where the second is " << get<1>(a_pair); + return true; + } else { + *listener << "where the second/2 is " << get<1>(a_pair)/2; + return false; + } + } + + void DescribeTo(ostream* os) const { + *os << "are a pair where the first is half of the second"; + } + + void DescribeNegationTo(ostream* os) const { + *os << "are a pair where the first isn't half of the second"; + } +}; + +PolymorphicMatcher IsHalfOf() { + return MakePolymorphicMatcher(IsHalfOfMatcher()); +} + +TEST(PointwiseTest, DescribesSelf) { + vector rhs; + rhs.push_back(1); + rhs.push_back(2); + rhs.push_back(3); + const Matcher&> m = Pointwise(IsHalfOf(), rhs); + EXPECT_EQ("contains 3 values, where each value and its corresponding value " + "in { 1, 2, 3 } are a pair where the first is half of the second", + Describe(m)); + EXPECT_EQ("doesn't contain exactly 3 values, or contains a value x at some " + "index i where x and the i-th value of { 1, 2, 3 } are a pair " + "where the first isn't half of the second", + DescribeNegation(m)); +} + +TEST(PointwiseTest, MakesCopyOfRhs) { + list rhs; + rhs.push_back(2); + rhs.push_back(4); + + int lhs[] = { 1, 2 }; + const Matcher m = Pointwise(IsHalfOf(), rhs); + EXPECT_THAT(lhs, m); + + // Changing rhs now shouldn't affect m, which made a copy of rhs. + rhs.push_back(6); + EXPECT_THAT(lhs, m); +} + +TEST(PointwiseTest, WorksForLhsNativeArray) { + const int lhs[] = { 1, 2, 3 }; + vector rhs; + rhs.push_back(2); + rhs.push_back(4); + rhs.push_back(6); + EXPECT_THAT(lhs, Pointwise(Lt(), rhs)); + EXPECT_THAT(lhs, Not(Pointwise(Gt(), rhs))); +} + +TEST(PointwiseTest, WorksForRhsNativeArray) { + const int rhs[] = { 1, 2, 3 }; + vector lhs; + lhs.push_back(2); + lhs.push_back(4); + lhs.push_back(6); + EXPECT_THAT(lhs, Pointwise(Gt(), rhs)); + EXPECT_THAT(lhs, Not(Pointwise(Lt(), rhs))); +} + +TEST(PointwiseTest, RejectsWrongSize) { + const double lhs[2] = { 1, 2 }; + const int rhs[1] = { 0 }; + EXPECT_THAT(lhs, Not(Pointwise(Gt(), rhs))); + EXPECT_EQ("which contains 2 values", + Explain(Pointwise(Gt(), rhs), lhs)); + + const int rhs2[3] = { 0, 1, 2 }; + EXPECT_THAT(lhs, Not(Pointwise(Gt(), rhs2))); +} + +TEST(PointwiseTest, RejectsWrongContent) { + const double lhs[3] = { 1, 2, 3 }; + const int rhs[3] = { 2, 6, 4 }; + EXPECT_THAT(lhs, Not(Pointwise(IsHalfOf(), rhs))); + EXPECT_EQ("where the value pair (2, 6) at index #1 don't match, " + "where the second/2 is 3", + Explain(Pointwise(IsHalfOf(), rhs), lhs)); +} + +TEST(PointwiseTest, AcceptsCorrectContent) { + const double lhs[3] = { 1, 2, 3 }; + const int rhs[3] = { 2, 4, 6 }; + EXPECT_THAT(lhs, Pointwise(IsHalfOf(), rhs)); + EXPECT_EQ("", Explain(Pointwise(IsHalfOf(), rhs), lhs)); +} + +TEST(PointwiseTest, AllowsMonomorphicInnerMatcher) { + const double lhs[3] = { 1, 2, 3 }; + const int rhs[3] = { 2, 4, 6 }; + const Matcher > m1 = IsHalfOf(); + EXPECT_THAT(lhs, Pointwise(m1, rhs)); + EXPECT_EQ("", Explain(Pointwise(m1, rhs), lhs)); + + // This type works as a tuple can be + // implicitly cast to tuple. + const Matcher > m2 = IsHalfOf(); + EXPECT_THAT(lhs, Pointwise(m2, rhs)); + EXPECT_EQ("", Explain(Pointwise(m2, rhs), lhs)); +} + } // namespace gmock_matchers_test } // namespace testing diff --git a/test/gmock_output_test_golden.txt b/test/gmock_output_test_golden.txt index 382dc8cc..a7ff5630 100644 --- a/test/gmock_output_test_golden.txt +++ b/test/gmock_output_test_golden.txt @@ -151,7 +151,7 @@ FILE:#: pre-requisite #1 [ RUN ] GMockOutputTest.UnsatisfiedWith FILE:#: Failure Actual function call count doesn't match EXPECT_CALL(foo_, Bar2(_, _))... - Expected args: are a pair (x, y) where x >= y + Expected args: are a pair where the first >= the second Expected: to be called once Actual: never called - unsatisfied and active [ FAILED ] GMockOutputTest.UnsatisfiedWith @@ -190,7 +190,7 @@ Unexpected mock function call - returning default value. Google Mock tried the following 1 expectation, but it didn't match: FILE:#: EXPECT_CALL(foo_, Bar2(Ge(2), Ge(1)))... - Expected args: are a pair (x, y) where x >= y + Expected args: are a pair where the first >= the second Actual: don't match Expected: to be called once Actual: never called - unsatisfied and active @@ -206,7 +206,7 @@ Google Mock tried the following 1 expectation, but it didn't match: FILE:#: EXPECT_CALL(foo_, Bar2(Ge(2), Ge(1)))... Expected arg #0: is >= 2 Actual: 1 - Expected args: are a pair (x, y) where x >= y + Expected args: are a pair where the first >= the second Actual: don't match Expected: to be called once Actual: never called - unsatisfied and active