Blame googlemock/docs/DesignDoc.md

Packit bd1cd8
This page discusses the design of new Google Mock features.
Packit bd1cd8
Packit bd1cd8
Packit bd1cd8
Packit bd1cd8
# Macros for Defining Actions #
Packit bd1cd8
Packit bd1cd8
## Problem ##
Packit bd1cd8
Packit bd1cd8
Due to the lack of closures in C++, it currently requires some
Packit bd1cd8
non-trivial effort to define a custom action in Google Mock.  For
Packit bd1cd8
example, suppose you want to "increment the value pointed to by the
Packit bd1cd8
second argument of the mock function and return it", you could write:
Packit bd1cd8
Packit bd1cd8
```
Packit bd1cd8
int IncrementArg1(Unused, int* p, Unused) {
Packit bd1cd8
  return ++(*p);
Packit bd1cd8
}
Packit bd1cd8
Packit bd1cd8
... WillOnce(Invoke(IncrementArg1));
Packit bd1cd8
```
Packit bd1cd8
Packit bd1cd8
There are several things unsatisfactory about this approach:
Packit bd1cd8
Packit bd1cd8
  * Even though the action only cares about the second argument of the mock function, its definition needs to list other arguments as dummies.  This is tedious.
Packit bd1cd8
  * The defined action is usable only in mock functions that takes exactly 3 arguments - an unnecessary restriction.
Packit bd1cd8
  * To use the action, one has to say `Invoke(IncrementArg1)`, which isn't as nice as `IncrementArg1()`.
Packit bd1cd8
Packit bd1cd8
The latter two problems can be overcome using `MakePolymorphicAction()`,
Packit bd1cd8
but it requires much more boilerplate code:
Packit bd1cd8
Packit bd1cd8
```
Packit bd1cd8
class IncrementArg1Action {
Packit bd1cd8
 public:
Packit bd1cd8
  template <typename Result, typename ArgumentTuple>
Packit bd1cd8
  Result Perform(const ArgumentTuple& args) const {
Packit bd1cd8
    return ++(*tr1::get<1>(args));
Packit bd1cd8
  }
Packit bd1cd8
};
Packit bd1cd8
Packit bd1cd8
PolymorphicAction<IncrementArg1Action> IncrementArg1() {
Packit bd1cd8
  return MakePolymorphicAction(IncrementArg1Action());
Packit bd1cd8
}
Packit bd1cd8
Packit bd1cd8
... WillOnce(IncrementArg1());
Packit bd1cd8
```
Packit bd1cd8
Packit bd1cd8
Our goal is to allow defining custom actions with the least amount of
Packit bd1cd8
boiler-plate C++ requires.
Packit bd1cd8
Packit bd1cd8
## Solution ##
Packit bd1cd8
Packit bd1cd8
We propose to introduce a new macro:
Packit bd1cd8
```
Packit bd1cd8
ACTION(name) { statements; }
Packit bd1cd8
```
Packit bd1cd8
Packit bd1cd8
Using this in a namespace scope will define an action with the given
Packit bd1cd8
name that executes the statements.  Inside the statements, you can
Packit bd1cd8
refer to the K-th (0-based) argument of the mock function as `argK`.
Packit bd1cd8
For example:
Packit bd1cd8
```
Packit bd1cd8
ACTION(IncrementArg1) { return ++(*arg1); }
Packit bd1cd8
```
Packit bd1cd8
allows you to write
Packit bd1cd8
```
Packit bd1cd8
... WillOnce(IncrementArg1());
Packit bd1cd8
```
Packit bd1cd8
Packit bd1cd8
Note that you don't need to specify the types of the mock function
Packit bd1cd8
arguments, as brevity is a top design goal here.  Rest assured that
Packit bd1cd8
your code is still type-safe though: you'll get a compiler error if
Packit bd1cd8
`*arg1` doesn't support the `++` operator, or if the type of
Packit bd1cd8
`++(*arg1)` isn't compatible with the mock function's return type.
Packit bd1cd8
Packit bd1cd8
Another example:
Packit bd1cd8
```
Packit bd1cd8
ACTION(Foo) {
Packit bd1cd8
  (*arg2)(5);
Packit bd1cd8
  Blah();
Packit bd1cd8
  *arg1 = 0;
Packit bd1cd8
  return arg0;
Packit bd1cd8
}
Packit bd1cd8
```
Packit bd1cd8
defines an action `Foo()` that invokes argument #2 (a function pointer)
Packit bd1cd8
with 5, calls function `Blah()`, sets the value pointed to by argument
Packit bd1cd8
#1 to 0, and returns argument #0.
Packit bd1cd8
Packit bd1cd8
For more convenience and flexibility, you can also use the following
Packit bd1cd8
pre-defined symbols in the body of `ACTION`:
Packit bd1cd8
Packit bd1cd8
| `argK_type` | The type of the K-th (0-based) argument of the mock function |
Packit bd1cd8
|:------------|:-------------------------------------------------------------|
Packit bd1cd8
| `args`      | All arguments of the mock function as a tuple                |
Packit bd1cd8
| `args_type` | The type of all arguments of the mock function as a tuple    |
Packit bd1cd8
| `return_type` | The return type of the mock function                         |
Packit bd1cd8
| `function_type` | The type of the mock function                                |
Packit bd1cd8
Packit bd1cd8
For example, when using an `ACTION` as a stub action for mock function:
Packit bd1cd8
```
Packit bd1cd8
int DoSomething(bool flag, int* ptr);
Packit bd1cd8
```
Packit bd1cd8
we have:
Packit bd1cd8
| **Pre-defined Symbol** | **Is Bound To** |
Packit bd1cd8
|:-----------------------|:----------------|
Packit bd1cd8
| `arg0`                 | the value of `flag` |
Packit bd1cd8
| `arg0_type`            | the type `bool` |
Packit bd1cd8
| `arg1`                 | the value of `ptr` |
Packit bd1cd8
| `arg1_type`            | the type `int*` |
Packit bd1cd8
| `args`                 | the tuple `(flag, ptr)` |
Packit bd1cd8
| `args_type`            | the type `std::tr1::tuple<bool, int*>` |
Packit bd1cd8
| `return_type`          | the type `int`  |
Packit bd1cd8
| `function_type`        | the type `int(bool, int*)` |
Packit bd1cd8
Packit bd1cd8
## Parameterized actions ##
Packit bd1cd8
Packit bd1cd8
Sometimes you'll want to parameterize the action.   For that we propose
Packit bd1cd8
another macro
Packit bd1cd8
```
Packit bd1cd8
ACTION_P(name, param) { statements; }
Packit bd1cd8
```
Packit bd1cd8
Packit bd1cd8
For example,
Packit bd1cd8
```
Packit bd1cd8
ACTION_P(Add, n) { return arg0 + n; }
Packit bd1cd8
```
Packit bd1cd8
will allow you to write
Packit bd1cd8
```
Packit bd1cd8
// Returns argument #0 + 5.
Packit bd1cd8
... WillOnce(Add(5));
Packit bd1cd8
```
Packit bd1cd8
Packit bd1cd8
For convenience, we use the term _arguments_ for the values used to
Packit bd1cd8
invoke the mock function, and the term _parameters_ for the values
Packit bd1cd8
used to instantiate an action.
Packit bd1cd8
Packit bd1cd8
Note that you don't need to provide the type of the parameter either.
Packit bd1cd8
Suppose the parameter is named `param`, you can also use the
Packit bd1cd8
Google-Mock-defined symbol `param_type` to refer to the type of the
Packit bd1cd8
parameter as inferred by the compiler.
Packit bd1cd8
Packit bd1cd8
We will also provide `ACTION_P2`, `ACTION_P3`, and etc to support
Packit bd1cd8
multi-parameter actions.  For example,
Packit bd1cd8
```
Packit bd1cd8
ACTION_P2(ReturnDistanceTo, x, y) {
Packit bd1cd8
  double dx = arg0 - x;
Packit bd1cd8
  double dy = arg1 - y;
Packit bd1cd8
  return sqrt(dx*dx + dy*dy);
Packit bd1cd8
}
Packit bd1cd8
```
Packit bd1cd8
lets you write
Packit bd1cd8
```
Packit bd1cd8
... WillOnce(ReturnDistanceTo(5.0, 26.5));
Packit bd1cd8
```
Packit bd1cd8
Packit bd1cd8
You can view `ACTION` as a degenerated parameterized action where the
Packit bd1cd8
number of parameters is 0.
Packit bd1cd8
Packit bd1cd8
## Advanced Usages ##
Packit bd1cd8
Packit bd1cd8
### Overloading Actions ###
Packit bd1cd8
Packit bd1cd8
You can easily define actions overloaded on the number of parameters:
Packit bd1cd8
```
Packit bd1cd8
ACTION_P(Plus, a) { ... }
Packit bd1cd8
ACTION_P2(Plus, a, b) { ... }
Packit bd1cd8
```
Packit bd1cd8
Packit bd1cd8
### Restricting the Type of an Argument or Parameter ###
Packit bd1cd8
Packit bd1cd8
For maximum brevity and reusability, the `ACTION*` macros don't let
Packit bd1cd8
you specify the types of the mock function arguments and the action
Packit bd1cd8
parameters.  Instead, we let the compiler infer the types for us.
Packit bd1cd8
Packit bd1cd8
Sometimes, however, we may want to be more explicit about the types.
Packit bd1cd8
There are several tricks to do that.  For example:
Packit bd1cd8
```
Packit bd1cd8
ACTION(Foo) {
Packit bd1cd8
  // Makes sure arg0 can be converted to int.
Packit bd1cd8
  int n = arg0;
Packit bd1cd8
  ... use n instead of arg0 here ...
Packit bd1cd8
}
Packit bd1cd8
Packit bd1cd8
ACTION_P(Bar, param) {
Packit bd1cd8
  // Makes sure the type of arg1 is const char*.
Packit bd1cd8
  ::testing::StaticAssertTypeEq<const char*, arg1_type>();
Packit bd1cd8
Packit bd1cd8
  // Makes sure param can be converted to bool.
Packit bd1cd8
  bool flag = param;
Packit bd1cd8
}
Packit bd1cd8
```
Packit bd1cd8
where `StaticAssertTypeEq` is a compile-time assertion we plan to add to
Packit bd1cd8
Google Test (the name is chosen to match `static_assert` in C++0x).
Packit bd1cd8
Packit bd1cd8
### Using the ACTION Object's Type ###
Packit bd1cd8
Packit bd1cd8
If you are writing a function that returns an `ACTION` object, you'll
Packit bd1cd8
need to know its type.  The type depends on the macro used to define
Packit bd1cd8
the action and the parameter types.  The rule is relatively simple:
Packit bd1cd8
| **Given Definition** | **Expression** | **Has Type** |
Packit bd1cd8
|:---------------------|:---------------|:-------------|
Packit bd1cd8
| `ACTION(Foo)`        | `Foo()`        | `FooAction`  |
Packit bd1cd8
| `ACTION_P(Bar, param)` | `Bar(int_value)` | `BarActionP<int>` |
Packit bd1cd8
| `ACTION_P2(Baz, p1, p2)` | `Baz(bool_value, int_value)` | `BazActionP2<bool, int>` |
Packit bd1cd8
| ...                  | ...            | ...          |
Packit bd1cd8
Packit bd1cd8
Note that we have to pick different suffixes (`Action`, `ActionP`,
Packit bd1cd8
`ActionP2`, and etc) for actions with different numbers of parameters,
Packit bd1cd8
or the action definitions cannot be overloaded on the number of
Packit bd1cd8
parameters.
Packit bd1cd8
Packit bd1cd8
## When to Use ##
Packit bd1cd8
Packit bd1cd8
While the new macros are very convenient, please also consider other
Packit bd1cd8
means of implementing actions (e.g. via `ActionInterface` or
Packit bd1cd8
`MakePolymorphicAction()`), especially if you need to use the defined
Packit bd1cd8
action a lot.  While the other approaches require more work, they give
Packit bd1cd8
you more control on the types of the mock function arguments and the
Packit bd1cd8
action parameters, which in general leads to better compiler error
Packit bd1cd8
messages that pay off in the long run.  They also allow overloading
Packit bd1cd8
actions based on parameter types, as opposed to just the number of
Packit bd1cd8
parameters.
Packit bd1cd8
Packit bd1cd8
## Related Work ##
Packit bd1cd8
Packit bd1cd8
As you may have realized, the `ACTION*` macros resemble closures (also
Packit bd1cd8
known as lambda expressions or anonymous functions).  Indeed, both of
Packit bd1cd8
them seek to lower the syntactic overhead for defining a function.
Packit bd1cd8
Packit bd1cd8
C++0x will support lambdas, but they are not part of C++ right now.
Packit bd1cd8
Some non-standard libraries (most notably BLL or Boost Lambda Library)
Packit bd1cd8
try to alleviate this problem.  However, they are not a good choice
Packit bd1cd8
for defining actions as:
Packit bd1cd8
Packit bd1cd8
  * They are non-standard and not widely installed.  Google Mock only depends on standard libraries and `tr1::tuple`, which is part of the new C++ standard and comes with gcc 4+.  We want to keep it that way.
