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]
|
[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]
|
[endsect]
|
||||||
|
|
|
||||||
|
|
@ -171,3 +171,8 @@ struct custom_policy
|
||||||
#define MOCK_ERROR_POLICY custom_policy
|
#define MOCK_ERROR_POLICY custom_policy
|
||||||
#include <turtle/mock.hpp>
|
#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">
|
<build-turtle-test name="turtle_no_variadic_macros">
|
||||||
<defineset define="MOCK_NO_VARIADIC_MACROS"/>
|
<defineset define="MOCK_NO_VARIADIC_MACROS"/>
|
||||||
</build-turtle-test>
|
</build-turtle-test>
|
||||||
|
<build-turtle-test name="turtle_thread_safe">
|
||||||
|
<defineset define="MOCK_THREAD_SAFE"/>
|
||||||
|
</build-turtle-test>
|
||||||
</target>
|
</target>
|
||||||
|
|
||||||
<target name="analyse" description="run errors analyser">
|
<target name="analyse" description="run errors analyser">
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,7 @@
|
||||||
<ClInclude Include="..\..\turtle\detail\is_functor.hpp" />
|
<ClInclude Include="..\..\turtle\detail\is_functor.hpp" />
|
||||||
<ClInclude Include="..\..\turtle\detail\lambda.hpp" />
|
<ClInclude Include="..\..\turtle\detail\lambda.hpp" />
|
||||||
<ClInclude Include="..\..\turtle\detail\matcher_base.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\object_impl.hpp" />
|
||||||
<ClInclude Include="..\..\turtle\detail\parameter.hpp" />
|
<ClInclude Include="..\..\turtle\detail\parameter.hpp" />
|
||||||
<ClInclude Include="..\..\turtle\detail\parent.hpp" />
|
<ClInclude Include="..\..\turtle\detail\parent.hpp" />
|
||||||
|
|
|
||||||
|
|
@ -127,5 +127,8 @@
|
||||||
<ClInclude Include="..\..\turtle\detail\addressof.hpp">
|
<ClInclude Include="..\..\turtle\detail\addressof.hpp">
|
||||||
<Filter>Source Files\detail</Filter>
|
<Filter>Source Files\detail</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\turtle\detail\mutex.hpp">
|
||||||
|
<Filter>Source Files\detail</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</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( "file name", mock_error_data.last_file );
|
||||||
BOOST_CHECK_EQUAL( 42, mock_error_data.last_line );
|
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 > )
|
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
|
||||||
#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
|
#endif // MOCK_CONFIG_HPP_INCLUDED
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@
|
||||||
#include "invocation.hpp"
|
#include "invocation.hpp"
|
||||||
#include "type_name.hpp"
|
#include "type_name.hpp"
|
||||||
#include "context.hpp"
|
#include "context.hpp"
|
||||||
|
#include "mutex.hpp"
|
||||||
#include <boost/preprocessor/iteration/iterate.hpp>
|
#include <boost/preprocessor/iteration/iterate.hpp>
|
||||||
#include <boost/preprocessor/repetition/repeat_from_to.hpp>
|
#include <boost/preprocessor/repetition/repeat_from_to.hpp>
|
||||||
#include <boost/preprocessor/repetition/enum_params.hpp>
|
#include <boost/preprocessor/repetition/enum_params.hpp>
|
||||||
|
|
@ -35,6 +36,57 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <list>
|
#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
|
||||||
#define MOCK_NUM_ARGS_0
|
#define MOCK_NUM_ARGS_0
|
||||||
#include "function_template.hpp"
|
#include "function_template.hpp"
|
||||||
|
|
|
||||||
|
|
@ -37,8 +37,7 @@ namespace detail
|
||||||
function_impl< R ( BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, T) )> >
|
function_impl< R ( BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, T) )> >
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef MOCK_ERROR_POLICY< R > error_type;
|
typedef safe_error< R, MOCK_ERROR_POLICY< R > > error_type;
|
||||||
|
|
||||||
typedef expectation<
|
typedef expectation<
|
||||||
R ( BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, T) )
|
R ( BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, T) )
|
||||||
> expectation_type;
|
> expectation_type;
|
||||||
|
|
@ -47,6 +46,7 @@ namespace detail
|
||||||
function_impl()
|
function_impl()
|
||||||
: context_( 0 )
|
: context_( 0 )
|
||||||
, valid_( true )
|
, valid_( true )
|
||||||
|
, mutex_( boost::make_shared< mutex >() )
|
||||||
{}
|
{}
|
||||||
virtual ~function_impl()
|
virtual ~function_impl()
|
||||||
{
|
{
|
||||||
|
|
@ -56,13 +56,16 @@ namespace detail
|
||||||
if( ! it->verify() )
|
if( ! it->verify() )
|
||||||
error_type::fail( "untriggered expectation",
|
error_type::fail( "untriggered expectation",
|
||||||
boost::unit_test::lazy_ostream::instance()
|
boost::unit_test::lazy_ostream::instance()
|
||||||
<< *this, it->file(), it->line() );
|
<< lazy_context( this )
|
||||||
|
<< lazy_expectations( this ),
|
||||||
|
it->file(), it->line() );
|
||||||
if( context_ )
|
if( context_ )
|
||||||
context_->remove( *this );
|
context_->remove( *this );
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool verify() const
|
virtual bool verify() const
|
||||||
{
|
{
|
||||||
|
lock _( mutex_ );
|
||||||
for( expectations_cit it = expectations_.begin();
|
for( expectations_cit it = expectations_.begin();
|
||||||
it != expectations_.end(); ++it )
|
it != expectations_.end(); ++it )
|
||||||
if( ! it->verify() )
|
if( ! it->verify() )
|
||||||
|
|
@ -70,35 +73,128 @@ namespace detail
|
||||||
valid_ = false;
|
valid_ = false;
|
||||||
error_type::fail( "verification failed",
|
error_type::fail( "verification failed",
|
||||||
boost::unit_test::lazy_ostream::instance()
|
boost::unit_test::lazy_ostream::instance()
|
||||||
<< *this, it->file(), it->line() );
|
<< lazy_context( this )
|
||||||
|
<< lazy_expectations( this ),
|
||||||
|
it->file(), it->line() );
|
||||||
}
|
}
|
||||||
return valid_;
|
return valid_;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void reset()
|
virtual void reset()
|
||||||
{
|
{
|
||||||
|
lock _( mutex_ );
|
||||||
valid_ = true;
|
valid_ = true;
|
||||||
boost::shared_ptr< function_impl > guard =
|
boost::shared_ptr< function_impl > guard =
|
||||||
this->shared_from_this();
|
this->shared_from_this();
|
||||||
expectations_.clear();
|
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 ) );
|
expectations_.push_back( expectation_type( file, line ) );
|
||||||
valid_ = true;
|
valid_ = true;
|
||||||
return expectations_.back();
|
return wrapper_type( mutex_, expectations_.back() );
|
||||||
}
|
}
|
||||||
expectation_type& expect()
|
wrapper_type expect()
|
||||||
{
|
{
|
||||||
|
lock _( mutex_ );
|
||||||
expectations_.push_back( expectation_type() );
|
expectations_.push_back( expectation_type() );
|
||||||
valid_ = true;
|
valid_ = true;
|
||||||
return expectations_.back();
|
return wrapper_type( mutex_, expectations_.back() );
|
||||||
}
|
}
|
||||||
|
|
||||||
R operator()(
|
R operator()(
|
||||||
BOOST_PP_ENUM_BINARY_PARAMS(MOCK_NUM_ARGS, T, t) ) const
|
BOOST_PP_ENUM_BINARY_PARAMS(MOCK_NUM_ARGS, T, t) ) const
|
||||||
{
|
{
|
||||||
|
lock _( mutex_ );
|
||||||
valid_ = false;
|
valid_ = false;
|
||||||
for( expectations_cit it = expectations_.begin();
|
for( expectations_cit it = expectations_.begin();
|
||||||
it != expectations_.end(); ++it )
|
it != expectations_.end(); ++it )
|
||||||
|
|
@ -132,6 +228,7 @@ namespace detail
|
||||||
boost::optional< type_name > type,
|
boost::optional< type_name > type,
|
||||||
boost::unit_test::const_string name )
|
boost::unit_test::const_string name )
|
||||||
{
|
{
|
||||||
|
lock _( mutex_ );
|
||||||
if( ! context_ )
|
if( ! context_ )
|
||||||
c.add( *this );
|
c.add( *this );
|
||||||
c.add( p, *this, instance, type, name );
|
c.add( p, *this, instance, type, name );
|
||||||
|
|
@ -141,6 +238,7 @@ namespace detail
|
||||||
friend std::ostream& operator<<(
|
friend std::ostream& operator<<(
|
||||||
std::ostream& s, const function_impl& impl )
|
std::ostream& s, const function_impl& impl )
|
||||||
{
|
{
|
||||||
|
lock _( impl.mutex_ );
|
||||||
return s << lazy_context( &impl ) << lazy_expectations( &impl );
|
return s << lazy_context( &impl ) << lazy_expectations( &impl );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -183,6 +281,7 @@ namespace detail
|
||||||
expectations_type expectations_;
|
expectations_type expectations_;
|
||||||
context* context_;
|
context* context_;
|
||||||
mutable bool valid_;
|
mutable bool valid_;
|
||||||
|
const boost::shared_ptr< mutex > mutex_;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
} // mock
|
} // mock
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ namespace detail
|
||||||
typedef function_impl<
|
typedef function_impl<
|
||||||
R ( BOOST_PP_REPEAT(MOCK_NUM_ARGS, MOCK_FUNCTION_CALL, _) )
|
R ( BOOST_PP_REPEAT(MOCK_NUM_ARGS, MOCK_FUNCTION_CALL, _) )
|
||||||
> impl_type;
|
> 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;
|
typedef typename impl_type::error_type error_type;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
@ -65,12 +65,12 @@ namespace detail
|
||||||
impl_->reset();
|
impl_->reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
expectation_type& expect( const char* file, int line )
|
expectation_type expect( const char* file, int line )
|
||||||
{
|
{
|
||||||
error_type::pass( file, line );
|
error_type::pass( file, line );
|
||||||
return impl_->expect( file, line );
|
return impl_->expect( file, line );
|
||||||
}
|
}
|
||||||
expectation_type& expect()
|
expectation_type expect()
|
||||||
{
|
{
|
||||||
return impl_->expect();
|
return impl_->expect();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@
|
||||||
|
|
||||||
#include "../config.hpp"
|
#include "../config.hpp"
|
||||||
#include "function.hpp"
|
#include "function.hpp"
|
||||||
|
#include "mutex.hpp"
|
||||||
|
|
||||||
namespace mock
|
namespace mock
|
||||||
{
|
{
|
||||||
|
|
@ -21,15 +22,21 @@ namespace detail
|
||||||
{
|
{
|
||||||
functor()
|
functor()
|
||||||
{
|
{
|
||||||
|
static mutex m_;
|
||||||
|
scoped_lock _( m_ );
|
||||||
static functor* f = 0;
|
static functor* f = 0;
|
||||||
if( f )
|
if( f )
|
||||||
{
|
{
|
||||||
*this = *f;
|
*this = *f;
|
||||||
f = 0;
|
f = 0;
|
||||||
|
m_.unlock();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
m_.lock();
|
||||||
f = this;
|
f = this;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
} // mock
|
} // mock
|
||||||
|
|
|
||||||
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 "type_name.hpp"
|
||||||
#include "context.hpp"
|
#include "context.hpp"
|
||||||
#include "child.hpp"
|
#include "child.hpp"
|
||||||
|
#include "mutex.hpp"
|
||||||
#include <boost/test/utils/basic_cstring/basic_cstring.hpp>
|
#include <boost/test/utils/basic_cstring/basic_cstring.hpp>
|
||||||
#include <boost/enable_shared_from_this.hpp>
|
#include <boost/enable_shared_from_this.hpp>
|
||||||
#include <boost/shared_ptr.hpp>
|
#include <boost/make_shared.hpp>
|
||||||
#include <boost/optional.hpp>
|
#include <boost/optional.hpp>
|
||||||
|
|
||||||
namespace mock
|
namespace mock
|
||||||
|
|
@ -28,21 +29,28 @@ namespace detail
|
||||||
public boost::enable_shared_from_this< object_impl >
|
public boost::enable_shared_from_this< object_impl >
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
object_impl()
|
||||||
|
: mutex_( boost::make_shared< mutex >() )
|
||||||
|
{}
|
||||||
|
|
||||||
virtual void add( const void* /*p*/, verifiable& v,
|
virtual void add( const void* /*p*/, verifiable& v,
|
||||||
boost::unit_test::const_string instance,
|
boost::unit_test::const_string instance,
|
||||||
boost::optional< type_name > type,
|
boost::optional< type_name > type,
|
||||||
boost::unit_test::const_string name )
|
boost::unit_test::const_string name )
|
||||||
{
|
{
|
||||||
|
lock _( mutex_ );
|
||||||
if( children_.empty() )
|
if( children_.empty() )
|
||||||
detail::root.add( *this );
|
detail::root.add( *this );
|
||||||
children_[ &v ].update( parent_, instance, type, name );
|
children_[ &v ].update( parent_, instance, type, name );
|
||||||
}
|
}
|
||||||
virtual void add( verifiable& v )
|
virtual void add( verifiable& v )
|
||||||
{
|
{
|
||||||
|
lock _( mutex_ );
|
||||||
group_.add( v );
|
group_.add( v );
|
||||||
}
|
}
|
||||||
virtual void remove( verifiable& v )
|
virtual void remove( verifiable& v )
|
||||||
{
|
{
|
||||||
|
lock _( mutex_ );
|
||||||
group_.remove( v );
|
group_.remove( v );
|
||||||
children_.erase( &v );
|
children_.erase( &v );
|
||||||
if( children_.empty() )
|
if( children_.empty() )
|
||||||
|
|
@ -51,6 +59,7 @@ namespace detail
|
||||||
|
|
||||||
virtual void serialize( std::ostream& s, const verifiable& v ) const
|
virtual void serialize( std::ostream& s, const verifiable& v ) const
|
||||||
{
|
{
|
||||||
|
lock _( mutex_ );
|
||||||
children_cit it = children_.find( &v );
|
children_cit it = children_.find( &v );
|
||||||
if( it != children_.end() )
|
if( it != children_.end() )
|
||||||
s << it->second;
|
s << it->second;
|
||||||
|
|
@ -60,10 +69,12 @@ namespace detail
|
||||||
|
|
||||||
virtual bool verify() const
|
virtual bool verify() const
|
||||||
{
|
{
|
||||||
|
lock _( mutex_ );
|
||||||
return group_.verify();
|
return group_.verify();
|
||||||
}
|
}
|
||||||
virtual void reset()
|
virtual void reset()
|
||||||
{
|
{
|
||||||
|
lock _( mutex_ );
|
||||||
boost::shared_ptr< object_impl > guard = shared_from_this();
|
boost::shared_ptr< object_impl > guard = shared_from_this();
|
||||||
group_.reset();
|
group_.reset();
|
||||||
}
|
}
|
||||||
|
|
@ -75,6 +86,7 @@ namespace detail
|
||||||
group group_;
|
group group_;
|
||||||
parent parent_;
|
parent parent_;
|
||||||
children_t children_;
|
children_t children_;
|
||||||
|
const boost::shared_ptr< mutex > mutex_;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
} // mock
|
} // mock
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@
|
||||||
#include "group.hpp"
|
#include "group.hpp"
|
||||||
#include "context.hpp"
|
#include "context.hpp"
|
||||||
#include "child.hpp"
|
#include "child.hpp"
|
||||||
|
#include "mutex.hpp"
|
||||||
#include <boost/test/utils/trivial_singleton.hpp>
|
#include <boost/test/utils/trivial_singleton.hpp>
|
||||||
#include <boost/optional.hpp>
|
#include <boost/optional.hpp>
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
|
|
@ -31,6 +32,7 @@ namespace detail
|
||||||
boost::optional< type_name > type,
|
boost::optional< type_name > type,
|
||||||
boost::unit_test::const_string name )
|
boost::unit_test::const_string name )
|
||||||
{
|
{
|
||||||
|
scoped_lock _( mutex_ );
|
||||||
children_t::iterator it = children_.lower_bound( &v );
|
children_t::iterator it = children_.lower_bound( &v );
|
||||||
if( it == children_.end() ||
|
if( it == children_.end() ||
|
||||||
children_.key_comp()( &v, it->first ) )
|
children_.key_comp()( &v, it->first ) )
|
||||||
|
|
@ -40,26 +42,31 @@ namespace detail
|
||||||
}
|
}
|
||||||
virtual void add( verifiable& v )
|
virtual void add( verifiable& v )
|
||||||
{
|
{
|
||||||
|
scoped_lock _( mutex_ );
|
||||||
group_.add( v );
|
group_.add( v );
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void remove( verifiable& v )
|
virtual void remove( verifiable& v )
|
||||||
{
|
{
|
||||||
|
scoped_lock _( mutex_ );
|
||||||
group_.remove( v );
|
group_.remove( v );
|
||||||
children_.erase( &v );
|
children_.erase( &v );
|
||||||
}
|
}
|
||||||
|
|
||||||
bool verify() const
|
bool verify() const
|
||||||
{
|
{
|
||||||
|
scoped_lock _( mutex_ );
|
||||||
return group_.verify();
|
return group_.verify();
|
||||||
}
|
}
|
||||||
void reset()
|
void reset()
|
||||||
{
|
{
|
||||||
|
scoped_lock _( mutex_ );
|
||||||
group_.reset();
|
group_.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void serialize( std::ostream& s, const verifiable& v ) const
|
virtual void serialize( std::ostream& s, const verifiable& v ) const
|
||||||
{
|
{
|
||||||
|
scoped_lock _( mutex_ );
|
||||||
children_cit it = children_.find( &v );
|
children_cit it = children_.find( &v );
|
||||||
if( it != children_.end() )
|
if( it != children_.end() )
|
||||||
s << it->second;
|
s << it->second;
|
||||||
|
|
@ -119,6 +126,7 @@ namespace detail
|
||||||
parents_t parents_;
|
parents_t parents_;
|
||||||
children_t children_;
|
children_t children_;
|
||||||
group group_;
|
group group_;
|
||||||
|
mutable mutex mutex_;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
BOOST_TEST_SINGLETON_CONS( root_t );
|
BOOST_TEST_SINGLETON_CONS( root_t );
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue