From 382cdf9162dd335b71f1e47e6be8244710c3c683 Mon Sep 17 00:00:00 2001 From: Krystian Kuzniarek <krystian.kuzniarek@gmail.com> Date: Sat, 13 Jul 2019 07:59:14 +0200 Subject: rename and apply snake_case on DesignDoc.md --- googlemock/docs/DesignDoc.md | 282 ------------------------------------------ googlemock/docs/design_doc.md | 282 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 282 insertions(+), 282 deletions(-) delete mode 100644 googlemock/docs/DesignDoc.md create mode 100644 googlemock/docs/design_doc.md diff --git a/googlemock/docs/DesignDoc.md b/googlemock/docs/DesignDoc.md deleted file mode 100644 index 4cddc9d..0000000 --- a/googlemock/docs/DesignDoc.md +++ /dev/null @@ -1,282 +0,0 @@ -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: - -```cpp -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: - -```cpp -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: -```cpp -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: -```cpp -ACTION(IncrementArg1) { return ++(*arg1); } -``` -allows you to write -```cpp -... 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: -```cpp -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`: - -| Argument | Description | -|:----------------|:-------------------------------------------------------------| -| `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: -```cpp -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 -```cpp -ACTION_P(name, param) { statements; } -``` - -For example, -```cpp -ACTION_P(Add, n) { return arg0 + n; } -``` -will allow you to write -```cpp -// 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, -```cpp -ACTION_P2(ReturnDistanceTo, x, y) { - double dx = arg0 - x; - double dy = arg1 - y; - return sqrt(dx*dx + dy*dy); -} -``` -lets you write -```cpp -... 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: -```cpp -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: -```cpp -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: - -```cpp -MATCHER(name) { statements; } -``` - -where you can refer to the value being matched as `arg`. For example, -given: - -```cpp -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. diff --git a/googlemock/docs/design_doc.md b/googlemock/docs/design_doc.md new file mode 100644 index 0000000..4cddc9d --- /dev/null +++ b/googlemock/docs/design_doc.md @@ -0,0 +1,282 @@ +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: + +```cpp +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: + +```cpp +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: +```cpp +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: +```cpp +ACTION(IncrementArg1) { return ++(*arg1); } +``` +allows you to write +```cpp +... 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: +```cpp +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`: + +| Argument | Description | +|:----------------|:-------------------------------------------------------------| +| `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: +```cpp +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 +```cpp +ACTION_P(name, param) { statements; } +``` + +For example, +```cpp +ACTION_P(Add, n) { return arg0 + n; } +``` +will allow you to write +```cpp +// 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, +```cpp +ACTION_P2(ReturnDistanceTo, x, y) { + double dx = arg0 - x; + double dy = arg1 - y; + return sqrt(dx*dx + dy*dy); +} +``` +lets you write +```cpp +... 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: +```cpp +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: +```cpp +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: + +```cpp +MATCHER(name) { statements; } +``` + +where you can refer to the value being matched as `arg`. For example, +given: + +```cpp +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. -- cgit v0.12