diff options
Diffstat (limited to 'include/gmock/gmock-matchers.h')
| -rw-r--r-- | include/gmock/gmock-matchers.h | 704 |
1 files changed, 382 insertions, 322 deletions
diff --git a/include/gmock/gmock-matchers.h b/include/gmock/gmock-matchers.h index 5f5a29fd..b1689d6e 100644 --- a/include/gmock/gmock-matchers.h +++ b/include/gmock/gmock-matchers.h @@ -64,14 +64,74 @@ namespace testing { // ownership management as Matcher objects can now be copied like // plain values. +// MatchResultListener is an abstract class. Its << operator can be +// used by a matcher to explain why a value matches or doesn't match. +// +// TODO(wan@google.com): add method +// bool InterestedInWhy(bool result) const; +// to indicate whether the listener is interested in why the match +// result is 'result'. +class MatchResultListener { + public: + // Creates a listener object with the given underlying ostream. The + // listener does not own the ostream. + explicit MatchResultListener(::std::ostream* os) : stream_(os) {} + virtual ~MatchResultListener() = 0; // Makes this class abstract. + + // Streams x to the underlying ostream; does nothing if the ostream + // is NULL. + template <typename T> + MatchResultListener& operator<<(const T& x) { + if (stream_ != NULL) + *stream_ << x; + return *this; + } + + // Returns the underlying ostream. + ::std::ostream* stream() { return stream_; } + + private: + ::std::ostream* const stream_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(MatchResultListener); +}; + +inline MatchResultListener::~MatchResultListener() { +} + // The implementation of a matcher. template <typename T> class MatcherInterface { public: virtual ~MatcherInterface() {} + // Returns true iff the matcher matches x; also explains the match + // result to 'listener'. + // + // You should override this method when defining a new matcher. For + // backward compatibility, we provide a default implementation that + // just forwards to the old, deprecated matcher API (Matches() and + // ExplainMatchResultTo()). + // + // It's the responsibility of the caller (Google Mock) to guarantee + // that 'listener' is not NULL. This helps to simplify a matcher's + // implementation when it doesn't care about the performance, as it + // can talk to 'listener' without checking its validity first. + // However, in order to implement dummy listeners efficiently, + // listener->stream() may be NULL. + virtual bool MatchAndExplain(T x, MatchResultListener* listener) const { + const bool match = Matches(x); + if (listener->stream() != NULL) { + ExplainMatchResultTo(x, listener->stream()); + } + return match; + } + + // DEPRECATED. This method will be removed. Override + // MatchAndExplain() instead. + // // Returns true iff the matcher matches x. - virtual bool Matches(T x) const = 0; + virtual bool Matches(T /* x */) const { return false; } // Describes this matcher to an ostream. virtual void DescribeTo(::std::ostream* os) const = 0; @@ -88,6 +148,9 @@ class MatcherInterface { *os << ")"; } + // DEPRECATED. This method will be removed. Override + // MatchAndExplain() instead. + // // Explains why x matches, or doesn't match, the matcher. Override // this to provide any additional information that helps a user // understand the match result. @@ -100,14 +163,58 @@ class MatcherInterface { namespace internal { +// A match result listener that ignores the explanation. +class DummyMatchResultListener : public MatchResultListener { + public: + DummyMatchResultListener() : MatchResultListener(NULL) {} + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(DummyMatchResultListener); +}; + +// A match result listener that forwards the explanation to a given +// ostream. The difference between this and MatchResultListener is +// that the former is concrete. +class StreamMatchResultListener : public MatchResultListener { + public: + explicit StreamMatchResultListener(::std::ostream* os) + : MatchResultListener(os) {} + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(StreamMatchResultListener); +}; + +// A match result listener that stores the explanation in a string. +class StringMatchResultListener : public MatchResultListener { + public: + StringMatchResultListener() : MatchResultListener(&ss_) {} + + // Returns the explanation heard so far. + internal::string str() const { return ss_.str(); } + + private: + ::std::stringstream ss_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(StringMatchResultListener); +}; + // An internal class for implementing Matcher<T>, which will derive // from it. We put functionalities common to all Matcher<T> // specializations here to avoid code duplication. template <typename T> class MatcherBase { public: + // Returns true iff the matcher matches x; also explains the match + // result to 'listener'. + bool MatchAndExplain(T x, MatchResultListener* listener) const { + return impl_->MatchAndExplain(x, listener); + } + // Returns true iff this matcher matches x. - bool Matches(T x) const { return impl_->Matches(x); } + bool Matches(T x) const { + DummyMatchResultListener dummy; + return MatchAndExplain(x, &dummy); + } // Describes this matcher to an ostream. void DescribeTo(::std::ostream* os) const { impl_->DescribeTo(os); } @@ -119,7 +226,8 @@ class MatcherBase { // Explains why x matches, or doesn't match, the matcher. void ExplainMatchResultTo(T x, ::std::ostream* os) const { - impl_->ExplainMatchResultTo(x, os); + StreamMatchResultListener listener(os); + MatchAndExplain(x, &listener); } protected: @@ -156,6 +264,27 @@ inline void ExplainMatchResultTo(const PolymorphicMatcherImpl& /* impl */, // prints the value of x elsewhere. } +// The default implementation of MatchAndExplain() for polymorphic +// matchers. +template <typename PolymorphicMatcherImpl, typename T> +inline bool MatchAndExplain(const PolymorphicMatcherImpl& impl, + const T& x, + MatchResultListener* listener) { + const bool match = impl.Matches(x); + + ::std::ostream* const os = listener->stream(); + if (os != NULL) { + using ::testing::internal::ExplainMatchResultTo; + // When resolving the following call, both + // ::testing::internal::ExplainMatchResultTo() and + // foo::ExplainMatchResultTo() are considered, where foo is the + // namespace where class PolymorphicMatcherImpl is defined. + ExplainMatchResultTo(impl, x, os); + } + + return match; +} + } // namespace internal // A Matcher<T> is a copyable and IMMUTABLE (except by assignment) @@ -220,19 +349,31 @@ class Matcher<internal::string> // polymorphic matcher (i.e. a matcher that can match values of more // than one type, e.g. Eq(n) and NotNull()). // -// To define a polymorphic matcher, a user first provides a Impl class -// that has a Matches() method, a DescribeTo() method, and a -// DescribeNegationTo() method. The Matches() method is usually a -// method template (such that it works with multiple types). Then the -// user creates the polymorphic matcher using -// MakePolymorphicMatcher(). To provide additional explanation to the -// match result, define a FREE function (or function template) +// To define a polymorphic matcher in the old, deprecated way, a user +// first provides an Impl class that has a Matches() method, a +// DescribeTo() method, and a DescribeNegationTo() method. The +// Matches() method is usually a method template (such that it works +// with multiple types). Then the user creates the polymorphic +// matcher using MakePolymorphicMatcher(). To provide additional +// explanation to the match result, define a FREE function (or +// function template) // // void ExplainMatchResultTo(const Impl& matcher, const Value& value, // ::std::ostream* os); // -// in the SAME NAME SPACE where Impl is defined. See the definition -// of NotNull() for a complete example. +// in the SAME NAME SPACE where Impl is defined. +// +// The new, recommended way to define a polymorphic matcher is to +// provide an Impl class that has a DescribeTo() method and a +// DescribeNegationTo() method, and define a FREE function (or +// function template) +// +// bool MatchAndExplain(const Impl& matcher, const Value& value, +// MatchResultListener* listener); +// +// in the SAME NAME SPACE where Impl is defined. +// +// See the definition of NotNull() for a complete example. template <class Impl> class PolymorphicMatcher { public: @@ -257,8 +398,6 @@ class PolymorphicMatcher { public: explicit MonomorphicImpl(const Impl& impl) : impl_(impl) {} - virtual bool Matches(T x) const { return impl_.Matches(x); } - virtual void DescribeTo(::std::ostream* os) const { impl_.DescribeTo(os); } @@ -267,22 +406,15 @@ class PolymorphicMatcher { impl_.DescribeNegationTo(os); } - virtual void ExplainMatchResultTo(T x, ::std::ostream* os) const { - using ::testing::internal::ExplainMatchResultTo; - + virtual bool MatchAndExplain(T x, MatchResultListener* listener) const { // C++ uses Argument-Dependent Look-up (aka Koenig Look-up) to - // resolve the call to ExplainMatchResultTo() here. This - // means that if there's a ExplainMatchResultTo() function - // defined in the name space where class Impl is defined, it - // will be picked by the compiler as the better match. - // Otherwise the default implementation of it in - // ::testing::internal will be picked. - // - // This look-up rule lets a writer of a polymorphic matcher - // customize the behavior of ExplainMatchResultTo() when he - // cares to. Nothing needs to be done by the writer if he - // doesn't need to customize it. - ExplainMatchResultTo(impl_, x, os); + // resolve the call to MatchAndExplain() here. This means that + // if there's a MatchAndExplain() function defined in the name + // space where class Impl is defined, it will be picked by the + // compiler as the better match. Otherwise the default + // implementation of it in ::testing::internal will be picked. + using ::testing::internal::MatchAndExplain; + return MatchAndExplain(impl_, x, listener); } private: @@ -390,16 +522,12 @@ Matcher<T> A(); // and MUST NOT BE USED IN USER CODE!!! namespace internal { -// Appends the explanation on the result of matcher.Matches(value) to -// os iff the explanation is not empty. -template <typename T> -void ExplainMatchResultAsNeededTo(const Matcher<T>& matcher, T value, - ::std::ostream* os) { - ::std::stringstream reason; - matcher.ExplainMatchResultTo(value, &reason); - const internal::string s = reason.str(); - if (s != "") { - *os << " (" << s << ")"; +// If the given string is not empty and os is not NULL, wraps the +// string inside a pair of parentheses and streams the result to os. +inline void StreamInParensAsNeeded(const internal::string& str, + ::std::ostream* os) { + if (!str.empty() && os != NULL) { + *os << " (" << str << ")"; } } @@ -439,7 +567,8 @@ class TuplePrefix { get<N - 1>(matchers); typedef typename tuple_element<N - 1, ValueTuple>::type Value; Value value = get<N - 1>(values); - if (!matcher.Matches(value)) { + StringMatchResultListener listener; + if (!matcher.MatchAndExplain(value, &listener)) { // TODO(wan): include in the message the name of the parameter // as used in MOCK_METHOD*() when possible. *os << " Expected arg #" << N - 1 << ": "; @@ -452,7 +581,8 @@ class TuplePrefix { // the address is interesting. internal::UniversalPrinter<GMOCK_REMOVE_REFERENCE_(Value)>:: Print(value, os); - ExplainMatchResultAsNeededTo<Value>(matcher, value, os); + + StreamInParensAsNeeded(listener.str(), os); *os << "\n"; } } @@ -537,8 +667,8 @@ class MatcherCastImpl<T, Matcher<U> > { : source_matcher_(source_matcher) {} // We delegate the matching logic to the source matcher. - virtual bool Matches(T x) const { - return source_matcher_.Matches(static_cast<U>(x)); + virtual bool MatchAndExplain(T x, MatchResultListener* listener) const { + return source_matcher_.MatchAndExplain(static_cast<U>(x), listener); } virtual void DescribeTo(::std::ostream* os) const { @@ -549,10 +679,6 @@ class MatcherCastImpl<T, Matcher<U> > { source_matcher_.DescribeNegationTo(os); } - virtual void ExplainMatchResultTo(T x, ::std::ostream* os) const { - source_matcher_.ExplainMatchResultTo(static_cast<U>(x), os); - } - private: const Matcher<U> source_matcher_; @@ -572,7 +698,8 @@ class MatcherCastImpl<T, Matcher<T> > { template <typename T> class AnyMatcherImpl : public MatcherInterface<T> { public: - virtual bool Matches(T /* x */) const { return true; } + virtual bool MatchAndExplain( + T /* x */, MatchResultListener* /* listener */) const { return true; } virtual void DescribeTo(::std::ostream* os) const { *os << "is anything"; } virtual void DescribeNegationTo(::std::ostream* os) const { // This is mostly for completeness' safe, as it's not very useful @@ -618,7 +745,10 @@ class AnythingMatcher { class Impl : public MatcherInterface<Lhs> { \ public: \ explicit Impl(const Rhs& rhs) : rhs_(rhs) {} \ - virtual bool Matches(Lhs lhs) const { return lhs op rhs_; } \ + virtual bool MatchAndExplain(\ + Lhs lhs, MatchResultListener* /* listener */) const { \ + return lhs op rhs_; \ + } \ virtual void DescribeTo(::std::ostream* os) const { \ *os << "is " relation " "; \ UniversalPrinter<Rhs>::Print(rhs_, os); \ @@ -719,7 +849,11 @@ class RefMatcher<T&> { // Matches() takes a Super& (as opposed to const Super&) in // order to match the interface MatcherInterface<Super&>. - virtual bool Matches(Super& x) const { return &x == &object_; } // NOLINT + virtual bool MatchAndExplain( + Super& x, MatchResultListener* listener) const { + *listener << "is located @" << static_cast<const void*>(&x); + return &x == &object_; + } virtual void DescribeTo(::std::ostream* os) const { *os << "references the variable "; @@ -731,11 +865,6 @@ class RefMatcher<T&> { UniversalPrinter<Super&>::Print(object_, os); } - virtual void ExplainMatchResultTo(Super& x, // NOLINT - ::std::ostream* os) const { - *os << "is located @" << static_cast<const void*>(&x); - } - private: const Super& object_; @@ -1017,7 +1146,9 @@ class MatchesRegexMatcher { template <typename T1, typename T2> \ class Impl : public MatcherInterface<const ::std::tr1::tuple<T1, T2>&> { \ public: \ - virtual bool Matches(const ::std::tr1::tuple<T1, T2>& args) const { \ + virtual bool MatchAndExplain( \ + const ::std::tr1::tuple<T1, T2>& args, \ + MatchResultListener* /* listener */) const { \ return ::std::tr1::get<0>(args) op ::std::tr1::get<1>(args); \ } \ virtual void DescribeTo(::std::ostream* os) const { \ @@ -1049,8 +1180,8 @@ class NotMatcherImpl : public MatcherInterface<T> { explicit NotMatcherImpl(const Matcher<T>& matcher) : matcher_(matcher) {} - virtual bool Matches(T x) const { - return !matcher_.Matches(x); + virtual bool MatchAndExplain(T x, MatchResultListener* listener) const { + return !matcher_.MatchAndExplain(x, listener); } virtual void DescribeTo(::std::ostream* os) const { @@ -1061,10 +1192,6 @@ class NotMatcherImpl : public MatcherInterface<T> { matcher_.DescribeTo(os); } - virtual void ExplainMatchResultTo(T x, ::std::ostream* os) const { - matcher_.ExplainMatchResultTo(x, os); - } - private: const Matcher<T> matcher_; @@ -1101,10 +1228,6 @@ class BothOfMatcherImpl : public MatcherInterface<T> { BothOfMatcherImpl(const Matcher<T>& matcher1, const Matcher<T>& matcher2) : matcher1_(matcher1), matcher2_(matcher2) {} - virtual bool Matches(T x) const { - return matcher1_.Matches(x) && matcher2_.Matches(x); - } - virtual void DescribeTo(::std::ostream* os) const { *os << "("; matcher1_.DescribeTo(os); @@ -1118,35 +1241,34 @@ class BothOfMatcherImpl : public MatcherInterface<T> { DescribeTo(os); } - virtual void ExplainMatchResultTo(T x, ::std::ostream* os) const { - if (Matches(x)) { - // When both matcher1_ and matcher2_ match x, we need to - // explain why *both* of them match. - ::std::stringstream ss1; - matcher1_.ExplainMatchResultTo(x, &ss1); - const internal::string s1 = ss1.str(); + virtual bool MatchAndExplain(T x, MatchResultListener* listener) const { + // If either matcher1_ or matcher2_ doesn't match x, we only need + // to explain why one of them fails. + StringMatchResultListener listener1; + if (!matcher1_.MatchAndExplain(x, &listener1)) { + *listener << listener1.str(); + return false; + } + + StringMatchResultListener listener2; + if (!matcher2_.MatchAndExplain(x, &listener2)) { + *listener << listener2.str(); + return false; + } - ::std::stringstream ss2; - matcher2_.ExplainMatchResultTo(x, &ss2); - const internal::string s2 = ss2.str(); + // Otherwise we need to explain why *both* of them match. + const internal::string s1 = listener1.str(); + const internal::string s2 = listener2.str(); - if (s1 == "") { - *os << s2; - } else { - *os << s1; - if (s2 != "") { - *os << "; " << s2; - } - } + if (s1 == "") { + *listener << s2; } else { - // Otherwise we only need to explain why *one* of them fails - // to match. - if (!matcher1_.Matches(x)) { - matcher1_.ExplainMatchResultTo(x, os); - } else { - matcher2_.ExplainMatchResultTo(x, os); + *listener << s1; + if (s2 != "") { + *listener << "; " << s2; } } + return true; } private: @@ -1190,10 +1312,6 @@ class EitherOfMatcherImpl : public MatcherInterface<T> { EitherOfMatcherImpl(const Matcher<T>& matcher1, const Matcher<T>& matcher2) : matcher1_(matcher1), matcher2_(matcher2) {} - virtual bool Matches(T x) const { - return matcher1_.Matches(x) || matcher2_.Matches(x); - } - virtual void DescribeTo(::std::ostream* os) const { *os << "("; matcher1_.DescribeTo(os); @@ -1207,34 +1325,34 @@ class EitherOfMatcherImpl : public MatcherInterface<T> { DescribeTo(os); } - virtual void ExplainMatchResultTo(T x, ::std::ostream* os) const { - if (Matches(x)) { - // If either matcher1_ or matcher2_ matches x, we just need - // to explain why *one* of them matches. - if (matcher1_.Matches(x)) { - matcher1_.ExplainMatchResultTo(x, os); - } else { - matcher2_.ExplainMatchResultTo(x, os); - } - } else { - // Otherwise we need to explain why *neither* matches. - ::std::stringstream ss1; - matcher1_.ExplainMatchResultTo(x, &ss1); - const internal::string s1 = ss1.str(); + virtual bool MatchAndExplain(T x, MatchResultListener* listener) const { + // If either matcher1_ or matcher2_ matches x, we just need to + // explain why *one* of them matches. + StringMatchResultListener listener1; + if (matcher1_.MatchAndExplain(x, &listener1)) { + *listener << listener1.str(); + return true; + } - ::std::stringstream ss2; - matcher2_.ExplainMatchResultTo(x, &ss2); - const internal::string s2 = ss2.str(); + StringMatchResultListener listener2; + if (matcher2_.MatchAndExplain(x, &listener2)) { + *listener << listener2.str(); + return true; + } - if (s1 == "") { - *os << s2; - } else { - *os << s1; - if (s2 != "") { - *os << "; " << s2; - } + // Otherwise we need to explain why *both* of them fail. + const internal::string s1 = listener1.str(); + const internal::string s2 = listener2.str(); + + if (s1 == "") { + *listener << s2; + } else { + *listener << s1; + if (s2 != "") { + *listener << "; " << s2; } } + return false; } private: @@ -1367,7 +1485,8 @@ class PredicateFormatterFromMatcher { // Matcher<const T&>(matcher_), as the latter won't compile when // matcher_ has type Matcher<T> (e.g. An<int>()). const Matcher<const T&> matcher = MatcherCast<const T&>(matcher_); - if (matcher.Matches(x)) { + StringMatchResultListener listener; + if (matcher.MatchAndExplain(x, &listener)) { return AssertionSuccess(); } else { ::std::stringstream ss; @@ -1376,7 +1495,7 @@ class PredicateFormatterFromMatcher { matcher.DescribeTo(&ss); ss << "\n Actual: "; UniversalPrinter<T>::Print(x, &ss); - ExplainMatchResultAsNeededTo<const T&>(matcher, x, &ss); + StreamInParensAsNeeded(listener.str(), &ss); return AssertionFailure(Message() << ss.str()); } } @@ -1417,7 +1536,8 @@ class FloatingEqMatcher { Impl(FloatType rhs, bool nan_eq_nan) : rhs_(rhs), nan_eq_nan_(nan_eq_nan) {} - virtual bool Matches(T value) const { + virtual bool MatchAndExplain(T value, + MatchResultListener* /* listener */) const { const FloatingPoint<FloatType> lhs(value), rhs(rhs_); // Compares NaNs first, if nan_eq_nan_ is true. @@ -1525,10 +1645,6 @@ class PointeeMatcher { explicit Impl(const InnerMatcher& matcher) : matcher_(MatcherCast<const Pointee&>(matcher)) {} - virtual bool Matches(Pointer p) const { - return GetRawPointer(p) != NULL && matcher_.Matches(*p); - } - virtual void DescribeTo(::std::ostream* os) const { *os << "points to a value that "; matcher_.DescribeTo(os); @@ -1539,17 +1655,18 @@ class PointeeMatcher { matcher_.DescribeTo(os); } - virtual void ExplainMatchResultTo(Pointer pointer, - ::std::ostream* os) const { + virtual bool MatchAndExplain(Pointer pointer, + MatchResultListener* listener) const { if (GetRawPointer(pointer) == NULL) - return; + return false; - ::std::stringstream ss; - matcher_.ExplainMatchResultTo(*pointer, &ss); - const internal::string s = ss.str(); + StringMatchResultListener inner_listener; + const bool match = matcher_.MatchAndExplain(*pointer, &inner_listener); + const internal::string s = inner_listener.str(); if (s != "") { - *os << "points to a value that " << s; + *listener << "points to a value that " << s; } + return match; } private: @@ -1572,16 +1689,6 @@ class FieldMatcher { const Matcher<const FieldType&>& matcher) : field_(field), matcher_(matcher) {} - // Returns true iff the inner matcher matches obj.field. - bool Matches(const Class& obj) const { - return matcher_.Matches(obj.*field_); - } - - // Returns true iff the inner matcher matches obj->field. - bool Matches(const Class* p) const { - return (p != NULL) && matcher_.Matches(p->*field_); - } - void DescribeTo(::std::ostream* os) const { *os << "the given field "; matcher_.DescribeTo(os); @@ -1592,27 +1699,29 @@ class FieldMatcher { matcher_.DescribeNegationTo(os); } - // The first argument of ExplainMatchResultTo() is needed to help + // The first argument of MatchAndExplain() is needed to help // Symbian's C++ compiler choose which overload to use. Its type is // true_type iff the Field() matcher is used to match a pointer. - void ExplainMatchResultTo(false_type /* is_not_pointer */, const Class& obj, - ::std::ostream* os) const { - ::std::stringstream ss; - matcher_.ExplainMatchResultTo(obj.*field_, &ss); - const internal::string s = ss.str(); + bool MatchAndExplain(false_type /* is_not_pointer */, const Class& obj, + MatchResultListener* listener) const { + StringMatchResultListener inner_listener; + const bool match = matcher_.MatchAndExplain(obj.*field_, &inner_listener); + const internal::string s = inner_listener.str(); if (s != "") { - *os << "the given field " << s; + *listener << "the given field " << s; } + return match; } - void ExplainMatchResultTo(true_type /* is_pointer */, const Class* p, - ::std::ostream* os) const { - if (p != NULL) { - // Since *p has a field, it must be a class/struct/union type - // and thus cannot be a pointer. Therefore we pass false_type() - // as the first argument. - ExplainMatchResultTo(false_type(), *p, os); - } + bool MatchAndExplain(true_type /* is_pointer */, const Class* p, + MatchResultListener* listener) const { + if (p == NULL) + return false; + + // Since *p has a field, it must be a class/struct/union type and + // thus cannot be a pointer. Therefore we pass false_type() as + // the first argument. + return MatchAndExplain(false_type(), *p, listener); } private: @@ -1622,12 +1731,11 @@ class FieldMatcher { GTEST_DISALLOW_ASSIGN_(FieldMatcher); }; -// Explains the result of matching an object or pointer against a field matcher. template <typename Class, typename FieldType, typename T> -void ExplainMatchResultTo(const FieldMatcher<Class, FieldType>& matcher, - const T& value, ::std::ostream* os) { - matcher.ExplainMatchResultTo( - typename ::testing::internal::is_pointer<T>::type(), value, os); +bool MatchAndExplain(const FieldMatcher<Class, FieldType>& matcher, + const T& value, MatchResultListener* listener) { + return matcher.MatchAndExplain( + typename ::testing::internal::is_pointer<T>::type(), value, listener); } // Implements the Property() matcher for matching a property @@ -1645,16 +1753,6 @@ class PropertyMatcher { const Matcher<RefToConstProperty>& matcher) : property_(property), matcher_(matcher) {} - // Returns true iff obj.property() matches the inner matcher. - bool Matches(const Class& obj) const { - return matcher_.Matches((obj.*property_)()); - } - - // Returns true iff p->property() matches the inner matcher. - bool Matches(const Class* p) const { - return (p != NULL) && matcher_.Matches((p->*property_)()); - } - void DescribeTo(::std::ostream* os) const { *os << "the given property "; matcher_.DescribeTo(os); @@ -1665,27 +1763,30 @@ class PropertyMatcher { matcher_.DescribeNegationTo(os); } - // The first argument of ExplainMatchResultTo() is needed to help + // The first argument of MatchAndExplain() is needed to help // Symbian's C++ compiler choose which overload to use. Its type is // true_type iff the Property() matcher is used to match a pointer. - void ExplainMatchResultTo(false_type /* is_not_pointer */, const Class& obj, - ::std::ostream* os) const { - ::std::stringstream ss; - matcher_.ExplainMatchResultTo((obj.*property_)(), &ss); - const internal::string s = ss.str(); + bool MatchAndExplain(false_type /* is_not_pointer */, const Class& obj, + MatchResultListener* listener) const { + StringMatchResultListener inner_listener; + const bool match = matcher_.MatchAndExplain((obj.*property_)(), + &inner_listener); + const internal::string s = inner_listener.str(); if (s != "") { - *os << "the given property " << s; + *listener << "the given property " << s; } + return match; } - void ExplainMatchResultTo(true_type /* is_pointer */, const Class* p, - ::std::ostream* os) const { - if (p != NULL) { - // Since *p has a property method, it must be a - // class/struct/union type and thus cannot be a pointer. - // Therefore we pass false_type() as the first argument. - ExplainMatchResultTo(false_type(), *p, os); - } + bool MatchAndExplain(true_type /* is_pointer */, const Class* p, + MatchResultListener* listener) const { + if (p == NULL) + return false; + + // Since *p has a property method, it must be a class/struct/union + // type and thus cannot be a pointer. Therefore we pass + // false_type() as the first argument. + return MatchAndExplain(false_type(), *p, listener); } private: @@ -1695,13 +1796,11 @@ class PropertyMatcher { GTEST_DISALLOW_ASSIGN_(PropertyMatcher); }; -// Explains the result of matching an object or pointer against a -// property matcher. -template <typename Class, typename PropertyType, typename T> -void ExplainMatchResultTo(const PropertyMatcher<Class, PropertyType>& matcher, - const T& value, ::std::ostream* os) { - matcher.ExplainMatchResultTo( - typename ::testing::internal::is_pointer<T>::type(), value, os); +template <typename Class, typename PropertyType, typename T> +bool MatchAndExplain(const PropertyMatcher<Class, PropertyType>& matcher, + const T& value, MatchResultListener* listener) { + return matcher.MatchAndExplain( + typename ::testing::internal::is_pointer<T>::type(), value, listener); } // Type traits specifying various features of different functors for ResultOf. @@ -1759,13 +1858,6 @@ class ResultOfMatcher { public: Impl(CallableStorageType callable, const Matcher<ResultType>& matcher) : callable_(callable), matcher_(matcher) {} - // Returns true iff callable_(obj) matches the inner matcher. - // The calling syntax is different for different types of callables - // so we abstract it in CallableTraits<Callable>::Invoke(). - virtual bool Matches(T obj) const { - return matcher_.Matches( - CallableTraits<Callable>::template Invoke<T>(callable_, obj)); - } virtual void DescribeTo(::std::ostream* os) const { *os << "result of the given callable "; @@ -1777,14 +1869,17 @@ class ResultOfMatcher { matcher_.DescribeNegationTo(os); } - virtual void ExplainMatchResultTo(T obj, ::std::ostream* os) const { - ::std::stringstream ss; - matcher_.ExplainMatchResultTo( + virtual bool MatchAndExplain(T obj, MatchResultListener* listener) const { + StringMatchResultListener inner_listener; + const bool match = matcher_.MatchAndExplain( CallableTraits<Callable>::template Invoke<T>(callable_, obj), - &ss); - const internal::string s = ss.str(); + &inner_listener); + + const internal::string s = inner_listener.str(); if (s != "") - *os << "result of the given callable " << s; + *listener << "result of the given callable " << s; + + return match; } private: @@ -1929,17 +2024,6 @@ class ContainsMatcherImpl : public MatcherInterface<Container> { : inner_matcher_( testing::SafeMatcherCast<const Element&>(inner_matcher)) {} - // Returns true iff 'container' matches. - virtual bool Matches(Container container) const { - StlContainerReference stl_container = View::ConstReference(container); - for (typename StlContainer::const_iterator it = stl_container.begin(); - it != stl_container.end(); ++it) { - if (inner_matcher_.Matches(*it)) - return true; - } - return false; - } - // Describes what this matcher does. virtual void DescribeTo(::std::ostream* os) const { *os << "contains at least one element that "; @@ -1952,19 +2036,18 @@ class ContainsMatcherImpl : public MatcherInterface<Container> { inner_matcher_.DescribeTo(os); } - // Explains why 'container' matches, or doesn't match, this matcher. - virtual void ExplainMatchResultTo(Container container, - ::std::ostream* os) const { + virtual bool MatchAndExplain(Container container, + MatchResultListener* listener) const { StlContainerReference stl_container = View::ConstReference(container); - - // We need to explain which (if any) element matches inner_matcher_. - typename StlContainer::const_iterator it = stl_container.begin(); - for (size_t i = 0; it != stl_container.end(); ++it, ++i) { + size_t i = 0; + for (typename StlContainer::const_iterator it = stl_container.begin(); + it != stl_container.end(); ++it, ++i) { if (inner_matcher_.Matches(*it)) { - *os << "element " << i << " matches"; - return; + *listener << "element " << i << " matches"; + return true; } } + return false; } private: @@ -2007,8 +2090,9 @@ class KeyMatcherImpl : public MatcherInterface<PairType> { } // Returns true iff 'key_value.first' (the key) matches the inner matcher. - virtual bool Matches(PairType key_value) const { - return inner_matcher_.Matches(key_value.first); + virtual bool MatchAndExplain(PairType key_value, + MatchResultListener* listener) const { + return inner_matcher_.MatchAndExplain(key_value.first, listener); } // Describes what this matcher does. @@ -2023,12 +2107,6 @@ class KeyMatcherImpl : public MatcherInterface<PairType> { inner_matcher_.DescribeTo(os); } - // Explains why 'key_value' matches, or doesn't match, this matcher. - virtual void ExplainMatchResultTo(PairType key_value, - ::std::ostream* os) const { - inner_matcher_.ExplainMatchResultTo(key_value.first, os); - } - private: const Matcher<const KeyType&> inner_matcher_; @@ -2069,13 +2147,6 @@ class PairMatcherImpl : public MatcherInterface<PairType> { testing::SafeMatcherCast<const SecondType&>(second_matcher)) { } - // Returns true iff 'a_pair.first' matches first_matcher and 'a_pair.second' - // matches second_matcher. - virtual bool Matches(PairType a_pair) const { - return first_matcher_.Matches(a_pair.first) && - second_matcher_.Matches(a_pair.second); - } - // Describes what this matcher does. virtual void DescribeTo(::std::ostream* os) const { *os << "has a first field that "; @@ -2092,28 +2163,40 @@ class PairMatcherImpl : public MatcherInterface<PairType> { second_matcher_.DescribeNegationTo(os); } - // Explains why 'a_pair' matches, or doesn't match, this matcher. - virtual void ExplainMatchResultTo(PairType a_pair, - ::std::ostream* os) const { - ::std::stringstream ss1; - first_matcher_.ExplainMatchResultTo(a_pair.first, &ss1); - internal::string s1 = ss1.str(); + // Returns true iff 'a_pair.first' matches first_matcher and 'a_pair.second' + // matches second_matcher. + virtual bool MatchAndExplain(PairType a_pair, + MatchResultListener* listener) const { + StringMatchResultListener listener1; + const bool match1 = first_matcher_.MatchAndExplain(a_pair.first, + &listener1); + internal::string s1 = listener1.str(); if (s1 != "") { - s1 = "the first field " + s1; + s1 = "the first field " + s1; + } + if (!match1) { + *listener << s1; + return false; } - ::std::stringstream ss2; - second_matcher_.ExplainMatchResultTo(a_pair.second, &ss2); - internal::string s2 = ss2.str(); + StringMatchResultListener listener2; + const bool match2 = second_matcher_.MatchAndExplain(a_pair.second, + &listener2); + internal::string s2 = listener2.str(); if (s2 != "") { - s2 = "the second field " + s2; + s2 = "the second field " + s2; + } + if (!match2) { + *listener << s2; + return false; } - *os << s1; + *listener << s1; if (s1 != "" && s2 != "") { - *os << ", and "; + *listener << ", and "; } - *os << s2; + *listener << s2; + return true; } private: @@ -2165,21 +2248,6 @@ class ElementsAreMatcherImpl : public MatcherInterface<Container> { } } - // Returns true iff 'container' matches. - virtual bool Matches(Container container) const { - StlContainerReference stl_container = View::ConstReference(container); - if (stl_container.size() != count()) - return false; - - typename StlContainer::const_iterator it = stl_container.begin(); - for (size_t i = 0; i != count(); ++it, ++i) { - if (!matchers_[i].Matches(*it)) - return false; - } - - return true; - } - // Describes what this matcher does. virtual void DescribeTo(::std::ostream* os) const { if (count() == 0) { @@ -2216,63 +2284,54 @@ class ElementsAreMatcherImpl : public MatcherInterface<Container> { } } - // Explains why 'container' matches, or doesn't match, this matcher. - virtual void ExplainMatchResultTo(Container container, - ::std::ostream* os) const { + virtual bool MatchAndExplain(Container container, + MatchResultListener* listener) const { StlContainerReference stl_container = View::ConstReference(container); - if (Matches(container)) { - // We need to explain why *each* element matches (the obvious - // ones can be skipped). - - bool reason_printed = false; - typename StlContainer::const_iterator it = stl_container.begin(); - for (size_t i = 0; i != count(); ++it, ++i) { - ::std::stringstream ss; - matchers_[i].ExplainMatchResultTo(*it, &ss); - - const string s = ss.str(); - if (!s.empty()) { - if (reason_printed) { - *os << ",\n"; - } - *os << "element " << i << " " << s; - reason_printed = true; - } - } - } else { - // We need to explain why the container doesn't match. - const size_t actual_count = stl_container.size(); - if (actual_count != count()) { - // The element count doesn't match. If the container is - // empty, there's no need to explain anything as Google Mock - // already prints the empty container. Otherwise we just need - // to show how many elements there actually are. - if (actual_count != 0) { - *os << "has " << Elements(actual_count); - } - return; + const size_t actual_count = stl_container.size(); + if (actual_count != count()) { + // The element count doesn't match. If the container is empty, + // there's no need to explain anything as Google Mock already + // prints the empty container. Otherwise we just need to show + // how many elements there actually are. + if (actual_count != 0) { + *listener << "has " << Elements(actual_count); } + return false; + } - // The container has the right size but at least one element - // doesn't match expectation. We need to find this element and - // explain why it doesn't match. - typename StlContainer::const_iterator it = stl_container.begin(); - for (size_t i = 0; i != count(); ++it, ++i) { - if (matchers_[i].Matches(*it)) { - continue; - } + typename StlContainer::const_iterator it = stl_container.begin(); + // explanations[i] is the explanation of the element at index i. + std::vector<internal::string> explanations(count()); + for (size_t i = 0; i != count(); ++it, ++i) { + StringMatchResultListener s; + if (matchers_[i].MatchAndExplain(*it, &s)) { + explanations[i] = s.str(); + } else { + // The container has the right size but the i-th element + // doesn't match its expectation. + *listener << "element " << i << " doesn't match"; + + StreamInParensAsNeeded(s.str(), listener->stream()); + return false; + } + } - *os << "element " << i << " doesn't match"; + // Every element matches its expectation. We need to explain why + // (the obvious ones can be skipped). - ::std::stringstream ss; - matchers_[i].ExplainMatchResultTo(*it, &ss); - const string s = ss.str(); - if (!s.empty()) { - *os << " (" << s << ")"; + bool reason_printed = false; + for (size_t i = 0; i != count(); ++i) { + const internal::string& s = explanations[i]; + if (!s.empty()) { + if (reason_printed) { + *listener << ",\n"; } - return; + *listener << "element " << i << " " << s; + reason_printed = true; } } + + return true; } private: @@ -2811,13 +2870,14 @@ Truly(Predicate pred) { // values that are included in one container but not the other. (Duplicate // values and order differences are not explained.) template <typename Container> -inline PolymorphicMatcher<internal::ContainerEqMatcher< +inline PolymorphicMatcher<internal::ContainerEqMatcher< // NOLINT GMOCK_REMOVE_CONST_(Container)> > ContainerEq(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 GMOCK_REMOVE_CONST_(Container) RawContainer; - return MakePolymorphicMatcher(internal::ContainerEqMatcher<RawContainer>(rhs)); + return MakePolymorphicMatcher( + internal::ContainerEqMatcher<RawContainer>(rhs)); } // Matches an STL-style container or a native array that contains at |
