From a6a363905528fa8afd7126448f7ccd24c348788d Mon Sep 17 00:00:00 2001 From: mat007 Date: Sat, 30 Jan 2010 10:11:18 +0000 Subject: [PATCH] Merged experimental features branch git-svn-id: https://svn.code.sf.net/p/turtle/code/trunk@104 860be788-9bd5-4423-9f1e-828f051e677b --- src/libraries/turtle/error.hpp | 4 + src/libraries/turtle/expectation.hpp | 21 +++-- src/libraries/turtle/mock.hpp | 135 +++++++++++++++++++++++---- src/tests/turtle_test/mock_test.cpp | 84 +++++++++++++++++ 4 files changed, 218 insertions(+), 26 deletions(-) diff --git a/src/libraries/turtle/error.hpp b/src/libraries/turtle/error.hpp index bd8515a..3f51c8e 100644 --- a/src/libraries/turtle/error.hpp +++ b/src/libraries/turtle/error.hpp @@ -10,15 +10,18 @@ #define MOCK_ERROR_HPP_INCLUDED #include "config.hpp" +#ifdef MOCK_USE_BOOST_TEST #include #include #include #include #include +#endif // MOCK_USE_BOOST_TEST #include namespace mock { +#ifdef MOCK_USE_BOOST_TEST template< typename Result > struct boost_test_error_policy { @@ -71,6 +74,7 @@ namespace mock << boost::unit_test::log::end(); } }; +#endif // MOCK_USE_BOOST_TEST struct exception {}; diff --git a/src/libraries/turtle/expectation.hpp b/src/libraries/turtle/expectation.hpp index 944572b..abd548a 100644 --- a/src/libraries/turtle/expectation.hpp +++ b/src/libraries/turtle/expectation.hpp @@ -17,11 +17,13 @@ #include "root.hpp" #include "format.hpp" #include "invocation.hpp" -#include -#include +#include +#include +#include #include #include #include +#include #include #include #include @@ -30,13 +32,17 @@ namespace mock { template< typename Signature, typename ErrorPolicy = MOCK_ERROR_POLICY< - BOOST_DEDUCED_TYPENAME boost::function< - Signature >::result_type > > + BOOST_DEDUCED_TYPENAME + boost::function_types::result_type< Signature >::type > > class expectation { public: typedef BOOST_DEDUCED_TYPENAME - boost::function< Signature >::result_type result_type; + boost::function_types::result_type< Signature >::type result_type; + typedef BOOST_DEDUCED_TYPENAME + boost::function_types::function_arity< Signature > arity; + typedef BOOST_DEDUCED_TYPENAME + boost::function_types::parameter_types< Signature >::type parameter_types; template< typename Args > struct sig @@ -45,10 +51,7 @@ namespace mock }; private: - typedef detail::matcher< result_type, - Signature, - boost::function< Signature >::arity > - matcher_type; + typedef detail::matcher< result_type, Signature, arity::value > matcher_type; public: struct expectation_tag diff --git a/src/libraries/turtle/mock.hpp b/src/libraries/turtle/mock.hpp index 01f2743..b346152 100644 --- a/src/libraries/turtle/mock.hpp +++ b/src/libraries/turtle/mock.hpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #define BOOST_TYPEOF_SILENT #include @@ -146,6 +147,79 @@ namespace detail { typedef T base_type; }; + + struct no_type + { + private: + no_type(); + }; + + template< typename S, int n, bool B > + struct arg_imp + { + typedef no_type type; + }; + template< typename S, int n > + struct arg_imp< S, n, true > + { + typedef BOOST_DEDUCED_TYPENAME + boost::mpl::at_c< + BOOST_DEDUCED_TYPENAME + boost::function_types::parameter_types< S >::type, + n - 1 + >::type type; + }; + template< typename S, int n, int N > + struct arg + { + BOOST_MPL_ASSERT_RELATION( n, >, 0 ); + BOOST_MPL_ASSERT_RELATION( n, <=, N ); + typedef BOOST_DEDUCED_TYPENAME + arg_imp< S, n, + boost::function_types::function_arity< S >::value == N + >::type type; + }; + + template< typename E, int N > + struct has_arity + { + typedef BOOST_DEDUCED_TYPENAME + boost::mpl::equal_to< + BOOST_DEDUCED_TYPENAME E::arity, + boost::mpl::size_t< N > + >::type type; + }; + +#define MOCK_CALL_PARAM(z, n, d) \ + BOOST_DEDUCED_TYPENAME \ + boost::mpl::at_c< \ + BOOST_DEDUCED_TYPENAME E::parameter_types, \ + n \ + >::type t##n +#define MOCK_CALL_NO_TYPE(z, n, d) no_type +#define MOCK_CALL(z, n, d) \ + template< typename E > \ + BOOST_DEDUCED_TYPENAME boost::enable_if< \ + BOOST_DEDUCED_TYPENAME has_arity< E, n >::type, \ + BOOST_DEDUCED_TYPENAME E::result_type \ + >::type \ + call( E e BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM(n, MOCK_CALL_PARAM, BOOST_PP_EMPTY) ) \ + { \ + return e( BOOST_PP_ENUM_PARAMS(n, t) ); \ + } \ + template< typename E > \ + BOOST_DEDUCED_TYPENAME boost::disable_if< \ + BOOST_DEDUCED_TYPENAME has_arity< E, n >::type, \ + BOOST_DEDUCED_TYPENAME E::result_type \ + >::type \ + call( E BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM(n, MOCK_CALL_NO_TYPE, BOOST_PP_EMPTY) ) \ + { \ + throw std::logic_error( "should never be called" ); \ + } + BOOST_PP_REPEAT_FROM_TO(0, MOCK_MAX_ARGS, MOCK_CALL, BOOST_PP_EMPTY) +#undef MOCK_CALL +#undef MOCK_CALL_NO_TYPE +#undef MOCK_CALL_PARAM } } @@ -164,29 +238,37 @@ namespace detail mock::detail::configure( mock::detail::ref( o ).exp##t, \ "?", ".", BOOST_PP_STRINGIZE(t), mock::detail::ref( o ) ) -#define MOCK_METHOD_ARG(z, n, arg) BOOST_PP_COMMA_IF(n) \ - BOOST_PP_CAT(BOOST_PP_CAT(arg, BOOST_PP_INC(n)),_type) \ - BOOST_PP_CAT(a, BOOST_PP_INC(n)) -#define MOCK_METHOD_ARGS(n, arg) \ - BOOST_PP_REPEAT_FROM_TO(0, n, MOCK_METHOD_ARG, arg) -#define MOCK_MOCKER_ARG(z, n, d) \ - BOOST_PP_COMMA_IF(n) BOOST_PP_CAT(a, BOOST_PP_INC(n)) -#define MOCK_MOCKER_ARGS(n) \ - BOOST_PP_REPEAT_FROM_TO(0, n, MOCK_MOCKER_ARG, BOOST_PP_EMPTY) #define MOCK_METHOD_EXPECTATION(S, t) \ mutable mock::expectation< S > exp##t; - -#define MOCK_METHOD_STUB(M, n, S, t, c, tpn) \ - tpn boost::function< S >::result_type M( \ - MOCK_METHOD_ARGS(n, tpn boost::function< S >::arg) ) c \ - { \ - return MOCK_ANONYMOUS_MOCKER(this, t)( MOCK_MOCKER_ARGS(n) ); \ - } #define MOCK_SIGNATURE(M) \ mock::detail::signature< BOOST_TYPEOF(&base_type::M) >::type #define MOCK_SIGNATURE_TPL(M) \ BOOST_DEDUCED_TYPENAME mock::detail::signature< BOOST_TYPEOF_TPL(&base_type::M) >::type +#define MOCK_METHOD_ARG(N, n, S, tpn) \ + BOOST_PP_COMMA_IF(n) tpn mock::detail::arg< S, BOOST_PP_INC(n), N >::type BOOST_PP_CAT(p, n) +#define MOCK_METHOD_ARG_PROXY(z, n, d) \ + MOCK_METHOD_ARG( \ + BOOST_PP_ARRAY_ELEM(0, d), \ + n, \ + BOOST_PP_ARRAY_ELEM(1, d), \ + BOOST_PP_ARRAY_ELEM(2, d) ) +#define MOCK_METHOD_STUB(M, n, S, t, c, tpn) \ + tpn boost::function_types::result_type< S >::type M( \ + BOOST_PP_REPEAT_FROM_TO(0, n, MOCK_METHOD_ARG_PROXY, (3, (n, S, tpn))) ) c \ + { \ + return mock::detail::call( MOCK_ANONYMOUS_MOCKER(this, t) \ + BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, p) ); \ + } +#define MOCK_METHOD_STUB_PROXY(z, n, d) \ + MOCK_METHOD_STUB( \ + BOOST_PP_ARRAY_ELEM(0, d), \ + n, \ + BOOST_PP_ARRAY_ELEM(1, d), \ + BOOST_PP_ARRAY_ELEM(2, d), \ + BOOST_PP_ARRAY_ELEM(3, d), \ + BOOST_PP_ARRAY_ELEM(4, d)) + #define MOCK_METHOD_EXT(M, n, S, t) \ MOCK_METHOD_STUB(M, n, S, t,,) \ MOCK_METHOD_STUB(M, n, S, t, const,) \ @@ -213,7 +295,7 @@ namespace detail #define MOCK_METHOD_TPL(M, n) \ MOCK_METHOD_EXT_TPL(M, n, MOCK_SIGNATURE_TPL(M), M) -#define MOCK_DESTRUCTOR( T, t ) \ +#define MOCK_DESTRUCTOR(T, t) \ ~T() { exp##t(); } \ MOCK_METHOD_EXPECTATION(void(), t) @@ -221,4 +303,23 @@ namespace detail #define MOCK_RESET(o,t) MOCK_MOCKER(o,t).reset() #define MOCK_VERIFY(o,t) MOCK_MOCKER(o,t).verify() +// alternate experimental macros below, way too slow to compile to be really usable + +#define MOCK_METHOD_STUB_ALT(M, S, t, c, tpn) \ + BOOST_PP_REPEAT_FROM_TO(0, MOCK_MAX_ARGS, MOCK_METHOD_STUB_PROXY, (5,(M, S, t, c, tpn))) + +#define MOCK_METHOD_EXT_ALT(M, S, t) \ + MOCK_METHOD_STUB_ALT(M, S, t,,) \ + MOCK_METHOD_STUB_ALT(M, S, t, const,) \ + MOCK_METHOD_EXPECTATION(S, t) +#define MOCK_METHOD_ALT(M) \ + MOCK_METHOD_EXT_ALT(M, MOCK_SIGNATURE(M), M) + +#define MOCK_METHOD_EXT_TPL_ALT(M, S, t) \ + MOCK_METHOD_STUB_ALT(M, S, t,, BOOST_DEDUCED_TYPENAME) \ + MOCK_METHOD_STUB_ALT(M, S, t, const, BOOST_DEDUCED_TYPENAME) \ + MOCK_METHOD_EXPECTATION(S, t) +#define MOCK_METHOD_TPL_ALT(M) \ + MOCK_METHOD_EXT_TPL_ALT(M, MOCK_SIGNATURE_TPL(M), M) + #endif // #ifndef MOCK_MOCK_HPP_INCLUDED diff --git a/src/tests/turtle_test/mock_test.cpp b/src/tests/turtle_test/mock_test.cpp index 9043297..0ddb52c 100644 --- a/src/tests/turtle_test/mock_test.cpp +++ b/src/tests/turtle_test/mock_test.cpp @@ -217,3 +217,87 @@ BOOST_AUTO_TEST_CASE( mocking_a_destructor ) my_destroyed_class c; MOCK_EXPECT( c, destructor ).once(); } + +BOOST_MPL_ASSERT(( boost::is_same< float, mock::detail::arg< void( float ), 1, 1 >::type > )); +BOOST_MPL_ASSERT(( boost::is_same< float, mock::detail::arg< void( float, int ), 1, 2 >::type > )); +BOOST_MPL_ASSERT(( boost::is_same< int, mock::detail::arg< void( float, int ), 2, 2 >::type > )); +BOOST_MPL_ASSERT(( boost::is_same< mock::detail::no_type, mock::detail::arg< void( float ), 1, 2 >::type > )); +BOOST_MPL_ASSERT(( boost::is_same< mock::detail::no_type, mock::detail::arg< void( float ), 2, 2 >::type > )); +BOOST_MPL_ASSERT(( boost::is_same< mock::detail::no_type, mock::detail::arg< void( float, int ), 1, 1 >::type > )); +BOOST_MPL_ASSERT(( boost::is_same< mock::detail::no_type, mock::detail::arg< void( float, int ), 1, 3 >::type > )); +BOOST_MPL_ASSERT(( boost::is_same< mock::detail::no_type, mock::detail::arg< void( float, int ), 2, 3 >::type > )); + +BOOST_AUTO_TEST_CASE( call_selects_proper_form ) +{ + { + mock::expectation< void() > e; + e.expect().once(); + mock::detail::call( e ); + } + { + mock::expectation< void( int ) > e; + e.expect().once(); + mock::detail::call( e, 3 ); + } + { + mock::expectation< int() > e; + e.expect().once().returns( 0 ); + mock::detail::call( e ); + } + { + mock::expectation< int( int ) > e; + e.expect().once().returns( 0 ); + mock::detail::call( e, 3 ); + } +} + +namespace +{ + struct mock_class_0 + { + MOCK_METHOD_EXT_ALT( method, void(), method ) + }; + struct mock_class_1 + { + MOCK_METHOD_EXT_ALT( method, void( float ), method ) + }; + + struct mock_class_r0 + { + MOCK_METHOD_EXT_ALT( method, int(), method ) + }; + struct mock_class_r1 + { + MOCK_METHOD_EXT_ALT( method, int( float ), method ) + }; + + struct forward_declared_only; + struct defined_but_non_copiable : private boost::noncopyable + { + }; + struct base_class + { + virtual ~base_class() {} + virtual void some_method( int, float&, const std::string& ) = 0; + virtual void some_other_method() = 0; + virtual int another_method() = 0; + virtual void yet_another_method( forward_declared_only& ) = 0; + virtual void yet_again_some_other_method( defined_but_non_copiable& ) = 0; + }; + MOCK_BASE_CLASS( mock_base_class, base_class ) + { + MOCK_METHOD_ALT( some_method ) + MOCK_METHOD_ALT( some_other_method ) + MOCK_METHOD_ALT( another_method ) + MOCK_METHOD_ALT( yet_another_method ) + MOCK_METHOD_ALT( yet_again_some_other_method ) + }; +} + +BOOST_AUTO_TEST_CASE( experimental_macros_slow_as_hell_to_compile ) +{ + mock_base_class c; + MOCK_EXPECT( c, some_method ).once(); + float f = 4.f; + c.some_method( 3, f, "" ); +}