Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(328)

Unified Diff: testing/gmock/include/gmock/gmock-matchers.h

Issue 1151006: Update to current gtest/gmock. (Closed)
Patch Set: rebase Created 10 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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()));
« no previous file with comments | « testing/gmock/include/gmock/gmock-generated-matchers.h.pump ('k') | testing/gmock/include/gmock/gmock-printers.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698