summaryrefslogtreecommitdiffstats
path: root/googlemock
diff options
context:
space:
mode:
authorXiaoyi Zhang <zhangxy988@gmail.com>2018-02-27 16:36:21 (GMT)
committerXiaoyi Zhang <zhangxy988@gmail.com>2018-02-27 16:36:21 (GMT)
commit190e2cdd0b55d289136a177638942e1cd1b2d457 (patch)
tree9af57d325ec43d5ec3170db1e45e720ff1ddff0d /googlemock
parentac34e6c950925df7165e626becd3f9d64dcd584b (diff)
downloadgoogletest-190e2cdd0b55d289136a177638942e1cd1b2d457.zip
googletest-190e2cdd0b55d289136a177638942e1cd1b2d457.tar.gz
googletest-190e2cdd0b55d289136a177638942e1cd1b2d457.tar.bz2
Add matcher for std::variant.
Diffstat (limited to 'googlemock')
-rw-r--r--googlemock/include/gmock/gmock-matchers.h71
-rw-r--r--googlemock/test/gmock-matchers_test.cc64
2 files changed, 135 insertions, 0 deletions
diff --git a/googlemock/include/gmock/gmock-matchers.h b/googlemock/include/gmock/gmock-matchers.h
index fc3fe3a..85b5b13 100644
--- a/googlemock/include/gmock/gmock-matchers.h
+++ b/googlemock/include/gmock/gmock-matchers.h
@@ -3623,6 +3623,66 @@ GTEST_API_ std::string FormatMatcherDescription(bool negation,
const char* matcher_name,
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
// ElementsAreArray(first, last)
@@ -4397,6 +4457,17 @@ inline internal::AnyOfMatcher<Args...> AnyOf(const Args&... matchers) {
template <typename InnerMatcher>
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
// tests. ASSERT_THAT(value, matcher) and EXPECT_THAT(value, matcher)
// succeed iff the value matches the matcher. If the assertion fails,
diff --git a/googlemock/test/gmock-matchers_test.cc b/googlemock/test/gmock-matchers_test.cc
index 761c0c2..829935e 100644
--- a/googlemock/test/gmock-matchers_test.cc
+++ b/googlemock/test/gmock-matchers_test.cc
@@ -5655,5 +5655,69 @@ TEST(UnorderedPointwiseTest, AllowsMonomorphicInnerMatcher) {
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 testing