mirror of
https://git.mirrors.martin98.com/https://github.com/google/googletest.git
synced 2025-06-04 11:25:34 +08:00
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:
parent
155b337c93
commit
cd430b47a5
@ -1312,6 +1312,15 @@ class AllOfMatcherImpl : public MatcherInterface<const T&> {
|
||||
|
||||
bool MatchAndExplain(const T& x,
|
||||
MatchResultListener* listener) const override {
|
||||
if (!listener->IsInterested()) {
|
||||
// Fast path to avoid unnecessary formatting.
|
||||
for (const Matcher<T>& matcher : matchers_) {
|
||||
if (!matcher.Matches(x)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// This method uses matcher's explanation when explaining the result.
|
||||
// However, if matcher doesn't provide one, this method uses matcher's
|
||||
// description.
|
||||
@ -1431,6 +1440,15 @@ class AnyOfMatcherImpl : public MatcherInterface<const T&> {
|
||||
|
||||
bool MatchAndExplain(const T& x,
|
||||
MatchResultListener* listener) const override {
|
||||
if (!listener->IsInterested()) {
|
||||
// Fast path to avoid unnecessary formatting of match explanations.
|
||||
for (const Matcher<T>& matcher : matchers_) {
|
||||
if (matcher.Matches(x)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
// This method uses matcher's explanation when explaining the result.
|
||||
// However, if matcher doesn't provide one, this method uses matcher's
|
||||
// description.
|
||||
@ -4118,6 +4136,10 @@ class OptionalMatcher {
|
||||
return false;
|
||||
}
|
||||
const ValueType& value = *optional;
|
||||
if (!listener->IsInterested()) {
|
||||
// Fast path to avoid unnecessary generation of match explanation.
|
||||
return value_matcher_.Matches(value);
|
||||
}
|
||||
StringMatchResultListener value_listener;
|
||||
const bool match = value_matcher_.MatchAndExplain(value, &value_listener);
|
||||
*listener << "whose value " << PrintToString(value)
|
||||
|
@ -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) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user