Re: [googletest] GMock and Pointee matchers

2,282 views
Skip to first unread message

Vlad Losev

unread,
Mar 11, 2010, 5:41:09 PM3/11/10
to Manuel Klimek, Google C++ Mocking Framework
[+googlemock, -googletestframework]

On Thu, Mar 11, 2010 at 2:10 PM, Manuel Klimek <kli...@google.com> wrote:
Hi,

just a quick question:
If I use a Pointee matcher in an EXPECT_CALL, the output in case of no
matching expectation doesn't show me the value of the pointed to
object, even if there is an operator<< for that type.
As a workaround, I declare
MATCHER_P(EqualsBlah, blah, "is equal to %(blah)s") {
 do_not_remember_the_name << "is equal to " << arg;
 return arg == blah;
}
Now if I match Pointee(EqualsBlah(blah)) instead of Pointee(blah) it
shows exactly what I want.
Would it be possible to implement the output for the "standard" Pointee case?

Thanks,
/Manuel

Vlad Losev

unread,
Mar 12, 2010, 12:24:34 AM3/12/10
to Manuel Klimek, Google C++ Mocking Framework
Hi Manuel,

The problem here is not in the Pointee matcher. The reason for this is that our relational matchers such as Eq(), Ne(), Lt(), etc. do not implement explanations. Pointee(blah) is in fact compiled as Pointee(Eq(blah)). When Pointee() sees that its inner matcher provides no explanation, it omits one itself, which is rather natural ("the provided value points to another value the properties of which are completely unknown" is not much of the explanation). In your own matcher, you provide the explanation by streaming into the explanation listener.

As to why explanations for the relational matchers are not implemented, I can only speculate. Zhanyong can sure provide a reasonable explanation (pun intended) when he returns from his leave next week. Adding explanations is trivial so maybe this is a performance issue. If you'd like to have them in your output, you can try out this patch:

--- /tmp/g4-84224/gmock/include/gmock/gmock-matchers.h#51 2010-03-11 21:06:20.000000000 -0800
+++ /home/vladl/gmock/include/gmock/gmock-matchers.h 2010-03-11 20:45:40.032643000 -0800
@@ -6664,7 +664,11 @@
      public: \
       explicit Impl(const Rhs& rhs) : rhs_(rhs) {} \
       virtual bool MatchAndExplain(\
-          Lhs lhs, MatchResultListener* /* listener */) const { \
+          Lhs lhs, MatchResultListener* listener) const { \
+        ::std::stringstream ss; \
+        UniversalPrinter<GMOCK_REMOVE_REFERENCE_(Lhs)>::Print(lhs, &ss); \
+        *listener << "is " << ss.str(); \
         return lhs op rhs_; \
       } \
       virtual void DescribeTo(::std::ostream* os) const { \
<end of patch> 

Thanks,
/Manuel

Regards,
Vlad

Zhanyong Wan (λx.x x)

unread,
Mar 12, 2010, 2:04:01 AM3/12/10
to Vlad Losev, Manuel Klimek, Google C++ Mocking Framework
On Thu, Mar 11, 2010 at 9:24 PM, Vlad Losev <vlad...@gmail.com> wrote:
> Hi Manuel,
>
> On Thu, Mar 11, 2010 at 2:41 PM, Vlad Losev <vlad...@gmail.com> wrote:
>>
>> [+googlemock, -googletestframework]
>>
>> On Thu, Mar 11, 2010 at 2:10 PM, Manuel Klimek <kli...@google.com> wrote:
>>>
>>> Hi,
>>>
>>> just a quick question:
>>> If I use a Pointee matcher in an EXPECT_CALL, the output in case of no
>>> matching expectation doesn't show me the value of the pointed to
>>> object, even if there is an operator<< for that type.
>>> As a workaround, I declare
>>> MATCHER_P(EqualsBlah, blah, "is equal to %(blah)s") {
>>>  do_not_remember_the_name << "is equal to " << arg;
>>>  return arg == blah;
>>> }
>>> Now if I match Pointee(EqualsBlah(blah)) instead of Pointee(blah) it
>>> shows exactly what I want.
>>> Would it be possible to implement the output for the "standard" Pointee
>>> case?

Yes, this is a reasonable improvement.

> The problem here is not in the Pointee matcher.

Actually it is. :-)

> The reason for this is that
> our relational matchers such as Eq(), Ne(), Lt(), etc. do not implement
> explanations. Pointee(blah) is in fact compiled as Pointee(Eq(blah)). When
> Pointee() sees that its inner matcher provides no explanation, it omits one
> itself, which is rather natural ("the provided value points to another value
> the properties of which are completely unknown" is not much of the
> explanation).

This is where Pointee() can do better. When the inner matcher fails,
it should print the pointee regardless of whether the inner matcher
provides an explanation.

