// 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_ACTION_HPP_INCLUDED #define MOCK_ACTION_HPP_INCLUDED #include "../config.hpp" #include #include #include #include #include #include #include #include namespace mock { namespace detail { template< typename Result, typename Signature > class action_base { private: typedef boost::function< Signature > functor_type; typedef boost::function< Result() > action_type; public: const functor_type& functor() const { return f_; } bool valid() const { return f_ || a_; } Result trigger() const { return a_(); } void calls( const functor_type& f ) { if( ! f ) throw std::invalid_argument( "null functor" ); f_ = f; } template< typename Exception > void throws( Exception e ) { a_ = boost::bind( &do_throw< Exception >, e ); } protected: void set( const action_type& a ) { a_ = a; } template< typename Y > void set( const boost::reference_wrapper< Y >& r ) { a_ = boost::bind( &do_ref< Y >, r.get_pointer() ); } private: template< typename T > static T& do_ref( T* t ) { return *t; } template< typename T > static Result do_throw( T t ) { throw t; } functor_type f_; action_type a_; }; template< typename Result, typename Signature > class action : public action_base< Result, Signature > { public: template< typename Value > void returns( const Value& v ) { returns( boost::ref( v_.store( v ) ) ); } template< typename Value > void returns( Value* v ) { typedef typename boost::remove_reference< typename boost::remove_const< Result >::type >::type result_type; returns( result_type( v ) ); } template< typename Y > void returns( const boost::reference_wrapper< Y >& r ) { this->set( r ); } template< typename Value > void moves( BOOST_RV_REF( Value ) v ) { this->set( boost::bind( &boost::move< BOOST_RV_REF( Value ) >, boost::ref( v_.store( boost::move( v ) ) ) ) ); } private: struct value { struct holder : boost::noncopyable { virtual ~holder() {} }; template< typename T > struct holder_imp : holder { holder_imp( BOOST_RV_REF( T ) t ) : t_( boost::move( t ) ) {} holder_imp( const T& t ) : t_( t ) {} T t_; }; template< typename T > T& store( BOOST_RV_REF( T ) t ) { h_.reset( new holder_imp< T >( boost::move( t ) ) ); return static_cast< holder_imp< T >& >( *h_ ).t_; } template< typename T > T& store( const T& t ) { h_.reset( new holder_imp< T >( t ) ); return static_cast< holder_imp< T >& >( *h_ ).t_; } boost::shared_ptr< holder > h_; }; value v_; }; template< typename Result, typename Signature > class action< Result*, Signature > : public action_base< Result*, Signature > { public: void returns( Result* r ) { this->set( boost::bind( &do_val< Result* >, r ) ); } template< typename Y > void returns( const boost::reference_wrapper< Y >& r ) { this->set( r ); } private: template< typename T > static T do_val( T t ) { return t; } }; template< typename Signature > class action< void, Signature > : public action_base< void, Signature > { public: action() { this->set( boost::bind( &do_nothing ) ); } private: static void do_nothing() {} }; template< typename Result, typename Signature > class action< std::auto_ptr< Result >, Signature > : public action_base< std::auto_ptr< Result >, Signature > { public: action() {} action( const action& rhs ) : v_( rhs.v_.release() ) { if( v_.get() ) returns( boost::ref( v_ ) ); } template< typename Y > void returns( Y* r ) { v_.reset( r ); returns( boost::ref( v_ ) ); } template< typename Y > void returns( std::auto_ptr< Y > r ) { v_ = r; returns( boost::ref( v_ ) ); } template< typename Y > void returns( const boost::reference_wrapper< Y >& r ) { this->set( r ); } private: mutable std::auto_ptr< Result > v_; }; } } // mock #endif // MOCK_ACTION_HPP_INCLUDED