Googletest export
Add AllOfArray matcher that verifies a value matches all member of some array/container/list/set/..., e.g: EXPECT_THAT(1, AnyOfArray({1, 2, 3})) In the simplest form this is identical to AnyOf(1, 2, 3). But unlike that one it works on containers. Add AnyOfArray matcher that verifies a value matches any member of some array/container/list/set/... PiperOrigin-RevId: 230403653
This commit is contained in:
parent
569fba4d74
commit
fdc59ffd05
@ -1175,6 +1175,37 @@ class AnyOfMatcherImpl : public MatcherInterface<const T&> {
|
|||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
using AnyOfMatcher = VariadicMatcher<AnyOfMatcherImpl, Args...>;
|
using AnyOfMatcher = VariadicMatcher<AnyOfMatcherImpl, Args...>;
|
||||||
|
|
||||||
|
// Wrapper for implementation of Any/AllOfArray().
|
||||||
|
template <template <class> class MatcherImpl, typename T>
|
||||||
|
class SomeOfArrayMatcher {
|
||||||
|
public:
|
||||||
|
// Constructs the matcher from a sequence of element values or
|
||||||
|
// element matchers.
|
||||||
|
template <typename Iter>
|
||||||
|
SomeOfArrayMatcher(Iter first, Iter last) : matchers_(first, last) {}
|
||||||
|
|
||||||
|
template <typename U>
|
||||||
|
operator Matcher<U>() const { // NOLINT
|
||||||
|
using RawU = typename std::decay<U>::type;
|
||||||
|
std::vector<Matcher<RawU>> matchers;
|
||||||
|
for (const auto& matcher : matchers_) {
|
||||||
|
matchers.push_back(MatcherCast<RawU>(matcher));
|
||||||
|
}
|
||||||
|
return Matcher<U>(new MatcherImpl<RawU>(std::move(matchers)));
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const ::std::vector<T> matchers_;
|
||||||
|
|
||||||
|
GTEST_DISALLOW_ASSIGN_(SomeOfArrayMatcher);
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
using AllOfArrayMatcher = SomeOfArrayMatcher<AllOfMatcherImpl, T>;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
using AnyOfArrayMatcher = SomeOfArrayMatcher<AnyOfMatcherImpl, T>;
|
||||||
|
|
||||||
// Used for implementing Truly(pred), which turns a predicate into a
|
// Used for implementing Truly(pred), which turns a predicate into a
|
||||||
// matcher.
|
// matcher.
|
||||||
template <typename Predicate>
|
template <typename Predicate>
|
||||||
@ -4376,6 +4407,88 @@ internal::AnyOfMatcher<typename std::decay<const Args&>::type...> AnyOf(
|
|||||||
matchers...);
|
matchers...);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AnyOfArray(array)
|
||||||
|
// AnyOfArray(pointer, count)
|
||||||
|
// AnyOfArray(container)
|
||||||
|
// AnyOfArray({ e1, e2, ..., en })
|
||||||
|
// AnyOfArray(iterator_first, iterator_last)
|
||||||
|
//
|
||||||
|
// AnyOfArray() verifies whether a given value matches any member of a
|
||||||
|
// collection of matchers.
|
||||||
|
//
|
||||||
|
// AllOfArray(array)
|
||||||
|
// AllOfArray(pointer, count)
|
||||||
|
// AllOfArray(container)
|
||||||
|
// AllOfArray({ e1, e2, ..., en })
|
||||||
|
// AllOfArray(iterator_first, iterator_last)
|
||||||
|
//
|
||||||
|
// AllOfArray() verifies whether a given value matches all members of a
|
||||||
|
// collection of matchers.
|
||||||
|
//
|
||||||
|
// The matchers can be specified as an array, a pointer and count, a container,
|
||||||
|
// an initializer list, or an STL iterator range. In each of these cases, the
|
||||||
|
// underlying matchers can be either values or matchers.
|
||||||
|
|
||||||
|
template <typename Iter>
|
||||||
|
inline internal::AnyOfArrayMatcher<
|
||||||
|
typename ::std::iterator_traits<Iter>::value_type>
|
||||||
|
AnyOfArray(Iter first, Iter last) {
|
||||||
|
return internal::AnyOfArrayMatcher<
|
||||||
|
typename ::std::iterator_traits<Iter>::value_type>(first, last);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Iter>
|
||||||
|
inline internal::AllOfArrayMatcher<
|
||||||
|
typename ::std::iterator_traits<Iter>::value_type>
|
||||||
|
AllOfArray(Iter first, Iter last) {
|
||||||
|
return internal::AllOfArrayMatcher<
|
||||||
|
typename ::std::iterator_traits<Iter>::value_type>(first, last);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
inline internal::AnyOfArrayMatcher<T> AnyOfArray(const T* ptr, size_t count) {
|
||||||
|
return AnyOfArray(ptr, ptr + count);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
inline internal::AllOfArrayMatcher<T> AllOfArray(const T* ptr, size_t count) {
|
||||||
|
return AllOfArray(ptr, ptr + count);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, size_t N>
|
||||||
|
inline internal::AnyOfArrayMatcher<T> AnyOfArray(const T (&array)[N]) {
|
||||||
|
return AnyOfArray(array, N);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, size_t N>
|
||||||
|
inline internal::AllOfArrayMatcher<T> AllOfArray(const T (&array)[N]) {
|
||||||
|
return AllOfArray(array, N);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Container>
|
||||||
|
inline internal::AnyOfArrayMatcher<typename Container::value_type> AnyOfArray(
|
||||||
|
const Container& container) {
|
||||||
|
return AnyOfArray(container.begin(), container.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Container>
|
||||||
|
inline internal::AllOfArrayMatcher<typename Container::value_type> AllOfArray(
|
||||||
|
const Container& container) {
|
||||||
|
return AllOfArray(container.begin(), container.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
inline internal::AnyOfArrayMatcher<T> AnyOfArray(
|
||||||
|
::std::initializer_list<T> xs) {
|
||||||
|
return AnyOfArray(xs.begin(), xs.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
inline internal::AllOfArrayMatcher<T> AllOfArray(
|
||||||
|
::std::initializer_list<T> xs) {
|
||||||
|
return AllOfArray(xs.begin(), xs.end());
|
||||||
|
}
|
||||||
|
|
||||||
// Args<N1, N2, ..., Nk>(a_matcher) matches a tuple if the selected
|
// Args<N1, N2, ..., Nk>(a_matcher) matches a tuple if the selected
|
||||||
// fields of it matches a_matcher. C++ doesn't support default
|
// fields of it matches a_matcher. C++ doesn't support default
|
||||||
// arguments for function templates, so we have to overload it.
|
// arguments for function templates, so we have to overload it.
|
||||||
|
@ -64,7 +64,9 @@ using std::stringstream;
|
|||||||
using std::vector;
|
using std::vector;
|
||||||
using testing::_;
|
using testing::_;
|
||||||
using testing::AllOf;
|
using testing::AllOf;
|
||||||
|
using testing::AllOfArray;
|
||||||
using testing::AnyOf;
|
using testing::AnyOf;
|
||||||
|
using testing::AnyOfArray;
|
||||||
using testing::Args;
|
using testing::Args;
|
||||||
using testing::Contains;
|
using testing::Contains;
|
||||||
using testing::ElementsAre;
|
using testing::ElementsAre;
|
||||||
@ -1094,6 +1096,146 @@ TEST(ContainsTest, WorksForTwoDimensionalNativeArray) {
|
|||||||
EXPECT_THAT(a, Contains(Not(Contains(5))));
|
EXPECT_THAT(a, Contains(Not(Contains(5))));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(AllOfArrayTest, BasicForms) {
|
||||||
|
// Iterator
|
||||||
|
std::vector<int> v0{};
|
||||||
|
std::vector<int> v1{1};
|
||||||
|
std::vector<int> v2{2, 3};
|
||||||
|
std::vector<int> v3{4, 4, 4};
|
||||||
|
EXPECT_THAT(0, AllOfArray(v0.begin(), v0.end()));
|
||||||
|
EXPECT_THAT(1, AllOfArray(v1.begin(), v1.end()));
|
||||||
|
EXPECT_THAT(2, Not(AllOfArray(v1.begin(), v1.end())));
|
||||||
|
EXPECT_THAT(3, Not(AllOfArray(v2.begin(), v2.end())));
|
||||||
|
EXPECT_THAT(4, AllOfArray(v3.begin(), v3.end()));
|
||||||
|
// Pointer + size
|
||||||
|
int ar[6] = {1, 2, 3, 4, 4, 4};
|
||||||
|
EXPECT_THAT(0, AllOfArray(ar, 0));
|
||||||
|
EXPECT_THAT(1, AllOfArray(ar, 1));
|
||||||
|
EXPECT_THAT(2, Not(AllOfArray(ar, 1)));
|
||||||
|
EXPECT_THAT(3, Not(AllOfArray(ar + 1, 3)));
|
||||||
|
EXPECT_THAT(4, AllOfArray(ar + 3, 3));
|
||||||
|
// Array
|
||||||
|
// int ar0[0]; Not usable
|
||||||
|
int ar1[1] = {1};
|
||||||
|
int ar2[2] = {2, 3};
|
||||||
|
int ar3[3] = {4, 4, 4};
|
||||||
|
// EXPECT_THAT(0, Not(AllOfArray(ar0))); // Cannot work
|
||||||
|
EXPECT_THAT(1, AllOfArray(ar1));
|
||||||
|
EXPECT_THAT(2, Not(AllOfArray(ar1)));
|
||||||
|
EXPECT_THAT(3, Not(AllOfArray(ar2)));
|
||||||
|
EXPECT_THAT(4, AllOfArray(ar3));
|
||||||
|
// Container
|
||||||
|
EXPECT_THAT(0, AllOfArray(v0));
|
||||||
|
EXPECT_THAT(1, AllOfArray(v1));
|
||||||
|
EXPECT_THAT(2, Not(AllOfArray(v1)));
|
||||||
|
EXPECT_THAT(3, Not(AllOfArray(v2)));
|
||||||
|
EXPECT_THAT(4, AllOfArray(v3));
|
||||||
|
// Initializer
|
||||||
|
EXPECT_THAT(0, AllOfArray<int>({})); // Requires template arg.
|
||||||
|
EXPECT_THAT(1, AllOfArray({1}));
|
||||||
|
EXPECT_THAT(2, Not(AllOfArray({1})));
|
||||||
|
EXPECT_THAT(3, Not(AllOfArray({2, 3})));
|
||||||
|
EXPECT_THAT(4, AllOfArray({4, 4, 4}));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(AllOfArrayTest, Matchers) {
|
||||||
|
// vector
|
||||||
|
std::vector<Matcher<int>> matchers{Ge(1), Lt(2)};
|
||||||
|
EXPECT_THAT(0, Not(AllOfArray(matchers)));
|
||||||
|
EXPECT_THAT(1, AllOfArray(matchers));
|
||||||
|
EXPECT_THAT(2, Not(AllOfArray(matchers)));
|
||||||
|
// initializer_list
|
||||||
|
EXPECT_THAT(0, Not(AllOfArray({Ge(0), Ge(1)})));
|
||||||
|
EXPECT_THAT(1, AllOfArray({Ge(0), Ge(1)}));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(AnyOfArrayTest, BasicForms) {
|
||||||
|
// Iterator
|
||||||
|
std::vector<int> v0{};
|
||||||
|
std::vector<int> v1{1};
|
||||||
|
std::vector<int> v2{2, 3};
|
||||||
|
EXPECT_THAT(0, Not(AnyOfArray(v0.begin(), v0.end())));
|
||||||
|
EXPECT_THAT(1, AnyOfArray(v1.begin(), v1.end()));
|
||||||
|
EXPECT_THAT(2, Not(AnyOfArray(v1.begin(), v1.end())));
|
||||||
|
EXPECT_THAT(3, AnyOfArray(v2.begin(), v2.end()));
|
||||||
|
EXPECT_THAT(4, Not(AnyOfArray(v2.begin(), v2.end())));
|
||||||
|
// Pointer + size
|
||||||
|
int ar[3] = {1, 2, 3};
|
||||||
|
EXPECT_THAT(0, Not(AnyOfArray(ar, 0)));
|
||||||
|
EXPECT_THAT(1, AnyOfArray(ar, 1));
|
||||||
|
EXPECT_THAT(2, Not(AnyOfArray(ar, 1)));
|
||||||
|
EXPECT_THAT(3, AnyOfArray(ar + 1, 3));
|
||||||
|
EXPECT_THAT(4, Not(AnyOfArray(ar + 1, 3)));
|
||||||
|
// Array
|
||||||
|
// int ar0[0]; Not usable
|
||||||
|
int ar1[1] = {1};
|
||||||
|
int ar2[2] = {2, 3};
|
||||||
|
// EXPECT_THAT(0, Not(AnyOfArray(ar0))); // Cannot work
|
||||||
|
EXPECT_THAT(1, AnyOfArray(ar1));
|
||||||
|
EXPECT_THAT(2, Not(AnyOfArray(ar1)));
|
||||||
|
EXPECT_THAT(3, AnyOfArray(ar2));
|
||||||
|
EXPECT_THAT(4, Not(AnyOfArray(ar2)));
|
||||||
|
// Container
|
||||||
|
EXPECT_THAT(0, Not(AnyOfArray(v0)));
|
||||||
|
EXPECT_THAT(1, AnyOfArray(v1));
|
||||||
|
EXPECT_THAT(2, Not(AnyOfArray(v1)));
|
||||||
|
EXPECT_THAT(3, AnyOfArray(v2));
|
||||||
|
EXPECT_THAT(4, Not(AnyOfArray(v2)));
|
||||||
|
// Initializer
|
||||||
|
EXPECT_THAT(0, Not(AnyOfArray<int>({}))); // Requires template arg.
|
||||||
|
EXPECT_THAT(1, AnyOfArray({1}));
|
||||||
|
EXPECT_THAT(2, Not(AnyOfArray({1})));
|
||||||
|
EXPECT_THAT(3, AnyOfArray({2, 3}));
|
||||||
|
EXPECT_THAT(4, Not(AnyOfArray({2, 3})));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(AnyOfArrayTest, Matchers) {
|
||||||
|
// We negate test AllOfArrayTest.Matchers.
|
||||||
|
// vector
|
||||||
|
std::vector<Matcher<int>> matchers{Lt(1), Ge(2)};
|
||||||
|
EXPECT_THAT(0, AnyOfArray(matchers));
|
||||||
|
EXPECT_THAT(1, Not(AnyOfArray(matchers)));
|
||||||
|
EXPECT_THAT(2, AnyOfArray(matchers));
|
||||||
|
// initializer_list
|
||||||
|
EXPECT_THAT(0, AnyOfArray({Lt(0), Lt(1)}));
|
||||||
|
EXPECT_THAT(1, Not(AllOfArray({Lt(0), Lt(1)})));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(AnyOfArrayTest, ExplainsMatchResultCorrectly) {
|
||||||
|
// AnyOfArray and AllOfArry use the same underlying template-template,
|
||||||
|
// thus it is sufficient to test one here.
|
||||||
|
const std::vector<int> v0{};
|
||||||
|
const std::vector<int> v1{1};
|
||||||
|
const std::vector<int> v2{2, 3};
|
||||||
|
const Matcher<int> m0 = AnyOfArray(v0);
|
||||||
|
const Matcher<int> m1 = AnyOfArray(v1);
|
||||||
|
const Matcher<int> 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("()", Describe(m0));
|
||||||
|
EXPECT_EQ("(is equal to 1)", Describe(m1));
|
||||||
|
EXPECT_EQ("(is equal to 2) or (is equal to 3)", Describe(m2));
|
||||||
|
EXPECT_EQ("()", DescribeNegation(m0));
|
||||||
|
EXPECT_EQ("(isn't equal to 1)", DescribeNegation(m1));
|
||||||
|
EXPECT_EQ("(isn't equal to 2) and (isn't equal to 3)", DescribeNegation(m2));
|
||||||
|
// Explain with matchers
|
||||||
|
const Matcher<int> g1 = AnyOfArray({GreaterThan(1)});
|
||||||
|
const Matcher<int> g2 = AnyOfArray({GreaterThan(1), GreaterThan(2)});
|
||||||
|
// Explains the first positiv match and all prior negative matches...
|
||||||
|
EXPECT_EQ("which is 1 less than 1", Explain(g1, 0));
|
||||||
|
EXPECT_EQ("which is the same as 1", Explain(g1, 1));
|
||||||
|
EXPECT_EQ("which is 1 more than 1", Explain(g1, 2));
|
||||||
|
EXPECT_EQ("which is 1 less than 1, and which is 2 less than 2",
|
||||||
|
Explain(g2, 0));
|
||||||
|
EXPECT_EQ("which is the same as 1, and which is 1 less than 2",
|
||||||
|
Explain(g2, 1));
|
||||||
|
EXPECT_EQ("which is 1 more than 1", // Only the first
|
||||||
|
Explain(g2, 2));
|
||||||
|
}
|
||||||
|
|
||||||
TEST(AllOfTest, HugeMatcher) {
|
TEST(AllOfTest, HugeMatcher) {
|
||||||
// Verify that using AllOf with many arguments doesn't cause
|
// Verify that using AllOf with many arguments doesn't cause
|
||||||
// the compiler to exceed template instantiation depth limit.
|
// the compiler to exceed template instantiation depth limit.
|
||||||
|
Loading…
Reference in New Issue
Block a user