From a7c62e523a5af5e90c50bfa1f7f4b0c44535d43e Mon Sep 17 00:00:00 2001 From: mat007 Date: Sat, 9 Jul 2011 15:16:03 +0000 Subject: [PATCH] Merged refactoring branch git-svn-id: https://svn.code.sf.net/p/turtle/code/trunk@379 860be788-9bd5-4423-9f1e-828f051e677b --- build/vc80/turtle.vcproj | 24 ++++- build/vc80/turtle_test.vcproj | 4 +- src/libraries/turtle/boost_test_error.hpp | 11 --- src/libraries/turtle/child.hpp | 47 +++++++++ src/libraries/turtle/cleanup.hpp | 37 +++++++ src/libraries/turtle/config.hpp | 4 + src/libraries/turtle/context.hpp | 38 ++++++++ src/libraries/turtle/error.hpp | 2 +- src/libraries/turtle/function.hpp | 110 +++++++++------------ src/libraries/turtle/group.hpp | 60 ++++++++++++ src/libraries/turtle/mock.hpp | 74 +++++--------- src/libraries/turtle/node.hpp | 17 +--- src/libraries/turtle/object.hpp | 113 +++++++++++++++------- src/libraries/turtle/parent.hpp | 42 ++++++++ src/libraries/turtle/root.hpp | 109 ++++++++++++++++++++- src/libraries/turtle/verifiable.hpp | 2 - src/tests/turtle_test/function_test.cpp | 18 ++-- src/tests/turtle_test/mock_test.cpp | 43 ++++---- src/tests/turtle_test/object_test.cpp | 66 ++++++------- 19 files changed, 558 insertions(+), 263 deletions(-) create mode 100644 src/libraries/turtle/child.hpp create mode 100644 src/libraries/turtle/cleanup.hpp create mode 100644 src/libraries/turtle/context.hpp create mode 100644 src/libraries/turtle/group.hpp create mode 100644 src/libraries/turtle/parent.hpp diff --git a/build/vc80/turtle.vcproj b/build/vc80/turtle.vcproj index 71c4c75..f36b314 100644 --- a/build/vc80/turtle.vcproj +++ b/build/vc80/turtle.vcproj @@ -168,6 +168,14 @@ RelativePath="..\..\src\libraries\turtle\check.hpp" > + + + + @@ -180,6 +188,10 @@ RelativePath="..\..\src\libraries\turtle\constraints.hpp" > + + @@ -196,6 +208,10 @@ RelativePath="..\..\src\libraries\turtle\function.hpp" > + + @@ -216,10 +232,6 @@ RelativePath="..\..\src\libraries\turtle\mock.hpp" > - - @@ -228,6 +240,10 @@ RelativePath="..\..\src\libraries\turtle\operators.hpp" > + + diff --git a/build/vc80/turtle_test.vcproj b/build/vc80/turtle_test.vcproj index 54a1911..4c642e3 100644 --- a/build/vc80/turtle_test.vcproj +++ b/build/vc80/turtle_test.vcproj @@ -95,7 +95,7 @@ /> diff --git a/src/libraries/turtle/boost_test_error.hpp b/src/libraries/turtle/boost_test_error.hpp index 01dbfde..c41e43c 100644 --- a/src/libraries/turtle/boost_test_error.hpp +++ b/src/libraries/turtle/boost_test_error.hpp @@ -9,7 +9,6 @@ #ifndef MOCK_BOOST_TEST_ERROR_POLICY_HPP_INCLUDED #define MOCK_BOOST_TEST_ERROR_POLICY_HPP_INCLUDED -#include "root.hpp" #include #include #include @@ -87,16 +86,6 @@ namespace mock fail( "untriggered expectation", context, file, line ); } }; - - struct cleanup - { - ~cleanup() - { - //mock::verify(); // $$$$ MAT : because of a bug in Boost.Test this will crash if anything needs to be logged - mock::reset(); - } - }; - BOOST_GLOBAL_FIXTURE( cleanup ); } #endif // MOCK_BOOST_TEST_ERROR_POLICY_HPP_INCLUDED diff --git a/src/libraries/turtle/child.hpp b/src/libraries/turtle/child.hpp new file mode 100644 index 0000000..db1cf04 --- /dev/null +++ b/src/libraries/turtle/child.hpp @@ -0,0 +1,47 @@ +// +// 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) +// + +#ifndef MOCK_CHILD_HPP_INCLUDED +#define MOCK_CHILD_HPP_INCLUDED + +#include "parent.hpp" +#include +#include + +namespace mock +{ +namespace detail +{ + class child + { + public: + child() + : parent_( 0 ) + {} + void update( parent& p, const std::string& instance, + const std::string& type, const std::string& name ) + { + if( instance != "?" || name_.empty() ) + p = parent( instance, type ); + parent_ = &p; + name_ = name; + } + friend std::ostream& operator<<( std::ostream& s, const child& c ) + { + if( c.parent_ ) + s << *c.parent_; + return s << c.name_; + } + private: + const parent* parent_; + std::string name_; + }; +} +} + +#endif // MOCK_CHILD_HPP_INCLUDED diff --git a/src/libraries/turtle/cleanup.hpp b/src/libraries/turtle/cleanup.hpp new file mode 100644 index 0000000..6c40fa5 --- /dev/null +++ b/src/libraries/turtle/cleanup.hpp @@ -0,0 +1,37 @@ +// +// 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) +// + +#ifndef MOCK_CLEANUP_HPP_INCLUDED +#define MOCK_CLEANUP_HPP_INCLUDED + +#include "config.hpp" + +#ifdef MOCK_USE_BOOST_TEST + +#include "root.hpp" +#include + +namespace mock +{ +namespace detail +{ + struct cleanup + { + ~cleanup() + { + //mock::verify(); // $$$$ MAT : because of a bug in Boost.Test this will crash if anything needs to be logged + mock::reset(); + } + }; + BOOST_GLOBAL_FIXTURE( cleanup ); +} +} + +#endif + +#endif // MOCK_CLEANUP_HPP_INCLUDED diff --git a/src/libraries/turtle/config.hpp b/src/libraries/turtle/config.hpp index c3d4081..f743df4 100644 --- a/src/libraries/turtle/config.hpp +++ b/src/libraries/turtle/config.hpp @@ -38,4 +38,8 @@ # endif #endif +#ifdef BOOST_TEST_DECL +# define MOCK_USE_BOOST_TEST +#endif + #endif // MOCK_CONFIG_HPP_INCLUDED diff --git a/src/libraries/turtle/context.hpp b/src/libraries/turtle/context.hpp new file mode 100644 index 0000000..775cb19 --- /dev/null +++ b/src/libraries/turtle/context.hpp @@ -0,0 +1,38 @@ +// +// 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) +// + +#ifndef MOCK_CONTEXT_HPP_INCLUDED +#define MOCK_CONTEXT_HPP_INCLUDED + +#include +#include +#include + +namespace mock +{ + class verifiable; + +namespace detail +{ + class context : boost::noncopyable + { + public: + context() {} + virtual ~context() {} + + virtual void add( const void* p, verifiable& v, const std::string& instance, + const std::string& type, const std::string& name ) = 0; + virtual void add( verifiable& v ) = 0; + virtual void remove( verifiable& v ) = 0; + + virtual void serialize( std::ostream& s, const verifiable& v ) const = 0; + }; +} +} + +#endif // MOCK_CONTEXT_HPP_INCLUDED diff --git a/src/libraries/turtle/error.hpp b/src/libraries/turtle/error.hpp index 750abb8..5c8a752 100644 --- a/src/libraries/turtle/error.hpp +++ b/src/libraries/turtle/error.hpp @@ -12,7 +12,7 @@ #include "config.hpp" #ifndef MOCK_ERROR_POLICY -# if defined(BOOST_TEST_DECL) || defined(MOCK_USE_BOOST_TEST) +# ifdef MOCK_USE_BOOST_TEST # define MOCK_ERROR_POLICY boost_test_error_policy # include "boost_test_error.hpp" # else diff --git a/src/libraries/turtle/function.hpp b/src/libraries/turtle/function.hpp index 24b084e..0546e34 100644 --- a/src/libraries/turtle/function.hpp +++ b/src/libraries/turtle/function.hpp @@ -11,8 +11,9 @@ #include "config.hpp" #include "error.hpp" +#include "context.hpp" #include "expectation.hpp" -#include "root.hpp" +#include "verifiable.hpp" #include "log.hpp" #include "args.hpp" #include @@ -29,10 +30,7 @@ namespace mock { - template< typename Signature, - typename ErrorPolicy = MOCK_ERROR_POLICY< - BOOST_DEDUCED_TYPENAME - boost::function_types::result_type< Signature >::type > > + template< typename Signature > class function { public: @@ -52,27 +50,10 @@ namespace mock detail::expectation< Signature, arity::value > expectation_type; public: - struct function_tag - {}; - function_tag exp_; - function() : impl_( new function_impl() ) {} - void tag( const std::string& name ) - { - impl_->tag( name ); - } - const std::string& tag() const - { - return impl_->tag(); - } - void set_parent( node& parent ) - { - impl_->set_parent( parent ); - } - bool verify() const { return impl_->verify(); @@ -114,36 +95,57 @@ namespace mock return s << *e.impl_; } - private: - class function_impl : private verifiable + function& _( detail::context& c, const std::string& instance ) { + if( ! impl_->context_ ) + c.add( *impl_ ); + c.add( impl_.get(), *impl_, instance, "", "" ); + impl_->context_ = &c; + return *this; + } + + void configure( detail::context& c, const void* p, + const std::string& instance, const std::string& type, + const std::string& name ) const + { + if( ! impl_->context_ ) + c.add( *impl_ ); + c.add( p, *impl_, instance, type, name ); + impl_->context_ = &c; + } + + private: + class function_impl : public verifiable + { + private: + typedef MOCK_ERROR_POLICY< result_type > error_type; + public: function_impl() - : name_( "?" ) - , parent_( 0 ) + : context_( 0 ) , valid_( true ) {} virtual ~function_impl() { - if( parent_ ) - parent_->remove( *this ); if( valid_ && ! std::uncaught_exception() ) for( expectations_cit it = expectations_.begin(); it != expectations_.end(); ++it ) { if( ! it->verify() ) - ErrorPolicy::untriggered_expectation( + error_type::untriggered_expectation( boost::unit_test::lazy_ostream::instance() << lazy_context( this ) << lazy_expectations( this ), it->file(), it->line() ); else if( ! it->invoked() ) - ErrorPolicy::expected_call( + error_type::expected_call( boost::unit_test::lazy_ostream::instance() << lazy_context( this ) << lazy_expectations( this ), it->file(), it->line() ); } + if( context_ ) + context_->remove( *this ); } virtual bool verify() const @@ -153,7 +155,7 @@ namespace mock if( !it->verify() ) { valid_ = false; - ErrorPolicy::verification_failed( + error_type::verification_failed( boost::unit_test::lazy_ostream::instance() << lazy_context( this ) << lazy_expectations( this ), @@ -167,26 +169,6 @@ namespace mock valid_ = true; expectations_.clear(); } - virtual void untie() - { - parent_ = 0; - } - - void tag( const std::string& name ) - { - name_ = name; - } - const std::string& tag() const - { - return name_; - } - void set_parent( node& parent ) - { - if( parent_ ) - parent_->remove( *this ); - parent.add( *this ); - parent_ = &parent; - } expectation_type& expect( const std::string& file, int line ) { @@ -196,8 +178,6 @@ namespace mock } expectation_type& expect() { - if( ! parent_ ) - set_parent( mock::detail::root ); expectations_.push_back( expectation_type() ); valid_ = true; return expectations_.back(); @@ -218,26 +198,26 @@ namespace mock if( ! it->invoke() ) \ { \ valid_ = false; \ - ErrorPolicy::sequence_failed( MOCK_EXPECTATION_CALL_CONTEXT(n), it->file(), it->line() ); \ + error_type::sequence_failed( MOCK_EXPECTATION_CALL_CONTEXT(n), it->file(), it->line() ); \ return A; \ } \ if( ! it->functor() ) \ { \ - ErrorPolicy::missing_action( MOCK_EXPECTATION_CALL_CONTEXT(n), it->file(), it->line() ); \ + error_type::missing_action( MOCK_EXPECTATION_CALL_CONTEXT(n), it->file(), it->line() ); \ return A; \ } \ - ErrorPolicy::expected_call( MOCK_EXPECTATION_CALL_CONTEXT(n), it->file(), it->line() ); \ + error_type::expected_call( MOCK_EXPECTATION_CALL_CONTEXT(n), it->file(), it->line() ); \ return it->functor()( BOOST_PP_ENUM_PARAMS(n, p) ); \ } \ valid_ = false; \ - ErrorPolicy::unexpected_call( MOCK_EXPECTATION_CALL_CONTEXT(n) ); \ + error_type::unexpected_call( MOCK_EXPECTATION_CALL_CONTEXT(n) ); \ return A; \ } #define MOCK_EXPECTATION_OPERATOR(z, n, P) \ MOCK_DECL(operator(), n, Signature, const, BOOST_DEDUCED_TYPENAME) \ MOCK_EXPECTATION_INVOKE(z, n, P) - BOOST_PP_REPEAT(BOOST_PP_INC(MOCK_MAX_ARGS), MOCK_EXPECTATION_OPERATOR, ErrorPolicy::abort()) + BOOST_PP_REPEAT(BOOST_PP_INC(MOCK_MAX_ARGS), MOCK_EXPECTATION_OPERATOR, error_type::abort()) void test() const MOCK_EXPECTATION_INVOKE(, 0,) @@ -259,11 +239,13 @@ namespace mock {} friend std::ostream& operator<<( std::ostream& s, const lazy_context& e ) { - if( e.impl_->parent_ ) - s << e.impl_->parent_->tag(); - return s << e.impl_->name_; + if( e.impl_->context_ ) + e.impl_->context_->serialize( s, *e.impl_ ); + else + s << "?"; + return s; } - const function_impl* impl_; + const function_impl* impl_; // $$$$ MAT : use detail::context directly }; struct lazy_expectations @@ -286,12 +268,10 @@ namespace mock expectations_type::const_iterator expectations_cit; expectations_type expectations_; - std::string name_; - node* parent_; + detail::context* context_; mutable bool valid_; }; - private: boost::shared_ptr< function_impl > impl_; }; } diff --git a/src/libraries/turtle/group.hpp b/src/libraries/turtle/group.hpp new file mode 100644 index 0000000..42f99d3 --- /dev/null +++ b/src/libraries/turtle/group.hpp @@ -0,0 +1,60 @@ +// +// 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) +// + +#ifndef MOCK_GROUP_HPP_INCLUDED +#define MOCK_GROUP_HPP_INCLUDED + +#include "verifiable.hpp" +#include +#include +#include + +namespace mock +{ +namespace detail +{ + class group + { + public: + void add( verifiable& v ) + { + verifiables_.push_back( &v ); + } + void remove( verifiable& v ) + { + verifiables_.erase( + std::remove( verifiables_.begin(), verifiables_.end(), &v ), + verifiables_.end() ); + } + + bool verify() const + { + bool valid = true; + for( verifiables_cit it = verifiables_.begin(); + it != verifiables_.end(); ++it ) + if( ! (*it)->verify() ) + valid = false; + return valid; + } + void reset() const + { + std::for_each( verifiables_.begin(), verifiables_.end(), + std::mem_fun( &verifiable::reset ) ); + } + + private: + typedef std::vector< verifiable* > verifiables_t; + typedef verifiables_t::iterator verifiables_it; + typedef verifiables_t::const_iterator verifiables_cit; + + verifiables_t verifiables_; + }; +} +} + +#endif // MOCK_GROUP_HPP_INCLUDED diff --git a/src/libraries/turtle/mock.hpp b/src/libraries/turtle/mock.hpp index 00c5ab0..0bd586c 100644 --- a/src/libraries/turtle/mock.hpp +++ b/src/libraries/turtle/mock.hpp @@ -10,6 +10,7 @@ #define MOCK_MOCK_HPP_INCLUDED #include "config.hpp" +#include "cleanup.hpp" #include "object.hpp" #include "function.hpp" #include "type_name.hpp" @@ -19,7 +20,6 @@ #include #include #include -#include #include #include #include @@ -81,43 +81,6 @@ namespace detail > {}; - template< typename E > - void set_parent( E& e, const std::string& prefix, - const std::string& name, const object& o ) - { - o.set_child( e ); - o.tag( prefix ); - e.tag( name ); - } - template< typename E, typename T > - void set_parent( E& e, const std::string& prefix, - const std::string& name, const T&, - BOOST_DEDUCED_TYPENAME boost::disable_if< - BOOST_DEDUCED_TYPENAME boost::is_base_of< object, T > - >::type* = 0 ) - { - e.tag( prefix + name ); - } - - template< typename E > - E& configure( BOOST_DEDUCED_TYPENAME E::function_tag, - const std::string& parent, const std::string& /*name*/, E& e ) - { - if( parent != "?" || e.tag() == "?" ) - e.tag( parent ); - return e; - } - template< typename E, typename T > - E& configure( E& e, const std::string& parent, - const std::string& name, const T& t ) - { - if( parent != "?" || e.tag() == "?" ) - mock::detail::set_parent( e, - parent + " " + mock::detail::type_name( typeid( T ) ) + "::", - name, t ); - return e; - } - template< typename T > struct base { @@ -134,22 +97,29 @@ namespace detail mock::function< S > #define MOCK_MOCKER(o, t) \ - mock::detail::configure( mock::detail::deref( o ).exp##t, \ - BOOST_PP_STRINGIZE(o), BOOST_PP_STRINGIZE(t), \ - mock::detail::deref( o ) ) -#define MOCK_ANONYMOUS_MOCKER(o, M, t) \ - mock::detail::configure( mock::detail::deref( o ).exp##t, \ - "?", BOOST_PP_STRINGIZE(M), mock::detail::deref( o ) ) + mock::detail::deref( o ).t( mock::detail::root, \ + BOOST_PP_STRINGIZE(o) ) +#define MOCK_ANONYMOUS_MOCKER(o, t) \ + mock::detail::deref( o ).t( mock::detail::root, "?" ) #define MOCK_METHOD_EXPECTATION(S, t) \ - mutable mock::function< S > exp##t; + mutable mock::function< S > t##expectation; \ + mock::function< S >& t( const mock::detail::context&, \ + const std::string& instance ) const \ + { \ + mock::detail::configure( *this, t##expectation, instance, \ + mock::detail::type_name( typeid( *this ) ), \ + BOOST_PP_STRINGIZE(t) ); \ + return t##expectation; \ + } + #define MOCK_SIGNATURE(M) \ - mock::detail::signature< BOOST_TYPEOF(&base_type::M) >::type + mock::detail::signature< BOOST_TYPEOF(&base_type::M) >::type // $$$$ MAT inline mock::detail::signature #define MOCK_METHOD_STUB(M, n, S, t, c, tpn) \ MOCK_DECL(M, n, S, c, tpn) \ { \ - return MOCK_ANONYMOUS_MOCKER(this, t, t)( \ + return MOCK_ANONYMOUS_MOCKER(this, t)( \ BOOST_PP_ENUM_PARAMS(n, p) ); \ } @@ -178,18 +148,18 @@ namespace detail MOCK_METHOD_EXPECTATION(S, t) #define MOCK_DESTRUCTOR(T, t) \ - ~T() { MOCK_ANONYMOUS_MOCKER(this, ~T, t).test(); } \ + ~T() { MOCK_ANONYMOUS_MOCKER(this, t).test(); } \ MOCK_METHOD_EXPECTATION(void(), t) #define MOCK_CONST_CONVERSION_OPERATOR(T, t) \ - operator T() const { return MOCK_ANONYMOUS_MOCKER(this, operator T, t)(); } \ + operator T() const { return MOCK_ANONYMOUS_MOCKER(this, t)(); } \ MOCK_METHOD_EXPECTATION(T(), t) #define MOCK_NON_CONST_CONVERSION_OPERATOR(T, t) \ - operator T() { return MOCK_ANONYMOUS_MOCKER(this, operator T, t)(); } \ + operator T() { return MOCK_ANONYMOUS_MOCKER(this, t)(); } \ MOCK_METHOD_EXPECTATION(T(), t) #define MOCK_CONVERSION_OPERATOR(T, t) \ - operator T() const { return MOCK_ANONYMOUS_MOCKER(this, operator T, t)(); } \ - operator T() { return MOCK_ANONYMOUS_MOCKER(this, operator T, t)(); } \ + operator T() const { return MOCK_ANONYMOUS_MOCKER(this, t)(); } \ + operator T() { return MOCK_ANONYMOUS_MOCKER(this, t)(); } \ MOCK_METHOD_EXPECTATION(T(), t) #define MOCK_EXPECT(o,t) MOCK_MOCKER(o,t).expect( __FILE__, __LINE__ ) diff --git a/src/libraries/turtle/node.hpp b/src/libraries/turtle/node.hpp index 0a190b1..2bc8b96 100644 --- a/src/libraries/turtle/node.hpp +++ b/src/libraries/turtle/node.hpp @@ -17,24 +17,9 @@ namespace mock { - class node : protected verifiable + class node { public: - virtual ~node() - { - std::for_each( v_.begin(), v_.end(), - std::mem_fun( &verifiable::untie ) ); - } - - void tag( const std::string& name ) - { - name_ = name; - } - const std::string& tag() const - { - return name_; - } - void add( verifiable& v ) { v_.push_back( &v ); diff --git a/src/libraries/turtle/object.hpp b/src/libraries/turtle/object.hpp index 75a2366..e8a2bc5 100644 --- a/src/libraries/turtle/object.hpp +++ b/src/libraries/turtle/object.hpp @@ -9,8 +9,12 @@ #ifndef MOCK_OBJECT_HPP_INCLUDED #define MOCK_OBJECT_HPP_INCLUDED -#include "node.hpp" #include "root.hpp" +#include "context.hpp" +#include "parent.hpp" +#include "child.hpp" +#include +#include #include #include @@ -23,60 +27,101 @@ namespace mock : impl_( new object_impl() ) {} - template< typename T > - void set_child( T& t ) const - { - impl_->set_child( t ); - } - void tag( const std::string& name ) const - { - impl_->tag( name ); - } - - bool verify() const + bool verify() const // $$$$ MAT : to be deprecated { return impl_->verify(); } - void reset() + void reset() // $$$$ MAT : to be deprecated { impl_->reset(); } private: - class object_impl : public node + class object_impl : public detail::context, private verifiable { public: - object_impl() - : parent_( 0 ) - {} - virtual ~object_impl() + virtual void add( const void* /*p*/, verifiable& v, + const std::string& instance, const std::string& type, + const std::string& name ) { - if( parent_ ) - parent_->remove( *this ); - } - template< typename T > - void set_child( T& t ) - { - if( ! parent_ ) - { + if( children_.empty() ) mock::detail::root.add( *this ); - parent_ = &mock::detail::root; - } - t.set_parent( *this ); + children_[ &v ].update( parent_, instance, type, name ); } - - private: - virtual void untie() + virtual void add( verifiable& v ) { - parent_ = 0; + group_.add( v ); + } + virtual void remove( verifiable& v ) + { + group_.remove( v ); + children_.erase( &v ); + if( children_.empty() ) + mock::detail::root.remove( *this ); + } + + virtual void serialize( std::ostream& s, + const verifiable& v ) const + { + children_cit it = children_.find( &v ); + if( it != children_.end() ) + s << it->second; + else + s << "?"; + } + + virtual bool verify() const + { + return group_.verify(); + } + virtual void reset() + { + group_.reset(); } private: - node* parent_; + typedef std::map< const verifiable*, detail::child > children_t; + typedef children_t::const_iterator children_cit; + + detail::group group_; + detail::parent parent_; + children_t children_; }; + public: boost::shared_ptr< object_impl > impl_; }; + +namespace detail +{ + template< typename E > + E& configure( const object& o, E& e, const std::string& instance, + const std::string& type, const std::string& name ) + { + e.configure( *o.impl_, o.impl_.get(), instance, type, name ); + return e; + } + + template< typename E, typename T > + E& configure( const T& t, E& e, const std::string& instance, + const std::string& type, const std::string& name, + BOOST_DEDUCED_TYPENAME boost::disable_if< + BOOST_DEDUCED_TYPENAME boost::is_base_of< object, T > + >::type* = 0 ) + { + e.configure( mock::detail::root, &t, instance, type, name ); + return e; + } +} + + inline bool verify( const object& o ) + { + return o.impl_->verify(); + } + inline void reset( object& o ) + { + o.impl_->reset(); + } } #endif // MOCK_OBJECT_HPP_INCLUDED diff --git a/src/libraries/turtle/parent.hpp b/src/libraries/turtle/parent.hpp new file mode 100644 index 0000000..d7fabf9 --- /dev/null +++ b/src/libraries/turtle/parent.hpp @@ -0,0 +1,42 @@ +// +// 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) +// + +#ifndef MOCK_PARENT_HPP_INCLUDED +#define MOCK_PARENT_HPP_INCLUDED + +#include +#include + +namespace mock +{ +namespace detail +{ + class parent + { + public: + parent() + {} + parent( const std::string& instance, const std::string& type ) + : instance_( instance ) + , type_( type ) + {} + friend std::ostream& operator<<( std::ostream& s, const parent& p ) + { + s << p.instance_; + if( ! p.type_.empty() ) + s << " " + p.type_ + "::"; + return s; + } + private: + std::string instance_; + std::string type_; + }; +} +} + +#endif // MOCK_PARENT_HPP_INCLUDED diff --git a/src/libraries/turtle/root.hpp b/src/libraries/turtle/root.hpp index 7afbdb6..7975435 100644 --- a/src/libraries/turtle/root.hpp +++ b/src/libraries/turtle/root.hpp @@ -9,19 +9,118 @@ #ifndef MOCK_ROOT_HPP_INCLUDED #define MOCK_ROOT_HPP_INCLUDED -#include "config.hpp" -#include "node.hpp" +#include "group.hpp" +#include "context.hpp" +#include "parent.hpp" +#include "child.hpp" +#include "function.hpp" #include +#include +#include +#include namespace mock { namespace detail { - class root_t : public boost::unit_test::singleton< root_t >, public node + class root_t : public boost::unit_test::singleton< root_t >, + public detail::context { + public: + virtual void add( const void* p, verifiable& v, + const std::string& instance, const std::string& type, + const std::string& name ) + { + children_it it = children_.lower_bound( &v ); + if( it == children_.end() || + children_.key_comp()( &v, it->first ) ) + it = children_.insert( it, + std::make_pair( &v, counter_child( parents_, p ) ) ); + it->second.update( instance, type, name ); + } + virtual void add( verifiable& v ) + { + group_.add( v ); + } + + virtual void remove( verifiable& v ) + { + group_.remove( v ); + children_.erase( &v ); + } + + bool verify() const + { + return group_.verify(); + } + void reset() const + { + group_.reset(); + } + + virtual void serialize( std::ostream& s, const verifiable& v ) const + { + children_cit it = children_.find( &v ); + if( it != children_.end() ) + s << it->second; + else + s << "?"; + } + private: - virtual void untie() - {} + typedef std::map< const void*, + std::pair< parent, std::size_t > > parents_t; + typedef parents_t::iterator parents_it; + + class counter_child + { + public: + counter_child( parents_t& parents, const void* p ) + : parents_( &parents ) + , it_( parents.insert( + std::make_pair( p, parents_t::mapped_type() ) ).first ) + { + ++it_->second.second; + } + counter_child( const counter_child& rhs ) + : parents_( rhs.parents_ ) + , it_( rhs.it_ ) + , child_( rhs.child_ ) + { + ++it_->second.second; + } + ~counter_child() + { + if( --it_->second.second == 0 ) + parents_->erase( it_ ); + } + void update( const std::string& instance, const std::string& type, + const std::string& name ) + { + child_.update( it_->second.first, instance, type, name ); + } + friend std::ostream& operator<<( std::ostream& s, + const counter_child& c ) + { + return s << c.child_; + } + + private: + counter_child& operator=( const counter_child& ); + + parents_t* parents_; + parents_it it_; + child child_; + }; + + typedef std::map< const verifiable*, counter_child > children_t; + typedef children_t::const_iterator children_cit; + typedef children_t::iterator children_it; + + parents_t parents_; + children_t children_; + group group_; + private: BOOST_TEST_SINGLETON_CONS( root_t ); }; diff --git a/src/libraries/turtle/verifiable.hpp b/src/libraries/turtle/verifiable.hpp index 6fdfa40..bf4f4f1 100644 --- a/src/libraries/turtle/verifiable.hpp +++ b/src/libraries/turtle/verifiable.hpp @@ -22,8 +22,6 @@ namespace mock virtual bool verify() const = 0; virtual void reset() = 0; - - virtual void untie() = 0; }; } diff --git a/src/tests/turtle_test/function_test.cpp b/src/tests/turtle_test/function_test.cpp index 178adc5..d9d3ca1 100644 --- a/src/tests/turtle_test/function_test.cpp +++ b/src/tests/turtle_test/function_test.cpp @@ -629,11 +629,10 @@ BOOST_FIXTURE_TEST_CASE( expectation_can_be_serialized_to_be_human_readable, err { { mock::function< void( int ) > f; - f.tag( "my function" ); f.expect().once().with( 1 ); f.expect().once().with( 2 ); BOOST_CHECK_NO_THROW( f( 2 ) ); - const std::string expected = "my function\n" + const std::string expected = "?\n" ". once().with( 1 )\n" "v once().with( 2 )"; BOOST_CHECK_EQUAL( expected, to_string( f ) ); @@ -642,9 +641,8 @@ BOOST_FIXTURE_TEST_CASE( expectation_can_be_serialized_to_be_human_readable, err } { mock::function< void( int ) > f; - f.tag( "my function" ); f.expect().never().with( 1 ); - const std::string expected = "my function\n" + const std::string expected = "?\n" "v never().with( 1 )"; BOOST_CHECK_EQUAL( expected, to_string( f ) ); f.reset(); @@ -672,36 +670,32 @@ BOOST_FIXTURE_TEST_CASE( expectation_can_be_serialized_to_be_human_readable, err } { mock::function< void( int ) > f; - f.tag( "my function" ); f.expect().once(); - const std::string expected = "my function\n" + const std::string expected = "?\n" ". once().with( any )"; BOOST_CHECK_EQUAL( expected, to_string( f ) ); f.reset(); } { mock::function< void( int ) > f; - f.tag( "my function" ); f.expect().once().with( mock::any ); - const std::string expected = "my function\n" + const std::string expected = "?\n" ". once().with( any )"; BOOST_CHECK_EQUAL( expected, to_string( f ) ); f.reset(); } { mock::function< void( int ) > f; - f.tag( "my function" ); f.expect().once(); - const std::string expected = "my function\n" + const std::string expected = "?\n" ". once().with( any )"; BOOST_CHECK_EQUAL( expected, to_string( f ) ); f.reset(); } { mock::function< void( int ) > f; - f.tag( "my function" ); f.expect().once().with( &custom_constraint ); - const std::string expected = "my function\n" + const std::string expected = "?\n" ". once().with( ? )"; BOOST_CHECK_EQUAL( expected, to_string( f ) ); f.reset(); diff --git a/src/tests/turtle_test/mock_test.cpp b/src/tests/turtle_test/mock_test.cpp index d53503e..2393ad8 100644 --- a/src/tests/turtle_test/mock_test.cpp +++ b/src/tests/turtle_test/mock_test.cpp @@ -160,53 +160,50 @@ namespace } } -#define MOCK_ANONYMOUS_MOCKER_EXT(o, t) \ - MOCK_ANONYMOUS_MOCKER( o, t, t ) - BOOST_AUTO_TEST_CASE( mock_object_is_named ) { my_mock m; - BOOST_CHECK_EQUAL( "? my_mock::my_method", to_string( MOCK_ANONYMOUS_MOCKER_EXT( m, my_method ) ) ); - BOOST_CHECK_EQUAL( "? my_mock::my_method_2", to_string( MOCK_ANONYMOUS_MOCKER_EXT( m, my_method_2 ) ) ); + BOOST_CHECK_EQUAL( "? my_mock::my_method", to_string( MOCK_ANONYMOUS_MOCKER( m, my_method ) ) ); + BOOST_CHECK_EQUAL( "? my_mock::my_method_2", to_string( MOCK_ANONYMOUS_MOCKER( m, my_method_2 ) ) ); BOOST_CHECK_EQUAL( "m my_mock::my_method", to_string( MOCK_MOCKER( m, my_method ) ) ); - BOOST_CHECK_EQUAL( "m my_mock::my_method_2", to_string( MOCK_ANONYMOUS_MOCKER_EXT( m, my_method_2 ) ) ); - BOOST_CHECK_EQUAL( "m my_mock::my_method", to_string( MOCK_ANONYMOUS_MOCKER_EXT( m, my_method ) ) ); + BOOST_CHECK_EQUAL( "m my_mock::my_method_2", to_string( MOCK_ANONYMOUS_MOCKER( m, my_method_2 ) ) ); + BOOST_CHECK_EQUAL( "m my_mock::my_method", to_string( MOCK_ANONYMOUS_MOCKER( m, my_method ) ) ); BOOST_CHECK_EQUAL( "m my_mock::my_method", to_string( MOCK_MOCKER( m, my_method ) ) ); } BOOST_AUTO_TEST_CASE( mock_object_auto_pointer_is_named ) { std::auto_ptr< my_mock > m( new my_mock ); - BOOST_CHECK_EQUAL( "? my_mock::my_method", to_string( MOCK_ANONYMOUS_MOCKER_EXT( m, my_method ) ) ); + BOOST_CHECK_EQUAL( "? my_mock::my_method", to_string( MOCK_ANONYMOUS_MOCKER( m, my_method ) ) ); BOOST_CHECK_EQUAL( "m my_mock::my_method", to_string( MOCK_MOCKER( m, my_method ) ) ); - BOOST_CHECK_EQUAL( "m my_mock::my_method", to_string( MOCK_ANONYMOUS_MOCKER_EXT( m, my_method ) ) ); + BOOST_CHECK_EQUAL( "m my_mock::my_method", to_string( MOCK_ANONYMOUS_MOCKER( m, my_method ) ) ); BOOST_CHECK_EQUAL( "m my_mock::my_method", to_string( MOCK_MOCKER( m, my_method ) ) ); } BOOST_AUTO_TEST_CASE( mock_object_const_auto_pointer_is_named ) { const std::auto_ptr< my_mock > m( new my_mock ); - BOOST_CHECK_EQUAL( "? my_mock::my_method", to_string( MOCK_ANONYMOUS_MOCKER_EXT( m, my_method ) ) ); + BOOST_CHECK_EQUAL( "? my_mock::my_method", to_string( MOCK_ANONYMOUS_MOCKER( m, my_method ) ) ); BOOST_CHECK_EQUAL( "m my_mock::my_method", to_string( MOCK_MOCKER( m, my_method ) ) ); - BOOST_CHECK_EQUAL( "m my_mock::my_method", to_string( MOCK_ANONYMOUS_MOCKER_EXT( m, my_method ) ) ); + BOOST_CHECK_EQUAL( "m my_mock::my_method", to_string( MOCK_ANONYMOUS_MOCKER( m, my_method ) ) ); BOOST_CHECK_EQUAL( "m my_mock::my_method", to_string( MOCK_MOCKER( m, my_method ) ) ); } BOOST_AUTO_TEST_CASE( mock_object_shared_pointer_is_named ) { boost::shared_ptr< my_mock > m( new my_mock ); - BOOST_CHECK_EQUAL( "? my_mock::my_method", to_string( MOCK_ANONYMOUS_MOCKER_EXT( m, my_method ) ) ); + BOOST_CHECK_EQUAL( "? my_mock::my_method", to_string( MOCK_ANONYMOUS_MOCKER( m, my_method ) ) ); BOOST_CHECK_EQUAL( "m my_mock::my_method", to_string( MOCK_MOCKER( m, my_method ) ) ); - BOOST_CHECK_EQUAL( "m my_mock::my_method", to_string( MOCK_ANONYMOUS_MOCKER_EXT( m, my_method ) ) ); + BOOST_CHECK_EQUAL( "m my_mock::my_method", to_string( MOCK_ANONYMOUS_MOCKER( m, my_method ) ) ); BOOST_CHECK_EQUAL( "m my_mock::my_method", to_string( MOCK_MOCKER( m, my_method ) ) ); } BOOST_AUTO_TEST_CASE( mock_object_const_shared_pointer_is_named ) { const boost::shared_ptr< my_mock > m( new my_mock ); - BOOST_CHECK_EQUAL( "? my_mock::my_method", to_string( MOCK_ANONYMOUS_MOCKER_EXT( m, my_method ) ) ); + BOOST_CHECK_EQUAL( "? my_mock::my_method", to_string( MOCK_ANONYMOUS_MOCKER( m, my_method ) ) ); BOOST_CHECK_EQUAL( "m my_mock::my_method", to_string( MOCK_MOCKER( m, my_method ) ) ); - BOOST_CHECK_EQUAL( "m my_mock::my_method", to_string( MOCK_ANONYMOUS_MOCKER_EXT( m, my_method ) ) ); + BOOST_CHECK_EQUAL( "m my_mock::my_method", to_string( MOCK_ANONYMOUS_MOCKER( m, my_method ) ) ); BOOST_CHECK_EQUAL( "m my_mock::my_method", to_string( MOCK_MOCKER( m, my_method ) ) ); } @@ -222,11 +219,11 @@ namespace 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_ANONYMOUS_MOCKER_EXT( m, my_method ) ) ); - BOOST_CHECK_EQUAL( "? my_custom_mock::my_method_2", to_string( MOCK_ANONYMOUS_MOCKER_EXT( m, my_method_2 ) ) ); + BOOST_CHECK_EQUAL( "? my_custom_mock::my_method", to_string( MOCK_ANONYMOUS_MOCKER( m, my_method ) ) ); + BOOST_CHECK_EQUAL( "? my_custom_mock::my_method_2", to_string( MOCK_ANONYMOUS_MOCKER( m, my_method_2 ) ) ); BOOST_CHECK_EQUAL( "m my_custom_mock::my_method", to_string( MOCK_MOCKER( m, my_method ) ) ); - BOOST_CHECK_EQUAL( "? my_custom_mock::my_method_2", to_string( MOCK_ANONYMOUS_MOCKER_EXT( m, my_method_2 ) ) ); - BOOST_CHECK_EQUAL( "m my_custom_mock::my_method", to_string( MOCK_ANONYMOUS_MOCKER_EXT( m, my_method ) ) ); + BOOST_CHECK_EQUAL( "m my_custom_mock::my_method_2", to_string( MOCK_ANONYMOUS_MOCKER( m, my_method_2 ) ) ); + BOOST_CHECK_EQUAL( "m my_custom_mock::my_method", to_string( MOCK_ANONYMOUS_MOCKER( m, my_method ) ) ); BOOST_CHECK_EQUAL( "m my_custom_mock::my_method", to_string( MOCK_MOCKER( m, my_method ) ) ); } @@ -242,11 +239,11 @@ namespace 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_ANONYMOUS_MOCKER_EXT( m, my_method ) ) ); - BOOST_CHECK_EQUAL( "? my_custom_mock_object::my_method_2", to_string( MOCK_ANONYMOUS_MOCKER_EXT( m, my_method_2 ) ) ); + BOOST_CHECK_EQUAL( "? my_custom_mock_object::my_method", to_string( MOCK_ANONYMOUS_MOCKER( m, my_method ) ) ); + BOOST_CHECK_EQUAL( "? my_custom_mock_object::my_method_2", to_string( MOCK_ANONYMOUS_MOCKER( m, my_method_2 ) ) ); BOOST_CHECK_EQUAL( "m my_custom_mock_object::my_method", to_string( MOCK_MOCKER( m, my_method ) ) ); - BOOST_CHECK_EQUAL( "m my_custom_mock_object::my_method_2", to_string( MOCK_ANONYMOUS_MOCKER_EXT( m, my_method_2 ) ) ); - BOOST_CHECK_EQUAL( "m my_custom_mock_object::my_method", to_string( MOCK_ANONYMOUS_MOCKER_EXT( m, my_method ) ) ); + BOOST_CHECK_EQUAL( "m my_custom_mock_object::my_method_2", to_string( MOCK_ANONYMOUS_MOCKER( m, my_method_2 ) ) ); + BOOST_CHECK_EQUAL( "m my_custom_mock_object::my_method", to_string( MOCK_ANONYMOUS_MOCKER( m, my_method ) ) ); BOOST_CHECK_EQUAL( "m 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 b584a17..77bfaaa 100644 --- a/src/tests/turtle_test/object_test.cpp +++ b/src/tests/turtle_test/object_test.cpp @@ -19,39 +19,43 @@ namespace BOOST_AUTO_TEST_CASE( verifying_an_empty_object_succeeds ) { mock::object o; - BOOST_CHECK( o.verify() ); + BOOST_CHECK( mock::verify( o ) ); } -BOOST_AUTO_TEST_CASE( verifying_an_object_containing_a_failing_expectation_fails ) +namespace +{ + struct fixture + { + fixture() + { + mock::detail::configure( o, e, "instance", "type", "name" ); + } + mock::object o; + mock::function< void() > e; + }; +} + +BOOST_FIXTURE_TEST_CASE( verifying_an_object_containing_a_failing_expectation_fails, fixture ) { - mock::object o; - mock::function< void() > e; - o.set_child( e ); e.expect().once(); - BOOST_CHECK( ! o.verify() ); - o.reset(); - BOOST_CHECK( o.verify() ); + BOOST_CHECK( ! mock::verify( o ) ); + mock::reset( o ); + BOOST_CHECK( mock::verify( o ) ); } -BOOST_AUTO_TEST_CASE( verifying_all_objects_with_one_of_them_containing_a_failing_expectation_fails ) +BOOST_FIXTURE_TEST_CASE( verifying_all_objects_with_one_of_them_containing_a_failing_expectation_fails, fixture ) { - mock::object o; - mock::function< void() > e; - o.set_child( e ); e.expect().once(); BOOST_CHECK( ! mock::verify() ); mock::reset(); BOOST_CHECK( mock::verify() ); } -BOOST_AUTO_TEST_CASE( resetting_an_object_containing_a_failing_expectation_and_verifying_it_succeeds ) +BOOST_FIXTURE_TEST_CASE( resetting_an_object_containing_a_failing_expectation_and_verifying_it_succeeds, fixture ) { - mock::object o; - mock::function< void() > e; - o.set_child( e ); e.expect().once(); - o.reset(); - BOOST_CHECK( o.verify() ); + mock::reset( o ); + BOOST_CHECK( mock::verify( o ) ); } BOOST_AUTO_TEST_CASE( an_object_is_assignable_by_sharing_its_state ) @@ -60,13 +64,13 @@ BOOST_AUTO_TEST_CASE( an_object_is_assignable_by_sharing_its_state ) mock::function< void() > e; { mock::object o2; - o2.set_child( e ); + mock::detail::configure( o2, e, "instance", "type", "name" ); e.expect().once(); o1 = o2; - BOOST_CHECK( ! o2.verify() ); - BOOST_CHECK( ! o1.verify() ); + BOOST_CHECK( ! mock::verify( o2 ) ); + BOOST_CHECK( ! mock::verify( o1 ) ); } - BOOST_CHECK( ! o1.verify() ); + BOOST_CHECK( ! mock::verify( o1 ) ); } BOOST_AUTO_TEST_CASE( an_object_is_copiable_by_sharing_its_state ) @@ -74,20 +78,10 @@ BOOST_AUTO_TEST_CASE( an_object_is_copiable_by_sharing_its_state ) std::auto_ptr< mock::object > o2( new mock::object ); const mock::object o1( *o2 ); mock::function< void() > e; - o2->set_child( e ); + mock::detail::configure( *o2, e, "instance", "type", "name" ); e.expect().once(); - BOOST_CHECK( ! o2->verify() ); - BOOST_CHECK( ! o1.verify() ); + BOOST_CHECK( ! mock::verify( *o2 ) ); + BOOST_CHECK( ! mock::verify( o1 ) ); o2.reset(); - BOOST_CHECK( ! o1.verify() ); -} - -BOOST_AUTO_TEST_CASE( an_object_can_be_destroyed_before_its_children_functions ) -{ - mock::function< void() > f; - { - mock::object o; - o.set_child( f ); - } - f.test(); + BOOST_CHECK( ! mock::verify( o1 ) ); }