Packit bd1cd8
  * They are not trivial to learn.
Packit bd1cd8
  * They will become obsolete when C++0x's lambda feature is widely supported.  We don't want to make our users use a dying library.
Packit bd1cd8
  * Since they are based on operators, they are rather ad hoc: you cannot use statements, and you cannot pass the lambda arguments to a function, for example.
Packit bd1cd8
  * They have subtle semantics that easily confuses new users.  For example, in expression `_1++ + foo++`, `foo` will be incremented only once where the expression is evaluated, while `_1` will be incremented every time the unnamed function is invoked.  This is far from intuitive.
Packit bd1cd8
Packit bd1cd8
`ACTION*` avoid all these problems.
Packit bd1cd8
Packit bd1cd8
## Future Improvements ##
Packit bd1cd8
Packit bd1cd8
There may be a need for composing `ACTION*` definitions (i.e. invoking
Packit bd1cd8
another `ACTION` inside the definition of one `ACTION*`).  We are not
Packit bd1cd8
sure we want it yet, as one can get a similar effect by putting
Packit bd1cd8
`ACTION` definitions in function templates and composing the function
Packit bd1cd8
templates.  We'll revisit this based on user feedback.
Packit bd1cd8
Packit bd1cd8
The reason we don't allow `ACTION*()` inside a function body is that
Packit bd1cd8
the current C++ standard doesn't allow function-local types to be used
Packit bd1cd8
to instantiate templates.  The upcoming C++0x standard will lift this
Packit bd1cd8
restriction.  Once this feature is widely supported by compilers, we
Packit bd1cd8
can revisit the implementation and add support for using `ACTION*()`
Packit bd1cd8
inside a function.
Packit bd1cd8
Packit bd1cd8
C++0x will also support lambda expressions.  When they become
Packit bd1cd8
available, we may want to support using lambdas as actions.
Packit bd1cd8
Packit bd1cd8
# Macros for Defining Matchers #
Packit bd1cd8
Packit bd1cd8
Once the macros for defining actions are implemented, we plan to do
Packit bd1cd8
the same for matchers:
Packit bd1cd8
Packit bd1cd8
```
Packit bd1cd8
MATCHER(name) { statements; }
Packit bd1cd8
```
Packit bd1cd8
Packit bd1cd8
where you can refer to the value being matched as `arg`.  For example,
Packit bd1cd8
given:
Packit bd1cd8
Packit bd1cd8
```
Packit bd1cd8
MATCHER(IsPositive) { return arg > 0; }
Packit bd1cd8
```
Packit bd1cd8
Packit bd1cd8
you can use `IsPositive()` as a matcher that matches a value iff it is
Packit bd1cd8
greater than 0.
Packit bd1cd8
Packit bd1cd8
We will also add `MATCHER_P`, `MATCHER_P2`, and etc for parameterized
Packit bd1cd8
matchers.