diff --git a/doc/changelog.qbk b/doc/changelog.qbk index c608e81..326f21a 100644 --- a/doc/changelog.qbk +++ b/doc/changelog.qbk @@ -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 making MOCK_MAX_ARGS superflous [endsect] diff --git a/doc/customization.qbk b/doc/customization.qbk index 6946cff..69e1835 100644 --- a/doc/customization.qbk +++ b/doc/customization.qbk @@ -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. : diff --git a/doc/example/customization.cpp b/doc/example/customization.cpp index 6e0c839..dae9ccb 100644 --- a/doc/example/customization.cpp +++ b/doc/example/customization.cpp @@ -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 -//] - #if defined(__GNUC__) # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wunused-parameter" diff --git a/include/turtle/config.hpp b/include/turtle/config.hpp index b2a0f68..d60fe72 100644 --- a/include/turtle/config.hpp +++ b/include/turtle/config.hpp @@ -18,10 +18,6 @@ # define MOCK_USE_BOOST_TEST #endif -#ifndef MOCK_MAX_ARGS -# define MOCK_MAX_ARGS 9 -#endif - #ifndef MOCK_MAX_SEQUENCES # define MOCK_MAX_SEQUENCES 10 #endif diff --git a/include/turtle/detail/expectation.hpp b/include/turtle/detail/expectation.hpp new file mode 100644 index 0000000..5c23895 --- /dev/null +++ b/include/turtle/detail/expectation.hpp @@ -0,0 +1,184 @@ +// http://turtle.sourceforge.net +// +// Copyright Mathieu Champlon 2012 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef MOCK_EXPECTATION_HPP_INCLUDED +#define MOCK_EXPECTATION_HPP_INCLUDED + +#include "../matcher.hpp" +#include "../sequence.hpp" +#include "action.hpp" +#include "invocation.hpp" +#include "matcher_base.hpp" +#include +#include +#include +#include + +namespace mock { namespace detail { + template + class default_matcher : public matcher_base + { + private: + bool operator()(typename ref_arg::type...) override { return true; } + void serialize(std::ostream& s) const override + { + for(unsigned i = 0; i < sizeof...(Args); ++i) + { + if(i) + s << ", "; + s << "any"; + } + } + }; + + template + class single_matcher; + + template + class single_matcher : public matcher_base + { + 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(constraints)...) {} + + private: + template + bool is_valid_impl(std::index_sequence, typename ref_arg::type... t) + { + using expander = bool[]; + bool result = true; + (void)expander{ result &= std::get(matchers_)(std::forward(t))... }; + return result; + } + bool operator()(typename ref_arg::type... t) override + { + return is_valid_impl(std::make_index_sequence{}, std::forward(t)...); + } + template + void serialize_impl(std::index_sequence, std::ostream& s) const + { + using expander = int[]; + s << std::get<0>(matchers_); + (void)expander{ 0, (s << ", " << std::get(matchers_), 0)... }; + } + void serialize(std::ostream& s) const override + { + serialize_impl(std::make_index_sequence{}, s); + } + + private: + std::tuple...> matchers_; + }; + + template + class multi_matcher : public matcher_base + { + static_assert(sizeof...(Args) > 0, "This class is only useful for functions with arguments"); + + public: + multi_matcher(const F& f) : f_(f) {} + + private: + bool operator()(typename ref_arg::type... t) override { return f_(std::forward(t)...); } + void serialize(std::ostream& s) const override { s << mock::format(f_); } + + private: + F f_; + }; + + template + class expectation; + + template + class expectation : public action + { + static constexpr auto arity = sizeof...(Args); + + public: + expectation() : expectation("unknown location", 0) {} + expectation(const char* file, int line) + : invocation_(std::make_unique()), matcher_(std::make_unique>()), + 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 i) { invocation_ = std::move(i); } + + template + std::enable_if_t<(arity > 0) && sizeof...(Constraints) == arity, expectation&> with(Constraints... c) + { + matcher_ = std::make_unique>(c...); + return *this; + } + template + std::enable_if_t<(Arity > 1), expectation&> with(const Constraint& c) + { + matcher_ = std::make_unique>(c); + return *this; + } + + void add(sequence& s) + { + s.impl_->add(this); + sequences_.push_back(s.impl_); + } + + bool verify() const { return invocation_->verify(); } + + bool is_valid(typename ref_arg::type... t) const + { + return !invocation_->exhausted() && (*matcher_)(std::forward(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_; + std::unique_ptr> matcher_; + std::vector> sequences_; + const char* file_; + int line_; + }; +}} // namespace mock::detail + +#endif // MOCK_EXPECTATION_HPP_INCLUDED diff --git a/include/turtle/detail/expectation_template.hpp b/include/turtle/detail/expectation_template.hpp deleted file mode 100644 index 3f42263..0000000 --- a/include/turtle/detail/expectation_template.hpp +++ /dev/null @@ -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 c##n##_; - -#define MOCK_EXPECTATION_IS_VALID(z, n, d) BOOST_PP_IF(n, &&, ) c##n##_(std::forward(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(a##n) - -#define MOCK_REF_ARG(z, n, d) typename ref_arg::type a##n - -#define MOCK_REF_ARG_T(z, n, d) typename ref_arg::type - -namespace mock { namespace detail { - template - class default_matcher; - - template - class default_matcher : - public matcher_base - { - 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 - class single_matcher; - - template - class single_matcher : - public matcher_base - { - 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 - class multi_matcher; - - template - class multi_matcher : - public matcher_base - { - 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 - class expectation; - - template - class expectation : - public action - { - public: - expectation() - : invocation_(std::make_unique()), - matcher_(std::make_unique>()), - file_("unknown location"), line_(0) - {} - expectation(const char* file, int line) - : invocation_(std::make_unique()), - matcher_(std::make_unique>()), 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 i) { invocation_ = std::move(i); } - -#ifndef MOCK_NUM_ARGS_0 - template - expectation& with(BOOST_PP_ENUM_BINARY_PARAMS(MOCK_NUM_ARGS, Constraint_, c)) - { - matcher_ = std::make_unique>( - BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, c)); - return *this; - } -# if MOCK_NUM_ARGS > 1 - template - expectation& with(const Constraint& c) - { - matcher_ = std::make_unique>(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_; - std::unique_ptr> matcher_; - std::vector> 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 diff --git a/include/turtle/detail/function.hpp b/include/turtle/detail/function.hpp index f5ae558..288990a 100644 --- a/include/turtle/detail/function.hpp +++ b/include/turtle/detail/function.hpp @@ -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 -#include -#include -#include -#include -#include -#include #include -#include -#include #include -#include namespace mock { namespace detail { - template - struct wrapper_base - { - wrapper_base(E& e) : e_(&e) {} + template + class function; - template - void returns(T t) + template + class function + { + private: + typedef function_impl impl_type; + typedef typename impl_type::wrapper_type expectation_type; + typedef typename impl_type::error_type error_type; + + public: + function() : impl_(std::make_shared()) {} + + bool verify() const { return impl_->verify(); } + bool verify(const char* file, int line) const { - e_->returns(t); + error_type::pass(file, line); + return impl_->verify(); + } + void reset() { impl_->reset(); } + void reset(const char* file, int line) + { + error_type::pass(file, line); + impl_->reset(); } - E* e_; - }; - template - struct wrapper_base - { - wrapper_base(E& e) : e_(&e) {} - - E* e_; - }; - template - struct wrapper_base - { - wrapper_base(E& e) : e_(&e) {} - - void returns(R* r) { e_->returns(r); } - template - void returns(const std::reference_wrapper& r) + expectation_type expect(const char* file, int line) { - e_->returns(r); + error_type::pass(file, line); + return impl_->expect(file, line); + } + expectation_type expect() { return impl_->expect(); } + + R operator()(Ts... args) const { return (*impl_)(std::forward(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, + boost::unit_test::const_string name) const + { + impl_->add(c, p, instance, type, name); + } - inline int exceptions() - { -#ifdef MOCK_UNCAUGHT_EXCEPTIONS - using namespace std; - return uncaught_exceptions(); -#else - return std::uncaught_exception() ? 1 : 0; -#endif - } + private: + std::shared_ptr impl_; + }; }} // 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 -#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 diff --git a/include/turtle/detail/function_impl_template.hpp b/include/turtle/detail/function_impl.hpp similarity index 71% rename from include/turtle/detail/function_impl_template.hpp rename to include/turtle/detail/function_impl.hpp index c9db991..8cbbd1f 100644 --- a/include/turtle/detail/function_impl_template.hpp +++ b/include/turtle/detail/function_impl.hpp @@ -6,29 +6,74 @@ // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -#include "expectation_template.hpp" +#ifndef MOCK_FUNCTION_IMPL_HPP_INCLUDED +#define MOCK_FUNCTION_IMPL_HPP_INCLUDED + +#include "../error.hpp" +#include "expectation.hpp" +#include "mutex.hpp" +#include "verifiable.hpp" +#include +#include +#include +#include +#include #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) - namespace mock { namespace detail { + template + struct wrapper_base + { + wrapper_base(E& e) : e_(&e) {} + + template + void returns(T t) + { + e_->returns(t); + } + + E* e_; + }; + template + struct wrapper_base + { + wrapper_base(E& e) : e_(&e) {} + + E* e_; + }; + template + struct wrapper_base + { + wrapper_base(E& e) : e_(&e) {} + + void returns(R* r) { e_->returns(r); } + template + void returns(const std::reference_wrapper& 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 class function_impl; - template - class function_impl : - public verifiable, - public std::enable_shared_from_this> + template + class function_impl : public verifiable, public std::enable_shared_from_this> { public: typedef safe_error> error_type; @@ -82,12 +127,13 @@ namespace mock { namespace detail { } private: - typedef expectation expectation_type; + typedef expectation expectation_type; class wrapper : public wrapper_base { private: typedef wrapper_base base_type; + static constexpr auto arity = sizeof...(Args); public: wrapper(const std::shared_ptr& m, expectation_type& e) : base_type(e), lock_(m) {} @@ -126,24 +172,18 @@ namespace mock { namespace detail { return *this; } -#ifndef MOCK_NUM_ARGS_0 - template - 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 + 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 - wrapper& with(const Constraint& c) - { - this->e_->with(c); - return *this; - } -# endif -#endif - #define MOCK_FUNCTION_IN_ADD(z, n, d) this->e_->add(s##n); #define MOCK_FUNCTION_IN(z, n, d) \ @@ -195,13 +235,17 @@ namespace mock { namespace detail { return wrapper(mutex_, expectations_.back()); } - R operator()(BOOST_PP_ENUM_BINARY_PARAMS(MOCK_NUM_ARGS, T, t)) const + R operator()(Args... args) const { +// Due to lifetime rules of references this must be created and consumed in one line +#define MOCK_FUNCTION_CONTEXT \ + boost::unit_test::lazy_ostream::instance() << lazy_context(this) << lazy_args(args...) << lazy_expectations(this) + lock _(mutex_); valid_ = false; for(const auto& expectation : expectations_) { - if(expectation.is_valid(BOOST_PP_ENUM(MOCK_NUM_ARGS, MOCK_FORWARD, _))) + if(expectation.is_valid(std::forward(args)...)) { if(!expectation.invoke()) { @@ -218,12 +262,13 @@ namespace mock { namespace detail { valid_ = true; error_type::call(MOCK_FUNCTION_CONTEXT, expectation.file(), expectation.line()); if(expectation.functor()) - return expectation.functor()(BOOST_PP_ENUM(MOCK_NUM_ARGS, MOCK_FORWARD, _)); + return expectation.functor()(std::forward(args)...); return expectation.trigger(); } } error_type::fail("unexpected call", MOCK_FUNCTION_CONTEXT); return error_type::abort(); +#undef MOCK_FUNCTION_CONTEXT } void add(context& c, @@ -271,6 +316,29 @@ namespace mock { namespace detail { const function_impl* impl_; }; + struct lazy_args + { + lazy_args(std::add_lvalue_reference_t... args) : args_(args...) {} + friend std::ostream& operator<<(std::ostream& s, const lazy_args& a) + { + return a.print_impl(std::make_index_sequence{}, s); + } + + private: + std::tuple...> args_; + + template + std::ostream& print_impl(std::index_sequence, std::ostream& s) const + { + s << '('; + using expander = int[]; + (void)expander{ + 0, (s << ' ' << mock::format(std::get(args_)) << (sizeof...(Args) - 1u == I ? ' ' : ','), 0)... + }; + return s << ')'; + } + }; + std::list expectations_; context* context_; mutable bool valid_; @@ -279,6 +347,4 @@ namespace mock { namespace detail { }; }} // namespace mock::detail -#undef MOCK_FUNCTION_FORMAT -#undef MOCK_FUNCTION_CONTEXT -#undef MOCK_FORWARD +#endif // MOCK_FUNCTION_IMPL_HPP_INCLUDED diff --git a/include/turtle/detail/function_iterate.hpp b/include/turtle/detail/function_iterate.hpp deleted file mode 100644 index f86538e..0000000 --- a/include/turtle/detail/function_iterate.hpp +++ /dev/null @@ -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 diff --git a/include/turtle/detail/function_template.hpp b/include/turtle/detail/function_template.hpp deleted file mode 100644 index 69a0e18..0000000 --- a/include/turtle/detail/function_template.hpp +++ /dev/null @@ -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) - -namespace mock { namespace detail { - template - class function; - - template - class function - { - private: - typedef function_impl impl_type; - typedef typename impl_type::wrapper_type expectation_type; - typedef typename impl_type::error_type error_type; - - public: - function() : impl_(std::make_shared()) {} - - 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, - boost::unit_test::const_string name) const - { - impl_->add(c, p, instance, type, name); - } - - private: - std::shared_ptr impl_; - }; -}} // namespace mock::detail - -#undef MOCK_FORWARD diff --git a/include/turtle/detail/matcher_base_template.hpp b/include/turtle/detail/matcher_base.hpp similarity index 67% rename from include/turtle/detail/matcher_base_template.hpp rename to include/turtle/detail/matcher_base.hpp index 8a6199d..de16e22 100644 --- a/include/turtle/detail/matcher_base_template.hpp +++ b/include/turtle/detail/matcher_base.hpp @@ -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::type +#ifndef MOCK_MATCHER_BASE_HPP_INCLUDED +#define MOCK_MATCHER_BASE_HPP_INCLUDED + +#include "move_helper.hpp" +#include namespace mock { namespace detail { - template - class matcher_base; - - template - class matcher_base + template + class matcher_base { public: matcher_base() = default; @@ -21,7 +22,7 @@ namespace mock { namespace detail { matcher_base& operator=(const matcher_base&) = delete; virtual ~matcher_base() = default; - virtual bool operator()(BOOST_PP_ENUM(MOCK_NUM_ARGS, MOCK_REF_ARG, _)) = 0; + virtual bool operator()(typename ref_arg::type...) = 0; friend std::ostream& operator<<(std::ostream& s, const matcher_base& m) { @@ -34,4 +35,4 @@ namespace mock { namespace detail { }; }} // namespace mock::detail -#undef MOCK_REF_ARG +#endif // MOCK_MATCHER_BASE_HPP_INCLUDED diff --git a/include/turtle/detail/signature_traits.hpp b/include/turtle/detail/signature_traits.hpp index e6948f6..02c108f 100644 --- a/include/turtle/detail/signature_traits.hpp +++ b/include/turtle/detail/signature_traits.hpp @@ -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 @@ -59,4 +59,4 @@ namespace mock { namespace detail { }} // namespace mock::detail -#endif // MOCK_PARAMETER_HPP_INCLUDED +#endif // MOCK_SIGNATURE_TRAITS_HPP_INCLUDED diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index c43f646..486fdb7 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -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) diff --git a/test/Jamfile.jam b/test/Jamfile.jam index 3e8768b..4575a0e 100644 --- a/test/Jamfile.jam +++ b/test/Jamfile.jam @@ -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 : : : MOCK_MAX_ARGS=21 : $(name)_max_args ; run $(name) undefined.cpp /boost//unit_test_framework : : : MOCK_USE_CONVERSIONS : $(name)_use_conversions ; run $(name) undefined.cpp /boost//unit_test_framework /boost//thread : : : MOCK_THREAD_SAFE BOOST_THREAD_USES_MOVE multi : $(name)_thread_safe ; } diff --git a/test/fail_number_of_arguments_greater_than_max_constant.cpp b/test/fail_number_of_arguments_greater_than_max_constant.cpp deleted file mode 100644 index ef7378a..0000000 --- a/test/fail_number_of_arguments_greater_than_max_constant.cpp +++ /dev/null @@ -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 - -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 diff --git a/test/test_matcher.cpp b/test/test_matcher.cpp index e966d2d..cc98be0 100644 --- a/test/test_matcher.cpp +++ b/test/test_matcher.cpp @@ -6,7 +6,7 @@ // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -#include +#include #include #include #include @@ -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{}) == ""); - BOOST_TEST(serialize(default_matcher{}) == "any"); - BOOST_TEST(serialize(default_matcher{}) == "any, any"); - BOOST_TEST(serialize(default_matcher{}) == "any, any, any, any, any"); + BOOST_TEST(serialize(default_matcher<>{}) == ""); + BOOST_TEST(serialize(default_matcher{}) == "any"); + BOOST_TEST(serialize(default_matcher{}) == "any, any"); + BOOST_TEST(serialize(default_matcher{}) == "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(1)) == "1"); - BOOST_TEST(serialize(single_matcher(1, 2)) == "1, 2"); + BOOST_TEST(serialize(single_matcher(1)) == "1"); + BOOST_TEST(serialize(single_matcher(1, 2)) == "1, 2"); BOOST_TEST( - serialize( - single_matcher, int, int), void(int, int, int, int, int)>( - 1, 2, custom_constraint(), 4, 5)) == "1, 2, custom42, 4, 5"); + serialize(single_matcher, 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(1337))) == "custom1337"); + BOOST_TEST(serialize(multi_matcher(custom_constraint(1337))) == "custom1337"); } diff --git a/test/test_max_args.cpp b/test/test_max_args.cpp index 147089c..a062548 100644 --- a/test/test_max_args.cpp +++ b/test/test_max_args.cpp @@ -11,28 +11,30 @@ #include #include -#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); }