Page Menu
Home
c4science
Search
Configure Global Search
Log In
Files
F85166918
design_doc.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
Fri, Sep 27, 06:02
Size
9 KB
Mime Type
text/x-c++
Expires
Sun, Sep 29, 06:02 (2 d)
Engine
blob
Format
Raw Data
Handle
21134648
Attached To
R9484 sp4e-homework-lars-bertil
design_doc.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