Skip to content

Commit 17d335d

Browse files
Quincunx271copybara-github
authored andcommitted
Remove short-circuiting from AllOf, for better failure messages
For `EXPECT_THAT` matcher usage, showing only the first failure meant that users would sometimes have to make a fix and run the test again only to notice that there's another failure. It's better to show more failures so that the user can fix several issues in one go. In practice, very little code actually wants the short circuiting here, only a handful of cases with custom matchers used like `AllOf(BoundsCheck(), UncheckedAccess())`. These cases are fixable by refactoring `UncheckedAccess()` to instead also apply a bounds check to fail the matcher rather than crash. Notably, this change doesn't affect `AnyOf`, so another workaround is to change `AllOf(m1, m2, ...)` into `Not(AnyOf(Not(m1), Not(m2), ...))`. PiperOrigin-RevId: 826316273 Change-Id: Ie8186f75c10443d8da35b5d07b6a8cd9ae85b451
1 parent 4fe3307 commit 17d335d

File tree

3 files changed

+17
-11
lines changed

3 files changed

+17
-11
lines changed

googlemock/include/gmock/gmock-matchers.h

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1329,17 +1329,23 @@ class AllOfMatcherImpl : public MatcherInterface<const T&> {
13291329
// However, if matcher doesn't provide one, this method uses matcher's
13301330
// description.
13311331
std::string all_match_result;
1332+
bool success = true;
13321333
for (const Matcher<T>& matcher : matchers_) {
13331334
StringMatchResultListener slistener;
13341335
// Return explanation for first failed matcher.
13351336
if (!matcher.MatchAndExplain(x, &slistener)) {
13361337
const std::string explanation = slistener.str();
1338+
if (!success) {
1339+
// Already had a failure.
1340+
*listener << ", and ";
1341+
}
13371342
if (!explanation.empty()) {
13381343
*listener << explanation;
13391344
} else {
13401345
*listener << "which doesn't match (" << Describe(matcher) << ")";
13411346
}
1342-
return false;
1347+
success = false;
1348+
continue;
13431349
}
13441350
// Keep track of explanations in case all matchers succeed.
13451351
std::string explanation = slistener.str();
@@ -1356,8 +1362,10 @@ class AllOfMatcherImpl : public MatcherInterface<const T&> {
13561362
}
13571363
}
13581364

1359-
*listener << all_match_result;
1360-
return true;
1365+
if (success) {
1366+
*listener << all_match_result;
1367+
}
1368+
return success;
13611369
}
13621370

13631371
private:

googlemock/test/gmock-matchers-arithmetic_test.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -770,7 +770,8 @@ TEST_P(AllOfTestP, ExplainsResult) {
770770
// Failed match. The first matcher, which failed, needs to
771771
// explain.
772772
m = AllOf(GreaterThan(10), GreaterThan(20));
773-
EXPECT_EQ("which is 5 less than 10", Explain(m, 5));
773+
EXPECT_EQ("which is 5 less than 10, and which is 15 less than 20",
774+
Explain(m, 5));
774775

775776
// Failed match. The second matcher, which failed, needs to
776777
// explain. Since it doesn't given an explanation, the matcher text is

googlemock/test/gmock-matchers-comparisons_test.cc

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2389,22 +2389,19 @@ PolymorphicMatcher<DivisibleByImpl> DivisibleBy(int n) {
23892389
return MakePolymorphicMatcher(DivisibleByImpl(n));
23902390
}
23912391

2392-
// Tests that when AllOf() fails, only the first failing matcher is
2393-
// asked to explain why.
2392+
// Tests that when AllOf() fails, all failing matchers are asked to explain why.
23942393
TEST(ExplainMatchResultTest, AllOf_False_False) {
23952394
const Matcher<int> m = AllOf(DivisibleBy(4), DivisibleBy(3));
2396-
EXPECT_EQ("which is 1 modulo 4", Explain(m, 5));
2395+
EXPECT_EQ("which is 1 modulo 4, and which is 2 modulo 3", Explain(m, 5));
23972396
}
23982397

2399-
// Tests that when AllOf() fails, only the first failing matcher is
2400-
// asked to explain why.
2398+
// Tests that when AllOf() fails, all failing matchers are asked to explain why.
24012399
TEST(ExplainMatchResultTest, AllOf_False_True) {
24022400
const Matcher<int> m = AllOf(DivisibleBy(4), DivisibleBy(3));
24032401
EXPECT_EQ("which is 2 modulo 4", Explain(m, 6));
24042402
}
24052403

2406-
// Tests that when AllOf() fails, only the first failing matcher is
2407-
// asked to explain why.
2404+
// Tests that when AllOf() fails, all failing matchers are asked to explain why.
24082405
TEST(ExplainMatchResultTest, AllOf_True_False) {
24092406
const Matcher<int> m = AllOf(Ge(1), DivisibleBy(3));
24102407
EXPECT_EQ("which is 2 modulo 3", Explain(m, 5));

0 commit comments

Comments
 (0)