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.