Add matcher for std::variant.
This commit is contained in:
		@@ -3623,6 +3623,66 @@ GTEST_API_ std::string FormatMatcherDescription(bool negation,
 | 
				
			|||||||
                                                const char* matcher_name,
 | 
					                                                const char* matcher_name,
 | 
				
			||||||
                                                const Strings& param_values);
 | 
					                                                const Strings& param_values);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace variant_matcher {
 | 
				
			||||||
 | 
					// Overloads to allow VariantMatcher to do proper ADL lookup.
 | 
				
			||||||
 | 
					template <typename T>
 | 
				
			||||||
 | 
					void holds_alternative() {}
 | 
				
			||||||
 | 
					template <typename T>
 | 
				
			||||||
 | 
					void get() {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Implements a matcher that checks the value of a variant<> type variable.
 | 
				
			||||||
 | 
					template <typename T>
 | 
				
			||||||
 | 
					class VariantMatcher {
 | 
				
			||||||
 | 
					 public:
 | 
				
			||||||
 | 
					  explicit VariantMatcher(::testing::Matcher<const T&> matcher)
 | 
				
			||||||
 | 
					      : matcher_(internal::move(matcher)) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  template <typename Variant>
 | 
				
			||||||
 | 
					  bool MatchAndExplain(const Variant& value,
 | 
				
			||||||
 | 
					                       ::testing::MatchResultListener* listener) const {
 | 
				
			||||||
 | 
					    if (!listener->IsInterested()) {
 | 
				
			||||||
 | 
					      return holds_alternative<T>(value) && matcher_.Matches(get<T>(value));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!holds_alternative<T>(value)) {
 | 
				
			||||||
 | 
					      *listener << "whose value is not of type '" << GetTypeName() << "'";
 | 
				
			||||||
 | 
					      return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const T& elem = get<T>(value);
 | 
				
			||||||
 | 
					    StringMatchResultListener elem_listener;
 | 
				
			||||||
 | 
					    const bool match = matcher_.MatchAndExplain(elem, &elem_listener);
 | 
				
			||||||
 | 
					    *listener << "whose value " << PrintToString(elem)
 | 
				
			||||||
 | 
					              << (match ? " matches" : " doesn't match");
 | 
				
			||||||
 | 
					    PrintIfNotEmpty(elem_listener.str(), listener->stream());
 | 
				
			||||||
 | 
					    return match;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void DescribeTo(std::ostream* os) const {
 | 
				
			||||||
 | 
					    *os << "is a variant<> with value of type '" << GetTypeName()
 | 
				
			||||||
 | 
					        << "' and the value ";
 | 
				
			||||||
 | 
					    matcher_.DescribeTo(os);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void DescribeNegationTo(std::ostream* os) const {
 | 
				
			||||||
 | 
					    *os << "is a variant<> with value of type other than '" << GetTypeName()
 | 
				
			||||||
 | 
					        << "' or the value ";
 | 
				
			||||||
 | 
					    matcher_.DescribeNegationTo(os);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 private:
 | 
				
			||||||
 | 
					  static string GetTypeName() {
 | 
				
			||||||
 | 
					#if GTEST_HAS_RTTI
 | 
				
			||||||
 | 
					    return internal::GetTypeName<T>();
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					    return "the element type";
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const ::testing::Matcher<const T&> matcher_;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}  // namespace variant_matcher
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}  // namespace internal
 | 
					}  // namespace internal
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ElementsAreArray(first, last)
 | 
					// ElementsAreArray(first, last)
 | 
				
			||||||
@@ -4397,6 +4457,17 @@ inline internal::AnyOfMatcher<Args...> AnyOf(const Args&... matchers) {
 | 
				
			|||||||
template <typename InnerMatcher>
 | 
					template <typename InnerMatcher>
 | 
				
			||||||
inline InnerMatcher AllArgs(const InnerMatcher& matcher) { return matcher; }
 | 
					inline InnerMatcher AllArgs(const InnerMatcher& matcher) { return matcher; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Returns a matcher that matches the value of a variant<> type variable.
 | 
				
			||||||
 | 
					// The matcher implementation uses ADL to find the holds_alternative and get
 | 
				
			||||||
 | 
					// functions.
 | 
				
			||||||
 | 
					// It is compatible with std::variant.
 | 
				
			||||||
 | 
					template <typename T>
 | 
				
			||||||
 | 
					PolymorphicMatcher<internal::variant_matcher::VariantMatcher<T> > VariantWith(
 | 
				
			||||||
 | 
					    const Matcher<const T&>& matcher) {
 | 
				
			||||||
 | 
					  return MakePolymorphicMatcher(
 | 
				
			||||||
 | 
					      internal::variant_matcher::VariantMatcher<T>(matcher));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// These macros allow using matchers to check values in Google Test
 | 
					// These macros allow using matchers to check values in Google Test
 | 
				
			||||||
// tests.  ASSERT_THAT(value, matcher) and EXPECT_THAT(value, matcher)
 | 
					// tests.  ASSERT_THAT(value, matcher) and EXPECT_THAT(value, matcher)
 | 
				
			||||||
// succeed iff the value matches the matcher.  If the assertion fails,
 | 
					// succeed iff the value matches the matcher.  If the assertion fails,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5655,5 +5655,69 @@ TEST(UnorderedPointwiseTest, AllowsMonomorphicInnerMatcher) {
 | 
				
			|||||||
  EXPECT_THAT(lhs, UnorderedPointwise(m2, rhs));
 | 
					  EXPECT_THAT(lhs, UnorderedPointwise(m2, rhs));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class SampleVariantIntString {
 | 
				
			||||||
 | 
					 public:
 | 
				
			||||||
 | 
					  SampleVariantIntString(int i) : i_(i), has_int_(true) {}
 | 
				
			||||||
 | 
					  SampleVariantIntString(const std::string& s) : s_(s), has_int_(false) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  template <typename T>
 | 
				
			||||||
 | 
					  friend bool holds_alternative(const SampleVariantIntString& value) {
 | 
				
			||||||
 | 
					    return value.has_int_ == internal::IsSame<T, int>::value;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  template <typename T>
 | 
				
			||||||
 | 
					  friend const T& get(const SampleVariantIntString& value) {
 | 
				
			||||||
 | 
					    return value.get_impl(static_cast<T*>(NULL));
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 private:
 | 
				
			||||||
 | 
					  const int& get_impl(int*) const { return i_; }
 | 
				
			||||||
 | 
					  const std::string& get_impl(std::string*) const { return s_; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  int i_;
 | 
				
			||||||
 | 
					  std::string s_;
 | 
				
			||||||
 | 
					  bool has_int_;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TEST(VariantTest, DescribesSelf) {
 | 
				
			||||||
 | 
					  const Matcher<SampleVariantIntString> m = VariantWith<int>(Eq(1));
 | 
				
			||||||
 | 
					  EXPECT_THAT(Describe(m), ContainsRegex("is a variant<> with value of type "
 | 
				
			||||||
 | 
					                                         "'.*' and the value is equal to 1"));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TEST(VariantTest, ExplainsSelf) {
 | 
				
			||||||
 | 
					  const Matcher<SampleVariantIntString> m = VariantWith<int>(Eq(1));
 | 
				
			||||||
 | 
					  EXPECT_THAT(Explain(m, SampleVariantIntString(1)),
 | 
				
			||||||
 | 
					              ContainsRegex("whose value 1"));
 | 
				
			||||||
 | 
					  EXPECT_THAT(Explain(m, SampleVariantIntString("A")),
 | 
				
			||||||
 | 
					              HasSubstr("whose value is not of type '"));
 | 
				
			||||||
 | 
					  EXPECT_THAT(Explain(m, SampleVariantIntString(2)),
 | 
				
			||||||
 | 
					              "whose value 2 doesn't match");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TEST(VariantTest, FullMatch) {
 | 
				
			||||||
 | 
					  Matcher<SampleVariantIntString> m = VariantWith<int>(Eq(1));
 | 
				
			||||||
 | 
					  EXPECT_TRUE(m.Matches(SampleVariantIntString(1)));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  m = VariantWith<std::string>(Eq("1"));
 | 
				
			||||||
 | 
					  EXPECT_TRUE(m.Matches(SampleVariantIntString("1")));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TEST(VariantTest, TypeDoesNotMatch) {
 | 
				
			||||||
 | 
					  Matcher<SampleVariantIntString> m = VariantWith<int>(Eq(1));
 | 
				
			||||||
 | 
					  EXPECT_FALSE(m.Matches(SampleVariantIntString("1")));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  m = VariantWith<std::string>(Eq("1"));
 | 
				
			||||||
 | 
					  EXPECT_FALSE(m.Matches(SampleVariantIntString(1)));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TEST(VariantTest, InnerDoesNotMatch) {
 | 
				
			||||||
 | 
					  Matcher<SampleVariantIntString> m = VariantWith<int>(Eq(1));
 | 
				
			||||||
 | 
					  EXPECT_FALSE(m.Matches(SampleVariantIntString(2)));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  m = VariantWith<std::string>(Eq("1"));
 | 
				
			||||||
 | 
					  EXPECT_FALSE(m.Matches(SampleVariantIntString("2")));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}  // namespace gmock_matchers_test
 | 
					}  // namespace gmock_matchers_test
 | 
				
			||||||
}  // namespace testing
 | 
					}  // namespace testing
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user