mirror of
https://github.com/mat007/turtle.git
synced 2026-06-22 12:13:43 +00:00
Added thread-safety
git-svn-id: https://svn.code.sf.net/p/turtle/code/trunk@730 860be788-9bd5-4423-9f1e-828f051e677b
This commit is contained in:
parent
f1580c95cc
commit
086a42e432
15 changed files with 464 additions and 12 deletions
|
|
@ -144,4 +144,14 @@ The policy can then be activated by defining MOCK_ERROR_POLICY prior to includin
|
|||
|
||||
[endsect]
|
||||
|
||||
[section Thread safety]
|
||||
|
||||
Thread safety is not activated by default however defining MOCK_THREAD_SAFE before including the library will make creations and calls to mock objects thread-safe :
|
||||
|
||||
[thread_safe]
|
||||
|
||||
If available the library will rely on the C++11 standard mutexes and locks, otherwise Boost.Thread will be used.
|
||||
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
||||
|
|
|
|||
|
|
@ -171,3 +171,8 @@ struct custom_policy
|
|||
#define MOCK_ERROR_POLICY custom_policy
|
||||
#include <turtle/mock.hpp>
|
||||
//]
|
||||
|
||||
//[ thread_safe
|
||||
#define MOCK_THREAD_SAFE
|
||||
#include <turtle/mock.hpp>
|
||||
//]
|
||||
|
|
|
|||
|
|
@ -39,6 +39,9 @@
|
|||
<build-turtle-test name="turtle_no_variadic_macros">
|
||||
<defineset define="MOCK_NO_VARIADIC_MACROS"/>
|
||||
</build-turtle-test>
|
||||
<build-turtle-test name="turtle_thread_safe">
|
||||
<defineset define="MOCK_THREAD_SAFE"/>
|
||||
</build-turtle-test>
|
||||
</target>
|
||||
|
||||
<target name="analyse" description="run errors analyser">
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@
|
|||
<ClInclude Include="..\..\turtle\detail\is_functor.hpp" />
|
||||
<ClInclude Include="..\..\turtle\detail\lambda.hpp" />
|
||||
<ClInclude Include="..\..\turtle\detail\matcher_base.hpp" />
|
||||
<ClInclude Include="..\..\turtle\detail\mutex.hpp" />
|
||||
<ClInclude Include="..\..\turtle\detail\object_impl.hpp" />
|
||||
<ClInclude Include="..\..\turtle\detail\parameter.hpp" />
|
||||
<ClInclude Include="..\..\turtle\detail\parent.hpp" />
|
||||
|
|
|
|||
|
|
@ -127,5 +127,8 @@
|
|||
<ClInclude Include="..\..\turtle\detail\addressof.hpp">
|
||||
<Filter>Source Files\detail</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\turtle\detail\mutex.hpp">
|
||||
<Filter>Source Files\detail</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
@ -846,3 +846,33 @@ BOOST_FIXTURE_TEST_CASE( adding_file_and_line_number_information, mock_error_fix
|
|||
BOOST_CHECK_EQUAL( "file name", mock_error_data.last_file );
|
||||
BOOST_CHECK_EQUAL( 42, mock_error_data.last_line );
|
||||
}
|
||||
|
||||
#ifdef MOCK_THREAD_SAFE
|
||||
|
||||
#include <boost/thread.hpp>
|
||||
|
||||
namespace
|
||||
{
|
||||
void iterate( mock::detail::function< int() >& f )
|
||||
{
|
||||
f.expect().once().returns( 0 );
|
||||
try
|
||||
{
|
||||
f();
|
||||
}
|
||||
catch( ... )
|
||||
{}
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_FIXTURE_TEST_CASE( function_is_thread_safe, mock_error_fixture )
|
||||
{
|
||||
mock::detail::function< int() > f;
|
||||
boost::thread_group group;
|
||||
for( int i = 0; i < 100; ++i )
|
||||
group.create_thread( boost::bind( &iterate, boost::ref( f ) ) );
|
||||
group.join_all();
|
||||
CHECK_CALLS( 100 );
|
||||
}
|
||||
|
||||
#endif // MOCK_THREAD_SAFE
|
||||
|
|
|
|||
|
|
@ -576,3 +576,78 @@ namespace
|
|||
MOCK_BASE_CLASS( my_comma_mock, my_base< int BOOST_PP_COMMA() int > )
|
||||
{};
|
||||
}
|
||||
|
||||
#ifdef MOCK_THREAD_SAFE
|
||||
|
||||
#include <boost/thread.hpp>
|
||||
|
||||
namespace
|
||||
{
|
||||
void create_class()
|
||||
{
|
||||
my_mock m;
|
||||
MOCK_EXPECT( m.my_tag ).once().with( 3 ).returns( 42 );
|
||||
try
|
||||
{
|
||||
m.my_method( 3 );
|
||||
}
|
||||
catch( ... )
|
||||
{}
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_FIXTURE_TEST_CASE( mock_class_creation_is_thread_safe, mock_error_fixture )
|
||||
{
|
||||
boost::thread_group group;
|
||||
for( int i = 0; i < 100; ++i )
|
||||
group.create_thread( &create_class );
|
||||
group.join_all();
|
||||
CHECK_CALLS( 100 );
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
void create_functor( int i )
|
||||
{
|
||||
mock::detail::functor< void( int ) > f;
|
||||
boost::this_thread::sleep( boost::posix_time::milliseconds( 100 ) );
|
||||
mock::detail::functor< void( int ) > f_mock;
|
||||
MOCK_EXPECT( f ).once().with( i );
|
||||
try
|
||||
{
|
||||
f( i );
|
||||
}
|
||||
catch( ... )
|
||||
{}
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_FIXTURE_TEST_CASE( mock_functor_creation_is_thread_safe, mock_error_fixture )
|
||||
{
|
||||
boost::thread_group group;
|
||||
for( int i = 0; i < 100; ++i )
|
||||
group.create_thread( boost::bind( &create_functor, i ) );
|
||||
group.join_all();
|
||||
CHECK_CALLS( 100 );
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
void iterate( my_mock& m )
|
||||
{
|
||||
MOCK_EXPECT( m.my_tag ).once().with( 3 ).returns( 42 );
|
||||
BOOST_CHECK_EQUAL( 42, m.my_method( 3 ) );
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_FIXTURE_TEST_CASE( mock_class_is_thread_safe, mock_error_fixture )
|
||||
{
|
||||
my_mock m;
|
||||
boost::thread_group group;
|
||||
for( int i = 0; i < 100; ++i )
|
||||
group.create_thread( boost::bind( &iterate, boost::ref( m ) ) );
|
||||
group.join_all();
|
||||
CHECK_CALLS( 100 );
|
||||
}
|
||||
|
||||
#endif // MOCK_THREAD_SAFE
|
||||
|
|
|
|||
|
|
@ -83,4 +83,10 @@
|
|||
# endif
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_HDR_MUTEX) && !defined(BOOST_NO_0X_HDR_MUTEX)
|
||||
# ifndef MOCK_NO_HDR_MUTEX
|
||||
# define MOCK_HDR_MUTEX
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#endif // MOCK_CONFIG_HPP_INCLUDED
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
#include "invocation.hpp"
|
||||
#include "type_name.hpp"
|
||||
#include "context.hpp"
|
||||
#include "mutex.hpp"
|
||||
#include <boost/preprocessor/iteration/iterate.hpp>
|
||||
#include <boost/preprocessor/repetition/repeat_from_to.hpp>
|
||||
#include <boost/preprocessor/repetition/enum_params.hpp>
|
||||
|
|
@ -35,6 +36,57 @@
|
|||
#include <vector>
|
||||
#include <list>
|
||||
|
||||
namespace mock
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
template< typename R, typename E >
|
||||
struct wrapper_base
|
||||
{
|
||||
wrapper_base( E& e )
|
||||
: e_( &e )
|
||||
{}
|
||||
|
||||
template< typename T >
|
||||
void returns( T t )
|
||||
{
|
||||
e_->returns( t );
|
||||
}
|
||||
|
||||
E* e_;
|
||||
};
|
||||
template< typename E >
|
||||
struct wrapper_base< void, E >
|
||||
{
|
||||
wrapper_base( E& e )
|
||||
: e_( &e )
|
||||
{}
|
||||
|
||||
E* e_;
|
||||
};
|
||||
template< typename R, typename E >
|
||||
struct wrapper_base< R*, E >
|
||||
{
|
||||
wrapper_base( E& e )
|
||||
: e_( &e )
|
||||
{}
|
||||
|
||||
void returns( R* r )
|
||||
{
|
||||
e_->returns( r );
|
||||
}
|
||||
template< typename Y >
|
||||
void returns( const boost::reference_wrapper< Y >& r )
|
||||
{
|
||||
e_->returns( r );
|
||||
}
|
||||
|
||||
E* e_;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#define MOCK_NUM_ARGS 0
|
||||
#define MOCK_NUM_ARGS_0
|
||||
#include "function_template.hpp"
|
||||
|
|
|
|||
|
|
@ -37,8 +37,7 @@ namespace detail
|
|||
function_impl< R ( BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, T) )> >
|
||||
{
|
||||
public:
|
||||
typedef MOCK_ERROR_POLICY< R > error_type;
|
||||
|
||||
typedef safe_error< R, MOCK_ERROR_POLICY< R > > error_type;
|
||||
typedef expectation<
|
||||
R ( BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, T) )
|
||||
> expectation_type;
|
||||
|
|
@ -47,6 +46,7 @@ namespace detail
|
|||
function_impl()
|
||||
: context_( 0 )
|
||||
, valid_( true )
|
||||
, mutex_( boost::make_shared< mutex >() )
|
||||
{}
|
||||
virtual ~function_impl()
|
||||
{
|
||||
|
|
@ -56,13 +56,16 @@ namespace detail
|
|||
if( ! it->verify() )
|
||||
error_type::fail( "untriggered expectation",
|
||||
boost::unit_test::lazy_ostream::instance()
|
||||
<< *this, it->file(), it->line() );
|
||||
<< lazy_context( this )
|
||||
<< lazy_expectations( this ),
|
||||
it->file(), it->line() );
|
||||
if( context_ )
|
||||
context_->remove( *this );
|
||||
}
|
||||
|
||||
virtual bool verify() const
|
||||
{
|
||||
lock _( mutex_ );
|
||||
for( expectations_cit it = expectations_.begin();
|
||||
it != expectations_.end(); ++it )
|
||||
if( ! it->verify() )
|
||||
|
|
@ -70,35 +73,128 @@ namespace detail
|
|||
valid_ = false;
|
||||
error_type::fail( "verification failed",
|
||||
boost::unit_test::lazy_ostream::instance()
|
||||
<< *this, it->file(), it->line() );
|
||||
<< lazy_context( this )
|
||||
<< lazy_expectations( this ),
|
||||
it->file(), it->line() );
|
||||
}
|
||||
return valid_;
|
||||
}
|
||||
|
||||
virtual void reset()
|
||||
{
|
||||
lock _( mutex_ );
|
||||
valid_ = true;
|
||||
boost::shared_ptr< function_impl > guard =
|
||||
this->shared_from_this();
|
||||
expectations_.clear();
|
||||
}
|
||||
|
||||
expectation_type& expect( const char* file, int line )
|
||||
private:
|
||||
template< typename T >
|
||||
struct wrapper : wrapper_base< T, expectation_type >
|
||||
{
|
||||
wrapper( const boost::shared_ptr< mutex >& m, expectation_type& e )
|
||||
: wrapper_base< T, expectation_type >( e )
|
||||
, lock_( m )
|
||||
{}
|
||||
|
||||
wrapper once()
|
||||
{
|
||||
this->e_->once();
|
||||
return *this;
|
||||
}
|
||||
wrapper never()
|
||||
{
|
||||
this->e_->never();
|
||||
return *this;
|
||||
}
|
||||
wrapper exactly( std::size_t count )
|
||||
{
|
||||
this->e_->exactly( count );
|
||||
return *this;
|
||||
}
|
||||
wrapper at_least( std::size_t min )
|
||||
{
|
||||
this->e_->at_least( min );
|
||||
return *this;
|
||||
}
|
||||
wrapper at_most( std::size_t max )
|
||||
{
|
||||
this->e_->at_most( max );
|
||||
return *this;
|
||||
}
|
||||
wrapper between( std::size_t min, std::size_t max )
|
||||
{
|
||||
this->e_->between( min, max );
|
||||
return *this;
|
||||
}
|
||||
|
||||
#ifndef MOCK_NUM_ARGS_0
|
||||
template<
|
||||
BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, typename Constraint_)
|
||||
>
|
||||
wrapper with(
|
||||
BOOST_PP_ENUM_BINARY_PARAMS(MOCK_NUM_ARGS, Constraint_, c) )
|
||||
{
|
||||
this->e_->with(
|
||||
BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, c) );
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
#define MOCK_FUNCTION_IN(z, n, d) \
|
||||
wrapper in( BOOST_PP_ENUM_PARAMS(n, sequence& s) ) \
|
||||
{ \
|
||||
this->e_->in( BOOST_PP_ENUM_PARAMS(n, s) ); \
|
||||
return *this; \
|
||||
}
|
||||
|
||||
BOOST_PP_REPEAT(MOCK_MAX_SEQUENCES,
|
||||
MOCK_FUNCTION_IN, _)
|
||||
|
||||
#undef MOCK_FUNCTION_IN
|
||||
|
||||
template< typename TT >
|
||||
void calls( TT t )
|
||||
{
|
||||
this->e_->calls( t );
|
||||
}
|
||||
template< typename TT >
|
||||
void throws( TT t )
|
||||
{
|
||||
this->e_->throws( t );
|
||||
}
|
||||
template< typename TT >
|
||||
void moves( TT t )
|
||||
{
|
||||
this->e_->moves( t );
|
||||
}
|
||||
|
||||
lock lock_;
|
||||
};
|
||||
|
||||
public:
|
||||
typedef wrapper< R > wrapper_type;
|
||||
|
||||
wrapper_type expect( const char* file, int line )
|
||||
{
|
||||
lock _( mutex_ );
|
||||
expectations_.push_back( expectation_type( file, line ) );
|
||||
valid_ = true;
|
||||
return expectations_.back();
|
||||
return wrapper_type( mutex_, expectations_.back() );
|
||||
}
|
||||
expectation_type& expect()
|
||||
wrapper_type expect()
|
||||
{
|
||||
lock _( mutex_ );
|
||||
expectations_.push_back( expectation_type() );
|
||||
valid_ = true;
|
||||
return expectations_.back();
|
||||
return wrapper_type( mutex_, expectations_.back() );
|
||||
}
|
||||
|
||||
R operator()(
|
||||
BOOST_PP_ENUM_BINARY_PARAMS(MOCK_NUM_ARGS, T, t) ) const
|
||||
{
|
||||
lock _( mutex_ );
|
||||
valid_ = false;
|
||||
for( expectations_cit it = expectations_.begin();
|
||||
it != expectations_.end(); ++it )
|
||||
|
|
@ -132,6 +228,7 @@ namespace detail
|
|||
boost::optional< type_name > type,
|
||||
boost::unit_test::const_string name )
|
||||
{
|
||||
lock _( mutex_ );
|
||||
if( ! context_ )
|
||||
c.add( *this );
|
||||
c.add( p, *this, instance, type, name );
|
||||
|
|
@ -141,6 +238,7 @@ namespace detail
|
|||
friend std::ostream& operator<<(
|
||||
std::ostream& s, const function_impl& impl )
|
||||
{
|
||||
lock _( impl.mutex_ );
|
||||
return s << lazy_context( &impl ) << lazy_expectations( &impl );
|
||||
}
|
||||
|
||||
|
|
@ -183,6 +281,7 @@ namespace detail
|
|||
expectations_type expectations_;
|
||||
context* context_;
|
||||
mutable bool valid_;
|
||||
const boost::shared_ptr< mutex > mutex_;
|
||||
};
|
||||
}
|
||||
} // mock
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ namespace detail
|
|||
typedef function_impl<
|
||||
R ( BOOST_PP_REPEAT(MOCK_NUM_ARGS, MOCK_FUNCTION_CALL, _) )
|
||||
> impl_type;
|
||||
typedef typename impl_type::expectation_type expectation_type;
|
||||
typedef typename impl_type::wrapper_type expectation_type;
|
||||
typedef typename impl_type::error_type error_type;
|
||||
|
||||
public:
|
||||
|
|
@ -65,12 +65,12 @@ namespace detail
|
|||
impl_->reset();
|
||||
}
|
||||
|
||||
expectation_type& expect( const char* file, int line )
|
||||
expectation_type expect( const char* file, int line )
|
||||
{
|
||||
error_type::pass( file, line );
|
||||
return impl_->expect( file, line );
|
||||
}
|
||||
expectation_type& expect()
|
||||
expectation_type expect()
|
||||
{
|
||||
return impl_->expect();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
#include "../config.hpp"
|
||||
#include "function.hpp"
|
||||
#include "mutex.hpp"
|
||||
|
||||
namespace mock
|
||||
{
|
||||
|
|
@ -21,14 +22,20 @@ namespace detail
|
|||
{
|
||||
functor()
|
||||
{
|
||||
static mutex m_;
|
||||
scoped_lock _( m_ );
|
||||
static functor* f = 0;
|
||||
if( f )
|
||||
{
|
||||
*this = *f;
|
||||
f = 0;
|
||||
m_.unlock();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_.lock();
|
||||
f = this;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
|||
141
turtle/detail/mutex.hpp
Normal file
141
turtle/detail/mutex.hpp
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
// http://turtle.sourceforge.net
|
||||
//
|
||||
// Copyright Mathieu Champlon 2014
|
||||
//
|
||||
// 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_MUTEX_HPP_INCLUDED
|
||||
#define MOCK_MUTEX_HPP_INCLUDED
|
||||
|
||||
#include "../config.hpp"
|
||||
#include <boost/test/utils/trivial_singleton.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
#ifdef MOCK_THREAD_SAFE
|
||||
|
||||
#ifdef MOCK_HDR_MUTEX
|
||||
#include <mutex>
|
||||
#else
|
||||
#include <boost/thread/recursive_mutex.hpp>
|
||||
#include <boost/thread/lock_guard.hpp>
|
||||
#endif
|
||||
|
||||
namespace mock
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
#ifdef MOCK_HDR_MUTEX
|
||||
typedef std::recursive_mutex mutex;
|
||||
typedef std::lock_guard< mutex > scoped_lock;
|
||||
#else
|
||||
typedef boost::recursive_mutex mutex;
|
||||
typedef boost::lock_guard< mutex > scoped_lock;
|
||||
#endif
|
||||
|
||||
struct lock
|
||||
{
|
||||
lock( const boost::shared_ptr< mutex >& m )
|
||||
: m_( m )
|
||||
{
|
||||
m_->lock();
|
||||
}
|
||||
lock( const lock& rhs )
|
||||
{
|
||||
m_.swap( rhs.m_ );
|
||||
}
|
||||
~lock()
|
||||
{
|
||||
if( m_ )
|
||||
m_->unlock();
|
||||
}
|
||||
|
||||
private:
|
||||
lock& operator=( const lock& rhs );
|
||||
|
||||
mutable boost::shared_ptr< mutex > m_;
|
||||
};
|
||||
}
|
||||
} // mock
|
||||
|
||||
#else // MOCK_THREAD_SAFE
|
||||
|
||||
namespace mock
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
struct mutex
|
||||
{
|
||||
mutex()
|
||||
{}
|
||||
void lock()
|
||||
{}
|
||||
void unlock()
|
||||
{}
|
||||
};
|
||||
struct scoped_lock
|
||||
{
|
||||
scoped_lock( mutex& )
|
||||
{}
|
||||
};
|
||||
struct lock
|
||||
{
|
||||
lock( const boost::shared_ptr< mutex >& )
|
||||
{}
|
||||
};
|
||||
}
|
||||
} // mock
|
||||
|
||||
#endif // MOCK_THREAD_SAFE
|
||||
|
||||
namespace mock
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
class error_mutex_t : public boost::unit_test::singleton< error_mutex_t >,
|
||||
public mutex
|
||||
{
|
||||
private:
|
||||
BOOST_TEST_SINGLETON_CONS( error_mutex_t );
|
||||
};
|
||||
BOOST_TEST_SINGLETON_INST( error_mutex )
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
# pragma warning( push, 0 )
|
||||
# pragma warning( disable: 4702 )
|
||||
#endif
|
||||
template< typename Result, typename Error >
|
||||
struct safe_error
|
||||
{
|
||||
static Result abort()
|
||||
{
|
||||
scoped_lock _( error_mutex );
|
||||
return Error::abort();
|
||||
}
|
||||
template< typename Context >
|
||||
static void fail( const char* message, const Context& context,
|
||||
const char* file = "unknown location", int line = 0 )
|
||||
{
|
||||
scoped_lock _( error_mutex );
|
||||
Error::fail( message, context, file, line );
|
||||
}
|
||||
template< typename Context >
|
||||
static void call( const Context& context, const char* file, int line )
|
||||
{
|
||||
scoped_lock _( error_mutex );
|
||||
Error::call( context, file, line );
|
||||
}
|
||||
static void pass( const char* file, int line )
|
||||
{
|
||||
scoped_lock _( error_mutex );
|
||||
Error::pass( file, line );
|
||||
}
|
||||
};
|
||||
#ifdef BOOST_MSVC
|
||||
# pragma warning( pop )
|
||||
#endif
|
||||
}
|
||||
} // mock
|
||||
|
||||
#endif // MOCK_MUTEX_HPP_INCLUDED
|
||||
|
|
@ -15,9 +15,10 @@
|
|||
#include "type_name.hpp"
|
||||
#include "context.hpp"
|
||||
#include "child.hpp"
|
||||
#include "mutex.hpp"
|
||||
#include <boost/test/utils/basic_cstring/basic_cstring.hpp>
|
||||
#include <boost/enable_shared_from_this.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/make_shared.hpp>
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
namespace mock
|
||||
|
|
@ -28,21 +29,28 @@ namespace detail
|
|||
public boost::enable_shared_from_this< object_impl >
|
||||
{
|
||||
public:
|
||||
object_impl()
|
||||
: mutex_( boost::make_shared< mutex >() )
|
||||
{}
|
||||
|
||||
virtual void add( const void* /*p*/, verifiable& v,
|
||||
boost::unit_test::const_string instance,
|
||||
boost::optional< type_name > type,
|
||||
boost::unit_test::const_string name )
|
||||
{
|
||||
lock _( mutex_ );
|
||||
if( children_.empty() )
|
||||
detail::root.add( *this );
|
||||
children_[ &v ].update( parent_, instance, type, name );
|
||||
}
|
||||
virtual void add( verifiable& v )
|
||||
{
|
||||
lock _( mutex_ );
|
||||
group_.add( v );
|
||||
}
|
||||
virtual void remove( verifiable& v )
|
||||
{
|
||||
lock _( mutex_ );
|
||||
group_.remove( v );
|
||||
children_.erase( &v );
|
||||
if( children_.empty() )
|
||||
|
|
@ -51,6 +59,7 @@ namespace detail
|
|||
|
||||
virtual void serialize( std::ostream& s, const verifiable& v ) const
|
||||
{
|
||||
lock _( mutex_ );
|
||||
children_cit it = children_.find( &v );
|
||||
if( it != children_.end() )
|
||||
s << it->second;
|
||||
|
|
@ -60,10 +69,12 @@ namespace detail
|
|||
|
||||
virtual bool verify() const
|
||||
{
|
||||
lock _( mutex_ );
|
||||
return group_.verify();
|
||||
}
|
||||
virtual void reset()
|
||||
{
|
||||
lock _( mutex_ );
|
||||
boost::shared_ptr< object_impl > guard = shared_from_this();
|
||||
group_.reset();
|
||||
}
|
||||
|
|
@ -75,6 +86,7 @@ namespace detail
|
|||
group group_;
|
||||
parent parent_;
|
||||
children_t children_;
|
||||
const boost::shared_ptr< mutex > mutex_;
|
||||
};
|
||||
}
|
||||
} // mock
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
#include "group.hpp"
|
||||
#include "context.hpp"
|
||||
#include "child.hpp"
|
||||
#include "mutex.hpp"
|
||||
#include <boost/test/utils/trivial_singleton.hpp>
|
||||
#include <boost/optional.hpp>
|
||||
#include <ostream>
|
||||
|
|
@ -31,6 +32,7 @@ namespace detail
|
|||
boost::optional< type_name > type,
|
||||
boost::unit_test::const_string name )
|
||||
{
|
||||
scoped_lock _( mutex_ );
|
||||
children_t::iterator it = children_.lower_bound( &v );
|
||||
if( it == children_.end() ||
|
||||
children_.key_comp()( &v, it->first ) )
|
||||
|
|
@ -40,26 +42,31 @@ namespace detail
|
|||
}
|
||||
virtual void add( verifiable& v )
|
||||
{
|
||||
scoped_lock _( mutex_ );
|
||||
group_.add( v );
|
||||
}
|
||||
|
||||
virtual void remove( verifiable& v )
|
||||
{
|
||||
scoped_lock _( mutex_ );
|
||||
group_.remove( v );
|
||||
children_.erase( &v );
|
||||
}
|
||||
|
||||
bool verify() const
|
||||
{
|
||||
scoped_lock _( mutex_ );
|
||||
return group_.verify();
|
||||
}
|
||||
void reset()
|
||||
{
|
||||
scoped_lock _( mutex_ );
|
||||
group_.reset();
|
||||
}
|
||||
|
||||
virtual void serialize( std::ostream& s, const verifiable& v ) const
|
||||
{
|
||||
scoped_lock _( mutex_ );
|
||||
children_cit it = children_.find( &v );
|
||||
if( it != children_.end() )
|
||||
s << it->second;
|
||||
|
|
@ -119,6 +126,7 @@ namespace detail
|
|||
parents_t parents_;
|
||||
children_t children_;
|
||||
group group_;
|
||||
mutable mutex mutex_;
|
||||
|
||||
private:
|
||||
BOOST_TEST_SINGLETON_CONS( root_t );
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue