Replace Boost PP_Iterate by C++11 variadic templates

This allows support for any number of arguments and makes setting MOCK_MAX_ARGS unnecessary.
It also allows for easier debugging due to being able to step into actual code instead of preprocessor generated stuff
This commit is contained in:
Alexander Grund 2022-01-31 19:27:57 +01:00
parent 90d9ac8055
commit fca30e7780
No known key found for this signature in database
GPG key ID: AA48A0760367A42B
17 changed files with 368 additions and 472 deletions

View file

@ -18,10 +18,6 @@
# define MOCK_USE_BOOST_TEST
#endif
#ifndef MOCK_MAX_ARGS
# define MOCK_MAX_ARGS 9
#endif
#ifndef MOCK_MAX_SEQUENCES
# define MOCK_MAX_SEQUENCES 10
#endif

View file

@ -0,0 +1,184 @@
// http://turtle.sourceforge.net
//
// Copyright Mathieu Champlon 2012
//
// Distributed under 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)
#ifndef MOCK_EXPECTATION_HPP_INCLUDED
#define MOCK_EXPECTATION_HPP_INCLUDED
#include "../matcher.hpp"
#include "../sequence.hpp"
#include "action.hpp"
#include "invocation.hpp"
#include "matcher_base.hpp"
#include <memory>
#include <tuple>
#include <type_traits>
#include <vector>
namespace mock { namespace detail {
template<typename... Args>
class default_matcher : public matcher_base<Args...>
{
private:
bool operator()(typename ref_arg<Args>::type...) override { return true; }
void serialize(std::ostream& s) const override
{
for(unsigned i = 0; i < sizeof...(Args); ++i)
{
if(i)
s << ", ";
s << "any";
}
}
};
template<typename ConstraintPack, typename... Args>
class single_matcher;
template<typename... Constraints, typename... Args>
class single_matcher<void(Constraints...), Args...> : public matcher_base<Args...>
{
static_assert(sizeof...(Args) > 0, "This class is only useful for functions with arguments");
static_assert(sizeof...(Constraints) == sizeof...(Args), "Need exactly 1 constraint per argument");
public:
single_matcher(Constraints... constraints) : matchers_(matcher<Args, Constraints>(constraints)...) {}
private:
template<std::size_t... I>
bool is_valid_impl(std::index_sequence<I...>, typename ref_arg<Args>::type... t)
{
using expander = bool[];
bool result = true;
(void)expander{ result &= std::get<I>(matchers_)(std::forward<Args>(t))... };
return result;
}
bool operator()(typename ref_arg<Args>::type... t) override
{
return is_valid_impl(std::make_index_sequence<sizeof...(Args)>{}, std::forward<Args>(t)...);
}
template<std::size_t... I>
void serialize_impl(std::index_sequence<I...>, std::ostream& s) const
{
using expander = int[];
s << std::get<0>(matchers_);
(void)expander{ 0, (s << ", " << std::get<I + 1>(matchers_), 0)... };
}
void serialize(std::ostream& s) const override
{
serialize_impl(std::make_index_sequence<sizeof...(Args) - 1>{}, s);
}
private:
std::tuple<matcher<Args, Constraints>...> matchers_;
};
template<typename F, typename... Args>
class multi_matcher : public matcher_base<Args...>
{
static_assert(sizeof...(Args) > 0, "This class is only useful for functions with arguments");
public:
multi_matcher(const F& f) : f_(f) {}
private:
bool operator()(typename ref_arg<Args>::type... t) override { return f_(std::forward<Args>(t)...); }
void serialize(std::ostream& s) const override { s << mock::format(f_); }
private:
F f_;
};
template<typename Signature>
class expectation;
template<typename R, typename... Args>
class expectation<R(Args...)> : public action<R, R(Args...)>
{
static constexpr auto arity = sizeof...(Args);
public:
expectation() : expectation("unknown location", 0) {}
expectation(const char* file, int line)
: invocation_(std::make_unique<unlimited>()), matcher_(std::make_unique<default_matcher<Args...>>()),
file_(file), line_(line)
{}
expectation(expectation&&) = default;
expectation(expectation const&) = default;
expectation& operator=(expectation&&) = default;
expectation& operator=(expectation const&) = default;
~expectation()
{
for(auto& sequence : sequences_)
sequence->remove(this);
}
void invoke(std::unique_ptr<invocation> i) { invocation_ = std::move(i); }
template<typename... Constraints>
std::enable_if_t<(arity > 0) && sizeof...(Constraints) == arity, expectation&> with(Constraints... c)
{
matcher_ = std::make_unique<single_matcher<void(Constraints...), Args...>>(c...);
return *this;
}
template<typename Constraint, std::size_t Arity = arity>
std::enable_if_t<(Arity > 1), expectation&> with(const Constraint& c)
{
matcher_ = std::make_unique<multi_matcher<Constraint, Args...>>(c);
return *this;
}
void add(sequence& s)
{
s.impl_->add(this);
sequences_.push_back(s.impl_);
}
bool verify() const { return invocation_->verify(); }
bool is_valid(typename ref_arg<Args>::type... t) const
{
return !invocation_->exhausted() && (*matcher_)(std::forward<Args>(t)...);
}
bool invoke() const
{
for(auto& sequence : sequences_)
{
if(!sequence->is_valid(this))
return false;
}
bool result = invocation_->invoke();
for(auto& sequence : sequences_)
sequence->invalidate(this);
return result;
}
const char* file() const { return file_; }
int line() const { return line_; }
friend std::ostream& operator<<(std::ostream& s, const expectation& e)
{
s << (e.invocation_->exhausted() ? 'v' : '.') << ' ' << *e.invocation_;
constexpr bool hasArguments = arity > 0u;
if(hasArguments)
s << ".with( " << *e.matcher_ << " )";
return s;
}
private:
std::unique_ptr<invocation> invocation_;
std::unique_ptr<matcher_base<Args...>> matcher_;
std::vector<std::shared_ptr<sequence_impl>> sequences_;
const char* file_;
int line_;
};
}} // namespace mock::detail
#endif // MOCK_EXPECTATION_HPP_INCLUDED

View file

@ -1,201 +0,0 @@
// http://turtle.sourceforge.net
//
// Copyright Mathieu Champlon 2012
//
// Distributed under 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)
#include "matcher_base_template.hpp"
#define MOCK_EXPECTATION_INITIALIZE(z, n, d) BOOST_PP_COMMA_IF(n) c##n##_(c##n)
#define MOCK_EXPECTATION_MEMBER(z, n, d) matcher<T##n, Constraint_##n> c##n##_;
#define MOCK_EXPECTATION_IS_VALID(z, n, d) BOOST_PP_IF(n, &&, ) c##n##_(std::forward<T##n>(a##n))
#define MOCK_EXPECTATION_SERIALIZE(z, n, d) BOOST_PP_IF(n, << ", " <<, ) c##n##_
#define MOCK_EXPECTATION_SERIALIZE_ANY(z, n, d) BOOST_PP_IF(n, << ", " <<, ) "any"
#define MOCK_EXPECTATION_PARAM(z, n, Args) std::forward<T##n>(a##n)
#define MOCK_REF_ARG(z, n, d) typename ref_arg<T##n>::type a##n
#define MOCK_REF_ARG_T(z, n, d) typename ref_arg<T##n>::type
namespace mock { namespace detail {
template<typename Signature>
class default_matcher;
template<BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, typename T)>
class default_matcher<void(BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, T))> :
public matcher_base<void(BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, T))>
{
private:
virtual bool operator()(BOOST_PP_ENUM(MOCK_NUM_ARGS, MOCK_REF_ARG_T, _)) { return true; }
virtual void serialize(std::ostream& s) const
{
s << "" BOOST_PP_REPEAT(MOCK_NUM_ARGS, MOCK_EXPECTATION_SERIALIZE_ANY, _);
}
};
#ifndef MOCK_NUM_ARGS_0
template<typename Constraint, typename Signature>
class single_matcher;
template<BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, typename Constraint_), BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, typename T)>
class single_matcher<void(BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, Constraint_)),
void(BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, T))> :
public matcher_base<void(BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, T))>
{
public:
single_matcher(BOOST_PP_ENUM_BINARY_PARAMS(MOCK_NUM_ARGS, Constraint_, c))
: BOOST_PP_REPEAT(MOCK_NUM_ARGS, MOCK_EXPECTATION_INITIALIZE, _)
{}
private:
virtual bool operator()(BOOST_PP_ENUM(MOCK_NUM_ARGS, MOCK_REF_ARG, _))
{
return BOOST_PP_REPEAT(MOCK_NUM_ARGS, MOCK_EXPECTATION_IS_VALID, _);
}
virtual void serialize(std::ostream& s) const
{
s << BOOST_PP_REPEAT(MOCK_NUM_ARGS, MOCK_EXPECTATION_SERIALIZE, _);
}
private:
BOOST_PP_REPEAT(MOCK_NUM_ARGS, MOCK_EXPECTATION_MEMBER, _)
};
template<typename F, typename Signature>
class multi_matcher;
template<typename F, BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, typename T)>
class multi_matcher<F, void(BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, T))> :
public matcher_base<void(BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, T))>
{
public:
multi_matcher(const F& f) : f_(f) {}
private:
virtual bool operator()(BOOST_PP_ENUM(MOCK_NUM_ARGS, MOCK_REF_ARG, _))
{
return f_(BOOST_PP_ENUM(MOCK_NUM_ARGS, MOCK_EXPECTATION_PARAM, _));
}
virtual void serialize(std::ostream& s) const { s << mock::format(f_); }
private:
F f_;
};
#endif
template<typename Signature>
class expectation;
template<typename R BOOST_PP_ENUM_TRAILING_PARAMS(MOCK_NUM_ARGS, typename T)>
class expectation<R(BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, T))> :
public action<R, R(BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, T))>
{
public:
expectation()
: invocation_(std::make_unique<unlimited>()),
matcher_(std::make_unique<default_matcher<void(BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, T))>>()),
file_("unknown location"), line_(0)
{}
expectation(const char* file, int line)
: invocation_(std::make_unique<unlimited>()),
matcher_(std::make_unique<default_matcher<void(BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, T))>>()), file_(file),
line_(line)
{}
expectation(expectation&&) = default;
expectation(expectation const&) = default;
expectation& operator=(expectation&&) = default;
expectation& operator=(expectation const&) = default;
~expectation()
{
for(auto& sequence : sequences_)
sequence->remove(this);
}
void invoke(std::unique_ptr<invocation> i) { invocation_ = std::move(i); }
#ifndef MOCK_NUM_ARGS_0
template<BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, typename Constraint_)>
expectation& with(BOOST_PP_ENUM_BINARY_PARAMS(MOCK_NUM_ARGS, Constraint_, c))
{
matcher_ = std::make_unique<single_matcher<void(BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, Constraint_)),
void(BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, T))>>(
BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, c));
return *this;
}
# if MOCK_NUM_ARGS > 1
template<typename Constraint>
expectation& with(const Constraint& c)
{
matcher_ = std::make_unique<multi_matcher<Constraint, void(BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, T))>>(c);
return *this;
}
# endif
#endif
void add(sequence& s)
{
s.impl_->add(this);
sequences_.push_back(s.impl_);
}
bool verify() const { return invocation_->verify(); }
bool is_valid(BOOST_PP_ENUM(MOCK_NUM_ARGS, MOCK_REF_ARG, _)) const
{
return !invocation_->exhausted() && (*matcher_)(BOOST_PP_ENUM(MOCK_NUM_ARGS, MOCK_EXPECTATION_PARAM, _));
}
bool invoke() const
{
for(auto& sequence : sequences_)
{
if(!sequence->is_valid(this))
return false;
}
bool result = invocation_->invoke();
for(auto& sequence : sequences_)
sequence->invalidate(this);
return result;
}
const char* file() const { return file_; }
int line() const { return line_; }
friend std::ostream& operator<<(std::ostream& s, const expectation& e)
{
return s << (e.invocation_->exhausted() ? 'v' : '.') << ' ' << *e.invocation_
#ifndef MOCK_NUM_ARGS_0
<< ".with( " << *e.matcher_ << " )"
#endif
;
}
private:
std::unique_ptr<invocation> invocation_;
std::unique_ptr<matcher_base<void(BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, T))>> matcher_;
std::vector<std::shared_ptr<sequence_impl>> sequences_;
const char* file_;
int line_;
};
}} // namespace mock::detail
#undef MOCK_EXPECTATION_INITIALIZE
#undef MOCK_EXPECTATION_MEMBER
#undef MOCK_EXPECTATION_IS_VALID
#undef MOCK_EXPECTATION_SERIALIZE
#undef MOCK_EXPECTATION_SERIALIZE_ANY
#undef MOCK_EXPECTATION_PARAM
#undef MOCK_REF_ARG
#undef MOCK_REF_ARG_T
#undef MOCK_RV_REF

