mirror of
https://github.com/mat007/turtle.git
synced 2026-06-22 12:13:43 +00:00
Merge pull request #110 from Flamefire/remove_pp_iterate
Replace Boost PP_Iterate by C++11 variadic templates
This commit is contained in:
commit
0dd0dfa15f
32 changed files with 445 additions and 3929 deletions
|
|
@ -15,6 +15,7 @@ Released -
|
|||
* Removed MOCK_*_TPL as they are no longer required, use the non _TPL variant even for templates
|
||||
* Added MOCK_PROTECT_SIGNATURE to pass function signatures with commas in the return type
|
||||
* Remove support for protecting function signatures via BOOST_IDENTITY_TYPE, use MOCK_PROTECT_SIGNATURE instead
|
||||
* Add support for unlimitted number of arguments and sequences making MOCK_MAX_ARGS and MOCK_MAX_SEQUENCES superflous
|
||||
|
||||
[endsect]
|
||||
|
||||
|
|
|
|||
|
|
@ -110,24 +110,6 @@ For more information about the serialization operator and the use of mock::forma
|
|||
|
||||
[endsect]
|
||||
|
||||
[section Number of arguments]
|
||||
|
||||
The maximum number of arguments a mocked method can have is defined by MOCK_MAX_ARGS.
|
||||
By default this value is set to 9, but if needed it can be changed before including the library :
|
||||
|
||||
[max_args]
|
||||
|
||||
This means methods with up to 20 arguments will then be accepted.
|
||||
|
||||
The mock object library uses several boost libraries and will adjust some of their constants if they haven't already been defined :
|
||||
|
||||
* Boost.Function with BOOST_FUNCTION_MAX_ARGS required at MOCK_MAX_ARGS or higher
|
||||
* Boost.FunctionTypes with BOOST_FT_MAX_ARITY required at MOCK_MAX_ARGS + 1 or higher
|
||||
|
||||
A compilation error will happen if one of those constants is already defined too low.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section Test framework integration]
|
||||
|
||||
By default the library expects to be used in conjunction with Boost.Test e.g. :
|
||||
|
|
|
|||
|
|
@ -145,12 +145,6 @@ BOOST_AUTO_TEST_CASE(near_constraint_works_with_with_float_wrapper_and_cref)
|
|||
}
|
||||
} // namespace near_constraint_cref_test
|
||||
|
||||
#undef MOCK_MAX_ARGS
|
||||
//[ max_args
|
||||
#define MOCK_MAX_ARGS 20
|
||||
#include <turtle/mock.hpp>
|
||||
//]
|
||||
|
||||
#if defined(__GNUC__)
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wunused-parameter"
|
||||
|
|
|
|||
|
|
@ -449,10 +449,7 @@ Synopsis :
|
|||
|
||||
Each sequence is an instance of mock::sequence.
|
||||
|
||||
The maximum number of sequences that can be set is MOCK_MAX_SEQUENCES which defaults to 10. If needed the value can be increased before including the library :
|
||||
|
||||
#define MOCK_MAX_SEQUENCES 12
|
||||
#include <turtle/mock.hpp>
|
||||
The maximum number of sequences that can be set is basically unlimited.
|
||||
|
||||
Example :
|
||||
|
||||
|
|
@ -467,7 +464,7 @@ An action performs additional treatments after an expectation has been deemed va
|
|||
Synopsis :
|
||||
|
||||
MOCK_EXPECT( identifier ).returns( value ); // stored internally by copy
|
||||
MOCK_EXPECT( identifier ).moves( value ); // stored internally by copy
|
||||
MOCK_EXPECT( identifier ).moves( value ); // stored internally by copy/move
|
||||
MOCK_EXPECT( identifier ).throws( exception ); // stored internally by copy
|
||||
MOCK_EXPECT( identifier ).calls( functor ); // stored internally by copy, throws std::invalid_argument if empty
|
||||
|
||||
|
|
|
|||
|
|
@ -18,14 +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
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_HDR_MUTEX) && !defined(BOOST_NO_0X_HDR_MUTEX)
|
||||
# ifndef MOCK_NO_HDR_MUTEX
|
||||
# define MOCK_HDR_MUTEX
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@
|
|||
#include <boost/preprocessor/repetition/enum_binary_params.hpp>
|
||||
#include <boost/preprocessor/repetition/enum_params.hpp>
|
||||
#include <boost/preprocessor/stringize.hpp>
|
||||
#include <boost/preprocessor/variadic/to_array.hpp>
|
||||
#include <boost/preprocessor/variadic/size.hpp>
|
||||
#include <functional>
|
||||
#include <type_traits>
|
||||
|
||||
|
|
@ -178,118 +178,11 @@ const constraint<detail::not_<Constraint>> operator!(const constraint<Constraint
|
|||
#define MOCK_CONSTRAINT_EXT(Name, n, Args, Expr) \
|
||||
BOOST_PP_IF(n, MOCK_NARY_CONSTRAINT, MOCK_UNARY_CONSTRAINT)(Name, n, Args, Expr)
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
# define MOCK_VARIADIC_SIZE(...) \
|
||||
BOOST_PP_CAT(MOCK_VARIADIC_SIZE_I(__VA_ARGS__, \
|
||||
32, \
|
||||
31, \
|
||||
30, \
|
||||
29, \
|
||||
28, \
|
||||
27, \
|
||||
26, \
|
||||
25, \
|
||||
24, \
|
||||
23, \
|
||||
22, \
|
||||
21, \
|
||||
20, \
|
||||
19, \
|
||||
18, \
|
||||
17, \
|
||||
16, \
|
||||
15, \
|
||||
14, \
|
||||
13, \
|
||||
12, \
|
||||
11, \
|
||||
10, \
|
||||
9, \
|
||||
8, \
|
||||
7, \
|
||||
6, \
|
||||
5, \
|
||||
4, \
|
||||
3, \
|
||||
2, \
|
||||
1, ), )
|
||||
#else // BOOST_MSVC
|
||||
# define MOCK_VARIADIC_SIZE(...) \
|
||||
MOCK_VARIADIC_SIZE_I(__VA_ARGS__, \
|
||||
32, \
|
||||
31, \
|
||||
30, \
|
||||
29, \
|
||||
28, \
|
||||
27, \
|
||||
26, \
|
||||
25, \
|
||||
24, \
|
||||
23, \
|
||||
22, \
|
||||
21, \
|
||||
20, \
|
||||
19, \
|
||||
18, \
|
||||
17, \
|
||||
16, \
|
||||
15, \
|
||||
14, \
|
||||
13, \
|
||||
12, \
|
||||
11, \
|
||||
10, \
|
||||
9, \
|
||||
8, \
|
||||
7, \
|
||||
6, \
|
||||
5, \
|
||||
4, \
|
||||
3, \
|
||||
2, \
|
||||
1, )
|
||||
#endif // BOOST_MSVC
|
||||
#define MOCK_VARIADIC_SIZE_I(e0, \
|
||||
e1, \
|
||||
e2, \
|
||||
e3, \
|
||||
e4, \
|
||||
e5, \
|
||||
e6, \
|
||||
e7, \
|
||||
e8, \
|
||||
e9, \
|
||||
e10, \
|
||||
e11, \
|
||||
e12, \
|
||||
e13, \
|
||||
e14, \
|
||||
e15, \
|
||||
e16, \
|
||||
e17, \
|
||||
e18, \
|
||||
e19, \
|
||||
e20, \
|
||||
e21, \
|
||||
e22, \
|
||||
e23, \
|
||||
e24, \
|
||||
e25, \
|
||||
e26, \
|
||||
e27, \
|
||||
e28, \
|
||||
e29, \
|
||||
e30, \
|
||||
e31, \
|
||||
size, \
|
||||
...) \
|
||||
size
|
||||
|
||||
#define MOCK_CONSTRAINT_AUX_AUX(Name, n, Array) \
|
||||
MOCK_CONSTRAINT_EXT(Name, n, BOOST_PP_ARRAY_TO_TUPLE(BOOST_PP_ARRAY_POP_BACK(Array)), BOOST_PP_ARRAY_ELEM(n, Array))
|
||||
|
||||
#define MOCK_CONSTRAINT_AUX(Name, Size, Tuple) MOCK_CONSTRAINT_AUX_AUX(Name, BOOST_PP_DEC(Size), (Size, Tuple))
|
||||
|
||||
#define MOCK_CONSTRAINT(Name, ...) MOCK_CONSTRAINT_AUX(Name, MOCK_VARIADIC_SIZE(__VA_ARGS__), (__VA_ARGS__))
|
||||
#define MOCK_CONSTRAINT(Name, ...) MOCK_CONSTRAINT_AUX(Name, BOOST_PP_VARIADIC_SIZE(__VA_ARGS__), (__VA_ARGS__))
|
||||
|
||||
#endif // MOCK_CONSTRAINT_HPP_INCLUDED
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@
|
|||
|
||||
#include "config.hpp"
|
||||
#include "constraint.hpp"
|
||||
#include "detail/move_helper.hpp"
|
||||
#include "detail/void_t.hpp"
|
||||
#include "unwrap_reference.hpp"
|
||||
#include <boost/version.hpp>
|
||||
|
|
|
|||
|
|
@ -62,6 +62,27 @@ namespace mock { namespace detail {
|
|||
action_type a_;
|
||||
};
|
||||
|
||||
/// Type erased value storage
|
||||
struct value
|
||||
{
|
||||
value() = default;
|
||||
value(const value&) = delete;
|
||||
value& operator=(const value&) = delete;
|
||||
virtual ~value() = default;
|
||||
};
|
||||
/// Actual value storage,
|
||||
/// holds an instance of T (stripped of reference qualifiers)
|
||||
template<typename T>
|
||||
struct value_imp : value
|
||||
{
|
||||
using type = std::remove_const_t<std::remove_reference_t<T>>;
|
||||
|
||||
template<typename U>
|
||||
value_imp(U&& t) : t_(std::forward<U>(t))
|
||||
{}
|
||||
type t_;
|
||||
};
|
||||
|
||||
template<typename Result, typename Signature>
|
||||
class action : public action_base<Result, Signature>
|
||||
{
|
||||
|
|
@ -85,24 +106,6 @@ namespace mock { namespace detail {
|
|||
}
|
||||
|
||||
private:
|
||||
struct value
|
||||
{
|
||||
value() = default;
|
||||
value(const value&) = delete;
|
||||
value& operator=(const value&) = delete;
|
||||
virtual ~value() = default;
|
||||
};
|
||||
template<typename T>
|
||||
struct value_imp : value
|
||||
{
|
||||
typedef std::remove_const_t<std::remove_reference_t<T>> type;
|
||||
|
||||
template<typename U>
|
||||
value_imp(U&& t) : t_(std::forward<U>(t))
|
||||
{}
|
||||
type t_;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
typename value_imp<T>::type& store(T&& t)
|
||||
{
|
||||
|
|
|
|||
183
include/turtle/detail/expectation.hpp
Normal file
183
include/turtle/detail/expectation.hpp
Normal file
|
|
@ -0,0 +1,183 @@
|
|||
// 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()(ref_arg_t<Args>...) override { return true; }
|
||||
void serialize(std::ostream& s) const override
|
||||
{
|
||||
constexpr auto arity = sizeof...(Args);
|
||||
for(unsigned i = 0; i < arity; ++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...>, ref_arg_t<Args>... t)
|
||||
{
|
||||
using expander = bool[];
|
||||
bool result = true;
|
||||
(void)expander{ result &= std::get<I>(matchers_)(static_cast<ref_arg_t<Args>>(t))... };
|
||||
return result;
|
||||
}
|
||||
bool operator()(ref_arg_t<Args>... t) override
|
||||
{
|
||||
return is_valid_impl(std::make_index_sequence<sizeof...(Args)>{}, static_cast<ref_arg_t<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()(ref_arg_t<Args>... t) override { return f_(static_cast<ref_arg_t<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 std::size_t 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 > 0u) && sizeof...(Constraints) == arity> with(Constraints... c)
|
||||
{
|
||||
matcher_ = std::make_unique<single_matcher<void(Constraints...), Args...>>(c...);
|
||||
}
|
||||
template<typename Constraint, std::size_t Arity = arity>
|
||||
std::enable_if_t<(Arity > 1u)> with(const Constraint& c)
|
||||
{
|
||||
matcher_ = std::make_unique<multi_matcher<Constraint, Args...>>(c);
|
||||
}
|
||||
|
||||
void add(sequence& s)
|
||||
{
|
||||
s.impl_->add(this);
|
||||
sequences_.push_back(s.impl_);
|
||||
}
|
||||
|
||||
bool verify() const { return invocation_->verify(); }
|
||||
|
||||
bool is_valid(ref_arg_t<Args>... t) const
|
||||
{
|
||||
return !invocation_->exhausted() && (*matcher_)(static_cast<ref_arg_t<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...)>
|
||||
{
|
||||
e_->returns(t);
|
||||
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
|
||||
{
|
||||
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>
|
||||
expectation_type expect(const char* file, int line)
|
||||
{
|
||||
wrapper_base(E& e) : e_(&e) {}
|
||||
error_type::pass(file, line);
|
||||
return impl_->expect(file, line);
|
||||
}
|
||||
expectation_type expect() { return impl_->expect(); }
|
||||
|
||||
E* e_;
|
||||
};
|
||||
template<typename R, typename E>
|
||||
struct wrapper_base<R*, E>
|
||||
{
|
||||
wrapper_base(E& e) : e_(&e) {}
|
||||
R operator()(Ts... args) const { return (*impl_)(static_cast<ref_arg_t<Ts>>(args)...); }
|
||||
|
||||
void returns(R* r) { e_->returns(r); }
|
||||
template<typename Y>
|
||||
void returns(const std::reference_wrapper<Y>& r)
|
||||
friend std::ostream& operator<<(std::ostream& s, const function& f) { return s << *f.impl_; }
|
||||
|
||||
function& operator()(context& c, boost::unit_test::const_string instance)
|
||||
{
|
||||
e_->returns(r);
|
||||
impl_->add(c, impl_.get(), instance, boost::none, "");
|
||||
return *this;
|
||||
}
|
||||
|
||||
E* e_;
|
||||
};
|
||||
|
||||
inline int exceptions()
|
||||
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
|
||||
{
|
||||
#ifdef MOCK_UNCAUGHT_EXCEPTIONS
|
||||
using namespace std;
|
||||
return uncaught_exceptions();
|
||||
#else
|
||||
return std::uncaught_exception() ? 1 : 0;
|
||||
#endif
|
||||
impl_->add(c, p, instance, type, name);
|
||||
}
|
||||
|
||||
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,75 @@
|
|||
// (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/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... Arg>
|
||||
class lazy_args;
|
||||
|
||||
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 +128,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 std::size_t arity = sizeof...(Args);
|
||||
|
||||
public:
|
||||
wrapper(const std::shared_ptr<mutex>& m, expectation_type& e) : base_type(e), lock_(m) {}
|
||||
|
|
@ -126,37 +173,26 @@ 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)
|
||||
/// Ensure the expectation is met in the given sequence(s)
|
||||
template<class... MockSequences>
|
||||
wrapper& in(sequence& s0, MockSequences&... s)
|
||||
{
|
||||
this->e_->with(c);
|
||||
using expander = int[];
|
||||
(void)expander{ (this->e_->add(s0), 0), (this->e_->add(s), 0)... };
|
||||
return *this;
|
||||
}
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#define MOCK_FUNCTION_IN_ADD(z, n, d) this->e_->add(s##n);
|
||||
|
||||
#define MOCK_FUNCTION_IN(z, n, d) \
|
||||
wrapper& in(BOOST_PP_ENUM_PARAMS(n, sequence& s)) \
|
||||
{ \
|
||||
BOOST_PP_REPEAT(n, MOCK_FUNCTION_IN_ADD, _) \
|
||||
return *this; \
|
||||
}
|
||||
|
||||
BOOST_PP_REPEAT(MOCK_MAX_SEQUENCES, MOCK_FUNCTION_IN, _)
|
||||
|
||||
#undef MOCK_FUNCTION_IN
|
||||
#undef MOCK_FUNCTION_IN_ADD
|
||||
|
||||
template<typename TT>
|
||||
void calls(TT t)
|
||||
|
|
@ -195,13 +231,18 @@ 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...>(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(static_cast<ref_arg_t<Args>>(args)...))
|
||||
{
|
||||
if(!expectation.invoke())
|
||||
{
|
||||
|
|
@ -218,12 +259,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()(static_cast<ref_arg_t<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,
|
||||
|
|
@ -277,8 +319,43 @@ namespace mock { namespace detail {
|
|||
const int exceptions_;
|
||||
const std::shared_ptr<mutex> mutex_;
|
||||
};
|
||||
|
||||
template<typename ArgFirst, typename... ArgRest>
|
||||
class lazy_args<ArgFirst, ArgRest...> : lazy_args<ArgRest...>
|
||||
{
|
||||
ArgFirst& arg_;
|
||||
|
||||
public:
|
||||
lazy_args(ArgFirst& arg, std::add_lvalue_reference_t<ArgRest>... args)
|
||||
: lazy_args<ArgRest...>(args...), arg_(arg)
|
||||
{}
|
||||
std::ostream& print(std::ostream& s) const
|
||||
{
|
||||
s << ' ' << mock::format(arg_) << ',';
|
||||
return lazy_args<ArgRest...>::print(s);
|
||||
}
|
||||
};
|
||||
template<typename ArgFirst>
|
||||
class lazy_args<ArgFirst>
|
||||
{
|
||||
ArgFirst& arg_;
|
||||
|
||||
public:
|
||||
lazy_args(ArgFirst& arg) : arg_(arg) {}
|
||||
std::ostream& print(std::ostream& s) const { return s << ' ' << mock::format(arg_) << ' '; }
|
||||
};
|
||||
template<>
|
||||
class lazy_args<>
|
||||
{
|
||||
public:
|
||||
std::ostream& print(std::ostream& s) const { return s; }
|
||||
};
|
||||
template<typename... Args>
|
||||
std::ostream& operator<<(std::ostream& s, const lazy_args<Args...>& a)
|
||||
{
|
||||
s << '(';
|
||||
return a.print(s) << ')';
|
||||
}
|
||||
}} // 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 "ref_arg.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... Args>
|
||||
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()(ref_arg_t<Args>...) = 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
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
// http://turtle.sourceforge.net
|
||||
//
|
||||
// Copyright Mathieu Champlon 2018
|
||||
//
|
||||
// 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_MOVE_HELPER_HPP_INCLUDED
|
||||
#define MOCK_MOVE_HELPER_HPP_INCLUDED
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
namespace mock { namespace detail {
|
||||
template<typename T>
|
||||
using ref_arg = std::conditional<std::is_reference<T>::value, T, std::add_rvalue_reference_t<T>>;
|
||||
}} // namespace mock::detail
|
||||
|
||||
#endif // MOCK_MOVE_HELPER_HPP_INCLUDED
|
||||
22
include/turtle/detail/ref_arg.hpp
Normal file
22
include/turtle/detail/ref_arg.hpp
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
// http://turtle.sourceforge.net
|
||||
//
|
||||
// Copyright Mathieu Champlon 2018
|
||||
//
|
||||
// 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_REF_ARG_HPP_INCLUDED
|
||||
#define MOCK_REF_ARG_HPP_INCLUDED
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
namespace mock { namespace detail {
|
||||
/// Make T a reference type:
|
||||
/// If T is already a reference type, return T, else return an rvalue reference to T
|
||||
/// Useful to pass along arguments keeping the ability to modify them (e.g. move from them)
|
||||
template<typename T>
|
||||
using ref_arg_t = typename std::conditional<std::is_reference<T>::value, T, std::add_rvalue_reference_t<T>>::type;
|
||||
}} // namespace mock::detail
|
||||
|
||||
#endif // MOCK_REF_ARG_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
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
#include "config.hpp"
|
||||
#include "constraints.hpp"
|
||||
#include "detail/is_functor.hpp"
|
||||
#include "detail/move_helper.hpp"
|
||||
#include "detail/ref_arg.hpp"
|
||||
#include "log.hpp"
|
||||
#include <cstring>
|
||||
#include <functional>
|
||||
|
|
@ -51,10 +51,7 @@ class matcher<Actual, mock::constraint<Constraint>>
|
|||
{
|
||||
public:
|
||||
explicit matcher(const constraint<Constraint>& c) : c_(c.c_) {}
|
||||
bool operator()(typename detail::ref_arg<Actual>::type actual)
|
||||
{
|
||||
return c_(std::forward<typename detail::ref_arg<Actual>::type>(actual));
|
||||
}
|
||||
bool operator()(detail::ref_arg_t<Actual> actual) { return c_(static_cast<detail::ref_arg_t<Actual>>(actual)); }
|
||||
friend std::ostream& operator<<(std::ostream& s, const matcher& m) { return s << mock::format(m.c_); }
|
||||
|
||||
private:
|
||||
|
|
@ -66,10 +63,7 @@ class matcher<Actual, Functor, std::enable_if_t<detail::is_functor<Functor, Actu
|
|||
{
|
||||
public:
|
||||
explicit matcher(const Functor& f) : c_(f) {}
|
||||
bool operator()(typename detail::ref_arg<Actual>::type actual)
|
||||
{
|
||||
return c_(std::forward<typename detail::ref_arg<Actual>::type>(actual));
|
||||
}
|
||||
bool operator()(detail::ref_arg_t<Actual> actual) { return c_(static_cast<detail::ref_arg_t<Actual>>(actual)); }
|
||||
friend std::ostream& operator<<(std::ostream& s, const matcher& m) { return s << mock::format(m.c_); }
|
||||
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ set(testsUsingUndefinedCPP test_function test_integration)
|
|||
foreach(testFile IN LISTS testFiles)
|
||||
get_filename_component(name ${testFile} NAME_WE)
|
||||
|
||||
foreach(testVariant IN ITEMS "" _max_args _use_conversions _thread_safe)
|
||||
foreach(testVariant IN ITEMS "" _use_conversions _thread_safe)
|
||||
set(curName ${name}${testVariant})
|
||||
add_executable(${curName} ${testFile})
|
||||
if(name IN_LIST testsUsingUndefinedCPP)
|
||||
|
|
@ -50,7 +50,6 @@ foreach(testFile IN LISTS testFiles)
|
|||
add_test(NAME ${curName} COMMAND ${curName})
|
||||
endforeach()
|
||||
|
||||
target_compile_definitions(${name}_max_args PRIVATE MOCK_MAX_ARGS=21)
|
||||
target_compile_definitions(${name}_use_conversions PRIVATE MOCK_USE_CONVERSIONS)
|
||||
|
||||
target_link_libraries(${name}_thread_safe PRIVATE Boost::thread)
|
||||
|
|
|
|||
|
|
@ -24,7 +24,6 @@ alias mock_inspect :
|
|||
rule run-test ( name )
|
||||
{
|
||||
run $(name) defined_1.cpp defined_2.cpp undefined.cpp /boost//unit_test_framework : : : : $(name)_ ;
|
||||
run $(name) undefined.cpp /boost//unit_test_framework : : : <define>MOCK_MAX_ARGS=21 : $(name)_max_args ;
|
||||
run $(name) undefined.cpp /boost//unit_test_framework : : : <define>MOCK_USE_CONVERSIONS : $(name)_use_conversions ;
|
||||
run $(name) undefined.cpp /boost//unit_test_framework /boost//thread : : : <define>MOCK_THREAD_SAFE <define>BOOST_THREAD_USES_MOVE <threading>multi : $(name)_thread_safe ;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,15 +0,0 @@
|
|||
// http://turtle.sourceforge.net
|
||||
//
|
||||
// Copyright Mathieu Champlon 2011
|
||||
//
|
||||
// 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_MAX_ARGS 10
|
||||
#include <turtle/mock.hpp>
|
||||
|
||||
int main()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
// http://turtle.sourceforge.net
|
||||
//
|
||||
// Copyright Mathieu Champlon 2011
|
||||
//
|
||||
// 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_MAX_ARGS 20
|
||||
#include <turtle/mock.hpp>
|
||||
|
||||
int main()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
// http://turtle.sourceforge.net
|
||||
//
|
||||
// Copyright Mathieu Champlon 2011
|
||||
//
|
||||
// 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_MAX_ARGS 30
|
||||
#include <turtle/mock.hpp>
|
||||
|
||||
int main()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -6,7 +6,6 @@
|
|||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#define MOCK_MAX_ARGS 30
|
||||
#include <turtle/mock.hpp>
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning(disable : 4505)
|
||||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -1,24 +0,0 @@
|
|||
// http://turtle.sourceforge.net
|
||||
//
|
||||
// Copyright Mathieu Champlon 2011
|
||||
//
|
||||
// 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 <turtle/mock.hpp>
|
||||
|
||||
BOOST_STATIC_ASSERT(MOCK_MAX_ARGS == 9);
|
||||
|
||||
namespace {
|
||||
struct my_base
|
||||
{
|
||||
virtual ~my_base() = default;
|
||||
virtual void my_method(int, int, int, int, int, int, int, int, int, int) = 0;
|
||||
};
|
||||
|
||||
MOCK_BASE_CLASS(my_class, my_base)
|
||||
{
|
||||
MOCK_METHOD(my_method, 10)
|
||||
};
|
||||
} // namespace
|
||||
|
|
@ -6,7 +6,7 @@
|
|||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <turtle/detail/function.hpp>
|
||||
#include <turtle/detail/expectation.hpp>
|
||||
#include <turtle/matcher.hpp>
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include <functional>
|
||||
|
|
@ -88,16 +88,16 @@ std::string serialize(const T& t)
|
|||
BOOST_AUTO_TEST_CASE(default_matcher_is_serialized_to_any)
|
||||
{
|
||||
using mock::detail::default_matcher;
|
||||
BOOST_TEST(serialize(default_matcher<void()>{}) == "");
|
||||
BOOST_TEST(serialize(default_matcher<void(int)>{}) == "any");
|
||||
BOOST_TEST(serialize(default_matcher<void(int, int)>{}) == "any, any");
|
||||
BOOST_TEST(serialize(default_matcher<void(int, int, int, int, int)>{}) == "any, any, any, any, any");
|
||||
BOOST_TEST(serialize(default_matcher<>{}) == "");
|
||||
BOOST_TEST(serialize(default_matcher<int>{}) == "any");
|
||||
BOOST_TEST(serialize(default_matcher<int, int>{}) == "any, any");
|
||||
BOOST_TEST(serialize(default_matcher<int, int, int, int, int>{}) == "any, any, any, any, any");
|
||||
}
|
||||
|
||||
namespace {
|
||||
struct custom_constraint
|
||||
{
|
||||
int expected_ = 42;
|
||||
int expected_;
|
||||
custom_constraint(int expected = 42) : expected_(expected) {}
|
||||
friend std::ostream& operator<<(std::ostream& s, const custom_constraint& c)
|
||||
{
|
||||
|
|
@ -110,16 +110,15 @@ struct custom_constraint
|
|||
BOOST_AUTO_TEST_CASE(single_matcher_serializes)
|
||||
{
|
||||
using mock::detail::single_matcher;
|
||||
BOOST_TEST(serialize(single_matcher<void(int), void(int)>(1)) == "1");
|
||||
BOOST_TEST(serialize(single_matcher<void(int, int), void(int, int)>(1, 2)) == "1, 2");
|
||||
BOOST_TEST(serialize(single_matcher<void(int), int>(1)) == "1");
|
||||
BOOST_TEST(serialize(single_matcher<void(int, int), int, int>(1, 2)) == "1, 2");
|
||||
BOOST_TEST(
|
||||
serialize(
|
||||
single_matcher<void(int, int, mock::constraint<custom_constraint>, int, int), void(int, int, int, int, int)>(
|
||||
serialize(single_matcher<void(int, int, mock::constraint<custom_constraint>, int, int), int, int, int, int, int>(
|
||||
1, 2, custom_constraint(), 4, 5)) == "1, 2, custom42, 4, 5");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(multi_matcher_serializes)
|
||||
{
|
||||
using mock::detail::multi_matcher;
|
||||
BOOST_TEST(serialize(multi_matcher<custom_constraint, void(int)>(custom_constraint(1337))) == "custom1337");
|
||||
BOOST_TEST(serialize(multi_matcher<custom_constraint, int>(custom_constraint(1337))) == "custom1337");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,28 +11,30 @@
|
|||
#include <boost/preprocessor/repetition/enum.hpp>
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
#define IDENTITY(z, n, d) d
|
||||
#define IDENTITY(z, n, text) text
|
||||
// Number of arguments is (now) unlimited, so take any high value here
|
||||
#define NUM_TEST_ARGS 100
|
||||
|
||||
namespace {
|
||||
struct my_custom_mock
|
||||
{
|
||||
MOCK_METHOD(method, MOCK_MAX_ARGS, void(BOOST_PP_ENUM(MOCK_MAX_ARGS, IDENTITY, int)), tag)
|
||||
MOCK_METHOD(method2, MOCK_MAX_ARGS, int(BOOST_PP_ENUM(MOCK_MAX_ARGS, IDENTITY, int)), tag_2)
|
||||
MOCK_METHOD(method, NUM_TEST_ARGS, void(BOOST_PP_ENUM(NUM_TEST_ARGS, IDENTITY, int)), tag)
|
||||
MOCK_METHOD(method2, NUM_TEST_ARGS, int(BOOST_PP_ENUM(NUM_TEST_ARGS, IDENTITY, int)), tag_2)
|
||||
};
|
||||
} // namespace
|
||||
|
||||
BOOST_FIXTURE_TEST_CASE(call_mock_method_with_max_number_of_args, mock_error_fixture)
|
||||
{
|
||||
my_custom_mock m;
|
||||
MOCK_EXPECT(m.tag).once().with(BOOST_PP_ENUM(MOCK_MAX_ARGS, IDENTITY, 0));
|
||||
m.method(BOOST_PP_ENUM(MOCK_MAX_ARGS, IDENTITY, 0));
|
||||
MOCK_EXPECT(m.tag).once().with(BOOST_PP_ENUM(NUM_TEST_ARGS, IDENTITY, 0));
|
||||
m.method(BOOST_PP_ENUM(NUM_TEST_ARGS, IDENTITY, 0));
|
||||
CHECK_CALLS(1);
|
||||
}
|
||||
|
||||
BOOST_FIXTURE_TEST_CASE(call_mock_method_with_max_number_of_args_and_a_return_value, mock_error_fixture)
|
||||
{
|
||||
my_custom_mock m;
|
||||
MOCK_EXPECT(m.tag_2).once().with(BOOST_PP_ENUM(MOCK_MAX_ARGS, IDENTITY, 0)).returns(42);
|
||||
BOOST_CHECK_EQUAL(42, m.method2(BOOST_PP_ENUM(MOCK_MAX_ARGS, IDENTITY, 0)));
|
||||
MOCK_EXPECT(m.tag_2).once().with(BOOST_PP_ENUM(NUM_TEST_ARGS, IDENTITY, 0)).returns(42);
|
||||
BOOST_CHECK_EQUAL(42, m.method2(BOOST_PP_ENUM(NUM_TEST_ARGS, IDENTITY, 0)));
|
||||
CHECK_CALLS(1);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
#include <turtle/detail/function.hpp>
|
||||
#include <turtle/sequence.hpp>
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include <array>
|
||||
|
||||
BOOST_FIXTURE_TEST_CASE(registering_to_a_sequence_and_calling_out_of_order_throws, mock_error_fixture)
|
||||
{
|
||||
|
|
@ -97,9 +98,13 @@ BOOST_FIXTURE_TEST_CASE(resetting_an_expectation_removes_it_from_order_call_enfo
|
|||
|
||||
BOOST_FIXTURE_TEST_CASE(an_expectation_can_be_used_in_several_sequences, mock_error_fixture)
|
||||
{
|
||||
mock::sequence s1, s2;
|
||||
std::array<mock::sequence, 20> s;
|
||||
mock::detail::function<void()> e;
|
||||
e.expect().once().in(s1, s2);
|
||||
// One can use any amount of sequences if wanted
|
||||
// clang-format off
|
||||
e.expect().once().in(s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], s[8], s[9],
|
||||
s[10], s[11], s[12], s[13], s[14], s[15], s[16], s[17], s[18], s[19]);
|
||||
// clang-format on
|
||||
BOOST_CHECK_NO_THROW(e());
|
||||
BOOST_CHECK(e.verify());
|
||||
CHECK_CALLS(1);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue