From 821133180ccdb9eb062548d964929ba3b354eb84 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Fri, 8 Jan 2010 21:55:40 +0000 Subject: [PATCH] Implements the new matcher API. --- include/gmock/gmock-generated-matchers.h | 189 +++-- include/gmock/gmock-generated-matchers.h.pump | 92 ++- include/gmock/gmock-matchers.h | 710 ++++++++++-------- include/gmock/gmock-spec-builders.h | 6 +- test/gmock-generated-matchers_test.cc | 52 ++ test/gmock-matchers_test.cc | 145 +++- 6 files changed, 766 insertions(+), 428 deletions(-) diff --git a/include/gmock/gmock-generated-matchers.h b/include/gmock/gmock-generated-matchers.h index 18420c1d..731ad7df 100644 --- a/include/gmock/gmock-generated-matchers.h +++ b/include/gmock/gmock-generated-matchers.h @@ -229,8 +229,9 @@ class ArgsMatcherImpl : public MatcherInterface { explicit ArgsMatcherImpl(const InnerMatcher& inner_matcher) : inner_matcher_(SafeMatcherCast(inner_matcher)) {} - virtual bool Matches(ArgsTuple args) const { - return inner_matcher_.Matches(GetSelectedArgs(args)); + virtual bool MatchAndExplain(ArgsTuple args, + MatchResultListener* listener) const { + return inner_matcher_.MatchAndExplain(GetSelectedArgs(args), listener); } virtual void DescribeTo(::std::ostream* os) const { @@ -243,11 +244,6 @@ class ArgsMatcherImpl : public MatcherInterface { inner_matcher_.DescribeNegationTo(os); } - virtual void ExplainMatchResultTo(ArgsTuple args, - ::std::ostream* os) const { - inner_matcher_.ExplainMatchResultTo(GetSelectedArgs(args), os); - } - private: static SelectedArgs GetSelectedArgs(ArgsTuple args) { return TupleFields\ - bool name##Matcher::\ - gmock_Impl::Matches(arg_type arg) const + bool name##Matcher::gmock_Impl::MatchAndExplain(\ + arg_type arg,\ + ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\ + const #define MATCHER_P(name, p0, description)\ template \ @@ -1071,7 +1109,8 @@ ElementsAreArray(const T (&array)[N]) { explicit gmock_Impl(p0##_type gmock_p0, \ const ::testing::internal::Interpolations& gmock_interp)\ : p0(gmock_p0), gmock_interp_(gmock_interp) {}\ - virtual bool Matches(arg_type arg) const;\ + virtual bool MatchAndExplain(\ + arg_type arg, ::testing::MatchResultListener* result_listener) const;\ virtual void DescribeTo(::std::ostream* gmock_os) const {\ const ::testing::internal::Strings& gmock_printed_params = \ ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\ @@ -1105,8 +1144,10 @@ ElementsAreArray(const T (&array)[N]) { }\ template \ template \ - bool name##MatcherP::\ - gmock_Impl::Matches(arg_type arg) const + bool name##MatcherP::gmock_Impl::MatchAndExplain(\ + arg_type arg,\ + ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\ + const #define MATCHER_P2(name, p0, p1, description)\ template \ @@ -1118,7 +1159,8 @@ ElementsAreArray(const T (&array)[N]) { gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, \ const ::testing::internal::Interpolations& gmock_interp)\ : p0(gmock_p0), p1(gmock_p1), gmock_interp_(gmock_interp) {}\ - virtual bool Matches(arg_type arg) const;\ + virtual bool MatchAndExplain(\ + arg_type arg, ::testing::MatchResultListener* result_listener) const;\ virtual void DescribeTo(::std::ostream* gmock_os) const {\ const ::testing::internal::Strings& gmock_printed_params = \ ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\ @@ -1156,8 +1198,11 @@ ElementsAreArray(const T (&array)[N]) { }\ template \ template \ - bool name##MatcherP2::\ - gmock_Impl::Matches(arg_type arg) const + bool name##MatcherP2::gmock_Impl::MatchAndExplain(\ + arg_type arg,\ + ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\ + const #define MATCHER_P3(name, p0, p1, p2, description)\ template \ @@ -1170,7 +1215,8 @@ ElementsAreArray(const T (&array)[N]) { const ::testing::internal::Interpolations& gmock_interp)\ : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \ gmock_interp_(gmock_interp) {}\ - virtual bool Matches(arg_type arg) const;\ + virtual bool MatchAndExplain(\ + arg_type arg, ::testing::MatchResultListener* result_listener) const;\ virtual void DescribeTo(::std::ostream* gmock_os) const {\ const ::testing::internal::Strings& gmock_printed_params = \ ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\ @@ -1211,8 +1257,11 @@ ElementsAreArray(const T (&array)[N]) { }\ template \ template \ - bool name##MatcherP3::\ - gmock_Impl::Matches(arg_type arg) const + bool name##MatcherP3::gmock_Impl::MatchAndExplain(\ + arg_type arg,\ + ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\ + const #define MATCHER_P4(name, p0, p1, p2, p3, description)\ template \ template \ - bool name##MatcherP4::\ - gmock_Impl::Matches(arg_type arg) const + bool name##MatcherP4::gmock_Impl::MatchAndExplain(\ + arg_type arg,\ + ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\ + const #define MATCHER_P5(name, p0, p1, p2, p3, p4, description)\ template \ template \ - bool name##MatcherP5::\ - gmock_Impl::Matches(arg_type arg) const + bool name##MatcherP5::gmock_Impl::MatchAndExplain(\ + arg_type arg,\ + ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\ + const #define MATCHER_P6(name, p0, p1, p2, p3, p4, p5, description)\ template \ template \ bool name##MatcherP6::\ - gmock_Impl::Matches(arg_type arg) const + p5##_type>::gmock_Impl::MatchAndExplain(\ + arg_type arg,\ + ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\ + const #define MATCHER_P7(name, p0, p1, p2, p3, p4, p5, p6, description)\ template \ template \ bool name##MatcherP7::\ - gmock_Impl::Matches(arg_type arg) const + p5##_type, p6##_type>::gmock_Impl::MatchAndExplain(\ + arg_type arg,\ + ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\ + const #define MATCHER_P8(name, p0, p1, p2, p3, p4, p5, p6, p7, description)\ template \ template \ bool name##MatcherP8::\ - gmock_Impl::Matches(arg_type arg) const + p5##_type, p6##_type, \ + p7##_type>::gmock_Impl::MatchAndExplain(\ + arg_type arg,\ + ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\ + const #define MATCHER_P9(name, p0, p1, p2, p3, p4, p5, p6, p7, p8, description)\ template \ template \ bool name##MatcherP9::\ - gmock_Impl::Matches(arg_type arg) const + p5##_type, p6##_type, p7##_type, \ + p8##_type>::gmock_Impl::MatchAndExplain(\ + arg_type arg,\ + ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\ + const #define MATCHER_P10(name, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, description)\ template \ template \ bool name##MatcherP10::\ - gmock_Impl::Matches(arg_type arg) const + p4##_type, p5##_type, p6##_type, p7##_type, p8##_type, \ + p9##_type>::gmock_Impl::MatchAndExplain(\ + arg_type arg,\ + ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\ + const #endif // GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_MATCHERS_H_ diff --git a/include/gmock/gmock-generated-matchers.h.pump b/include/gmock/gmock-generated-matchers.h.pump index 8abbc0cb..fb2bc358 100644 --- a/include/gmock/gmock-generated-matchers.h.pump +++ b/include/gmock/gmock-generated-matchers.h.pump @@ -116,8 +116,9 @@ class ArgsMatcherImpl : public MatcherInterface { explicit ArgsMatcherImpl(const InnerMatcher& inner_matcher) : inner_matcher_(SafeMatcherCast(inner_matcher)) {} - virtual bool Matches(ArgsTuple args) const { - return inner_matcher_.Matches(GetSelectedArgs(args)); + virtual bool MatchAndExplain(ArgsTuple args, + MatchResultListener* listener) const { + return inner_matcher_.MatchAndExplain(GetSelectedArgs(args), listener); } virtual void DescribeTo(::std::ostream* os) const { @@ -130,11 +131,6 @@ class ArgsMatcherImpl : public MatcherInterface { inner_matcher_.DescribeNegationTo(os); } - virtual void ExplainMatchResultTo(ArgsTuple args, - ::std::ostream* os) const { - inner_matcher_.ExplainMatchResultTo(GetSelectedArgs(args), os); - } - private: static SelectedArgs GetSelectedArgs(ArgsTuple args) { return TupleFields::GetSelectedFields(args); @@ -301,14 +297,19 @@ $$ // show up in the generated code. // The MATCHER* family of macros can be used in a namespace scope to -// define custom matchers easily. The syntax: +// define custom matchers easily. +// +// Basic Usage +// =========== +// +// The syntax // // MATCHER(name, description_string) { statements; } // -// will define a matcher with the given name that executes the -// statements, which must return a bool to indicate if the match -// succeeds. Inside the statements, you can refer to the value being -// matched by 'arg', and refer to its type by 'arg_type'. +// defines a matcher with the given name that executes the statements, +// which must return a bool to indicate if the match succeeds. Inside +// the statements, you can refer to the value being matched by 'arg', +// and refer to its type by 'arg_type'. // // The description string documents what the matcher does, and is used // to generate the failure message when the match fails. Since a @@ -341,6 +342,9 @@ $$ // show up in the generated code. // where the description "is even" is automatically calculated from the // matcher name IsEven. // +// Argument Type +// ============= +// // Note that the type of the value being matched (arg_type) is // determined by the context in which you use the matcher and is // supplied to you by the compiler, so you don't need to worry about @@ -351,6 +355,9 @@ $$ // show up in the generated code. // takes an int, 'arg_type' will be int; if it takes an unsigned long, // 'arg_type' will be unsigned long; and so on. // +// Parameterizing Matchers +// ======================= +// // Sometimes you'll want to parameterize the matcher. For that you // can use another macro: // @@ -381,6 +388,9 @@ $$ // show up in the generated code. // We also provide MATCHER_P2, MATCHER_P3, ..., up to MATCHER_P$n to // support multi-parameter matchers. // +// Describing Parameterized Matchers +// ================================= +// // When defining a parameterized matcher, you can use Python-style // interpolations in the description string to refer to the parameter // values. We support the following syntax currently: @@ -413,6 +423,9 @@ $$ // show up in the generated code. // // Expected: in closed range (4, 6) // +// Types of Matcher Parameters +// =========================== +// // For the purpose of typing, you can view // // MATCHER_Pk(Foo, p1, ..., pk, description_string) { ... } @@ -440,23 +453,44 @@ $$ // show up in the generated code. // matcher you will see the value of the referenced object but not its // address. // +// Explaining Match Results +// ======================== +// +// Sometimes the matcher description alone isn't enough to explain why +// the match has failed or succeeded. For example, when expecting a +// long string, it can be very helpful to also print the diff between +// the expected string and the actual one. To achieve that, you can +// optionally stream additional information to a special variable +// named result_listener, whose type is a pointer to class +// MatchResultListener: +// +// MATCHER_P(EqualsLongString, str, "") { +// if (arg == str) return true; +// +// *result_listener << "the difference: " +/// << DiffStrings(str, arg); +// return false; +// } +// +// Overloading Matchers +// ==================== +// // You can overload matchers with different numbers of parameters: // // MATCHER_P(Blah, a, description_string1) { ... } // MATCHER_P2(Blah, a, b, description_string2) { ... } // -// While it's tempting to always use the MATCHER* macros when defining -// a new matcher, you should also consider implementing -// MatcherInterface or using MakePolymorphicMatcher() instead, -// especially if you need to use the matcher a lot. While these -// approaches require more work, they give you more control on the -// types of the value being matched and the matcher parameters, which -// in general leads to better compiler error messages that pay off in -// the long run. They also allow overloading matchers based on -// parameter types (as opposed to just based on the number of -// parameters). +// Caveats +// ======= // -// CAVEAT: +// When defining a new matcher, you should also consider implementing +// MatcherInterface or using MakePolymorphicMatcher(). These +// approaches require more work than the MATCHER* macros, but also +// give you more control on the types of the value being matched and +// the matcher parameters, which may leads to better compiler error +// messages when the matcher is used wrong. They also allow +// overloading matchers based on parameter types (as opposed to just +// based on the number of parameters). // // MATCHER*() can only be used in a namespace scope. The reason is // that C++ doesn't yet allow function-local types to be used to @@ -464,7 +498,8 @@ $$ // show up in the generated code. // Once that's done, we'll consider supporting using MATCHER*() inside // a function. // -// MORE INFORMATION: +// More Information +// ================ // // To learn more about using these macros, please search for 'MATCHER' // on http://code.google.com/p/googlemock/wiki/CookBook. @@ -510,7 +545,8 @@ $var param_field_decls2 = [[$for j public:\ [[$if i==1 [[explicit ]]]]gmock_Impl($impl_ctor_param_list)\ $impl_inits {}\ - virtual bool Matches(arg_type arg) const;\ + virtual bool MatchAndExplain(\ + arg_type arg, ::testing::MatchResultListener* result_listener) const;\ virtual void DescribeTo(::std::ostream* gmock_os) const {\ const ::testing::internal::Strings& gmock_printed_params = \ ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\ @@ -540,8 +576,10 @@ $var param_field_decls2 = [[$for j return $class_name$param_types($params);\ }\$template template \ - bool $class_name$param_types::\ - gmock_Impl::Matches(arg_type arg) const + bool $class_name$param_types::gmock_Impl::MatchAndExplain(\ + arg_type arg,\ + ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\ + const ]] diff --git a/include/gmock/gmock-matchers.h b/include/gmock/gmock-matchers.h index 5f5a29fd..b1689d6e 100644 --- a/include/gmock/gmock-matchers.h +++ b/include/gmock/gmock-matchers.h @@ -64,14 +64,74 @@ namespace testing { // ownership management as Matcher objects can now be copied like // plain values. +// MatchResultListener is an abstract class. Its << operator can be +// used by a matcher to explain why a value matches or doesn't match. +// +// TODO(wan@google.com): add method +// bool InterestedInWhy(bool result) const; +// to indicate whether the listener is interested in why the match +// result is 'result'. +class MatchResultListener { + public: + // Creates a listener object with the given underlying ostream. The + // listener does not own the ostream. + explicit MatchResultListener(::std::ostream* os) : stream_(os) {} + virtual ~MatchResultListener() = 0; // Makes this class abstract. + + // Streams x to the underlying ostream; does nothing if the ostream + // is NULL. + template + MatchResultListener& operator<<(const T& x) { + if (stream_ != NULL) + *stream_ << x; + return *this; + } + + // Returns the underlying ostream. + ::std::ostream* stream() { return stream_; } + + private: + ::std::ostream* const stream_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(MatchResultListener); +}; + +inline MatchResultListener::~MatchResultListener() { +} + // The implementation of a matcher. template class MatcherInterface { public: virtual ~MatcherInterface() {} + // Returns true iff the matcher matches x; also explains the match + // result to 'listener'. + // + // You should override this method when defining a new matcher. For + // backward compatibility, we provide a default implementation that + // just forwards to the old, deprecated matcher API (Matches() and + // ExplainMatchResultTo()). + // + // It's the responsibility of the caller (Google Mock) to guarantee + // that 'listener' is not NULL. This helps to simplify a matcher's + // implementation when it doesn't care about the performance, as it + // can talk to 'listener' without checking its validity first. + // However, in order to implement dummy listeners efficiently, + // listener->stream() may be NULL. + virtual bool MatchAndExplain(T x, MatchResultListener* listener) const { + const bool match = Matches(x); + if (listener->stream() != NULL) { + ExplainMatchResultTo(x, listener->stream()); + } + return match; + } + + // DEPRECATED. This method will be removed. Override + // MatchAndExplain() instead. + // // Returns true iff the matcher matches x. - virtual bool Matches(T x) const = 0; + virtual bool Matches(T /* x */) const { return false; } // Describes this matcher to an ostream. virtual void DescribeTo(::std::ostream* os) const = 0; @@ -88,6 +148,9 @@ class MatcherInterface { *os << ")"; } + // DEPRECATED. This method will be removed. Override + // MatchAndExplain() instead. + // // Explains why x matches, or doesn't match, the matcher. Override // this to provide any additional information that helps a user // understand the match result. @@ -100,14 +163,58 @@ class MatcherInterface { namespace internal { +// A match result listener that ignores the explanation. +class DummyMatchResultListener : public MatchResultListener { + public: + DummyMatchResultListener() : MatchResultListener(NULL) {} + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(DummyMatchResultListener); +}; + +// A match result listener that forwards the explanation to a given +// ostream. The difference between this and MatchResultListener is +// that the former is concrete. +class StreamMatchResultListener : public MatchResultListener { + public: + explicit StreamMatchResultListener(::std::ostream* os) + : MatchResultListener(os) {} + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(StreamMatchResultListener); +}; + +// A match result listener that stores the explanation in a string. +class StringMatchResultListener : public MatchResultListener { + public: + StringMatchResultListener() : MatchResultListener(&ss_) {} + + // Returns the explanation heard so far. + internal::string str() const { return ss_.str(); } + + private: + ::std::stringstream ss_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(StringMatchResultListener); +}; + // An internal class for implementing Matcher, which will derive // from it. We put functionalities common to all Matcher // specializations here to avoid code duplication. template class MatcherBase { public: + // Returns true iff the matcher matches x; also explains the match + // result to 'listener'. + bool MatchAndExplain(T x, MatchResultListener* listener) const { + return impl_->MatchAndExplain(x, listener); + } + // Returns true iff this matcher matches x. - bool Matches(T x) const { return impl_->Matches(x); } + bool Matches(T x) const { + DummyMatchResultListener dummy; + return MatchAndExplain(x, &dummy); + } // Describes this matcher to an ostream. void DescribeTo(::std::ostream* os) const { impl_->DescribeTo(os); } @@ -119,7 +226,8 @@ class MatcherBase { // Explains why x matches, or doesn't match, the matcher. void ExplainMatchResultTo(T x, ::std::ostream* os) const { - impl_->ExplainMatchResultTo(x, os); + StreamMatchResultListener listener(os); + MatchAndExplain(x, &listener); } protected: @@ -156,6 +264,27 @@ inline void ExplainMatchResultTo(const PolymorphicMatcherImpl& /* impl */, // prints the value of x elsewhere. } +// The default implementation of MatchAndExplain() for polymorphic +// matchers. +template +inline bool MatchAndExplain(const PolymorphicMatcherImpl& impl, + const T& x, + MatchResultListener* listener) { + const bool match = impl.Matches(x); + + ::std::ostream* const os = listener->stream(); + if (os != NULL) { + using ::testing::internal::ExplainMatchResultTo; + // When resolving the following call, both + // ::testing::internal::ExplainMatchResultTo() and + // foo::ExplainMatchResultTo() are considered, where foo is the + // namespace where class PolymorphicMatcherImpl is defined. + ExplainMatchResultTo(impl, x, os); + } + + return match; +} + } // namespace internal // A Matcher is a copyable and IMMUTABLE (except by assignment) @@ -220,19 +349,31 @@ class Matcher // polymorphic matcher (i.e. a matcher that can match values of more // than one type, e.g. Eq(n) and NotNull()). // -// To define a polymorphic matcher, a user first provides a Impl class -// that has a Matches() method, a DescribeTo() method, and a -// DescribeNegationTo() method. The Matches() method is usually a -// method template (such that it works with multiple types). Then the -// user creates the polymorphic matcher using -// MakePolymorphicMatcher(). To provide additional explanation to the -// match result, define a FREE function (or function template) +// To define a polymorphic matcher in the old, deprecated way, a user +// first provides an Impl class that has a Matches() method, a +// DescribeTo() method, and a DescribeNegationTo() method. The +// Matches() method is usually a method template (such that it works +// with multiple types). Then the user creates the polymorphic +// matcher using MakePolymorphicMatcher(). To provide additional +// explanation to the match result, define a FREE function (or +// function template) // // void ExplainMatchResultTo(const Impl& matcher, const Value& value, // ::std::ostream* os); // -// in the SAME NAME SPACE where Impl is defined. See the definition -// of NotNull() for a complete example. +// in the SAME NAME SPACE where Impl is defined. +// +// The new, recommended way to define a polymorphic matcher is to +// provide an Impl class that has a DescribeTo() method and a +// DescribeNegationTo() method, and define a FREE function (or +// function template) +// +// bool MatchAndExplain(const Impl& matcher, const Value& value, +// MatchResultListener* listener); +// +// in the SAME NAME SPACE where Impl is defined. +// +// See the definition of NotNull() for a complete example. template class PolymorphicMatcher { public: @@ -257,8 +398,6 @@ class PolymorphicMatcher { public: explicit MonomorphicImpl(const Impl& impl) : impl_(impl) {} - virtual bool Matches(T x) const { return impl_.Matches(x); } - virtual void DescribeTo(::std::ostream* os) const { impl_.DescribeTo(os); } @@ -267,22 +406,15 @@ class PolymorphicMatcher { impl_.DescribeNegationTo(os); } - virtual void ExplainMatchResultTo(T x, ::std::ostream* os) const { - using ::testing::internal::ExplainMatchResultTo; - + virtual bool MatchAndExplain(T x, MatchResultListener* listener) const { // C++ uses Argument-Dependent Look-up (aka Koenig Look-up) to - // resolve the call to ExplainMatchResultTo() here. This - // means that if there's a ExplainMatchResultTo() function - // defined in the name space where class Impl is defined, it - // will be picked by the compiler as the better match. - // Otherwise the default implementation of it in - // ::testing::internal will be picked. - // - // This look-up rule lets a writer of a polymorphic matcher - // customize the behavior of ExplainMatchResultTo() when he - // cares to. Nothing needs to be done by the writer if he - // doesn't need to customize it. - ExplainMatchResultTo(impl_, x, os); + // resolve the call to MatchAndExplain() here. This means that + // if there's a MatchAndExplain() function defined in the name + // space where class Impl is defined, it will be picked by the + // compiler as the better match. Otherwise the default + // implementation of it in ::testing::internal will be picked. + using ::testing::internal::MatchAndExplain; + return MatchAndExplain(impl_, x, listener); } private: @@ -390,16 +522,12 @@ Matcher 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 -void ExplainMatchResultAsNeededTo(const Matcher& matcher, T value, - ::std::ostream* os) { - ::std::stringstream reason; - matcher.ExplainMatchResultTo(value, &reason); - const internal::string s = reason.str(); - if (s != "") { - *os << " (" << s << ")"; +// If the given string is not empty and os is not NULL, wraps the +// string inside a pair of parentheses and streams the result to os. +inline void StreamInParensAsNeeded(const internal::string& str, + ::std::ostream* os) { + if (!str.empty() && os != NULL) { + *os << " (" << str << ")"; } } @@ -439,7 +567,8 @@ class TuplePrefix { get(matchers); typedef typename tuple_element::type Value; Value value = get(values); - if (!matcher.Matches(value)) { + StringMatchResultListener listener; + if (!matcher.MatchAndExplain(value, &listener)) { // TODO(wan): include in the message the name of the parameter // as used in MOCK_METHOD*() when possible. *os << " Expected arg #" << N - 1 << ": "; @@ -452,7 +581,8 @@ class TuplePrefix { // the address is interesting. internal::UniversalPrinter:: Print(value, os); - ExplainMatchResultAsNeededTo(matcher, value, os); + + StreamInParensAsNeeded(listener.str(), os); *os << "\n"; } } @@ -537,8 +667,8 @@ class MatcherCastImpl > { : 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(x)); + virtual bool MatchAndExplain(T x, MatchResultListener* listener) const { + return source_matcher_.MatchAndExplain(static_cast(x), listener); } virtual void DescribeTo(::std::ostream* os) const { @@ -549,10 +679,6 @@ class MatcherCastImpl > { source_matcher_.DescribeNegationTo(os); } - virtual void ExplainMatchResultTo(T x, ::std::ostream* os) const { - source_matcher_.ExplainMatchResultTo(static_cast(x), os); - } - private: const Matcher source_matcher_; @@ -572,7 +698,8 @@ class MatcherCastImpl > { template class AnyMatcherImpl : public MatcherInterface { public: - virtual bool Matches(T /* x */) const { return true; } + virtual bool MatchAndExplain( + T /* x */, MatchResultListener* /* listener */) const { return true; } virtual void DescribeTo(::std::ostream* os) const { *os << "is anything"; } virtual void DescribeNegationTo(::std::ostream* os) const { // This is mostly for completeness' safe, as it's not very useful @@ -618,7 +745,10 @@ class AnythingMatcher { class Impl : public MatcherInterface { \ 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::Print(rhs_, os); \ @@ -719,7 +849,11 @@ class RefMatcher { // Matches() takes a Super& (as opposed to const Super&) in // order to match the interface MatcherInterface. - virtual bool Matches(Super& x) const { return &x == &object_; } // NOLINT + virtual bool MatchAndExplain( + Super& x, MatchResultListener* listener) const { + *listener << "is located @" << static_cast(&x); + return &x == &object_; + } virtual void DescribeTo(::std::ostream* os) const { *os << "references the variable "; @@ -731,11 +865,6 @@ class RefMatcher { UniversalPrinter::Print(object_, os); } - virtual void ExplainMatchResultTo(Super& x, // NOLINT - ::std::ostream* os) const { - *os << "is located @" << static_cast(&x); - } - private: const Super& object_; @@ -1017,7 +1146,9 @@ class MatchesRegexMatcher { template \ class Impl : public MatcherInterface&> { \ public: \ - virtual bool Matches(const ::std::tr1::tuple& args) const { \ + virtual bool MatchAndExplain( \ + const ::std::tr1::tuple& args, \ + MatchResultListener* /* listener */) const { \ return ::std::tr1::get<0>(args) op ::std::tr1::get<1>(args); \ } \ virtual void DescribeTo(::std::ostream* os) const { \ @@ -1049,8 +1180,8 @@ class NotMatcherImpl : public MatcherInterface { explicit NotMatcherImpl(const Matcher& matcher) : matcher_(matcher) {} - virtual bool Matches(T x) const { - return !matcher_.Matches(x); + virtual bool MatchAndExplain(T x, MatchResultListener* listener) const { + return !matcher_.MatchAndExplain(x, listener); } virtual void DescribeTo(::std::ostream* os) const { @@ -1061,10 +1192,6 @@ class NotMatcherImpl : public MatcherInterface { matcher_.DescribeTo(os); } - virtual void ExplainMatchResultTo(T x, ::std::ostream* os) const { - matcher_.ExplainMatchResultTo(x, os); - } - private: const Matcher matcher_; @@ -1101,10 +1228,6 @@ class BothOfMatcherImpl : public MatcherInterface { BothOfMatcherImpl(const Matcher& matcher1, const Matcher& matcher2) : matcher1_(matcher1), matcher2_(matcher2) {} - virtual bool Matches(T x) const { - return matcher1_.Matches(x) && matcher2_.Matches(x); - } - virtual void DescribeTo(::std::ostream* os) const { *os << "("; matcher1_.DescribeTo(os); @@ -1118,35 +1241,34 @@ class BothOfMatcherImpl : public MatcherInterface { 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 +1312,6 @@ class EitherOfMatcherImpl : public MatcherInterface { EitherOfMatcherImpl(const Matcher& matcher1, const Matcher& matcher2) : matcher1_(matcher1), matcher2_(matcher2) {} - virtual bool Matches(T x) const { - return matcher1_.Matches(x) || matcher2_.Matches(x); - } - virtual void DescribeTo(::std::ostream* os) const { *os << "("; matcher1_.DescribeTo(os); @@ -1207,34 +1325,34 @@ class EitherOfMatcherImpl : public MatcherInterface { 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); - } + 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; + } + + StringMatchResultListener listener2; + if (matcher2_.MatchAndExplain(x, &listener2)) { + *listener << listener2.str(); + return true; + } + + // 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 { - // Otherwise we need to explain why *neither* matches. - ::std::stringstream ss1; - matcher1_.ExplainMatchResultTo(x, &ss1); - const internal::string s1 = ss1.str(); - - ::std::stringstream ss2; - matcher2_.ExplainMatchResultTo(x, &ss2); - const internal::string s2 = ss2.str(); - - if (s1 == "") { - *os << s2; - } else { - *os << s1; - if (s2 != "") { - *os << "; " << s2; - } + *listener << s1; + if (s2 != "") { + *listener << "; " << s2; } } + return false; } private: @@ -1367,7 +1485,8 @@ class PredicateFormatterFromMatcher { // Matcher(matcher_), as the latter won't compile when // matcher_ has type Matcher (e.g. An()). const Matcher matcher = MatcherCast(matcher_); - if (matcher.Matches(x)) { + StringMatchResultListener listener; + if (matcher.MatchAndExplain(x, &listener)) { return AssertionSuccess(); } else { ::std::stringstream ss; @@ -1376,7 +1495,7 @@ class PredicateFormatterFromMatcher { matcher.DescribeTo(&ss); ss << "\n Actual: "; UniversalPrinter::Print(x, &ss); - ExplainMatchResultAsNeededTo(matcher, x, &ss); + StreamInParensAsNeeded(listener.str(), &ss); return AssertionFailure(Message() << ss.str()); } } @@ -1417,7 +1536,8 @@ class FloatingEqMatcher { Impl(FloatType rhs, bool nan_eq_nan) : rhs_(rhs), nan_eq_nan_(nan_eq_nan) {} - virtual bool Matches(T value) const { + virtual bool MatchAndExplain(T value, + MatchResultListener* /* listener */) const { const FloatingPoint lhs(value), rhs(rhs_); // Compares NaNs first, if nan_eq_nan_ is true. @@ -1525,10 +1645,6 @@ class PointeeMatcher { explicit Impl(const InnerMatcher& matcher) : matcher_(MatcherCast(matcher)) {} - virtual bool Matches(Pointer p) const { - return GetRawPointer(p) != NULL && matcher_.Matches(*p); - } - virtual void DescribeTo(::std::ostream* os) const { *os << "points to a value that "; matcher_.DescribeTo(os); @@ -1539,17 +1655,18 @@ class PointeeMatcher { matcher_.DescribeTo(os); } - virtual void ExplainMatchResultTo(Pointer pointer, - ::std::ostream* os) const { + virtual bool MatchAndExplain(Pointer pointer, + MatchResultListener* listener) const { if (GetRawPointer(pointer) == NULL) - return; + return false; - ::std::stringstream ss; - matcher_.ExplainMatchResultTo(*pointer, &ss); - const internal::string s = ss.str(); + StringMatchResultListener inner_listener; + const bool match = matcher_.MatchAndExplain(*pointer, &inner_listener); + const internal::string s = inner_listener.str(); if (s != "") { - *os << "points to a value that " << s; + *listener << "points to a value that " << s; } + return match; } private: @@ -1572,16 +1689,6 @@ class FieldMatcher { const Matcher& matcher) : field_(field), matcher_(matcher) {} - // Returns true iff the inner matcher matches obj.field. - bool Matches(const Class& obj) const { - return matcher_.Matches(obj.*field_); - } - - // Returns true iff the inner matcher matches obj->field. - bool Matches(const Class* p) const { - return (p != NULL) && matcher_.Matches(p->*field_); - } - void DescribeTo(::std::ostream* os) const { *os << "the given field "; matcher_.DescribeTo(os); @@ -1592,27 +1699,29 @@ class FieldMatcher { matcher_.DescribeNegationTo(os); } - // The first argument of ExplainMatchResultTo() is needed to help + // The first argument of MatchAndExplain() is needed to help // Symbian's C++ compiler choose which overload to use. Its type is // true_type iff the Field() matcher is used to match a pointer. - void ExplainMatchResultTo(false_type /* is_not_pointer */, const Class& obj, - ::std::ostream* os) const { - ::std::stringstream ss; - matcher_.ExplainMatchResultTo(obj.*field_, &ss); - const internal::string s = ss.str(); + bool MatchAndExplain(false_type /* is_not_pointer */, const Class& obj, + MatchResultListener* listener) const { + StringMatchResultListener inner_listener; + const bool match = matcher_.MatchAndExplain(obj.*field_, &inner_listener); + const internal::string s = inner_listener.str(); if (s != "") { - *os << "the given field " << s; + *listener << "the given field " << s; } + return match; } - void ExplainMatchResultTo(true_type /* is_pointer */, const Class* p, - ::std::ostream* os) const { - if (p != NULL) { - // Since *p has a field, it must be a class/struct/union type - // and thus cannot be a pointer. Therefore we pass false_type() - // as the first argument. - ExplainMatchResultTo(false_type(), *p, os); - } + bool MatchAndExplain(true_type /* is_pointer */, const Class* p, + MatchResultListener* listener) const { + if (p == NULL) + return false; + + // Since *p has a field, it must be a class/struct/union type and + // thus cannot be a pointer. Therefore we pass false_type() as + // the first argument. + return MatchAndExplain(false_type(), *p, listener); } private: @@ -1622,12 +1731,11 @@ class FieldMatcher { GTEST_DISALLOW_ASSIGN_(FieldMatcher); }; -// Explains the result of matching an object or pointer against a field matcher. template -void ExplainMatchResultTo(const FieldMatcher& matcher, - const T& value, ::std::ostream* os) { - matcher.ExplainMatchResultTo( - typename ::testing::internal::is_pointer::type(), value, os); +bool MatchAndExplain(const FieldMatcher& matcher, + const T& value, MatchResultListener* listener) { + return matcher.MatchAndExplain( + typename ::testing::internal::is_pointer::type(), value, listener); } // Implements the Property() matcher for matching a property @@ -1645,16 +1753,6 @@ class PropertyMatcher { const Matcher& matcher) : property_(property), matcher_(matcher) {} - // Returns true iff obj.property() matches the inner matcher. - bool Matches(const Class& obj) const { - return matcher_.Matches((obj.*property_)()); - } - - // Returns true iff p->property() matches the inner matcher. - bool Matches(const Class* p) const { - return (p != NULL) && matcher_.Matches((p->*property_)()); - } - void DescribeTo(::std::ostream* os) const { *os << "the given property "; matcher_.DescribeTo(os); @@ -1665,27 +1763,30 @@ class PropertyMatcher { matcher_.DescribeNegationTo(os); } - // The first argument of ExplainMatchResultTo() is needed to help + // The first argument of MatchAndExplain() is needed to help // Symbian's C++ compiler choose which overload to use. Its type is // true_type iff the Property() matcher is used to match a pointer. - void ExplainMatchResultTo(false_type /* is_not_pointer */, const Class& obj, - ::std::ostream* os) const { - ::std::stringstream ss; - matcher_.ExplainMatchResultTo((obj.*property_)(), &ss); - const internal::string s = ss.str(); + bool MatchAndExplain(false_type /* is_not_pointer */, const Class& obj, + MatchResultListener* listener) const { + StringMatchResultListener inner_listener; + const bool match = matcher_.MatchAndExplain((obj.*property_)(), + &inner_listener); + const internal::string s = inner_listener.str(); if (s != "") { - *os << "the given property " << s; + *listener << "the given property " << s; } + return match; } - void ExplainMatchResultTo(true_type /* is_pointer */, const Class* p, - ::std::ostream* os) const { - if (p != NULL) { - // Since *p has a property method, it must be a - // class/struct/union type and thus cannot be a pointer. - // Therefore we pass false_type() as the first argument. - ExplainMatchResultTo(false_type(), *p, os); - } + bool MatchAndExplain(true_type /* is_pointer */, const Class* p, + MatchResultListener* listener) const { + if (p == NULL) + return false; + + // Since *p has a property method, it must be a class/struct/union + // type and thus cannot be a pointer. Therefore we pass + // false_type() as the first argument. + return MatchAndExplain(false_type(), *p, listener); } private: @@ -1695,13 +1796,11 @@ class PropertyMatcher { GTEST_DISALLOW_ASSIGN_(PropertyMatcher); }; -// Explains the result of matching an object or pointer against a -// property matcher. -template -void ExplainMatchResultTo(const PropertyMatcher& matcher, - const T& value, ::std::ostream* os) { - matcher.ExplainMatchResultTo( - typename ::testing::internal::is_pointer::type(), value, os); +template +bool MatchAndExplain(const PropertyMatcher& matcher, + const T& value, MatchResultListener* listener) { + return matcher.MatchAndExplain( + typename ::testing::internal::is_pointer::type(), value, listener); } // Type traits specifying various features of different functors for ResultOf. @@ -1759,13 +1858,6 @@ class ResultOfMatcher { public: Impl(CallableStorageType callable, const Matcher& 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::Invoke(). - virtual bool Matches(T obj) const { - return matcher_.Matches( - CallableTraits::template Invoke(callable_, obj)); - } virtual void DescribeTo(::std::ostream* os) const { *os << "result of the given callable "; @@ -1777,14 +1869,17 @@ class ResultOfMatcher { matcher_.DescribeNegationTo(os); } - virtual void ExplainMatchResultTo(T obj, ::std::ostream* os) const { - ::std::stringstream ss; - matcher_.ExplainMatchResultTo( + virtual bool MatchAndExplain(T obj, MatchResultListener* listener) const { + StringMatchResultListener inner_listener; + const bool match = matcher_.MatchAndExplain( CallableTraits::template Invoke(callable_, obj), - &ss); - const internal::string s = ss.str(); + &inner_listener); + + const internal::string s = inner_listener.str(); if (s != "") - *os << "result of the given callable " << s; + *listener << "result of the given callable " << s; + + return match; } private: @@ -1929,17 +2024,6 @@ class ContainsMatcherImpl : public MatcherInterface { : inner_matcher_( testing::SafeMatcherCast(inner_matcher)) {} - // Returns true iff 'container' matches. - virtual bool Matches(Container container) const { - StlContainerReference stl_container = View::ConstReference(container); - for (typename StlContainer::const_iterator it = stl_container.begin(); - it != stl_container.end(); ++it) { - if (inner_matcher_.Matches(*it)) - return true; - } - return false; - } - // Describes what this matcher does. virtual void DescribeTo(::std::ostream* os) const { *os << "contains at least one element that "; @@ -1952,19 +2036,18 @@ class ContainsMatcherImpl : public MatcherInterface { inner_matcher_.DescribeTo(os); } - // Explains why 'container' matches, or doesn't match, this matcher. - virtual void ExplainMatchResultTo(Container container, - ::std::ostream* os) const { + virtual bool MatchAndExplain(Container container, + MatchResultListener* listener) const { StlContainerReference stl_container = View::ConstReference(container); - - // We need to explain which (if any) element matches inner_matcher_. - typename StlContainer::const_iterator it = stl_container.begin(); - for (size_t i = 0; it != stl_container.end(); ++it, ++i) { + size_t i = 0; + for (typename StlContainer::const_iterator it = stl_container.begin(); + it != stl_container.end(); ++it, ++i) { if (inner_matcher_.Matches(*it)) { - *os << "element " << i << " matches"; - return; + *listener << "element " << i << " matches"; + return true; } } + return false; } private: @@ -2007,8 +2090,9 @@ class KeyMatcherImpl : public MatcherInterface { } // Returns true iff 'key_value.first' (the key) matches the inner matcher. - virtual bool Matches(PairType key_value) const { - return inner_matcher_.Matches(key_value.first); + virtual bool MatchAndExplain(PairType key_value, + MatchResultListener* listener) const { + return inner_matcher_.MatchAndExplain(key_value.first, listener); } // Describes what this matcher does. @@ -2023,12 +2107,6 @@ class KeyMatcherImpl : public MatcherInterface { 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 inner_matcher_; @@ -2069,13 +2147,6 @@ class PairMatcherImpl : public MatcherInterface { testing::SafeMatcherCast(second_matcher)) { } - // Returns true iff 'a_pair.first' matches first_matcher and 'a_pair.second' - // matches second_matcher. - virtual bool Matches(PairType a_pair) const { - return first_matcher_.Matches(a_pair.first) && - second_matcher_.Matches(a_pair.second); - } - // Describes what this matcher does. virtual void DescribeTo(::std::ostream* os) const { *os << "has a first field that "; @@ -2092,28 +2163,40 @@ class PairMatcherImpl : public MatcherInterface { second_matcher_.DescribeNegationTo(os); } - // Explains why 'a_pair' matches, or doesn't match, this matcher. - virtual void ExplainMatchResultTo(PairType a_pair, - ::std::ostream* os) const { - ::std::stringstream ss1; - first_matcher_.ExplainMatchResultTo(a_pair.first, &ss1); - internal::string s1 = ss1.str(); + // Returns true iff 'a_pair.first' matches first_matcher and 'a_pair.second' + // matches second_matcher. + virtual bool MatchAndExplain(PairType a_pair, + MatchResultListener* listener) const { + StringMatchResultListener listener1; + const bool match1 = first_matcher_.MatchAndExplain(a_pair.first, + &listener1); + internal::string s1 = listener1.str(); if (s1 != "") { - s1 = "the first field " + s1; + s1 = "the first field " + s1; + } + if (!match1) { + *listener << s1; + return false; } - ::std::stringstream ss2; - second_matcher_.ExplainMatchResultTo(a_pair.second, &ss2); - internal::string s2 = ss2.str(); + StringMatchResultListener listener2; + const bool match2 = second_matcher_.MatchAndExplain(a_pair.second, + &listener2); + internal::string s2 = listener2.str(); if (s2 != "") { - s2 = "the second field " + s2; + s2 = "the second field " + s2; + } + if (!match2) { + *listener << s2; + return false; } - *os << s1; + *listener << s1; if (s1 != "" && s2 != "") { - *os << ", and "; + *listener << ", and "; } - *os << s2; + *listener << s2; + return true; } private: @@ -2165,21 +2248,6 @@ class ElementsAreMatcherImpl : public MatcherInterface { } } - // Returns true iff 'container' matches. - virtual bool Matches(Container container) const { - StlContainerReference stl_container = View::ConstReference(container); - if (stl_container.size() != count()) - return false; - - typename StlContainer::const_iterator it = stl_container.begin(); - for (size_t i = 0; i != count(); ++it, ++i) { - if (!matchers_[i].Matches(*it)) - return false; - } - - return true; - } - // Describes what this matcher does. virtual void DescribeTo(::std::ostream* os) const { if (count() == 0) { @@ -2216,63 +2284,54 @@ class ElementsAreMatcherImpl : public MatcherInterface { } } - // 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 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"; - - ::std::stringstream ss; - matchers_[i].ExplainMatchResultTo(*it, &ss); - const string s = ss.str(); - if (!s.empty()) { - *os << " (" << s << ")"; - } - return; + StreamInParensAsNeeded(s.str(), listener->stream()); + return false; } } + + // Every element matches its expectation. We need to explain why + // (the obvious ones can be skipped). + + 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"; + } + *listener << "element " << i << " " << s; + reason_printed = true; + } + } + + return true; } private: @@ -2811,13 +2870,14 @@ Truly(Predicate pred) { // values that are included in one container but not the other. (Duplicate // values and order differences are not explained.) template -inline PolymorphicMatcher > 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(rhs)); + return MakePolymorphicMatcher( + internal::ContainerEqMatcher(rhs)); } // Matches an STL-style container or a native array that contains at diff --git a/include/gmock/gmock-spec-builders.h b/include/gmock/gmock-spec-builders.h index 9aa0a9ee..d8d4749a 100644 --- a/include/gmock/gmock-spec-builders.h +++ b/include/gmock/gmock-spec-builders.h @@ -1004,13 +1004,13 @@ class TypedExpectation : public ExpectationBase { if (!TupleMatches(matchers_, args)) { DescribeMatchFailureTupleTo(matchers_, args, os); } - if (!extra_matcher_.Matches(args)) { + StringMatchResultListener listener; + if (!extra_matcher_.MatchAndExplain(args, &listener)) { *os << " Expected args: "; extra_matcher_.DescribeTo(os); *os << "\n Actual: don't match"; - internal::ExplainMatchResultAsNeededTo( - extra_matcher_, args, os); + internal::StreamInParensAsNeeded(listener.str(), os); *os << "\n"; } } else if (!AllPrerequisitesAreSatisfied()) { diff --git a/test/gmock-generated-matchers_test.cc b/test/gmock-generated-matchers_test.cc index 41413055..40c2367c 100644 --- a/test/gmock-generated-matchers_test.cc +++ b/test/gmock-generated-matchers_test.cc @@ -136,6 +136,16 @@ TEST(ArgsTest, AcceptsDecreasingTemplateArgs) { EXPECT_THAT(t, Not(Args<2, 1>(Lt()))); } +// The MATCHER*() macros trigger warning C4100 (unreferenced formal +// parameter) in MSVC with -W4. Unfortunately they cannot be fixed in +// the macro definition, as the warnings are generated when the macro +// is expanded and macro expansion cannot contain #pragma. Therefore +// we suppress them here. +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable:4100) +#endif + MATCHER(SumIsZero, "") { return get<0>(arg) + get<1>(arg) + get<2>(arg) == 0; } @@ -553,6 +563,44 @@ TEST(MatcherMacroTest, Works) { EXPECT_EQ("", Explain(m, 7)); } +// Tests explaining match result in a MATCHER* macro. + +MATCHER(IsEven2, "is even") { + if ((arg % 2) == 0) { + // Verifies that we can stream to result_listener, a listener + // supplied by the MATCHER macro implicitly. + *result_listener << "OK"; + return true; + } else { + *result_listener << "% 2 == " << (arg % 2); + return false; + } +} + +MATCHER_P2(EqSumOf, x, y, "") { + if (arg == (x + y)) { + *result_listener << "OK"; + return true; + } else { + // Verifies that we can stream to the underlying stream of + // result_listener. + if (result_listener->stream() != NULL) { + *result_listener->stream() << "diff == " << (x + y - arg); + } + return false; + } +} + +TEST(MatcherMacroTest, CanExplainMatchResult) { + const Matcher m1 = IsEven2(); + EXPECT_EQ("OK", Explain(m1, 4)); + EXPECT_EQ("% 2 == 1", Explain(m1, 5)); + + const Matcher m2 = EqSumOf(1, 2); + EXPECT_EQ("OK", Explain(m2, 3)); + EXPECT_EQ("diff == -1", Explain(m2, 4)); +} + // Tests that the description string supplied to MATCHER() must be // valid. @@ -1052,4 +1100,8 @@ TEST(ContainsTest, WorksForTwoDimensionalNativeArray) { EXPECT_THAT(a, Contains(Not(Contains(5)))); } +#ifdef _MSC_VER +#pragma warning(pop) +#endif + } // namespace diff --git a/test/gmock-matchers_test.cc b/test/gmock-matchers_test.cc index 907749d1..e69844fa 100644 --- a/test/gmock-matchers_test.cc +++ b/test/gmock-matchers_test.cc @@ -88,6 +88,7 @@ using testing::Matcher; using testing::MatcherCast; using testing::MatcherInterface; using testing::Matches; +using testing::MatchResultListener; using testing::NanSensitiveDoubleEq; using testing::NanSensitiveFloatEq; using testing::Ne; @@ -200,10 +201,39 @@ class EvenMatcherImpl : public MatcherInterface { // two methods is optional. }; -TEST(MatcherInterfaceTest, CanBeImplemented) { +TEST(MatcherInterfaceTest, CanBeImplementedUsingDeprecatedAPI) { EvenMatcherImpl m; } +// Tests implementing a monomorphic matcher using MatchAndExplain(). + +class NewEvenMatcherImpl : public MatcherInterface { + public: + virtual bool MatchAndExplain(int x, MatchResultListener* listener) const { + const bool match = x % 2 == 0; + // Verifies that we can stream to a listener directly. + *listener << "value % " << 2; + if (listener->stream() != NULL) { + // Verifies that we can stream to a listener's underlying stream + // too. + *listener->stream() << " == " << (x % 2); + } + return match; + } + + virtual void DescribeTo(::std::ostream* os) const { + *os << "is an even number"; + } +}; + +TEST(MatcherInterfaceTest, CanBeImplementedUsingNewAPI) { + Matcher m = MakeMatcher(new NewEvenMatcherImpl); + EXPECT_TRUE(m.Matches(2)); + EXPECT_FALSE(m.Matches(3)); + EXPECT_EQ("value % 2 == 0", Explain(m, 2)); + EXPECT_EQ("value % 2 == 1", Explain(m, 3)); +} + // Tests default-constructing a matcher. TEST(MatcherTest, CanBeDefaultConstructed) { Matcher m; @@ -252,6 +282,18 @@ TEST(MatcherTest, CanDescribeItself) { Describe(Matcher(new EvenMatcherImpl))); } +// Tests Matcher::MatchAndExplain(). +TEST(MatcherTest, MatchAndExplain) { + Matcher m = GreaterThan(0); + ::testing::internal::StringMatchResultListener listener1; + EXPECT_TRUE(m.MatchAndExplain(42, &listener1)); + EXPECT_EQ("is 42 more than 0", listener1.str()); + + ::testing::internal::StringMatchResultListener listener2; + EXPECT_FALSE(m.MatchAndExplain(-9, &listener2)); + EXPECT_EQ("is 9 less than 0", listener2.str()); +} + // Tests that a C-string literal can be implicitly converted to a // Matcher or Matcher. TEST(StringMatcherTest, CanBeImplicitlyConstructedFromCStringLiteral) { @@ -284,8 +326,8 @@ TEST(MakeMatcherTest, ConstructsMatcherFromMatcherInterface) { Matcher m = MakeMatcher(dummy_impl); } -// Tests that MakePolymorphicMatcher() constructs a polymorphic -// matcher from its implementation. +// Tests that MakePolymorphicMatcher() can construct a polymorphic +// matcher from its implementation using the old API. const int bar = 1; class ReferencesBarOrIsZeroImpl { public: @@ -308,7 +350,7 @@ PolymorphicMatcher ReferencesBarOrIsZero() { return MakePolymorphicMatcher(ReferencesBarOrIsZeroImpl()); } -TEST(MakePolymorphicMatcherTest, ConstructsMatcherFromImpl) { +TEST(MakePolymorphicMatcherTest, ConstructsMatcherUsingOldAPI) { // Using a polymorphic matcher to match a reference type. Matcher m1 = ReferencesBarOrIsZero(); EXPECT_TRUE(m1.Matches(0)); @@ -324,6 +366,58 @@ TEST(MakePolymorphicMatcherTest, ConstructsMatcherFromImpl) { EXPECT_EQ("bar or zero", Describe(m2)); } +// Tests implementing a polymorphic matcher using MatchAndExplain(). + +class PolymorphicIsEvenImpl { + public: + void DescribeTo(::std::ostream* os) const { *os << "is even"; } + + void DescribeNegationTo(::std::ostream* os) const { + *os << "is odd"; + } +}; + +template +bool MatchAndExplain(const PolymorphicIsEvenImpl& /* impl */, + T x, MatchResultListener* listener) { + // Verifies that we can stream to the listener directly. + *listener << "% " << 2; + if (listener->stream() != NULL) { + // Verifies that we can stream to the listener's underlying stream + // too. + *listener->stream() << " == " << (x % 2); + } + return (x % 2) == 0; +} + +PolymorphicMatcher PolymorphicIsEven() { + return MakePolymorphicMatcher(PolymorphicIsEvenImpl()); +} + +TEST(MakePolymorphicMatcherTest, ConstructsMatcherUsingNewAPI) { + // Using PolymorphicIsEven() as a Matcher. + const Matcher m1 = PolymorphicIsEven(); + EXPECT_TRUE(m1.Matches(42)); + EXPECT_FALSE(m1.Matches(43)); + EXPECT_EQ("is even", Describe(m1)); + + const Matcher not_m1 = Not(m1); + EXPECT_EQ("is odd", Describe(not_m1)); + + EXPECT_EQ("% 2 == 0", Explain(m1, 42)); + + // Using PolymorphicIsEven() as a Matcher. + const Matcher m2 = PolymorphicIsEven(); + EXPECT_TRUE(m2.Matches('\x42')); + EXPECT_FALSE(m2.Matches('\x43')); + EXPECT_EQ("is even", Describe(m2)); + + const Matcher not_m2 = Not(m2); + EXPECT_EQ("is odd", Describe(not_m2)); + + EXPECT_EQ("% 2 == 0", Explain(m2, '\x42')); +} + // Tests that MatcherCast(m) works when m is a polymorphic matcher. TEST(MatcherCastTest, FromPolymorphicMatcher) { Matcher m = MatcherCast(Eq(5)); @@ -1050,21 +1144,26 @@ TEST(PairTest, CanDescribeSelf) { } TEST(PairTest, CanExplainMatchResultTo) { - const Matcher > m0 = Pair(0, 0); - EXPECT_EQ("", Explain(m0, std::make_pair(25, 42))); + // If neither field matches, Pair() should explain about the first + // field. + const Matcher > m = Pair(GreaterThan(0), GreaterThan(0)); + EXPECT_EQ("the first field is 1 less than 0", + Explain(m, std::make_pair(-1, -2))); - const Matcher > m1 = Pair(GreaterThan(0), 0); - EXPECT_EQ("the first field is 25 more than 0", - Explain(m1, std::make_pair(25, 42))); + // If the first field matches but the second doesn't, Pair() should + // explain about the second field. + EXPECT_EQ("the second field is 2 less than 0", + Explain(m, std::make_pair(1, -2))); - const Matcher > m2 = Pair(0, GreaterThan(0)); - EXPECT_EQ("the second field is 42 more than 0", - Explain(m2, std::make_pair(25, 42))); + // If the first field doesn't match but the second does, Pair() + // should explain about the first field. + EXPECT_EQ("the first field is 1 less than 0", + Explain(m, std::make_pair(-1, 2))); - const Matcher > m3 = Pair(GreaterThan(0), GreaterThan(0)); - EXPECT_EQ("the first field is 25 more than 0" - ", and the second field is 42 more than 0", - Explain(m3, std::make_pair(25, 42))); + // If both fields match, Pair() should explain about them both. + EXPECT_EQ("the first field is 1 more than 0" + ", and the second field is 2 more than 0", + Explain(m, std::make_pair(1, 2))); } TEST(PairTest, MatchesCorrectly) { @@ -3335,6 +3434,16 @@ TEST(ValidateMatcherDescriptionTest, ElementsAre()); } +// The MATCHER*() macros trigger warning C4100 (unreferenced formal +// parameter) in MSVC with -W4. Unfortunately they cannot be fixed in +// the macro definition, as the warnings are generated when the macro +// is expanded and macro expansion cannot contain #pragma. Therefore +// we suppress them here. +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable:4100) +#endif + // We use MATCHER_P3() to define a matcher for testing // ValidateMatcherDescription(); otherwise we'll end up with much // plumbing code. This is not circular as @@ -3345,6 +3454,10 @@ MATCHER_P3(EqInterpolation, start, end, index, "equals Interpolation%(*)s") { arg.param_index == index; } +#ifdef _MSC_VER +#pragma warning(pop) +#endif + TEST(ValidateMatcherDescriptionTest, AcceptsPercentInterpolation) { const char* params[] = { "foo", NULL }; const char* const desc = "one %%";