View file

@ -10,88 +10,72 @@
#define MOCK_FUNCTION_HPP_INCLUDED
#include "../config.hpp"
#include "../constraints.hpp"
#include "../error.hpp"
#include "../log.hpp"
#include "../matcher.hpp"
#include "../sequence.hpp"
#include "action.hpp"
#include "context.hpp"
#include "invocation.hpp"
#include "move_helper.hpp"
#include "mutex.hpp"
#include "function_impl.hpp"
#include "type_name.hpp"
#include "verifiable.hpp"
#include <boost/optional.hpp>
#include <boost/preprocessor/comparison/equal.hpp>
#include <boost/preprocessor/comparison/greater.hpp>
#include <boost/preprocessor/iteration/iterate.hpp>
#include <boost/preprocessor/repetition/enum_binary_params.hpp>
#include <boost/preprocessor/repetition/enum_params.hpp>
#include <boost/preprocessor/repetition/repeat_from_to.hpp>
#include <boost/test/utils/basic_cstring/basic_cstring.hpp>
#include <boost/test/utils/lazy_ostream.hpp>
#include <list>
#include <ostream>
#include <vector>
namespace mock { namespace detail {
template<typename R, typename E>
struct wrapper_base
{
wrapper_base(E& e) : e_(&e) {}
template<typename Signature>
class function;
template<typename T>
void returns(T t)
template<typename R, typename... Ts>
class function<R(Ts...)>
{
private:
typedef function_impl<R(Ts...)> impl_type;
typedef typename impl_type::wrapper_type expectation_type;
typedef typename impl_type::error_type error_type;
public:
function() : impl_(std::make_shared<impl_type>()) {}
bool verify() const { return impl_->verify(); }
bool verify(const char* file, int line) const
{
e_->returns(t);
error_type::pass(file, line);
return impl_->verify();
}
void reset() { impl_->reset(); }
void reset(const char* file, int line)
{
error_type::pass(file, line);
impl_->reset();
}
E* e_;
};
template<typename E>
struct wrapper_base<void, E>
{
wrapper_base(E& e) : e_(&e) {}
E* e_;
};
template<typename R, typename E>
struct wrapper_base<R*, E>
{
wrapper_base(E& e) : e_(&e) {}
void returns(R* r) { e_->returns(r); }
template<typename Y>
void returns(const std::reference_wrapper<Y>& r)
expectation_type expect(const char* file, int line)
{
e_->returns(r);
error_type::pass(file, line);
return impl_->expect(file, line);
}
expectation_type expect() { return impl_->expect(); }
R operator()(Ts... args) const { return (*impl_)(std::forward<Ts>(args)...); }
friend std::ostream& operator<<(std::ostream& s, const function& f) { return s << *f.impl_; }
function& operator()(context& c, boost::unit_test::const_string instance)
{
impl_->add(c, impl_.get(), instance, boost::none, "");
return *this;
}
E* e_;
};
void configure(context& c,
const void* p,
boost::unit_test::const_string instance,
boost::optional<type_name> type,
boost::unit_test::const_string name) const
{
impl_->add(c, p, instance, type, name);
}
inline int exceptions()
{
#ifdef MOCK_UNCAUGHT_EXCEPTIONS
using namespace std;
return uncaught_exceptions();
#else
return std::uncaught_exception() ? 1 : 0;
#endif
}
private:
std::shared_ptr<impl_type> impl_;
};
}} // namespace mock::detail
#define MOCK_NUM_ARGS 0
#define MOCK_NUM_ARGS_0
#include "function_template.hpp"
#undef MOCK_NUM_ARGS_0
#undef MOCK_NUM_ARGS
#define BOOST_PP_FILENAME_1 <turtle/detail/function_iterate.hpp>
#define BOOST_PP_ITERATION_LIMITS (1, MOCK_MAX_ARGS)
#include BOOST_PP_ITERATE()
#undef BOOST_PP_FILENAME_1
#undef BOOST_PP_ITERATION_LIMITS
#endif // MOCK_FUNCTION_HPP_INCLUDED

