Merge pull request #110 from Flamefire/remove_pp_iterate

Replace Boost PP_Iterate by C++11 variadic templates
This commit is contained in:
Alexander Grund 2022-02-16 16:04:05 +01:00 committed by GitHub
commit 0dd0dfa15f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
32 changed files with 445 additions and 3929 deletions

View file

@ -15,6 +15,7 @@ Released -
* Removed MOCK_*_TPL as they are no longer required, use the non _TPL variant even for templates * 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 * 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 * 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] [endsect]

View file

@ -110,24 +110,6 @@ For more information about the serialization operator and the use of mock::forma
[endsect] [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] [section Test framework integration]
By default the library expects to be used in conjunction with Boost.Test e.g. : By default the library expects to be used in conjunction with Boost.Test e.g. :

View file

@ -145,12 +145,6 @@ BOOST_AUTO_TEST_CASE(near_constraint_works_with_with_float_wrapper_and_cref)
} }
} // namespace near_constraint_cref_test } // namespace near_constraint_cref_test
#undef MOCK_MAX_ARGS
//[ max_args
#define MOCK_MAX_ARGS 20
#include <turtle/mock.hpp>
//]
#if defined(__GNUC__) #if defined(__GNUC__)
# pragma GCC diagnostic push # pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wunused-parameter" # pragma GCC diagnostic ignored "-Wunused-parameter"

View file

@ -449,10 +449,7 @@ Synopsis :
Each sequence is an instance of mock::sequence. 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 : The maximum number of sequences that can be set is basically unlimited.
#define MOCK_MAX_SEQUENCES 12
#include <turtle/mock.hpp>
Example : Example :
@ -467,7 +464,7 @@ An action performs additional treatments after an expectation has been deemed va
Synopsis : Synopsis :
MOCK_EXPECT( identifier ).returns( value ); // stored internally by copy 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 ).throws( exception ); // stored internally by copy
MOCK_EXPECT( identifier ).calls( functor ); // stored internally by copy, throws std::invalid_argument if empty MOCK_EXPECT( identifier ).calls( functor ); // stored internally by copy, throws std::invalid_argument if empty

View file

@ -18,14 +18,6 @@
# define MOCK_USE_BOOST_TEST # define MOCK_USE_BOOST_TEST
#endif #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) #if !defined(BOOST_NO_CXX11_HDR_MUTEX) && !defined(BOOST_NO_0X_HDR_MUTEX)
# ifndef MOCK_NO_HDR_MUTEX # ifndef MOCK_NO_HDR_MUTEX
# define MOCK_HDR_MUTEX # define MOCK_HDR_MUTEX

View file

