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