View file

@ -6,29 +6,74 @@
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include "expectation_template.hpp"
#ifndef MOCK_FUNCTION_IMPL_HPP_INCLUDED
#define MOCK_FUNCTION_IMPL_HPP_INCLUDED
#include "../error.hpp"
#include "expectation.hpp"
#include "mutex.hpp"
#include "verifiable.hpp"
#include <boost/preprocessor/repetition/enum_params.hpp>
#include <boost/preprocessor/repetition/repeat_from_to.hpp>
#include <boost/test/utils/lazy_ostream.hpp>
#include <list>
#include <memory>
#ifndef MOCK_ERROR_POLICY
# error no error policy has been set
#endif
#define MOCK_FUNCTION_FORMAT(z, n, N) << ' ' << mock::format(t##n) << BOOST_PP_IF(BOOST_PP_EQUAL(N, n), ' ', ',')
#define MOCK_FUNCTION_CONTEXT \
boost::unit_test::lazy_ostream::instance() \
<< lazy_context(this) << '(' BOOST_PP_REPEAT(MOCK_NUM_ARGS, MOCK_FUNCTION_FORMAT, BOOST_PP_DEC(MOCK_NUM_ARGS)) \
<< ')' << lazy_expectations(this)
#define MOCK_FORWARD(z, n, d) std::forward<T##n>(t##n)
namespace mock { namespace detail {
template<typename R, typename E>
struct wrapper_base
{
wrapper_base(E& e) : e_(&e) {}
template<typename T>
void returns(T t)
{
e_->returns(t);
}
E* e_;
};
template<typename E>
struct wrapper_base<void, E>
{
wrapper_base(E& e) : e_(&e) {}
E* e_;
};
template<typename R, typename E>
struct wrapper_base<R*, E>
{
wrapper_base(E& e) : e_(&e) {}
void returns(R* r) { e_->returns(r); }
template<typename Y>
void returns(const std::reference_wrapper<Y>& r)
{
e_->returns(r);
}
E* e_;
};
inline int exceptions()
{
#ifdef MOCK_UNCAUGHT_EXCEPTIONS
using namespace std;
return uncaught_exceptions();
#else
return std::uncaught_exception() ? 1 : 0;
#endif
}
template<typename Signature>
class function_impl;
template<typename R BOOST_PP_ENUM_TRAILING_PARAMS(MOCK_NUM_ARGS, typename T)>
class function_impl<R(BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, T))> :
public verifiable,
public std::enable_shared_from_this<function_impl<R(BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, T))>>
template<typename R, typename... Args>
class function_impl<R(Args...)> : public verifiable, public std::enable_shared_from_this<function_impl<R(Args...)>>
{
public:
typedef safe_error<R, MOCK_ERROR_POLICY<R>> error_type;
@ -82,12 +127,13 @@ namespace mock { namespace detail {
}
private:
typedef expectation<R(BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, T))> expectation_type;
typedef expectation<R(Args...)> expectation_type;
class wrapper : public wrapper_base<R, expectation_type>
{
private:
typedef wrapper_base<R, expectation_type> base_type;
static constexpr auto arity = sizeof...(Args);
public:
wrapper(const std::shared_ptr<mutex>& m, expectation_type& e) : base_type(e), lock_(m) {}
@ -126,24 +172,18 @@ namespace mock { namespace detail {
return *this;
}
#ifndef MOCK_NUM_ARGS_0
template<BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, typename Constraint_)>
wrapper& with(BOOST_PP_ENUM_BINARY_PARAMS(MOCK_NUM_ARGS, Constraint_, c))
/// Callable only for functions taking arguments
/// Number of constraints must match the number of arguments
/// or a single constraint checking all arguments must be passed
template<typename... Constraints>
std::enable_if_t<(arity > 0u && (sizeof...(Constraints) == arity || sizeof...(Constraints) == 1u)),
wrapper&>
with(Constraints... c)
{
this->e_->with(BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, c));
this->e_->with(c...);
return *this;
}
# if MOCK_NUM_ARGS > 1
template<typename Constraint>
wrapper& with(const Constraint& c)
{
this->e_->with(c);
return *this;
}
# endif
#endif
#define MOCK_FUNCTION_IN_ADD(z, n, d) this->e_->add(s##n);
#define MOCK_FUNCTION_IN(z, n, d) \
@ -195,13 +235,17 @@ namespace mock { namespace detail {
return wrapper(mutex_, expectations_.back());
}
R operator()(BOOST_PP_ENUM_BINARY_PARAMS(MOCK_NUM_ARGS, T, t)) const
R operator()(Args... args) const
{
// Due to lifetime rules of references this must be created and consumed in one line
#define MOCK_FUNCTION_CONTEXT \
boost::unit_test::lazy_ostream::instance() << lazy_context(this) << lazy_args(args...) << lazy_expectations(this)
lock _(mutex_);
valid_ = false;
for(const auto& expectation : expectations_)
{
if(expectation.is_valid(BOOST_PP_ENUM(MOCK_NUM_ARGS, MOCK_FORWARD, _)))
if(expectation.is_valid(std::forward<Args>(args)...))
{
if(!expectation.invoke())
{
@ -218,12 +262,13 @@ namespace mock { namespace detail {
valid_ = true;
error_type::call(MOCK_FUNCTION_CONTEXT, expectation.file(), expectation.line());
if(expectation.functor())
return expectation.functor()(BOOST_PP_ENUM(MOCK_NUM_ARGS, MOCK_FORWARD, _));
return expectation.functor()(std::forward<Args>(args)...);
return expectation.trigger();
}
}
error_type::fail("unexpected call", MOCK_FUNCTION_CONTEXT);
return error_type::abort();
#undef MOCK_FUNCTION_CONTEXT
}
void add(context& c,
@ -271,6 +316,29 @@ namespace mock { namespace detail {
const function_impl* impl_;
};
struct lazy_args
{
lazy_args(std::add_lvalue_reference_t<Args>... args) : args_(args...) {}
friend std::ostream& operator<<(std::ostream& s, const lazy_args& a)
{
return a.print_impl(std::make_index_sequence<sizeof...(Args)>{}, s);
}
private:
std::tuple<std::add_lvalue_reference_t<Args>...> args_;
template<std::size_t... I>
std::ostream& print_impl(std::index_sequence<I...>, std::ostream& s) const
{
s << '(';
using expander = int[];
(void)expander{
0, (s << ' ' << mock::format(std::get<I>(args_)) << (sizeof...(Args) - 1u == I ? ' ' : ','), 0)...
};
return s << ')';
}
};
std::list<expectation_type> expectations_;
context* context_;
mutable bool valid_;
@ -279,6 +347,4 @@ namespace mock { namespace detail {
};
}} // namespace mock::detail
#undef MOCK_FUNCTION_FORMAT
#undef MOCK_FUNCTION_CONTEXT
#undef MOCK_FORWARD
#endif // MOCK_FUNCTION_IMPL_HPP_INCLUDED

View file

@ -1,11 +0,0 @@
// http://turtle.sourceforge.net
//
// Copyright Mathieu Champlon 2012
//
// Distributed under 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)
#define MOCK_NUM_ARGS BOOST_PP_ITERATION()
#include "function_template.hpp"
#undef MOCK_NUM_ARGS

View file

@ -1,75 +0,0 @@
// http://turtle.sourceforge.net
//
// Copyright Mathieu Champlon 2008
//
// Distributed under 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)
#include "function_impl_template.hpp"
#define MOCK_FORWARD(z, n, d) std::forward<T##n>(t##n)
namespace mock { namespace detail {
template<typename Signature>
class function;
template<typename R BOOST_PP_ENUM_TRAILING_PARAMS(MOCK_NUM_ARGS, typename T)>
class function<R(BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, T))>
{
private:
typedef function_impl<R(BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, T))> impl_type;
typedef typename impl_type::wrapper_type expectation_type;
typedef typename impl_type::error_type error_type;
public:
function() : impl_(std::make_shared<impl_type>()) {}
bool verify() const { return impl_->verify(); }
bool verify(const char* file, int line) const
{
error_type::pass(file, line);
return impl_->verify();
}
void reset() { impl_->reset(); }
void reset(const char* file, int line)
{
error_type::pass(file, line);
impl_->reset();
}
expectation_type expect(const char* file, int line)
{
error_type::pass(file, line);
return impl_->expect(file, line);
}
expectation_type expect() { return impl_->expect(); }
R operator()(BOOST_PP_ENUM_BINARY_PARAMS(MOCK_NUM_ARGS, T, t)) const
{
return (*impl_)(BOOST_PP_ENUM(MOCK_NUM_ARGS, MOCK_FORWARD, _));
}
friend std::ostream& operator<<(std::ostream& s, const function& f) { return s << *f.impl_; }
function& operator()(context& c, boost::unit_test::const_string instance)
{
impl_->add(c, impl_.get(), instance, boost::none, "");
return *this;
}
void configure(context& c,
const void* p,
boost::unit_test::const_string instance,
boost::optional<type_name> type,
boost::unit_test::const_string name) const
{
impl_->add(c, p, instance, type, name);
}
private:
std::shared_ptr<impl_type> impl_;
};
}} // namespace mock::detail
#undef MOCK_FORWARD

View file

@ -6,14 +6,15 @@
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#define MOCK_REF_ARG(z, n, d) typename ref_arg<T##n>::type
#ifndef MOCK_MATCHER_BASE_HPP_INCLUDED
#define MOCK_MATCHER_BASE_HPP_INCLUDED
#include "move_helper.hpp"
#include <ostream>
namespace mock { namespace detail {
template<typename Signature>
class matcher_base;
template<BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, typename T)>
class matcher_base<void(BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, T))>
template<typename... Ts>
class matcher_base
{
public:
matcher_base() = default;
@ -21,7 +22,7 @@ namespace mock { namespace detail {
matcher_base& operator=(const matcher_base&) = delete;
virtual ~matcher_base() = default;
virtual bool operator()(BOOST_PP_ENUM(MOCK_NUM_ARGS, MOCK_REF_ARG, _)) = 0;
virtual bool operator()(typename ref_arg<Ts>::type...) = 0;
friend std::ostream& operator<<(std::ostream& s, const matcher_base& m)
{
@ -34,4 +35,4 @@ namespace mock { namespace detail {
};
}} // namespace mock::detail
#undef MOCK_REF_ARG
#endif // MOCK_MATCHER_BASE_HPP_INCLUDED

View file

@ -6,8 +6,8 @@
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef MOCK_PARAMETER_HPP_INCLUDED
#define MOCK_PARAMETER_HPP_INCLUDED
#ifndef MOCK_SIGNATURE_TRAITS_HPP_INCLUDED
#define MOCK_SIGNATURE_TRAITS_HPP_INCLUDED
#include "../config.hpp"
#include <cstddef>
@ -59,4 +59,4 @@ namespace mock { namespace detail {
}} // namespace mock::detail
#endif // MOCK_PARAMETER_HPP_INCLUDED
#endif // MOCK_SIGNATURE_TRAITS_HPP_INCLUDED