Googletest export

Add tuple version of Optional() matches. This allows Optional() to be used in Pointwise matchers.

PiperOrigin-RevId: 265110864
diff --git a/googlemock/include/gmock/gmock-matchers.h b/googlemock/include/gmock/gmock-matchers.h
index b1c0dc0..40e0452 100644
--- a/googlemock/include/gmock/gmock-matchers.h
+++ b/googlemock/include/gmock/gmock-matchers.h
@@ -3239,10 +3239,16 @@
       : value_matcher_(value_matcher) {}
 
   template <typename Optional>
-  operator Matcher<Optional>() const {
+  operator Matcher<Optional>() const {  // NOLINT
     return Matcher<Optional>(new Impl<const Optional&>(value_matcher_));
   }
 
+  template <typename Optional1, typename ValueType2>
+  operator Matcher<std::tuple<Optional1, ValueType2>>() const {  // NOLINT
+    return MakeMatcher(
+        new PairImpl<Optional1, ValueType2>(value_matcher_));
+  }
+
   template <typename Optional>
   class Impl : public MatcherInterface<Optional> {
    public:
@@ -3281,6 +3287,49 @@
     GTEST_DISALLOW_ASSIGN_(Impl);
   };
 
+  template <typename Optional1, typename ValueType2>
+  class PairImpl : public MatcherInterface<std::tuple<Optional1, ValueType2>> {
+   public:
+    typedef GTEST_REMOVE_REFERENCE_AND_CONST_(Optional1) Optional1View;
+    typedef typename Optional1View::value_type ValueType1;
+    typedef std::tuple<Optional1, ValueType2> OptionalTuple;
+    typedef std::tuple<ValueType1, ValueType2> ValuePair;
+
+    explicit PairImpl(const ValueMatcher& value_matcher)
+        : value_matcher_(MatcherCast<ValuePair>(value_matcher)) {}
+
+    void DescribeTo(::std::ostream* os) const override {
+      *os << "are optionals where the values ";
+      value_matcher_.DescribeTo(os);
+    }
+
+    void DescribeNegationTo(::std::ostream* os) const override {
+      *os << "are optionals where the values ";
+      value_matcher_.DescribeNegationTo(os);
+    }
+
+    bool MatchAndExplain(OptionalTuple optional_tuple,
+                         MatchResultListener* listener) const override {
+      const auto& optional1 = std::get<0>(optional_tuple);
+      const auto& value2 = std::get<1>(optional_tuple);
+      if (!optional1) {
+        *listener << "left is nullopt";
+        return false;
+      }
+      const ValueType1& value1 = *optional1;
+      StringMatchResultListener value_listener;
+      const bool match = value_matcher_.MatchAndExplain(
+          std::make_tuple(value1, value2), &value_listener);
+      *listener << (match ? "which match" : "whose values don't match");
+      PrintIfNotEmpty(value_listener.str(), listener->stream());
+      return match;
+    }
+
+   private:
+    const Matcher<ValuePair> value_matcher_;
+    GTEST_DISALLOW_ASSIGN_(PairImpl);
+  };
+
  private:
   const ValueMatcher value_matcher_;
   GTEST_DISALLOW_ASSIGN_(OptionalMatcher);
diff --git a/googlemock/test/gmock-matchers_test.cc b/googlemock/test/gmock-matchers_test.cc
index a61d040..f5e25e0 100644
--- a/googlemock/test/gmock-matchers_test.cc
+++ b/googlemock/test/gmock-matchers_test.cc
@@ -6387,7 +6387,7 @@
   explicit SampleOptional(T value)
       : value_(std::move(value)), has_value_(true) {}
   SampleOptional() : value_(), has_value_(false) {}
-  operator bool() const { return has_value_; }
+  explicit operator bool() const { return has_value_; }
   const T& operator*() const { return value_; }
 
  private:
@@ -6427,6 +6427,39 @@
   EXPECT_TRUE(m.Matches(SampleOptional<std::unique_ptr<int>>(nullptr)));
 }
 
+TEST(OptionalTest, TupleDescribesSelf) {
+  const Matcher<std::tuple<SampleOptional<int>, int>> m = Optional(Eq());
+  EXPECT_EQ("are optionals where the values are an equal pair", Describe(m));
+}
+
+TEST(OptionalTest, TupleExplainsSelf) {
+  const Matcher<std::tuple<SampleOptional<int>, int>> m = Optional(Eq());
+  EXPECT_EQ("which match",
+            Explain(m, std::make_tuple(SampleOptional<int>(1), 1)));
+  EXPECT_EQ("whose values don't match",
+            Explain(m, std::make_tuple(SampleOptional<int>(1), 2)));
+}
+
+TEST(OptionalTest, TupleMatchesNonEmpty) {
+  const Matcher<std::tuple<SampleOptional<int>, int>> m1 = Optional(Eq());
+  const Matcher<std::tuple<SampleOptional<int>, int>> m2 = Optional(Lt());
+  EXPECT_TRUE(m1.Matches(std::make_tuple(SampleOptional<int>(1), 1)));
+  EXPECT_FALSE(m1.Matches(std::make_tuple(SampleOptional<int>(1), 2)));
+  EXPECT_FALSE(m2.Matches(std::make_tuple(SampleOptional<int>(1), 1)));
+  EXPECT_TRUE(m2.Matches(std::make_tuple(SampleOptional<int>(1), 2)));
+}
+
+TEST(OptionalTest, TupleDoesNotMatchNullopt) {
+  const Matcher<std::tuple<SampleOptional<int>, int>> m1 = Optional(Eq());
+  EXPECT_FALSE(m1.Matches(std::make_tuple(SampleOptional<int>(), 1)));
+}
+
+TEST(OptionalTest, TupleWorksInPointwise) {
+  std::vector<SampleOptional<int>> v = {
+      SampleOptional<int>(1), SampleOptional<int>(2), SampleOptional<int>(3)};
+  EXPECT_THAT(v, Pointwise(Optional(Eq()), {1, 2, 3}));
+}
+
 class SampleVariantIntString {
  public:
   SampleVariantIntString(int i) : i_(i), has_int_(true) {}