You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
trompeloeil/compiling_tests.cpp

1728 lines
42 KiB
C++

/*
* Trompeloeil C++ mocking framework
*
* Copyright Björn Fahller 2014,2015
*
* Use, modification and distribution is subject to the
* Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* Project home: https://github.com/rollbear/trompeloeil
*/
// Regular expressions do not match, but results look OK.
#define TROMPELOEIL_SANITY_CHECKS
#include "trompeloeil.hpp"
#define CATCH_CONFIG_MAIN
#include <catch.hpp>
#include <vector>
#include <string>
#include <algorithm>
#include <regex>
struct Fixture
{
Fixture() {
trompeloeil::set_reporter([this](auto s,auto f, auto l, auto m) { send_report(s, f, l, m);});
}
class reported {};
struct report
{
trompeloeil::severity s;
const char* file;
unsigned line;
std::string msg;
};
std::vector<report> reports;
void send_report(trompeloeil::severity s, const char* file, unsigned line, const std::string msg)
{
reports.push_back(report{ s, file, line, msg });
if (s == trompeloeil::severity::fatal && !std::uncaught_exception())
{
throw reported{};
}
}
};
struct uncopyable
{
uncopyable() {}
uncopyable(uncopyable&&) = default;
uncopyable(const uncopyable&) = delete;
uncopyable& operator=(const uncopyable&) = delete;
bool operator==(const uncopyable& p) const { return &p == this; }
bool operator!=(const uncopyable& p) const { return &p == this; }
friend std::ostream& operator<<(std::ostream& os, const uncopyable& obj)
{
return os << "uncopyable@" << &obj;
}
};
struct unmovable
{
unmovable() {}
unmovable(unmovable&&) = delete;
unmovable(const unmovable&) = delete;
unmovable& operator=(unmovable&&) = delete;
unmovable& operator=(const unmovable&) = delete;
bool operator==(const unmovable& p) const { return &p == this; }
bool operator!=(const unmovable& p) const { return &p != this; }
friend std::ostream& operator<<(std::ostream& os, const unmovable& obj)
{
return os << "unmovable@" << &obj;
}
};
struct uncomparable { };
class C
{
public:
C() {}
C(int) {}
virtual ~C() = default;
virtual int count() = 0;
virtual void func(int, std::string& s) = 0;
virtual unmovable& getter(unmovable&) = 0;
virtual int getter(int) = 0;
virtual void getter(int, std::string&) = 0;
virtual std::unique_ptr<int> ptr(std::unique_ptr<int>&&) = 0;
protected:
C(const char* s) : p_{ s } {}
const char *p_ = nullptr;
};
class mock_c : public C
{
public:
mock_c() {}
mock_c(int i) : C(i) {}
mock_c(const char* p) : C(p) {}
MAKE_MOCK1(ptr, std::unique_ptr<int>(std::unique_ptr<int>&&));
MAKE_MOCK0(count, int());
MAKE_MOCK1(foo, void(std::string));
MAKE_MOCK2(func, void(int, std::string&));
MAKE_MOCK1(getter, unmovable&(unmovable&));
MAKE_MOCK1(getter, int(int));
MAKE_MOCK2(getter, void(int, std::string&));
using C::p_;
};
using trompeloeil::_;
// IN_SEQUENCE tests
TEST_CASE_METHOD(Fixture, "follow single sequence gives no reports", "[sequences]")
{
{
mock_c obj1(1), obj2("apa");
trompeloeil::sequence seq;
REQUIRE_CALL(obj1, count())
.IN_SEQUENCE(seq)
.RETURN(1);
REQUIRE_CALL(obj2, func(_, _))
.IN_SEQUENCE(seq);
REQUIRE_CALL(obj2, count())
.IN_SEQUENCE(seq)
.RETURN(3);
std::string str = "apa";
obj1.count();
obj2.func(3, str);
obj2.count();
}
REQUIRE(reports.empty());
}
TEST_CASE_METHOD(Fixture, "join two sequences gives no report", "[sequences]")
{
{
mock_c obj1, obj2;
trompeloeil::sequence seq1, seq2;
REQUIRE_CALL(obj1, count())
.IN_SEQUENCE(seq1)
.RETURN(1);
REQUIRE_CALL(obj2, func(_, _))
.IN_SEQUENCE(seq2);
REQUIRE_CALL(obj2, count())
.IN_SEQUENCE(seq2, seq1)
.RETURN(3);
std::string str = "apa";
obj2.func(3, str);
obj1.count();
obj2.count();
}
REQUIRE(reports.empty());
}
TEST_CASE_METHOD(Fixture, "violating single sequence reports first violation as fatal", "[sequences]")
{
try {
mock_c obj1, obj2;
trompeloeil::sequence seq;
REQUIRE_CALL(obj1, count())
.IN_SEQUENCE(seq)
.RETURN(1);
REQUIRE_CALL(obj2, func(_,_))
.IN_SEQUENCE(seq);
REQUIRE_CALL(obj2, count())
.IN_SEQUENCE(seq)
.RETURN(3);
std::string str = "apa";
obj1.count();
obj2.count();
obj2.func(3, str);
FAIL("didn't throw!");
}
catch (reported)
{
REQUIRE(!reports.empty());
auto re = R":(Sequence mismatch.*\"seq\".*matching.*obj2.count\(\).*has obj2\.func\(_,_\) at.*first):";
REQUIRE(std::regex_search(reports.front().msg, std::regex(re)));
}
}
TEST_CASE_METHOD(Fixture, "violating parallel sequences reports first violation as fatal", "[sequences]")
{
try {
mock_c obj1, obj2;
trompeloeil::sequence seq1, seq2;
REQUIRE_CALL(obj1, count())
.IN_SEQUENCE(seq1)
.RETURN(1);
REQUIRE_CALL(obj2, func(_, _))
.IN_SEQUENCE(seq2, seq1);
REQUIRE_CALL(obj1, count())
.IN_SEQUENCE(seq2)
.RETURN(3);
REQUIRE_CALL(obj2, count())
.IN_SEQUENCE(seq2)
.RETURN(3);
std::string str = "apa";
obj1.count();
obj2.func(3, str);
obj2.count();
FAIL("didn't throw!");
}
catch (reported)
{
REQUIRE(!reports.empty());
auto re = R":(Sequence mismatch.*seq2.*of obj2\.count\(\).*has obj1.count\(\).*first):";
REQUIRE(std::regex_search(reports.front().msg, std::regex(re)));
}
}
TEST_CASE_METHOD(Fixture, "a sequence retires after min calls", "[sequences]")
{
{
int count = 0;
mock_c obj1;
trompeloeil::sequence seq1;
REQUIRE_CALL(obj1, count())
.IN_SEQUENCE(seq1)
.TIMES(AT_LEAST(3))
.RETURN(1);
REQUIRE_CALL(obj1, func(_, _))
.IN_SEQUENCE(seq1);
count += obj1.count();
count += obj1.count();
count += obj1.count();
std::string s = "apa";
obj1.func(3, s);
}
REQUIRE(reports.empty());
}
TEST_CASE_METHOD(Fixture, "calling a sequenced match after seq retires is allowed", "[sequences]")
{
{
int count = 0;
mock_c obj1;
trompeloeil::sequence seq1;
REQUIRE_CALL(obj1, count())
.IN_SEQUENCE(seq1)
.TIMES(AT_LEAST(3))
.RETURN(1);
REQUIRE_CALL(obj1, func(_, _))
.IN_SEQUENCE(seq1);
count += obj1.count();
count += obj1.count();
count += obj1.count();
count += obj1.count();
count += obj1.count();
std::string s = "apa";
obj1.func(3, s);
}
REQUIRE(reports.empty());
}
TEST_CASE_METHOD(Fixture, "breaking a sequence before retirement is illegal", "[sequences]")
{
int count = 0;
mock_c obj1;
trompeloeil::sequence seq1;
REQUIRE_CALL(obj1, count())
.IN_SEQUENCE(seq1)
.TIMES(AT_LEAST(3))
.RETURN(1);
REQUIRE_CALL(obj1, func(_, _))
.IN_SEQUENCE(seq1);
count += obj1.count();
count += obj1.count();
try {
std::string s = "apa";
obj1.func(3, s);
FAIL("didn't throw");
}
catch (reported)
{
REQUIRE(reports.size() == 1U);
auto re = R":(Sequence mismatch.*seq1.*of obj1\.func\(_, _\).*has obj1\.count\(\).*first):";
INFO("report=" << reports.front().msg);
REQUIRE(std::regex_search(reports.front().msg, std::regex(re)));
auto& first = reports.front();
INFO(first.file << ':' << first.line << "\n" << first.msg);
}
}
TEST_CASE_METHOD(Fixture, "sequences impose order between multiple matching expectations", "[sequences]")
{
mock_c obj;
trompeloeil::sequence seq;
REQUIRE_CALL(obj, getter(ANY(int)))
.RETURN(1)
.IN_SEQUENCE(seq);
REQUIRE_CALL(obj, getter(ANY(int)))
.RETURN(2)
.IN_SEQUENCE(seq);
REQUIRE_CALL(obj, getter(ANY(int)))
.RETURN(3)
.IN_SEQUENCE(seq);
std::string s;
s += std::to_string(obj.getter(1));
s += std::to_string(obj.getter(1));
s += std::to_string(obj.getter(1));
REQUIRE(s == "123");
}
// SIDE_EFFECT and LR_SIDE_EFFECT tests
static int global_n = 0;
TEST_CASE_METHOD(Fixture, "side effect access copy of local object", "[side effects]")
{
int n = 1;
mock_c obj;
REQUIRE_CALL(obj, getter(ANY(int)))
.SIDE_EFFECT(global_n = n)
.RETURN(_1);
n = 2;
obj.getter(n);
REQUIRE(global_n == 1);
}
TEST_CASE_METHOD(Fixture, "lr side effect access reference of local object", "[side effects]")
{
int n = 1;
mock_c obj;
REQUIRE_CALL(obj, getter(ANY(int)))
.LR_SIDE_EFFECT(global_n = n)
.RETURN(_1);
n = 2;
obj.getter(n);
REQUIRE(global_n == 2);
}
TEST_CASE_METHOD(Fixture, "multiple side effects are executed in the order declared", "[side effects]")
{
std::string s;
mock_c obj;
REQUIRE_CALL(obj, getter(ANY(int)))
.LR_SIDE_EFFECT(s = std::to_string(_1))
.LR_SIDE_EFFECT(s += "_")
.LR_SIDE_EFFECT(s += s)
.RETURN(_1);
obj.getter(3);
REQUIRE(s == "3_3_");
}
// RETURN and LR_RETURN tests
TEST_CASE_METHOD(Fixture, "RETURN access copy of local object", "[return values]")
{
int n = 1;
mock_c obj;
REQUIRE_CALL(obj, getter(ANY(int)))
.RETURN(n);
n = 2;
auto m = obj.getter(n);
REQUIRE(m == 1);
}
TEST_CASE_METHOD(Fixture, "LR_RETURN access the actual local object", "[return values]")
{
int n = 1;
mock_c obj;
REQUIRE_CALL(obj, getter(ANY(int)))
.LR_RETURN(n);
n = 2;
auto m = obj.getter(n);
REQUIRE(m == 2);
}
TEST_CASE_METHOD(Fixture, "RETURN a std::ref of local obj by ref returns object given", "[return values]")
{
{
mock_c obj;
unmovable s;
REQUIRE_CALL(obj, getter(ANY(unmovable&)))
.LR_RETURN(std::ref(s));
REQUIRE(&obj.getter(s) == &s);
}
REQUIRE(reports.empty());
}
// THROW and LR_THROW tests
TEST_CASE_METHOD(Fixture, "RETURN ref param by reference via std::ref returns object given", "[return values]")
{
{
mock_c obj;
unmovable s;
REQUIRE_CALL(obj, getter(ANY(unmovable&)))
.RETURN(std::ref(_1));
REQUIRE(&obj.getter(s) == &s);
}
REQUIRE(reports.empty());
}
TEST_CASE_METHOD(Fixture, "THROW access copy of local object", "[return values]")
{
int n = 1;
mock_c obj;
REQUIRE_CALL(obj, getter(ANY(int)))
.THROW(n);
n = 2;
try {
obj.getter(n);
FAIL("didn't throw");
}
catch (int m)
{
REQUIRE(m == 1);
}
}
TEST_CASE_METHOD(Fixture, "LR_THROW access actual local object", "[return values]")
{
int n = 1;
mock_c obj;
REQUIRE_CALL(obj, getter(ANY(int)))
.LR_THROW(n);
n = 2;
try {
obj.getter(n);
FAIL("didn't throw");
}
catch (int m)
{
REQUIRE(m == 2);
}
}
TEST_CASE_METHOD(Fixture, "THROW throws after side effect when replacing return for non void functions", "[return values]")
{
int thrown = 0;
int global = 0;
try {
mock_c obj;
REQUIRE_CALL(obj, getter(ANY(int)))
.THROW(8)
.LR_SIDE_EFFECT(global = _1);
obj.getter(8);
FAIL("didn't throw");
}
catch (int n)
{
thrown = n;
}
REQUIRE(thrown == 8);
REQUIRE(global == 8);
}
TEST_CASE_METHOD(Fixture, "THROW throws after side effect in void functions", "[return values]")
{
int thrown = 0;
std::string s;
try {
mock_c obj;
REQUIRE_CALL(obj, func(_, _))
.THROW(8)
.SIDE_EFFECT(_2 = std::to_string(_1));
obj.func(8, s);
FAIL("didn't throw");
}
catch (int n)
{
thrown = n;
}
REQUIRE(thrown == 8);
REQUIRE(s == "8");
}
// WITH and LR_WITH tests
TEST_CASE_METHOD(Fixture, "WITH matches copy of local object", "[matching]")
{
mock_c obj;
int n = 1;
REQUIRE_CALL(obj, getter(ANY(int)))
.WITH(_1 == n)
.RETURN(_1);
n = 2;
obj.getter(1);
}
TEST_CASE_METHOD(Fixture, "LR_WITH access actual local object", "[matching]")
{
mock_c obj;
int n = 1;
REQUIRE_CALL(obj, getter(ANY(int)))
.LR_WITH(_1 == n)
.RETURN(_1);
n = 2;
obj.getter(2);
}
TEST_CASE_METHOD(Fixture, "rvalue reference parameter can be compared with nullptr in WITH", "[matching]")
{
{
mock_c obj;
REQUIRE_CALL(obj, ptr(_))
.WITH(_1 != nullptr)
.RETURN(std::move(_1));
auto p = obj.ptr(std::unique_ptr<int>(new int{ 3 }));
REQUIRE(p);
REQUIRE(*p == 3);
}
REQUIRE(reports.empty());
}
TEST_CASE_METHOD(Fixture, "rvalue reference parameter can be compared with external value on WITH", "[matching]")
{
{
mock_c obj;
auto pi = new int{ 3 };
REQUIRE_CALL(obj, ptr(_))
.WITH(_1.get() == pi)
.RETURN(std::move(_1));
auto p = obj.ptr(std::unique_ptr<int>(pi));
REQUIRE(p);
REQUIRE(p.get() == pi);
}
REQUIRE(reports.empty());
}
class U
{
public:
MAKE_MOCK1(func_u, void(const uncomparable&));
MAKE_MOCK1(func_v, void(int));
MAKE_MOCK1(func_cv, void(const int));
MAKE_MOCK1(func_lr, void(int&));
MAKE_MOCK1(func_clr, void(const int&));
MAKE_MOCK1(func_rr, void(int&&));
MAKE_MOCK1(func_crr, void(const int&&));
MAKE_MOCK1(func, void(int&));
MAKE_MOCK1(func, void(const int&));
MAKE_MOCK1(func, void(int&&));
};
// tests of direct parameter matching with fixed values and wildcards
TEST_CASE_METHOD(Fixture, "uncomparable parameter matches wildcard", "[matching]")
{
U u;
REQUIRE_CALL(u, func_u(_));
u.func_u(uncomparable{});
}
TEST_CASE_METHOD(Fixture, "uncomparable parameter matches typed wildcard", "[matching]")
{
U u;
REQUIRE_CALL(u, func_u(ANY(uncomparable)));
u.func_u(uncomparable{});
}
TEST_CASE_METHOD(Fixture, "wildcard matches parameter value type", "[matching]")
{
U u;
REQUIRE_CALL(u, func_v(_));
u.func_v(1);
}
TEST_CASE_METHOD(Fixture, "wildcard matches parameter const value type", "[matching]")
{
U u;
REQUIRE_CALL(u, func_cv(_));
u.func_cv(1);
}
TEST_CASE_METHOD(Fixture, "wildcard matches parameter lvalue reference type", "[matching]")
{
U u;
REQUIRE_CALL(u, func_lr(_));
int v = 1;
u.func_lr(v);
}
TEST_CASE_METHOD(Fixture, "wildcard matches parameter const lvalue reference type", "[matching]")
{
U u;
REQUIRE_CALL(u, func_clr(_));
int v = 1;
u.func_clr(v);
}
TEST_CASE_METHOD(Fixture, "wildcard matches parameter rvalue reference type", "[matching]")
{
U u;
REQUIRE_CALL(u, func_rr(_));
u.func_rr(1);
}
TEST_CASE_METHOD(Fixture, "wildcard matches parameter const rvalue reference type", "[matching]")
{
U u;
REQUIRE_CALL(u, func_crr(_));
u.func_crr(1);
}
TEST_CASE_METHOD(Fixture, "ANY can select overload on lvalue reference type", "[matching]")
{
U u;
REQUIRE_CALL(u, func(ANY(int&)));
int i = 1;
u.func(i);
}
TEST_CASE_METHOD(Fixture, "ANY can select overload on const lvalue reference type", "[matching]")
{
U u;
REQUIRE_CALL(u, func(ANY(const int&)));
const int i = 1;
u.func(i);
}
TEST_CASE_METHOD(Fixture, "ANY can select overload on rvalue reference type", "[matching]")
{
U u;
REQUIRE_CALL(u, func(ANY(int&&)));
u.func(1);
}
// tests of overload selection with parameter matching
TEST_CASE_METHOD(Fixture, "wildcards matches overload on type and parameter count", "[matching][overloads]")
{
{
mock_c obj;
REQUIRE_CALL(obj, getter(ANY(unmovable&)))
.RETURN(std::ref(_1));
FORBID_CALL(obj, getter(ANY(int)));
REQUIRE_CALL(obj, getter(_, _))
.SIDE_EFFECT(_2 = std::to_string(_1));
unmovable u;
auto& ur = obj.getter(u);
REQUIRE(&ur == &u);
std::string s;
obj.getter(3, s);
REQUIRE(s == "3");
}
REQUIRE(reports.empty());
}
// tests of parameter matching using typed matcher ne
TEST_CASE_METHOD(Fixture, "a non equal value matches ne", "[matching][matchers][ne]")
{
mock_c obj;
REQUIRE_CALL(obj, foo(trompeloeil::ne<std::string>("bar")));
obj.foo("baz");
}
TEST_CASE_METHOD(Fixture, "an equal value fails ne with report", "[matching][matchers][ne]")
{
try {
mock_c obj;
REQUIRE_CALL(obj, foo(trompeloeil::ne<std::string>("bar")));
obj.foo("bar");
FAIL("didn't report");
}
catch (reported)
{
REQUIRE(reports.size() == 1U);
INFO("report=" << reports.front().msg);
auto re = R":(No match for call of foo with signature void\(std::string\) with\.
param _1 = bar
Tried obj\.foo\(trompeloeil::ne<std::string>\("bar"\)\) at [A-Za-z0-9_ ./:\]*:[0-9]*.*
Expected _1 != bar):";
REQUIRE(std::regex_search(reports.front().msg, std::regex(re)));
}
}
// tests of parameter matching using typed matcher ge
TEST_CASE_METHOD(Fixture, "an equal value matches ge", "[matching][matchers][ge]")
{
mock_c obj;
REQUIRE_CALL(obj, getter(trompeloeil::ge(3)))
.RETURN(0);
obj.getter(3);
}
TEST_CASE_METHOD(Fixture, "a greater value matches ge", "[matching][matchers][ge]")
{
mock_c obj;
REQUIRE_CALL(obj, getter(trompeloeil::ge(3)))
.RETURN(0);
obj.getter(4);
}
TEST_CASE_METHOD(Fixture, "a lesser value is reported by ge", "[matching][matchers][ge]")
{
try {
mock_c obj;
REQUIRE_CALL(obj, getter(trompeloeil::ge(3)))
.RETURN(0);
obj.getter(2);
FAIL("didn't report");
}
catch (reported)
{
REQUIRE(reports.size() == 1U);
auto re = R":(No match for call of getter with signature int\(int\) with.
param _1 = 2
Tried obj\.getter\(trompeloeil::ge\(3\)\) at [A-Za-z0-9_ ./:\]*:[0-9]*.*
Expected _1 >= 3):";
REQUIRE(std::regex_search(reports.front().msg, std::regex(re)));
}
}
// tests of parameter matching using typed matcher gt
TEST_CASE_METHOD(Fixture, "an equal value is reported by gt", "[matching][matchers][gt]")
{
try {
mock_c obj;
REQUIRE_CALL(obj, getter(trompeloeil::gt(3)))
.RETURN(0);
obj.getter(3);
FAIL("didn't report");
}
catch (reported)
{
REQUIRE(reports.size() == 1U);
auto re = R":(No match for call of getter with signature int\(int\) with\.
param _1 = 3
Tried obj\.getter\(trompeloeil::gt\(3\)\) at [A-Za-z0-9_ ./:\]*:[0-9]*.*
Expected _1 > 3):";
REQUIRE(std::regex_search(reports.front().msg, std::regex(re)));
}
}
TEST_CASE_METHOD(Fixture, "a greater value matches gt", "[matching][matchers][gt]")
{
mock_c obj;
REQUIRE_CALL(obj, getter(trompeloeil::gt(3)))
.RETURN(0);
obj.getter(4);
}
TEST_CASE_METHOD(Fixture, "a lesser value is reported by gt", "[matching][matchers][gt]")
{
try {
mock_c obj;
REQUIRE_CALL(obj, getter(trompeloeil::gt(3)))
.RETURN(0);
obj.getter(2);
FAIL("didn't report");
}
catch (reported)
{
REQUIRE(reports.size() == 1U);
auto re = R":(No match for call of getter with signature int\(int\) with\.
param _1 = 2
Tried obj.getter\(trompeloeil::gt\(3\)\) at [A-Za-z0-9_ ./:\]*:[0-9]*.*
Expected _1 > 3):";
REQUIRE(std::regex_search(reports.front().msg, std::regex(re)));
}
}
// tests of parameter matching using typed matcher lt
TEST_CASE_METHOD(Fixture, "an equal value is reported by lt", "[matching][matchers][lt]")
{
try {
mock_c obj;
REQUIRE_CALL(obj, getter(trompeloeil::lt(3)))
.RETURN(0);
obj.getter(3);
FAIL("didn't report");
}
catch (reported)
{
REQUIRE(reports.size() == 1U);
auto re = R":(No match for call of getter with signature int\(int\) with\.
param _1 = 3
Tried obj\.getter\(trompeloeil::lt\(3\)\) at [A-Za-z0-9_ ./:\]*:[0-9]*.*
Expected _1 < 3):";
REQUIRE(std::regex_search(reports.front().msg, std::regex(re)));
}
}
TEST_CASE_METHOD(Fixture, "a greater value is reported by lt", "[matching][matchers][lt]")
{
try {
mock_c obj;
REQUIRE_CALL(obj, getter(trompeloeil::lt(3)))
.RETURN(0);
obj.getter(4);
FAIL("didn't report");
}
catch (reported)
{
REQUIRE(reports.size() == 1U);
auto re = R":(No match for call of getter with signature int\(int\) with\.
param _1 = 4
Tried obj\.getter\(trompeloeil::lt\(3\)\) at [A-Za-z0-9_ ./:\]*:[0-9]*.*
Expected _1 < 3):";
REQUIRE(std::regex_search(reports.front().msg, std::regex(re)));
}
}
TEST_CASE_METHOD(Fixture, "a lesser value matches lt", "[matching][matchers][lt]")
{
mock_c obj;
REQUIRE_CALL(obj, getter(trompeloeil::lt(3)))
.RETURN(0);
obj.getter(2);
}
// tests of parameter matching using typed matcher le
TEST_CASE_METHOD(Fixture, "an equal value matches le", "[matching][matchers][le]")
{
mock_c obj;
REQUIRE_CALL(obj, getter(trompeloeil::le(3)))
.RETURN(0);
obj.getter(3);
}
TEST_CASE_METHOD(Fixture, "a greater value is reported by le", "[matching][matchers][le]")
{
try {
mock_c obj;
REQUIRE_CALL(obj, getter(trompeloeil::le(3)))
.RETURN(0);
obj.getter(4);
FAIL("didn't report");
}
catch (reported)
{
REQUIRE(reports.size() == 1U);
auto re = R":(No match for call of getter with signature int\(int\) with\.
param _1 = 4
Tried obj\.getter\(trompeloeil::le\(3\)\) at [A-Za-z0-9_ ./:\]*:[0-9]*.*
Expected _1 <= 3):";
REQUIRE(std::regex_search(reports.front().msg, std::regex(re)));
}
}
TEST_CASE_METHOD(Fixture, "a lesser value matches le", "[matching][matchers][le]")
{
mock_c obj;
REQUIRE_CALL(obj, getter(trompeloeil::le(3)))
.RETURN(0);
obj.getter(2);
}
// tests of parameter matching using custom typed matcher
template <typename T>
class any_of_t : public trompeloeil::typed_matcher<T>
{
public:
any_of_t(std::initializer_list<T> elements) : alternatives(std::begin(elements), std::end(elements)) {}
bool matches(T const& t) const
{
return std::any_of(std::begin(alternatives), std::end(alternatives),
[&](T val) { return t == val; });
}
friend std::ostream& operator<<(std::ostream& os, any_of_t<T> const& t)
{
os << " matching any_of({";
char const* prefix = " ";
for (auto& n : t.alternatives)
{
os << prefix << n;
prefix = ", ";
}
return os << " })";
}
private:
std::vector<T> alternatives;
};
template <typename T>
auto any_of(std::initializer_list<T> elements)
{
return any_of_t<T>(elements);
}
TEST_CASE_METHOD(Fixture, "custom matcher of first element is not reported", "[matching][matchers][custom]")
{
mock_c obj;
REQUIRE_CALL(obj, getter(any_of({ 1, 5, 77 })))
.RETURN(0);
obj.getter(1);
}
TEST_CASE_METHOD(Fixture, "custom matcher of last element is not reported", "[matching][matchers][custom]")
{
mock_c obj;
REQUIRE_CALL(obj, getter(any_of({ 1, 5, 77 })))
.RETURN(0);
obj.getter(77);
}
TEST_CASE_METHOD(Fixture, "custom matcher of mid element is not reported", "[matching][matchers][custom]")
{
mock_c obj;
REQUIRE_CALL(obj, getter(any_of({ 1, 5, 77 })))
.RETURN(0);
obj.getter(5);
}
TEST_CASE_METHOD(Fixture, "custom matcher of unlisted element is reported", "[matching][matchers][custom]")
{
try {
mock_c obj;
REQUIRE_CALL(obj, getter(any_of({ 1,5,77 })))
.RETURN(0);
obj.getter(4);
FAIL("didn't report");
}
catch (reported)
{
REQUIRE(reports.size() == 1U);
INFO("report=" << reports.front().msg);
auto re = R":(No match for call of getter with signature int\(int\) with\.
param _1 = 4
Tried obj\.getter\(any_of\(\{ 1,5,77 \}\)\) at [A-Za-z0-9_ ./:\]*:[0-9]*.*
Expected _1 matching any_of\(\{ 1, 5, 77 \}\)):";
REQUIRE(std::regex_search(reports.front().msg, std::regex(re)));
}
}
// tests of parameter matching using custom duck-typed matcher
template <typename T>
class has_empty
{
struct no;
static no func(...);
template <typename U>
static auto func(U const* u) -> decltype(u->empty());
public:
static const bool value = !std::is_same<no, decltype(func(std::declval<T*>()))>::value;
};
class not_empty : public trompeloeil::matcher
{
public:
template <typename T, typename = typename std::enable_if<has_empty<T>::value>::type>
operator T() const;
template <typename T>
bool matches(T const& t) const
{
return !t.empty();
}
friend std::ostream& operator<<(std::ostream& os, not_empty const&)
{
return os << " is not empty";
}
};
TEST_CASE_METHOD(Fixture, "a non empty string gives no report", "[matching][matchers][custom]")
{
mock_c obj;
REQUIRE_CALL(obj, foo(not_empty{}));
obj.foo("bar");
}
TEST_CASE_METHOD(Fixture, "an empty string is reported", "[matching][matchers][custom]")
{
try {
mock_c obj;
REQUIRE_CALL(obj, foo(not_empty{}));
obj.foo("");
FAIL("didn't report");
}
catch (reported)
{
REQUIRE(reports.size() == 1U);
auto re = R":(No match for call of foo with signature void\(std::string\) with\.
param _1 =
Tried obj\.foo\(not_empty\{\}\) at [A-Za-z0-9_ ./:\]*:[0-9]*.*
Expected _1 is not empty):";
REQUIRE(std::regex_search(reports.front().msg, std::regex(re)));
}
}
// tests of parameter values ostream insertion
struct unknown {
const char values[4] = { 0x10, 0x11, 0x12, 0x13 };
};
TEST_CASE_METHOD(Fixture, "unknown type is printed as hex dump", "[streaming]")
{
std::ostringstream os;
trompeloeil::print(os, unknown{});
REQUIRE(os.str() == "4-byte object={ 0x10 0x11 0x12 0x13 }");
}
TEST_CASE_METHOD(Fixture, "print after unknown has flags back to default", "[streaming]")
{
std::ostringstream os;
trompeloeil::print(os, unknown{});
int16_t u = 10000;
os << u;
REQUIRE(os.str() == "4-byte object={ 0x10 0x11 0x12 0x13 }10000");
}
TEST_CASE_METHOD(Fixture, "previous formatting is ignored before hexdump and then reset", "[streaming]")
{
std::ostringstream os;
os << std::oct << std::setfill('_') << std::setw(4) << std::left;
trompeloeil::print(os, unknown{});
os << 8;
REQUIRE(os.str() == "4-byte object={ 0x10 0x11 0x12 0x13 }10__");
}
TEST_CASE_METHOD(Fixture, "call predefined ostream operator with defaulted flags and then reset", "[streaming]")
{
std::ostringstream os;
os << std::oct << std::setfill('_') << std::setw(4) << std::left;
trompeloeil::print(os, 25);
os << 8;
REQUIRE(os.str() == "2510__");
}
TEST_CASE_METHOD(Fixture, "large unknown is multi row hex dump", "[streaming]")
{
struct big {
char c[64] = { 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f };
};
std::ostringstream os;
trompeloeil::print(os, big{});
char str[] = R"__(64-byte object={
0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1a 0x1b 0x1c 0x1d 0x1e 0x1f
0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2a 0x2b 0x2c 0x2d 0x2e 0x2f
0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3a 0x3b 0x3c 0x3d 0x3e 0x3f
0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4a 0x4b 0x4c 0x4d 0x4e 0x4f
})__";
auto s = os.str();
REQUIRE(os.str() == str);
}
TEST_CASE_METHOD(Fixture, "unknown object is one line if 8 bytes", "[streaming]")
{
struct big {
char c[8] = { 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17 };
};
std::ostringstream os;
trompeloeil::print(os, big{});
REQUIRE(os.str() == "8-byte object={ 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 }");
}
// tests on scoping (lifetime) of expectations
TEST_CASE_METHOD(Fixture, "require calls are matched in reversed order of creation", "[scoping]")
{
{
mock_c obj;
ALLOW_CALL(obj, getter(_, _))
.SIDE_EFFECT(_2 = std::to_string(_1));
REQUIRE_CALL(obj, getter(3, _))
.SIDE_EFFECT(_2 = "III")
.TIMES(2);
std::string s;
obj.getter(2, s);
REQUIRE(s == "2");
obj.getter(3, s);
REQUIRE(s == "III");
obj.getter(1, s);
REQUIRE(s == "1");
obj.getter(3, s);
REQUIRE(s == "III");
obj.getter(3, s);
REQUIRE(s == "3");
}
REQUIRE(reports.empty());
}
TEST_CASE_METHOD(Fixture, "require calls are removed when they go out of scope", "[scoping]")
{
{
mock_c obj;
std::string s;
ALLOW_CALL(obj, getter(_, _))
.SIDE_EFFECT(_2 = std::to_string(_1));
{
REQUIRE_CALL(obj, getter(3, _))
.SIDE_EFFECT(_2 = "III")
.TIMES(1, 8);
obj.getter(3, s);
REQUIRE(s == "III");
obj.getter(2, s);
REQUIRE(s == "2");
obj.getter(3, s);
REQUIRE(s == "III");
}
obj.getter(3, s);
REQUIRE(s == "3");
}
REQUIRE(reports.empty());
}
TEST_CASE_METHOD(Fixture, "an unsatisfied require call is reported at end of scope", "[scoping]")
{
mock_c obj;
{
REQUIRE_CALL(obj, foo("bar"));
}
REQUIRE(reports.size() == 1U);
auto re = R":(Unfulfilled expectation:
Expected obj\.foo\("bar"\) to be called once, actually never called
param _1 = bar):";
REQUIRE(std::regex_search(reports.front().msg, std::regex(re)));
}
// test of multiplicity retiring expectations, fulfilled or not
TEST_CASE_METHOD(Fixture, "no calls reported as never called", "[scoping][multiplicity]")
{
mock_c obj;
{
REQUIRE_CALL(obj, count())
.RETURN(1);
}
REQUIRE(reports.size() == 1U);
REQUIRE(std::regex_search(reports.front().msg, std::regex("actually never called")));
}
TEST_CASE_METHOD(Fixture, "undersatisfied with one call reported as once", "[scoping][multiplicity]")
{
mock_c obj;
{
REQUIRE_CALL(obj, count())
.RETURN(1)
.TIMES(2);
obj.count();
}
REQUIRE(reports.size() == 1U);
REQUIRE(std::regex_search(reports.front().msg, std::regex("actually called once")));
}
TEST_CASE_METHOD(Fixture, "undersatisfied with two call reported as count", "[scoping][multiplicity]")
{
mock_c obj;
{
REQUIRE_CALL(obj, count())
.RETURN(1)
.TIMES(3);
obj.count();
obj.count();
}
REQUIRE(reports.size() == 1U);
REQUIRE(std::regex_search(reports.front().msg, std::regex("actually called 2 times")));
}
TEST_CASE_METHOD(Fixture, "no calls when one required reported as expected once", "[scoping][multiplicity]")
{
mock_c obj;
{
REQUIRE_CALL(obj, count())
.RETURN(1);
}
REQUIRE(reports.size() == 1U);
REQUIRE(std::regex_search(reports.front().msg, std::regex("to be called once")));
}
TEST_CASE_METHOD(Fixture, "no calls when two required reported as expected 2 times", "[scoping][multiplicity]")
{
mock_c obj;
{
REQUIRE_CALL(obj, count())
.TIMES(2)
.RETURN(1);
}
REQUIRE(reports.size() == 1U);
REQUIRE(std::regex_search(reports.front().msg, std::regex("to be called 2 times")));
}
// test of destruction, or lack of, for deathwatched objects
TEST_CASE_METHOD(Fixture, "an unexpected destruction of monitored object is reported", "[deatwatched]")
{
{
trompeloeil::deathwatched<mock_c> obj;
}
REQUIRE(reports.size() == 1U);
REQUIRE(std::regex_search(reports.front().msg, std::regex("Unexpected destruction of.*@")));
}
TEST_CASE_METHOD(Fixture, "an expected destruction of monitored object is not reported", "[deatwatched]")
{
{
auto obj = new trompeloeil::deathwatched<mock_c>;
REQUIRE_DESTRUCTION(*obj);
delete obj;
}
REQUIRE(reports.empty());
}
class none
{
public:
virtual ~none() = default;
};
TEST_CASE_METHOD(Fixture, "a copy of a deathwatched object with expectation is not expected to die", "[deatwatched]")
{
auto orig = new trompeloeil::deathwatched<none>;
REQUIRE_DESTRUCTION(*orig);
auto copy = new trompeloeil::deathwatched<none>(*orig);
delete orig;
REQUIRE(reports.empty());
delete copy;
REQUIRE(reports.size() == 1U);
REQUIRE(std::regex_search(reports.front().msg, std::regex("Unexpected destruction of .*@")));
}
TEST_CASE_METHOD(Fixture, "a deathwatched object move constructed from original with expectation is not expected to die and the original still is", "[deatwatched]")
{
auto orig = new trompeloeil::deathwatched<none>;
REQUIRE_DESTRUCTION(*orig);
auto copy = new trompeloeil::deathwatched<none>(std::move(*orig));
delete orig;
REQUIRE(reports.empty());
delete copy;
REQUIRE(reports.size() == 1U);
REQUIRE(std::regex_search(reports.front().msg, std::regex("Unexpected destruction of .*@")));
}
TEST_CASE_METHOD(Fixture, "object alive when destruction expectation goes out of scope is reported", "[deatwatched]")
{
trompeloeil::deathwatched<mock_c> obj;
{
auto p = NAMED_REQUIRE_DESTRUCTION(obj);
}
REQUIRE(reports.size() == 1U);
REQUIRE(std::regex_search(reports.front().msg, std::regex("Object obj is still alive")));
}
TEST_CASE_METHOD(Fixture, "require destruction succeeds also without deathwatch", "[deatwatched]")
{
{
auto obj = new trompeloeil::deathwatched<mock_c>;
REQUIRE_DESTRUCTION(*obj);
delete obj;
}
REQUIRE(reports.empty());
}
TEST_CASE_METHOD(Fixture, "a deathwatched objects constructor passes params to mock", "[deatwatched]")
{
auto obj = new trompeloeil::deathwatched<mock_c>{ "apa" };
REQUIRE(obj->p_ == std::string("apa"));
REQUIRE_DESTRUCTION(*obj);
delete obj;
}
// tests of calls that do not match any valid expections
TEST_CASE_METHOD(Fixture, "unmatched call is reported", "[mismatches]")
{
try {
mock_c obj;
obj.getter(7);
FAIL("didn't throw!");
}
catch (reported)
{
REQUIRE(reports.size() == 1U);
auto re = R":(No match for call of getter with signature int\(int\) with\.
param _1 = 7):";
REQUIRE(std::regex_search(reports.front().msg, std::regex(re)));
}
}
TEST_CASE_METHOD(Fixture, "match of saturated call is reported", "[mismatches]")
{
int count = 0;
try {
mock_c obj;
ALLOW_CALL(obj, getter(ANY(int)))
.WITH(_1 != 3)
.RETURN(1);
REQUIRE_CALL(obj, getter(3))
.TIMES(3)
.RETURN(1);
count += obj.getter(4); // 1
count += obj.getter(2); // 2
count += obj.getter(3); // 3 -> 1
count += obj.getter(4); // 4
count += obj.getter(2); // 5
count += obj.getter(3); // 6 -> 2
count += obj.getter(5); // 7
count += obj.getter(3); // 8 -> 3
count += obj.getter(8); // 9
count += obj.getter(3); // boom!
FAIL("didn't report");
}
catch (reported)
{
REQUIRE(count == 9);
REQUIRE(reports.size() == 1U);
auto re =
R":(No match for call of getter with signature int\(int\) with\.
param _1 = 3
Matches saturated call requirement
obj\.getter\(3\) at [A-Za-z0-9_ ./:\]*:[0-9]*.*):";
REQUIRE(std::regex_search(reports.front().msg, std::regex(re)));
}
}
TEST_CASE_METHOD(Fixture, "a matching call that throws is saturated", "[mismatches]")
{
int count = 0;
try {
mock_c obj;
ALLOW_CALL(obj, getter(ANY(int)))
.WITH(_1 != 3)
.RETURN(1);
REQUIRE_CALL(obj, getter(3))
.TIMES(3)
.SIDE_EFFECT(throw 0)
.RETURN(1);
count += obj.getter(4); // 1
count += obj.getter(2); // 2
try {
count += obj.getter(3); // 2 -> 1
FAIL("didn't throw");
}
catch (int) {}
count += obj.getter(4); // 3
count += obj.getter(2); // 4
try {
count += obj.getter(3); // 4 -> 2
FAIL("didn't throw");
}
catch (int) {}
count += obj.getter(5); // 5
try {
count += obj.getter(3); // 5 -> 3
FAIL("didn't throw");
}
catch (int) {}
count += obj.getter(8); // 6
count += obj.getter(3); // boom!
FAIL("didn't report");
}
catch (reported)
{
REQUIRE(count == 6);
REQUIRE(reports.size() == 1U);
auto re =
R":(No match for call of getter with signature int\(int\) with\.
param _1 = 3
Matches saturated call requirement
obj\.getter\(3\) at [A-Za-z0-9_ ./:\]*:[0-9]*.*):";
REQUIRE(std::regex_search(reports.front().msg, std::regex(re)));
}
}
TEST_CASE_METHOD(Fixture, "unmatched call with mismatching requirements is reported", "[mismatches]")
{
try {
mock_c obj;
REQUIRE_CALL(obj, getter(4))
.RETURN(0);
REQUIRE_CALL(obj, getter(5))
.RETURN(0);
obj.getter(3);
}
catch (reported)
{
REQUIRE(reports.size() == 1U);
auto re =
R":(No match for call of getter with signature int\(int\) with\.
param _1 = 3
Tried obj\.getter\(5\) at [A-Za-z0-9_ ./:\]*:[0-9]*.*
Expected _1 = 5
Tried obj\.getter\(4\) at [A-Za-z0-9_ ./:\]*:[0-9]*.*
Expected _1 = 4):";
REQUIRE(std::regex_search(reports.front().msg, std::regex(re)));
}
}
TEST_CASE_METHOD(Fixture, "unmatched with wildcard reports failed WITH clauses", "[mismatches]")
{
try {
mock_c obj;
REQUIRE_CALL(obj, getter(ANY(int)))
.WITH(_1 < 3)
.WITH(_1 > 5)
.RETURN(0);
obj.getter(4);
}
catch (reported)
{
REQUIRE(reports.size() == 1U);
auto re =
R":(No match for call of getter with signature int\(int\) with\.
param _1 = 4
Tried obj\.getter\(ANY\(int\)\) at [A-Za-z0-9_ ./:\]*:[0-9]*.*
Failed WITH\(_1 < 3\)
Failed WITH\(_1 > 5\)):";
REQUIRE(std::regex_search(reports.front().msg, std::regex(re)));
}
}
TEST_CASE_METHOD(Fixture, "unmatched with wildcard reports only failed WITH clauses", "[mismatches]")
{
try {
mock_c obj;
REQUIRE_CALL(obj, getter(ANY(int)))
.WITH(_1 < 3)
.WITH(_1 > 3)
.RETURN(0);
obj.getter(4);
}
catch (reported)
{
REQUIRE(reports.size() == 1U);
auto re =
R":(No match for call of getter with signature int\(int\) with\.
param _1 = 4
Tried obj\.getter\(ANY\(int\)\) at [A-Za-z0-9_ ./:\]*:[0-9]*.*
Failed WITH\(_1 < 3\)):";
REQUIRE(std::regex_search(reports.front().msg, std::regex(re)));
}
}
TEST_CASE_METHOD(Fixture, "match of forbidden call is reported", "[mismatches]")
{
try {
mock_c obj;
ALLOW_CALL(obj, getter(ANY(int)))
.RETURN(0);
FORBID_CALL(obj, getter(3));
obj.getter(4);
obj.getter(2);
obj.getter(3);
FAIL("didn't report");
}
catch (reported)
{
REQUIRE(reports.size() == 1U);
INFO("report=" << reports.front().msg);
auto re = R":(Match of forbidden call of obj\.getter\(3\) at [A-Za-z0-9_ ./:\]*:[0-9]*.*
param _1 = 3):";
REQUIRE(std::regex_search(reports.front().msg, std::regex(re)));
}
}
// tests of parameter passing to expectations
class T
{
public:
MAKE_MOCK15(concats, std::string(int, int, int, int,
int, int, int, int,
int, int, int, int,
int, int, int));
MAKE_MOCK1(ptr, void(std::shared_ptr<int>));
MAKE_MOCK1(ptr, void(std::unique_ptr<int>));
};
TEST_CASE_METHOD(Fixture, "parameters are passed in correct order when matching", "[parameters]")
{
T obj;
REQUIRE_CALL(obj, concats(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15))
.RETURN("");
auto s = obj.concats(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15);
REQUIRE(s == "");
}
TEST_CASE_METHOD(Fixture, "parameters are passed in correct order to WITH", "[parameters]")
{
T obj;
REQUIRE_CALL(obj, concats(_, _, _, _, _, _, _, _, _, _, _, _, _, _, _))
.WITH(_1 == 1 && _2 == 2 && _3 == 3 && _4 == 4 &&
_5 == 5 && _6 == 6 && _7 == 7 && _8 == 8 &&
_9 == 9 && _10 == 10 && _11 == 11 && _12 == 12 &&
_13 == 13 && _14 == 14 && _15 == 15)
.RETURN("");
auto s = obj.concats(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15);
REQUIRE(s == "");
}
TEST_CASE_METHOD(Fixture, "parameters are passed in correct order to LR_SIDE_EFFECT", "[parameters]")
{
T obj;
int n = 0;
REQUIRE_CALL(obj, concats(_, _, _, _, _, _, _, _, _, _, _, _, _, _, _))
.LR_SIDE_EFFECT(n = _1 + _2 - _3 + _4 - _5 + _6 - _7 + _8 - _9 + _10 - _11 + _12 - _13 + _14 - _15)
.RETURN("");
auto s = obj.concats(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15);
REQUIRE(n == -6);
}
TEST_CASE_METHOD(Fixture, "parameters are passed in correct order to RETURN", "[parameters]")
{
T obj;
REQUIRE_CALL(obj, concats(_, _, _, _, _, _, _, _, _, _, _, _, _, _, _))
.RETURN(std::to_string(_1) +
std::to_string(_2) +
std::to_string(_3) +
std::to_string(_4) +
std::to_string(_5) +
std::to_string(_6) +
std::to_string(_7) +
std::to_string(_8) +
std::to_string(_9) +
std::to_string(_10) +
std::to_string(_11) +
std::to_string(_12) +
std::to_string(_13) +
std::to_string(_14) +
std::to_string(_15));
auto s = obj.concats(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15);
REQUIRE(s == "123456789101112131415");
}
TEST_CASE_METHOD(Fixture, "parameters are passed in correct order to THROW", "[parameters]")
{
T obj;
REQUIRE_CALL(obj, concats(_, _, _, _, _, _, _, _, _, _, _, _, _, _, _))
.THROW(_1 + _2 - _3 + _4 - _5 + _6 - _7 + _8 - _9 + _10 - _11 + _12 - _13 + _14 - _15);
try {
obj.concats(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15);
FAIL("didn't throw");
}
catch (int n)
{
REQUIRE(n == -6);
}
}
TEST_CASE_METHOD(Fixture, "shared ptr by value in expectation is copied", "[parameters]")
{
T obj;
auto s = std::make_shared<int>(3);
{
REQUIRE_CALL(obj, ptr(s));
REQUIRE(s.use_count() == 2U);
obj.ptr(s);
}
REQUIRE(s.use_count() == 1U);
}
TEST_CASE_METHOD(Fixture, "shared ptr by std ref in expectation is not copied", "[parameters]")
{
T obj;
auto s = std::make_shared<int>(3);
{
REQUIRE_CALL(obj, ptr(std::ref(s)));
REQUIRE(s.use_count() == 1U);
obj.ptr(s);
}
REQUIRE(s.use_count() == 1U);
}
TEST_CASE_METHOD(Fixture, "unique ptr by value is matched with raw ptr in WITH", "[parameters]")
{
T obj;
auto s = std::unique_ptr<int>(new int(3));
{
auto sr = s.get();
REQUIRE_CALL(obj, ptr(ANY(std::unique_ptr<int>)))
.WITH(_1.get() == sr);
obj.ptr(std::move(s));
REQUIRE_FALSE(s);
}
}
// tests of tracing of matched calls
TEST_CASE_METHOD(Fixture, "matching calls are traced", "[tracing]")
{
std::ostringstream os;
trompeloeil::stream_tracer logger(os);
mock_c obj1;
mock_c obj2;
REQUIRE_CALL(obj1, getter(_, _));
REQUIRE_CALL(obj2, foo("bar"));
std::string s = "foo";
obj1.getter(3, s);
obj2.foo("bar");
auto re =
R":([A-Za-z0-9_ ./:\]*:[0-9]*.*
obj1\.getter\(_, _\) with.
param _1 = 3
param _2 = foo
[A-Za-z0-9_ ./:\]*:[0-9]*.*
obj2\.foo\("bar"\) with\.
param _1 = bar
):";
REQUIRE(std::regex_search(os.str(), std::regex(re)));
}
TEST_CASE_METHOD(Fixture, "tracing is only active when tracer obj is alive", "[tracing]")
{
std::ostringstream os;
mock_c obj1;
mock_c obj2;
ALLOW_CALL(obj1, getter(_, _));
REQUIRE_CALL(obj2, foo("bar"));
std::string s = "foo";
obj1.getter(3, s);
{
trompeloeil::stream_tracer logger(os);
obj2.foo("bar");
}
obj1.getter(4, s);
auto re =
R":([A-Za-z0-9_ ./:\]*:[0-9]*.*
obj2\.foo\("bar"\) with\.
param _1 = bar
):";
REQUIRE(std::regex_search(os.str(), std::regex(re)));
}