Googletest export

Allow container matchers to accept move-only containers.

PiperOrigin-RevId: 225667441
This commit is contained in:
Abseil Team 2018-12-15 08:11:02 -05:00 committed by Mark Barolak
parent 096fb37a19
commit 1ec20f87e3
2 changed files with 121 additions and 16 deletions

View File

@ -1959,7 +1959,7 @@ class SizeIsMatcher {
template <typename Container> template <typename Container>
operator Matcher<Container>() const { operator Matcher<Container>() const {
return MakeMatcher(new Impl<Container>(size_matcher_)); return Matcher<Container>(new Impl<const Container&>(size_matcher_));
} }
template <typename Container> template <typename Container>
@ -2009,7 +2009,7 @@ class BeginEndDistanceIsMatcher {
template <typename Container> template <typename Container>
operator Matcher<Container>() const { operator Matcher<Container>() const {
return MakeMatcher(new Impl<Container>(distance_matcher_)); return Matcher<Container>(new Impl<const Container&>(distance_matcher_));
} }
template <typename Container> template <typename Container>
@ -2269,7 +2269,8 @@ class PointwiseMatcher {
!IsHashTable<GTEST_REMOVE_REFERENCE_AND_CONST_(LhsContainer)>::value, !IsHashTable<GTEST_REMOVE_REFERENCE_AND_CONST_(LhsContainer)>::value,
use_UnorderedPointwise_with_hash_tables); use_UnorderedPointwise_with_hash_tables);
return MakeMatcher(new Impl<LhsContainer>(tuple_matcher_, rhs_)); return Matcher<LhsContainer>(
new Impl<const LhsContainer&>(tuple_matcher_, rhs_));
} }
template <typename LhsContainer> template <typename LhsContainer>
@ -2471,7 +2472,8 @@ class ContainsMatcher {
template <typename Container> template <typename Container>
operator Matcher<Container>() const { operator Matcher<Container>() const {
return MakeMatcher(new ContainsMatcherImpl<Container>(inner_matcher_)); return Matcher<Container>(
new ContainsMatcherImpl<const Container&>(inner_matcher_));
} }
private: private:
@ -2488,7 +2490,8 @@ class EachMatcher {
template <typename Container> template <typename Container>
operator Matcher<Container>() const { operator Matcher<Container>() const {
return MakeMatcher(new EachMatcherImpl<Container>(inner_matcher_)); return Matcher<Container>(
new EachMatcherImpl<const Container&>(inner_matcher_));
} }
private: private:
@ -3086,8 +3089,10 @@ class UnorderedElementsAreMatcher {
matchers.reserve(::std::tuple_size<MatcherTuple>::value); matchers.reserve(::std::tuple_size<MatcherTuple>::value);
TransformTupleValues(CastAndAppendTransform<const Element&>(), matchers_, TransformTupleValues(CastAndAppendTransform<const Element&>(), matchers_,
::std::back_inserter(matchers)); ::std::back_inserter(matchers));
return MakeMatcher(new UnorderedElementsAreMatcherImpl<Container>( return Matcher<Container>(
UnorderedMatcherRequire::ExactMatch, matchers.begin(), matchers.end())); new UnorderedElementsAreMatcherImpl<const Container&>(
UnorderedMatcherRequire::ExactMatch, matchers.begin(),
matchers.end()));
} }
private: private:
@ -3116,8 +3121,8 @@ class ElementsAreMatcher {
matchers.reserve(::std::tuple_size<MatcherTuple>::value); matchers.reserve(::std::tuple_size<MatcherTuple>::value);
TransformTupleValues(CastAndAppendTransform<const Element&>(), matchers_, TransformTupleValues(CastAndAppendTransform<const Element&>(), matchers_,
::std::back_inserter(matchers)); ::std::back_inserter(matchers));
return MakeMatcher(new ElementsAreMatcherImpl<Container>( return Matcher<Container>(new ElementsAreMatcherImpl<const Container&>(
matchers.begin(), matchers.end())); matchers.begin(), matchers.end()));
} }
private: private:
@ -3136,8 +3141,9 @@ class UnorderedElementsAreArrayMatcher {
template <typename Container> template <typename Container>
operator Matcher<Container>() const { operator Matcher<Container>() const {
return MakeMatcher(new UnorderedElementsAreMatcherImpl<Container>( return Matcher<Container>(
match_flags_, matchers_.begin(), matchers_.end())); new UnorderedElementsAreMatcherImpl<const Container&>(
match_flags_, matchers_.begin(), matchers_.end()));
} }
private: private:
@ -3160,7 +3166,7 @@ class ElementsAreArrayMatcher {
!IsHashTable<GTEST_REMOVE_REFERENCE_AND_CONST_(Container)>::value, !IsHashTable<GTEST_REMOVE_REFERENCE_AND_CONST_(Container)>::value,
use_UnorderedElementsAreArray_with_hash_tables); use_UnorderedElementsAreArray_with_hash_tables);
return MakeMatcher(new ElementsAreMatcherImpl<Container>( return Matcher<Container>(new ElementsAreMatcherImpl<const Container&>(
matchers_.begin(), matchers_.end())); matchers_.begin(), matchers_.end()));
} }

