Merged experimental features branch

git-svn-id: https://svn.code.sf.net/p/turtle/code/trunk@104 860be788-9bd5-4423-9f1e-828f051e677b
This commit is contained in:
mat007 2010-01-30 10:11:18 +00:00
parent 92e13e815e
commit a6a3639055
4 changed files with 218 additions and 26 deletions

View file

@ -10,15 +10,18 @@
#define MOCK_ERROR_HPP_INCLUDED #define MOCK_ERROR_HPP_INCLUDED
#include "config.hpp" #include "config.hpp"
#ifdef MOCK_USE_BOOST_TEST
#include <boost/test/framework.hpp> #include <boost/test/framework.hpp>
#include <boost/test/test_tools.hpp> #include <boost/test/test_tools.hpp>
#include <boost/test/unit_test_suite.hpp> #include <boost/test/unit_test_suite.hpp>
#include <boost/test/execution_monitor.hpp> #include <boost/test/execution_monitor.hpp>
#include <boost/exception/enable_current_exception.hpp> #include <boost/exception/enable_current_exception.hpp>
#endif // MOCK_USE_BOOST_TEST
#include <iostream> #include <iostream>
namespace mock namespace mock
{ {
#ifdef MOCK_USE_BOOST_TEST
template< typename Result > template< typename Result >
struct boost_test_error_policy struct boost_test_error_policy
{ {
@ -71,6 +74,7 @@ namespace mock
<< boost::unit_test::log::end(); << boost::unit_test::log::end();
} }
}; };
#endif // MOCK_USE_BOOST_TEST
struct exception struct exception
{}; {};

View file

@ -17,11 +17,13 @@
#include "root.hpp" #include "root.hpp"
#include "format.hpp" #include "format.hpp"
#include "invocation.hpp" #include "invocation.hpp"
#include <boost/function.hpp> #include <boost/function_types/result_type.hpp>
#include <boost/shared_ptr.hpp> #include <boost/function_types/function_arity.hpp>
#include <boost/function_types/parameter_types.hpp>
#include <boost/preprocessor/repetition/repeat_from_to.hpp> #include <boost/preprocessor/repetition/repeat_from_to.hpp>
#include <boost/preprocessor/repetition/enum_params.hpp> #include <boost/preprocessor/repetition/enum_params.hpp>
#include <boost/preprocessor/repetition/enum_binary_params.hpp> #include <boost/preprocessor/repetition/enum_binary_params.hpp>
#include <boost/shared_ptr.hpp>
#include <exception> #include <exception>
#include <ostream> #include <ostream>
#include <list> #include <list>
@ -30,13 +32,17 @@ namespace mock
{ {
template< typename Signature, template< typename Signature,
typename ErrorPolicy = MOCK_ERROR_POLICY< typename ErrorPolicy = MOCK_ERROR_POLICY<
BOOST_DEDUCED_TYPENAME boost::function< BOOST_DEDUCED_TYPENAME
Signature >::result_type > > boost::function_types::result_type< Signature >::type > >
class expectation class expectation
{ {
public: public:
typedef BOOST_DEDUCED_TYPENAME 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 > template< typename Args >
struct sig struct sig
@ -45,10 +51,7 @@ namespace mock
}; };
private: private:
typedef detail::matcher< result_type, typedef detail::matcher< result_type, Signature, arity::value > matcher_type;
Signature,
boost::function< Signature >::arity >
matcher_type;
public: public:
struct expectation_tag struct expectation_tag

View file

@ -26,6 +26,7 @@
#include <boost/mpl/vector.hpp> #include <boost/mpl/vector.hpp>
#include <boost/mpl/erase.hpp> #include <boost/mpl/erase.hpp>
#include <boost/mpl/copy.hpp> #include <boost/mpl/copy.hpp>
#include <boost/mpl/equal_to.hpp>
#include <boost/mpl/back_inserter.hpp> #include <boost/mpl/back_inserter.hpp>
#define BOOST_TYPEOF_SILENT #define BOOST_TYPEOF_SILENT
#include <boost/typeof/typeof.hpp> #include <boost/typeof/typeof.hpp>
@ -146,6 +147,79 @@ namespace detail
{ {
typedef T base_type; 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, \ mock::detail::configure( mock::detail::ref( o ).exp##t, \
"?", ".", BOOST_PP_STRINGIZE(t), mock::detail::ref( o ) ) "?", ".", 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) \ #define MOCK_METHOD_EXPECTATION(S, t) \
mutable mock::expectation< S > exp##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) \ #define MOCK_SIGNATURE(M) \
mock::detail::signature< BOOST_TYPEOF(&base_type::M) >::type mock::detail::signature< BOOST_TYPEOF(&base_type::M) >::type
#define MOCK_SIGNATURE_TPL(M) \ #define MOCK_SIGNATURE_TPL(M) \
BOOST_DEDUCED_TYPENAME mock::detail::signature< BOOST_TYPEOF_TPL(&base_type::M) >::type 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) \ #define MOCK_METHOD_EXT(M, n, S, t) \
MOCK_METHOD_STUB(M, n, S, t,,) \ MOCK_METHOD_STUB(M, n, S, t,,) \
MOCK_METHOD_STUB(M, n, S, t, const,) \ MOCK_METHOD_STUB(M, n, S, t, const,) \
@ -213,7 +295,7 @@ namespace detail
#define MOCK_METHOD_TPL(M, n) \ #define MOCK_METHOD_TPL(M, n) \
MOCK_METHOD_EXT_TPL(M, n, MOCK_SIGNATURE_TPL(M), M) MOCK_METHOD_EXT_TPL(M, n, MOCK_SIGNATURE_TPL(M), M)
#define MOCK_DESTRUCTOR( T, t ) \ #define MOCK_DESTRUCTOR(T, t) \
~T() { exp##t(); } \ ~T() { exp##t(); } \
MOCK_METHOD_EXPECTATION(void(), t) MOCK_METHOD_EXPECTATION(void(), t)
@ -221,4 +303,23 @@ namespace detail
#define MOCK_RESET(o,t) MOCK_MOCKER(o,t).reset() #define MOCK_RESET(o,t) MOCK_MOCKER(o,t).reset()
#define MOCK_VERIFY(o,t) MOCK_MOCKER(o,t).verify() #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 #endif // #ifndef MOCK_MOCK_HPP_INCLUDED

View file

@ -217,3 +217,87 @@ BOOST_AUTO_TEST_CASE( mocking_a_destructor )
my_destroyed_class c; my_destroyed_class c;
MOCK_EXPECT( c, destructor ).once(); 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, "" );
}