Page Menu
Home
c4science
Search
Configure Global Search
Log In
Files
F92321265
DesignDoc.md
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Subscribers
None
File Metadata
Details
File Info
Storage
Attached
Created
Tue, Nov 19, 09:43
Size
9 KB
Mime Type
text/x-c++
Expires
Thu, Nov 21, 09:43 (2 d)
Engine
blob
Format
Raw Data
Handle
22422979
Attached To
R7934 PCSC_project
DesignDoc.md
View Options
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
++
0
x
).
###
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
++
0
x
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
++
0
x
'
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
++
0
x
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
++
0
x
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
.
Event Timeline
Log In to Comment