mirror of
https://github.com/mat007/turtle.git
synced 2026-06-22 12:13:43 +00:00
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:
parent
90d9ac8055
commit
fca30e7780
17 changed files with 368 additions and 472 deletions
|
|
@ -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
|
||||
|
|
|
|||
184
include/turtle/detail/expectation.hpp
Normal file
184
include/turtle/detail/expectation.hpp
Normal 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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue