DesignDoc.md revision 13481
113481Sgiacomo.travaglini@arm.comThis page discusses the design of new Google Mock features.
213481Sgiacomo.travaglini@arm.com
313481Sgiacomo.travaglini@arm.com
413481Sgiacomo.travaglini@arm.com
513481Sgiacomo.travaglini@arm.com# Macros for Defining Actions #
613481Sgiacomo.travaglini@arm.com
713481Sgiacomo.travaglini@arm.com## Problem ##
813481Sgiacomo.travaglini@arm.com
913481Sgiacomo.travaglini@arm.comDue to the lack of closures in C++, it currently requires some
1013481Sgiacomo.travaglini@arm.comnon-trivial effort to define a custom action in Google Mock.  For
1113481Sgiacomo.travaglini@arm.comexample, suppose you want to "increment the value pointed to by the
1213481Sgiacomo.travaglini@arm.comsecond argument of the mock function and return it", you could write:
1313481Sgiacomo.travaglini@arm.com
1413481Sgiacomo.travaglini@arm.com```
1513481Sgiacomo.travaglini@arm.comint IncrementArg1(Unused, int* p, Unused) {
1613481Sgiacomo.travaglini@arm.com  return ++(*p);
1713481Sgiacomo.travaglini@arm.com}
1813481Sgiacomo.travaglini@arm.com
1913481Sgiacomo.travaglini@arm.com... WillOnce(Invoke(IncrementArg1));
2013481Sgiacomo.travaglini@arm.com```
2113481Sgiacomo.travaglini@arm.com
2213481Sgiacomo.travaglini@arm.comThere are several things unsatisfactory about this approach:
2313481Sgiacomo.travaglini@arm.com
2413481Sgiacomo.travaglini@arm.com  * 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.
2513481Sgiacomo.travaglini@arm.com  * The defined action is usable only in mock functions that takes exactly 3 arguments - an unnecessary restriction.
2613481Sgiacomo.travaglini@arm.com  * To use the action, one has to say `Invoke(IncrementArg1)`, which isn't as nice as `IncrementArg1()`.
2713481Sgiacomo.travaglini@arm.com
2813481Sgiacomo.travaglini@arm.comThe latter two problems can be overcome using `MakePolymorphicAction()`,
2913481Sgiacomo.travaglini@arm.combut it requires much more boilerplate code:
3013481Sgiacomo.travaglini@arm.com
3113481Sgiacomo.travaglini@arm.com```
3213481Sgiacomo.travaglini@arm.comclass IncrementArg1Action {
3313481Sgiacomo.travaglini@arm.com public:
3413481Sgiacomo.travaglini@arm.com  template <typename Result, typename ArgumentTuple>
3513481Sgiacomo.travaglini@arm.com  Result Perform(const ArgumentTuple& args) const {
3613481Sgiacomo.travaglini@arm.com    return ++(*tr1::get<1>(args));
3713481Sgiacomo.travaglini@arm.com  }
3813481Sgiacomo.travaglini@arm.com};
3913481Sgiacomo.travaglini@arm.com
4013481Sgiacomo.travaglini@arm.comPolymorphicAction<IncrementArg1Action> IncrementArg1() {
4113481Sgiacomo.travaglini@arm.com  return MakePolymorphicAction(IncrementArg1Action());
4213481Sgiacomo.travaglini@arm.com}
4313481Sgiacomo.travaglini@arm.com
4413481Sgiacomo.travaglini@arm.com... WillOnce(IncrementArg1());
4513481Sgiacomo.travaglini@arm.com```
4613481Sgiacomo.travaglini@arm.com
4713481Sgiacomo.travaglini@arm.comOur goal is to allow defining custom actions with the least amount of
4813481Sgiacomo.travaglini@arm.comboiler-plate C++ requires.
4913481Sgiacomo.travaglini@arm.com
5013481Sgiacomo.travaglini@arm.com## Solution ##
5113481Sgiacomo.travaglini@arm.com
5213481Sgiacomo.travaglini@arm.comWe propose to introduce a new macro:
5313481Sgiacomo.travaglini@arm.com```
5413481Sgiacomo.travaglini@arm.comACTION(name) { statements; }
5513481Sgiacomo.travaglini@arm.com```
5613481Sgiacomo.travaglini@arm.com
5713481Sgiacomo.travaglini@arm.comUsing this in a namespace scope will define an action with the given
5813481Sgiacomo.travaglini@arm.comname that executes the statements.  Inside the statements, you can
5913481Sgiacomo.travaglini@arm.comrefer to the K-th (0-based) argument of the mock function as `argK`.
6013481Sgiacomo.travaglini@arm.comFor example:
6113481Sgiacomo.travaglini@arm.com```
6213481Sgiacomo.travaglini@arm.comACTION(IncrementArg1) { return ++(*arg1); }
6313481Sgiacomo.travaglini@arm.com```
6413481Sgiacomo.travaglini@arm.comallows you to write
6513481Sgiacomo.travaglini@arm.com```
6613481Sgiacomo.travaglini@arm.com... WillOnce(IncrementArg1());
6713481Sgiacomo.travaglini@arm.com```
6813481Sgiacomo.travaglini@arm.com
6913481Sgiacomo.travaglini@arm.comNote that you don't need to specify the types of the mock function
7013481Sgiacomo.travaglini@arm.comarguments, as brevity is a top design goal here.  Rest assured that
7113481Sgiacomo.travaglini@arm.comyour code is still type-safe though: you'll get a compiler error if
7213481Sgiacomo.travaglini@arm.com`*arg1` doesn't support the `++` operator, or if the type of
7313481Sgiacomo.travaglini@arm.com`++(*arg1)` isn't compatible with the mock function's return type.
7413481Sgiacomo.travaglini@arm.com
7513481Sgiacomo.travaglini@arm.comAnother example:
7613481Sgiacomo.travaglini@arm.com```
7713481Sgiacomo.travaglini@arm.comACTION(Foo) {
7813481Sgiacomo.travaglini@arm.com  (*arg2)(5);
7913481Sgiacomo.travaglini@arm.com  Blah();
8013481Sgiacomo.travaglini@arm.com  *arg1 = 0;
8113481Sgiacomo.travaglini@arm.com  return arg0;
8213481Sgiacomo.travaglini@arm.com}
8313481Sgiacomo.travaglini@arm.com```
8413481Sgiacomo.travaglini@arm.comdefines an action `Foo()` that invokes argument #2 (a function pointer)
8513481Sgiacomo.travaglini@arm.comwith 5, calls function `Blah()`, sets the value pointed to by argument
8613481Sgiacomo.travaglini@arm.com#1 to 0, and returns argument #0.
8713481Sgiacomo.travaglini@arm.com
8813481Sgiacomo.travaglini@arm.comFor more convenience and flexibility, you can also use the following
8913481Sgiacomo.travaglini@arm.compre-defined symbols in the body of `ACTION`:
9013481Sgiacomo.travaglini@arm.com
9113481Sgiacomo.travaglini@arm.com| `argK_type` | The type of the K-th (0-based) argument of the mock function |
9213481Sgiacomo.travaglini@arm.com|:------------|:-------------------------------------------------------------|
9313481Sgiacomo.travaglini@arm.com| `args`      | All arguments of the mock function as a tuple                |
9413481Sgiacomo.travaglini@arm.com| `args_type` | The type of all arguments of the mock function as a tuple    |
9513481Sgiacomo.travaglini@arm.com| `return_type` | The return type of the mock function                         |
9613481Sgiacomo.travaglini@arm.com| `function_type` | The type of the mock function                                |
9713481Sgiacomo.travaglini@arm.com
9813481Sgiacomo.travaglini@arm.comFor example, when using an `ACTION` as a stub action for mock function:
9913481Sgiacomo.travaglini@arm.com```
10013481Sgiacomo.travaglini@arm.comint DoSomething(bool flag, int* ptr);
10113481Sgiacomo.travaglini@arm.com```
10213481Sgiacomo.travaglini@arm.comwe have:
10313481Sgiacomo.travaglini@arm.com| **Pre-defined Symbol** | **Is Bound To** |
10413481Sgiacomo.travaglini@arm.com|:-----------------------|:----------------|
10513481Sgiacomo.travaglini@arm.com| `arg0`                 | the value of `flag` |
10613481Sgiacomo.travaglini@arm.com| `arg0_type`            | the type `bool` |
10713481Sgiacomo.travaglini@arm.com| `arg1`                 | the value of `ptr` |
10813481Sgiacomo.travaglini@arm.com| `arg1_type`            | the type `int*` |
10913481Sgiacomo.travaglini@arm.com| `args`                 | the tuple `(flag, ptr)` |
11013481Sgiacomo.travaglini@arm.com| `args_type`            | the type `std::tr1::tuple<bool, int*>` |
11113481Sgiacomo.travaglini@arm.com| `return_type`          | the type `int`  |
11213481Sgiacomo.travaglini@arm.com| `function_type`        | the type `int(bool, int*)` |
11313481Sgiacomo.travaglini@arm.com
11413481Sgiacomo.travaglini@arm.com## Parameterized actions ##
11513481Sgiacomo.travaglini@arm.com
11613481Sgiacomo.travaglini@arm.comSometimes you'll want to parameterize the action.   For that we propose
11713481Sgiacomo.travaglini@arm.comanother macro
11813481Sgiacomo.travaglini@arm.com```
11913481Sgiacomo.travaglini@arm.comACTION_P(name, param) { statements; }
12013481Sgiacomo.travaglini@arm.com```
12113481Sgiacomo.travaglini@arm.com
12213481Sgiacomo.travaglini@arm.comFor example,
12313481Sgiacomo.travaglini@arm.com```
12413481Sgiacomo.travaglini@arm.comACTION_P(Add, n) { return arg0 + n; }
12513481Sgiacomo.travaglini@arm.com```
12613481Sgiacomo.travaglini@arm.comwill allow you to write
12713481Sgiacomo.travaglini@arm.com```
12813481Sgiacomo.travaglini@arm.com// Returns argument #0 + 5.
12913481Sgiacomo.travaglini@arm.com... WillOnce(Add(5));
13013481Sgiacomo.travaglini@arm.com```
13113481Sgiacomo.travaglini@arm.com
13213481Sgiacomo.travaglini@arm.comFor convenience, we use the term _arguments_ for the values used to
13313481Sgiacomo.travaglini@arm.cominvoke the mock function, and the term _parameters_ for the values
13413481Sgiacomo.travaglini@arm.comused to instantiate an action.
13513481Sgiacomo.travaglini@arm.com
13613481Sgiacomo.travaglini@arm.comNote that you don't need to provide the type of the parameter either.
13713481Sgiacomo.travaglini@arm.comSuppose the parameter is named `param`, you can also use the
13813481Sgiacomo.travaglini@arm.comGoogle-Mock-defined symbol `param_type` to refer to the type of the
13913481Sgiacomo.travaglini@arm.comparameter as inferred by the compiler.
14013481Sgiacomo.travaglini@arm.com
14113481Sgiacomo.travaglini@arm.comWe will also provide `ACTION_P2`, `ACTION_P3`, and etc to support
14213481Sgiacomo.travaglini@arm.commulti-parameter actions.  For example,
14313481Sgiacomo.travaglini@arm.com```
14413481Sgiacomo.travaglini@arm.comACTION_P2(ReturnDistanceTo, x, y) {
14513481Sgiacomo.travaglini@arm.com  double dx = arg0 - x;
14613481Sgiacomo.travaglini@arm.com  double dy = arg1 - y;
14713481Sgiacomo.travaglini@arm.com  return sqrt(dx*dx + dy*dy);
14813481Sgiacomo.travaglini@arm.com}
14913481Sgiacomo.travaglini@arm.com```
15013481Sgiacomo.travaglini@arm.comlets you write
15113481Sgiacomo.travaglini@arm.com```
15213481Sgiacomo.travaglini@arm.com... WillOnce(ReturnDistanceTo(5.0, 26.5));
15313481Sgiacomo.travaglini@arm.com```
15413481Sgiacomo.travaglini@arm.com
15513481Sgiacomo.travaglini@arm.comYou can view `ACTION` as a degenerated parameterized action where the
15613481Sgiacomo.travaglini@arm.comnumber of parameters is 0.
15713481Sgiacomo.travaglini@arm.com
15813481Sgiacomo.travaglini@arm.com## Advanced Usages ##
15913481Sgiacomo.travaglini@arm.com
16013481Sgiacomo.travaglini@arm.com### Overloading Actions ###
16113481Sgiacomo.travaglini@arm.com
16213481Sgiacomo.travaglini@arm.comYou can easily define actions overloaded on the number of parameters:
16313481Sgiacomo.travaglini@arm.com```
16413481Sgiacomo.travaglini@arm.comACTION_P(Plus, a) { ... }
16513481Sgiacomo.travaglini@arm.comACTION_P2(Plus, a, b) { ... }
16613481Sgiacomo.travaglini@arm.com```
16713481Sgiacomo.travaglini@arm.com
16813481Sgiacomo.travaglini@arm.com### Restricting the Type of an Argument or Parameter ###
16913481Sgiacomo.travaglini@arm.com
17013481Sgiacomo.travaglini@arm.comFor maximum brevity and reusability, the `ACTION*` macros don't let
17113481Sgiacomo.travaglini@arm.comyou specify the types of the mock function arguments and the action
17213481Sgiacomo.travaglini@arm.comparameters.  Instead, we let the compiler infer the types for us.
17313481Sgiacomo.travaglini@arm.com
17413481Sgiacomo.travaglini@arm.comSometimes, however, we may want to be more explicit about the types.
17513481Sgiacomo.travaglini@arm.comThere are several tricks to do that.  For example:
17613481Sgiacomo.travaglini@arm.com```
17713481Sgiacomo.travaglini@arm.comACTION(Foo) {
17813481Sgiacomo.travaglini@arm.com  // Makes sure arg0 can be converted to int.
17913481Sgiacomo.travaglini@arm.com  int n = arg0;
18013481Sgiacomo.travaglini@arm.com  ... use n instead of arg0 here ...
18113481Sgiacomo.travaglini@arm.com}
18213481Sgiacomo.travaglini@arm.com
18313481Sgiacomo.travaglini@arm.comACTION_P(Bar, param) {
18413481Sgiacomo.travaglini@arm.com  // Makes sure the type of arg1 is const char*.
18513481Sgiacomo.travaglini@arm.com  ::testing::StaticAssertTypeEq<const char*, arg1_type>();
18613481Sgiacomo.travaglini@arm.com
18713481Sgiacomo.travaglini@arm.com  // Makes sure param can be converted to bool.
18813481Sgiacomo.travaglini@arm.com  bool flag = param;
18913481Sgiacomo.travaglini@arm.com}
19013481Sgiacomo.travaglini@arm.com```
19113481Sgiacomo.travaglini@arm.comwhere `StaticAssertTypeEq` is a compile-time assertion we plan to add to
19213481Sgiacomo.travaglini@arm.comGoogle Test (the name is chosen to match `static_assert` in C++0x).
19313481Sgiacomo.travaglini@arm.com
19413481Sgiacomo.travaglini@arm.com### Using the ACTION Object's Type ###
19513481Sgiacomo.travaglini@arm.com
19613481Sgiacomo.travaglini@arm.comIf you are writing a function that returns an `ACTION` object, you'll
19713481Sgiacomo.travaglini@arm.comneed to know its type.  The type depends on the macro used to define
19813481Sgiacomo.travaglini@arm.comthe action and the parameter types.  The rule is relatively simple:
19913481Sgiacomo.travaglini@arm.com| **Given Definition** | **Expression** | **Has Type** |
20013481Sgiacomo.travaglini@arm.com|:---------------------|:---------------|:-------------|
20113481Sgiacomo.travaglini@arm.com| `ACTION(Foo)`        | `Foo()`        | `FooAction`  |
20213481Sgiacomo.travaglini@arm.com| `ACTION_P(Bar, param)` | `Bar(int_value)` | `BarActionP<int>` |
20313481Sgiacomo.travaglini@arm.com| `ACTION_P2(Baz, p1, p2)` | `Baz(bool_value, int_value)` | `BazActionP2<bool, int>` |
20413481Sgiacomo.travaglini@arm.com| ...                  | ...            | ...          |
20513481Sgiacomo.travaglini@arm.com
20613481Sgiacomo.travaglini@arm.comNote that we have to pick different suffixes (`Action`, `ActionP`,
20713481Sgiacomo.travaglini@arm.com`ActionP2`, and etc) for actions with different numbers of parameters,
20813481Sgiacomo.travaglini@arm.comor the action definitions cannot be overloaded on the number of
20913481Sgiacomo.travaglini@arm.comparameters.
21013481Sgiacomo.travaglini@arm.com
21113481Sgiacomo.travaglini@arm.com## When to Use ##
21213481Sgiacomo.travaglini@arm.com
21313481Sgiacomo.travaglini@arm.comWhile the new macros are very convenient, please also consider other
21413481Sgiacomo.travaglini@arm.commeans of implementing actions (e.g. via `ActionInterface` or
21513481Sgiacomo.travaglini@arm.com`MakePolymorphicAction()`), especially if you need to use the defined
21613481Sgiacomo.travaglini@arm.comaction a lot.  While the other approaches require more work, they give
21713481Sgiacomo.travaglini@arm.comyou more control on the types of the mock function arguments and the
21813481Sgiacomo.travaglini@arm.comaction parameters, which in general leads to better compiler error
21913481Sgiacomo.travaglini@arm.commessages that pay off in the long run.  They also allow overloading
22013481Sgiacomo.travaglini@arm.comactions based on parameter types, as opposed to just the number of
22113481Sgiacomo.travaglini@arm.comparameters.
22213481Sgiacomo.travaglini@arm.com
22313481Sgiacomo.travaglini@arm.com## Related Work ##
22413481Sgiacomo.travaglini@arm.com
22513481Sgiacomo.travaglini@arm.comAs you may have realized, the `ACTION*` macros resemble closures (also
22613481Sgiacomo.travaglini@arm.comknown as lambda expressions or anonymous functions).  Indeed, both of
22713481Sgiacomo.travaglini@arm.comthem seek to lower the syntactic overhead for defining a function.
22813481Sgiacomo.travaglini@arm.com
22913481Sgiacomo.travaglini@arm.comC++0x will support lambdas, but they are not part of C++ right now.
23013481Sgiacomo.travaglini@arm.comSome non-standard libraries (most notably BLL or Boost Lambda Library)
23113481Sgiacomo.travaglini@arm.comtry to alleviate this problem.  However, they are not a good choice
23213481Sgiacomo.travaglini@arm.comfor defining actions as:
23313481Sgiacomo.travaglini@arm.com
23413481Sgiacomo.travaglini@arm.com  * 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.
23513481Sgiacomo.travaglini@arm.com  * They are not trivial to learn.
23613481Sgiacomo.travaglini@arm.com  * 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.
23713481Sgiacomo.travaglini@arm.com  * 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.
23813481Sgiacomo.travaglini@arm.com  * 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.
23913481Sgiacomo.travaglini@arm.com
24013481Sgiacomo.travaglini@arm.com`ACTION*` avoid all these problems.
24113481Sgiacomo.travaglini@arm.com
24213481Sgiacomo.travaglini@arm.com## Future Improvements ##
24313481Sgiacomo.travaglini@arm.com
24413481Sgiacomo.travaglini@arm.comThere may be a need for composing `ACTION*` definitions (i.e. invoking
24513481Sgiacomo.travaglini@arm.comanother `ACTION` inside the definition of one `ACTION*`).  We are not
24613481Sgiacomo.travaglini@arm.comsure we want it yet, as one can get a similar effect by putting
24713481Sgiacomo.travaglini@arm.com`ACTION` definitions in function templates and composing the function
24813481Sgiacomo.travaglini@arm.comtemplates.  We'll revisit this based on user feedback.
24913481Sgiacomo.travaglini@arm.com
25013481Sgiacomo.travaglini@arm.comThe reason we don't allow `ACTION*()` inside a function body is that
25113481Sgiacomo.travaglini@arm.comthe current C++ standard doesn't allow function-local types to be used
25213481Sgiacomo.travaglini@arm.comto instantiate templates.  The upcoming C++0x standard will lift this
25313481Sgiacomo.travaglini@arm.comrestriction.  Once this feature is widely supported by compilers, we
25413481Sgiacomo.travaglini@arm.comcan revisit the implementation and add support for using `ACTION*()`
25513481Sgiacomo.travaglini@arm.cominside a function.
25613481Sgiacomo.travaglini@arm.com
25713481Sgiacomo.travaglini@arm.comC++0x will also support lambda expressions.  When they become
25813481Sgiacomo.travaglini@arm.comavailable, we may want to support using lambdas as actions.
25913481Sgiacomo.travaglini@arm.com
26013481Sgiacomo.travaglini@arm.com# Macros for Defining Matchers #
26113481Sgiacomo.travaglini@arm.com
26213481Sgiacomo.travaglini@arm.comOnce the macros for defining actions are implemented, we plan to do
26313481Sgiacomo.travaglini@arm.comthe same for matchers:
26413481Sgiacomo.travaglini@arm.com
26513481Sgiacomo.travaglini@arm.com```
26613481Sgiacomo.travaglini@arm.comMATCHER(name) { statements; }
26713481Sgiacomo.travaglini@arm.com```
26813481Sgiacomo.travaglini@arm.com
26913481Sgiacomo.travaglini@arm.comwhere you can refer to the value being matched as `arg`.  For example,
27013481Sgiacomo.travaglini@arm.comgiven:
27113481Sgiacomo.travaglini@arm.com
27213481Sgiacomo.travaglini@arm.com```
27313481Sgiacomo.travaglini@arm.comMATCHER(IsPositive) { return arg > 0; }
27413481Sgiacomo.travaglini@arm.com```
27513481Sgiacomo.travaglini@arm.com
27613481Sgiacomo.travaglini@arm.comyou can use `IsPositive()` as a matcher that matches a value iff it is
27713481Sgiacomo.travaglini@arm.comgreater than 0.
27813481Sgiacomo.travaglini@arm.com
27913481Sgiacomo.travaglini@arm.comWe will also add `MATCHER_P`, `MATCHER_P2`, and etc for parameterized
28013481Sgiacomo.travaglini@arm.commatchers.