> In your own matcher, you provide the explanation by streaming
> into the explanation listener.
> As to why explanations for the relational matchers are not implemented, I
> can only speculate. Zhanyong can sure provide a reasonable explanation (pun
> intended) when he returns from his leave next week. Adding explanations is
> trivial so maybe this is a performance issue.

It's not a performance issue. The way a matcher is used (in
EXPECT_CALL() or EXPECT_THAT()) by gmock, when it fails, gmock already
has printed the value being matched, so there's no point printing it
again in the match result explanation. For example,

EXPECT_THAT(Foo(), Eq(42));

may print something like:

Value of: Foo()
Expected: equals 42
Actual: 43

The string "43" is printed by the EXPECT_THAT() macro, not the Eq(42)
matcher. If Eq(42) prints "43" too, the user will see it twice in
the message, which isn't helpful.

Manuel, would you like to make this improvement yourself? I can do it
myself if you can wait. :-) Thanks,

> If you'd like to have them in
> your output, you can try out this patch:
> --- /tmp/g4-84224/gmock/include/gmock/gmock-matchers.h#51 2010-03-11
> 21:06:20.000000000 -0800
> +++ /home/vladl/gmock/include/gmock/gmock-matchers.h 2010-03-11
> 20:45:40.032643000 -0800
> @@ -6664,7 +664,11 @@
>       public: \
>        explicit Impl(const Rhs& rhs) : rhs_(rhs) {} \
>        virtual bool MatchAndExplain(\
> -          Lhs lhs, MatchResultListener* /* listener */) const { \
> +          Lhs lhs, MatchResultListener* listener) const { \
> +        ::std::stringstream ss; \
> +        UniversalPrinter<GMOCK_REMOVE_REFERENCE_(Lhs)>::Print(lhs, &ss); \
> +        *listener << "is " << ss.str(); \
>          return lhs op rhs_; \
>        } \
>        virtual void DescribeTo(::std::ostream* os) const { \
> <end of patch>
>>>
>>> Thanks,
>>> /Manuel
>>
> Regards,
> Vlad

--
Zhanyong

Vlad Losev

unread,
Mar 12, 2010, 11:35:32 AM3/12/10
to Zhanyong Wan (λx.x x), Manuel Klimek, Google C++ Mocking Framework


2010/3/11 Zhanyong Wan (λx.x x) <w...@google.com>
If you take this approach, you have to fix gmock other higher order matchers that propagate empty explanations (Field, Property, Key, etc.) to be consistent.

And then you still have the same problem when one higher order matcher is passed to another: the value will be printed by each one.

Zhanyong Wan (λx.x x)

unread,
Mar 12, 2010, 11:41:44 AM3/12/10
to Vlad Losev, Manuel Klimek, Google C++ Mocking Framework
2010/3/12 Vlad Losev <vlad...@gmail.com>:

Yes. We already have a bug tracking Field/Property.

> And then you still have the same problem when one higher order matcher is
> passed to another: the value will be printed by each one.

But each matcher prints a different part of the value, so the
information is still useful.

Example:

EXPECT_THAT(foo, Pointee(Pointee(Eq(42))));

may print:

Value of: foo
Expected: points to a value that points to a value that is equals to 42
Actual: 0x1234abcd (points to 0xabcd1234, which points to 43)

Here:

0x1234abcd is printed by EXPECT_THAT.
0xabcd1234 is printed by the outer Pointee.
43 is printed by the inner Pointee.

No duplicated information in the message.

--
Zhanyong

Manuel Klimek

unread,
Mar 12, 2010, 4:37:46 PM3/12/10
to Vlad Losev, Zhanyong Wan (λx.x x), Google C++ Mocking Framework
Ok, after talking to Vlad I got the idea - now I included the changes
to other matcher that use inner matchers. I also adapted some output
to fit better into the explanation scheme of chained matchers.

Some things feel a little strange to me, so please tell me where to put stuff...

Open for discussion :-)

On Fri, Mar 12, 2010 at 7:40 PM, Manuel Klimek <kli...@google.com> wrote:


> On Fri, Mar 12, 2010 at 5:35 PM, Vlad Losev <vlad...@gmail.com> wrote:
>>> This is where Pointee() can do better.  When the inner matcher fails,
>>> it should print the pointee regardless of whether the inner matcher
>>> provides an explanation.
>>>
>> If you take this approach, you have to fix gmock other higher order matchers
>> that propagate empty explanations (Field, Property, Key, etc.) to be
>> consistent.
>

> I don't understand that yet:
> struct X { int* f; };
> If I take a Field with a pointer, I just need to use Field(&X::f,
> Pointee(42)) to get
> actual: the given field points to 42
> I think that's exactly what I want, isn't it?
>
> Of course, if I care about matching pointer values, and not what the
> pointer points to, I don't get the content of the Field, but I think
> here Pointee has a different connotation: I use pointee exactly to
> /not/ match the pointer, but what the pointer points to.
>
> Cheers,
> /Manuel
>

Reply all
Reply to author
Forward
0 new messages