An expectation is a functor

git-svn-id: https://svn.code.sf.net/p/turtle/code/trunk@18 860be788-9bd5-4423-9f1e-828f051e677b
This commit is contained in:
mat007 2009-09-01 12:25:40 +00:00
parent 135846946f
commit 60d5c263a6
2 changed files with 174 additions and 111 deletions

View file

@ -32,172 +32,229 @@ namespace mock
typename ErrorPolicy = boost_test_error_policy< typename ErrorPolicy = boost_test_error_policy<
BOOST_DEDUCED_TYPENAME boost::function< BOOST_DEDUCED_TYPENAME boost::function<
Signature >::result_type > > // $$$$ MAT : concept check Signature is actually a signature Signature >::result_type > > // $$$$ MAT : concept check Signature is actually a signature
class expectation : private verifiable class expectation
{ {
public: public:
typedef BOOST_DEDUCED_TYPENAME typedef BOOST_DEDUCED_TYPENAME
boost::function< Signature >::result_type result_type; boost::function< Signature >::result_type result_type;
private:
typedef detail::matcher< result_type, typedef detail::matcher< result_type,
Signature, Signature,
ErrorPolicy, ErrorPolicy,
boost::function< Signature >::arity > boost::function< Signature >::arity >
matcher_type; matcher_type;
public:
expectation( node& parent = root, const std::string& name = "?" ) expectation( node& parent = root, const std::string& name = "?" )
: name_( name ) : impl_( new expectation_impl( parent, name ) )
, parent_( &parent ) {}
, valid_( true )
{
parent_->add( *this );
}
expectation( const std::string& name ) expectation( const std::string& name )
: name_( name ) : impl_( new expectation_impl( root, name ) )
, parent_( &root ) {}
, valid_( true )
{
parent_->add( *this );
}
virtual ~expectation()
{
parent_->remove( *this );
if( ! std::uncaught_exception() )
for( matchers_cit it = matchers_.begin();
it != matchers_.end(); ++it )
if( valid_ && ! it->verify() )
ErrorPolicy::untriggered_expectation(
context(), it->file(), it->line() );
}
expectation& set_name( const std::string& name ) expectation& set_name( const std::string& name )
{ {
name_ = name; impl_->set_name( name );
return *this; return *this;
} }
expectation& set_parent( node& parent ) expectation& set_parent( node& parent )
{ {
parent_->remove( *this ); impl_->set_parent( parent );
parent.add( *this );
parent_ = &parent;
return *this; return *this;
} }
virtual bool verify() bool verify()
{ {
for( matchers_cit it = matchers_.begin(); return impl_->verify();
it != matchers_.end(); ++it )
if( !it->verify() )
{
valid_ = false;
ErrorPolicy::verification_failed( context(),
it->file(), it->line() );
}
return valid_;
} }
virtual void reset() void reset()
{ {
valid_ = true; impl_->reset();
matchers_.clear();
} }
matcher_type& expect( const std::string& file, int line ) matcher_type& expect( const std::string& file, int line )
{ {
matchers_.push_back( matcher_type() ); return impl_->expect( file, line );
matchers_.back().set_location( file, line );
valid_ = true;
return matchers_.back();
} }
matcher_type& expect() matcher_type& expect()
{ {
matchers_.push_back( matcher_type() ); return impl_->expect();
valid_ = true;
return matchers_.back();
} }
result_type operator()() const result_type operator()() const
{ {
for( matchers_cit it = matchers_.begin(); return (*impl_)();
it != matchers_.end(); ++it ) }
if( it->is_valid() )
{ #define MOCK_EXPECTATION_OPERATOR(z, n, d) \
if( !it->invoke() ) template< BOOST_PP_ENUM_PARAMS(n, typename A) > \
result_type operator()( BOOST_PP_ENUM_BINARY_PARAMS(n, const A, & a) ) const \
{ \
return (*impl_)( BOOST_PP_ENUM_PARAMS(n, a) ); \
}
BOOST_PP_REPEAT_FROM_TO(1, MOCK_MAX_ARGS, MOCK_EXPECTATION_OPERATOR, BOOST_PP_EMPTY)
#undef MOCK_EXPECTATION_OPERATOR
friend std::ostream& operator<<( std::ostream& s, const expectation& e )
{
return s << *e.impl_;
}
private:
class expectation_impl : private verifiable
{
public:
expectation_impl( node& parent, const std::string& name )
: name_( name )
, parent_( &parent )
, valid_( true )
{
parent_->add( *this );
}
virtual ~expectation_impl()
{
parent_->remove( *this );
if( ! std::uncaught_exception() )
for( matchers_cit it = matchers_.begin();
it != matchers_.end(); ++it )
if( valid_ && ! it->verify() )
ErrorPolicy::untriggered_expectation(
context(), it->file(), it->line() );
}
void set_name( const std::string& name )
{
name_ = name;
}
void set_parent( node& parent )
{
parent_->remove( *this );
parent.add( *this );
parent_ = &parent;
}
virtual bool verify()
{
for( matchers_cit it = matchers_.begin();
it != matchers_.end(); ++it )
if( !it->verify() )
{ {
valid_ = false; valid_ = false;
ErrorPolicy::sequence_failed( context( "" ), ErrorPolicy::verification_failed( context(),
it->file(), it->line() ); it->file(), it->line() );
} }
return it->functor()(); return valid_;
} }
valid_ = false; virtual void reset()
return ErrorPolicy::no_match( context( "" ) ); {
} valid_ = true;
matchers_.clear();
}
matcher_type& expect( const std::string& file, int line )
{
matchers_.push_back( matcher_type() );
matchers_.back().set_location( file, line );
valid_ = true;
return matchers_.back();
}
matcher_type& expect()
{
matchers_.push_back( matcher_type() );
valid_ = true;
return matchers_.back();
}
result_type operator()() const
{
for( matchers_cit it = matchers_.begin();
it != matchers_.end(); ++it )
if( it->is_valid() )
{
if( !it->invoke() )
{
valid_ = false;
ErrorPolicy::sequence_failed( context( "" ),
it->file(), it->line() );
}
return it->functor()();
}
valid_ = false;
return ErrorPolicy::no_match( context( "" ) );
}
#define MOCK_EXPECTATION_PARAMETER(z, n, d) BOOST_PP_COMMA_IF(n) const_cast< A##n & >( a##n ) #define MOCK_EXPECTATION_PARAMETER(z, n, d) BOOST_PP_COMMA_IF(n) const_cast< A##n & >( a##n )
#define MOCK_EXPECTATION_DETAIL(z, n, d) + ", " + format( a##n ) #define MOCK_EXPECTATION_DETAIL(z, n, d) + ", " + format( a##n )
#define MOCK_EXPECTATION_PARAMETERS(n) \ #define MOCK_EXPECTATION_PARAMETERS(n) \
format( a0 ) BOOST_PP_REPEAT_FROM_TO(1, n, MOCK_EXPECTATION_DETAIL, BOOST_PP_EMPTY) format( a0 ) BOOST_PP_REPEAT_FROM_TO(1, n, MOCK_EXPECTATION_DETAIL, BOOST_PP_EMPTY)
#define MOCK_EXPECTATION_OPERATOR(z, n, d) \ #define MOCK_EXPECTATION_OPERATOR(z, n, d) \
template< BOOST_PP_ENUM_PARAMS(n, typename A) > \ template< BOOST_PP_ENUM_PARAMS(n, typename A) > \
result_type operator()( BOOST_PP_ENUM_BINARY_PARAMS(n, const A, & a) ) const \ result_type operator()( BOOST_PP_ENUM_BINARY_PARAMS(n, const A, & a) ) const \
{ \ { \
for( matchers_cit it = matchers_.begin(); it != matchers_.end(); ++it ) \ for( matchers_cit it = matchers_.begin(); it != matchers_.end(); ++it ) \
if( it->is_valid( BOOST_PP_REPEAT_FROM_TO(0, n, MOCK_EXPECTATION_PARAMETER, BOOST_PP_EMPTY) ) ) \ if( it->is_valid( BOOST_PP_REPEAT_FROM_TO(0, n, MOCK_EXPECTATION_PARAMETER, BOOST_PP_EMPTY) ) ) \
{ \
if( !it->invoke() ) \
{ \ { \
valid_ = false; \ if( !it->invoke() ) \
ErrorPolicy::sequence_failed( context( MOCK_EXPECTATION_PARAMETERS(n) ), it->file(), it->line() ); \ { \
valid_ = false; \
ErrorPolicy::sequence_failed( context( MOCK_EXPECTATION_PARAMETERS(n) ), it->file(), it->line() ); \
} \
return it->functor()( BOOST_PP_REPEAT_FROM_TO(0, n, MOCK_EXPECTATION_PARAMETER, BOOST_PP_EMPTY) ); \
} \ } \
return it->functor()( BOOST_PP_REPEAT_FROM_TO(0, n, MOCK_EXPECTATION_PARAMETER, BOOST_PP_EMPTY) ); \ valid_ = false; \
} \ return ErrorPolicy::no_match( context( MOCK_EXPECTATION_PARAMETERS(n) ) ); \
valid_ = false; \ }
return ErrorPolicy::no_match( context( MOCK_EXPECTATION_PARAMETERS(n) ) ); \ BOOST_PP_REPEAT_FROM_TO(1, MOCK_MAX_ARGS, MOCK_EXPECTATION_OPERATOR, BOOST_PP_EMPTY)
}
BOOST_PP_REPEAT_FROM_TO(1, MOCK_MAX_ARGS, MOCK_EXPECTATION_OPERATOR, BOOST_PP_EMPTY)
#undef MOCK_EXPECTATION_PARAMETER #undef MOCK_EXPECTATION_PARAMETER
#undef MOCK_EXPECTATION_PARAMETERS #undef MOCK_EXPECTATION_PARAMETERS
#undef MOCK_EXPECTATION_DETAIL #undef MOCK_EXPECTATION_DETAIL
#undef MOCK_EXPECTATION_OPERATOR #undef MOCK_EXPECTATION_OPERATOR
friend std::ostream& operator<<( std::ostream& s, const expectation& e ) friend std::ostream& operator<<( std::ostream& s, const expectation_impl& e )
{ {
return s << e.context(); return s << e.context();
} }
private:
typedef std::list< matcher_type > matchers_type;
typedef BOOST_DEDUCED_TYPENAME
matchers_type::const_iterator matchers_cit;
void serialize( std::ostream& s ) const
{
for( matchers_cit it = matchers_.begin();
it != matchers_.end(); ++it )
s << std::endl << *it;
}
std::string context() const
{
std::stringstream s;
s << *parent_ << name_;
serialize( s );
return s.str();
}
std::string context( const std::string& parameters ) const
{
std::stringstream s;
s << *parent_ << name_;
if( parameters.empty() )
s << "()";
else
s << "( " << parameters << " )";
serialize( s );
return s.str();
}
std::string name_;
node* parent_;
mutable bool valid_;
matchers_type matchers_;
};
private: private:
typedef std::list< matcher_type > matchers_type; boost::shared_ptr< expectation_impl > impl_;
typedef BOOST_DEDUCED_TYPENAME
matchers_type::const_iterator matchers_cit;
void serialize( std::ostream& s ) const
{
for( matchers_cit it = matchers_.begin();
it != matchers_.end(); ++it )
s << std::endl << *it;
}
std::string context() const
{
std::stringstream s;
s << *parent_ << name_;
serialize( s );
return s.str();
}
std::string context( const std::string& parameters ) const
{
std::stringstream s;
s << *parent_ << name_;
if( parameters.empty() )
s << "()";
else
s << "( " << parameters << " )";
serialize( s );
return s.str();
}
std::string name_;
node* parent_;
mutable bool valid_;
matchers_type matchers_;
}; };
} }

View file

@ -26,6 +26,12 @@ namespace
// functor // functor
BOOST_AUTO_TEST_CASE( an_expectation_can_be_passed_as_functor )
{
mock::expectation< void() > e;
boost::function< void() > f = e;
}
BOOST_AUTO_TEST_CASE( an_expectation_can_be_passed_as_functor_using_boost_bind_and_boost_ref ) BOOST_AUTO_TEST_CASE( an_expectation_can_be_passed_as_functor_using_boost_bind_and_boost_ref )
{ {
mock::expectation< void() > e; mock::expectation< void() > e;