aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/gmock/gmock-generated-matchers.h189
-rw-r--r--include/gmock/gmock-generated-matchers.h.pump92
-rw-r--r--include/gmock/gmock-matchers.h704
-rw-r--r--include/gmock/gmock-spec-builders.h6
-rw-r--r--test/gmock-generated-matchers_test.cc52
-rw-r--r--test/gmock-matchers_test.cc145
6 files changed, 763 insertions, 425 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<ArgsTuple> {
explicit ArgsMatcherImpl(const InnerMatcher& inner_matcher)
: inner_matcher_(SafeMatcherCast<const SelectedArgs&>(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<ArgsTuple> {
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<RawArgsTuple, k0, k1, k2, k3, k4, k5, k6, k7, k8,
@@ -852,14 +848,19 @@ ElementsAreArray(const T (&array)[N]) {
} // namespace testing
// 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
@@ -892,6 +893,9 @@ ElementsAreArray(const T (&array)[N]) {
// 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
@@ -902,6 +906,9 @@ ElementsAreArray(const T (&array)[N]) {
// 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:
//
@@ -932,6 +939,9 @@ ElementsAreArray(const T (&array)[N]) {
// We also provide MATCHER_P2, MATCHER_P3, ..., up to MATCHER_P10 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:
@@ -964,6 +974,9 @@ ElementsAreArray(const T (&array)[N]) {
//
// 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) { ... }
@@ -991,23 +1004,44 @@ ElementsAreArray(const T (&array)[N]) {
// 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
@@ -1015,7 +1049,8 @@ ElementsAreArray(const T (&array)[N]) {
// 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.
@@ -1028,7 +1063,8 @@ ElementsAreArray(const T (&array)[N]) {
public:\
gmock_Impl(const ::testing::internal::Interpolations& gmock_interp)\
: 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(\
@@ -1058,8 +1094,10 @@ ElementsAreArray(const T (&array)[N]) {
return name##Matcher();\
}\
template <typename arg_type>\
- bool name##Matcher::\
- gmock_Impl<arg_type>::Matches(arg_type arg) const
+ bool name##Matcher::gmock_Impl<arg_type>::MatchAndExplain(\
+ arg_type arg,\
+ ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\
+ const
#define MATCHER_P(name, p0, description)\
template <typename p0##_type>\
@@ -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 <typename p0##_type>\
template <typename arg_type>\
- bool name##MatcherP<p0##_type>::\
- gmock_Impl<arg_type>::Matches(arg_type arg) const
+ bool name##MatcherP<p0##_type>::gmock_Impl<arg_type>::MatchAndExplain(\
+ arg_type arg,\
+ ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\
+ const
#define MATCHER_P2(name, p0, p1, description)\
template <typename p0##_type, typename p1##_type>\
@@ -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 <typename p0##_type, typename p1##_type>\
template <typename arg_type>\
- bool name##MatcherP2<p0##_type, p1##_type>::\
- gmock_Impl<arg_type>::Matches(arg_type arg) const
+ bool name##MatcherP2<p0##_type, \
+ p1##_type>::gmock_Impl<arg_type>::MatchAndExplain(\
+ arg_type arg,\
+ ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\
+ const
#define MATCHER_P3(name, p0, p1, p2, description)\
template <typename p0##_type, typename p1##_type, typename p2##_type>\
@@ -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 <typename p0##_type, typename p1##_type, typename p2##_type>\
template <typename arg_type>\
- bool name##MatcherP3<p0##_type, p1##_type, p2##_type>::\
- gmock_Impl<arg_type>::Matches(arg_type arg) const
+ bool name##MatcherP3<p0##_type, p1##_type, \
+ p2##_type>::gmock_Impl<arg_type>::MatchAndExplain(\
+ arg_type arg,\
+ ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\
+ const
#define MATCHER_P4(name, p0, p1, p2, p3, description)\
template <typename p0##_type, typename p1##_type, typename p2##_type, \
@@ -1227,7 +1276,8 @@ ElementsAreArray(const T (&array)[N]) {
const ::testing::internal::Interpolations& gmock_interp)\
: p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), p3(gmock_p3), \
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(\
@@ -1275,8 +1325,11 @@ ElementsAreArray(const T (&array)[N]) {
template <typename p0##_type, typename p1##_type, typename p2##_type, \
typename p3##_type>\
template <typename arg_type>\
- bool name##MatcherP4<p0##_type, p1##_type, p2##_type, p3##_type>::\
- gmock_Impl<arg_type>::Matches(arg_type arg) const
+ bool name##MatcherP4<p0##_type, p1##_type, p2##_type, \
+ p3##_type>::gmock_Impl<arg_type>::MatchAndExplain(\
+ arg_type arg,\
+ ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\
+ const
#define MATCHER_P5(name, p0, p1, p2, p3, p4, description)\
template <typename p0##_type, typename p1##_type, typename p2##_type, \
@@ -1291,7 +1344,8 @@ ElementsAreArray(const T (&array)[N]) {
const ::testing::internal::Interpolations& gmock_interp)\
: p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), p3(gmock_p3), \
p4(gmock_p4), 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(\
@@ -1342,8 +1396,11 @@ ElementsAreArray(const T (&array)[N]) {
template <typename p0##_type, typename p1##_type, typename p2##_type, \
typename p3##_type, typename p4##_type>\
template <typename arg_type>\
- bool name##MatcherP5<p0##_type, p1##_type, p2##_type, p3##_type, p4##_type>::\
- gmock_Impl<arg_type>::Matches(arg_type arg) const
+ bool name##MatcherP5<p0##_type, p1##_type, p2##_type, p3##_type, \
+ p4##_type>::gmock_Impl<arg_type>::MatchAndExplain(\
+ arg_type arg,\
+ ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\
+ const
#define MATCHER_P6(name, p0, p1, p2, p3, p4, p5, description)\
template <typename p0##_type, typename p1##_type, typename p2##_type, \
@@ -1358,7 +1415,8 @@ ElementsAreArray(const T (&array)[N]) {
const ::testing::internal::Interpolations& gmock_interp)\
: p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), p3(gmock_p3), \
p4(gmock_p4), p5(gmock_p5), 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(\
@@ -1412,8 +1470,10 @@ ElementsAreArray(const T (&array)[N]) {
typename p3##_type, typename p4##_type, typename p5##_type>\
template <typename arg_type>\
bool name##MatcherP6<p0##_type, p1##_type, p2##_type, p3##_type, p4##_type, \
- p5##_type>::\
- gmock_Impl<arg_type>::Matches(arg_type arg) const
+ p5##_type>::gmock_Impl<arg_type>::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 <typename p0##_type, typename p1##_type, typename p2##_type, \
@@ -1431,7 +1491,8 @@ ElementsAreArray(const T (&array)[N]) {
: p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), p3(gmock_p3), \
p4(gmock_p4), p5(gmock_p5), p6(gmock_p6), \
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(\
@@ -1493,8 +1554,10 @@ ElementsAreArray(const T (&array)[N]) {
typename p6##_type>\
template <typename arg_type>\
bool name##MatcherP7<p0##_type, p1##_type, p2##_type, p3##_type, p4##_type, \
- p5##_type, p6##_type>::\
- gmock_Impl<arg_type>::Matches(arg_type arg) const
+ p5##_type, p6##_type>::gmock_Impl<arg_type>::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 <typename p0##_type, typename p1##_type, typename p2##_type, \
@@ -1512,7 +1575,8 @@ ElementsAreArray(const T (&array)[N]) {
: p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), p3(gmock_p3), \
p4(gmock_p4), p5(gmock_p5), p6(gmock_p6), p7(gmock_p7), \
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(\
@@ -1579,8 +1643,11 @@ ElementsAreArray(const T (&array)[N]) {
typename p6##_type, typename p7##_type>\
template <typename arg_type>\
bool name##MatcherP8<p0##_type, p1##_type, p2##_type, p3##_type, p4##_type, \
- p5##_type, p6##_type, p7##_type>::\
- gmock_Impl<arg_type>::Matches(arg_type arg) const
+ p5##_type, p6##_type, \
+ p7##_type>::gmock_Impl<arg_type>::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 <typename p0##_type, typename p1##_type, typename p2##_type, \
@@ -1598,7 +1665,8 @@ ElementsAreArray(const T (&array)[N]) {
: p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), p3(gmock_p3), \
p4(gmock_p4), p5(gmock_p5), p6(gmock_p6), p7(gmock_p7), \
p8(gmock_p8), 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(\
@@ -1668,8 +1736,11 @@ ElementsAreArray(const T (&array)[N]) {
typename p6##_type, typename p7##_type, typename p8##_type>\
template <typename arg_type>\
bool name##MatcherP9<p0##_type, p1##_type, p2##_type, p3##_type, p4##_type, \
- p5##_type, p6##_type, p7##_type, p8##_type>::\
- gmock_Impl<arg_type>::Matches(arg_type arg) const
+ p5##_type, p6##_type, p7##_type, \
+ p8##_type>::gmock_Impl<arg_type>::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 <typename p0##_type, typename p1##_type, typename p2##_type, \
@@ -1689,7 +1760,8 @@ ElementsAreArray(const T (&array)[N]) {
: p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), p3(gmock_p3), \
p4(gmock_p4), p5(gmock_p5), p6(gmock_p6), p7(gmock_p7), \
p8(gmock_p8), p9(gmock_p9), 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(\
@@ -1763,7 +1835,10 @@ ElementsAreArray(const T (&array)[N]) {
typename p9##_type>\
template <typename arg_type>\
bool name##MatcherP10<p0##_type, p1##_type, p2##_type, p3##_type, \
- p4##_type, p5##_type, p6##_type, p7##_type, p8##_type, p9##_type>::\
- gmock_Impl<arg_type>::Matches(arg_type arg) const
+ p4##_type, p5##_type, p6##_type, p7##_type, p8##_type, \
+ p9##_type>::gmock_Impl<arg_type>::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<ArgsTuple> {
explicit ArgsMatcherImpl(const InnerMatcher& inner_matcher)
: inner_matcher_(SafeMatcherCast<const SelectedArgs&>(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<ArgsTuple> {
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<RawArgsTuple, $ks>::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 <typename arg_type>\
- bool $class_name$param_types::\
- gmock_Impl<arg_type>::Matches(arg_type arg) const
+ bool $class_name$param_types::gmock_Impl<arg_type>::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 <typename T>
+ MatchResultListener& operator<<(const T& x) {
+ if (stream_ != NULL)
+ *stream_ << x;
+ return *this;
+ }
+
+ // Returns the underlying ostream.
+ ::std::ostream* stream() { return stream_; }
+
+ private:
+ ::std::ostream* const stream_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(MatchResultListener);
+};
+
+inline MatchResultListener::~MatchResultListener() {
+}
+
// The implementation of a matcher.
template <typename T>
class MatcherInterface {
public:
virtual ~MatcherInterface() {}
+ // Returns true iff the matcher matches x; also explains the match
+ // result to 'listener'.
+ //
+ // You should override this method when defining a new matcher. For
+ // backward compatibility, we provide a default implementation that
+ // just forwards to the old, deprecated matcher API (Matches() and
+ // ExplainMatchResultTo()).
+ //
+ // It's the responsibility of the caller (Google Mock) to guarantee
+ // that 'listener' is not NULL. This helps to simplify a matcher's
+ // implementation when it doesn't care about the performance, as it
+ // can talk to 'listener' without checking its validity first.
+ // However, in order to implement dummy listeners efficiently,
+ // listener->stream() may be NULL.
+ virtual bool MatchAndExplain(T x, MatchResultListener* listener) const {
+ const bool match = Matches(x);
+ if (listener->stream() != NULL) {
+ ExplainMatchResultTo(x, listener->stream());
+ }
+ return match;
+ }
+
+ // DEPRECATED. This method will be removed. Override
+ // MatchAndExplain() instead.
+ //
// Returns true iff the matcher matches x.
- virtual bool Matches(T x) const = 0;
+ virtual bool Matches(T /* x */) const { return false; }
// Describes this matcher to an ostream.
virtual void DescribeTo(::std::ostream* os) const = 0;
@@ -88,6 +148,9 @@ class MatcherInterface {
*os << ")";
}
+ // DEPRECATED. This method will be removed. Override
+ // MatchAndExplain() instead.
+ //
// Explains why x matches, or doesn't match, the matcher. Override
// this to provide any additional information that helps a user
// understand the match result.
@@ -100,14 +163,58 @@ class MatcherInterface {
namespace internal {
+// A match result listener that ignores the explanation.
+class DummyMatchResultListener : public MatchResultListener {
+ public:
+ DummyMatchResultListener() : MatchResultListener(NULL) {}
+
+ private:
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(DummyMatchResultListener);
+};
+
+// A match result listener that forwards the explanation to a given
+// ostream. The difference between this and MatchResultListener is
+// that the former is concrete.
+class StreamMatchResultListener : public MatchResultListener {
+ public:
+ explicit StreamMatchResultListener(::std::ostream* os)
+ : MatchResultListener(os) {}
+
+ private:
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(StreamMatchResultListener);
+};
+
+// A match result listener that stores the explanation in a string.
+class StringMatchResultListener : public MatchResultListener {
+ public:
+ StringMatchResultListener() : MatchResultListener(&ss_) {}
+
+ // Returns the explanation heard so far.
+ internal::string str() const { return ss_.str(); }
+
+ private:
+ ::std::stringstream ss_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(StringMatchResultListener);
+};
+
// An internal class for implementing Matcher<T>, which will derive
// from it. We put functionalities common to all Matcher<T>
// specializations here to avoid code duplication.
template <typename T>
class MatcherBase {
public:
+ // Returns true iff the matcher matches x; also explains the match
+ // result to 'listener'.
+ bool MatchAndExplain(T x, MatchResultListener* listener) const {
+ return impl_->MatchAndExplain(x, listener);
+ }
+
// Returns true iff this matcher matches x.
- bool Matches(T x) const { return impl_->Matches(x); }
+ bool Matches(T x) const {
+ DummyMatchResultListener dummy;
+ return MatchAndExplain(x, &dummy);
+ }
// Describes this matcher to an ostream.
void DescribeTo(::std::ostream* os) const { impl_->DescribeTo(os); }
@@ -119,7 +226,8 @@ class MatcherBase {
// Explains why x matches, or doesn't match, the matcher.
void ExplainMatchResultTo(T x, ::std::ostream* os) const {
- impl_->ExplainMatchResultTo(x, os);
+ StreamMatchResultListener listener(os);
+ MatchAndExplain(x, &listener);
}
protected:
@@ -156,6 +264,27 @@ inline void ExplainMatchResultTo(const PolymorphicMatcherImpl& /* impl */,
// prints the value of x elsewhere.
}
+// The default implementation of MatchAndExplain() for polymorphic
+// matchers.
+template <typename PolymorphicMatcherImpl, typename T>
+inline bool MatchAndExplain(const PolymorphicMatcherImpl& impl,
+ const T& x,
+ MatchResultListener* listener) {
+ const bool match = impl.Matches(x);
+
+ ::std::ostream* const os = listener->stream();
+ if (os != NULL) {
+ using ::testing::internal::ExplainMatchResultTo;
+ // When resolving the following call, both
+ // ::testing::internal::ExplainMatchResultTo() and
+ // foo::ExplainMatchResultTo() are considered, where foo is the
+ // namespace where class PolymorphicMatcherImpl is defined.
+ ExplainMatchResultTo(impl, x, os);
+ }
+
+ return match;
+}
+
} // namespace internal
// A Matcher<T> is a copyable and IMMUTABLE (except by assignment)
@@ -220,19 +349,31 @@ class Matcher<internal::string>
// polymorphic matcher (i.e. a matcher that can match values of more
// than one type, e.g. Eq(n) and NotNull()).
//
-// To define a polymorphic matcher, a user first provides a Impl class
-// that has a Matches() method, a DescribeTo() method, and a
-// DescribeNegationTo() method. The Matches() method is usually a
-// method template (such that it works with multiple types). Then the
-// user creates the polymorphic matcher using
-// MakePolymorphicMatcher(). To provide additional explanation to the
-// match result, define a FREE function (or function template)
+// To define a polymorphic matcher in the old, deprecated way, a user
+// first provides an Impl class that has a Matches() method, a
+// DescribeTo() method, and a DescribeNegationTo() method. The
+// Matches() method is usually a method template (such that it works
+// with multiple types). Then the user creates the polymorphic
+// matcher using MakePolymorphicMatcher(). To provide additional
+// explanation to the match result, define a FREE function (or
+// function template)
//
// void ExplainMatchResultTo(const Impl& matcher, const Value& value,
// ::std::ostream* os);
//
-// in the SAME NAME SPACE where Impl is defined. See the definition
-// of NotNull() for a complete example.
+// in the SAME NAME SPACE where Impl is defined.
+//
+// The new, recommended way to define a polymorphic matcher is to
+// provide an Impl class that has a DescribeTo() method and a
+// DescribeNegationTo() method, and define a FREE function (or
+// function template)
+//
+// bool MatchAndExplain(const Impl& matcher, const Value& value,
+// MatchResultListener* listener);
+//
+// in the SAME NAME SPACE where Impl is defined.
+//
+// See the definition of NotNull() for a complete example.
template <class Impl>
class PolymorphicMatcher {
public:
@@ -257,8 +398,6 @@ class PolymorphicMatcher {
public:
explicit MonomorphicImpl(const Impl& impl) : impl_(impl) {}
- virtual bool Matches(T x) const { return impl_.Matches(x); }
-
virtual void DescribeTo(::std::ostream* os) const {
impl_.DescribeTo(os);
}
@@ -267,22 +406,15 @@ class PolymorphicMatcher {
impl_.DescribeNegationTo(os);
}
- virtual void ExplainMatchResultTo(T x, ::std::ostream* os) const {
- using ::testing::internal::ExplainMatchResultTo;
-
+ virtual bool MatchAndExplain(T x, MatchResultListener* listener) const {
// C++ uses Argument-Dependent Look-up (aka Koenig Look-up) to
- // resolve the call to ExplainMatchResultTo() here. This
- // means that if there's a ExplainMatchResultTo() function
- // defined in the name space where class Impl is defined, it
- // will be picked by the compiler as the better match.
- // Otherwise the default implementation of it in
- // ::testing::internal will be picked.
- //
- // This look-up rule lets a writer of a polymorphic matcher
- // customize the behavior of ExplainMatchResultTo() when he
- // cares to. Nothing needs to be done by the writer if he
- // doesn't need to customize it.
- ExplainMatchResultTo(impl_, x, os);
+ // resolve the call to MatchAndExplain() here. This means that
+ // if there's a MatchAndExplain() function defined in the name
+ // space where class Impl is defined, it will be picked by the
+ // compiler as the better match. Otherwise the default
+ // implementation of it in ::testing::internal will be picked.
+ using ::testing::internal::MatchAndExplain;
+ return MatchAndExplain(impl_, x, listener);
}
private:
@@ -390,16 +522,12 @@ Matcher<T> A();
// and MUST NOT BE USED IN USER CODE!!!
namespace internal {
-// Appends the explanation on the result of matcher.Matches(value) to
-// os iff the explanation is not empty.
-template <typename T>
-void ExplainMatchResultAsNeededTo(const Matcher<T>& matcher, T value,
- ::std::ostream* os) {
- ::std::stringstream reason;
- matcher.ExplainMatchResultTo(value, &reason);
- const internal::string s = reason.str();
- if (s != "") {
- *os << " (" << s << ")";
+// If the given string is not empty and os is not NULL, wraps the
+// string inside a pair of parentheses and streams the result to os.
+inline void StreamInParensAsNeeded(const internal::string& str,
+ ::std::ostream* os) {
+ if (!str.empty() && os != NULL) {
+ *os << " (" << str << ")";
}
}
@@ -439,7 +567,8 @@ class TuplePrefix {
get<N - 1>(matchers);
typedef typename tuple_element<N - 1, ValueTuple>::type Value;
Value value = get<N - 1>(values);
- if (!matcher.Matches(value)) {
+ StringMatchResultListener listener;
+ if (!matcher.MatchAndExplain(value, &listener)) {
// TODO(wan): include in the message the name of the parameter
// as used in MOCK_METHOD*() when possible.
*os << " Expected arg #" << N - 1 << ": ";
@@ -452,7 +581,8 @@ class TuplePrefix {
// the address is interesting.
internal::UniversalPrinter<GMOCK_REMOVE_REFERENCE_(Value)>::
Print(value, os);
- ExplainMatchResultAsNeededTo<Value>(matcher, value, os);
+
+ StreamInParensAsNeeded(listener.str(), os);
*os << "\n";
}
}
@@ -537,8 +667,8 @@ class MatcherCastImpl<T, Matcher<U> > {
: source_matcher_(source_matcher) {}
// We delegate the matching logic to the source matcher.
- virtual bool Matches(T x) const {
- return source_matcher_.Matches(static_cast<U>(x));
+ virtual bool MatchAndExplain(T x, MatchResultListener* listener) const {
+ return source_matcher_.MatchAndExplain(static_cast<U>(x), listener);
}
virtual void DescribeTo(::std::ostream* os) const {
@@ -549,10 +679,6 @@ class MatcherCastImpl<T, Matcher<U> > {
source_matcher_.DescribeNegationTo(os);
}
- virtual void ExplainMatchResultTo(T x, ::std::ostream* os) const {
- source_matcher_.ExplainMatchResultTo(static_cast<U>(x), os);
- }
-
private:
const Matcher<U> source_matcher_;
@@ -572,7 +698,8 @@ class MatcherCastImpl<T, Matcher<T> > {
template <typename T>
class AnyMatcherImpl : public MatcherInterface<T> {
public:
- virtual bool Matches(T /* x */) const { return true; }
+ virtual bool MatchAndExplain(
+ T /* x */, MatchResultListener* /* listener */) const { return true; }
virtual void DescribeTo(::std::ostream* os) const { *os << "is anything"; }
virtual void DescribeNegationTo(::std::ostream* os) const {
// This is mostly for completeness' safe, as it's not very useful
@@ -618,7 +745,10 @@ class AnythingMatcher {
class Impl : public MatcherInterface<Lhs> { \
public: \
explicit Impl(const Rhs& rhs) : rhs_(rhs) {} \
- virtual bool Matches(Lhs lhs) const { return lhs op rhs_; } \
+ virtual bool MatchAndExplain(\
+ Lhs lhs, MatchResultListener* /* listener */) const { \
+ return lhs op rhs_; \
+ } \
virtual void DescribeTo(::std::ostream* os) const { \
*os << "is " relation " "; \
UniversalPrinter<Rhs>::Print(rhs_, os); \
@@ -719,7 +849,11 @@ class RefMatcher<T&> {
// Matches() takes a Super& (as opposed to const Super&) in
// order to match the interface MatcherInterface<Super&>.
- virtual bool Matches(Super& x) const { return &x == &object_; } // NOLINT
+ virtual bool MatchAndExplain(
+ Super& x, MatchResultListener* listener) const {
+ *listener << "is located @" << static_cast<const void*>(&x);
+ return &x == &object_;
+ }
virtual void DescribeTo(::std::ostream* os) const {
*os << "references the variable ";
@@ -731,11 +865,6 @@ class RefMatcher<T&> {
UniversalPrinter<Super&>::Print(object_, os);
}
- virtual void ExplainMatchResultTo(Super& x, // NOLINT
- ::std::ostream* os) const {
- *os << "is located @" << static_cast<const void*>(&x);
- }
-
private:
const Super& object_;
@@ -1017,7 +1146,9 @@ class MatchesRegexMatcher {
template <typename T1, typename T2> \
class Impl : public MatcherInterface<const ::std::tr1::tuple<T1, T2>&> { \
public: \
- virtual bool Matches(const ::std::tr1::tuple<T1, T2>& args) const { \
+ virtual bool MatchAndExplain( \
+ const ::std::tr1::tuple<T1, T2>& args, \
+ MatchResultListener* /* listener */) const { \
return ::std::tr1::get<0>(args) op ::std::tr1::get<1>(args); \
} \
virtual void DescribeTo(::std::ostream* os) const { \
@@ -1049,8 +1180,8 @@ class NotMatcherImpl : public MatcherInterface<T> {
explicit NotMatcherImpl(const Matcher<T>& matcher)
: matcher_(matcher) {}
- virtual bool Matches(T x) const {
- return !matcher_.Matches(x);
+ virtual bool MatchAndExplain(T x, MatchResultListener* listener) const {
+ return !matcher_.MatchAndExplain(x, listener);
}
virtual void DescribeTo(::std::ostream* os) const {
@@ -1061,10 +1192,6 @@ class NotMatcherImpl : public MatcherInterface<T> {
matcher_.DescribeTo(os);
}
- virtual void ExplainMatchResultTo(T x, ::std::ostream* os) const {
- matcher_.ExplainMatchResultTo(x, os);
- }
-
private:
const Matcher<T> matcher_;
@@ -1101,10 +1228,6 @@ class BothOfMatcherImpl : public MatcherInterface<T> {
BothOfMatcherImpl(const Matcher<T>& matcher1, const Matcher<T>& matcher2)
: matcher1_(matcher1), matcher2_(matcher2) {}
- virtual bool Matches(T x) const {
- return matcher1_.Matches(x) && matcher2_.Matches(x);
- }
-
virtual void DescribeTo(::std::ostream* os) const {
*os << "(";
matcher1_.DescribeTo(os);
@@ -1118,35 +1241,34 @@ class BothOfMatcherImpl : public MatcherInterface<T> {
DescribeTo(os);
}
- virtual void ExplainMatchResultTo(T x, ::std::ostream* os) const {
- if (Matches(x)) {
- // When both matcher1_ and matcher2_ match x, we need to
- // explain why *both* of them match.
- ::std::stringstream ss1;
- matcher1_.ExplainMatchResultTo(x, &ss1);
- const internal::string s1 = ss1.str();
+ virtual bool MatchAndExplain(T x, MatchResultListener* listener) const {
+ // If either matcher1_ or matcher2_ doesn't match x, we only need
+ // to explain why one of them fails.
+ StringMatchResultListener listener1;
+ if (!matcher1_.MatchAndExplain(x, &listener1)) {
+ *listener << listener1.str();
+ return false;
+ }
+
+ StringMatchResultListener listener2;
+ if (!matcher2_.MatchAndExplain(x, &listener2)) {
+ *listener << listener2.str();
+ return false;
+ }
- ::std::stringstream ss2;
- matcher2_.ExplainMatchResultTo(x, &ss2);
- const internal::string s2 = ss2.str();
+ // Otherwise we need to explain why *both* of them match.
+ const internal::string s1 = listener1.str();
+ const internal::string s2 = listener2.str();
- if (s1 == "") {
- *os << s2;
- } else {
- *os << s1;
- if (s2 != "") {
- *os << "; " << s2;
- }
- }
+ if (s1 == "") {
+ *listener << s2;
} else {
- // Otherwise we only need to explain why *one* of them fails
- // to match.
- if (!matcher1_.Matches(x)) {
- matcher1_.ExplainMatchResultTo(x, os);
- } else {
- matcher2_.ExplainMatchResultTo(x, os);
+ *listener << s1;
+ if (s2 != "") {
+ *listener << "; " << s2;
}
}
+ return true;
}
private:
@@ -1190,10 +1312,6 @@ class EitherOfMatcherImpl : public MatcherInterface<T> {
EitherOfMatcherImpl(const Matcher<T>& matcher1, const Matcher<T>& matcher2)
: matcher1_(matcher1), matcher2_(matcher2) {}
- virtual bool Matches(T x) const {
- return matcher1_.Matches(x) || matcher2_.Matches(x);
- }
-
virtual void DescribeTo(::std::ostream* os) const {
*os << "(";
matcher1_.DescribeTo(os);
@@ -1207,34 +1325,34 @@ class EitherOfMatcherImpl : public MatcherInterface<T> {
DescribeTo(os);
}
- virtual void ExplainMatchResultTo(T x, ::std::ostream* os) const {
- if (Matches(x)) {
- // If either matcher1_ or matcher2_ matches x, we just need
- // to explain why *one* of them matches.
- if (matcher1_.Matches(x)) {
- matcher1_.ExplainMatchResultTo(x, os);
- } else {
- matcher2_.ExplainMatchResultTo(x, os);
- }
- } else {
- // Otherwise we need to explain why *neither* matches.
- ::std::stringstream ss1;
- matcher1_.ExplainMatchResultTo(x, &ss1);
- const internal::string s1 = ss1.str();
+ virtual bool MatchAndExplain(T x, MatchResultListener* listener) const {
+ // If either matcher1_ or matcher2_ matches x, we just need to
+ // explain why *one* of them matches.
+ StringMatchResultListener listener1;
+ if (matcher1_.MatchAndExplain(x, &listener1)) {
+ *listener << listener1.str();
+ return true;
+ }
- ::std::stringstream ss2;
- matcher2_.ExplainMatchResultTo(x, &ss2);
- const internal::string s2 = ss2.str();
+ StringMatchResultListener listener2;
+ if (matcher2_.MatchAndExplain(x, &listener2)) {
+ *listener << listener2.str();
+ return true;
+ }
- if (s1 == "") {
- *os << s2;
- } else {
- *os << s1;
- if (s2 != "") {
- *os << "; " << s2;
- }
+ // Otherwise we need to explain why *both* of them fail.
+ const internal::string s1 = listener1.str();
+ const internal::string s2 = listener2.str();
+
+ if (s1 == "") {
+ *listener << s2;
+ } else {
+ *listener << s1;
+ if (s2 != "") {
+ *listener << "; " << s2;
}
}
+ return false;
}
private:
@@ -1367,7 +1485,8 @@ class PredicateFormatterFromMatcher {
// Matcher<const T&>(matcher_), as the latter won't compile when
// matcher_ has type Matcher<T> (e.g. An<int>()).
const Matcher<const T&> matcher = MatcherCast<const T&>(matcher_);
- if (matcher.Matches(x)) {
+ StringMatchResultListener listener;
+ if (matcher.MatchAndExplain(x, &listener)) {
return AssertionSuccess();
} else {
::std::stringstream ss;
@@ -1376,7 +1495,7 @@ class PredicateFormatterFromMatcher {
matcher.DescribeTo(&ss);
ss << "\n Actual: ";
UniversalPrinter<T>::Print(x, &ss);
- ExplainMatchResultAsNeededTo<const T&>(matcher, x, &ss);
+ StreamInParensAsNeeded(listener.str(), &ss);
return AssertionFailure(Message() << ss.str());
}
}
@@ -1417,7 +1536,8 @@ class FloatingEqMatcher {
Impl(FloatType rhs, bool nan_eq_nan) :
rhs_(rhs), nan_eq_nan_(nan_eq_nan) {}
- virtual bool Matches(T value) const {
+ virtual bool MatchAndExplain(T value,
+ MatchResultListener* /* listener */) const {
const FloatingPoint<FloatType> lhs(value), rhs(rhs_);
// Compares NaNs first, if nan_eq_nan_ is true.
@@ -1525,10 +1645,6 @@ class PointeeMatcher {
explicit Impl(const InnerMatcher& matcher)
: matcher_(MatcherCast<const Pointee&>(matcher)) {}
- virtual bool Matches(Pointer p) const {
- return GetRawPointer(p) != NULL && matcher_.Matches(*p);
- }
-
virtual void DescribeTo(::std::ostream* os) const {
*os << "points to a value that ";
matcher_.DescribeTo(os);
@@ -1539,17 +1655,18 @@ class PointeeMatcher {
matcher_.DescribeTo(os);
}
- virtual void ExplainMatchResultTo(Pointer pointer,
- ::std::ostream* os) const {
+ virtual bool MatchAndExplain(Pointer pointer,
+ MatchResultListener* listener) const {
if (GetRawPointer(pointer) == NULL)
- return;
+ return false;
- ::std::stringstream ss;
- matcher_.ExplainMatchResultTo(*pointer, &ss);
- const internal::string s = ss.str();
+ StringMatchResultListener inner_listener;
+ const bool match = matcher_.MatchAndExplain(*pointer, &inner_listener);
+ const internal::string s = inner_listener.str();
if (s != "") {
- *os << "points to a value that " << s;
+ *listener << "points to a value that " << s;
}
+ return match;
}
private:
@@ -1572,16 +1689,6 @@ class FieldMatcher {
const Matcher<const FieldType&>& matcher)
: field_(field), matcher_(matcher) {}
- // Returns true iff the inner matcher matches obj.field.
- bool Matches(const Class& obj) const {
- return matcher_.Matches(obj.*field_);
- }
-
- // Returns true iff the inner matcher matches obj->field.
- bool Matches(const Class* p) const {
- return (p != NULL) && matcher_.Matches(p->*field_);
- }
-
void DescribeTo(::std::ostream* os) const {
*os << "the given field ";
matcher_.DescribeTo(os);
@@ -1592,27 +1699,29 @@ class FieldMatcher {
matcher_.DescribeNegationTo(os);
}
- // The first argument of ExplainMatchResultTo() is needed to help
+ // The first argument of MatchAndExplain() is needed to help
// Symbian's C++ compiler choose which overload to use. Its type is
// true_type iff the Field() matcher is used to match a pointer.
- void ExplainMatchResultTo(false_type /* is_not_pointer */, const Class& obj,
- ::std::ostream* os) const {
- ::std::stringstream ss;
- matcher_.ExplainMatchResultTo(obj.*field_, &ss);
- const internal::string s = ss.str();
+ bool MatchAndExplain(false_type /* is_not_pointer */, const Class& obj,
+ MatchResultListener* listener) const {
+ StringMatchResultListener inner_listener;
+ const bool match = matcher_.MatchAndExplain(obj.*field_, &inner_listener);
+ const internal::string s = inner_listener.str();
if (s != "") {
- *os << "the given field " << s;
+ *listener << "the given field " << s;
}
+ return match;
}
- void ExplainMatchResultTo(true_type /* is_pointer */, const Class* p,
- ::std::ostream* os) const {
- if (p != NULL) {
- // Since *p has a field, it must be a class/struct/union type
- // and thus cannot be a pointer. Therefore we pass false_type()
- // as the first argument.
- ExplainMatchResultTo(false_type(), *p, os);
- }
+ bool MatchAndExplain(true_type /* is_pointer */, const Class* p,
+ MatchResultListener* listener) const {
+ if (p == NULL)
+ return false;
+
+ // Since *p has a field, it must be a class/struct/union type and
+ // thus cannot be a pointer. Therefore we pass false_type() as
+ // the first argument.
+ return MatchAndExplain(false_type(), *p, listener);
}
private:
@@ -1622,12 +1731,11 @@ class FieldMatcher {
GTEST_DISALLOW_ASSIGN_(FieldMatcher);
};
-// Explains the result of matching an object or pointer against a field matcher.
template <typename Class, typename FieldType, typename T>
-void ExplainMatchResultTo(const FieldMatcher<Class, FieldType>& matcher,
- const T& value, ::std::ostream* os) {
- matcher.ExplainMatchResultTo(
- typename ::testing::internal::is_pointer<T>::type(), value, os);
+bool MatchAndExplain(const FieldMatcher<Class, FieldType>& matcher,
+ const T& value, MatchResultListener* listener) {
+ return matcher.MatchAndExplain(
+ typename ::testing::internal::is_pointer<T>::type(), value, listener);
}
// Implements the Property() matcher for matching a property
@@ -1645,16 +1753,6 @@ class PropertyMatcher {
const Matcher<RefToConstProperty>& matcher)
: property_(property), matcher_(matcher) {}
- // Returns true iff obj.property() matches the inner matcher.
- bool Matches(const Class& obj) const {
- return matcher_.Matches((obj.*property_)());
- }
-
- // Returns true iff p->property() matches the inner matcher.
- bool Matches(const Class* p) const {
- return (p != NULL) && matcher_.Matches((p->*property_)());
- }
-
void DescribeTo(::std::ostream* os) const {
*os << "the given property ";
matcher_.DescribeTo(os);
@@ -1665,27 +1763,30 @@ class PropertyMatcher {
matcher_.DescribeNegationTo(os);
}
- // The first argument of ExplainMatchResultTo() is needed to help
+ // The first argument of MatchAndExplain() is needed to help
// Symbian's C++ compiler choose which overload to use. Its type is
// true_type iff the Property() matcher is used to match a pointer.
- void ExplainMatchResultTo(false_type /* is_not_pointer */, const Class& obj,
- ::std::ostream* os) const {
- ::std::stringstream ss;
- matcher_.ExplainMatchResultTo((obj.*property_)(), &ss);
- const internal::string s = ss.str();
+ bool MatchAndExplain(false_type /* is_not_pointer */, const Class& obj,
+ MatchResultListener* listener) const {
+ StringMatchResultListener inner_listener;
+ const bool match = matcher_.MatchAndExplain((obj.*property_)(),
+ &inner_listener);
+ const internal::string s = inner_listener.str();
if (s != "") {
- *os << "the given property " << s;
+ *listener << "the given property " << s;
}
+ return match;
}
- void ExplainMatchResultTo(true_type /* is_pointer */, const Class* p,
- ::std::ostream* os) const {
- if (p != NULL) {
- // Since *p has a property method, it must be a
- // class/struct/union type and thus cannot be a pointer.
- // Therefore we pass false_type() as the first argument.
- ExplainMatchResultTo(false_type(), *p, os);
- }
+ bool MatchAndExplain(true_type /* is_pointer */, const Class* p,
+ MatchResultListener* listener) const {
+ if (p == NULL)
+ return false;
+
+ // Since *p has a property method, it must be a class/struct/union
+ // type and thus cannot be a pointer. Therefore we pass
+ // false_type() as the first argument.
+ return MatchAndExplain(false_type(), *p, listener);
}
private:
@@ -1695,13 +1796,11 @@ class PropertyMatcher {
GTEST_DISALLOW_ASSIGN_(PropertyMatcher);
};
-// Explains the result of matching an object or pointer against a
-// property matcher.
-template <typename Class, typename PropertyType, typename T>
-void ExplainMatchResultTo(const PropertyMatcher<Class, PropertyType>& matcher,
- const T& value, ::std::ostream* os) {
- matcher.ExplainMatchResultTo(
- typename ::testing::internal::is_pointer<T>::type(), value, os);
+template <typename Class, typename PropertyType, typename T>
+bool MatchAndExplain(const PropertyMatcher<Class, PropertyType>& matcher,
+ const T& value, MatchResultListener* listener) {
+ return matcher.MatchAndExplain(
+ typename ::testing::internal::is_pointer<T>::type(), value, listener);
}
// Type traits specifying various features of different functors for ResultOf.
@@ -1759,13 +1858,6 @@ class ResultOfMatcher {
public:
Impl(CallableStorageType callable, const Matcher<ResultType>& matcher)
: callable_(callable), matcher_(matcher) {}
- // Returns true iff callable_(obj) matches the inner matcher.
- // The calling syntax is different for different types of callables
- // so we abstract it in CallableTraits<Callable>::Invoke().
- virtual bool Matches(T obj) const {
- return matcher_.Matches(
- CallableTraits<Callable>::template Invoke<T>(callable_, obj));
- }
virtual void DescribeTo(::std::ostream* os) const {
*os << "result of the given callable ";
@@ -1777,14 +1869,17 @@ class ResultOfMatcher {
matcher_.DescribeNegationTo(os);
}
- virtual void ExplainMatchResultTo(T obj, ::std::ostream* os) const {
- ::std::stringstream ss;
- matcher_.ExplainMatchResultTo(
+ virtual bool MatchAndExplain(T obj, MatchResultListener* listener) const {
+ StringMatchResultListener inner_listener;
+ const bool match = matcher_.MatchAndExplain(
CallableTraits<Callable>::template Invoke<T>(callable_, obj),
- &ss);
- const internal::string s = ss.str();
+ &inner_listener);
+
+ const internal::string s = inner_listener.str();
if (s != "")
- *os << "result of the given callable " << s;
+ *listener << "result of the given callable " << s;
+
+ return match;
}
private:
@@ -1929,17 +2024,6 @@ class ContainsMatcherImpl : public MatcherInterface<Container> {
: inner_matcher_(
testing::SafeMatcherCast<const Element&>(inner_matcher)) {}
- // Returns true iff 'container' matches.
- virtual bool Matches(Container container) const {
- StlContainerReference stl_container = View::ConstReference(container);
- for (typename StlContainer::const_iterator it = stl_container.begin();
- it != stl_container.end(); ++it) {
- if (inner_matcher_.Matches(*it))
- return true;
- }
- return false;
- }
-
// Describes what this matcher does.
virtual void DescribeTo(::std::ostream* os) const {
*os << "contains at least one element that ";
@@ -1952,19 +2036,18 @@ class ContainsMatcherImpl : public MatcherInterface<Container> {
inner_matcher_.DescribeTo(os);
}
- // Explains why 'container' matches, or doesn't match, this matcher.
- virtual void ExplainMatchResultTo(Container container,
- ::std::ostream* os) const {
+ virtual bool MatchAndExplain(Container container,
+ MatchResultListener* listener) const {
StlContainerReference stl_container = View::ConstReference(container);
-
- // We need to explain which (if any) element matches inner_matcher_.
- typename StlContainer::const_iterator it = stl_container.begin();
- for (size_t i = 0; it != stl_container.end(); ++it, ++i) {
+ size_t i = 0;
+ for (typename StlContainer::const_iterator it = stl_container.begin();
+ it != stl_container.end(); ++it, ++i) {
if (inner_matcher_.Matches(*it)) {
- *os << "element " << i << " matches";
- return;
+ *listener << "element " << i << " matches";
+ return true;
}
}
+ return false;
}
private:
@@ -2007,8 +2090,9 @@ class KeyMatcherImpl : public MatcherInterface<PairType> {
}
// Returns true iff 'key_value.first' (the key) matches the inner matcher.
- virtual bool Matches(PairType key_value) const {
- return inner_matcher_.Matches(key_value.first);
+ virtual bool MatchAndExplain(PairType key_value,
+ MatchResultListener* listener) const {
+ return inner_matcher_.MatchAndExplain(key_value.first, listener);
}
// Describes what this matcher does.
@@ -2023,12 +2107,6 @@ class KeyMatcherImpl : public MatcherInterface<PairType> {
inner_matcher_.DescribeTo(os);
}
- // Explains why 'key_value' matches, or doesn't match, this matcher.
- virtual void ExplainMatchResultTo(PairType key_value,
- ::std::ostream* os) const {
- inner_matcher_.ExplainMatchResultTo(key_value.first, os);
- }
-
private:
const Matcher<const KeyType&> inner_matcher_;
@@ -2069,13 +2147,6 @@ class PairMatcherImpl : public MatcherInterface<PairType> {
testing::SafeMatcherCast<const SecondType&>(second_matcher)) {
}
- // Returns true iff 'a_pair.first' matches first_matcher and 'a_pair.second'
- // matches second_matcher.
- virtual bool Matches(PairType a_pair) const {
- return first_matcher_.Matches(a_pair.first) &&
- second_matcher_.Matches(a_pair.second);
- }
-
// Describes what this matcher does.
virtual void DescribeTo(::std::ostream* os) const {
*os << "has a first field that ";
@@ -2092,28 +2163,40 @@ class PairMatcherImpl : public MatcherInterface<PairType> {
second_matcher_.DescribeNegationTo(os);
}
- // Explains why 'a_pair' matches, or doesn't match, this matcher.
- virtual void ExplainMatchResultTo(PairType a_pair,
- ::std::ostream* os) const {
- ::std::stringstream ss1;
- first_matcher_.ExplainMatchResultTo(a_pair.first, &ss1);
- internal::string s1 = ss1.str();
+ // Returns true iff 'a_pair.first' matches first_matcher and 'a_pair.second'
+ // matches second_matcher.
+ virtual bool MatchAndExplain(PairType a_pair,
+ MatchResultListener* listener) const {
+ StringMatchResultListener listener1;
+ const bool match1 = first_matcher_.MatchAndExplain(a_pair.first,
+ &listener1);
+ internal::string s1 = listener1.str();
if (s1 != "") {
- s1 = "the first field " + s1;
+ s1 = "the first field " + s1;
+ }
+ if (!match1) {
+ *listener << s1;
+ return false;
}
- ::std::stringstream ss2;
- second_matcher_.ExplainMatchResultTo(a_pair.second, &ss2);
- internal::string s2 = ss2.str();
+ StringMatchResultListener listener2;
+ const bool match2 = second_matcher_.MatchAndExplain(a_pair.second,
+ &listener2);
+ internal::string s2 = listener2.str();
if (s2 != "") {
- s2 = "the second field " + s2;
+ s2 = "the second field " + s2;
+ }
+ if (!match2) {
+ *listener << s2;
+ return false;
}
- *os << s1;
+ *listener << s1;
if (s1 != "" && s2 != "") {
- *os << ", and ";
+ *listener << ", and ";
}
- *os << s2;
+ *listener << s2;
+ return true;
}
private:
@@ -2165,21 +2248,6 @@ class ElementsAreMatcherImpl : public MatcherInterface<Container> {
}
}
- // Returns true iff 'container' matches.
- virtual bool Matches(Container container) const {
- StlContainerReference stl_container = View::ConstReference(container);
- if (stl_container.size() != count())
- return false;
-
- typename StlContainer::const_iterator it = stl_container.begin();
- for (size_t i = 0; i != count(); ++it, ++i) {
- if (!matchers_[i].Matches(*it))
- return false;
- }
-
- return true;
- }
-
// Describes what this matcher does.
virtual void DescribeTo(::std::ostream* os) const {
if (count() == 0) {
@@ -2216,63 +2284,54 @@ class ElementsAreMatcherImpl : public MatcherInterface<Container> {
}
}
- // Explains why 'container' matches, or doesn't match, this matcher.
- virtual void ExplainMatchResultTo(Container container,
- ::std::ostream* os) const {
+ virtual bool MatchAndExplain(Container container,
+ MatchResultListener* listener) const {
StlContainerReference stl_container = View::ConstReference(container);
- if (Matches(container)) {
- // We need to explain why *each* element matches (the obvious
- // ones can be skipped).
-
- bool reason_printed = false;
- typename StlContainer::const_iterator it = stl_container.begin();
- for (size_t i = 0; i != count(); ++it, ++i) {
- ::std::stringstream ss;
- matchers_[i].ExplainMatchResultTo(*it, &ss);
-
- const string s = ss.str();
- if (!s.empty()) {
- if (reason_printed) {
- *os << ",\n";
- }
- *os << "element " << i << " " << s;
- reason_printed = true;
- }
- }
- } else {
- // We need to explain why the container doesn't match.
- const size_t actual_count = stl_container.size();
- if (actual_count != count()) {
- // The element count doesn't match. If the container is
- // empty, there's no need to explain anything as Google Mock
- // already prints the empty container. Otherwise we just need
- // to show how many elements there actually are.
- if (actual_count != 0) {
- *os << "has " << Elements(actual_count);
- }
- return;
+ const size_t actual_count = stl_container.size();
+ if (actual_count != count()) {
+ // The element count doesn't match. If the container is empty,
+ // there's no need to explain anything as Google Mock already
+ // prints the empty container. Otherwise we just need to show
+ // how many elements there actually are.
+ if (actual_count != 0) {
+ *listener << "has " << Elements(actual_count);
}
+ return false;
+ }
- // The container has the right size but at least one element
- // doesn't match expectation. We need to find this element and
- // explain why it doesn't match.
- typename StlContainer::const_iterator it = stl_container.begin();
- for (size_t i = 0; i != count(); ++it, ++i) {
- if (matchers_[i].Matches(*it)) {
- continue;
- }
+ typename StlContainer::const_iterator it = stl_container.begin();
+ // explanations[i] is the explanation of the element at index i.
+ std::vector<internal::string> explanations(count());
+ for (size_t i = 0; i != count(); ++it, ++i) {
+ StringMatchResultListener s;
+ if (matchers_[i].MatchAndExplain(*it, &s)) {
+ explanations[i] = s.str();
+ } else {
+ // The container has the right size but the i-th element
+ // doesn't match its expectation.
+ *listener << "element " << i << " doesn't match";
+
+ StreamInParensAsNeeded(s.str(), listener->stream());
+ return false;
+ }
+ }
- *os << "element " << i << " doesn't match";
+ // Every element matches its expectation. We need to explain why
+ // (the obvious ones can be skipped).
- ::std::stringstream ss;
- matchers_[i].ExplainMatchResultTo(*it, &ss);
- const string s = ss.str();
- if (!s.empty()) {
- *os << " (" << s << ")";
+ bool reason_printed = false;
+ for (size_t i = 0; i != count(); ++i) {
+ const internal::string& s = explanations[i];
+ if (!s.empty()) {
+ if (reason_printed) {
+ *listener << ",\n";
}
- return;
+ *listener << "element " << i << " " << s;
+ reason_printed = true;
}
}
+
+ return true;
}
private:
@@ -2811,13 +2870,14 @@ Truly(Predicate pred) {
// values that are included in one container but not the other. (Duplicate
// values and order differences are not explained.)
template <typename Container>
-inline PolymorphicMatcher<internal::ContainerEqMatcher<
+inline PolymorphicMatcher<internal::ContainerEqMatcher< // NOLINT
GMOCK_REMOVE_CONST_(Container)> >
ContainerEq(const Container& rhs) {
// This following line is for working around a bug in MSVC 8.0,
// which causes Container to be a const type sometimes.
typedef GMOCK_REMOVE_CONST_(Container) RawContainer;
- return MakePolymorphicMatcher(internal::ContainerEqMatcher<RawContainer>(rhs));
+ return MakePolymorphicMatcher(
+ internal::ContainerEqMatcher<RawContainer>(rhs));
}
// Matches an STL-style container or a native array that contains at
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<const ArgumentTuple&>(
- 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<int> m1 = IsEven2();
+ EXPECT_EQ("OK", Explain(m1, 4));
+ EXPECT_EQ("% 2 == 1", Explain(m1, 5));
+
+ const Matcher<int> 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<int> {
// two methods is optional.
};
-TEST(MatcherInterfaceTest, CanBeImplemented) {
+TEST(MatcherInterfaceTest, CanBeImplementedUsingDeprecatedAPI) {
EvenMatcherImpl m;
}
+// Tests implementing a monomorphic matcher using MatchAndExplain().
+
+class NewEvenMatcherImpl : public MatcherInterface<int> {
+ 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<int> 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<double> m;
@@ -252,6 +282,18 @@ TEST(MatcherTest, CanDescribeItself) {
Describe(Matcher<int>(new EvenMatcherImpl)));
}
+// Tests Matcher<T>::MatchAndExplain().
+TEST(MatcherTest, MatchAndExplain) {
+ Matcher<int> 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<string> or Matcher<const string&>.
TEST(StringMatcherTest, CanBeImplicitlyConstructedFromCStringLiteral) {
@@ -284,8 +326,8 @@ TEST(MakeMatcherTest, ConstructsMatcherFromMatcherInterface) {
Matcher<int> 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<ReferencesBarOrIsZeroImpl> ReferencesBarOrIsZero() {
return MakePolymorphicMatcher(ReferencesBarOrIsZeroImpl());
}
-TEST(MakePolymorphicMatcherTest, ConstructsMatcherFromImpl) {
+TEST(MakePolymorphicMatcherTest, ConstructsMatcherUsingOldAPI) {
// Using a polymorphic matcher to match a reference type.
Matcher<const int&> 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 <typename T>
+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<PolymorphicIsEvenImpl> PolymorphicIsEven() {
+ return MakePolymorphicMatcher(PolymorphicIsEvenImpl());
+}
+
+TEST(MakePolymorphicMatcherTest, ConstructsMatcherUsingNewAPI) {
+ // Using PolymorphicIsEven() as a Matcher<int>.
+ const Matcher<int> m1 = PolymorphicIsEven();
+ EXPECT_TRUE(m1.Matches(42));
+ EXPECT_FALSE(m1.Matches(43));
+ EXPECT_EQ("is even", Describe(m1));
+
+ const Matcher<int> not_m1 = Not(m1);
+ EXPECT_EQ("is odd", Describe(not_m1));
+
+ EXPECT_EQ("% 2 == 0", Explain(m1, 42));
+
+ // Using PolymorphicIsEven() as a Matcher<char>.
+ const Matcher<char> m2 = PolymorphicIsEven();
+ EXPECT_TRUE(m2.Matches('\x42'));
+ EXPECT_FALSE(m2.Matches('\x43'));
+ EXPECT_EQ("is even", Describe(m2));
+
+ const Matcher<char> not_m2 = Not(m2);
+ EXPECT_EQ("is odd", Describe(not_m2));
+
+ EXPECT_EQ("% 2 == 0", Explain(m2, '\x42'));
+}
+
// Tests that MatcherCast<T>(m) works when m is a polymorphic matcher.
TEST(MatcherCastTest, FromPolymorphicMatcher) {
Matcher<int> m = MatcherCast<int>(Eq(5));
@@ -1050,21 +1144,26 @@ TEST(PairTest, CanDescribeSelf) {
}
TEST(PairTest, CanExplainMatchResultTo) {
- const Matcher<std::pair<int, int> > 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<std::pair<int, int> > 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<std::pair<int, int> > 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<std::pair<int, int> > 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<std::pair<int, int> > 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 %%";