Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
yangql
googletest
Commits
326aa564
Commit
326aa564
authored
Jan 09, 2009
by
shiqian
Browse files
Implements the ACTION* macros.
parent
44a8cf19
Changes
3
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
1518 additions
and
0 deletions
+1518
-0
include/gmock/gmock-generated-actions.h
include/gmock/gmock-generated-actions.h
+972
-0
include/gmock/gmock-generated-actions.h.pump
include/gmock/gmock-generated-actions.h.pump
+208
-0
test/gmock-generated-actions_test.cc
test/gmock-generated-actions_test.cc
+338
-0
No files found.
include/gmock/gmock-generated-actions.h
View file @
326aa564
This diff is collapsed.
Click to expand it.
include/gmock/gmock-generated-actions.h.pump
View file @
326aa564
...
...
@@ -395,6 +395,49 @@ class DoBothAction {
Action2
action2_
;
};
// A macro from the ACTION* family (defined later in this file)
// defines an action that can be used in a mock function. Typically,
// these actions only care about a subset of the arguments of the mock
// function. For example, if such an action only uses the second
// argument, it can be used in any mock function that takes >= 2
// arguments where the type of the second argument is compatible.
//
// Therefore, the action implementation must be prepared to take more
// arguments than it needs. The ExcessiveArg type is used to
// represent those excessive arguments. In order to keep the compiler
// error messages tractable, we define it in the testing namespace
// instead of testing::internal. However, this is an INTERNAL TYPE
// and subject to change without notice, so a user MUST NOT USE THIS
// TYPE DIRECTLY.
struct
ExcessiveArg
{};
// A helper class needed for implementing the ACTION* macros.
template
<
typename
Result
,
class
Impl
>
class
ActionHelper
{
public:
$
range
i
0.
.
n
$
for
i
[[
$
var
template
=
[[
$
if
i
==
0
[[]]
$
else
[[
$
range
j
0.
.
i
-
1
template
<
$
for
j
,
[[
typename
A
$
j
]]>
]]]]
$
range
j
0.
.
i
-
1
$
var
As
=
[[
$
for
j
,
[[
A
$
j
]]]]
$
var
as
=
[[
$
for
j
,
[[
get
<
$
j
>(
args
)]]]]
$
range
k
1.
.
n
-
i
$
var
eas
=
[[
$
for
k
,
[[
ExcessiveArg
()]]]]
$
var
arg_list
=
[[
$
if
(
i
==
0
)
|
(
i
==
n
)
[[
$
as
$
eas
]]
$
else
[[
$
as
,
$
eas
]]]]
$
template
static
Result
Perform
(
Impl
*
impl
,
const
::
std
::
tr1
::
tuple
<
$
As
>
&
args
)
{
using
::
std
::
tr1
::
get
;
return
impl
->
gmock_PerformImpl
(
args
,
$
arg_list
);
}
]]
};
}
// namespace internal
// Various overloads for Invoke().
...
...
@@ -564,4 +607,169 @@ $range j2 2..i
}
// namespace testing
// The ACTION* family of macros can be used in a namespace scope to
// define custom actions easily. The syntax:
//
// ACTION(name) { statements; }
//
// will define an action with the given name that executes the
// statements. The value returned by the statements will be used as
// the return value of the action. Inside the statements, you can
// refer to the K-th (0-based) argument of the mock function by
// 'argK', and refer to its type by 'argK_type'. For example:
//
// ACTION(IncrementArg1) {
// arg1_type temp = arg1;
// return ++(*temp);
// }
//
// allows you to write
//
// ...WillOnce(IncrementArg1());
//
// You can also refer to the entire argument tuple and its type by
// 'args' and 'args_type', and refer to the mock function type and its
// return type by 'function_type' and 'return_type'.
//
// Note that you don't need to specify the types of the mock function
// arguments. However rest assured that your code is still type-safe:
// 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, for example.
//
// Sometimes you'll want to parameterize the action. For that you can use
// another macro:
//
// ACTION_P(name, param_name) { statements; }
//
// For example:
//
// ACTION_P(Add, n) { return arg0 + n; }
//
// will allow you to write:
//
// ...WillOnce(Add(5));
//
// Note that you don't need to provide the type of the parameter
// either. If you need to reference the type of a parameter named
// 'foo', you can write 'foo_type'. For example, in the body of
// ACTION_P(Add, n) above, you can write 'n_type' to refer to the type
// of 'n'.
//
// We also provide ACTION_P2, ACTION_P3, ..., up to ACTION_P$n to support
// multi-parameter actions.
//
// For the purpose of typing, you can view
//
// ACTION_Pk(Foo, p1, ..., pk) { ... }
//
// as shorthand for
//
// template <typename p1_type, ..., typename pk_type>
// FooActionPk<p1_type, ..., pk_type> Foo(p1_type p1, ..., pk_type pk) { ... }
//
// In particular, you can provide the template type arguments
// explicitly when invoking Foo(), as in Foo<long, bool>(5, false);
// although usually you can rely on the compiler to infer the types
// for you automatically. You can assign the result of expression
// Foo(p1, ..., pk) to a variable of type FooActionPk<p1_type, ...,
// pk_type>. This can be useful when composing actions.
//
// You can also overload actions with different numbers of parameters:
//
// ACTION_P(Plus, a) { ... }
// ACTION_P2(Plus, a, b) { ... }
//
// While it's tempting to always use the ACTION* macros when defining
// a new action, you should also consider implementing ActionInterface
// or using MakePolymorphicAction() instead, especially if you need to
// use the action a lot. While these 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 based on the number of parameters).
//
// CAVEAT:
//
// ACTION*() can only be used in a namespace scope. The reason is
// that C++ doesn't yet allow function-local types to be used to
// instantiate templates. The up-coming C++0x standard will fix this.
// Once that's done, we'll consider supporting using ACTION*() inside
// a function.
//
// MORE INFORMATION:
//
// To learn more about using these macros, please search for 'ACTION'
// on http://code.google.com/p/googlemock/wiki/CookBook.
$
range
i
0.
.
n
$
for
i
[[
$
var
template
=
[[
$
if
i
==
0
[[]]
$
else
[[
$
range
j
0.
.
i
-
1
template
<
$
for
j
,
[[
typename
p
$
j
##
_type
]]>
\
]]]]
$
var
class_name
=
[[
name
##
Action
[[
$
if
i
==
0
[[]]
$
elif
i
==
1
[[
P
]]
$
else
[[
P
$
i
]]]]]]
$
range
j
0.
.
i
-
1
$
var
ctor_param_list
=
[[
$
for
j
,
[[
p
$
j
##
_type
gmock_p
$
j
]]]]
$
var
param_types_and_names
=
[[
$
for
j
,
[[
p
$
j
##
_type
p
$
j
]]]]
$
var
inits
=
[[
$
if
i
==
0
[[]]
$
else
[[
:
$
for
j
,
[[
p
$
j
(
gmock_p
$
j
)]]]]]]
$
var
const_param_field_decls
=
[[
$
for
j
[[
const
p
$
j
##
_type
p
$
j
;
\
]]]]
$
var
const_param_field_decls2
=
[[
$
for
j
[[
const
p
$
j
##
_type
p
$
j
;
\
]]]]
$
var
params
=
[[
$
for
j
,
[[
p
$
j
]]]]
$
var
param_types
=
[[
$
if
i
==
0
[[]]
$
else
[[
<
$
for
j
,
[[
p
$
j
##
_type
]]
>
]]]]
$
range
k
0.
.
n
-
1
$
var
typename_arg_types
=
[[
$
for
k
,
[[
typename
arg
$
k
[[]]
_type
]]]]
$
var
arg_types_and_names
=
[[
$
for
k
,
[[
arg
$
k
[[]]
_type
arg
$
k
]]]]
$
var
macro_name
=
[[
$
if
i
==
0
[[
ACTION
]]
$
elif
i
==
1
[[
ACTION_P
]]
$
else
[[
ACTION_P
$
i
]]]]
#define $macro_name(name$for j [[, p$j]])\$template
class
$
class_name
{
\
public
:
\
$
class_name
(
$
ctor_param_list
)
$
inits
{}
\
template
<
typename
F
>
\
class
gmock_Impl
:
public
::
testing
::
ActionInterface
<
F
>
{
\
public
:
\
typedef
F
function_type
;
\
typedef
typename
::
testing
::
internal
::
Function
<
F
>::
Result
return_type
;
\
typedef
typename
::
testing
::
internal
::
Function
<
F
>::
ArgumentTuple
\
args_type
;
\
[[
$
if
i
==
1
[[
explicit
]]]]
gmock_Impl
(
$
ctor_param_list
)
$
inits
{}
\
virtual
return_type
Perform
(
const
args_type
&
args
)
{
\
return
::
testing
::
internal
::
ActionHelper
<
return_type
,
gmock_Impl
>::
\
Perform
(
this
,
args
);
\
}
\
template
<
$
typename_arg_types
>
\
return_type
gmock_PerformImpl
(
const
args_type
&
args
,
[[]]
$
arg_types_and_names
)
const
;
\$
const_param_field_decls
};
\
template
<
typename
F
>
operator
::
testing
::
Action
<
F
>
()
const
{
\
return
::
testing
::
Action
<
F
>
(
new
gmock_Impl
<
F
>
(
$
params
));
\
}
\$
const_param_field_decls2
};
\$
template
inline
$
class_name
$
param_types
name
(
$
param_types_and_names
)
{
\
return
$
class_name
$
param_types
(
$
params
);
\
}\$
template
template
<
typename
F
>
\
template
<
$
typename_arg_types
>
\
typename
::
testing
::
internal
::
Function
<
F
>
::
Result
\
$
class_name
$
param_types
::
\
gmock_Impl
<
F
>::
gmock_PerformImpl
(
const
args_type
&
args
,
[[]]
$
arg_types_and_names
)
const
]]
#endif // GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_ACTIONS_H_
test/gmock-generated-actions_test.cc
View file @
326aa564
...
...
@@ -58,6 +58,7 @@ using testing::Invoke;
using
testing
::
InvokeArgument
;
using
testing
::
Return
;
using
testing
::
SetArgumentPointee
;
using
testing
::
StaticAssertTypeEq
;
using
testing
::
Unused
;
using
testing
::
WithArg
;
using
testing
::
WithArgs
;
...
...
@@ -942,5 +943,342 @@ TEST(DoAllTest, TenActions) {
EXPECT_EQ
(
'g'
,
g
);
}
// Tests the ACTION*() macro family.
// Tests that ACTION() can define an action that doesn't reference the
// mock function arguments.
ACTION
(
Return5
)
{
return
5
;
}
TEST
(
ActionMacroTest
,
WorksWhenNotReferencingArguments
)
{
Action
<
double
()
>
a1
=
Return5
();
EXPECT_DOUBLE_EQ
(
5
,
a1
.
Perform
(
make_tuple
()));
Action
<
int
(
double
,
bool
)
>
a2
=
Return5
();
EXPECT_EQ
(
5
,
a2
.
Perform
(
make_tuple
(
1
,
true
)));
}
// Tests that ACTION() can define an action that returns void.
ACTION
(
IncrementArg1
)
{
(
*
arg1
)
++
;
}
TEST
(
ActionMacroTest
,
WorksWhenReturningVoid
)
{
Action
<
void
(
int
,
int
*
)
>
a1
=
IncrementArg1
();
int
n
=
0
;
a1
.
Perform
(
make_tuple
(
5
,
&
n
));
EXPECT_EQ
(
1
,
n
);
}
// Tests that the body of ACTION() can reference the type of the
// argument.
ACTION
(
IncrementArg2
)
{
StaticAssertTypeEq
<
int
*
,
arg2_type
>
();
arg2_type
temp
=
arg2
;
(
*
temp
)
++
;
}
TEST
(
ActionMacroTest
,
CanReferenceArgumentType
)
{
Action
<
void
(
int
,
bool
,
int
*
)
>
a1
=
IncrementArg2
();
int
n
=
0
;
a1
.
Perform
(
make_tuple
(
5
,
false
,
&
n
));
EXPECT_EQ
(
1
,
n
);
}
// Tests that the body of ACTION() can reference the argument tuple
// via args_type and args.
ACTION
(
Sum2
)
{
StaticAssertTypeEq
<
::
std
::
tr1
::
tuple
<
int
,
char
,
int
*>
,
args_type
>
();
args_type
args_copy
=
args
;
return
get
<
0
>
(
args_copy
)
+
get
<
1
>
(
args_copy
);
}
TEST
(
ActionMacroTest
,
CanReferenceArgumentTuple
)
{
Action
<
int
(
int
,
char
,
int
*
)
>
a1
=
Sum2
();
int
dummy
=
0
;
EXPECT_EQ
(
11
,
a1
.
Perform
(
make_tuple
(
5
,
static_cast
<
char
>
(
6
),
&
dummy
)));
}
// Tests that the body of ACTION() can reference the mock function
// type.
int
Dummy
(
bool
flag
)
{
return
flag
?
1
:
0
;
}
ACTION
(
InvokeDummy
)
{
StaticAssertTypeEq
<
int
(
bool
),
function_type
>
();
function_type
*
fp
=
&
Dummy
;
return
(
*
fp
)(
true
);
}
TEST
(
ActionMacroTest
,
CanReferenceMockFunctionType
)
{
Action
<
int
(
bool
)
>
a1
=
InvokeDummy
();
EXPECT_EQ
(
1
,
a1
.
Perform
(
make_tuple
(
true
)));
EXPECT_EQ
(
1
,
a1
.
Perform
(
make_tuple
(
false
)));
}
// Tests that the body of ACTION() can reference the mock function's
// return type.
ACTION
(
InvokeDummy2
)
{
StaticAssertTypeEq
<
int
,
return_type
>
();
return_type
result
=
Dummy
(
true
);
return
result
;
}
TEST
(
ActionMacroTest
,
CanReferenceMockFunctionReturnType
)
{
Action
<
int
(
bool
)
>
a1
=
InvokeDummy2
();
EXPECT_EQ
(
1
,
a1
.
Perform
(
make_tuple
(
true
)));
EXPECT_EQ
(
1
,
a1
.
Perform
(
make_tuple
(
false
)));
}
// Tests that ACTION() can be used in a namespace.
namespace
action_test
{
ACTION
(
Sum
)
{
return
arg0
+
arg1
;
}
}
// namespace action_test
TEST
(
ActionMacroTest
,
WorksInNamespace
)
{
Action
<
int
(
int
,
int
)
>
a1
=
action_test
::
Sum
();
EXPECT_EQ
(
3
,
a1
.
Perform
(
make_tuple
(
1
,
2
)));
}
// Tests that the same ACTION definition works for mock functions with
// different argument numbers.
ACTION
(
PlusTwo
)
{
return
arg0
+
2
;
}
TEST
(
ActionMacroTest
,
WorksForDifferentArgumentNumbers
)
{
Action
<
int
(
int
)
>
a1
=
PlusTwo
();
EXPECT_EQ
(
4
,
a1
.
Perform
(
make_tuple
(
2
)));
Action
<
double
(
float
,
void
*
)
>
a2
=
PlusTwo
();
int
dummy
;
EXPECT_DOUBLE_EQ
(
6
,
a2
.
Perform
(
make_tuple
(
4.0
f
,
&
dummy
)));
}
// Tests that ACTION_P can define a parameterized action.
ACTION_P
(
Plus
,
n
)
{
return
arg0
+
n
;
}
TEST
(
ActionPMacroTest
,
DefinesParameterizedAction
)
{
Action
<
int
(
int
m
,
bool
t
)
>
a1
=
Plus
(
9
);
EXPECT_EQ
(
10
,
a1
.
Perform
(
make_tuple
(
1
,
true
)));
}
// Tests that the body of ACTION_P can reference the argument types
// and the parameter type.
ACTION_P
(
TypedPlus
,
n
)
{
arg0_type
t1
=
arg0
;
n_type
t2
=
n
;
return
t1
+
t2
;
}
TEST
(
ActionPMacroTest
,
CanReferenceArgumentAndParameterTypes
)
{
Action
<
int
(
char
m
,
bool
t
)
>
a1
=
TypedPlus
(
9
);
EXPECT_EQ
(
10
,
a1
.
Perform
(
make_tuple
(
static_cast
<
char
>
(
1
),
true
)));
}
// Tests that a parameterized action can be used in any mock function
// whose type is compatible.
TEST
(
ActionPMacroTest
,
WorksInCompatibleMockFunction
)
{
Action
<
std
::
string
(
const
std
::
string
&
s
)
>
a1
=
Plus
(
"tail"
);
const
std
::
string
re
=
"re"
;
EXPECT_EQ
(
"retail"
,
a1
.
Perform
(
make_tuple
(
re
)));
}
// Tests that we can use ACTION*() to define actions overloaded on the
// number of parameters.
ACTION
(
OverloadedAction
)
{
return
arg0
?
arg1
:
"hello"
;
}
ACTION_P
(
OverloadedAction
,
default_value
)
{
return
arg0
?
arg1
:
default_value
;
}
ACTION_P2
(
OverloadedAction
,
true_value
,
false_value
)
{
return
arg0
?
true_value
:
false_value
;
}
TEST
(
ActionMacroTest
,
CanDefineOverloadedActions
)
{
typedef
Action
<
const
char
*
(
bool
,
const
char
*
)
>
MyAction
;
const
MyAction
a1
=
OverloadedAction
();
EXPECT_STREQ
(
"hello"
,
a1
.
Perform
(
make_tuple
(
false
,
"world"
)));
EXPECT_STREQ
(
"world"
,
a1
.
Perform
(
make_tuple
(
true
,
"world"
)));
const
MyAction
a2
=
OverloadedAction
(
"hi"
);
EXPECT_STREQ
(
"hi"
,
a2
.
Perform
(
make_tuple
(
false
,
"world"
)));
EXPECT_STREQ
(
"world"
,
a2
.
Perform
(
make_tuple
(
true
,
"world"
)));
const
MyAction
a3
=
OverloadedAction
(
"hi"
,
"you"
);
EXPECT_STREQ
(
"hi"
,
a3
.
Perform
(
make_tuple
(
true
,
"world"
)));
EXPECT_STREQ
(
"you"
,
a3
.
Perform
(
make_tuple
(
false
,
"world"
)));
}
// Tests ACTION_Pn where n >= 3.
ACTION_P3
(
Plus
,
m
,
n
,
k
)
{
return
arg0
+
m
+
n
+
k
;
}
TEST
(
ActionPnMacroTest
,
WorksFor3Parameters
)
{
Action
<
double
(
int
m
,
bool
t
)
>
a1
=
Plus
(
100
,
20
,
3.4
);
EXPECT_DOUBLE_EQ
(
3123.4
,
a1
.
Perform
(
make_tuple
(
3000
,
true
)));
Action
<
std
::
string
(
const
std
::
string
&
s
)
>
a2
=
Plus
(
"tail"
,
"-"
,
">"
);
const
std
::
string
re
=
"re"
;
EXPECT_EQ
(
"retail->"
,
a2
.
Perform
(
make_tuple
(
re
)));
}
ACTION_P4
(
Plus
,
p0
,
p1
,
p2
,
p3
)
{
return
arg0
+
p0
+
p1
+
p2
+
p3
;
}
TEST
(
ActionPnMacroTest
,
WorksFor4Parameters
)
{
Action
<
int
(
int
)
>
a1
=
Plus
(
1
,
2
,
3
,
4
);
EXPECT_EQ
(
10
+
1
+
2
+
3
+
4
,
a1
.
Perform
(
make_tuple
(
10
)));
}
ACTION_P5
(
Plus
,
p0
,
p1
,
p2
,
p3
,
p4
)
{
return
arg0
+
p0
+
p1
+
p2
+
p3
+
p4
;
}
TEST
(
ActionPnMacroTest
,
WorksFor5Parameters
)
{
Action
<
int
(
int
)
>
a1
=
Plus
(
1
,
2
,
3
,
4
,
5
);
EXPECT_EQ
(
10
+
1
+
2
+
3
+
4
+
5
,
a1
.
Perform
(
make_tuple
(
10
)));
}
ACTION_P6
(
Plus
,
p0
,
p1
,
p2
,
p3
,
p4
,
p5
)
{
return
arg0
+
p0
+
p1
+
p2
+
p3
+
p4
+
p5
;
}
TEST
(
ActionPnMacroTest
,
WorksFor6Parameters
)
{
Action
<
int
(
int
)
>
a1
=
Plus
(
1
,
2
,
3
,
4
,
5
,
6
);
EXPECT_EQ
(
10
+
1
+
2
+
3
+
4
+
5
+
6
,
a1
.
Perform
(
make_tuple
(
10
)));
}
ACTION_P7
(
Plus
,
p0
,
p1
,
p2
,
p3
,
p4
,
p5
,
p6
)
{
return
arg0
+
p0
+
p1
+
p2
+
p3
+
p4
+
p5
+
p6
;
}
TEST
(
ActionPnMacroTest
,
WorksFor7Parameters
)
{
Action
<
int
(
int
)
>
a1
=
Plus
(
1
,
2
,
3
,
4
,
5
,
6
,
7
);
EXPECT_EQ
(
10
+
1
+
2
+
3
+
4
+
5
+
6
+
7
,
a1
.
Perform
(
make_tuple
(
10
)));
}
ACTION_P8
(
Plus
,
p0
,
p1
,
p2
,
p3
,
p4
,
p5
,
p6
,
p7
)
{
return
arg0
+
p0
+
p1
+
p2
+
p3
+
p4
+
p5
+
p6
+
p7
;
}
TEST
(
ActionPnMacroTest
,
WorksFor8Parameters
)
{
Action
<
int
(
int
)
>
a1
=
Plus
(
1
,
2
,
3
,
4
,
5
,
6
,
7
,
8
);
EXPECT_EQ
(
10
+
1
+
2
+
3
+
4
+
5
+
6
+
7
+
8
,
a1
.
Perform
(
make_tuple
(
10
)));
}
ACTION_P9
(
Plus
,
p0
,
p1
,
p2
,
p3
,
p4
,
p5
,
p6
,
p7
,
p8
)
{
return
arg0
+
p0
+
p1
+
p2
+
p3
+
p4
+
p5
+
p6
+
p7
+
p8
;
}
TEST
(
ActionPnMacroTest
,
WorksFor9Parameters
)
{
Action
<
int
(
int
)
>
a1
=
Plus
(
1
,
2
,
3
,
4
,
5
,
6
,
7
,
8
,
9
);
EXPECT_EQ
(
10
+
1
+
2
+
3
+
4
+
5
+
6
+
7
+
8
+
9
,
a1
.
Perform
(
make_tuple
(
10
)));
}
ACTION_P10
(
Plus
,
p0
,
p1
,
p2
,
p3
,
p4
,
p5
,
p6
,
p7
,
p8
,
last_param
)
{
arg0_type
t0
=
arg0
;
last_param_type
t9
=
last_param
;
return
t0
+
p0
+
p1
+
p2
+
p3
+
p4
+
p5
+
p6
+
p7
+
p8
+
t9
;
}
TEST
(
ActionPnMacroTest
,
WorksFor10Parameters
)
{
Action
<
int
(
int
)
>
a1
=
Plus
(
1
,
2
,
3
,
4
,
5
,
6
,
7
,
8
,
9
,
10
);
EXPECT_EQ
(
10
+
1
+
2
+
3
+
4
+
5
+
6
+
7
+
8
+
9
+
10
,
a1
.
Perform
(
make_tuple
(
10
)));
}
// Tests that the action body can promote the parameter types.
ACTION_P2
(
PadArgument
,
prefix
,
suffix
)
{
// The following lines promote the two parameters to desired types.
std
::
string
prefix_str
(
prefix
);
char
suffix_char
(
suffix
);
return
prefix_str
+
arg0
+
suffix_char
;
}
TEST
(
ActionPnMacroTest
,
SimpleTypePromotion
)
{
Action
<
std
::
string
(
const
char
*
)
>
no_promo
=
PadArgument
(
std
::
string
(
"foo"
),
'r'
);
Action
<
std
::
string
(
const
char
*
)
>
promo
=
PadArgument
(
"foo"
,
static_cast
<
int
>
(
'r'
));
EXPECT_EQ
(
"foobar"
,
no_promo
.
Perform
(
make_tuple
(
"ba"
)));
EXPECT_EQ
(
"foobar"
,
promo
.
Perform
(
make_tuple
(
"ba"
)));
}
// Tests that we can partially restrict parameter types using a
// straight-forward pattern.
// Defines a generic action that doesn't restrict the types of its
// parameters.
ACTION_P3
(
ConcatImpl
,
a
,
b
,
c
)
{
std
::
stringstream
ss
;
ss
<<
a
<<
b
<<
c
;
return
ss
.
str
();
}
// Next, we try to restrict that either the first parameter is a
// string, or the second parameter is an int.
// Defines a partially specialized wrapper that restricts the first
// parameter to std::string.
template
<
typename
T1
,
typename
T2
>
// ConcatImplActionP3 is the class template ACTION_P3 uses to
// implement ConcatImpl. We shouldn't change the name as this
// pattern requires the user to use it directly.
ConcatImplActionP3
<
std
::
string
,
T1
,
T2
>
Concat
(
const
std
::
string
&
a
,
T1
b
,
T2
c
)
{
if
(
true
)
{
// This branch verifies that ConcatImpl() can be invoked without
// explicit template arguments.
return
ConcatImpl
(
a
,
b
,
c
);
}
else
{
// This branch verifies that ConcatImpl() can also be invoked with
// explicit template arguments. It doesn't really need to be
// executed as this is a compile-time verification.
return
ConcatImpl
<
std
::
string
,
T1
,
T2
>
(
a
,
b
,
c
);
}
}
// Defines another partially specialized wrapper that restricts the
// second parameter to int.
template
<
typename
T1
,
typename
T2
>
ConcatImplActionP3
<
T1
,
int
,
T2
>
Concat
(
T1
a
,
int
b
,
T2
c
)
{
return
ConcatImpl
(
a
,
b
,
c
);
}
TEST
(
ActionPnMacroTest
,
CanPartiallyRestrictParameterTypes
)
{
Action
<
const
std
::
string
()
>
a1
=
Concat
(
"Hello"
,
"1"
,
2
);
EXPECT_EQ
(
"Hello12"
,
a1
.
Perform
(
make_tuple
()));
a1
=
Concat
(
1
,
2
,
3
);
EXPECT_EQ
(
"123"
,
a1
.
Perform
(
make_tuple
()));
}
// Verifies the type of an ACTION*.
ACTION
(
DoFoo
)
{}
ACTION_P
(
DoFoo
,
p
)
{}
ACTION_P2
(
DoFoo
,
p0
,
p1
)
{}
TEST
(
ActionPnMacroTest
,
TypesAreCorrect
)
{
// DoFoo() must be assignable to a DoFooAction variable.
DoFooAction
a0
=
DoFoo
();
// DoFoo(1) must be assignable to a DoFooActionP variable.
DoFooActionP
<
int
>
a1
=
DoFoo
(
1
);
// DoFoo(p1, ..., pk) must be assignable to a DoFooActionPk
// variable, and so on.
DoFooActionP2
<
int
,
char
>
a2
=
DoFoo
(
1
,
'2'
);
PlusActionP3
<
int
,
int
,
char
>
a3
=
Plus
(
1
,
2
,
'3'
);
PlusActionP4
<
int
,
int
,
int
,
char
>
a4
=
Plus
(
1
,
2
,
3
,
'4'
);
PlusActionP5
<
int
,
int
,
int
,
int
,
char
>
a5
=
Plus
(
1
,
2
,
3
,
4
,
'5'
);
PlusActionP6
<
int
,
int
,
int
,
int
,
int
,
char
>
a6
=
Plus
(
1
,
2
,
3
,
4
,
5
,
'6'
);
PlusActionP7
<
int
,
int
,
int
,
int
,
int
,
int
,
char
>
a7
=
Plus
(
1
,
2
,
3
,
4
,
5
,
6
,
'7'
);
PlusActionP8
<
int
,
int
,
int
,
int
,
int
,
int
,
int
,
char
>
a8
=
Plus
(
1
,
2
,
3
,
4
,
5
,
6
,
7
,
'8'
);
PlusActionP9
<
int
,
int
,
int
,
int
,
int
,
int
,
int
,
int
,
char
>
a9
=
Plus
(
1
,
2
,
3
,
4
,
5
,
6
,
7
,
8
,
'9'
);
PlusActionP10
<
int
,
int
,
int
,
int
,
int
,
int
,
int
,
int
,
int
,
char
>
a10
=
Plus
(
1
,
2
,
3
,
4
,
5
,
6
,
7
,
8
,
9
,
'0'
);
}
}
// namespace gmock_generated_actions_test
}
// namespace testing
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment