Can I use the monomorphic matcher with EXPECT_THAT
or do I need to create it as polymorphic matcher?
class EvenMatcher : public MatcherInterface<int>
{
public:
virtual bool Matches(int n) const {
return (n % 2) == 0;
}
virtual void DescribeTo(::std::ostream* os) const {
*os << "is an even number";
}
virtual void DescribeNegationTo(::std::ostream* os) const {
*os << "is an odd number";
}
};
inline Matcher<int> Even() {
return MakeMatcher(new EvenMatcher);
}
// inline PolymorphicMatcher<EvenMatcher> Even() {
// return MakePolymorphicMatcher(EvenMatcher());
// }
TEST(TestNot, testitout)
{
EXPECT_THAT(3, Not(Even()));
}
I have been having a look at the following in gmock-matchers.h but its just not popping out at me.
// For implementing ASSERT_THAT() and EXPECT_THAT(). The template
// argument M must be a type that can be converted to a matcher.
template <typename M>
class PredicateFormatterFromMatcher {
public:
explicit PredicateFormatterFromMatcher(const M& m) : matcher_(m) {}
// This template () operator allows a PredicateFormatterFromMatcher
// object to act as a predicate-formatter suitable for using with
// Google Test's EXPECT_PRED_FORMAT1() macro.
template <typename T>
AssertionResult operator()(const char* value_text, const T& x) const {
// We convert matcher_ to a Matcher<const T&> *now* instead of
// when the PredicateFormatterFromMatcher object was constructed,
// as matcher_ may be polymorphic (e.g. NotNull()) and we won't
// know which type to instantiate it to until we actually see the
// type of x here.
//
// We write MatcherCast<const T&>(matcher_) instead of
// Matcher<const T&>(matcher_), as the latter won't compile when
// matcher_ has type Matcher<T> (e.g. An<int>()).
const Matcher<const T&> matcher = MatcherCast<const T&>(matcher_);
if (matcher.Matches(x)) {
return AssertionSuccess();
} else {
::std::stringstream ss;
ss << "Value of: " << value_text << "\n"
<< "Expected: ";
matcher.DescribeTo(&ss);
ss << "\n Actual: ";
UniversalPrinter<T>::Print(x, &ss);
ExplainMatchResultAsNeededTo<const T&>(matcher, x, &ss);
return AssertionFailure(Message() << ss.str());
}
}
private:
const M matcher_;
};
Thanks in advance.
Bruce
Yes, you can. Do you have problem using it?
See TEST(MatcherAssertionTest, WorksForMonomorphicMatcher) in
test/gmock-matchers_test.cc for examples.
> or do I need to create it as polymorphic matcher?
>
> class EvenMatcher : public MatcherInterface<int>
> {
> public:
> virtual bool Matches(int n) const {
> return (n % 2) == 0;
> }
>
> virtual void DescribeTo(::std::ostream* os) const {
> *os << "is an even number";
> }
>
> virtual void DescribeNegationTo(::std::ostream* os) const {
> *os << "is an odd number";
> }
> };
>
> inline Matcher<int> Even() {
> return MakeMatcher(new EvenMatcher);
> }
I assume this is just a contrived example, as MATCHER() can define
this much more easily (although the negative description won't be as
nice - not a big problem).
--
Zhanyong
BTW, An<int>() is a monomorphic matcher. Its type is Matcher<int>.
> const Matcher<const T&> matcher = MatcherCast<const T&>(matcher_);
> if (matcher.Matches(x)) {
> return AssertionSuccess();
> } else {
> ::std::stringstream ss;
> ss << "Value of: " << value_text << "\n"
> << "Expected: ";
> matcher.DescribeTo(&ss);
> ss << "\n Actual: ";
> UniversalPrinter<T>::Print(x, &ss);
> ExplainMatchResultAsNeededTo<const T&>(matcher, x, &ss);
> return AssertionFailure(Message() << ss.str());
> }
> }
> private:
> const M matcher_;
> };
>
> Thanks in advance.
> Bruce
>
--
Zhanyong
Yes. My compiler is barfing on this code:
class EvenMatcher : public MatcherInterface<int>
{
public:
virtual bool Matches(int n) const {
return (n % 2) == 0;
}
virtual void DescribeTo(::std::ostream* os) const {
*os << "is an even number";
}
virtual void DescribeNegationTo(::std::ostream* os) const {
*os << "is an odd number";
}
};
inline Matcher<int> Even() {
return MakeMatcher(new EvenMatcher);
}
TEST(TestNot, testitout)
{
EXPECT_THAT(3, Not(Even()));
}
--- On Wed, 4/22/09, Zhanyong Wan (λx.x x) <w...@google.com> wrote:
> From: Zhanyong Wan (λx.x x) <w...@google.com>
> Subject: [googlemock: 261] Re: using monomorphic matchers with EXPECT_THAT?
> To: "Bruce Trask" <bruce...@mdesystems.com>
> Cc: googl...@googlegroups.com
> Date: Wednesday, April 22, 2009, 12:24 AM
>
> On Tue, Apr 21, 2009 at 8:16 PM, Bruce Trask <bruce...@mdesystems.com>
> wrote:
> >
> >
> > Hello,
> >
> > Can I use the monomorphic matcher with EXPECT_THAT
>
> Yes, you can. Do you have problem using it?
>
> See TEST(MatcherAssertionTest, WorksForMonomorphicMatcher)
> in
> test/gmock-matchers_test.cc for examples.
>
> > or do I need to create it as polymorphic matcher?
> >
> > class EvenMatcher : public
> MatcherInterface<int>
> > {
> > public:
> > virtual bool Matches(int n) const {
> > return (n % 2) == 0;
> > }
> >
> > virtual void DescribeTo(::std::ostream* os) const {
> > *os << "is an even number";
> > }
> >
> > virtual void DescribeNegationTo(::std::ostream* os)
> const {
> > *os << "is an odd number";
> > }
> > };
> >
> > inline Matcher<int> Even() {
> > return MakeMatcher(new EvenMatcher);
> > }
>
> I assume this is just a contrived example, as MATCHER() can
> define
> this much more easily (although the negative description
> won't be as
> nice - not a big problem).
>
> > See TEST(MatcherAssertionTest,
> WorksForMonomorphicMatcher)
> > in
> > test/gmock-matchers_test.cc for examples.
I tweaked it a bit. Does this compile for you. It does not for me.
I maybe missing something.
TEST(MatcherAssertionTest, WorksForMonomorphicMatcher) {
Matcher<const char*> starts_with_he = StartsWith("he");
ASSERT_THAT("hello", starts_with_he);
Matcher<const std::string&> ends_with_ok = EndsWith("ok");
ASSERT_THAT("book", ends_with_ok);
Matcher<int> is_greater_than_5 = Gt(5);
EXPECT_THAT(5, Not(is_greater_than_5));
}
Regards,
Bruce
--- On Wed, 4/22/09, Bruce Trask <bruce...@mdesystems.com> wrote:
I think this may have to do with using a monomorphic matcher inside a
composite matcher like Not(). Does it compile without Not()?
I'll take a closer look probably tomorrow. Meanwhile, can you use MATCHER()?
I also suspect that you can workaround the problem by:
Matcher<int> not_even = Not(Even());
EXPECT_THAT(3, not_even);
--
Zhanyong
> I think this may have to do with using a monomorphic
> matcher inside a
> composite matcher like Not(). Does it compile without
> Not()?
Yes. It compiles without Not. So I guess my more specific question should have been: can I use a monomorphic matcher inside a composite matcher that gets used directly in an EXPECT_THAT macro?
>
> I'll take a closer look probably tomorrow.
Thanks. No rush. I am doing a bit of a deep dive into the Matcher code so I understand more of how it works under the hood and came across the above Not-related error in some of my test cases hand making some Matchers.
> Meanwhile,
> can you use MATCHER()?
Thanks.
> I also suspect that you can workaround the problem by:
>
> Matcher<int> not_even = Not(Even());
> EXPECT_THAT(3, not_even);
TEST(TEstEven, WithNot)
{
Matcher<int> not_even = Not(Even());
EXPECT_THAT(3, not_even); //compiles
EXPECT_THAT(3, Not(Even)); //does not compile
}
Thanks for the workaround. Just curious: should I expect the 2nd one to compile?
Regards,
Bruce
TEST(TEstEven, WithNot)
{
Matcher<int> not_even = Not(Even());
EXPECT_THAT(3, not_even); //compiles
EXPECT_THAT(3, Not(Even())); //does not compile
}
Thanks for the workaround. Just curious: should I expect the 2nd one to compile?
--- On Wed, 4/22/09, Bruce Trask <bruce...@mdesystems.com> wrote:
> From: Bruce Trask <bruce...@mdesystems.com>
> Subject: [googlemock: 266] Re: using monomorphic matchers with EXPECT_THAT?
> To: "Zhanyong Wan (λx.x x)" <w...@google.com>
> Cc: googl...@googlegroups.com
Yes, I would like to make the 2nd one compile. I'm still thinking
about what the best fix is. Thanks,
--
Zhanyong
To understand why the 2nd doesn't compile, we need to know how
matchers and EXPECT_THAT work under the hood. It's a bit complex, but
I'll try my best to explain:
- Matchers are typed. A matcher of type Matcher<T> validates an argument
of type T.
- In C++, an argument can be passed either by value or by reference.
The argument's type is different in the two cases (T vs const T&).
- Matcher<T> and Matcher<const T&> are not equivalent. This
distinction is necessary for catching user errors. For example, the
Ref(x) matcher matches a variable that references x. Its type is
Matcher<const T&>, and it can only be used in an EXPECT_CALL where
the mock function's argument has type const T&. If you say
EXPECT_CALL(mock, Foo(Ref(x))) where Foo() takes its argument by
value, you will get a compiler error - a good thing since Ref(x)
doesn't make sense here.
- The type of a polymorphic matcher is neither Matcher<T> nor
Matcher<const T&>. Instead, it's a type that can be implicitly
converted to Matcher<A>, where A is the argument type. A can be
either a reference or a non-reference.
- In EXPECT_THAT(value, matcher), 'matcher' can be a polymorphic
matcher. Since the context doesn't tell us whether 'matcher' should
be used as a Matcher<T> or a Matcher<const T&>, we use it as a
Matcher<const T&> to be safe. The reason is two-fold: T may not be
copyable (in which case Matcher<T> won't compile), or 'matcher' may
be interested in the address of 'value'.
- For EXPECT_THAT(3, Not(m)) to compile, Not(m) needs to be
convertible to Matcher<const int&>. This in turn requires
converting m to Matcher<const int&>. When m is a monomorphic
matcher of type Matcher<int>, this conversion cannot happen
implicitly. Hence the compiler error you see.
First, is this worth fixing? I think yes, as the compiler error can
be frustrating, and it's not easy to explain to the user why he gets
it and how to avoid it.
How do we fix it, then?
To do it in a principled and safe way, we need to distinguish two
kinds of conversions between monomorphic matchers: *safe* conversions
and *unsafe* conversions. As an example, there is a way to safely use
a Matcher<int> (let's call it m) as a Matcher<const int&>: you just
pass the argument (typed as const int&) to m, which takes an int. No
information will be lost in the process. The converse is not true: if
you use a Matcher<const int&> as a Matcher<int>, you may get a wrong
result as the Matcher<const int&> may be interested in the address of
the argument (as in the example of Ref(x)).
Currently, the implementation of Not() is such that to use Not(m) as a
Matcher<T>, m must be *implicitly* convertible to Matcher<T>. In
other words, either m is a polymorhpic matcher that can be used as
Matcher<T>, or m is a monomorphic matcher of Matcher<T>. This is
safe, yet overly conservative as shown by Bruce's example.
By replacing "implicit conversion" with "safe conversion" in Not()'s
implementation (and similarly for AllOf() and AnyOf()), we can make
EXPECT_THAT(3, Not(Even())) compile without sacrificing the safety of
the matcher type system. The question, is when a conversion is safe.
In general, if type A can be implicitly converted to type B, we can
safely convert a Matcher<B> to a Matcher<A> (i.e. Matcher is
contravariant): just keep a copy of the original Matcher<B>, convert
the argument from type A to B, and then pass it to the underlying
Matcher<B>. The only exception is when B is a reference and A is not,
as the underlying Matcher<B> may be interested in the argument's
address, which is not preserved in the conversion from A to B.
My plan is to implement this safe matcher conversion operation, and
use it in the implementation of composite matchers (Not, AllOf, AnyOf,
etc).
Sounds good?
--
Zhanyong
Yes! Let me know if I can help with code review btw, this is interesting.
Strange as it sounds, despite working with gMock internals for quite
some time now, this still did a better job of explaining some of the
previous mysterious behavior than anything I had read in the source
code. I think it would make a fantastic blog post BTW as kinda a
discussion on how "generic" matching can be done in C++ and the
challenges that arise.
-Chandler
> Yes! Let me know if I can help with code review btw, this is interesting.
Great to see your interest.
Vlad is interested in implementing this. We will keep you in the code
review loop.
> Strange as it sounds, despite working with gMock internals for quite
> some time now, this still did a better job of explaining some of the
> previous mysterious behavior than anything I had read in the source
> code. I think it would make a fantastic blog post BTW as kinda a
> discussion on how "generic" matching can be done in C++ and the
> challenges that arise.
I was thinking about the blog too.:-) Since it's possible we change
the plan when actually implementing it, I decided to wait until the
fix is ready. Thanks,
--
Zhanyong
> Strange as it sounds, despite working with gMock internals for quite
> some time now, this still did a better job of explaining some of the
> previous mysterious behavior than anything I had read in
> the source code. I think it would make a fantastic blog post BTW as
> kinda a discussion on how "generic" matching can be done in C++ and
> the challenges that arise.
I will second Chandler's sentiments here. I really enjoyed reading Zhanyong's explanation of the internal workings. We are primarily interested in extending gmock (in addition to using all of its really cool out-of-the-box facilities) and as such we want to really understand the internals (also so that we might meaningfully contribute back as well).
Regards,
Bruce
Alright, a post there will be - once we are sure the fix works. :-)
Looking forward to your contribution!
>
> Regards,
> Bruce
>
>
--
Zhanyong
Vlad has implemented this safe matcher conversion operation (not
checked in yet). In doing that, we found a new issue worth noting.
This is the safe conversion operation I had in mind:
> In general, if type A can be implicitly converted to type B, we can
> safely convert a Matcher<B> to a Matcher<A> (i.e. Matcher is
> contravariant): just keep a copy of the original Matcher<B>, convert
> the argument from type A to B, and then pass it to the underlying
> Matcher<B>. The only exception is when B is a reference and A is not,
> as the underlying Matcher<B> may be interested in the argument's
> address, which is not preserved in the conversion from A to B.
When writing this, I had the impression that lossy conversion between
built-in numeric types is not implicit in C++. That is, I thought
that you must explicitly cast a double to an int, since the double may
not be representable as an int. I was wrong. C++ allows such
conversion to happen implicitly.
So, my original simple plan has a problem: it allows us to "safely"
cast a Matcher<int> to Matcher<double>, which could lead to surprising
results. Consider this example:
Matcher<int> equals_5 = Eq(5);
Matcher<double> double_equals_5 = SafeMatcherCast<double>(equals_5);
If you use double_equals_5 to match 5.2, you'll get "yes", even though
5.2 isn't equal to 5. Here's what happens:
1. the argument 5.2 is implicitly converted to int to match the
argument type of the underlying matcher (equals_5); this turns 5.2
into 5.
2. since 5 equals 5, the underlying matcher reports "yes".
3. double_equals_5 in turn reports "yes, 5.2 equals 5".
To prevent this, we really need to ensure that the conversion of the
matcher argument is not only implicit, but also non-lossy. I plan to
add this constraint to the implementation. Let me know what you
think. Thanks,
2009/4/23 Zhanyong Wan (λx.x x) <w...@google.com>:
--
Zhanyong
2009/5/8 Zhanyong Wan (λx.x x) <w...@google.com>:
Vlad and I have implemented and checked in this "safe conversion of
matchers" operation. You can use SafeMatcherCast<T>(m) to safely cast
a matcher m to Matcher<T>. Not(), AnyOf(), and AllOf() have been
updated to use SafeMatcherCast internally.
For usage of SafeMatcherCast, you can read
http://code.google.com/p/googlemock/wiki/CookBook#Casting_Matchers.
Thanks,
--
Zhanyong