Skip to content

Commit fe11442

Browse files
Merge pull request google#1482 from zhangxy988/variant_matcher
Add matcher for std::variant.
2 parents a9f2368 + e162233 commit fe11442

File tree

3 files changed

+137
-0
lines changed

3 files changed

+137
-0
lines changed

googlemock/docs/CheatSheet.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,8 @@ divided into several categories:
178178
|`Ne(value)` |`argument != value`|
179179
|`IsNull()` |`argument` is a `NULL` pointer (raw or smart).|
180180
|`NotNull()` |`argument` is a non-null pointer (raw or smart).|
181+
|`VariantWith<T>(m)` |`argument` is `variant<>` that holds the alternative of
182+
type T with a value matching `m`.|
181183
|`Ref(variable)` |`argument` is a reference to `variable`.|
182184
|`TypedEq<type>(value)`|`argument` has type `type` and is equal to `value`. You may need to use this instead of `Eq(value)` when the mock function is overloaded.|
183185

googlemock/include/gmock/gmock-matchers.h

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3636,6 +3636,66 @@ GTEST_API_ std::string FormatMatcherDescription(bool negation,
36363636
const char* matcher_name,
36373637
const Strings& param_values);
36383638

3639+
namespace variant_matcher {
3640+
// Overloads to allow VariantMatcher to do proper ADL lookup.
3641+
template <typename T>
3642+
void holds_alternative() {}
3643+
template <typename T>
3644+
void get() {}
3645+
3646+
// Implements a matcher that checks the value of a variant<> type variable.
3647+
template <typename T>
3648+
class VariantMatcher {
3649+
public:
3650+
explicit VariantMatcher(::testing::Matcher<const T&> matcher)
3651+
: matcher_(internal::move(matcher)) {}
3652+
3653+
template <typename Variant>
3654+
bool MatchAndExplain(const Variant& value,
3655+
::testing::MatchResultListener* listener) const {
3656+
if (!listener->IsInterested()) {
3657+
return holds_alternative<T>(value) && matcher_.Matches(get<T>(value));
3658+
}
3659+
3660+
if (!holds_alternative<T>(value)) {
3661+
*listener << "whose value is not of type '" << GetTypeName() << "'";
3662+
return false;
3663+
}
3664+
3665+
const T& elem = get<T>(value);
3666+
StringMatchResultListener elem_listener;
3667+
const bool match = matcher_.MatchAndExplain(elem, &elem_listener);
3668+
*listener << "whose value " << PrintToString(elem)
3669+
<< (match ? " matches" : " doesn't match");
3670+
PrintIfNotEmpty(elem_listener.str(), listener->stream());
3671+
return match;
3672+
}
3673+
3674+
void DescribeTo(std::ostream* os) const {
3675+
*os << "is a variant<> with value of type '" << GetTypeName()
3676+
<< "' and the value ";
3677+
matcher_.DescribeTo(os);
3678+
}
3679+
3680+
void DescribeNegationTo(std::ostream* os) const {
3681+
*os << "is a variant<> with value of type other than '" << GetTypeName()
3682+
<< "' or the value ";
3683+
matcher_.DescribeNegationTo(os);
3684+
}
3685+
3686+
private:
3687+
static string GetTypeName() {
3688+
#if GTEST_HAS_RTTI
3689+
return internal::GetTypeName<T>();
3690+
#endif
3691+
return "the element type";
3692+
}
3693+
3694+
const ::testing::Matcher<const T&> matcher_;
3695+
};
3696+
3697+
} // namespace variant_matcher
3698+
36393699
} // namespace internal
36403700

