Tuesday, May 19, 2009

Google Mock Internals: How Not to Compare Apples to Oranges

Earlier, we wrote about how matchers can help you validate values in tests and how you can easily define your own matchers.  The latter post also shows that some matchers can match more than one type of values.  We can them polymorphic matchers.  Naturally, matchers that accept only one type of values are called monomorphic matchers.

Since C++ is a statically-typed language, matchers in Google Mock are statically typed.  Namely, a monomorphic matcher that validates a value of type T is implemented as an object of class Matcher<T>.  This lets the compiler catch the user error of giving the matcher a value with the wrong type.  Failing early is far better than returning a bogus answer!

In Google Mock, the context where a matcher is used determines what type of value it receives, and hence determines the matcher's type. For example, if your mock object has a method Foo() that takes an int argument, you can write

EXPECT_CALL(mock, Foo(an_int_matcher));

to verify that Foo() will be called with an argument that matches an_int_matcher.  Here, an_int_matcher is an expression of type Matcher<int>, and the compiler enforces that.

So far it has been simple.  It gets more interesting when the argument is passed by reference, in which case the argument type becomes const T& instead of T (let's ignore the possibility of T& for now) .  What type of matcher should we use to match such an argument?

The answer is Matcher<const T&>.  This type is considered not equivalent to Matcher<T>, so you cannot use the two interchangeably. Such distinction is necessary for catching user errors (again).  For example, the standard Ref(x) matcher matches a reference value that references x.  Its type is Matcher<const T&> where T is x's type.  If you say

EXPECT_CALL(mock, Foo(Ref(an_int_variable)));

where Foo() takes an int argument, you will get a compiler error - a good thing since Ref(an_int_variable) doesn't make sense for an int value.

Yet often we don't care about if a value is passed by value or by reference.  After all, you cannot tell them apart by looking at the call site.  This, is when a polymorphic matcher is useful.

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.

A frequently-used polymorphic matcher is Eq(x), which matches any value equal to x.  For instance, Eq(5) can be used as Matcher<int>, Matcher<const int&>, Matcher<short>, etc, depending on the context.

In EXPECT_THAT(value, matcher), the context doesn't make it clear whether matcher should b a Matcher<T> or a Matcher<const T&>, where T is the type of value.  To be safe, we treat matcher as a Matcher<const T&> here.  The reason is two-fold: T may not be copyable (in which case Matcher<T> won't compile as it requires passing T by value), and matcher may be interested in the address of value (as in Ref(x)).

It gets even more interesting when we consider the typing rule for composite matchers like Not(m).  Suppose we are using Not(m) where a Matcher<T> is expected.  Since we need to pass the value (with type T) to the underlying matcher m, an obvious idea is to require that m has type Matcher<T> as well.  While this is safe, it is also overly restrictive.  In particular, it doesn't allow us to use Not(an_int_matcher) as a Matcher<short>, even though we could convert the short argument to int and then feed it to an_int_matcher.

In the next post, we will reveal how we define composite matchers in a safe yet non-restrictive way, and how we solve the problem of safely converting between matcher types in general.

No comments:

Post a Comment

Note: Only a member of this blog may post a comment.