55 KiB
Reference
- Notions
- Macros (alphabetical order)
ALLOW_CALL(
mock_object, func_name(parameter_list))
ANY(
type)
AT_LEAST(
number)
AT_MOST(
number)
FORBID_CALL(
mock_object, func_name(parameter_list))
IN_SEQUENCE(
seq...)
LR_RETURN(
expr)
LR_SIDE_EFFECT(
expr)
LR_THROW(
expr)
LR_WITH(
expr)
MAKE_CONST_MOCKn(
func_name, signature)
MAKE_MOCKn(
name, signature)
NAMED_ALLOW_CALL(
mock_object, func_name(parameter_list))
NAMED_FORBID_CALL(
mock_object, func_name(parameter_list))
NAMED_REQUIRE_CALL(
mock_object, func_name(parameter_list))
NAMED_REQUIRE_DESTRUCTION(
mock_object)
REQUIRE_CALL(
mock_object, func_name(parameter_list))
REQUIRE_DESTRUCTION(
mock_object)
RETURN(
expr)
SIDE_EFFECT(
expr)
THROW(
expr)
TIMES(
limit)
WITH(
expr)
- Types and Templates (alphabetical order)
- Functions
Notions
Mock function
A member function that is mocked with
MAKE_MOCKn(name, signature)
or
MAKE_CONST_MOCKn(name, signature)
.
Example:
class C
{
public:
MAKE_MOCK1(func, void(int));
MAKE_CONST_MOCK2(cfunc, int(std::string, int));
};
Above C
is a type that has two mock functions void func(int)
and
int cfunc(std::string, int) const
. With a mock object
of type C
it is possible to place expectations
on the functions func(...)
and cfunc(...)
.
Mock object
A mock object is an object of a type that has mock functions.
Example:
class C
{
public:
MAKE_MOCK1(func, void(int));
};
C obj;
Above obj
is a mock object. It is possible to place
expectations on mock functions for the object
obj
.
Expectation
By default it is illegal to call mock functions. Expectations change that. Example:
class C
{
public:
MAKE_MOCK1(func, void(int));
};
TEST(atest)
{
C mock_obj;
REQUIRE_CALL(mock_obj, func(3));
tested_function(mock_obj);
}
Above mock_obj
is a mock object with one
mock function void func(int)
.
The line REQUIRE_CALL(mock_obj, func(3))
places an
expectation that mock_obj.func(3)
is called before the end of the scope.
Unless tested_function(mock_obj)
calls mock_obj.func(3)
a violation is
reported.
The ways to set expectations are:
REQUIRE_CALL(
mock_object, func_name(parameter_list))
ALLOW_CALL(
mock_object, func_name(parameter_list))
FORBID_CALL(
mock_object, func_name(parameter_list))
NAMED_REQUIRE_CALL(
mock_object, func_name(parameter_list))
NAMED_ALLOW_CALL(
mock_object, func_name(parameter_list))
NAMED_FORBID_CALL(
mock_object, func_name(parameter_list))
The NAMED variants returns expectations as
std::unique_ptr<trompeloeil::expectation>
which can be
saved in variables for storage in test fixtures or other programmatic lifetime
control.
If expectations are not met by the time they go out or scope (or in case of the
NAMED variants, when the object held by the std::unique_ptr<>
is
destroyed) a violation is reported.
By default there is no order imposed on expectations. One way to impose order is
through their lifetimes. Another is by using
IN_SEQUENCE(...)
If there are several expectations that matches the same call, they are tried in the reverse order of creation, and the first found match is accepted. In other words, the last created matching expectation is the one used.
Example:
class C
{
public:
MAKE_MOCK1(func, void(int));
};
using trompeloeil::_;
TEST(atest)
{
C mock_obj;
ALLOW_CALL(mock_obj, func(_));
FORBID_CALL(mock_obj, func(3));
FORBID_CALL(mock_obj, func(4));
tested_function(mock_obj);
}
Above, the first expectation ALLOW_CALL(...)
matches
everything using the wildcard trompeloeil::_
, but the two
FORBID_CALL(...)
are created later and are thus matched
first. This means that if tested_function(...)
calls mock_obj.func(int)
with
5
, the two FORBID_CALL(...)
do not match, but the
ALLOW_CALL(...)
does, so the call is allowed. A call with
3
or 4
, results in a violation is report since a
FORBID_CALL(...)
is matched.
Matcher
Each parameter in the parameter list of an expectation can be
an exact value to match for equality (using operator==
,) or a matcher.
Matchers check a condition on the parameter value. Trompeloeil provides the
matchers
You can also provide your own matchers.
_
Used in the parameter list of an expectation trompeloeil::_
matches any value of any type.
Example:
class C
{
public:
MAKE_MOCK1(func, int(int));
};
trompeloeil::_;
TEST(atest)
{
C mock_obj;
ALLOW_CALL(mock_obj, func(_))
.RETURN(_1 + 1);
test_function(&mock_obj);
}
Above, mock_obj.func()
is allowed to be called with any value, and it will
return 1 + the value provided.
If type is needed, for example to disambiguate overloads, use
ANY(
type )
.
ANY(
type )
Used in the parameter list of an expectation to match any value
of a specified type. This can be used as an alternative to
trompeloeil::_
when it is important to disambiguate between
overloads.
Example:
class C
{
public:
MAKE_MOCK1(func, void(int));
MAKE_MOCK2(func, void(std::string));
};
TEST(atest)
{
C mock_obj;
ALLOW_CALL(mock_obj, func(ANY(int)));
test_function(&mock_obj);
}
Above, any call to mock_obj.func(int)
is accepted, but calls to
mock_obj.func(std::string)
renders a violation report since there is no
matching expectation.
eq(
value )
Used in the parameter list of an expectation to match a
value equal to the one provided. By default it matches any parameter type
that supports operator==()
with the value, but an explicit type can be
specified if needed for disambiguation.
Example:
class C
{
public:
MAKE_MOCK1(func, void(int*));
MAKE_MOCK1(func, void(const char*));
MAKE_MOCK1(func, void(const std::string&));
};
using trompeloeil::ne;
TEST(atest)
{
C mock_obj;
ALLOW_CALL(mock_obj, func(*eq(3)));
std::string expected = "foo";
REQUIRE_CALL(mock_obj, func(eq<const char*>(expected)));
test_function(&mock_obj);
}
Above, the first expectation matches only calls to
mock_obj.func(int*)
with a non-null pointer pointing to the value 3
. Any
call with a nullptr
or a pointer pointing to another value than 3
renders
a violation report since no expectation matches.
The second expectation matches only calls to
mock_obj.func(const char*)
, with a c-string "foo"
.
ne(
value )
Used in the parameter list of an expectation to match a
value not equal to the one provided. By default it matches any parameter type
that supports operator!=()
with the value, but an explicit type can be
specified if needed for disambiguation.
Example:
class C
{
public:
MAKE_MOCK1(func, void(const char*));
MAKE_MOCK1(func, void(const std::string&));
};
using trompeloeil::ne;
TEST(atest)
{
C mock_obj;
ALLOW_CALL(mock_obj, func(ne(nullptr)));
REQUIRE_CALL(mock_obj, func(ne<std::string>("")));
test_function(&mock_obj);
}
Above, the first expectation matches only calls to
mock_obj.func(const char*)
with non-null pointer. Any call with a nullptr
renders a violation report since no expectation matches.
The second expectation matches only calls to
mock_obj.func(const std::string&)
, with a non-empty string.
It is also possible to use *ne(val)
to match a pointer to a non-equal value.
gt(
value )
Used in the parameter list of an expectation to match a
value greater than the one provided. By default it matches any parameter type
that supports operator>()
with the value, but an explicit type can be
specified if needed for disambiguation.
Example:
class C
{
public:
MAKE_MOCK1(func, void(short));
MAKE_MOCK1(func, void(int));
MAKE_MOCK1(func, void(std::string));
};
using trompeloeil::gt;
TEST(atest)
{
C mock_obj;
ALLOW_CALL(mock_obj, func(gt<short>(0)));
ALLOW_CALL(mock_obj, func(gt("foo")));
test_function(&mock_obj);
}
Above, the first expectation matches only calls to
mock_obj.func(short)
with positive values. Any call with 0 or negative, and
any calls to mock_obj.func(int)
renders a violation report since no
expectation matches.
The second expectation matches calls to
mock_obj.func(std::string)
, since
std::string
is
greater-than comparable with a string literal.
It is also possible to use *gt(val)
to match a pointer to a greater-than
value.
ge(
value )
Used in the parameter list of an expectation to match a
value greater than on equal to the one provided. By default it matches any
parameter type that supports operator>=()
with the value, but an explicit
type can be specified if needed for disambiguation.
Example:
class C
{
public:
MAKE_MOCK1(func, void(int));
MAKE_MOCK1(func, void(short));
MAKE_MOCK1(func, void(std::string));
};
using trompeloeil::ge;
TEST(atest)
{
C mock_obj;
ALLOW_CALL(mock_obj, func(ge<short>(0)));
REQUIRE_CALL(mock_obj, func(ge("foo")));
test_function(&mock_obj);
}
Above, the first expectation matches only calls to
mock_obj.func(short)
with zero or positive values. Any call with a negative
value renders a violation report since no expectation matches.
The second expectation matches only calls to
mock_obj.func(std::string)
, since
std::string
is
greater-than-or-equal-to comparable with string literal.
It is also possible to use *ge(val)
to match a pointer to a greater-than or
equal value.
lt(
value )
Used in the parameter list of an expectation to match a
value less than the one provided. By default it matches any parameter type
that supports operator<()
with the value, but an explicit type can be
specified if needed for disambiguation.
Example:
class C
{
public:
MAKE_MOCK1(func, void(long));
MAKE_MOCK1(func, void(int));
MAKE_MOCK1(func, void(const std::string&));
};
using trompeloeil::lt;
TEST(atest)
{
C mock_obj;
ALLOW_CALL(mock_obj, func(lt<int>(0)));
REQUIRE_CALL(mock_obj, func(lt("foo")));
test_function(&mock_obj);
}
Above, the first expectation matches only calls to
mock_obj.func(int)
with negative values. Any call with 0 or positive
renders a violation report since no expectation matches.
The second expectation matches calls to
mock_obj.func(cost std::string&)
, since
std::string
is
less-than comparable with string a literal.
It is also possible to use *lt(val)
to match a pointer to a less-than value.
le(
value )
Used in the parameter list of an expectation to match a
value less than or equal to the one provided. By default it matches any
parameter type taht supports operator<=()
with the value, but an explicit type
can be specified if needed for disambiguation.
Example:
class C
{
public:
MAKE_MOCK1(func, void(int));
MAKE_MOCK1(func, void(short));
MAKE_MOCK1(func, void(const char*));
};
using trompeloeil::le;
using std::string_literals;
TEST(atest)
{
C mock_obj;
ALLOW_CALL(mock_obj, func(le<short>(0)));
REQUIRE_CALL(mock_obj, func(le("foo"s)));
test_function(&mock_obj);
}
Above, first the expectation matches only calls to
mock_obj.func(short)
with zero or negative values. Any call with a positive
value renders a violation report since no expectation matches.
The second expectation matches calls to
mock_obj.func(const char*)
, since a c-string is less-than comparable
with a std::string
It is also possible to use *le(val)
to match a pointer to a less-than or
equal value.
re(
string )
Used in the parameter list of an expectation to match a string with a regular expression.
re()
exists in two flavours.
re(
string, flags...)
which can match both C-strings (char*
,const char*
) as well asC++
std::string
.re<type>(
string, flags...)
which can be used to disambiguate overloads.
For both versions, the string can be either std::string
or a C-string.
flags... can be
- empty
- std::regex_constants::syntax_option_type
- std::regex_constants::match_flag_type
- std::regex_constants::syntax_option_type, std::regex_constants::match_flag_type
Regular expression matching is made with
std::regex_search()
Example:
class C
{
public:
MAKE_MOCK1(unique, void(std::string&));
MAKE_MOCK1(overloaded, void(const char*));
MAKE_MOCK1(overloaded, void(const std::string&));
};
using trompeloeil::re;
TEST(atest)
{
C mock_obj;
REQUIRE_CALL(mock_obj, unique(re("end$", std::regex_constants::icase)));
REQUIRE_CALL(mock_obj, overloaded(re<const char*>("end", std::regex_constants::match_not_eol)));
test_function(&mock_obj);
}
Above, test_function(&mock_obj)
must call mock_obj.unique()
with a string
case insensitively matching the regular expression /end$/
, and also call
mock_obj.overloaded(const char*)
with a regular expression matching
the regular expression /end/
.
It is also possible to use *re(string)
to match a pointer to a string with
a regular expression.
Macros
### **`ALLOW_CALL(`** *mock_object*, *func_name*(*parameter_list*)**`)`** Make an expectation that *mock_object*.*func_name*(*parameter_list*) may be called zero or more times until the end of the surrounding scope. *parameter_list* may contain exact values or [matchers](#matcher) that describes matching calls.This is the same as
REQUIRE_CALL(...)
.TIMES(
0,infinity )
.
Matches any number of times, but is not required to match. (actually the limit is 0..~0ULL, but that is for all practical purposes "infinity")
Example:
class C
{
public:
MAKE_MOCK1(func, int(int));
};
trompeloeil::_;
TEST(atest)
{
C mock_obj;
ALLOW_CALL(mock_obj, func(_))
.RETURN(_1 + 1);
test_function(&mock_obj);
}
Above ALLOW_CALL(mock_obj, func(_))
places an expectation that
mock_obj.func()
may be called any number of times with any parameter value
and will always return the parameter value + 1. test_function(...)
is allowed to call mock_obj.func()
any number of times (including no call at
all.)
The expectation is valid until the end of the scope, which in the example above
is until after the return from test_function(...)
.
See also NAMED_ALLOW_CALL(...)
which creates an
expectation as a
std::unique_ptr<trompeloeil::expectation>
which can be
stored in test fixtures or otherwise have its lifetime programmatically controlled.
A matcher for use in the parameter list of an
expectation to disambiguate overloaded functions on type when
the exact value is unimportant. See the matcher ANY(
type )
above.
Example:
class C
{
public:
MAKE_MOCK1(func, void(int));
};
using trompeloeil::_;
TEST(atest)
{
C mock_obj;
REQUIRE_CALL(mock_obj, func(_))
.TIMES(AT_LEAST(3));
tested_function(&mock_obj);
}
Above, the line TIMES(
AT_LEAST(3))
modifies the
expectation such that mock_obj.func() must be called 3 times
or more, before the end of the scope, or a violation is reported.
In reality the upper limit is ~0ULL, but that is for all practical purposes "infinity".
### **`AT_MOST(`** *number* **`)`** Used in [**`TIMES(...)`**](#TIMES) to set the range 0..*number*. *number* must be [`constexpr`](http://en.cppreference.com/w/cpp/language/constexpr). Example:class C
{
public:
MAKE_MOCK1(func, void(int));
};
using trompeloeil::_;
TEST(atest)
{
C mock_obj;
REQUIRE_CALL(mock_obj, func(_))
.TIMES(AT_MOST(3));
tested_function(&mock_obj);
}
Above, the line TIMES(
AT_MOST(3))
modifies the
expectation such that mock_obj.func() must be called 3 times
or less (including no call at all,) before the end of the scope, or a violation
is reported.
This is the same as
REQUIRE_CALL(...)
.TIMES(
0 )
,
making any matching call an error. This is often done in a narrow scope
where the wider scope would allow the call. LR_RETURN(...)
,
RETURN(...)
, LR_THROW(...)
and
THROW(...)
are illegal in a FORBID_CALL(...)
.
Example:
class C
{
public:
MAKE_MOCK1(func, void(int));
};
using trompeloeil::_;
TEST(atest)
{
C mock_obj;
ALLOW_CALL(mock_obj, func(_));
tested_function(1, &mock_obj);
{
FORBID_CALL(mock_obj, func(2));
tested_function(2, &mock_obj);
}
tested_function(3, &mock_obj);
}
Above, the mock function C::func(int) may be called with any value for mock_obj, except in the scope of the tested_function(2, &mock_obj), where mock_obj.func(2) would lead to a violation being reported. At tested_function(3, &mock_obj) any value is allowed again.
See also NAMED_FORBID_CALL(...)
which creates an
expectation as a
std::unique_ptr<trompeloeil::expectation>
which can be
stored in test fixtures.
Example:
class Mock
{
public:
MAKE_MOCK1(func, void(int));
MAKE_MOCK1(func, void(const std::string&));
};
class ephemeral
{
public:
virtual ~ephemeral() {};
};
TEST(atest)
{
Mock m[2];
auto e = new trompeloeil::deathwatched<ephemeral>;
trompeloeil::sequence seq1, seq2;
REQUIRE_CALL(m[0], func(ANY(int))
.IN_SEQUENCE(seq1, seq2);
REQUIRE_CALL(m[0], func(ANY(const std::string&))
.IN_SEQUENCE(seq1);
REQUIRE_CALL(m[1], func(ANY(const std::string&))
.IN_SEQUENCE(seq2);
REQUIRE_CALL(m[1], func(ANY(int))
.IN_SEQUENCE(seq1, seq2);
REQUIRE_DESTRUCTION(*e)
.IN_SEQUENCE(seq1, seq2);
tested_func(&m[0], &m[1], e);
}
All sequence objects are listed in the first REQUIRE_CALL(...)
,
thus it must be the first expectation matched. Likewise all
sequences are listed in the last
REQUIRE_CALL(...)
, so it must be last
expectaiton matched. The intermediate
expectations has one sequence object each, thus they have no
matching order imposed between them. Last of all is the
REQUIRE_DESTRUCTION(...)
, which also lists
all sequence objects and must happen after all other
expectations are fulfilled.
The above allows the following two sequences only.
m[0].func(int)
->m[0].func(string)
->m[1].func(string)
->m[1].func(int)
->delete e
m[0].func(int)
->m[1].func(string)
->m[0].func(string)
->m[1].func(int)
->delete e
Any other sequence of calls renders a violation report.
### **`LR_RETURN(`** *expr* **`)`** Used in [expectations](#expectation) to set the return value after having evaluated every [**`SIDE_EFFECT(...)`**](#SIDE_EFFECT) and [**`LR_SIDE_EFFECT(...)`**](#LR_SIDE_EFFECT). For `void` functions **`LR_RETURN(...)`** is illegal. For non-`void` functions exactly one of [**`RETURN(...)`**](#RETURN), **`LR_RETURN(...)`**, [**`LR_THROW(...)`**](#LR_THROW) or [**`THROW(...)`**](#THROW) is required. *expr* may refer to parameters in the call with their positional names `_1`, `_2`, etc. This code may alter out-parameters.If you need to return an
lvalue-reference,
to a variable, use
std::ref(value)
or
std::cref(value)
for it, or just enclose the value in an extra parenthesis, like this
.LR_RETURN((value))
.
NOTE! Any named local objects named in expr are captured by reference so lifetime management is important.
Example:
class C
{
public:
MAKE_MOCK1(func, int&(unsigned));
};
TEST(atest)
{
C mock_obj;
int rv = 3;
ALLOW_CALL(mock_obj, func(0))
.LR_RETURN(std::ref(rv)); // reference to captured local variable
rv = 4;
test_func(&mock_obj);
}
Above, the LR_RETURN(...)
clause tells matching calls of
mock_obj.func(...)
to return a reference to the local variable rv
.
Since LR_RETURN(...)
accesses local variables by reference, the value
of the returned reference will be 4 if called from within test_func(...)
.
See also RETURN(...)
which accesses copies of local variables.
Example:
class C
{
public:
MAKE_MOCK1(func, void(unsigned));
};
TEST(atest)
{
C mock_obj;
unsigned sum = 0;
ALLOW_CALL(mock_obj, func(ANY(unsigned))
.LR_SIDE_EFFECT(sum += _1);
tested_func(&mock_obj);
std::cout << "parameter sum=" << sum << "\n";
}
Above, tested_func(&mock_obj)
is allowed to call C::func(int)
any
number of times on mock_obj
. Each time a side effect is that the local
variable sum
gets the parameter value added to it. Since
LR_SIDE_EFFECT(...)
refers to sum
by reference, it is the actual
local variable that is changed is every call.
See also SIDE_EFFECT(...)
which accesses copies of local
objects.
Example:
class C
{
public:
MAKE_MOCK1(func, void(unsigned));
};
TEST(atest)
{
C mock_obj;
const char* what="";
ALLOW_CALL(mock_obj, func(3))
.LR_THROW(std::invalid_argument(what));
what = "nonsense";
tested_func(&mock_obj);
}
Above, LR_THROW(std::invalid_argument(what))
will refer to the c-string
what
with the value it has at the time of a call to mock_obj.func(3)
, i.e.
"nonsense"
if tested_func()
does the call.
See also THROW(...)
which accesses copies of local objects.
first has failed.
Named local objects are accessed by reference so lifetime management is important.
Example:
class C
{
public:
MAKE_MOCK1(func, void(const char*));
};
using trompeloeil::_;
TEST(atest)
{
C mock_obj;
const char buff[] = "string";
REQUIRE_CALL(mock_obj, func(_))
.LR_WITH(_1 == buff);
tested_func(buff, &mock_obj);
}
Above, LR_WITH(_1 == buff)
checks the condition that the const char*
parameter is the same pointer value as the address to the local array buff
.
NOTE! It is legal, but a very bad idea, to modify global/static objects in
LR_WITH(...)
. If several expectations could match and
are disambiguated by LR_WITH(...)
and WITH(...)
the
global/static objects will be modified also by those
expectations that do not match.
See also WITH(...)
which accesses copies of local objects.
Example:
class I
{
public:
virtual ~I() = default;
virtual int func1(int, const std::vector<int>&)) const = 0;
};
class C
{
public:
MAKE_CONST_MOCK2(func1, int(int, const std::vector<int>&), override);
MAKE_CONST_MOCK1(func2, int(std::string));
};
Above, class C
will effectively become:
class C : public I
{
public:
int func1(int, const std::vector<int>&) const override;
int func2(std::string) const;
};
It is not possible to mock operators, constructors or the destructor, but you can call mock functions from those.
See also MAKE_MOCKn(...)
for non-const
member functions.
Example:
class I
{
public:
virtual ~I() = default;
virtual int func1(int, const std::vector<int>&)) = 0;
};
class C : public I
{
public:
MAKE_MOCK2(func1, int(int, const std::vector<int>&), override);
MAKE_MOCK1(func2, int(std::string));
};
Above, class C
will effectively become:
class C : public I
{
public:
int func1(int, const std::vector<int>&) override;
int func2(std::string);
};
It is not possible to mock operators, constructors or the destructor, but you can call mock functions from those.
See also MAKE_CONST_MOCKn(...)
for const
member functions.
This is the same as
NAMED_REQUIRE_CALL(...)
.TIMES(
0,infinity )
.
Matches any number of times, but is not required to match. (actually the limit is 0..~0ULL, but that is for all practical purposes "infinity")
NOTE! Any named objects referenced in attached
LR_WITH(...)
, LR_SIDE_EFFECT(...)
,
LR_RETURN(...)
and LR_THROW(...)
are
captured by reference so lifetime management is important.
Example:
class C
{
public:
MAKE_MOCK1(func, void(int));
};
using trompeloeil::gt;
using trompeloeil::lt;
using expectation = std::unique_ptr<trompeloeil::expectation>;
TEST(atest)
{
C mock_obj;
expectation x1 = NAMED_ALLOW_CALL(mock_obj, func(gt(0));
test_function(0, &mock_obj);
expectation x2 = NAMED_ALLOW_CALL(mock_obj, func(lt(0));
test_function(1, &mock_obj);
x1.reset(); // no longer allow calls with positive values
test_function(2, &mock_obj);
}
Above each NAMED_ALLOW_CALL(mock_obj, func(...))
creates an expectation
that mock_obj.func() may be called any number of times. Each expectation is
valid for as long at the expectation object is alive. In the example above,
this means that x1
is valid for the first two calls to test_function(...)
,
while x2
is valid for the last two calls to test_function(...)
.
See also ALLOW_CALL(...)
which creates an expectation
that is valid until the end of the surrounding scope.
This is the same as
NAMED_REQUIRE_CALL(...)
.TIMES(
0 )
, making any matching call an error. This is typically done when a wider
scope would allow the call. RETURN(...)
,
LR_RETURN(...)
, LR_THROW(...)
and
THROW(...)
are illegal in a NAMED_FORBID_CALL(...)
.
NOTE! Any named objects referenced in attached
LR_WITH(...)
are captured by reference so lifetime management
is important.
Example:
class C
{
public:
MAKE_MOCK1(func, void(int));
}
using trompeloeil::_;
using trompeloeil::gt;
using trompeloeil::lt;
using expectation = std::unique_ptr<trompeloeil::expectation>;
TEST(atest)
{
C mock_obj;
ALLOW_CALL(mock_obj, func(_));
expectation x1 = NAMED_FORBID_CALL(mock_obj, func(gt(0));
test_function(0, &mock_obj);
expectation x2 = NAMED_FORBID_CALL(mock_obj, func(lt(0));
test_function(1, &mock_obj);
x1.reset(); // allow calls with positive values again
test_function(2, &mock_obj);
}
Above, calls to mock_obj.func()
are generally allowed throughout the test.
However, x1
imposes a restriction that calls with positive values are illegal,
and that restriction is in place for the first two calls to
test_function(...)
. x2
imposes a restrictions that calls with negative
values are illegal, and that restriction is in place for the last two calls to
test_function(...)
.
See also FORBID_CALL(...)
which creates an
expectation that is valid until the end of the surrounding scope.
The number of matches required before the expectation object
is destroyed can be changed with an optional TIMES(...)
clause.
NOTE! Any named objects referenced in attached
LR_WITH(...)
, LR_SIDE_EFFECT(...)
,
LR_RETURN(...)
and LR_THROW(...)
are
captured by reference so lifetime management is important.
Example:
class C
{
public:
MAKE_MOCK1(func, void(int));
}
using trompeloeil::gt;
using trompeloeil::lt;
using expectation = std::unique_ptr<trompeloeil::expectation>;
TEST(atest)
{
C mock_obj;
expectation x1 = NAMED_REQUIRE_CALL(mock_obj, func(gt(0));
test_function(0, &mock_obj);
expectation x2 = NAMED_REQUIRE_CALL(mock_obj, func(lt(0));
test_function(1, &mock_obj);
x1.reset(); // The call with positive number must be done here.
test_function(2, &mock_obj);
}
Above, the first two calls to test_function(...)
must together call
mock_obj.func(...)
exactly once with a positive value, and the last two
calls to test_function(...)
must together call mock_obj.func(...)
exactly once with a negative number.
See also REQUIRE_CALL(...)
which creates an
expectation that is valid until the end of the surrounding scope.
Example:
class C
{
public:
virtual ~C() = default; // must be virtual for deathwatched
MAKE_MOCK1(func, void(int));
}
using monitor = std::unique_ptr<trompeloeil::expectation>;
using trompeloeil::deathwatched;
TEST(atest)
{
C* p = new deathwatched<C>();
test_function(0, p); // must not destroy *p
monitor m = NAMED_REQUIRE_DESTRUCTION(*p);
test_function(1, p);
m.reset(); // *p must have been destroyed here
}
Above, p
points to a deathwatched
mock object, meaning that a violation is reported if *p
is
destroyed without having a destruction requirement.
The monitor m
is a requirement that *p
is destroyed before the
lifetime_monitor
(subtype of expectation
) held by m
is destroyed.
It is thus a violation if the first call to test_function(...)
destroys
*p
, and another violation if the second call to test_function(...)
does not destroy *p
See also REQUIRE_DESTRUCTION(...)
which places
a requirement that the deathwatched
mock object is destroyed before the end of the scope.
The number of matches required before the expectation object
is destroyed can be changed with an optional TIMES(...)
clause.
Example:
class C
{
public:
MAKE_MOCK1(func, void(int));
}
using trompeloeil::gt;
using trompeloeil::lt;
TEST(atest)
{
C mock_obj;
{
REQUIRE_CALL(mock_obj, func(gt(0));
test_function(0, &mock_obj);
// end of scope, requirement must be fulfilled here
}
{
REQUIRE_CALL(mock_obj, func(lt(0));
test_function(1, &mock_obj);
// end of scope, requirement must be fulfilled here
}
}
Above, the first call to test_function(...)
must call
mock_obj.func(...)
exactly once with a positive value, and the second
call to test_function(...)
must call mock_obj.func(...)
exactly once with a negative number.
See also NAMED_REQUIRE_CALL(...)
which creates an
expectation that is held by a
std::unique_ptr<trompeloeil::expectation>
which can be stored in test
fixtures.
Example:
class C
{
public:
virtual ~C() = default; // must be virtual for deathwatched
MAKE_MOCK1(func, void(int));
}
using trompeloeil::deathwatched;
TEST(atest)
{
C* p = new deathwatched<C>();
test_function(0, p); // must not destroy *p
{
REQUIRE_DESTRUCTION(*p);
test_function(1, p);
// end of scope, *p must have been destroyed here
}
}
Above, p
points to a deathwatched
mock object, meaning that a violation is reported if *p
is
destroyed without having a destruction requirement.
[REQUIRE_DESTRUCTION(...)
] in the local scope puts a requirement on
*p
that it must be destroyed by the end of the scope.
It is thus a violation if the first call to test_function(...)
destroys
*p
, and another violation if the second call to test_function(...)
does not destroy *p
See also NAMED_REQUIRE_DESTRUCTION(...)
which creates the requirement that the deathwatched
mock object is destroyed as a
std::unique_ptr<trompeloeil::lifetime_monitor>
which can be stored in test fixtures.
Named local objects accessed here refers to a immutable copies.
Example:
class C
{
public:
MAKE_MOCK1(func, int&(unsigned));
};
using trompeloeil::_;
std::vector<int> values{3,2,1,0};
TEST(atest)
{
C mock_obj;
int offset = 1;
ALLOW_CALL(mock_obj, func(_))
.WITH(_1 + offset < values.size())
.RETURN(values[_1 + offset]);
offset = 2;
test_func(&mock_obj);
}
Above, the RETURN(...)
clause tells matching calls of
mock_obj.func(...)
to return a reference to an element in the global
std::vector<int> values
. Since RETURN(...)
accesses copies of local
variables, the value of offset
is 1 in the index calculation if called from
within test_func(...)
.
NOTE! It is illegal to return a reference to a captured local variable.
See also LR_RETURN(...)
which accesses local variables
by reference.
Named local objects accessed here refers to immutable copies.
Example:
class C
{
public:
MAKE_MOCK1(func, void(unsigned));
};
unsigned sum = 0;
TEST(atest)
{
C mock_obj;
unsigned offset = 0;
ALLOW_CALL(mock_obj, func(ANY(unsigned))
.SIDE_EFFECT(sum += offset + _1);
offset = 2;
tested_func(&mock_obj);
std::cout << "offset corrected parameter sum=" << sum << "\n";
}
Above, tested_func(...)
is allowed to call mock_obj.func()
any
number of times. Each time a side effect is that the global
variable sum
gets the parameter value added to it adjusted for offset
.
Since SIDE_EFFECT(...)
refers to a copy of offset
, the value of
offset
is 0
in any matching calls from within tested_func(...)
See also LR_SIDE_EFFECT(...)
which accesses local
objects by reference.
Named local objects here refers to immutable copies.
Example:
class C
{
public:
MAKE_MOCK1(func, void(unsigned));
};
TEST(atest)
{
C mock_obj;
std::string what="<unknown>";
ALLOW_CALL(mock_obj, func(3))
.THROW(std::invalid_argument(what));
what = "";
tested_func(&mock_obj);
}
Above, THROW(...)
will refer to a copy of the string what
with the value
"<unknown>"
if a matching call is made from within tested_func(...)
See also LR_THROW(...)
which accesses copies of local objects.
limits may be a single number, in which case it is the exact number of matching calls required.
limits may also be two numbers, describing a range min-inclusive, max-inclusive.
If the minimum number of matching calls in not met before the end of the lifetime of the expectation, a violation is reported.
If the maximum number of matching calls is exceeded, a violation is reported.
limits must be
constexpr
.
TIMES(...)
may only be used once for each
REQUIRE_CALL(..)
or
NAMED_REQUIRE_CALL(...)
.
Example:
class C
{
public:
MAKE_MOCK1(func, void(unsigned));
};
using trompeloeil::_;
TEST(atest)
{
C mock_obj;
REQUIRE_CALL(mock_obj, func(_))
.TIMES(2, 5);
tested_func(&mock_obj);
Above, tested_func(...)
is expected to call mock_obj.func()
at least two
times, and no more than 5 times.
See also the helpers AT_LEAST(...)
and
AT_MOST(...)
.
Named local objects here refers to immutable copies.
Example:
class C
{
public:
MAKE_MOCK1(func, void(const char*, size_t));
};
using trompeloeil::_;
TEST(atest)
{
C mock_obj;
std::string str = "string";
REQUIRE_CALL(mock_obj, func(_,_))
.WITH(std::string(_1, _2) == str);
str = ""; // does not alter the copy in the expectation above.
tested_func(buff, &mock_obj);
}
Above, WITH(std::string(_1, _2) == str)
checks the condition that the
string constructed from the parameters is equal to a copy of the local variable
str
. To pass the test, tested_func(...)
must in other words call
mock_obj.func()
with string "string"
.
NOTE! It is legal, but a very bad idea, to modify global/static objects in
WITH(...)
. If several expectations could match and
are disambiguated by LR_WITH(...)
and WITH(...)
the
global/static objects will be modified also by those
expectations that do not match.
See also LR_WITH(...)
which accesses local objects by
reference.
Types and Templates (alphabetical order)
trompeloeil::deathwatched<T>
Template used when it is necessary to control the life time of a
mock object. The macros
REQUIRE_DESTRUCTION(...)
and
NAMED_REQUIRE_DESTRUCTION(...)
operates on instances of trompeloeil::deathwatched<T>
.
Example:
class Mock
{
public:
virtual ~Mock() = default; // virtual destructor needed for deathwatched<>
MAKE_MOCK1(func, void(int));
};
using trompeloeil::_;
void test_func()
{
auto p = new trompeloeil::deathwatched<Mock>();
ALLOW_CALL(*p, func(_));
func1(p);
{
FORBID_CALL(*p, func(_));
REQUIRE_DESTRUCTION(*p);
func2(p);
}
}
Above, func1(p)
must not destroy p
, or a violation is reported, and
func2(p)
may not call the mock function on p
, but
is required to destroy the mock objeck, or a violation will
be reported.
trompeloeil::deathwatched<T>
inherits from T
, and the constructor
accepts any parameters and
perfectly forwards
them to the constructor of T
. The mock type T
must have a virtual
destructor.
trompeloeil::expectation
Base class for all expectations. The macros
NAMED_ALLOW_CALL(...)
,
NAMED_FORBID_CALL(...)
and
NAMED_REQUIRE_CALL(...)
results in a
std::unique_ptr<trompeloeil::expectation>
which you can hold in a variable.
trompeloeil::expectation_violation
The exception type used by default to report violations.
class expectation_violation : public std::logic_error
{
public:
using std::logic_error::logic_error;
};
The what()
string contains the violation report message.
trompeloeil::lifetime_monitor
The macro NAMED_REQUIRE_DESTRUCTION(...)
results in a
std::unique_ptr<trompeloeil::lifetime_monitor>
which you can hold in a varaible. trompeloeil::lifetime_monitor
inherits from
trompeloeil::expectation
.
Example:
class Mock
{
public:
virtual ~Mock() = default; // virtual destructor needed for deathwatched<>
MAKE_MOCK1(func, void(int));
};
using trompeloeil::_;
using monitor = std::unique_ptr<trompeloeil::lifetime_monitor>;
void test_func()
{
auto p = new trompeloeil::deathwatched<Mock>();
ALLOW_CALL(*p, func(_));
func1(p);
{
FORBID_CALL(*p, func(_));
monitor m = NAMED_REQUIRE_DESTRUCTION(*p);
std::unique_ptr<trompeloeil::expectation> e = std::move(m);
func2(p);
e.reset();
}
}
trompeloeil::matcher
trompeloeil::matcher
is the base class for all matchers. It does
not do anything and is solely used in internal
SFINAE
constructions
and tag dispatch
Use it, or trompeloeil::typed_matcher<T>
, as the base class
when writing custom matchers
trompeloeil::sequence
Type of object used for fine tuned control of sequencing of matched expectations.
Example:
class FileOps
{
public:
using handle = int;
MAKE_MOCK1(open, handle(const std::string&));
MAKE_MOCK3(write, size_t(handle, const char*, size_t));
MAKE_MOCK1(close, void(handle));
};
using trompeloeil::ne;
void test()
{
FileOps ops;
trompeloeil::sequence seq; // sequence object
int handle = 4711;
REQUIRE_CALL(ops, open("name"))
.RETURN(handle)
.IN_SEQUENCE(seq);
REQUIRE_CALL(ops, write(handle, ne(nullptr), ne(0)))
.RETURN(0) // indicate failure
.IN_SEQUENCE(seq);
REQUIRE_CALL(ops, write(handle, ne(nullptr), ne(0)))
.RETURN(_3) // successful retry
.IN_SEQUENCE(seq);
REQUIRE_CALL(ops, close(handle))
.IN_SEQUENCE(seq);
test_writes(&ops);
}
NOTE! The .IN_SEQUENCE(...)
macro accepts many
sequence objects.
trompeloeil::severity
Type used in violation reports to dictate what actions are allowed by the report handler.
namespace trompeloeil {
enum class severity { fatal, nonfatal };
}
A value of trompeloeil::severity::fatal
dictates that the report handler
must not return. It may throw or end the program execution.
A value of trompeloeil::severity::nonfatal
dictates that the report handler
is called from stack rollback and must not throw, lest
std::terminate
is
called.
trompeloeil::stream_tracer
An instance of trompeloeil::stream_tracer
prints information about
matched calls to the
output stream
it refers to. stream_tracer
inherits from
trompeloeil::tracer
.
namespace trompeloeil {
class stream_tracer : public ::trompeloeil::tracer
{
public:
stream_tracer(std::ostream& stream);
void trace(char const* file, unsigned long line, std::string const& call) override;
};
}
See "Using trompeloeil::stream_tracer
" in the
Cook Book.
trompeloeil::typed_matcher<T>
Convenience class available when writing custom matchers for a specific
type. It inherits from trompeloeil::matcher
.
See "Writing custom matchers" in the Cook Book for examples.
tropmeloeil::tracer
Base class for tracers. Inherit from it when writing custom tracers.
namespace trompeloeil {
class tracer
{
public:
virtual void trace(char const* file, unsigned long line, std::string const& call) = 0;
protected:
tracer();
tracer(tracer const&) = delete;
virtual ~tracer();
...
};
}
See "Writing custom tracers" in the Cook Book for an example.
Functions
trompeloeil::set_reporter()
This function is used to adapt Trompeloeil to your unit test framework of choice.
The default reporter throws
trompeloeil::expectation_violation
for
all reports, with the violation message in the what()
string.
If this is not suitable, you can change the report mechanism by
calling trompeloeil::set_reporter(...)
trompeloeil::set_reporter(std::function<void(trompeloeil::severity,
char const *file,
unsigned long line,
const std::string& msg)>)
See trompeloeil::severity
for the rules that it
dictates.
The Cook Book lists adapter code for a number of popular unit test frame works.
trompeloeil::get_lock()
Get the global
recursive_mutex
used by Trompeloeil. The mutex is held until the end of the scope.