View File

@ -72,6 +72,7 @@
namespace testing { namespace testing {
namespace gmock_matchers_test { namespace gmock_matchers_test {
namespace {
using std::greater; using std::greater;
using std::less; using std::less;
@ -158,6 +159,19 @@ using testing::internal::StreamMatchResultListener;
using testing::internal::string; using testing::internal::string;
using testing::internal::Strings; using testing::internal::Strings;
// Helper for testing container-valued matchers in mock method context. It is
// important to test matchers in this context, since it requires additional type
// deduction beyond what EXPECT_THAT does, thus making it more restrictive.
struct ContainerHelper {
MOCK_METHOD1(Call, void(std::vector<std::unique_ptr<int>>));
};
std::vector<std::unique_ptr<int>> MakeUniquePtrs(const std::vector<int>& ints) {
std::vector<std::unique_ptr<int>> pointers;
for (int i : ints) pointers.emplace_back(new int(i));
return pointers;
}
// For testing ExplainMatchResultTo(). // For testing ExplainMatchResultTo().
class GreaterThanMatcher : public MatcherInterface<int> { class GreaterThanMatcher : public MatcherInterface<int> {
public: public:
@ -1679,6 +1693,12 @@ TEST(PairTest, InsideContainsUsingMap) {
EXPECT_THAT(container, Not(Contains(Pair(3, _)))); EXPECT_THAT(container, Not(Contains(Pair(3, _))));
} }
TEST(ContainsTest, WorksWithMoveOnly) {
ContainerHelper helper;
EXPECT_CALL(helper, Call(Contains(Pointee(2))));
helper.Call(MakeUniquePtrs({1, 2}));
}
#if GTEST_LANG_CXX11 #if GTEST_LANG_CXX11
TEST(PairTest, UseGetInsteadOfMembers) { TEST(PairTest, UseGetInsteadOfMembers) {
PairWithGet pair{7, "ABC"}; PairWithGet pair{7, "ABC"};
@ -4752,6 +4772,12 @@ TEST(IsEmptyTest, ExplainsResult) {
EXPECT_EQ("whose size is 1", Explain(m, container)); EXPECT_EQ("whose size is 1", Explain(m, container));
} }
TEST(IsEmptyTest, WorksWithMoveOnly) {
ContainerHelper helper;
EXPECT_CALL(helper, Call(IsEmpty()));
helper.Call({});
}
TEST(IsTrueTest, IsTrueIsFalse) { TEST(IsTrueTest, IsTrueIsFalse) {
EXPECT_THAT(true, IsTrue()); EXPECT_THAT(true, IsTrue());
EXPECT_THAT(false, IsFalse()); EXPECT_THAT(false, IsFalse());
@ -4822,6 +4848,12 @@ TEST(SizeIsTest, WorksWithReferences) {
EXPECT_THAT(container, m); EXPECT_THAT(container, m);
} }
TEST(SizeIsTest, WorksWithMoveOnly) {
ContainerHelper helper;
EXPECT_CALL(helper, Call(SizeIs(3)));
helper.Call(MakeUniquePtrs({1, 2, 3}));
}
// SizeIs should work for any type that provides a size() member function. // SizeIs should work for any type that provides a size() member function.
// For example, a size_type member type should not need to be provided. // For example, a size_type member type should not need to be provided.
struct MinimalistCustomType { struct MinimalistCustomType {
@ -5308,6 +5340,12 @@ TEST(BeginEndDistanceIsTest, CanDescribeSelf) {
DescribeNegation(m)); DescribeNegation(m));
} }
TEST(BeginEndDistanceIsTest, WorksWithMoveOnly) {
ContainerHelper helper;
EXPECT_CALL(helper, Call(BeginEndDistanceIs(2)));
helper.Call(MakeUniquePtrs({1, 2}));
}
TEST(BeginEndDistanceIsTest, ExplainsResult) { TEST(BeginEndDistanceIsTest, ExplainsResult) {
Matcher<vector<int> > m1 = BeginEndDistanceIs(2); Matcher<vector<int> > m1 = BeginEndDistanceIs(2);
Matcher<vector<int> > m2 = BeginEndDistanceIs(Lt(2)); Matcher<vector<int> > m2 = BeginEndDistanceIs(Lt(2));
@ -5477,6 +5515,14 @@ TEST(IsSupersetOfTest, WorksForRhsInitializerList) {
} }
#endif #endif
TEST(IsSupersetOfTest, WorksWithMoveOnly) {
ContainerHelper helper;
EXPECT_CALL(helper, Call(IsSupersetOf({Pointee(1)})));
helper.Call(MakeUniquePtrs({1, 2}));
EXPECT_CALL(helper, Call(Not(IsSupersetOf({Pointee(1), Pointee(2)}))));
helper.Call(MakeUniquePtrs({2}));
}
TEST(IsSubsetOfTest, WorksForNativeArray) { TEST(IsSubsetOfTest, WorksForNativeArray) {
const int subset[] = {1, 4}; const int subset[] = {1, 4};
const int superset[] = {1, 2, 4}; const int superset[] = {1, 2, 4};
@ -5599,6 +5645,14 @@ TEST(IsSubsetOfTest, WorksForRhsInitializerList) {
} }
#endif #endif
TEST(IsSubsetOfTest, WorksWithMoveOnly) {
ContainerHelper helper;
EXPECT_CALL(helper, Call(IsSubsetOf({Pointee(1), Pointee(2)})));
helper.Call(MakeUniquePtrs({1}));
EXPECT_CALL(helper, Call(Not(IsSubsetOf({Pointee(1)}))));
helper.Call(MakeUniquePtrs({2}));
}
// Tests using ElementsAre() and ElementsAreArray() with stream-like // Tests using ElementsAre() and ElementsAreArray() with stream-like
// "containers". // "containers".
@ -5632,6 +5686,15 @@ TEST(ElementsAreTest, WorksWithUncopyable) {
EXPECT_THAT(objs, ElementsAre(UncopyableIs(-3), Truly(ValueIsPositive))); EXPECT_THAT(objs, ElementsAre(UncopyableIs(-3), Truly(ValueIsPositive)));
} }
TEST(ElementsAreTest, WorksWithMoveOnly) {
ContainerHelper helper;
EXPECT_CALL(helper, Call(ElementsAre(Pointee(1), Pointee(2))));
helper.Call(MakeUniquePtrs({1, 2}));
EXPECT_CALL(helper, Call(ElementsAreArray({Pointee(3), Pointee(4)})));
helper.Call(MakeUniquePtrs({3, 4}));
}
TEST(ElementsAreTest, TakesStlContainer) { TEST(ElementsAreTest, TakesStlContainer) {
const int actual[] = {3, 1, 2}; const int actual[] = {3, 1, 2};
@ -5735,6 +5798,13 @@ TEST(UnorderedElementsAreArrayTest,
#endif // GTEST_HAS_STD_INITIALIZER_LIST_ #endif // GTEST_HAS_STD_INITIALIZER_LIST_
TEST(UnorderedElementsAreArrayTest, WorksWithMoveOnly) {
ContainerHelper helper;
EXPECT_CALL(helper,
Call(UnorderedElementsAreArray({Pointee(1), Pointee(2)})));
helper.Call(MakeUniquePtrs({2, 1}));
}
class UnorderedElementsAreTest : public testing::Test { class UnorderedElementsAreTest : public testing::Test {
protected: protected:
typedef std::vector<int> IntVec; typedef std::vector<int> IntVec;
@ -5782,6 +5852,12 @@ TEST_F(UnorderedElementsAreTest, WorksForStreamlike) {
EXPECT_THAT(s, Not(UnorderedElementsAre(2, 2, 3, 4, 5))); EXPECT_THAT(s, Not(UnorderedElementsAre(2, 2, 3, 4, 5)));
} }
TEST_F(UnorderedElementsAreTest, WorksWithMoveOnly) {
ContainerHelper helper;
EXPECT_CALL(helper, Call(UnorderedElementsAre(Pointee(1), Pointee(2))));
helper.Call(MakeUniquePtrs({2, 1}));
}
// One naive implementation of the matcher runs in O(N!) time, which is too // One naive implementation of the matcher runs in O(N!) time, which is too
// slow for many real-world inputs. This test shows that our matcher can match // slow for many real-world inputs. This test shows that our matcher can match
// 100 inputs very quickly (a few milliseconds). An O(100!) is 10^158 // 100 inputs very quickly (a few milliseconds). An O(100!) is 10^158
@ -6332,6 +6408,12 @@ TEST(EachTest, WorksForNativeArrayAsTuple) {
EXPECT_THAT(std::make_tuple(pointer, 2), Not(Each(Gt(1)))); EXPECT_THAT(std::make_tuple(pointer, 2), Not(Each(Gt(1))));
} }
TEST(EachTest, WorksWithMoveOnly) {
ContainerHelper helper;
EXPECT_CALL(helper, Call(Each(Pointee(Gt(0)))));
helper.Call(MakeUniquePtrs({1, 2}));
}
// For testing Pointwise(). // For testing Pointwise().
class IsHalfOfMatcher { class IsHalfOfMatcher {
public: public:
@ -6470,6 +6552,17 @@ TEST(PointwiseTest, AllowsMonomorphicInnerMatcher) {
EXPECT_EQ("", Explain(Pointwise(m2, rhs), lhs)); EXPECT_EQ("", Explain(Pointwise(m2, rhs), lhs));
} }
MATCHER(PointeeEquals, "Points to an equal value") {
return ExplainMatchResult(::testing::Pointee(::testing::get<1>(arg)),
::testing::get<0>(arg), result_listener);
}
TEST(PointwiseTest, WorksWithMoveOnly) {
ContainerHelper helper;
EXPECT_CALL(helper, Call(Pointwise(PointeeEquals(), std::vector<int>{1, 2})));
helper.Call(MakeUniquePtrs({1, 2}));
}
TEST(UnorderedPointwiseTest, DescribesSelf) { TEST(UnorderedPointwiseTest, DescribesSelf) {
vector<int> rhs; vector<int> rhs;
rhs.push_back(1); rhs.push_back(1);
@ -6584,6 +6677,13 @@ TEST(UnorderedPointwiseTest, AllowsMonomorphicInnerMatcher) {
EXPECT_THAT(lhs, UnorderedPointwise(m2, rhs)); EXPECT_THAT(lhs, UnorderedPointwise(m2, rhs));
} }
TEST(UnorderedPointwiseTest, WorksWithMoveOnly) {
ContainerHelper helper;
EXPECT_CALL(helper, Call(UnorderedPointwise(PointeeEquals(),
std::vector<int>{1, 2})));
helper.Call(MakeUniquePtrs({2, 1}));
}
// Sample optional type implementation with minimal requirements for use with // Sample optional type implementation with minimal requirements for use with
// Optional matcher. // Optional matcher.
class SampleOptionalInt { class SampleOptionalInt {
@ -6976,8 +7076,7 @@ TEST_F(PredicateFormatterFromMatcherTest, NoShortCircuitOnFailure) {
EXPECT_FALSE(result); // Implicit cast to bool. EXPECT_FALSE(result); // Implicit cast to bool.
std::string expect = std::string expect =
"Value of: dummy-name\nExpected: [DescribeTo]\n" "Value of: dummy-name\nExpected: [DescribeTo]\n"
" Actual: 1" + " Actual: 1, [MatchAndExplain]";
OfType(kMatcherType) + ", [MatchAndExplain]";
EXPECT_EQ(expect, result.message()); EXPECT_EQ(expect, result.message());
} }
@ -6988,11 +7087,11 @@ TEST_F(PredicateFormatterFromMatcherTest, DetectsFlakyShortCircuit) {
"Value of: dummy-name\nExpected: [DescribeTo]\n" "Value of: dummy-name\nExpected: [DescribeTo]\n"
" The matcher failed on the initial attempt; but passed when rerun to " " The matcher failed on the initial attempt; but passed when rerun to "
"generate the explanation.\n" "generate the explanation.\n"
" Actual: 2" + " Actual: 2, [MatchAndExplain]";
OfType(kMatcherType) + ", [MatchAndExplain]";
EXPECT_EQ(expect, result.message()); EXPECT_EQ(expect, result.message());
} }
} // namespace
} // namespace gmock_matchers_test } // namespace gmock_matchers_test
} // namespace testing } // namespace testing