diff --git a/build/vc80/turtle.vcproj b/build/vc80/turtle.vcproj index 11b973e..9276e53 100644 --- a/build/vc80/turtle.vcproj +++ b/build/vc80/turtle.vcproj @@ -220,6 +220,10 @@ RelativePath="..\..\src\libraries\turtle\sequence.hpp" > + + diff --git a/build/vc80/turtle_test.vcproj b/build/vc80/turtle_test.vcproj index 574846f..6816e39 100644 --- a/build/vc80/turtle_test.vcproj +++ b/build/vc80/turtle_test.vcproj @@ -204,6 +204,10 @@ RelativePath="..\..\src\tests\turtle_test\format_test.cpp" > + + @@ -220,18 +224,6 @@ RelativePath="..\..\src\tests\turtle_test\object_test.cpp" > - - - - - diff --git a/src/libraries/turtle/error.hpp b/src/libraries/turtle/error.hpp index 374b51d..37bcbf6 100644 --- a/src/libraries/turtle/error.hpp +++ b/src/libraries/turtle/error.hpp @@ -9,8 +9,6 @@ #ifndef MOCK_ERROR_HPP_INCLUDED #define MOCK_ERROR_HPP_INCLUDED -#include -#include #include #include #include @@ -22,13 +20,8 @@ namespace detail { class errors_t : public boost::unit_test::singleton< errors_t > { - public: - long count_; private: friend class boost::unit_test::singleton< errors_t >; - errors_t() - : count_( 0 ) - {} }; BOOST_TEST_SINGLETON_INST( errors ) } @@ -46,7 +39,6 @@ namespace detail { static void missing_result_specification() { - ++detail::errors.count_; static std::string m; m = "mock error : missing result specification"; throw boost::enable_current_exception( mock::exception( m ) ); @@ -54,7 +46,6 @@ namespace detail static Result no_match( const std::string& context ) { - ++detail::errors.count_; static std::string m; m = "mock error : unexpected call : " + context; throw boost::enable_current_exception( mock::exception( m ) ); @@ -63,7 +54,6 @@ namespace detail static void sequence_failed( const std::string& context, const std::string& /*file*/, int /*line*/ ) { - ++detail::errors.count_; static std::string m; m = "mock error : sequence failed : " + context; throw boost::enable_current_exception( mock::exception( m ) ); @@ -78,8 +68,7 @@ namespace detail static void untriggered_expectation( const std::string& context, const std::string& file, int line ) { - if( detail::errors.count_ == 0 ) - notify( "untriggered expectation : " + context, file, line ); + notify( "untriggered expectation : " + context, file, line ); } static void notify( const std::string& message, diff --git a/src/libraries/turtle/expectation.hpp b/src/libraries/turtle/expectation.hpp index c3937a5..837cdae 100644 --- a/src/libraries/turtle/expectation.hpp +++ b/src/libraries/turtle/expectation.hpp @@ -46,25 +46,24 @@ namespace mock matcher_type; public: - expectation( node& parent = root, const std::string& name = "?" ) - : impl_( new expectation_impl( parent, name ) ) - {} - expectation( const std::string& name ) + struct expectation_tag + {}; + expectation_tag operator_exp; + + expectation( const std::string& name = "?" ) : impl_( new expectation_impl( root, name ) ) {} - expectation& set_name( const std::string& name ) + void set_name( const std::string& name ) { impl_->set_name( name ); - return *this; } - expectation& set_parent( node& parent ) + void set_parent( node& parent ) { impl_->set_parent( parent ); - return *this; } - bool verify() + bool verify() const { return impl_->verify(); } @@ -134,7 +133,7 @@ namespace mock parent_ = &parent; } - virtual bool verify() + virtual bool verify() const { for( matchers_cit it = matchers_.begin(); it != matchers_.end(); ++it ) @@ -231,14 +230,14 @@ namespace mock std::string context() const { std::stringstream s; - s << *parent_ << name_; + s << name_; serialize( s ); return s.str(); } std::string context( const std::string& parameters ) const { std::stringstream s; - s << *parent_ << name_; + s << name_; if( parameters.empty() ) s << "()"; else diff --git a/src/libraries/turtle/mock.hpp b/src/libraries/turtle/mock.hpp index e2b474c..1fc9091 100644 --- a/src/libraries/turtle/mock.hpp +++ b/src/libraries/turtle/mock.hpp @@ -12,6 +12,7 @@ #include "error.hpp" #include "object.hpp" #include "expectation.hpp" +#include "type_name.hpp" #include #include #include @@ -60,36 +61,7 @@ namespace detail throw std::invalid_argument( "derefencing null pointer" ); return *t; } -} -} -#define MOCK_MIXIN(T) \ - template< typename U > struct T##_mock_mixin : U \ - { \ - explicit T##_mock_mixin( const std::string& tag = "" ) \ - { \ - mock::object::set_name( BOOST_PP_STRINGIZE(T) + tag ); \ - } \ - explicit T##_mock_mixin( mock::node& parent, const std::string& tag = "" ) \ - { \ - mock::object::set_name( BOOST_PP_STRINGIZE(T) + tag ); \ - mock::node::set_parent( parent ); \ - } \ - }; \ - struct T##_super_class; \ - typedef T##_mock_mixin< T##_super_class > T; -#define MOCK_BASE_CLASS(T, I) \ - MOCK_MIXIN(T) \ - struct T##_typedef { typedef I interface_type; }; \ - struct T##_super_class : I, mock::object, private T##_typedef -#define MOCK_CLASS(T) \ - MOCK_MIXIN(T) \ - struct T##_super_class : mock::object - -namespace mock -{ -namespace detail -{ template< typename M > struct signature { @@ -112,45 +84,116 @@ namespace detail >::type >::type type; }; + + template< typename E > + void set_parent( E& e, const object& o ) + { + o.set_parent( e ); + } + template< typename E, typename T > + void set_parent( E&, const T&, + BOOST_DEDUCED_TYPENAME boost::disable_if< + BOOST_DEDUCED_TYPENAME boost::is_base_of< object, T >::type + >::type* = 0 ) + {} + template< typename E > + void tag( E& e, const object& o, const std::string& type_name, const std::string& name ) + { + e.set_name( type_name + o.tag() + "::" + name ); + } + template< typename E, typename T > + void tag( E& e, const T&, const std::string& type_name, const std::string& name, + BOOST_DEDUCED_TYPENAME boost::disable_if< + BOOST_DEDUCED_TYPENAME boost::is_base_of< object, T >::type + >::type* = 0 ) + { + e.set_name( type_name + "::" + name ); + } + + template< typename E > + E& configure( typename E::expectation_tag, const std::string& name, E& e ) + { + e.set_name( name ); + return e; + } + template< typename E, typename T > + E& configure( E& e, const std::string& name, const T& t ) + { + set_parent( e, t ); + tag( e, t, type_name< T >(), name ); + return e; + } + + template< typename T > + struct base + { + typedef T base_type; + }; } } -#define MOCK_METHOD_ARG(z, n, S) BOOST_PP_COMMA_IF(n) \ - BOOST_PP_CAT(BOOST_PP_CAT(boost::function< S >::arg, BOOST_PP_INC(n)),_type) \ +#define MOCK_BASE_CLASS(T, I) \ + struct T : I, mock::object, mock::detail::base< I > +#define MOCK_CLASS(T) \ + struct T : mock::object +#define MOCK_FUNCTOR(S) \ + mock::expectation< S > + +#define MOCK_MOCKER(o, t) \ + mock::detail::configure( mock::detail::ref( o ).t##_exp, \ + 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, S) \ - BOOST_PP_REPEAT_FROM_TO(0, n, MOCK_METHOD_ARG, S) +#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, M) \ +#define MOCK_MOCKER_ARGS(n) \ BOOST_PP_REPEAT_FROM_TO(0, n, MOCK_MOCKER_ARG, BOOST_PP_EMPTY) -#define MOCK_METHOD_STUB(M, n, S, t, c) \ - boost::function< S >::result_type M( MOCK_METHOD_ARGS(n, S) ) c \ - { \ - return MOCK_MOCKER(*this, t)( MOCK_MOCKER_ARGS(n, M) ); \ - } #define MOCK_METHOD_EXPECTATION(S, t) \ mutable mock::expectation< S > t##_exp; + +#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_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_EXT(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,,) \ + MOCK_METHOD_STUB(M, n, S, t, const,) \ MOCK_METHOD_EXPECTATION(S, t) #define MOCK_CONST_METHOD_EXT(M, n, S, t) \ - MOCK_METHOD_STUB(M, n, S, t, const) \ + MOCK_METHOD_STUB(M, n, S, t, const,) \ MOCK_METHOD_EXPECTATION(S, t) #define MOCK_NON_CONST_METHOD_EXT(M, n, S, t) \ - MOCK_METHOD_STUB(M, n, S, t,) \ + MOCK_METHOD_STUB(M, n, S, t,,) \ MOCK_METHOD_EXPECTATION(S, t) #define MOCK_METHOD(M, n) \ - MOCK_METHOD_EXT(M, n, MOCK_SIGNATURE(&interface_type::M), M) -#define MOCK_SIGNATURE(pM) \ - mock::detail::signature< BOOST_TYPEOF(pM) >::type -#define MOCK_MOCKER(m, t) \ - mock::detail::ref( m ).t##_exp.set_name( BOOST_PP_STRINGIZE(t) ).set_parent( \ - const_cast< mock::object& >( dynamic_cast< const mock::object& >( mock::detail::ref( m ) ) ) ) + MOCK_METHOD_EXT(M, n, MOCK_SIGNATURE(M), M) -#define MOCK_EXPECT(m,t) MOCK_MOCKER(m,t).expect( __FILE__, __LINE__ ) -#define MOCK_RESET(m,t) MOCK_MOCKER(m,t).reset() -#define MOCK_VERIFY(m,t) MOCK_MOCKER(m,t).verify() +#define MOCK_METHOD_EXT_TPL(M, n, S, t) \ + MOCK_METHOD_STUB(M, n, S, t,,BOOST_DEDUCED_TYPENAME) \ + MOCK_METHOD_STUB(M, n, S, t, const,BOOST_DEDUCED_TYPENAME) \ + MOCK_METHOD_EXPECTATION(S, t) +#define MOCK_CONST_METHOD_EXT_TPL(M, n, S, t) \ + MOCK_METHOD_STUB(M, n, S, t, const,BOOST_DEDUCED_TYPENAME) \ + MOCK_METHOD_EXPECTATION(S, t) +#define MOCK_NON_CONST_METHOD_EXT_TPL(M, n, S, t) \ + MOCK_METHOD_STUB(M, n, S, t,,BOOST_DEDUCED_TYPENAME) \ + MOCK_METHOD_EXPECTATION(S, t) +#define MOCK_METHOD_TPL(M, n) \ + MOCK_METHOD_EXT_TPL(M, n, MOCK_SIGNATURE_TPL(M), M) + +#define MOCK_EXPECT(o,t) MOCK_MOCKER(o,t).expect( __FILE__, __LINE__ ) +#define MOCK_RESET(o,t) MOCK_MOCKER(o,t).reset() +#define MOCK_VERIFY(o,t) MOCK_MOCKER(o,t).verify() #endif // #ifndef MOCK_MOCK_HPP_INCLUDED diff --git a/src/libraries/turtle/node.hpp b/src/libraries/turtle/node.hpp index 859e613..1d88477 100644 --- a/src/libraries/turtle/node.hpp +++ b/src/libraries/turtle/node.hpp @@ -10,41 +10,18 @@ #define MOCK_NODE_HPP_INCLUDED #include "verifiable.hpp" -#include -#include +#include #include -#include +#include #include +#include +#include namespace mock { - class node : private verifiable + class node : private boost::noncopyable { public: - node() - : parent_( 0 ) - {} - explicit node( node& parent ) - : verifiable() - , parent_( &parent ) - { - if( parent_ ) - parent_->add( *this ); - } - virtual ~node() - { - if( parent_ ) - parent_->remove( *this ); - } - - void set_parent( node& parent ) - { - if( parent_ ) - parent_->remove( *this ); - parent_ = &parent; - parent_->add( *this ); - } - void add( verifiable& e ) { v_.push_back( &e ); @@ -54,7 +31,7 @@ namespace mock v_.erase( std::remove( v_.begin(), v_.end(), &e ), v_.end() ); } - virtual bool verify() + bool verify() const { bool valid = true; for( verifiables_cit it = v_.begin(); it != v_.end(); ++it ) @@ -62,7 +39,7 @@ namespace mock valid = false; return valid; } - virtual void reset() + void reset() { std::for_each( v_.begin(), v_.end(), std::mem_fun( &verifiable::reset ) ); @@ -70,20 +47,20 @@ namespace mock friend std::ostream& operator<<( std::ostream& s, const node& n ) { - if( n.parent_ ) - s << *n.parent_; n.serialize( s ); return s; } protected: + virtual ~node() + {} + virtual void serialize( std::ostream& s ) const = 0; private: typedef std::vector< verifiable* > verifiables_type; typedef verifiables_type::const_iterator verifiables_cit; - node* parent_; std::vector< verifiable* > v_; }; } diff --git a/src/libraries/turtle/object.hpp b/src/libraries/turtle/object.hpp index e180c41..79e4858 100644 --- a/src/libraries/turtle/object.hpp +++ b/src/libraries/turtle/object.hpp @@ -11,36 +11,61 @@ #include "node.hpp" #include "root.hpp" -#include +#include #include +#include namespace mock { - class object : public node + class object { public: - explicit object( node& parent = root, const std::string& name = "" ) - : node( parent ) - , name_( name ) - {} - explicit object( const std::string& name ) - : node( root ) - , name_( name ) + explicit object( const std::string& name = "" ) + : impl_( new object_impl( name ) ) {} - void set_name( const std::string& name ) + void tag( const std::string& name ) { - name_ = name; + impl_->name_ = name; + } + const std::string& tag() const + { + return impl_->name_; + } + + template< typename T > + void set_parent( T& t ) const + { + t.set_parent( *impl_ ); + } + + bool verify() const + { + return impl_->verify(); + } + void reset() + { + impl_->reset(); } private: - virtual void serialize( std::ostream& s ) const + class object_impl : public node { - s << (name_.empty() ? "?" : name_) << "::"; - } + public: + explicit object_impl( const std::string& name ) + : name_( name ) + {} - private: - std::string name_; + std::string name_; + + private: + virtual void serialize( std::ostream& s ) const + { + s << (name_.empty() ? "?" : name_) << "::"; + } + }; + + boost::shared_ptr< object_impl > impl_; }; } diff --git a/src/libraries/turtle/type_name.hpp b/src/libraries/turtle/type_name.hpp new file mode 100644 index 0000000..856afdb --- /dev/null +++ b/src/libraries/turtle/type_name.hpp @@ -0,0 +1,71 @@ +// +// Copyright Mathieu Champlon 2009 +// +// 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_TYPE_NAME_HPP_INCLUDED +#define MOCK_TYPE_NAME_HPP_INCLUDED + +#include +#include +#ifdef __GNUC__ +#include +#include +#endif + +namespace mock +{ +namespace detail +{ + struct guard + { + explicit guard( char* p ) + : p_( p ) + {} + ~guard() + { + free( p_ ); + } + private: + char* p_; + }; + + inline std::string type_full_name( const std::type_info& info ) + { + const char* name = info.name(); +#ifdef __GNUC__ + size_t size = 0; + int status = 0; + char* result = abi::__cxa_demangle( name, NULL, &size, &status ); + guard g( result ); + if( result ) + return result; + else + return name; +#else + return name; +#endif + } + + template< typename T > + std::string type_full_name() + { + return type_full_name( typeid( T ) ); + } + + template< typename T > + std::string type_name() + { + const std::string name = type_full_name< T >(); + std::size_t p = name.rfind( "::" ); + if( p != std::string::npos ) + return name.substr( p + 2 ); + return ""; + } +} +} + +#endif // #ifndef MOCK_TYPE_NAME_HPP_INCLUDED diff --git a/src/libraries/turtle/verifiable.hpp b/src/libraries/turtle/verifiable.hpp index 48da575..7069b5d 100644 --- a/src/libraries/turtle/verifiable.hpp +++ b/src/libraries/turtle/verifiable.hpp @@ -20,7 +20,7 @@ namespace mock virtual ~verifiable() {} // return false if verification fails - virtual bool verify() = 0; + virtual bool verify() const = 0; // return to the initial state virtual void reset() = 0; diff --git a/src/tests/turtle_test/constraint_test.cpp b/src/tests/turtle_test/constraint_test.cpp index d4fe4f1..e9a64af 100644 --- a/src/tests/turtle_test/constraint_test.cpp +++ b/src/tests/turtle_test/constraint_test.cpp @@ -14,9 +14,6 @@ BOOST_AUTO_TEST_CASE( all_comparison_constraints_can_be_instanciated ) { - mock::any; - mock::negate; - mock::evaluate; mock::equal( 0 ); mock::less( 0 ); mock::greater( 0 ); diff --git a/src/tests/turtle_test/expectation_test.cpp b/src/tests/turtle_test/expectation_test.cpp index f3c1dcb..f019ea4 100644 --- a/src/tests/turtle_test/expectation_test.cpp +++ b/src/tests/turtle_test/expectation_test.cpp @@ -580,6 +580,17 @@ BOOST_AUTO_TEST_CASE( best_matcher_is_selected_first ) // error report +namespace +{ + template< typename T > + std::string to_string( const T& t ) + { + std::stringstream s; + s << t; + return s.str(); + } +} + BOOST_AUTO_TEST_CASE( expectation_can_be_serialized_to_be_human_readable ) { { @@ -587,22 +598,18 @@ BOOST_AUTO_TEST_CASE( expectation_can_be_serialized_to_be_human_readable ) e.expect().once().with( 1 ); e.expect().once().with( 2 ); BOOST_CHECK_NO_THROW( e( 2 ) ); - std::stringstream s; - s << e; const std::string expected = "my expectation\n" ". expect( once() ).with( 1 )\n" "v expect( once() ).with( 2 )"; - BOOST_CHECK_EQUAL( expected, s.str() ); + BOOST_CHECK_EQUAL( expected, to_string( e ) ); e.reset(); } { mock::expectation< void( int ) > e( "my expectation" ); e.expect().never().with( 1 ); - std::stringstream s; - s << e; const std::string expected = "my expectation\n" "v expect( never() ).with( 1 )"; - BOOST_CHECK_EQUAL( expected, s.str() ); + BOOST_CHECK_EQUAL( expected, to_string( e ) ); e.reset(); } { @@ -611,82 +618,66 @@ BOOST_AUTO_TEST_CASE( expectation_can_be_serialized_to_be_human_readable ) e.expect().exactly( 2 ).with( "second" ); BOOST_CHECK_NO_THROW( e( "second" ) ); { - std::stringstream s; - s << e; const std::string expected = "?\n" "v expect( never() ).with( less( \"first\" ) )\n" ". expect( exactly( 1/2 ) ).with( \"second\" )"; - BOOST_CHECK_EQUAL( expected, s.str() ); + BOOST_CHECK_EQUAL( expected, to_string( e ) ); } BOOST_CHECK_NO_THROW( e( "second" ) ); { - std::stringstream s; - s << e; const std::string expected = "?\n" "v expect( never() ).with( less( \"first\" ) )\n" "v expect( exactly( 2/2 ) ).with( \"second\" )"; - BOOST_CHECK_EQUAL( expected, s.str() ); + BOOST_CHECK_EQUAL( expected, to_string( e ) ); } e.reset(); } { mock::expectation< void( int ) > e( "my expectation" ); e.expect().once(); - std::stringstream s; - s << e; const std::string expected = "my expectation\n" ". expect( once() ).with( any )"; - BOOST_CHECK_EQUAL( expected, s.str() ); + BOOST_CHECK_EQUAL( expected, to_string( e ) ); e.reset(); } { mock::expectation< void( int ) > e( "my expectation" ); e.expect().once().with( mock::any ); - std::stringstream s; - s << e; const std::string expected = "my expectation\n" ". expect( once() ).with( any )"; - BOOST_CHECK_EQUAL( expected, s.str() ); + BOOST_CHECK_EQUAL( expected, to_string( e ) ); e.reset(); } { mock::expectation< void( int ) > e( "my expectation" ); e.expect().once(); - std::stringstream s; - s << e; const std::string expected = "my expectation\n" ". expect( once() ).with( any )"; - BOOST_CHECK_EQUAL( expected, s.str() ); + BOOST_CHECK_EQUAL( expected, to_string( e ) ); e.reset(); } { mock::expectation< void( int ) > e( "my expectation" ); e.expect().once().with( &custom_constraint ); - std::stringstream s; - s << e; const std::string expected = "my expectation\n" ". expect( once() ).with( ? )"; - BOOST_CHECK_EQUAL( expected, s.str() ); + BOOST_CHECK_EQUAL( expected, to_string( e ) ); e.reset(); } { mock::expectation< void( int ) > e( "my expectation" ); e.expect().once().with( mock::constraint( &custom_constraint, "custom constraint" ) ); - std::stringstream s; - s << e; const std::string expected = "my expectation\n" ". expect( once() ).with( custom constraint )"; - BOOST_CHECK_EQUAL( expected, s.str() ); + BOOST_CHECK_EQUAL( expected, to_string( e ) ); e.reset(); } { mock::expectation< void( int ) > e( "my expectation" ); e.expect().once().with( mock::constraint( &custom_constraint, true ) ); - std::stringstream s; - s << e; const std::string expected = "my expectation\n" ". expect( once() ).with( true )"; - BOOST_CHECK_EQUAL( expected, s.str() ); + BOOST_CHECK_EQUAL( expected, to_string( e ) ); e.reset(); } } diff --git a/src/tests/turtle_test/samples_test.cpp b/src/tests/turtle_test/integration_test.cpp similarity index 59% rename from src/tests/turtle_test/samples_test.cpp rename to src/tests/turtle_test/integration_test.cpp index fb2eb72..ec69e5d 100644 --- a/src/tests/turtle_test/samples_test.cpp +++ b/src/tests/turtle_test/integration_test.cpp @@ -19,6 +19,21 @@ # pragma warning( disable : 4355 4505 ) #endif +namespace +{ + struct my_custom_mock + { + MOCK_METHOD_EXT( my_method, 0, void(), my_method ) + }; +} + +BOOST_AUTO_TEST_CASE( custom_mock_object_without_macros_and_without_inheriting_from_object ) +{ + my_custom_mock m; + MOCK_EXPECT( m, my_method ).once(); + m.my_method(); +} + namespace { struct my_custom_mock_object : mock::object @@ -32,9 +47,9 @@ namespace BOOST_AUTO_TEST_CASE( custom_mock_object_without_macros ) { - my_custom_mock_object mock; - MOCK_EXPECT( mock, my_method ); - mock.my_method(); + my_custom_mock_object m; + MOCK_EXPECT( m, my_method ).once(); + m.my_method(); } namespace @@ -51,7 +66,7 @@ BOOST_AUTO_TEST_CASE( basic_mock_object_usage ) MOCK_EXPECT( m, my_method ).once().returns( 0 ); BOOST_CHECK_EQUAL( 0, m.my_method( 13 ) ); mock::verify(); - mock::reset(); // $$$$ MAT : shouldn't reset implicitly call verify ? + mock::reset(); MOCK_EXPECT( m, my_method ).once().with( 42 ).returns( 7 ); BOOST_CHECK_EQUAL( 7, m.my_method( 42 ) ); mock::verify(); @@ -60,73 +75,6 @@ BOOST_AUTO_TEST_CASE( basic_mock_object_usage ) BOOST_CHECK_EQUAL( 51, m.my_method( 27 ) ); } -namespace -{ - class my_observer : boost::noncopyable - { - public: - virtual ~my_observer() {} - - virtual void notify( int value ) = 0; - }; - - class my_manager : boost::noncopyable - { - public: - virtual ~my_manager() {} - - virtual my_observer& get_observer() const = 0; - }; - - class my_subject : boost::noncopyable - { - public: - explicit my_subject( my_manager& f ) - : o_( f.get_observer() ) - , value_( 0 ) - {} - void increment() - { - o_.notify( ++value_ ); - } - private: - my_observer& o_; - int value_; - }; - - MOCK_BASE_CLASS( my_mock_observer, my_observer ) - { - MOCK_METHOD( notify, 1 ) - }; - - MOCK_BASE_CLASS( my_mock_manager, my_manager ) - { - MOCK_METHOD( get_observer, 0 ) - }; - - class fixture - { - public: - fixture() - : manager( "(the only one)" ) - {} - my_mock_manager manager; - my_mock_observer observer; - }; -} - -BOOST_FIXTURE_TEST_CASE( basic_mock_object_collaboration_usage, fixture ) -{ - MOCK_EXPECT( manager, get_observer ).returns( boost::ref( observer ) ); - my_subject subject( manager ); - MOCK_EXPECT( observer, notify ).once().with( 1 ); - subject.increment(); - MOCK_EXPECT( observer, notify ).once().with( 2 ); - subject.increment(); - MOCK_EXPECT( observer, notify ).once().with( 3 ); - subject.increment(); -} - namespace { class my_ambiguited_interface : boost::noncopyable @@ -179,3 +127,148 @@ BOOST_AUTO_TEST_CASE( mock_object_method_const_disambiguation ) const my_const_ambiguited_mock const_mock; BOOST_CHECK_THROW( const_mock.my_method(), mock::exception ); } + +BOOST_AUTO_TEST_CASE( mock_functor_in_function_is_supported ) +{ + boost::function< int( float, const std::string& ) > func; + { + MOCK_FUNCTOR( int( float, const std::string& ) ) f; + MOCK_EXPECT(f, operator).once().with( 3, "op" ).returns( 42 ); + func = f; + } + BOOST_CHECK_EQUAL( 42, func( 3, "op" ) ); +} + +BOOST_AUTO_TEST_CASE( mock_functor_name_can_be_customised ) +{ + MOCK_FUNCTOR( int( float, const std::string& ) ) f( "my functor" ); +} + +namespace +{ + struct functor_fixture + { + MOCK_FUNCTOR( int( float, const std::string& ) ) f; + }; +} + +BOOST_FIXTURE_TEST_CASE( mock_functor_in_fixture_is_supported, functor_fixture ) +{ + MOCK_EXPECT(f, operator).once().with( 3, "op" ).returns( 42 ); + BOOST_CHECK_EQUAL( 42, f( 3.f, "op" ) ); +} + +namespace +{ + template< typename T > + struct my_template_mock + { + MOCK_METHOD_EXT( my_method, 0, void(), my_method ) + MOCK_METHOD_EXT_TPL( my_method, 2, void( T, std::string ), my_method_t ) + MOCK_METHOD_EXT_TPL( my_other_method, 0, void(), my_other_method ) + }; +} + +BOOST_AUTO_TEST_CASE( mocking_a_template_class_method_is_supported ) +{ + my_template_mock< int > m; + MOCK_EXPECT( m, my_method_t ).with( 3, "" ); + m.my_method( 3, "" ); +} + +namespace +{ + template< typename T > + struct my_template_base_class + { + virtual ~my_template_base_class() + {} + virtual void my_method( T ) = 0; + virtual void my_other_method() = 0; + }; + template< typename T > + MOCK_BASE_CLASS( my_template_base_class_mock, my_template_base_class< T > ) + { +#if (defined __CYGWIN__) && (__GNUC__ == 3) + MOCK_METHOD_EXT_TPL( my_method, 1, void( T ), my_method ) + MOCK_METHOD_EXT_TPL( my_other_method, 0, void(), my_other_method ) +#else + MOCK_METHOD_TPL( my_method, 1 ) + MOCK_METHOD_TPL( my_other_method, 0 ) +#endif + }; +} + +BOOST_AUTO_TEST_CASE( mocking_a_template_base_class_method_is_supported ) +{ + my_template_base_class_mock< int > m; + MOCK_EXPECT( m, my_method ).once().with( 3 ); + m.my_method( 3 ); +} + +namespace +{ + class my_observer : boost::noncopyable + { + public: + virtual ~my_observer() {} + + virtual void notify( int value ) = 0; + }; + + class my_manager : boost::noncopyable + { + public: + virtual ~my_manager() {} + + virtual my_observer& get_observer() const = 0; + }; + + class my_subject : boost::noncopyable + { + public: + explicit my_subject( my_manager& f ) + : o_( f.get_observer() ) + , value_( 0 ) + {} + void increment() + { + o_.notify( ++value_ ); + } + private: + my_observer& o_; + int value_; + }; + + MOCK_BASE_CLASS( my_mock_observer, my_observer ) + { + MOCK_METHOD( notify, 1 ) + }; + + MOCK_BASE_CLASS( my_mock_manager, my_manager ) + { + MOCK_METHOD( get_observer, 0 ) + }; + + struct fixture + { + fixture() + { + manager.tag( "(the only one)" ); + } + my_mock_manager manager; + my_mock_observer observer; + }; +} + +BOOST_FIXTURE_TEST_CASE( basic_mock_object_collaboration_usage, fixture ) +{ + MOCK_EXPECT( manager, get_observer ).returns( boost::ref( observer ) ); + my_subject subject( manager ); + MOCK_EXPECT( observer, notify ).once().with( 1 ); + subject.increment(); + MOCK_EXPECT( observer, notify ).once().with( 2 ); + subject.increment(); + MOCK_EXPECT( observer, notify ).once().with( 3 ); + subject.increment(); +} diff --git a/src/tests/turtle_test/mock_test.cpp b/src/tests/turtle_test/mock_test.cpp index dbb2f88..48fc094 100644 --- a/src/tests/turtle_test/mock_test.cpp +++ b/src/tests/turtle_test/mock_test.cpp @@ -141,3 +141,55 @@ BOOST_AUTO_TEST_CASE( MOCK_EXPECT_macro ) MOCK_EXPECT( m, my_method ).once().with( 42 ); m.my_method( 42 ); } + +namespace +{ + template< typename T > + std::string to_string( const T& t ) + { + std::stringstream s; + s << t; + return s.str(); + } +} + +BOOST_AUTO_TEST_CASE( mock_object_is_named ) +{ + my_mock m; + BOOST_CHECK_EQUAL( "my_mock::my_method", to_string( MOCK_MOCKER( m, my_method ) ) ); +} + +BOOST_AUTO_TEST_CASE( mock_object_with_tag_is_named ) +{ + my_mock m; + m.tag( "(my tag)" ); + BOOST_CHECK_EQUAL( "my_mock(my tag)::my_method", to_string( MOCK_MOCKER( m, my_method ) ) ); +} + +namespace +{ + struct my_custom_mock + { + MOCK_METHOD_EXT( my_method, 0, void(), my_method ) + }; +} + +BOOST_AUTO_TEST_CASE( custom_mock_object_without_macros_and_without_inheriting_from_object_is_named ) +{ + my_custom_mock m; + BOOST_CHECK_EQUAL( "my_custom_mock::my_method", to_string( MOCK_MOCKER( m, my_method ) ) ); +} + +namespace +{ + struct my_custom_mock_object : mock::object + { + MOCK_METHOD_EXT( my_method, 0, void(), my_method ) + }; +} + +BOOST_AUTO_TEST_CASE( custom_mock_object_without_macros_is_named ) +{ + my_custom_mock_object m; + BOOST_CHECK_EQUAL( "my_custom_mock_object::my_method", to_string( MOCK_MOCKER( m, my_method ) ) ); +} diff --git a/src/tests/turtle_test/object_test.cpp b/src/tests/turtle_test/object_test.cpp index 3005a9d..291836d 100644 --- a/src/tests/turtle_test/object_test.cpp +++ b/src/tests/turtle_test/object_test.cpp @@ -35,7 +35,8 @@ namespace BOOST_AUTO_TEST_CASE( verifying_an_object_containing_a_failing_expectation_fails ) { mock::object o; - mock::expectation< void(), silent_error > e( o ); + mock::expectation< void(), silent_error > e; + o.set_parent( e ); e.expect().once(); BOOST_CHECK( ! o.verify() ); } @@ -43,30 +44,37 @@ BOOST_AUTO_TEST_CASE( verifying_an_object_containing_a_failing_expectation_fails BOOST_AUTO_TEST_CASE( resetting_an_object_containing_a_failing_expectation_and_verifying_it_succeeds ) { mock::object o; - mock::expectation< void() > e( o ); + mock::expectation< void() > e; + o.set_parent( e ); e.expect().once(); o.reset(); BOOST_CHECK( o.verify() ); - BOOST_CHECK( e.verify() ); } -BOOST_AUTO_TEST_CASE( verifying_an_object_containing_another_object_with_a_failing_expectation_fails ) +BOOST_AUTO_TEST_CASE( an_object_is_assignable_by_sharing_its_state ) { mock::object o1; - mock::object o2( o1 ); - mock::expectation< void(), silent_error > e( o2 ); - e.expect().once(); + mock::expectation< void(), silent_error > e; + { + mock::object o2; + o2.set_parent( e ); + e.expect().once(); + o1 = o2; + BOOST_CHECK( ! o2.verify() ); + BOOST_CHECK( ! o1.verify() ); + } BOOST_CHECK( ! o1.verify() ); } -BOOST_AUTO_TEST_CASE( resetting_an_object_containing_another_object_with_a_failing_expectation_and_verifying_it_succeeds ) +BOOST_AUTO_TEST_CASE( an_object_is_copiable_by_sharing_its_state ) { - mock::object o1; - mock::object o2( o1 ); - mock::expectation< void() > e( o2 ); + std::auto_ptr< mock::object > o2( new mock::object ); + const mock::object o1( *o2 ); + mock::expectation< void(), silent_error > e; + o2->set_parent( e ); e.expect().once(); - o1.reset(); - BOOST_CHECK( o1.verify() ); - BOOST_CHECK( o2.verify() ); - BOOST_CHECK( e.verify() ); + BOOST_CHECK( ! o2->verify() ); + BOOST_CHECK( ! o1.verify() ); + o2.reset(); + BOOST_CHECK( ! o1.verify() ); }