@ -18,7 +18,7 @@
#include <boost/preprocessor/repetition/enum_binary_params.hpp> #include <boost/preprocessor/repetition/enum_binary_params.hpp>
#include <boost/preprocessor/repetition/enum_params.hpp> #include <boost/preprocessor/repetition/enum_params.hpp>
#include <boost/preprocessor/stringize.hpp> #include <boost/preprocessor/stringize.hpp>
#include <boost/preprocessor/variadic/to_array.hpp> #include <boost/preprocessor/variadic/size.hpp>
#include <functional> #include <functional>
#include <type_traits> #include <type_traits>
@ -178,118 +178,11 @@ const constraint<detail::not_<Constraint>> operator!(const constraint<Constraint
#define MOCK_CONSTRAINT_EXT(Name, n, Args, Expr) \ #define MOCK_CONSTRAINT_EXT(Name, n, Args, Expr) \
BOOST_PP_IF(n, MOCK_NARY_CONSTRAINT, MOCK_UNARY_CONSTRAINT)(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) \ #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)) 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_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 #endif // MOCK_CONSTRAINT_HPP_INCLUDED

View file

@ -11,7 +11,6 @@
#include "config.hpp" #include "config.hpp"
#include "constraint.hpp" #include "constraint.hpp"
#include "detail/move_helper.hpp"
#include "detail/void_t.hpp" #include "detail/void_t.hpp"
#include "unwrap_reference.hpp" #include "unwrap_reference.hpp"
#include <boost/version.hpp> #include <boost/version.hpp>

View file

@ -62,6 +62,27 @@ namespace mock { namespace detail {
action_type a_; 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> template<typename Result, typename Signature>
class action : public action_base<Result, Signature> class action : public action_base<Result, Signature>
{ {
@ -85,24 +106,6 @@ namespace mock { namespace detail {
} }
private: 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> template<typename T>
typename value_imp<T>::type& store(T&& t) typename value_imp<T>::type& store(T&& t)
{ {

View 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

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 #define MOCK_FUNCTION_HPP_INCLUDED
#include "../config.hpp" #include "../config.hpp"
#include "../constraints.hpp"
#include "../error.hpp"
#include "../log.hpp" #include "../log.hpp"
#include "../matcher.hpp"
#include "../sequence.hpp" #include "../sequence.hpp"
#include "action.hpp"
#include "context.hpp" #include "context.hpp"
#include "invocation.hpp" #include "function_impl.hpp"
#include "move_helper.hpp"
#include "mutex.hpp"
#include "type_name.hpp" #include "type_name.hpp"
#include "verifiable.hpp"
#include <boost/optional.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/basic_cstring/basic_cstring.hpp>
#include <boost/test/utils/lazy_ostream.hpp>
#include <list>
#include <ostream> #include <ostream>
#include <vector>
namespace mock { namespace detail { namespace mock { namespace detail {
template<typename R, typename E> template<typename Signature>
struct wrapper_base class function;
{
wrapper_base(E& e) : e_(&e) {}
template<typename T> template<typename R, typename... Ts>
void returns(T t) 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_; expectation_type expect(const char* file, int line)
};
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); error_type::pass(file, line);
return impl_->expect(file, line);
}
expectation_type expect() { return impl_->expect(); }
R operator()(Ts... args) const { return (*impl_)(static_cast<ref_arg_t<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() private:
{ std::shared_ptr<impl_type> impl_;
#ifdef MOCK_UNCAUGHT_EXCEPTIONS };
using namespace std;
return uncaught_exceptions();
#else
return std::uncaught_exception() ? 1 : 0;
#endif
}
}} // namespace mock::detail }} // 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 #endif // MOCK_FUNCTION_HPP_INCLUDED

View file

@ -6,29 +6,75 @@
// (See accompanying file LICENSE_1_0.txt or copy at // (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt) // 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 #ifndef MOCK_ERROR_POLICY
# error no error policy has been set # error no error policy has been set
#endif #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 { 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> template<typename Signature>
class function_impl; class function_impl;
template<typename R BOOST_PP_ENUM_TRAILING_PARAMS(MOCK_NUM_ARGS, typename T)> template<typename R, typename... Args>
class function_impl<R(BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, T))> : class function_impl<R(Args...)> : public verifiable, public std::enable_shared_from_this<function_impl<R(Args...)>>
public verifiable,
public std::enable_shared_from_this<function_impl<R(BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, T))>>
{ {
public: public:
typedef safe_error<R, MOCK_ERROR_POLICY<R>> error_type; typedef safe_error<R, MOCK_ERROR_POLICY<R>> error_type;
@ -82,12 +128,13 @@ namespace mock { namespace detail {
} }
private: 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> class wrapper : public wrapper_base<R, expectation_type>
{ {
private: private:
typedef wrapper_base<R, expectation_type> base_type; typedef wrapper_base<R, expectation_type> base_type;
static constexpr std::size_t arity = sizeof...(Args);
public: public:
wrapper(const std::shared_ptr<mutex>& m, expectation_type& e) : base_type(e), lock_(m) {} 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; return *this;
} }
#ifndef MOCK_NUM_ARGS_0 /// Callable only for functions taking arguments
template<BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, typename Constraint_)> /// Number of constraints must match the number of arguments
wrapper& with(BOOST_PP_ENUM_BINARY_PARAMS(MOCK_NUM_ARGS, Constraint_, c)) /// 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; return *this;
} }
# if MOCK_NUM_ARGS > 1 /// Ensure the expectation is met in the given sequence(s)
template<typename Constraint> template<class... MockSequences>
wrapper& with(const Constraint& c) 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; 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> template<typename TT>
void calls(TT t) void calls(TT t)
@ -195,13 +231,18 @@ namespace mock { namespace detail {
return wrapper(mutex_, expectations_.back()); 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_); lock _(mutex_);
valid_ = false; valid_ = false;
for(const auto& expectation : expectations_) 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()) if(!expectation.invoke())
{ {
@ -218,12 +259,13 @@ namespace mock { namespace detail {
valid_ = true; valid_ = true;
error_type::call(MOCK_FUNCTION_CONTEXT, expectation.file(), expectation.line()); error_type::call(MOCK_FUNCTION_CONTEXT, expectation.file(), expectation.line());
if(expectation.functor()) 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(); return expectation.trigger();
} }
} }
error_type::fail("unexpected call", MOCK_FUNCTION_CONTEXT); error_type::fail("unexpected call", MOCK_FUNCTION_CONTEXT);
return error_type::abort(); return error_type::abort();
#undef MOCK_FUNCTION_CONTEXT
} }
void add(context& c, void add(context& c,
@ -277,8 +319,43 @@ namespace mock { namespace detail {
const int exceptions_; const int exceptions_;
const std::shared_ptr<mutex> mutex_; 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 }} // namespace mock::detail
#undef MOCK_FUNCTION_FORMAT #endif // MOCK_FUNCTION_IMPL_HPP_INCLUDED
#undef MOCK_FUNCTION_CONTEXT
#undef MOCK_FORWARD

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 // (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt) // 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 { namespace mock { namespace detail {
template<typename Signature> template<typename... Args>
class matcher_base; 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))>
{ {
public: public:
matcher_base() = default; matcher_base() = default;
@ -21,7 +22,7 @@ namespace mock { namespace detail {
matcher_base& operator=(const matcher_base&) = delete; matcher_base& operator=(const matcher_base&) = delete;
virtual ~matcher_base() = default; 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) friend std::ostream& operator<<(std::ostream& s, const matcher_base& m)
{ {
@ -34,4 +35,4 @@ namespace mock { namespace detail {
}; };
}} // namespace mock::detail }} // namespace mock::detail
#undef MOCK_REF_ARG #endif // MOCK_MATCHER_BASE_HPP_INCLUDED

View file

@ -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

View 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

View file

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

View file

@ -12,7 +12,7 @@
#include "config.hpp" #include "config.hpp"
#include "constraints.hpp" #include "constraints.hpp"
#include "detail/is_functor.hpp" #include "detail/is_functor.hpp"
#include "detail/move_helper.hpp" #include "detail/ref_arg.hpp"
#include "log.hpp" #include "log.hpp"
#include <cstring> #include <cstring>
#include <functional> #include <functional>
@ -51,10 +51,7 @@ class matcher<Actual, mock::constraint<Constraint>>
{ {
public: public:
explicit matcher(const constraint<Constraint>& c) : c_(c.c_) {} explicit matcher(const constraint<Constraint>& c) : c_(c.c_) {}
bool operator()(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)); }
{
return c_(std::forward<typename detail::ref_arg<Actual>::type>(actual));
}
friend std::ostream& operator<<(std::ostream& s, const matcher& m) { return s << mock::format(m.c_); } friend std::ostream& operator<<(std::ostream& s, const matcher& m) { return s << mock::format(m.c_); }
private: private:
@ -66,10 +63,7 @@ class matcher<Actual, Functor, std::enable_if_t<detail::is_functor<Functor, Actu
{ {
public: public:
explicit matcher(const Functor& f) : c_(f) {} explicit matcher(const Functor& f) : c_(f) {}
bool operator()(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)); }
{
return c_(std::forward<typename detail::ref_arg<Actual>::type>(actual));
}
friend std::ostream& operator<<(std::ostream& s, const matcher& m) { return s << mock::format(m.c_); } friend std::ostream& operator<<(std::ostream& s, const matcher& m) { return s << mock::format(m.c_); }
private: private:

View file

@ -40,7 +40,7 @@ set(testsUsingUndefinedCPP test_function test_integration)
foreach(testFile IN LISTS testFiles) foreach(testFile IN LISTS testFiles)
get_filename_component(name ${testFile} NAME_WE) 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}) set(curName ${name}${testVariant})
add_executable(${curName} ${testFile}) add_executable(${curName} ${testFile})
if(name IN_LIST testsUsingUndefinedCPP) if(name IN_LIST testsUsingUndefinedCPP)
@ -50,7 +50,6 @@ foreach(testFile IN LISTS testFiles)
add_test(NAME ${curName} COMMAND ${curName}) add_test(NAME ${curName} COMMAND ${curName})
endforeach() endforeach()
target_compile_definitions(${name}_max_args PRIVATE MOCK_MAX_ARGS=21)
target_compile_definitions(${name}_use_conversions PRIVATE MOCK_USE_CONVERSIONS) target_compile_definitions(${name}_use_conversions PRIVATE MOCK_USE_CONVERSIONS)
target_link_libraries(${name}_thread_safe PRIVATE Boost::thread) target_link_libraries(${name}_thread_safe PRIVATE Boost::thread)

View file

@ -24,7 +24,6 @@ alias mock_inspect :
rule run-test ( name ) rule run-test ( name )
{ {
run $(name) defined_1.cpp defined_2.cpp undefined.cpp /boost//unit_test_framework : : : : $(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 : : : <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 ; run $(name) undefined.cpp /boost//unit_test_framework /boost//thread : : : <define>MOCK_THREAD_SAFE <define>BOOST_THREAD_USES_MOVE <threading>multi : $(name)_thread_safe ;
} }

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -6,7 +6,6 @@
// (See accompanying file LICENSE_1_0.txt or copy at // (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt) // http://www.boost.org/LICENSE_1_0.txt)
#define MOCK_MAX_ARGS 30
#include <turtle/mock.hpp> #include <turtle/mock.hpp>
#ifdef _MSC_VER #ifdef _MSC_VER
# pragma warning(disable : 4505) # 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

View file

@ -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

View file

@ -6,7 +6,7 @@
// (See accompanying file LICENSE_1_0.txt or copy at // (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt) // http://www.boost.org/LICENSE_1_0.txt)
#include <turtle/detail/function.hpp> #include <turtle/detail/expectation.hpp>
#include <turtle/matcher.hpp> #include <turtle/matcher.hpp>
#include <boost/test/unit_test.hpp> #include <boost/test/unit_test.hpp>
#include <functional> #include <functional>
@ -88,16 +88,16 @@ std::string serialize(const T& t)
BOOST_AUTO_TEST_CASE(default_matcher_is_serialized_to_any) BOOST_AUTO_TEST_CASE(default_matcher_is_serialized_to_any)
{ {
using mock::detail::default_matcher; using mock::detail::default_matcher;
BOOST_TEST(serialize(default_matcher<void()>{}) == ""); BOOST_TEST(serialize(default_matcher<>{}) == "");
BOOST_TEST(serialize(default_matcher<void(int)>{}) == "any"); BOOST_TEST(serialize(default_matcher<int>{}) == "any");
BOOST_TEST(serialize(default_matcher<void(int, int)>{}) == "any, any"); BOOST_TEST(serialize(default_matcher<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<int, int, int, int, int>{}) == "any, any, any, any, any");
} }
namespace { namespace {
struct custom_constraint struct custom_constraint
{ {
int expected_ = 42; int expected_;
custom_constraint(int expected = 42) : expected_(expected) {} custom_constraint(int expected = 42) : expected_(expected) {}
friend std::ostream& operator<<(std::ostream& s, const custom_constraint& c) 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) BOOST_AUTO_TEST_CASE(single_matcher_serializes)
{ {
using mock::detail::single_matcher; using mock::detail::single_matcher;
BOOST_TEST(serialize(single_matcher<void(int), void(int)>(1)) == "1"); BOOST_TEST(serialize(single_matcher<void(int), 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), int, int>(1, 2)) == "1, 2");
BOOST_TEST( BOOST_TEST(
serialize( serialize(single_matcher<void(int, int, mock::constraint<custom_constraint>, int, int), int, int, int, int, int>(
single_matcher<void(int, int, mock::constraint<custom_constraint>, int, int), void(int, int, int, int, int)>( 1, 2, custom_constraint(), 4, 5)) == "1, 2, custom42, 4, 5");
1, 2, custom_constraint(), 4, 5)) == "1, 2, custom42, 4, 5");
} }
BOOST_AUTO_TEST_CASE(multi_matcher_serializes) BOOST_AUTO_TEST_CASE(multi_matcher_serializes)
{ {
using mock::detail::multi_matcher; 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");
} }

View file

@ -11,28 +11,30 @@
#include <boost/preprocessor/repetition/enum.hpp> #include <boost/preprocessor/repetition/enum.hpp>
#include <boost/test/unit_test.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 { namespace {
struct my_custom_mock struct my_custom_mock
{ {
MOCK_METHOD(method, MOCK_MAX_ARGS, void(BOOST_PP_ENUM(MOCK_MAX_ARGS, IDENTITY, int)), tag) MOCK_METHOD(method, NUM_TEST_ARGS, void(BOOST_PP_ENUM(NUM_TEST_ARGS, IDENTITY, int)), tag)
MOCK_METHOD(method2, MOCK_MAX_ARGS, int(BOOST_PP_ENUM(MOCK_MAX_ARGS, IDENTITY, int)), tag_2) MOCK_METHOD(method2, NUM_TEST_ARGS, int(BOOST_PP_ENUM(NUM_TEST_ARGS, IDENTITY, int)), tag_2)
}; };
} // namespace } // namespace
BOOST_FIXTURE_TEST_CASE(call_mock_method_with_max_number_of_args, mock_error_fixture) BOOST_FIXTURE_TEST_CASE(call_mock_method_with_max_number_of_args, mock_error_fixture)
{ {
my_custom_mock m; my_custom_mock m;
MOCK_EXPECT(m.tag).once().with(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(MOCK_MAX_ARGS, IDENTITY, 0)); m.method(BOOST_PP_ENUM(NUM_TEST_ARGS, IDENTITY, 0));
CHECK_CALLS(1); CHECK_CALLS(1);
} }
BOOST_FIXTURE_TEST_CASE(call_mock_method_with_max_number_of_args_and_a_return_value, mock_error_fixture) BOOST_FIXTURE_TEST_CASE(call_mock_method_with_max_number_of_args_and_a_return_value, mock_error_fixture)
{ {
my_custom_mock m; my_custom_mock m;
MOCK_EXPECT(m.tag_2).once().with(BOOST_PP_ENUM(MOCK_MAX_ARGS, IDENTITY, 0)).returns(42); 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(MOCK_MAX_ARGS, IDENTITY, 0))); BOOST_CHECK_EQUAL(42, m.method2(BOOST_PP_ENUM(NUM_TEST_ARGS, IDENTITY, 0)));
CHECK_CALLS(1); CHECK_CALLS(1);
} }

View file

@ -10,6 +10,7 @@
#include <turtle/detail/function.hpp> #include <turtle/detail/function.hpp>
#include <turtle/sequence.hpp> #include <turtle/sequence.hpp>
#include <boost/test/unit_test.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) 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) 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; 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_NO_THROW(e());
BOOST_CHECK(e.verify()); BOOST_CHECK(e.verify());
CHECK_CALLS(1); CHECK_CALLS(1);