diff --git a/googlemock/include/gmock/gmock-matchers.h b/googlemock/include/gmock/gmock-matchers.h index 3daf617307..26401d534e 100644 --- a/googlemock/include/gmock/gmock-matchers.h +++ b/googlemock/include/gmock/gmock-matchers.h @@ -1419,34 +1419,55 @@ class AnyOfMatcherImpl : public MatcherInterface { bool MatchAndExplain(const T& x, MatchResultListener* listener) const override { + // This method uses matcher's explanation when explaining the result. + // However, if matcher doesn't provide one, this method uses matcher's + // description. std::string no_match_result; - - // If either matcher1_ or matcher2_ matches x, we just need to - // explain why *one* of them matches. - for (size_t i = 0; i < matchers_.size(); ++i) { + for (const Matcher& matcher : matchers_) { StringMatchResultListener slistener; - if (matchers_[i].MatchAndExplain(x, &slistener)) { - *listener << slistener.str(); + // Return explanation for first match. + if (matcher.MatchAndExplain(x, &slistener)) { + const std::string explanation = slistener.str(); + if (!explanation.empty()) { + *listener << explanation; + } else { + *listener << "which matches (" << Describe(matcher) << ")"; + } return true; + } + // Keep track of explanations in case there is no match. + std::string explanation = slistener.str(); + if (explanation.empty()) { + explanation = DescribeNegation(matcher); + } + if (no_match_result.empty()) { + no_match_result = explanation; } else { - if (no_match_result.empty()) { - no_match_result = slistener.str(); - } else { - std::string result = slistener.str(); - if (!result.empty()) { - no_match_result += ", and "; - no_match_result += result; - } + if (!explanation.empty()) { + no_match_result += ", and "; + no_match_result += explanation; } } } - // Otherwise we need to explain why *both* of them fail. *listener << no_match_result; return false; } private: + // Returns matcher description as a string. + std::string Describe(const Matcher& matcher) const { + StringMatchResultListener listener; + matcher.DescribeTo(listener.stream()); + return listener.str(); + } + + std::string DescribeNegation(const Matcher& matcher) const { + StringMatchResultListener listener; + matcher.DescribeNegationTo(listener.stream()); + return listener.str(); + } + const std::vector> matchers_; }; diff --git a/googlemock/test/gmock-matchers-arithmetic_test.cc b/googlemock/test/gmock-matchers-arithmetic_test.cc index 6968f55bec..06b0b477c1 100644 --- a/googlemock/test/gmock-matchers-arithmetic_test.cc +++ b/googlemock/test/gmock-matchers-arithmetic_test.cc @@ -776,45 +776,43 @@ TEST(AnyOfTest, AnyOfMatcherSafelyCastsMonomorphicMatchers) { TEST_P(AnyOfTestP, ExplainsResult) { Matcher m; - // Failed match. Both matchers need to explain. The second - // matcher doesn't give an explanation, so only the first matcher's - // explanation is printed. + // Failed match. The second matcher have no explanation (description is used). m = AnyOf(GreaterThan(10), Lt(0)); - EXPECT_EQ("which is 5 less than 10", Explain(m, 5)); + EXPECT_EQ("which is 5 less than 10, and isn't < 0", Explain(m, 5)); - // Failed match. Both matchers need to explain. + // Failed match. Both matchers have explanations. m = AnyOf(GreaterThan(10), GreaterThan(20)); EXPECT_EQ("which is 5 less than 10, and which is 15 less than 20", Explain(m, 5)); - // Failed match. All matchers need to explain. The second - // matcher doesn't given an explanation. + // Failed match. The middle matcher have no explanation. m = AnyOf(GreaterThan(10), Gt(20), GreaterThan(30)); - EXPECT_EQ("which is 5 less than 10, and which is 25 less than 30", - Explain(m, 5)); + EXPECT_EQ( + "which is 5 less than 10, and isn't > 20, and which is 25 less than 30", + Explain(m, 5)); - // Failed match. All matchers need to explain. + // Failed match. All three matchers have explanations. m = AnyOf(GreaterThan(10), GreaterThan(20), GreaterThan(30)); EXPECT_EQ( "which is 5 less than 10, and which is 15 less than 20, " "and which is 25 less than 30", Explain(m, 5)); - // Successful match. The first matcher, which succeeded, needs to - // explain. + // Successful match. The first macher succeeded and has explanation. m = AnyOf(GreaterThan(10), GreaterThan(20)); EXPECT_EQ("which is 5 more than 10", Explain(m, 15)); - // Successful match. The second matcher, which succeeded, needs to - // explain. Since it doesn't given an explanation, nothing is - // printed. - m = AnyOf(GreaterThan(10), Lt(30)); - EXPECT_EQ("", Explain(m, 0)); - - // Successful match. The second matcher, which succeeded, needs to - // explain. + // Successful match. The second matcher succeeded and has explanation. m = AnyOf(GreaterThan(30), GreaterThan(20)); EXPECT_EQ("which is 5 more than 20", Explain(m, 25)); + + // Successful match. The first matcher succeeded and has no explanation. + m = AnyOf(Gt(10), Lt(20)); + EXPECT_EQ("which matches (is > 10)", Explain(m, 15)); + + // Successful match. The second matcher succeeded and has no explanation. + m = AnyOf(Gt(30), Gt(20)); + EXPECT_EQ("which matches (is > 20)", Explain(m, 25)); } // The following predicate function and predicate functor are for diff --git a/googlemock/test/gmock-matchers-containers_test.cc b/googlemock/test/gmock-matchers-containers_test.cc index 52b52d5d1f..751fb60ef0 100644 --- a/googlemock/test/gmock-matchers-containers_test.cc +++ b/googlemock/test/gmock-matchers-containers_test.cc @@ -1204,13 +1204,16 @@ TEST(SizeIsTest, ExplainsResult) { vector container; EXPECT_EQ("whose size 0 doesn't match", Explain(m1, container)); EXPECT_EQ("whose size 0 matches", Explain(m2, container)); - EXPECT_EQ("whose size 0 matches", Explain(m3, container)); + EXPECT_EQ("whose size 0 matches, which matches (is equal to 0)", + Explain(m3, container)); EXPECT_EQ("whose size 0 doesn't match", Explain(m4, container)); container.push_back(0); container.push_back(0); EXPECT_EQ("whose size 2 matches", Explain(m1, container)); EXPECT_EQ("whose size 2 doesn't match", Explain(m2, container)); - EXPECT_EQ("whose size 2 doesn't match", Explain(m3, container)); + EXPECT_EQ( + "whose size 2 doesn't match, isn't equal to 0, and isn't equal to 3", + Explain(m3, container)); EXPECT_EQ("whose size 2 matches", Explain(m4, container)); } @@ -1475,8 +1478,10 @@ TEST_P(BeginEndDistanceIsTestP, ExplainsResult) { Explain(m1, container)); EXPECT_EQ("whose distance between begin() and end() 0 matches", Explain(m2, container)); - EXPECT_EQ("whose distance between begin() and end() 0 matches", - Explain(m3, container)); + EXPECT_EQ( + "whose distance between begin() and end() 0 matches, which matches (is " + "equal to 0)", + Explain(m3, container)); EXPECT_EQ( "whose distance between begin() and end() 0 doesn't match, which is 1 " "less than 1", @@ -1487,8 +1492,10 @@ TEST_P(BeginEndDistanceIsTestP, ExplainsResult) { Explain(m1, container)); EXPECT_EQ("whose distance between begin() and end() 2 doesn't match", Explain(m2, container)); - EXPECT_EQ("whose distance between begin() and end() 2 doesn't match", - Explain(m3, container)); + EXPECT_EQ( + "whose distance between begin() and end() 2 doesn't match, isn't equal " + "to 0, and isn't equal to 3", + Explain(m3, container)); EXPECT_EQ( "whose distance between begin() and end() 2 matches, which is 1 more " "than 1", diff --git a/googlemock/test/gmock-matchers-misc_test.cc b/googlemock/test/gmock-matchers-misc_test.cc index 2bb4cdbe15..9ac245868b 100644 --- a/googlemock/test/gmock-matchers-misc_test.cc +++ b/googlemock/test/gmock-matchers-misc_test.cc @@ -1576,10 +1576,10 @@ TEST_P(AnyOfArrayTestP, ExplainsMatchResultCorrectly) { const Matcher m1 = AnyOfArray(v1); const Matcher m2 = AnyOfArray(v2); EXPECT_EQ("", Explain(m0, 0)); - EXPECT_EQ("", Explain(m1, 1)); - EXPECT_EQ("", Explain(m1, 2)); - EXPECT_EQ("", Explain(m2, 3)); - EXPECT_EQ("", Explain(m2, 4)); + EXPECT_EQ("which matches (is equal to 1)", Explain(m1, 1)); + EXPECT_EQ("isn't equal to 1", Explain(m1, 2)); + EXPECT_EQ("which matches (is equal to 3)", Explain(m2, 3)); + EXPECT_EQ("isn't equal to 2, and isn't equal to 3", Explain(m2, 4)); EXPECT_EQ("()", Describe(m0)); EXPECT_EQ("(is equal to 1)", Describe(m1)); EXPECT_EQ("(is equal to 2) or (is equal to 3)", Describe(m2));