36413701
// ElementsAreArray(iterator_first, iterator_last)
@@ -4540,6 +4600,17 @@ inline internal::AnyOfMatcher<Args...> AnyOf(const Args&... matchers) {
45404600
template <typename InnerMatcher>
45414601
inline InnerMatcher AllArgs(const InnerMatcher& matcher) { return matcher; }
45424602

4603+
// Returns a matcher that matches the value of a variant<> type variable.
4604+
// The matcher implementation uses ADL to find the holds_alternative and get
4605+
// functions.
4606+
// It is compatible with std::variant.
4607+
template <typename T>
4608+
PolymorphicMatcher<internal::variant_matcher::VariantMatcher<T> > VariantWith(
4609+
const Matcher<const T&>& matcher) {
4610+
return MakePolymorphicMatcher(
4611+
internal::variant_matcher::VariantMatcher<T>(matcher));
4612+
}
4613+
45434614
// These macros allow using matchers to check values in Google Test
45444615
// tests. ASSERT_THAT(value, matcher) and EXPECT_THAT(value, matcher)
45454616
// succeed iff the value matches the matcher. If the assertion fails,

googlemock/test/gmock-matchers_test.cc

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5655,5 +5655,69 @@ TEST(UnorderedPointwiseTest, AllowsMonomorphicInnerMatcher) {
56555655
EXPECT_THAT(lhs, UnorderedPointwise(m2, rhs));
56565656
}
56575657

5658+
class SampleVariantIntString {
5659+
public:
5660+
SampleVariantIntString(int i) : i_(i), has_int_(true) {}
5661+
SampleVariantIntString(const std::string& s) : s_(s), has_int_(false) {}
5662+
5663+
template <typename T>
5664+
friend bool holds_alternative(const SampleVariantIntString& value) {
5665+
return value.has_int_ == internal::IsSame<T, int>::value;
5666+
}
5667+
5668+
template <typename T>
5669+
friend const T& get(const SampleVariantIntString& value) {
5670+
return value.get_impl(static_cast<T*>(NULL));
5671+
}
5672+
5673+
private:
5674+
const int& get_impl(int*) const { return i_; }
5675+
const std::string& get_impl(std::string*) const { return s_; }
5676+
5677+
int i_;
5678+
std::string s_;
5679+
bool has_int_;
5680+
};
5681+
5682+
TEST(VariantTest, DescribesSelf) {
5683+
const Matcher<SampleVariantIntString> m = VariantWith<int>(Eq(1));
5684+
EXPECT_THAT(Describe(m), ContainsRegex("is a variant<> with value of type "
5685+
"'.*' and the value is equal to 1"));
5686+
}
5687+
5688+
TEST(VariantTest, ExplainsSelf) {
5689+
const Matcher<SampleVariantIntString> m = VariantWith<int>(Eq(1));
5690+
EXPECT_THAT(Explain(m, SampleVariantIntString(1)),
5691+
ContainsRegex("whose value 1"));
5692+
EXPECT_THAT(Explain(m, SampleVariantIntString("A")),
5693+
HasSubstr("whose value is not of type '"));
5694+
EXPECT_THAT(Explain(m, SampleVariantIntString(2)),
5695+
"whose value 2 doesn't match");
5696+
}
5697+
5698+
TEST(VariantTest, FullMatch) {
5699+
Matcher<SampleVariantIntString> m = VariantWith<int>(Eq(1));
5700+
EXPECT_TRUE(m.Matches(SampleVariantIntString(1)));
5701+
5702+
m = VariantWith<std::string>(Eq("1"));
5703+
EXPECT_TRUE(m.Matches(SampleVariantIntString("1")));
5704+
}
5705+
5706+
TEST(VariantTest, TypeDoesNotMatch) {
5707+
Matcher<SampleVariantIntString> m = VariantWith<int>(Eq(1));
5708+
EXPECT_FALSE(m.Matches(SampleVariantIntString("1")));
5709+
5710+
m = VariantWith<std::string>(Eq("1"));
5711+
EXPECT_FALSE(m.Matches(SampleVariantIntString(1)));
5712+
}
5713+
5714+
TEST(VariantTest, InnerDoesNotMatch) {
5715+
Matcher<SampleVariantIntString> m = VariantWith<int>(Eq(1));
5716+
EXPECT_FALSE(m.Matches(SampleVariantIntString(2)));
5717+
5718+
m = VariantWith<std::string>(Eq("1"));
5719+
EXPECT_FALSE(m.Matches(SampleVariantIntString("2")));
5720+
}
5721+
56585722
} // namespace gmock_matchers_test
56595723
} // namespace testing

0 commit comments

Comments
 (0)