AllOf, AnyOf, Optional: Avoid generating unnecessary match explanations

Previously, those matchers always invoked the child matchers with an IsInterested MatchResultListener, resulting in unnecessary work formatting match results that would be discarded.

PiperOrigin-RevId: 750704295
Change-Id: I1639a3a15d269459f26b3aebc3a6cbdced6896a3
This commit is contained in:
Abseil Team
2025-04-23 13:29:56 -07:00
committed by Copybara-Service
parent 155b337c93
commit cd430b47a5
2 changed files with 91 additions and 0 deletions
@@ -33,6 +33,7 @@
#include <functional>
#include <memory>
#include <optional>
#include <string>
#include <tuple>
#include <vector>
@@ -2396,6 +2397,74 @@ TEST(ExplainMatchResultTest, AllOf_True_True_2) {
EXPECT_EQ("is >= 2, and is <= 3", Explain(m, 2));
}
// A matcher that records whether the listener was interested.
template <typename T>
class CountingMatcher : public MatcherInterface<T> {
public:
explicit CountingMatcher(const Matcher<T>& base_matcher,
std::vector<bool>* listener_interested)
: base_matcher_(base_matcher),
listener_interested_(listener_interested) {}
bool MatchAndExplain(T x, MatchResultListener* listener) const override {
listener_interested_->push_back(listener->IsInterested());
return base_matcher_.MatchAndExplain(x, listener);
}
void DescribeTo(ostream* os) const override { base_matcher_.DescribeTo(os); }
private:
Matcher<T> base_matcher_;
std::vector<bool>* listener_interested_;
};
TEST(AllOfTest, DoesNotFormatChildMatchersWhenNotInterested) {
std::vector<bool> listener_interested;
Matcher<int> matcher =
MakeMatcher(new CountingMatcher<int>(Eq(1), &listener_interested));
EXPECT_TRUE(matcher.Matches(1));
EXPECT_THAT(listener_interested, ElementsAre(false));
listener_interested.clear();
Matcher<int> all_of_matcher = AllOf(matcher, matcher);
EXPECT_TRUE(all_of_matcher.Matches(1));
EXPECT_THAT(listener_interested, ElementsAre(false, false));
listener_interested.clear();
EXPECT_FALSE(all_of_matcher.Matches(0));
EXPECT_THAT(listener_interested, ElementsAre(false));
}
TEST(AnyOfTest, DoesNotFormatChildMatchersWhenNotInterested) {
std::vector<bool> listener_interested;
Matcher<int> matcher =
MakeMatcher(new CountingMatcher<int>(Eq(1), &listener_interested));
EXPECT_TRUE(matcher.Matches(1));
EXPECT_THAT(listener_interested, ElementsAre(false));
listener_interested.clear();
Matcher<int> any_of_matcher = AnyOf(matcher, matcher);
EXPECT_TRUE(any_of_matcher.Matches(1));
EXPECT_THAT(listener_interested, ElementsAre(false));
listener_interested.clear();
EXPECT_FALSE(any_of_matcher.Matches(0));
EXPECT_THAT(listener_interested, ElementsAre(false, false));
}
TEST(OptionalTest, DoesNotFormatChildMatcherWhenNotInterested) {
std::vector<bool> listener_interested;
Matcher<int> matcher =
MakeMatcher(new CountingMatcher<int>(Eq(1), &listener_interested));
EXPECT_TRUE(matcher.Matches(1));
EXPECT_THAT(listener_interested, ElementsAre(false));
listener_interested.clear();
Matcher<std::optional<int>> optional_matcher = Optional(matcher);
EXPECT_FALSE(optional_matcher.Matches(std::nullopt));
EXPECT_THAT(listener_interested, ElementsAre());
EXPECT_TRUE(optional_matcher.Matches(1));
EXPECT_THAT(listener_interested, ElementsAre(false));
listener_interested.clear();
EXPECT_FALSE(matcher.Matches(0));
EXPECT_THAT(listener_interested, ElementsAre(false));
}
INSTANTIATE_GTEST_MATCHER_TEST_P(ExplainmatcherResultTest);
TEST_P(ExplainmatcherResultTestP, MonomorphicMatcher) {