Merge from refactoring branch

git-svn-id: https://svn.code.sf.net/p/turtle/code/trunk@53 860be788-9bd5-4423-9f1e-828f051e677b
This commit is contained in:
mat007 2009-09-26 13:23:32 +00:00
parent be0af3d224
commit 3f118a8164
14 changed files with 498 additions and 257 deletions

View file

@ -9,8 +9,6 @@
#ifndef MOCK_ERROR_HPP_INCLUDED
#define MOCK_ERROR_HPP_INCLUDED
#include <stdexcept>
#include <string>
#include <boost/test/test_tools.hpp>
#include <boost/test/execution_monitor.hpp>
#include <boost/test/utils/trivial_singleton.hpp>
@ -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,

View file

@ -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

View file

@ -12,6 +12,7 @@
#include "error.hpp"
#include "object.hpp"
#include "expectation.hpp"
#include "type_name.hpp"
#include <boost/function.hpp>
#include <boost/preprocessor/cat.hpp>
#include <boost/preprocessor/inc.hpp>
@ -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

View file

@ -10,41 +10,18 @@
#define MOCK_NODE_HPP_INCLUDED
#include "verifiable.hpp"
#include <vector>
#include <algorithm>
#include <boost/noncopyable.hpp>
#include <functional>
#include <string>
#include <algorithm>
#include <ostream>
#include <vector>
#include <string>
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_;
};
}

View file

@ -11,36 +11,61 @@
#include "node.hpp"
#include "root.hpp"
#include <string>
#include <boost/shared_ptr.hpp>
#include <ostream>
#include <string>
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_;
};
}

View file

@ -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 <stdexcept>
#include <typeinfo>
#ifdef __GNUC__
#include <cxxabi.h>
#include <memory.h>
#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

View file

@ -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;