diff --git a/include/turtle/detail/action.hpp b/include/turtle/detail/action.hpp index 7bc5fa0..8b267e5 100644 --- a/include/turtle/detail/action.hpp +++ b/include/turtle/detail/action.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 + struct value_imp : value + { + using type = std::remove_const_t>; + + template + value_imp(U&& t) : t_(std::forward(t)) + {} + type t_; + }; + template class action : public action_base { @@ -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 - struct value_imp : value - { - typedef std::remove_const_t> type; - - template - value_imp(U&& t) : t_(std::forward(t)) - {} - type t_; - }; - template typename value_imp::type& store(T&& t) { diff --git a/include/turtle/detail/expectation.hpp b/include/turtle/detail/expectation.hpp index 5c23895..cd107dc 100644 --- a/include/turtle/detail/expectation.hpp +++ b/include/turtle/detail/expectation.hpp @@ -27,7 +27,8 @@ namespace mock { namespace detail { bool operator()(typename ref_arg::type...) override { return true; } void serialize(std::ostream& s) const override { - for(unsigned i = 0; i < sizeof...(Args); ++i) + constexpr auto arity = sizeof...(Args); + for(unsigned i = 0; i < arity; ++i) { if(i) s << ", "; @@ -99,7 +100,7 @@ namespace mock { namespace detail { template class expectation : public action { - static constexpr auto arity = sizeof...(Args); + static constexpr std::size_t arity = sizeof...(Args); public: expectation() : expectation("unknown location", 0) {} @@ -122,13 +123,13 @@ namespace mock { namespace detail { void invoke(std::unique_ptr i) { invocation_ = std::move(i); } template - std::enable_if_t<(arity > 0) && sizeof...(Constraints) == arity, expectation&> with(Constraints... c) + std::enable_if_t<(arity > 0u) && 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) + std::enable_if_t<(Arity > 1u), expectation&> with(const Constraint& c) { matcher_ = std::make_unique>(c); return *this; diff --git a/include/turtle/detail/function_impl.hpp b/include/turtle/detail/function_impl.hpp index 8cbbd1f..1c0bea4 100644 --- a/include/turtle/detail/function_impl.hpp +++ b/include/turtle/detail/function_impl.hpp @@ -69,6 +69,9 @@ namespace mock { namespace detail { #endif } + template + class lazy_args; + template class function_impl; @@ -133,7 +136,7 @@ namespace mock { namespace detail { { private: typedef wrapper_base base_type; - static constexpr auto arity = sizeof...(Args); + static constexpr std::size_t arity = sizeof...(Args); public: wrapper(const std::shared_ptr& m, expectation_type& e) : base_type(e), lock_(m) {} @@ -238,8 +241,9 @@ namespace mock { namespace detail { 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) +#define MOCK_FUNCTION_CONTEXT \ + boost::unit_test::lazy_ostream::instance() \ + << lazy_context(this) << lazy_args(args...) << lazy_expectations(this) lock _(mutex_); valid_ = false; @@ -316,35 +320,49 @@ 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_; const int exceptions_; const std::shared_ptr mutex_; }; + + template + class lazy_args : lazy_args + { + ArgFirst& arg_; + + public: + lazy_args(ArgFirst& arg, std::add_lvalue_reference_t... args) + : lazy_args(args...), arg_(arg) + {} + std::ostream& print(std::ostream& s) const + { + s << ' ' << mock::format(arg_) << ','; + return lazy_args::print(s); + } + }; + template + class lazy_args + { + 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 + std::ostream& operator<<(std::ostream& s, const lazy_args& a) + { + s << '('; + return a.print(s) << ')'; + } }} // namespace mock::detail #endif // MOCK_FUNCTION_IMPL_HPP_INCLUDED