Googletest export
Implement 'Contains(e).Times(n)' matcher modifier which allows to test for arbitrary occurrences including absence with Times(0). PiperOrigin-RevId: 382210276
This commit is contained in:
@@ -2581,7 +2581,7 @@ class PointwiseMatcher {
|
||||
StringMatchResultListener inner_listener;
|
||||
// Create InnerMatcherArg as a temporarily object to avoid it outlives
|
||||
// *left and *right. Dereference or the conversion to `const T&` may
|
||||
// return temp objects, e.g for vector<bool>.
|
||||
// return temp objects, e.g. for vector<bool>.
|
||||
if (!mono_tuple_matcher_.MatchAndExplain(
|
||||
InnerMatcherArg(ImplicitCast_<const LhsValue&>(*left),
|
||||
ImplicitCast_<const RhsValue&>(*right)),
|
||||
@@ -2653,6 +2653,54 @@ class QuantifierMatcherImpl : public MatcherInterface<Container> {
|
||||
return all_elements_should_match;
|
||||
}
|
||||
|
||||
bool MatchAndExplainImpl(const Matcher<size_t>& count_matcher,
|
||||
Container container,
|
||||
MatchResultListener* listener) const {
|
||||
StlContainerReference stl_container = View::ConstReference(container);
|
||||
size_t i = 0;
|
||||
std::vector<size_t> match_elements;
|
||||
for (auto it = stl_container.begin(); it != stl_container.end();
|
||||
++it, ++i) {
|
||||
StringMatchResultListener inner_listener;
|
||||
const bool matches = inner_matcher_.MatchAndExplain(*it, &inner_listener);
|
||||
if (matches) {
|
||||
match_elements.push_back(i);
|
||||
}
|
||||
}
|
||||
if (listener->IsInterested()) {
|
||||
if (match_elements.empty()) {
|
||||
*listener << "has no element that matches";
|
||||
} else if (match_elements.size() == 1) {
|
||||
*listener << "whose element #" << match_elements[0] << " matches";
|
||||
} else {
|
||||
*listener << "whose elements (";
|
||||
std::string sep = "";
|
||||
for (size_t e : match_elements) {
|
||||
*listener << sep << e;
|
||||
sep = ", ";
|
||||
}
|
||||
*listener << ") match";
|
||||
}
|
||||
}
|
||||
StringMatchResultListener count_listener;
|
||||
if (count_matcher.MatchAndExplain(match_elements.size(), &count_listener)) {
|
||||
*listener << " and whose match quantity of " << match_elements.size()
|
||||
<< " matches";
|
||||
PrintIfNotEmpty(count_listener.str(), listener->stream());
|
||||
return true;
|
||||
} else {
|
||||
if (match_elements.empty()) {
|
||||
*listener << " and";
|
||||
} else {
|
||||
*listener << " but";
|
||||
}
|
||||
*listener << " whose match quantity of " << match_elements.size()
|
||||
<< " does not match";
|
||||
PrintIfNotEmpty(count_listener.str(), listener->stream());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
const Matcher<const Element&> inner_matcher_;
|
||||
};
|
||||
@@ -2709,6 +2757,58 @@ class EachMatcherImpl : public QuantifierMatcherImpl<Container> {
|
||||
}
|
||||
};
|
||||
|
||||
// Implements Contains(element_matcher).Times(n) for the given argument type
|
||||
// Container.
|
||||
template <typename Container>
|
||||
class ContainsTimesMatcherImpl : public QuantifierMatcherImpl<Container> {
|
||||
public:
|
||||
template <typename InnerMatcher>
|
||||
explicit ContainsTimesMatcherImpl(InnerMatcher inner_matcher,
|
||||
Matcher<size_t> count_matcher)
|
||||
: QuantifierMatcherImpl<Container>(inner_matcher),
|
||||
count_matcher_(std::move(count_matcher)) {}
|
||||
|
||||
void DescribeTo(::std::ostream* os) const override {
|
||||
*os << "quantity of elements that match ";
|
||||
this->inner_matcher_.DescribeTo(os);
|
||||
*os << " ";
|
||||
count_matcher_.DescribeTo(os);
|
||||
}
|
||||
|
||||
void DescribeNegationTo(::std::ostream* os) const override {
|
||||
*os << "quantity of elements that match ";
|
||||
this->inner_matcher_.DescribeTo(os);
|
||||
*os << " ";
|
||||
count_matcher_.DescribeNegationTo(os);
|
||||
}
|
||||
|
||||
bool MatchAndExplain(Container container,
|
||||
MatchResultListener* listener) const override {
|
||||
return this->MatchAndExplainImpl(count_matcher_, container, listener);
|
||||
}
|
||||
|
||||
private:
|
||||
const Matcher<size_t> count_matcher_;
|
||||
};
|
||||
|
||||
// Implements polymorphic Contains(element_matcher).Times(n).
|
||||
template <typename M>
|
||||
class ContainsTimesMatcher {
|
||||
public:
|
||||
explicit ContainsTimesMatcher(M m, Matcher<size_t> count_matcher)
|
||||
: inner_matcher_(m), count_matcher_(std::move(count_matcher)) {}
|
||||
|
||||
template <typename Container>
|
||||
operator Matcher<Container>() const { // NOLINT
|
||||
return Matcher<Container>(new ContainsTimesMatcherImpl<const Container&>(
|
||||
inner_matcher_, count_matcher_));
|
||||
}
|
||||
|
||||
private:
|
||||
const M inner_matcher_;
|
||||
const Matcher<size_t> count_matcher_;
|
||||
};
|
||||
|
||||
// Implements polymorphic Contains(element_matcher).
|
||||
template <typename M>
|
||||
class ContainsMatcher {
|
||||
@@ -2716,11 +2816,15 @@ class ContainsMatcher {
|
||||
explicit ContainsMatcher(M m) : inner_matcher_(m) {}
|
||||
|
||||
template <typename Container>
|
||||
operator Matcher<Container>() const {
|
||||
operator Matcher<Container>() const { // NOLINT
|
||||
return Matcher<Container>(
|
||||
new ContainsMatcherImpl<const Container&>(inner_matcher_));
|
||||
}
|
||||
|
||||
ContainsTimesMatcher<M> Times(Matcher<size_t> count_matcher) const {
|
||||
return ContainsTimesMatcher<M>(inner_matcher_, std::move(count_matcher));
|
||||
}
|
||||
|
||||
private:
|
||||
const M inner_matcher_;
|
||||
};
|
||||
@@ -2732,7 +2836,7 @@ class EachMatcher {
|
||||
explicit EachMatcher(M m) : inner_matcher_(m) {}
|
||||
|
||||
template <typename Container>
|
||||
operator Matcher<Container>() const {
|
||||
operator Matcher<Container>() const { // NOLINT
|
||||
return Matcher<Container>(
|
||||
new EachMatcherImpl<const Container&>(inner_matcher_));
|
||||
}
|
||||
@@ -4615,7 +4719,6 @@ UnorderedPointwise(const Tuple2Matcher& tuple2_matcher,
|
||||
return UnorderedPointwise(tuple2_matcher, std::vector<T>(rhs));
|
||||
}
|
||||
|
||||
|
||||
// Matches an STL-style container or a native array that contains at
|
||||
// least one element matching the given value or matcher.
|
||||
//
|
||||
@@ -4625,7 +4728,7 @@ UnorderedPointwise(const Tuple2Matcher& tuple2_matcher,
|
||||
// page_ids.insert(1);
|
||||
// EXPECT_THAT(page_ids, Contains(1));
|
||||
// EXPECT_THAT(page_ids, Contains(Gt(2)));
|
||||
// EXPECT_THAT(page_ids, Not(Contains(4)));
|
||||
// EXPECT_THAT(page_ids, Not(Contains(4))); // See below for Times(0)
|
||||
//
|
||||
// ::std::map<int, size_t> page_lengths;
|
||||
// page_lengths[1] = 100;
|
||||
@@ -4634,6 +4737,19 @@ UnorderedPointwise(const Tuple2Matcher& tuple2_matcher,
|
||||
//
|
||||
// const char* user_ids[] = { "joe", "mike", "tom" };
|
||||
// EXPECT_THAT(user_ids, Contains(Eq(::std::string("tom"))));
|
||||
//
|
||||
// The matcher supports a modifier `Times` that allows to check for arbitrary
|
||||
// occurrences including testing for absence with Times(0).
|
||||
//
|
||||
// Examples:
|
||||
// ::std::vector<int> ids;
|
||||
// ids.insert(1);
|
||||
// ids.insert(1);
|
||||
// ids.insert(3);
|
||||
// EXPECT_THAT(ids, Contains(1).Times(2)); // 1 occurs 2 times
|
||||
// EXPECT_THAT(ids, Contains(2).Times(0)); // 2 is not present
|
||||
// EXPECT_THAT(ids, Contains(3).Times(Ge(1))); // 3 occurs at least once
|
||||
|
||||
template <typename M>
|
||||
inline internal::ContainsMatcher<M> Contains(M matcher) {
|
||||
return internal::ContainsMatcher<M>(matcher);
|
||||
@@ -4760,7 +4876,7 @@ inline internal::UnorderedElementsAreArrayMatcher<T> IsSubsetOf(
|
||||
// Matches an STL-style container or a native array that contains only
|
||||
// elements matching the given value or matcher.
|
||||
//
|
||||
// Each(m) is semantically equivalent to Not(Contains(Not(m))). Only
|
||||
// Each(m) is semantically equivalent to `Not(Contains(Not(m)))`. Only
|
||||
// the messages are different.
|
||||
//
|
||||
// Examples:
|
||||
|
||||
Reference in New Issue
Block a user