From f2a617882b22837e35a613d99b4ae3de77167110 Mon Sep 17 00:00:00 2001 From: mat007 Date: Sun, 22 Jul 2012 06:58:12 +0000 Subject: [PATCH] Toying with PP git-svn-id: https://svn.code.sf.net/p/turtle/code/trunk@480 860be788-9bd5-4423-9f1e-828f051e677b --- build/build.xml | 2 +- build/vc100/turtle.vcxproj | 5 +- build/vc100/turtle.vcxproj.filters | 15 +- turtle/expectation.hpp | 261 ------------------------- turtle/expectation_base.hpp | 101 ++++++++++ turtle/expectation_template.hpp | 141 +++++++++++++ turtle/function.hpp | 304 ++--------------------------- turtle/function_iterate.hpp | 11 ++ turtle/function_template.hpp | 275 ++++++++++++++++++++++++++ 9 files changed, 563 insertions(+), 552 deletions(-) delete mode 100644 turtle/expectation.hpp create mode 100644 turtle/expectation_base.hpp create mode 100644 turtle/expectation_template.hpp create mode 100644 turtle/function_iterate.hpp create mode 100644 turtle/function_template.hpp diff --git a/build/build.xml b/build/build.xml index cab6e14..3a35e40 100644 --- a/build/build.xml +++ b/build/build.xml @@ -96,7 +96,7 @@ - + diff --git a/build/vc100/turtle.vcxproj b/build/vc100/turtle.vcxproj index c714e46..05fa556 100644 --- a/build/vc100/turtle.vcxproj +++ b/build/vc100/turtle.vcxproj @@ -39,8 +39,11 @@ - + + + + diff --git a/build/vc100/turtle.vcxproj.filters b/build/vc100/turtle.vcxproj.filters index 77db42a..a64dfb7 100644 --- a/build/vc100/turtle.vcxproj.filters +++ b/build/vc100/turtle.vcxproj.filters @@ -25,9 +25,6 @@ Source Files - - Source Files - Source Files @@ -97,5 +94,17 @@ Source Files\detail + + Source Files + + + Source Files + + + Source Files + + + Source Files + \ No newline at end of file diff --git a/turtle/expectation.hpp b/turtle/expectation.hpp deleted file mode 100644 index 3d9cab5..0000000 --- a/turtle/expectation.hpp +++ /dev/null @@ -1,261 +0,0 @@ -// http://turtle.sourceforge.net -// -// Copyright Mathieu Champlon 2008 -// -// 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_EXPECTATION_HPP_INCLUDED -#define MOCK_EXPECTATION_HPP_INCLUDED - -#include "config.hpp" -#include "invocation.hpp" -#include "action.hpp" -#include "sequence.hpp" -#include "check.hpp" -#include "constraints.hpp" -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace mock -{ -namespace detail -{ - class expectation_base - { - public: - expectation_base() - : i_( new detail::unlimited() ) - , file_( "unknown location" ) - , line_( 0 ) - {} - void set_location( const char* file, int line ) - { - file_ = file; - line_ = line; - } - - bool verify() const - { - return i_->verify(); - } - - bool invoke() const - { - for( sequences_cit it = sequences_.begin(); - it != sequences_.end(); ++it ) - if( ! (*it)->is_valid( this ) ) - return false; - bool result = i_->invoke(); - for( sequences_cit it = sequences_.begin(); - it != sequences_.end(); ++it ) - (*it)->invalidate( this ); - return result; - } - - bool invoked() const - { - return i_->invoked(); - } - - const char* file() const - { - return file_; - } - int line() const - { - return line_; - } - - protected: - ~expectation_base() - { - for( sequences_cit it = sequences_.begin(); - it != sequences_.end(); ++it ) - (*it)->remove( this ); - } - - void expect( detail::invocation* i ) - { - i_.reset( i ); - } - - void add( boost::shared_ptr< detail::sequence_impl > s ) - { - s->add( this ); - sequences_.push_back( s ); - } - - boost::shared_ptr< detail::invocation > i_; - - private: - typedef std::vector< - boost::shared_ptr< detail::sequence_impl > - > sequences_type; - typedef sequences_type::const_iterator sequences_cit; - - sequences_type sequences_; - const char* file_; - int line_; - }; - - template< typename Signature, int Arity > - class expectation - { - }; - -#define MOCK_EXPECTATION_METHODS \ - expectation& in( sequence& s ) \ - { \ - add( s.impl_ ); \ - return *this; \ - } \ - expectation& once() \ - { \ - expect( new detail::once() ); \ - return *this; \ - } \ - expectation& never() \ - { \ - expect( new detail::never() ); \ - return *this; \ - } \ - expectation& exactly( std::size_t count ) \ - { \ - expect( new detail::exactly( count ) ); \ - return *this; \ - } \ - expectation& at_least( std::size_t min ) \ - { \ - expect( new detail::at_least( min ) ); \ - return *this; \ - } \ - expectation& at_most( std::size_t max ) \ - { \ - expect( new detail::at_most( max ) ); \ - return *this; \ - } \ - expectation& between( std::size_t min, std::size_t max ) \ - { \ - expect( new detail::between( min, max ) ); \ - return *this; \ - } - - template< typename Signature > - class expectation< Signature, 0 > - : public expectation_base - , public action< BOOST_DEDUCED_TYPENAME - boost::function_types::result_type< Signature >::type, Signature > - { - public: - bool is_valid() const - { - return ! i_->exhausted(); - } - - MOCK_EXPECTATION_METHODS - - friend std::ostream& operator<<( std::ostream& s, - const expectation& m ) - { - return s << (m.i_->exhausted() ? 'v' : '.') << ' ' << *m.i_; - } - }; - -#define MOCK_EXPECTATION_TYPEDEF(z, n, d) \ - typedef BOOST_DEDUCED_TYPENAME \ - boost::mpl::at_c< \ - BOOST_DEDUCED_TYPENAME \ - boost::function_types::parameter_types< Signature >, \ - n \ - >::type arg##n##_type; -#define MOCK_EXPECTATION_INITIALIZE(z, n, d) \ - BOOST_PP_COMMA_IF(n) c##n##_( \ - new detail::check< \ - arg##n##_type, \ - constraint< detail::any > \ - >( mock::any ) ) -#define MOCK_EXPECTATION_WITH(z, n, d) \ - c##n##_.reset( \ - new detail::check< \ - arg##n##_type, \ - Constraint_##n \ - >( c##n ) ); -#define MOCK_EXPECTATION_MEMBER(z, n, d) \ - boost::shared_ptr< detail::check_base< arg##n##_type > > c##n##_; -#define MOCK_EXPECTATION_ARGS(z, n, d) \ - BOOST_PP_COMMA_IF(n) arg##n##_type a##n -#define MOCK_EXPECTATION_IS_VALID(z, n, d) \ - && (*c##n##_)( a##n ) -#define MOCK_EXPECTATION_SERIALIZE(z, n, d) \ - BOOST_PP_IF(n, << ", " <<,) *m.c##n##_ -#define MOCK_EXPECTATION(z, n, d) \ - template< typename Signature > \ - class expectation< Signature, n > \ - : public expectation_base \ - , public action< \ - BOOST_DEDUCED_TYPENAME \ - boost::function_types::result_type< Signature >::type, \ - Signature \ - > \ - { \ - BOOST_PP_REPEAT(n, MOCK_EXPECTATION_TYPEDEF, BOOST_PP_EMPTY) \ - public: \ - expectation() \ - : BOOST_PP_REPEAT(n, MOCK_EXPECTATION_INITIALIZE, BOOST_PP_EMPTY) \ - {} \ - template< BOOST_PP_ENUM_PARAMS(n, typename Constraint_) > \ - expectation& with( BOOST_PP_ENUM_BINARY_PARAMS(n, Constraint_, c) ) \ - { \ - BOOST_PP_REPEAT(n, MOCK_EXPECTATION_WITH, BOOST_PP_EMPTY) \ - return *this; \ - } \ - bool is_valid( \ - BOOST_PP_REPEAT(n, MOCK_EXPECTATION_ARGS, BOOST_PP_EMPTY) ) const \ - { \ - return ! i_->exhausted() \ - BOOST_PP_REPEAT(n, \ - MOCK_EXPECTATION_IS_VALID, BOOST_PP_EMPTY); \ - } \ - MOCK_EXPECTATION_METHODS \ - friend std::ostream& operator<<( \ - std::ostream& s, const expectation& m ) \ - { \ - return s << (m.i_->exhausted() ? 'v' : '.') \ - << ' ' << *m.i_ << ".with( " \ - << BOOST_PP_REPEAT(n, \ - MOCK_EXPECTATION_SERIALIZE, BOOST_PP_EMPTY) \ - << " )"; \ - } \ - private: \ - BOOST_PP_REPEAT(n, MOCK_EXPECTATION_MEMBER, BOOST_PP_EMPTY) \ - }; - - BOOST_PP_REPEAT_FROM_TO( - 1, - BOOST_PP_INC(MOCK_MAX_ARGS), - MOCK_EXPECTATION, - BOOST_PP_EMPTY) - -#undef MOCK_EXPECTATION_METHODS -#undef MOCK_EXPECTATION_TYPEDEF -#undef MOCK_EXPECTATION_INITIALIZE -#undef MOCK_EXPECTATION_WITH -#undef MOCK_EXPECTATION_MEMBER -#undef MOCK_EXPECTATION_ARGS -#undef MOCK_EXPECTATION_IS_VALID -#undef MOCK_EXPECTATION_SERIALIZE -#undef MOCK_EXPECTATION - -} -} // mock - -#endif // MOCK_EXPECTATION_HPP_INCLUDED diff --git a/turtle/expectation_base.hpp b/turtle/expectation_base.hpp new file mode 100644 index 0000000..b436424 --- /dev/null +++ b/turtle/expectation_base.hpp @@ -0,0 +1,101 @@ +// http://turtle.sourceforge.net +// +// Copyright Mathieu Champlon 2012 +// +// 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_EXPECTATION_BASE_HPP_INCLUDED +#define MOCK_EXPECTATION_BASE_HPP_INCLUDED + +#include "invocation.hpp" +#include "sequence.hpp" +#include +#include + +namespace mock +{ +namespace detail +{ + class expectation_base + { + public: + expectation_base() + : i_( new detail::unlimited() ) + , file_( "unknown location" ) + , line_( 0 ) + {} + void set_location( const char* file, int line ) + { + file_ = file; + line_ = line; + } + + bool verify() const + { + return i_->verify(); + } + + bool invoke() const + { + for( sequences_cit it = sequences_.begin(); + it != sequences_.end(); ++it ) + if( ! (*it)->is_valid( this ) ) + return false; + bool result = i_->invoke(); + for( sequences_cit it = sequences_.begin(); + it != sequences_.end(); ++it ) + (*it)->invalidate( this ); + return result; + } + + bool invoked() const + { + return i_->invoked(); + } + + const char* file() const + { + return file_; + } + int line() const + { + return line_; + } + + protected: + ~expectation_base() + { + for( sequences_cit it = sequences_.begin(); + it != sequences_.end(); ++it ) + (*it)->remove( this ); + } + + void expect( detail::invocation* i ) + { + i_.reset( i ); + } + + void add( boost::shared_ptr< detail::sequence_impl > s ) + { + s->add( this ); + sequences_.push_back( s ); + } + + boost::shared_ptr< detail::invocation > i_; + + private: + typedef std::vector< + boost::shared_ptr< detail::sequence_impl > + > sequences_type; + typedef sequences_type::const_iterator sequences_cit; + + sequences_type sequences_; + const char* file_; + int line_; + }; +} +} // mock + +#endif // MOCK_EXPECTATION_BASE_HPP_INCLUDED diff --git a/turtle/expectation_template.hpp b/turtle/expectation_template.hpp new file mode 100644 index 0000000..93718ae --- /dev/null +++ b/turtle/expectation_template.hpp @@ -0,0 +1,141 @@ +// http://turtle.sourceforge.net +// +// Copyright Mathieu Champlon 2012 +// +// 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) + +#include "expectation_base.hpp" + +#define MOCK_EXPECTATION_TYPEDEF(z, n, d) \ + typedef T##n arg##n##_type; + +#define MOCK_EXPECTATION_INITIALIZE(z, n, d) \ + BOOST_PP_COMMA_IF(n) c##n##_( \ + new detail::check< \ + arg##n##_type, \ + constraint< detail::any > \ + >( mock::any ) ) + +#define MOCK_EXPECTATION_WITH(z, n, d) \ + c##n##_.reset( \ + new detail::check< \ + arg##n##_type, \ + Constraint_##n \ + >( c##n ) ); + +#define MOCK_EXPECTATION_MEMBER(z, n, d) \ + boost::shared_ptr< detail::check_base< arg##n##_type > > c##n##_; + +#define MOCK_EXPECTATION_ARGS(z, n, d) \ + BOOST_PP_COMMA_IF(n) arg##n##_type a##n + +#define MOCK_EXPECTATION_IS_VALID(z, n, d) \ + && (*c##n##_)( a##n ) + +#define MOCK_EXPECTATION_SERIALIZE(z, n, d) \ + BOOST_PP_IF(n, << ", " <<,) *m.c##n##_ + +namespace mock +{ +namespace detail +{ + template< typename Signature > class expectation; + + template< typename R BOOST_PP_COMMA_IF(MOCK_NUM_ARGS) + BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, typename T) > + class expectation< R (BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS,T)) > + : public expectation_base + , public action< R, R (BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS,T)) > + { + BOOST_PP_REPEAT(MOCK_NUM_ARGS, + MOCK_EXPECTATION_TYPEDEF, BOOST_PP_EMPTY) + public: +#ifndef MOCK_NUM_ARGS_0 + expectation() + : + BOOST_PP_REPEAT(MOCK_NUM_ARGS, + MOCK_EXPECTATION_INITIALIZE, BOOST_PP_EMPTY) + {} + template< BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, typename Constraint_) > + expectation& with( + BOOST_PP_ENUM_BINARY_PARAMS(MOCK_NUM_ARGS, Constraint_, c) ) + { + BOOST_PP_REPEAT(MOCK_NUM_ARGS, + MOCK_EXPECTATION_WITH, BOOST_PP_EMPTY) + return *this; + } +#endif + bool is_valid( + BOOST_PP_REPEAT(MOCK_NUM_ARGS, + MOCK_EXPECTATION_ARGS, BOOST_PP_EMPTY) ) const + { + return ! i_->exhausted() + BOOST_PP_REPEAT(MOCK_NUM_ARGS, + MOCK_EXPECTATION_IS_VALID, BOOST_PP_EMPTY); + } + + expectation& in( sequence& s ) + { + add( s.impl_ ); + return *this; + } + expectation& once() + { + expect( new detail::once() ); + return *this; + } + expectation& never() + { + expect( new detail::never() ); + return *this; + } + expectation& exactly( std::size_t count ) + { + expect( new detail::exactly( count ) ); + return *this; + } + expectation& at_least( std::size_t min ) + { + expect( new detail::at_least( min ) ); + return *this; + } + expectation& at_most( std::size_t max ) + { + expect( new detail::at_most( max ) ); + return *this; + } + expectation& between( std::size_t min, std::size_t max ) + { + expect( new detail::between( min, max ) ); + return *this; + } + + friend std::ostream& operator<<( + std::ostream& s, const expectation& m ) + { + return s << (m.i_->exhausted() ? 'v' : '.') + << ' ' << *m.i_ +#ifndef MOCK_NUM_ARGS_0 + << ".with( " + << BOOST_PP_REPEAT(MOCK_NUM_ARGS, + MOCK_EXPECTATION_SERIALIZE, BOOST_PP_EMPTY) + << " )" +#endif + ; + } + private: + BOOST_PP_REPEAT(MOCK_NUM_ARGS, MOCK_EXPECTATION_MEMBER, BOOST_PP_EMPTY) + }; +} +} // mock + +#undef MOCK_EXPECTATION_TYPEDEF +#undef MOCK_EXPECTATION_INITIALIZE +#undef MOCK_EXPECTATION_WITH +#undef MOCK_EXPECTATION_MEMBER +#undef MOCK_EXPECTATION_ARGS +#undef MOCK_EXPECTATION_IS_VALID +#undef MOCK_EXPECTATION_SERIALIZE +#undef MOCK_EXPECTATION diff --git a/turtle/function.hpp b/turtle/function.hpp index 9a637fb..1e29701 100644 --- a/turtle/function.hpp +++ b/turtle/function.hpp @@ -11,309 +11,41 @@ #include "config.hpp" #include "error.hpp" -#include "expectation.hpp" #include "log.hpp" +#include "check.hpp" +#include "action.hpp" +#include "invocation.hpp" +#include "constraints.hpp" +#include "sequence.hpp" #include "detail/verifiable.hpp" #include "detail/type_name.hpp" #include "detail/context.hpp" -#include "detail/args.hpp" -#include -#include -#include #include #include #include #include #include #include +#include #include -#include #include #include +#include #include +#define MOCK_NUM_ARGS 0 +#define MOCK_NUM_ARGS_0 +#include "function_template.hpp" +#undef MOCK_NUM_ARGS_0 +#undef MOCK_NUM_ARGS + +#define BOOST_PP_ITERATION_PARAMS_1 \ + (3,(1,MOCK_MAX_ARGS,"function_iterate.hpp")) +#include BOOST_PP_ITERATE() +#undef BOOST_PP_ITERATION_PARAMS_1 + namespace mock { - template< typename Signature > - class function - { - public: - typedef BOOST_DEDUCED_TYPENAME - boost::function_types::result_type< Signature >::type result_type; - - template< typename Args > - struct sig - { - typedef result_type type; - }; - - private: - typedef BOOST_DEDUCED_TYPENAME - boost::function_types::function_arity< Signature > arity; - typedef BOOST_DEDUCED_TYPENAME - detail::expectation< Signature, arity::value > expectation_type; - - public: - function() - : impl_( new function_impl() ) - {} - - bool verify() const - { - return impl_->verify(); - } - bool verify( const char* file, int line ) const - { - function_impl::error_type::checkpoint( file, line ); - return impl_->verify(); - } - void reset() - { - impl_->reset(); - } - void reset( const char* file, int line ) - { - function_impl::error_type::checkpoint( file, line ); - return impl_->reset(); - } - - expectation_type& expect( const char* file, int line ) - { - function_impl::error_type::checkpoint( file, line ); - return impl_->expect(); - } - expectation_type& expect() - { - return impl_->expect(); - } - - void test() const - { - impl_->test(); - } - - result_type operator()() const - { - return (*impl_)(); - } - -#define MOCK_FUNCTION_OPERATOR(z, n, d) \ - MOCK_DECL(operator(), n, Signature, const, BOOST_DEDUCED_TYPENAME) \ - { \ - return (*impl_)( BOOST_PP_ENUM_PARAMS(n, p) ); \ - } - - BOOST_PP_REPEAT_FROM_TO( - 1, - BOOST_PP_INC(MOCK_MAX_ARGS), - MOCK_FUNCTION_OPERATOR, - BOOST_PP_EMPTY) - -#undef MOCK_FUNCTION_OPERATOR - - friend std::ostream& operator<<( std::ostream& s, const function& e ) - { - return s << *e.impl_; - } - - function& operator()( detail::context& c, - boost::unit_test::const_string instance ) - { - if( ! impl_->context_ ) - c.add( *impl_ ); - c.add( impl_.get(), *impl_, instance, - boost::optional< detail::type_name >(), "" ); - impl_->context_ = &c; - return *this; - } - - void configure( detail::context& c, const void* p, - boost::unit_test::const_string instance, - const boost::optional< detail::type_name >& type, - boost::unit_test::const_string name ) const - { - if( ! impl_->context_ ) - c.add( *impl_ ); - c.add( p, *impl_, instance, type, name ); - impl_->context_ = &c; - } - - private: - class function_impl : public detail::verifiable, - public boost::enable_shared_from_this< function_impl > - { - public: - typedef MOCK_ERROR_POLICY< result_type > error_type; - - public: - function_impl() - : context_( 0 ) - , valid_( true ) - {} - virtual ~function_impl() - { - if( valid_ && ! std::uncaught_exception() ) - for( expectations_cit it = expectations_.begin(); - it != expectations_.end(); ++it ) - { - if( ! it->verify() ) - error_type::untriggered_expectation( - boost::unit_test::lazy_ostream::instance() - << lazy_context( this ) - << lazy_expectations( this ), - it->file(), it->line() ); - else if( ! it->invoked() ) - 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 - { - for( expectations_cit it = expectations_.begin(); - it != expectations_.end(); ++it ) - if( !it->verify() ) - { - valid_ = false; - error_type::verification_failed( - boost::unit_test::lazy_ostream::instance() - << lazy_context( this ) - << lazy_expectations( this ), - it->file(), it->line() ); - } - return valid_; - } - - virtual void reset() - { - valid_ = true; - boost::shared_ptr< function_impl > guard = - this->shared_from_this(); - expectations_.clear(); - } - - expectation_type& expect( const char* file, int line ) - { - expectation_type& e = expect(); - e.set_location( file, line ); - return e; - } - expectation_type& expect() - { - expectations_.push_back( expectation_type() ); - valid_ = true; - return expectations_.back(); - } - -#define MOCK_FUNCTION_FORMAT(z, n, N) \ - << " " << mock::format( p##n ) \ - << BOOST_PP_IF(BOOST_PP_EQUAL(N,n), " ", ",") -#define MOCK_FUNCTION_CONTEXT(n) \ - boost::unit_test::lazy_ostream::instance() \ - << lazy_context( this ) \ - << "(" BOOST_PP_REPEAT(n, MOCK_FUNCTION_FORMAT, BOOST_PP_DEC(n)) \ - << ")" \ - << lazy_expectations( this ) -#define MOCK_FUNCTION_INVOKE(z, n, A) \ - { \ - valid_ = false; \ - for( expectations_cit it = expectations_.begin(); \ - it != expectations_.end(); ++it ) \ - if( it->is_valid( BOOST_PP_ENUM_PARAMS(n, p) ) ) \ - { \ - if( ! it->invoke() ) \ - { \ - error_type::sequence_failed( \ - MOCK_FUNCTION_CONTEXT(n), it->file(), it->line() ); \ - return A; \ - } \ - if( ! it->functor() ) \ - { \ - error_type::missing_action( \ - MOCK_FUNCTION_CONTEXT(n), it->file(), it->line() ); \ - return A; \ - } \ - valid_ = true; \ - error_type::expected_call( \ - MOCK_FUNCTION_CONTEXT(n), it->file(), it->line() ); \ - return it->functor()( BOOST_PP_ENUM_PARAMS(n, p) ); \ - } \ - error_type::unexpected_call( MOCK_FUNCTION_CONTEXT(n) ); \ - return A; \ - } -#define MOCK_FUNCTION_OPERATOR(z, n, P) \ - MOCK_DECL(operator(), n, Signature, const, BOOST_DEDUCED_TYPENAME) \ - MOCK_FUNCTION_INVOKE(z, n, P) - - BOOST_PP_REPEAT( - BOOST_PP_INC(MOCK_MAX_ARGS), - MOCK_FUNCTION_OPERATOR, - error_type::abort()) - - void test() const - MOCK_FUNCTION_INVOKE(, 0,) - -#undef MOCK_FUNCTION_FORMAT -#undef MOCK_FUNCTION_OPERATOR -#undef MOCK_FUNCTION_INVOKE -#undef MOCK_FUNCTION_CONTEXT - - friend std::ostream& operator<<( - std::ostream& s, const function_impl& e ) - { - return s << lazy_context( &e ) << lazy_expectations( &e ); - } - - struct lazy_context - { - lazy_context( const function_impl* impl ) - : impl_( impl ) - {} - friend std::ostream& operator<<( - std::ostream& s, const lazy_context& c ) - { - if( c.impl_->context_ ) - c.impl_->context_->serialize( s, *c.impl_ ); - else - s << "?"; - return s; - } - const function_impl* impl_; - }; - - struct lazy_expectations - { - lazy_expectations( const function_impl* impl ) - : impl_( impl ) - {} - friend std::ostream& operator<<( - std::ostream& s, const lazy_expectations& e ) - { - for( expectations_cit it = e.impl_->expectations_.begin(); - it != e.impl_->expectations_.end(); ++it ) - s << std::endl << *it; - return s; - } - const function_impl* impl_; - }; - - typedef std::list< expectation_type > expectations_type; - typedef BOOST_DEDUCED_TYPENAME - expectations_type::const_iterator expectations_cit; - - expectations_type expectations_; - detail::context* context_; - mutable bool valid_; - }; - - boost::shared_ptr< function_impl > impl_; - }; - template< typename Signature > bool verify( const function< Signature >& f ) { diff --git a/turtle/function_iterate.hpp b/turtle/function_iterate.hpp new file mode 100644 index 0000000..7bf1794 --- /dev/null +++ b/turtle/function_iterate.hpp @@ -0,0 +1,11 @@ +// http://turtle.sourceforge.net +// +// Copyright Mathieu Champlon 2012 +// +// 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) + +#define MOCK_NUM_ARGS BOOST_PP_ITERATION() +#include "function_template.hpp" +#undef MOCK_NUM_ARGS diff --git a/turtle/function_template.hpp b/turtle/function_template.hpp new file mode 100644 index 0000000..87749e0 --- /dev/null +++ b/turtle/function_template.hpp @@ -0,0 +1,275 @@ +// http://turtle.sourceforge.net +// +// Copyright Mathieu Champlon 2008 +// +// 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) + +#include "expectation_template.hpp" + +namespace mock +{ + template< typename Signature > class function; + + template< typename R BOOST_PP_COMMA_IF(MOCK_NUM_ARGS) + BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, typename T) > + class function< R ( BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, T) ) > + { + public: + typedef R result_type; + + template< typename Args > + struct sig + { + typedef R type; + }; + + private: + typedef detail::expectation< + R ( BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, T) ) + > expectation_type; + + public: + function() + : impl_( new function_impl() ) + {} + + bool verify() const + { + return impl_->verify(); + } + bool verify( const char* file, int line ) const + { + function_impl::error_type::checkpoint( file, line ); + return impl_->verify(); + } + void reset() + { + impl_->reset(); + } + void reset( const char* file, int line ) + { + function_impl::error_type::checkpoint( file, line ); + return impl_->reset(); + } + + expectation_type& expect( const char* file, int line ) + { + function_impl::error_type::checkpoint( file, line ); + return impl_->expect(); + } + expectation_type& expect() + { + return impl_->expect(); + } + + void test() const + { + impl_->test(); + } + + R operator()( BOOST_PP_ENUM_BINARY_PARAMS(MOCK_NUM_ARGS, T, t) ) const + { + return (*impl_)( BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, t) ); + } + + friend std::ostream& operator<<( std::ostream& s, const function& e ) + { + return s << *e.impl_; + } + + function& operator()( detail::context& c, + boost::unit_test::const_string instance ) + { + if( ! impl_->context_ ) + c.add( *impl_ ); + c.add( impl_.get(), *impl_, instance, + boost::optional< detail::type_name >(), "" ); + impl_->context_ = &c; + return *this; + } + + void configure( detail::context& c, const void* p, + boost::unit_test::const_string instance, + const boost::optional< detail::type_name >& type, + boost::unit_test::const_string name ) const + { + if( ! impl_->context_ ) + c.add( *impl_ ); + c.add( p, *impl_, instance, type, name ); + impl_->context_ = &c; + } + + private: + class function_impl : public detail::verifiable, + public boost::enable_shared_from_this< function_impl > + { + public: + typedef MOCK_ERROR_POLICY< result_type > error_type; + + public: + function_impl() + : context_( 0 ) + , valid_( true ) + {} + virtual ~function_impl() + { + if( valid_ && ! std::uncaught_exception() ) + for( expectations_cit it = expectations_.begin(); + it != expectations_.end(); ++it ) + { + if( ! it->verify() ) + error_type::untriggered_expectation( + boost::unit_test::lazy_ostream::instance() + << lazy_context( this ) + << lazy_expectations( this ), + it->file(), it->line() ); + else if( ! it->invoked() ) + 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 + { + for( expectations_cit it = expectations_.begin(); + it != expectations_.end(); ++it ) + if( !it->verify() ) + { + valid_ = false; + error_type::verification_failed( + boost::unit_test::lazy_ostream::instance() + << lazy_context( this ) + << lazy_expectations( this ), + it->file(), it->line() ); + } + return valid_; + } + + virtual void reset() + { + valid_ = true; + boost::shared_ptr< function_impl > guard = + this->shared_from_this(); + expectations_.clear(); + } + + expectation_type& expect( const char* file, int line ) + { + expectation_type& e = expect(); + e.set_location( file, line ); + return e; + } + expectation_type& expect() + { + expectations_.push_back( expectation_type() ); + valid_ = true; + return expectations_.back(); + } + +#define MOCK_FORMAT(z, n, N) \ + << " " << mock::format( t##n ) \ + << BOOST_PP_IF(BOOST_PP_EQUAL(N,n), " ", ",") +#define MOCK_CONTEXT(n) \ + boost::unit_test::lazy_ostream::instance() \ + << lazy_context( this ) \ + << "(" BOOST_PP_REPEAT(n, MOCK_FORMAT, BOOST_PP_DEC(n)) \ + << ")" \ + << lazy_expectations( this ) +#define MOCK_INVOKE(z, n, A) \ + { \ + valid_ = false; \ + for( expectations_cit it = expectations_.begin(); \ + it != expectations_.end(); ++it ) \ + if( it->is_valid( BOOST_PP_ENUM_PARAMS(n, t) ) ) \ + { \ + if( ! it->invoke() ) \ + { \ + error_type::sequence_failed( \ + MOCK_CONTEXT(n), it->file(), it->line() ); \ + return A; \ + } \ + if( ! it->functor() ) \ + { \ + error_type::missing_action( \ + MOCK_CONTEXT(n), it->file(), it->line() ); \ + return A; \ + } \ + valid_ = true; \ + error_type::expected_call( \ + MOCK_CONTEXT(n), it->file(), it->line() ); \ + return it->functor()( BOOST_PP_ENUM_PARAMS(n, t) ); \ + } \ + error_type::unexpected_call( MOCK_CONTEXT(n) ); \ + return A; \ + } + + result_type operator()( + BOOST_PP_ENUM_BINARY_PARAMS(MOCK_NUM_ARGS, T, t) ) const + MOCK_INVOKE(, MOCK_NUM_ARGS, error_type::abort()) + + void test() const + MOCK_INVOKE(, 0,) + +#undef MOCK_FORMAT +#undef MOCK_OPERATOR +#undef MOCK_INVOKE +#undef MOCK_CONTEXT + + friend std::ostream& operator<<( + std::ostream& s, const function_impl& e ) + { + return s << lazy_context( &e ) << lazy_expectations( &e ); + } + + struct lazy_context + { + lazy_context( const function_impl* impl ) + : impl_( impl ) + {} + friend std::ostream& operator<<( + std::ostream& s, const lazy_context& c ) + { + if( c.impl_->context_ ) + c.impl_->context_->serialize( s, *c.impl_ ); + else + s << "?"; + return s; + } + const function_impl* impl_; + }; + + struct lazy_expectations + { + lazy_expectations( const function_impl* impl ) + : impl_( impl ) + {} + friend std::ostream& operator<<( + std::ostream& s, const lazy_expectations& e ) + { + for( expectations_cit it = e.impl_->expectations_.begin(); + it != e.impl_->expectations_.end(); ++it ) + s << std::endl << *it; + return s; + } + const function_impl* impl_; + }; + + typedef std::list< expectation_type > expectations_type; + typedef BOOST_DEDUCED_TYPENAME + expectations_type::const_iterator expectations_cit; + + expectations_type expectations_; + detail::context* context_; + mutable bool valid_; + }; + + boost::shared_ptr< function_impl > impl_; + }; +} // mock