From 1ec20f87e390e1d711e69b69345e68a1fa656bbc Mon Sep 17 00:00:00 2001
From: Abseil Team <absl-team@google.com>
Date: Sat, 15 Dec 2018 08:11:02 -0500
Subject: [PATCH] Googletest export

Allow container matchers to accept move-only containers.

PiperOrigin-RevId: 225667441
---
 googlemock/include/gmock/gmock-matchers.h |  30 +++---
 googlemock/test/gmock-matchers_test.cc    | 107 +++++++++++++++++++++-
 2 files changed, 121 insertions(+), 16 deletions(-)

diff --git a/googlemock/include/gmock/gmock-matchers.h b/googlemock/include/gmock/gmock-matchers.h
index 68278bea8..fa89bd607 100644
--- a/googlemock/include/gmock/gmock-matchers.h
+++ b/googlemock/include/gmock/gmock-matchers.h
@@ -1959,7 +1959,7 @@ class SizeIsMatcher {
 
   template <typename Container>
   operator Matcher<Container>() const {
-    return MakeMatcher(new Impl<Container>(size_matcher_));
+    return Matcher<Container>(new Impl<const Container&>(size_matcher_));
   }
 
   template <typename Container>
@@ -2009,7 +2009,7 @@ class BeginEndDistanceIsMatcher {
 
   template <typename Container>
   operator Matcher<Container>() const {
-    return MakeMatcher(new Impl<Container>(distance_matcher_));
+    return Matcher<Container>(new Impl<const Container&>(distance_matcher_));
   }
 
   template <typename Container>
@@ -2269,7 +2269,8 @@ class PointwiseMatcher {
         !IsHashTable<GTEST_REMOVE_REFERENCE_AND_CONST_(LhsContainer)>::value,
         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>
@@ -2471,7 +2472,8 @@ class ContainsMatcher {
 
   template <typename Container>
   operator Matcher<Container>() const {
-    return MakeMatcher(new ContainsMatcherImpl<Container>(inner_matcher_));
+    return Matcher<Container>(
+        new ContainsMatcherImpl<const Container&>(inner_matcher_));
   }
 
  private:
@@ -2488,7 +2490,8 @@ class EachMatcher {
 
   template <typename Container>
   operator Matcher<Container>() const {
-    return MakeMatcher(new EachMatcherImpl<Container>(inner_matcher_));
+    return Matcher<Container>(
+        new EachMatcherImpl<const Container&>(inner_matcher_));
   }
 
  private:
@@ -3086,8 +3089,10 @@ class UnorderedElementsAreMatcher {
     matchers.reserve(::std::tuple_size<MatcherTuple>::value);
     TransformTupleValues(CastAndAppendTransform<const Element&>(), matchers_,
                          ::std::back_inserter(matchers));
-    return MakeMatcher(new UnorderedElementsAreMatcherImpl<Container>(
-        UnorderedMatcherRequire::ExactMatch, matchers.begin(), matchers.end()));
+    return Matcher<Container>(
+        new UnorderedElementsAreMatcherImpl<const Container&>(
+            UnorderedMatcherRequire::ExactMatch, matchers.begin(),
+            matchers.end()));
   }
 
  private:
@@ -3116,8 +3121,8 @@ class ElementsAreMatcher {
     matchers.reserve(::std::tuple_size<MatcherTuple>::value);
     TransformTupleValues(CastAndAppendTransform<const Element&>(), matchers_,
                          ::std::back_inserter(matchers));
-    return MakeMatcher(new ElementsAreMatcherImpl<Container>(
-                           matchers.begin(), matchers.end()));
+    return Matcher<Container>(new ElementsAreMatcherImpl<const Container&>(
+        matchers.begin(), matchers.end()));
   }
 
  private:
@@ -3136,8 +3141,9 @@ class UnorderedElementsAreArrayMatcher {
 
   template <typename Container>
   operator Matcher<Container>() const {
-    return MakeMatcher(new UnorderedElementsAreMatcherImpl<Container>(
-        match_flags_, matchers_.begin(), matchers_.end()));
+    return Matcher<Container>(
+        new UnorderedElementsAreMatcherImpl<const Container&>(
+            match_flags_, matchers_.begin(), matchers_.end()));
   }
 
  private:
@@ -3160,7 +3166,7 @@ class ElementsAreArrayMatcher {
         !IsHashTable<GTEST_REMOVE_REFERENCE_AND_CONST_(Container)>::value,
         use_UnorderedElementsAreArray_with_hash_tables);
 
-    return MakeMatcher(new ElementsAreMatcherImpl<Container>(
+    return Matcher<Container>(new ElementsAreMatcherImpl<const Container&>(
         matchers_.begin(), matchers_.end()));
   }
 
diff --git a/googlemock/test/gmock-matchers_test.cc b/googlemock/test/gmock-matchers_test.cc
index c1589a405..a72218777 100644
--- a/googlemock/test/gmock-matchers_test.cc
+++ b/googlemock/test/gmock-matchers_test.cc
@@ -72,6 +72,7 @@
 
 namespace testing {
 namespace gmock_matchers_test {
+namespace {
 
 using std::greater;
 using std::less;
@@ -158,6 +159,19 @@ using testing::internal::StreamMatchResultListener;
 using testing::internal::string;
 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().
 class GreaterThanMatcher : public MatcherInterface<int> {
  public:
@@ -1679,6 +1693,12 @@ TEST(PairTest, InsideContainsUsingMap) {
   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
 TEST(PairTest, UseGetInsteadOfMembers) {
   PairWithGet pair{7, "ABC"};
@@ -4752,6 +4772,12 @@ TEST(IsEmptyTest, ExplainsResult) {
   EXPECT_EQ("whose size is 1", Explain(m, container));
 }
 
+TEST(IsEmptyTest, WorksWithMoveOnly) {
+  ContainerHelper helper;
+  EXPECT_CALL(helper, Call(IsEmpty()));
+  helper.Call({});
+}
+
 TEST(IsTrueTest, IsTrueIsFalse) {
   EXPECT_THAT(true, IsTrue());
   EXPECT_THAT(false, IsFalse());
@@ -4822,6 +4848,12 @@ TEST(SizeIsTest, WorksWithReferences) {
   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.
 // For example, a size_type member type should not need to be provided.
 struct MinimalistCustomType {
@@ -5308,6 +5340,12 @@ TEST(BeginEndDistanceIsTest, CanDescribeSelf) {
             DescribeNegation(m));
 }
 
+TEST(BeginEndDistanceIsTest, WorksWithMoveOnly) {
+  ContainerHelper helper;
+  EXPECT_CALL(helper, Call(BeginEndDistanceIs(2)));
+  helper.Call(MakeUniquePtrs({1, 2}));
+}
+
 TEST(BeginEndDistanceIsTest, ExplainsResult) {
   Matcher<vector<int> > m1 = BeginEndDistanceIs(2);
   Matcher<vector<int> > m2 = BeginEndDistanceIs(Lt(2));
@@ -5477,6 +5515,14 @@ TEST(IsSupersetOfTest, WorksForRhsInitializerList) {
 }
 #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) {
   const int subset[] = {1, 4};
   const int superset[] = {1, 2, 4};
@@ -5599,6 +5645,14 @@ TEST(IsSubsetOfTest, WorksForRhsInitializerList) {
 }
 #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
 // "containers".
 
@@ -5632,6 +5686,15 @@ TEST(ElementsAreTest, WorksWithUncopyable) {
   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) {
   const int actual[] = {3, 1, 2};
 
@@ -5735,6 +5798,13 @@ TEST(UnorderedElementsAreArrayTest,
 
 #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 {
  protected:
   typedef std::vector<int> IntVec;
@@ -5782,6 +5852,12 @@ TEST_F(UnorderedElementsAreTest, WorksForStreamlike) {
   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
 // 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
@@ -6332,6 +6408,12 @@ TEST(EachTest, WorksForNativeArrayAsTuple) {
   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().
 class IsHalfOfMatcher {
  public:
@@ -6470,6 +6552,17 @@ TEST(PointwiseTest, AllowsMonomorphicInnerMatcher) {
   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) {
   vector<int> rhs;
   rhs.push_back(1);
@@ -6584,6 +6677,13 @@ TEST(UnorderedPointwiseTest, AllowsMonomorphicInnerMatcher) {
   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
 // Optional matcher.
 class SampleOptionalInt {
@@ -6976,8 +7076,7 @@ TEST_F(PredicateFormatterFromMatcherTest, NoShortCircuitOnFailure) {
   EXPECT_FALSE(result);  // Implicit cast to bool.
   std::string expect =
       "Value of: dummy-name\nExpected: [DescribeTo]\n"
-      "  Actual: 1" +
-      OfType(kMatcherType) + ", [MatchAndExplain]";
+      "  Actual: 1, [MatchAndExplain]";
   EXPECT_EQ(expect, result.message());
 }
 
@@ -6988,11 +7087,11 @@ TEST_F(PredicateFormatterFromMatcherTest, DetectsFlakyShortCircuit) {
       "Value of: dummy-name\nExpected: [DescribeTo]\n"
       "  The matcher failed on the initial attempt; but passed when rerun to "
       "generate the explanation.\n"
-      "  Actual: 2" +
-      OfType(kMatcherType) + ", [MatchAndExplain]";
+      "  Actual: 2, [MatchAndExplain]";
   EXPECT_EQ(expect, result.message());
 }
 
+}  // namespace
 }  // namespace gmock_matchers_test
 }  // namespace testing