Index: testing/gmock/include/gmock/gmock-matchers.h |
diff --git a/testing/gmock/include/gmock/gmock-matchers.h b/testing/gmock/include/gmock/gmock-matchers.h |
index 5f5a29fd93b7c6eb309daaabd5b66c092ac0191c..9a1bab242a03b60f8d2c7d5ecd67fd0926d02e01 100644 |
--- a/testing/gmock/include/gmock/gmock-matchers.h |
+++ b/testing/gmock/include/gmock/gmock-matchers.h |
@@ -64,16 +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_; } |
+ |
+ // Returns true iff the listener is interested in an explanation of |
+ // the match result. A matcher's MatchAndExplain() method can use |
+ // this information to avoid generating the explanation when no one |
+ // intends to hear it. |
+ bool IsInterested() const { return stream_ != NULL; } |
+ |
+ 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. |
- virtual bool Matches(T x) const = 0; |
- |
- // Describes this matcher to an ostream. |
+ // Returns true iff the matcher matches x; also explains the match |
+ // result to 'listener', in the form of a non-restrictive relative |
+ // clause ("which ...", "whose ...", etc) that describes x. For |
+ // example, the MatchAndExplain() method of the Pointee(...) matcher |
+ // should generate an explanation like "which points to ...". |
+ // |
+ // You should override this method when defining a new matcher. |
+ // |
+ // 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 = 0; |
+ |
+ // Describes this matcher to an ostream. The function should print |
+ // a verb phrase that describes the property a value matching this |
+ // matcher should have. The subject of the verb phrase is the value |
+ // being matched. For example, the DescribeTo() method of the Gt(7) |
+ // matcher prints "is greater than 7". |
virtual void DescribeTo(::std::ostream* os) const = 0; |
// Describes the negation of this matcher to an ostream. For |
@@ -87,27 +145,62 @@ class MatcherInterface { |
DescribeTo(os); |
*os << ")"; |
} |
- |
- // 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. |
- virtual void ExplainMatchResultTo(T /* x */, ::std::ostream* /* os */) const { |
- // By default, nothing more needs to be explained, as Google Mock |
- // has already printed the value of x when this function is |
- // called. |
- } |
}; |
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 +212,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: |
@@ -146,16 +240,6 @@ class MatcherBase { |
::testing::internal::linked_ptr<const MatcherInterface<T> > impl_; |
}; |
-// The default implementation of ExplainMatchResultTo() for |
-// polymorphic matchers. |
-template <typename PolymorphicMatcherImpl, typename T> |
-inline void ExplainMatchResultTo(const PolymorphicMatcherImpl& /* impl */, |
- const T& /* x */, |
- ::std::ostream* /* os */) { |
- // By default, nothing more needs to be said, as Google Mock already |
- // prints the value of x elsewhere. |
-} |
- |
} // namespace internal |
// A Matcher<T> is a copyable and IMMUTABLE (except by assignment) |
@@ -220,19 +304,14 @@ 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, a user should provide an Impl |
+// class that has a DescribeTo() method and a DescribeNegationTo() |
+// method, and define a member function (or member function template) |
// |
-// void ExplainMatchResultTo(const Impl& matcher, const Value& value, |
-// ::std::ostream* os); |
+// bool MatchAndExplain(const Value& value, |
+// MatchResultListener* listener) const; |
// |
-// in the SAME NAME SPACE where Impl is defined. See the definition |
-// of NotNull() for a complete example. |
+// See the definition of NotNull() for a complete example. |
template <class Impl> |
class PolymorphicMatcher { |
public: |
@@ -257,8 +336,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 +344,8 @@ class PolymorphicMatcher { |
impl_.DescribeNegationTo(os); |
} |
- virtual void ExplainMatchResultTo(T x, ::std::ostream* os) const { |
- using ::testing::internal::ExplainMatchResultTo; |
- |
- // 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); |
+ virtual bool MatchAndExplain(T x, MatchResultListener* listener) const { |
+ return impl_.MatchAndExplain(x, listener); |
} |
private: |
@@ -390,16 +453,44 @@ 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 explanation is not empty, prints it to the listener. |
+// 'listener' must not be NULL. |
+inline void PrintIfNotEmpty( |
+ const internal::string& explanation, MatchResultListener* listener) { |
+ if (explanation != "") { |
+ *listener << ", " << explanation; |
+ } |
+} |
+ |
+// Matches the value against the given matcher, prints the value and explains |
+// the match result to the listener. Returns the match result. |
+// 'listener' must not be NULL. |
+// Value cannot be passed by const reference, because some matchers take a |
+// non-const argument. |
+template <typename Value, typename T> |
+bool MatchPrintAndExplain(Value& value, const Matcher<T>& matcher, |
+ MatchResultListener* listener) { |
+ if (!listener->IsInterested()) { |
+ // If the listener is not interested, we do not need to construct the |
+ // inner explanation. |
+ return matcher.Matches(value); |
+ } |
+ |
+ StringMatchResultListener inner_listener; |
+ const bool match = matcher.MatchAndExplain(value, &inner_listener); |
+ |
+ UniversalPrint(value, listener->stream()); |
+ PrintIfNotEmpty(inner_listener.str(), listener); |
+ |
+ return match; |
+} |
+ |
+// 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 +530,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 << ": "; |
@@ -448,11 +540,12 @@ class TuplePrefix { |
// We remove the reference in type Value to prevent the |
// universal printer from printing the address of value, which |
// isn't interesting to the user most of the time. The |
- // matcher's ExplainMatchResultTo() method handles the case when |
+ // matcher's MatchAndExplain() method handles the case when |
// 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 +630,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 +642,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 +661,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 +708,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); \ |
@@ -651,7 +744,10 @@ GMOCK_IMPLEMENT_COMPARISON_MATCHER_(Ne, !=, "not equal to"); |
class IsNullMatcher { |
public: |
template <typename Pointer> |
- bool Matches(const Pointer& p) const { return GetRawPointer(p) == NULL; } |
+ bool MatchAndExplain(const Pointer& p, |
+ MatchResultListener* /* listener */) const { |
+ return GetRawPointer(p) == NULL; |
+ } |
void DescribeTo(::std::ostream* os) const { *os << "is NULL"; } |
void DescribeNegationTo(::std::ostream* os) const { |
@@ -664,7 +760,10 @@ class IsNullMatcher { |
class NotNullMatcher { |
public: |
template <typename Pointer> |
- bool Matches(const Pointer& p) const { return GetRawPointer(p) != NULL; } |
+ bool MatchAndExplain(const Pointer& p, |
+ MatchResultListener* /* listener */) const { |
+ return GetRawPointer(p) != NULL; |
+ } |
void DescribeTo(::std::ostream* os) const { *os << "is not NULL"; } |
void DescribeNegationTo(::std::ostream* os) const { |
@@ -717,9 +816,13 @@ class RefMatcher<T&> { |
public: |
explicit Impl(Super& x) : object_(x) {} // NOLINT |
- // 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 |
+ // MatchAndExplain() takes a Super& (as opposed to const Super&) |
+ // in order to match the interface MatcherInterface<Super&>. |
+ 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 +834,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_; |
@@ -794,14 +892,16 @@ class StrEqualityMatcher { |
// When expect_eq_ is true, returns true iff s is equal to string_; |
// otherwise returns true iff s is not equal to string_. |
- bool Matches(ConstCharPointer s) const { |
+ bool MatchAndExplain(ConstCharPointer s, |
+ MatchResultListener* listener) const { |
if (s == NULL) { |
return !expect_eq_; |
} |
- return Matches(StringType(s)); |
+ return MatchAndExplain(StringType(s), listener); |
} |
- bool Matches(const StringType& s) const { |
+ bool MatchAndExplain(const StringType& s, |
+ MatchResultListener* /* listener */) const { |
const bool eq = case_sensitive_ ? s == string_ : |
CaseInsensitiveStringEquals(s, string_); |
return expect_eq_ == eq; |
@@ -849,11 +949,13 @@ class HasSubstrMatcher { |
// These overloaded methods allow HasSubstr(substring) to be used as a |
// Matcher<T> as long as T can be converted to string. Returns true |
// iff s contains substring_ as a substring. |
- bool Matches(ConstCharPointer s) const { |
- return s != NULL && Matches(StringType(s)); |
+ bool MatchAndExplain(ConstCharPointer s, |
+ MatchResultListener* listener) const { |
+ return s != NULL && MatchAndExplain(StringType(s), listener); |
} |
- bool Matches(const StringType& s) const { |
+ bool MatchAndExplain(const StringType& s, |
+ MatchResultListener* /* listener */) const { |
return s.find(substring_) != StringType::npos; |
} |
@@ -888,11 +990,13 @@ class StartsWithMatcher { |
// These overloaded methods allow StartsWith(prefix) to be used as a |
// Matcher<T> as long as T can be converted to string. Returns true |
// iff s starts with prefix_. |
- bool Matches(ConstCharPointer s) const { |
- return s != NULL && Matches(StringType(s)); |
+ bool MatchAndExplain(ConstCharPointer s, |
+ MatchResultListener* listener) const { |
+ return s != NULL && MatchAndExplain(StringType(s), listener); |
} |
- bool Matches(const StringType& s) const { |
+ bool MatchAndExplain(const StringType& s, |
+ MatchResultListener* /* listener */) const { |
return s.length() >= prefix_.length() && |
s.substr(0, prefix_.length()) == prefix_; |
} |
@@ -926,11 +1030,13 @@ class EndsWithMatcher { |
// These overloaded methods allow EndsWith(suffix) to be used as a |
// Matcher<T> as long as T can be converted to string. Returns true |
// iff s ends with suffix_. |
- bool Matches(ConstCharPointer s) const { |
- return s != NULL && Matches(StringType(s)); |
+ bool MatchAndExplain(ConstCharPointer s, |
+ MatchResultListener* listener) const { |
+ return s != NULL && MatchAndExplain(StringType(s), listener); |
} |
- bool Matches(const StringType& s) const { |
+ bool MatchAndExplain(const StringType& s, |
+ MatchResultListener* /* listener */) const { |
return s.length() >= suffix_.length() && |
s.substr(s.length() - suffix_.length()) == suffix_; |
} |
@@ -951,8 +1057,6 @@ class EndsWithMatcher { |
GTEST_DISALLOW_ASSIGN_(EndsWithMatcher); |
}; |
-#if GMOCK_HAS_REGEX |
- |
// Implements polymorphic matchers MatchesRegex(regex) and |
// ContainsRegex(regex), which can be used as a Matcher<T> as long as |
// T can be converted to a string. |
@@ -965,11 +1069,13 @@ class MatchesRegexMatcher { |
// a Matcher<T> as long as T can be converted to string. Returns |
// true iff s matches regular expression regex. When full_match_ is |
// true, a full match is done; otherwise a partial match is done. |
- bool Matches(const char* s) const { |
- return s != NULL && Matches(internal::string(s)); |
+ bool MatchAndExplain(const char* s, |
+ MatchResultListener* listener) const { |
+ return s != NULL && MatchAndExplain(internal::string(s), listener); |
} |
- bool Matches(const internal::string& s) const { |
+ bool MatchAndExplain(const internal::string& s, |
+ MatchResultListener* /* listener */) const { |
return full_match_ ? RE::FullMatch(s, *regex_) : |
RE::PartialMatch(s, *regex_); |
} |
@@ -993,8 +1099,6 @@ class MatchesRegexMatcher { |
GTEST_DISALLOW_ASSIGN_(MatchesRegexMatcher); |
}; |
-#endif // GMOCK_HAS_REGEX |
- |
// Implements a matcher that compares the two fields of a 2-tuple |
// using one of the ==, <=, <, etc, operators. The two fields being |
// compared don't have to have the same type. |
@@ -1017,7 +1121,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 +1155,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 +1167,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 +1203,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 +1216,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; |
+ } |
- ::std::stringstream ss2; |
- matcher2_.ExplainMatchResultTo(x, &ss2); |
- const internal::string s2 = ss2.str(); |
+ StringMatchResultListener listener2; |
+ if (!matcher2_.MatchAndExplain(x, &listener2)) { |
+ *listener << listener2.str(); |
+ return false; |
+ } |
- if (s1 == "") { |
- *os << s2; |
- } else { |
- *os << s1; |
- if (s2 != "") { |
- *os << "; " << s2; |
- } |
- } |
+ // Otherwise we need to explain why *both* of them match. |
+ const internal::string s1 = listener1.str(); |
+ const internal::string s2 = listener2.str(); |
+ |
+ 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 +1287,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 +1300,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: |
@@ -1281,7 +1374,8 @@ class TrulyMatcher { |
// argument is passed by reference as the predicate may be |
// interested in the address of the argument. |
template <typename T> |
- bool Matches(T& x) const { // NOLINT |
+ bool MatchAndExplain(T& x, // NOLINT |
+ MatchResultListener* /* listener */) const { |
#if GTEST_OS_WINDOWS |
// MSVC warns about converting a value into bool (warning 4800). |
#pragma warning(push) // Saves the current warning state. |
@@ -1367,7 +1461,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 +1471,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 +1512,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 +1621,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 +1631,13 @@ 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(); |
- if (s != "") { |
- *os << "points to a value that " << s; |
- } |
+ *listener << "which points to "; |
+ return MatchPrintAndExplain(*pointer, matcher_, listener); |
} |
private: |
@@ -1572,64 +1660,52 @@ 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 "; |
+ *os << "is an object whose given field "; |
matcher_.DescribeTo(os); |
} |
void DescribeNegationTo(::std::ostream* os) const { |
- *os << "the given field "; |
+ *os << "is an object whose given field "; |
matcher_.DescribeNegationTo(os); |
} |
- // The first argument of ExplainMatchResultTo() is needed to help |
+ template <typename T> |
+ bool MatchAndExplain(const T& value, MatchResultListener* listener) const { |
+ return MatchAndExplainImpl( |
+ typename ::testing::internal:: |
+ is_pointer<GMOCK_REMOVE_CONST_(T)>::type(), |
+ value, listener); |
+ } |
+ |
+ private: |
+ // The first argument of MatchAndExplainImpl() 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(); |
- if (s != "") { |
- *os << "the given field " << s; |
- } |
+ bool MatchAndExplainImpl(false_type /* is_not_pointer */, const Class& obj, |
+ MatchResultListener* listener) const { |
+ *listener << "whose given field is "; |
+ return MatchPrintAndExplain(obj.*field_, matcher_, listener); |
} |
- 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 MatchAndExplainImpl(true_type /* is_pointer */, const Class* p, |
+ MatchResultListener* listener) const { |
+ if (p == NULL) |
+ return false; |
+ |
+ *listener << "which points to an object "; |
+ // 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 MatchAndExplainImpl(false_type(), *p, listener); |
} |
- private: |
const FieldType Class::*field_; |
const Matcher<const FieldType&> matcher_; |
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); |
-} |
- |
// Implements the Property() matcher for matching a property |
// (i.e. return value of a getter method) of an object. |
template <typename Class, typename PropertyType> |
@@ -1645,65 +1721,55 @@ 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 "; |
+ *os << "is an object whose given property "; |
matcher_.DescribeTo(os); |
} |
void DescribeNegationTo(::std::ostream* os) const { |
- *os << "the given property "; |
+ *os << "is an object whose given property "; |
matcher_.DescribeNegationTo(os); |
} |
- // The first argument of ExplainMatchResultTo() is needed to help |
+ template <typename T> |
+ bool MatchAndExplain(const T&value, MatchResultListener* listener) const { |
+ return MatchAndExplainImpl( |
+ typename ::testing::internal:: |
+ is_pointer<GMOCK_REMOVE_CONST_(T)>::type(), |
+ value, listener); |
+ } |
+ |
+ private: |
+ // The first argument of MatchAndExplainImpl() 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(); |
- if (s != "") { |
- *os << "the given property " << s; |
- } |
- } |
+ bool MatchAndExplainImpl(false_type /* is_not_pointer */, const Class& obj, |
+ MatchResultListener* listener) const { |
+ *listener << "whose given property is "; |
+ // Cannot pass the return value (for example, int) to MatchPrintAndExplain, |
+ // which takes a non-const reference as argument. |
+ RefToConstProperty result = (obj.*property_)(); |
+ return MatchPrintAndExplain(result, matcher_, listener); |
+ } |
+ |
+ bool MatchAndExplainImpl(true_type /* is_pointer */, const Class* p, |
+ MatchResultListener* listener) const { |
+ if (p == NULL) |
+ return false; |
- 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); |
- } |
+ *listener << "which points to an object "; |
+ // 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 MatchAndExplainImpl(false_type(), *p, listener); |
} |
- private: |
PropertyType (Class::*property_)() const; |
const Matcher<RefToConstProperty> matcher_; |
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); |
-} |
- |
// Type traits specifying various features of different functors for ResultOf. |
// The default template specifies features for functor objects. |
// Functor classes have to typedef argument_type and result_type |
@@ -1759,32 +1825,24 @@ 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 "; |
+ *os << "is mapped by the given callable to a value that "; |
matcher_.DescribeTo(os); |
} |
virtual void DescribeNegationTo(::std::ostream* os) const { |
- *os << "result of the given callable "; |
+ *os << "is mapped by the given callable to a value that "; |
matcher_.DescribeNegationTo(os); |
} |
- virtual void ExplainMatchResultTo(T obj, ::std::ostream* os) const { |
- ::std::stringstream ss; |
- matcher_.ExplainMatchResultTo( |
- CallableTraits<Callable>::template Invoke<T>(callable_, obj), |
- &ss); |
- const internal::string s = ss.str(); |
- if (s != "") |
- *os << "result of the given callable " << s; |
+ virtual bool MatchAndExplain(T obj, MatchResultListener* listener) const { |
+ *listener << "which is mapped by the given callable to "; |
+ // Cannot pass the return value (for example, int) to |
+ // MatchPrintAndExplain, which takes a non-const reference as argument. |
+ ResultType result = |
+ CallableTraits<Callable>::template Invoke<T>(callable_, obj); |
+ return MatchPrintAndExplain(result, matcher_, listener); |
} |
private: |
@@ -1805,13 +1863,6 @@ class ResultOfMatcher { |
GTEST_DISALLOW_ASSIGN_(ResultOfMatcher); |
}; |
-// Explains the result of matching a value against a functor matcher. |
-template <typename T, typename Callable> |
-void ExplainMatchResultTo(const ResultOfMatcher<Callable>& matcher, |
- T obj, ::std::ostream* os) { |
- matcher.ExplainMatchResultTo(obj, os); |
-} |
- |
// Implements an equality matcher for any STL-style container whose elements |
// support ==. This matcher is like Eq(), but its failure explanations provide |
// more detailed information that is useful when the container is used as a set. |
@@ -1838,15 +1889,6 @@ class ContainerEqMatcher { |
GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container))>(); |
} |
- template <typename LhsContainer> |
- bool Matches(const LhsContainer& lhs) const { |
- // GMOCK_REMOVE_CONST_() is needed to work around an MSVC 8.0 bug |
- // that causes LhsContainer to be a const type sometimes. |
- typedef internal::StlContainerView<GMOCK_REMOVE_CONST_(LhsContainer)> |
- LhsView; |
- StlContainerReference lhs_stl_container = LhsView::ConstReference(lhs); |
- return lhs_stl_container == rhs_; |
- } |
void DescribeTo(::std::ostream* os) const { |
*os << "equals "; |
UniversalPrinter<StlContainer>::Print(rhs_, os); |
@@ -1857,48 +1899,56 @@ class ContainerEqMatcher { |
} |
template <typename LhsContainer> |
- void ExplainMatchResultTo(const LhsContainer& lhs, |
- ::std::ostream* os) const { |
+ bool MatchAndExplain(const LhsContainer& lhs, |
+ MatchResultListener* listener) const { |
// GMOCK_REMOVE_CONST_() is needed to work around an MSVC 8.0 bug |
// that causes LhsContainer to be a const type sometimes. |
typedef internal::StlContainerView<GMOCK_REMOVE_CONST_(LhsContainer)> |
LhsView; |
typedef typename LhsView::type LhsStlContainer; |
StlContainerReference lhs_stl_container = LhsView::ConstReference(lhs); |
- |
- // Something is different. Check for missing values first. |
- bool printed_header = false; |
- for (typename LhsStlContainer::const_iterator it = |
- lhs_stl_container.begin(); |
- it != lhs_stl_container.end(); ++it) { |
- if (internal::ArrayAwareFind(rhs_.begin(), rhs_.end(), *it) == |
- rhs_.end()) { |
- if (printed_header) { |
- *os << ", "; |
- } else { |
- *os << "Only in actual: "; |
- printed_header = true; |
+ if (lhs_stl_container == rhs_) |
+ return true; |
+ |
+ ::std::ostream* const os = listener->stream(); |
+ if (os != NULL) { |
+ // Something is different. Check for missing values first. |
+ bool printed_header = false; |
+ for (typename LhsStlContainer::const_iterator it = |
+ lhs_stl_container.begin(); |
+ it != lhs_stl_container.end(); ++it) { |
+ if (internal::ArrayAwareFind(rhs_.begin(), rhs_.end(), *it) == |
+ rhs_.end()) { |
+ if (printed_header) { |
+ *os << ", "; |
+ } else { |
+ *os << "Only in actual: "; |
+ printed_header = true; |
+ } |
+ UniversalPrinter<typename LhsStlContainer::value_type>:: |
+ Print(*it, os); |
} |
- UniversalPrinter<typename LhsStlContainer::value_type>::Print(*it, os); |
} |
- } |
- // Now check for extra values. |
- bool printed_header2 = false; |
- for (typename StlContainer::const_iterator it = rhs_.begin(); |
- it != rhs_.end(); ++it) { |
- if (internal::ArrayAwareFind( |
- lhs_stl_container.begin(), lhs_stl_container.end(), *it) == |
- lhs_stl_container.end()) { |
- if (printed_header2) { |
- *os << ", "; |
- } else { |
- *os << (printed_header ? "; not" : "Not") << " in actual: "; |
- printed_header2 = true; |
+ // Now check for extra values. |
+ bool printed_header2 = false; |
+ for (typename StlContainer::const_iterator it = rhs_.begin(); |
+ it != rhs_.end(); ++it) { |
+ if (internal::ArrayAwareFind( |
+ lhs_stl_container.begin(), lhs_stl_container.end(), *it) == |
+ lhs_stl_container.end()) { |
+ if (printed_header2) { |
+ *os << ", "; |
+ } else { |
+ *os << (printed_header ? "; not" : "Not") << " in actual: "; |
+ printed_header2 = true; |
+ } |
+ UniversalPrinter<typename StlContainer::value_type>::Print(*it, os); |
} |
- UniversalPrinter<typename StlContainer::value_type>::Print(*it, os); |
} |
} |
+ |
+ return false; |
} |
private: |
@@ -1907,13 +1957,6 @@ class ContainerEqMatcher { |
GTEST_DISALLOW_ASSIGN_(ContainerEqMatcher); |
}; |
-template <typename LhsContainer, typename Container> |
-void ExplainMatchResultTo(const ContainerEqMatcher<Container>& matcher, |
- const LhsContainer& lhs, |
- ::std::ostream* os) { |
- matcher.ExplainMatchResultTo(lhs, os); |
-} |
- |
// Implements Contains(element_matcher) for the given argument type Container. |
template <typename Container> |
class ContainsMatcherImpl : public MatcherInterface<Container> { |
@@ -1929,17 +1972,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 +1984,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 +2038,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 +2055,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 +2095,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,31 +2111,54 @@ 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(); |
- if (s1 != "") { |
- s1 = "the first field " + s1; |
+ // 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 { |
+ if (!listener->IsInterested()) { |
+ // If the listener is not interested, we don't need to construct the |
+ // explanation. |
+ return first_matcher_.Matches(a_pair.first) && |
+ second_matcher_.Matches(a_pair.second); |
} |
- |
- ::std::stringstream ss2; |
- second_matcher_.ExplainMatchResultTo(a_pair.second, &ss2); |
- internal::string s2 = ss2.str(); |
- if (s2 != "") { |
- s2 = "the second field " + s2; |
+ StringMatchResultListener first_inner_listener; |
+ if (!first_matcher_.MatchAndExplain(a_pair.first, |
+ &first_inner_listener)) { |
+ *listener << "whose first field does not match"; |
+ PrintIfNotEmpty(first_inner_listener.str(), listener); |
+ return false; |
} |
- |
- *os << s1; |
- if (s1 != "" && s2 != "") { |
- *os << ", and "; |
+ StringMatchResultListener second_inner_listener; |
+ if (!second_matcher_.MatchAndExplain(a_pair.second, |
+ &second_inner_listener)) { |
+ *listener << "whose second field does not match"; |
+ PrintIfNotEmpty(second_inner_listener.str(), listener); |
+ return false; |
} |
- *os << s2; |
+ ExplainSuccess(first_inner_listener.str(), second_inner_listener.str(), |
+ listener); |
+ return true; |
} |
private: |
+ void ExplainSuccess(const internal::string& first_explanation, |
+ const internal::string& second_explanation, |
+ MatchResultListener* listener) const { |
+ *listener << "whose both fields match"; |
+ if (first_explanation != "") { |
+ *listener << ", where the first field is a value " << first_explanation; |
+ } |
+ if (second_explanation != "") { |
+ *listener << ", "; |
+ if (first_explanation != "") { |
+ *listener << "and "; |
+ } else { |
+ *listener << "where "; |
+ } |
+ *listener << "the second field is a value " << second_explanation; |
+ } |
+ } |
+ |
const Matcher<const FirstType&> first_matcher_; |
const Matcher<const SecondType&> second_matcher_; |
@@ -2165,21 +2207,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 +2243,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"; |
- *os << "element " << i << " doesn't match"; |
+ StreamInParensAsNeeded(s.str(), listener->stream()); |
+ return false; |
+ } |
+ } |
+ |
+ // 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: |
@@ -2609,8 +2627,6 @@ inline PolymorphicMatcher<internal::EndsWithMatcher<internal::string> > |
suffix)); |
} |
-#ifdef GMOCK_HAS_REGEX |
- |
// Matches a string that fully matches regular expression 'regex'. |
// The matcher takes ownership of 'regex'. |
inline PolymorphicMatcher<internal::MatchesRegexMatcher> MatchesRegex( |
@@ -2633,8 +2649,6 @@ inline PolymorphicMatcher<internal::MatchesRegexMatcher> ContainsRegex( |
return ContainsRegex(new internal::RE(regex)); |
} |
-#endif // GMOCK_HAS_REGEX |
- |
#if GTEST_HAS_GLOBAL_WSTRING || GTEST_HAS_STD_WSTRING |
// Wide string matchers. |
@@ -2811,13 +2825,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 |
@@ -2876,6 +2891,14 @@ inline bool Value(const T& value, M matcher) { |
return testing::Matches(matcher)(value); |
} |
+// Matches the value against the given matcher and explains the match |
+// result to listener. |
+template <typename T, typename M> |
+inline bool ExplainMatchResult( |
+ M matcher, const T& value, MatchResultListener* listener) { |
+ return SafeMatcherCast<const T&>(matcher).MatchAndExplain(value, listener); |
+} |
+ |
// AllArgs(m) is a synonym of m. This is useful in |
// |
// EXPECT_CALL(foo, Bar(_, _)).With(AllArgs(Eq())); |