• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1This page discusses the design of new Google Mock features.
2
3
4
5# Macros for Defining Actions #
6
7## Problem ##
8
9Due to the lack of closures in C++, it currently requires some
10non-trivial effort to define a custom action in Google Mock.  For
11example, suppose you want to "increment the value pointed to by the
12second argument of the mock function and return it", you could write:
13
14```cpp
15int IncrementArg1(Unused, int* p, Unused) {
16  return ++(*p);
17}
18
19... WillOnce(Invoke(IncrementArg1));
20```
21
22There are several things unsatisfactory about this approach:
23
24  * 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.
25  * The defined action is usable only in mock functions that takes exactly 3 arguments - an unnecessary restriction.
26  * To use the action, one has to say `Invoke(IncrementArg1)`, which isn't as nice as `IncrementArg1()`.
27
28The latter two problems can be overcome using `MakePolymorphicAction()`,
29but it requires much more boilerplate code:
30
31```cpp
32class IncrementArg1Action {
33 public:
34  template <typename Result, typename ArgumentTuple>
35  Result Perform(const ArgumentTuple& args) const {
36    return ++(*tr1::get<1>(args));
37  }
38};
39
40PolymorphicAction<IncrementArg1Action> IncrementArg1() {
41  return MakePolymorphicAction(IncrementArg1Action());
42}
43
44... WillOnce(IncrementArg1());
45```
46
47Our goal is to allow defining custom actions with the least amount of
48boiler-plate C++ requires.
49
50## Solution ##
51
52We propose to introduce a new macro:
53```cpp
54ACTION(name) { statements; }
55```
56
57Using this in a namespace scope will define an action with the given
58name that executes the statements.  Inside the statements, you can
59refer to the K-th (0-based) argument of the mock function as `argK`.
60For example:
61```cpp
62ACTION(IncrementArg1) { return ++(*arg1); }
63```
64allows you to write
65```cpp
66... WillOnce(IncrementArg1());
67```
68
69Note that you don't need to specify the types of the mock function
70arguments, as brevity is a top design goal here.  Rest assured that
71your code is still type-safe though: you'll get a compiler error if
72`*arg1` doesn't support the `++` operator, or if the type of
73`++(*arg1)` isn't compatible with the mock function's return type.
74
75Another example:
76```cpp
77ACTION(Foo) {
78  (*arg2)(5);
79  Blah();
80  *arg1 = 0;
81  return arg0;
82}
83```
84defines an action `Foo()` that invokes argument #2 (a function pointer)
85with 5, calls function `Blah()`, sets the value pointed to by argument
86#1 to 0, and returns argument #0.
87
88For more convenience and flexibility, you can also use the following
89pre-defined symbols in the body of `ACTION`:
90
91| Argument        | Description                                                  |
92|:----------------|:-------------------------------------------------------------|
93| `argK_type`     | The type of the K-th (0-based) argument of the mock function |
94| `args`          | All arguments of the mock function as a tuple                |
95| `args_type`     | The type of all arguments of the mock function as a tuple    |
96| `return_type`   | The return type of the mock function                         |
97| `function_type` | The type of the mock function                                |
98
99For example, when using an `ACTION` as a stub action for mock function:
100```cpp
101int DoSomething(bool flag, int* ptr);
102```
103we have:
104
105| **Pre-defined Symbol** | **Is Bound To** |
106|:-----------------------|:----------------|
107| `arg0`                 | the value of `flag` |
108| `arg0_type`            | the type `bool` |
109| `arg1`                 | the value of `ptr` |
110| `arg1_type`            | the type `int*` |
111| `args`                 | the tuple `(flag, ptr)` |
112| `args_type`            | the type `std::tr1::tuple<bool, int*>` |
113| `return_type`          | the type `int`  |
114| `function_type`        | the type `int(bool, int*)` |
115
116## Parameterized actions ##
117
118Sometimes you'll want to parameterize the action.   For that we propose
119another macro
120```cpp
121ACTION_P(name, param) { statements; }
122```
123
124For example,
125```cpp
126ACTION_P(Add, n) { return arg0 + n; }
127```
128will allow you to write
129```cpp
130// Returns argument #0 + 5.
131... WillOnce(Add(5));
132```
133
134For convenience, we use the term _arguments_ for the values used to
135invoke the mock function, and the term _parameters_ for the values
136used to instantiate an action.
137
138Note that you don't need to provide the type of the parameter either.
139Suppose the parameter is named `param`, you can also use the
140Google-Mock-defined symbol `param_type` to refer to the type of the
141parameter as inferred by the compiler.
142
143We will also provide `ACTION_P2`, `ACTION_P3`, and etc to support
144multi-parameter actions.  For example,
145```cpp
146ACTION_P2(ReturnDistanceTo, x, y) {
147  double dx = arg0 - x;
148  double dy = arg1 - y;
149  return sqrt(dx*dx + dy*dy);
150}
151```
152lets you write
153```cpp
154... WillOnce(ReturnDistanceTo(5.0, 26.5));
155```
156
157You can view `ACTION` as a degenerated parameterized action where the
158number of parameters is 0.
159
160## Advanced Usages ##
161
162### Overloading Actions ###
163
164You can easily define actions overloaded on the number of parameters:
165```cpp
166ACTION_P(Plus, a) { ... }
167ACTION_P2(Plus, a, b) { ... }
168```
169
170### Restricting the Type of an Argument or Parameter ###
171
172For maximum brevity and reusability, the `ACTION*` macros don't let
173you specify the types of the mock function arguments and the action
174parameters.  Instead, we let the compiler infer the types for us.
175
176Sometimes, however, we may want to be more explicit about the types.
177There are several tricks to do that.  For example:
178```cpp
179ACTION(Foo) {
180  // Makes sure arg0 can be converted to int.
181  int n = arg0;
182  ... use n instead of arg0 here ...
183}
184
185ACTION_P(Bar, param) {
186  // Makes sure the type of arg1 is const char*.
187  ::testing::StaticAssertTypeEq<const char*, arg1_type>();
188
189  // Makes sure param can be converted to bool.
190  bool flag = param;
191}
192```
193where `StaticAssertTypeEq` is a compile-time assertion we plan to add to
194Google Test (the name is chosen to match `static_assert` in C++0x).
195
196### Using the ACTION Object's Type ###
197
198If you are writing a function that returns an `ACTION` object, you'll
199need to know its type.  The type depends on the macro used to define
200the action and the parameter types.  The rule is relatively simple:
201| **Given Definition**     | **Expression**               | **Has Type**             |
202|:-------------------------|:-----------------------------|:-------------------------|
203| `ACTION(Foo)`            | `Foo()`                      | `FooAction`              |
204| `ACTION_P(Bar, param)`   | `Bar(int_value)`             | `BarActionP<int>`        |
205| `ACTION_P2(Baz, p1, p2)` | `Baz(bool_value, int_value)` | `BazActionP2<bool, int>` |
206| ...                      | ...                          | ...                      |
207
208Note that we have to pick different suffixes (`Action`, `ActionP`,
209`ActionP2`, and etc) for actions with different numbers of parameters,
210or the action definitions cannot be overloaded on the number of
211parameters.
212
213## When to Use ##
214
215While the new macros are very convenient, please also consider other
216means of implementing actions (e.g. via `ActionInterface` or
217`MakePolymorphicAction()`), especially if you need to use the defined
218action a lot.  While the other approaches require more work, they give
219you more control on the types of the mock function arguments and the
220action parameters, which in general leads to better compiler error
221messages that pay off in the long run.  They also allow overloading
222actions based on parameter types, as opposed to just the number of
223parameters.
224
225## Related Work ##
226
227As you may have realized, the `ACTION*` macros resemble closures (also
228known as lambda expressions or anonymous functions).  Indeed, both of
229them seek to lower the syntactic overhead for defining a function.
230
231C++0x will support lambdas, but they are not part of C++ right now.
232Some non-standard libraries (most notably BLL or Boost Lambda Library)
233try to alleviate this problem.  However, they are not a good choice
234for defining actions as:
235
236  * 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.
237  * They are not trivial to learn.
238  * 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.
239  * 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.
240  * 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.
241
242`ACTION*` avoid all these problems.
243
244## Future Improvements ##
245
246There may be a need for composing `ACTION*` definitions (i.e. invoking
247another `ACTION` inside the definition of one `ACTION*`).  We are not
248sure we want it yet, as one can get a similar effect by putting
249`ACTION` definitions in function templates and composing the function
250templates.  We'll revisit this based on user feedback.
251
252The reason we don't allow `ACTION*()` inside a function body is that
253the current C++ standard doesn't allow function-local types to be used
254to instantiate templates.  The upcoming C++0x standard will lift this
255restriction.  Once this feature is widely supported by compilers, we
256can revisit the implementation and add support for using `ACTION*()`
257inside a function.
258
259C++0x will also support lambda expressions.  When they become
260available, we may want to support using lambdas as actions.
261
262# Macros for Defining Matchers #
263
264Once the macros for defining actions are implemented, we plan to do
265the same for matchers:
266
267```cpp
268MATCHER(name) { statements; }
269```
270
271where you can refer to the value being matched as `arg`.  For example,
272given:
273
274```cpp
275MATCHER(IsPositive) { return arg > 0; }
276```
277
278you can use `IsPositive()` as a matcher that matches a value iff it is
279greater than 0.
280
281We will also add `MATCHER_P`, `MATCHER_P2`, and etc for parameterized
282matchers.
283