mirror of
https://github.com/mat007/turtle.git
synced 2026-06-22 12:13:43 +00:00
Make action classes non-relocatable
This fixes an issue with auto_ptr. As shown by missing coverage the actual copy/move ctors are not required as C++11 emplace functions can be used. Furthermore some places using shared_ptr could be replaced by unique_ptr leading to better performance.
This commit is contained in:
parent
f3d6564d2b
commit
d9f9fce6fc
5 changed files with 54 additions and 55 deletions
|
|
@ -25,7 +25,16 @@ namespace detail
|
||||||
typedef std::function< Signature > functor_type;
|
typedef std::function< Signature > functor_type;
|
||||||
typedef std::function< Result() > action_type;
|
typedef std::function< Result() > action_type;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// Meant to be subclassed and not be directly used
|
||||||
|
// Non-relocatable (contained functions may wrap references/pointers which could be invalidated)
|
||||||
|
action_base() = default;
|
||||||
|
action_base(const action_base&) = delete;
|
||||||
|
action_base(action_base&&) = delete;
|
||||||
|
action_base& operator=(const action_base&) = delete;
|
||||||
|
action_base& operator=(action_base&&) = delete;
|
||||||
public:
|
public:
|
||||||
|
|
||||||
const functor_type& functor() const
|
const functor_type& functor() const
|
||||||
{
|
{
|
||||||
return f_;
|
return f_;
|
||||||
|
|
@ -91,11 +100,6 @@ namespace detail
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
template< typename Value >
|
|
||||||
static Value&& move( Value& t )
|
|
||||||
{
|
|
||||||
return std::move( t );
|
|
||||||
}
|
|
||||||
struct value
|
struct value
|
||||||
{
|
{
|
||||||
value() = default;
|
value() = default;
|
||||||
|
|
@ -106,41 +110,28 @@ namespace detail
|
||||||
template< typename T >
|
template< typename T >
|
||||||
struct value_imp : value
|
struct value_imp : value
|
||||||
{
|
{
|
||||||
typedef std::remove_const_t<std::remove_reference_t<T>> value_type;
|
typedef std::remove_const_t<std::remove_reference_t<T>> type;
|
||||||
|
|
||||||
value_imp( value_type&& t )
|
template< typename U >
|
||||||
: t_( std::move( t ) )
|
value_imp( U&& t ) : t_( std::forward<U>( t ) )
|
||||||
{}
|
{}
|
||||||
value_imp( const value_type& t )
|
type t_;
|
||||||
: t_( t )
|
|
||||||
{}
|
|
||||||
template< typename Y >
|
|
||||||
value_imp( Y* y )
|
|
||||||
: t_( y )
|
|
||||||
{}
|
|
||||||
value_type t_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template< typename T >
|
template< typename T >
|
||||||
T& store( T&& t )
|
typename value_imp<T>::type& store( T&& t )
|
||||||
{
|
{
|
||||||
v_ = std::make_shared< value_imp<T> >( std::move( t ) );
|
v_ = std::make_unique< value_imp<T> >( std::forward<T>( t ) );
|
||||||
return static_cast< value_imp< T >& >( *v_ ).t_;
|
|
||||||
}
|
|
||||||
template< typename T >
|
|
||||||
T& store( const T& t )
|
|
||||||
{
|
|
||||||
v_ = std::make_shared< value_imp<T> >( t );
|
|
||||||
return static_cast< value_imp< T >& >( *v_ ).t_;
|
return static_cast< value_imp< T >& >( *v_ ).t_;
|
||||||
}
|
}
|
||||||
template< typename T >
|
template< typename T >
|
||||||
std::remove_reference_t< Result >& store( T* t )
|
std::remove_reference_t< Result >& store( T* t )
|
||||||
{
|
{
|
||||||
v_ = std::make_shared< value_imp<Result> >( t );
|
v_ = std::make_unique< value_imp<Result> >( t );
|
||||||
return static_cast< value_imp< Result >& >( *v_ ).t_;
|
return static_cast< value_imp< Result >& >( *v_ ).t_;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr< value > v_;
|
std::unique_ptr< value > v_;
|
||||||
};
|
};
|
||||||
|
|
||||||
template< typename Signature >
|
template< typename Signature >
|
||||||
|
|
@ -159,14 +150,6 @@ namespace detail
|
||||||
: public action_base< std::auto_ptr< Result >, Signature >
|
: public action_base< std::auto_ptr< Result >, Signature >
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
action() = default;
|
|
||||||
action( const action& rhs )
|
|
||||||
: v_( rhs.v_.release() )
|
|
||||||
{
|
|
||||||
if( v_.get() )
|
|
||||||
returns( std::ref( v_ ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
template< typename Y >
|
template< typename Y >
|
||||||
void returns( Y* r )
|
void returns( Y* r )
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -133,9 +133,9 @@ namespace detail
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
expectation()
|
expectation()
|
||||||
: invocation_( std::make_shared< unlimited >() )
|
: invocation_( std::make_unique< unlimited >() )
|
||||||
, matcher_(
|
, matcher_(
|
||||||
std::make_shared<
|
std::make_unique<
|
||||||
default_matcher<
|
default_matcher<
|
||||||
void( BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, T) )
|
void( BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, T) )
|
||||||
>
|
>
|
||||||
|
|
@ -144,9 +144,9 @@ namespace detail
|
||||||
, line_( 0 )
|
, line_( 0 )
|
||||||
{}
|
{}
|
||||||
expectation( const char* file, int line )
|
expectation( const char* file, int line )
|
||||||
: invocation_( std::make_shared< unlimited >() )
|
: invocation_( std::make_unique< unlimited >() )
|
||||||
, matcher_(
|
, matcher_(
|
||||||
std::make_shared<
|
std::make_unique<
|
||||||
default_matcher<
|
default_matcher<
|
||||||
void( BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, T) )
|
void( BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, T) )
|
||||||
>
|
>
|
||||||
|
|
@ -166,9 +166,9 @@ namespace detail
|
||||||
sequence->remove( this );
|
sequence->remove( this );
|
||||||
}
|
}
|
||||||
|
|
||||||
void invoke( const std::shared_ptr< invocation >& i )
|
void invoke( std::unique_ptr< invocation > i )
|
||||||
{
|
{
|
||||||
invocation_ = i;
|
invocation_ = std::move(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef MOCK_NUM_ARGS_0
|
#ifndef MOCK_NUM_ARGS_0
|
||||||
|
|
@ -178,7 +178,7 @@ namespace detail
|
||||||
expectation& with(
|
expectation& with(
|
||||||
BOOST_PP_ENUM_BINARY_PARAMS(MOCK_NUM_ARGS, Constraint_, c) )
|
BOOST_PP_ENUM_BINARY_PARAMS(MOCK_NUM_ARGS, Constraint_, c) )
|
||||||
{
|
{
|
||||||
matcher_ = std::make_shared<
|
matcher_ = std::make_unique<
|
||||||
single_matcher<
|
single_matcher<
|
||||||
void( BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, Constraint_) ),
|
void( BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, Constraint_) ),
|
||||||
void( BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, T) )
|
void( BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, T) )
|
||||||
|
|
@ -189,7 +189,7 @@ namespace detail
|
||||||
template< typename Constraint >
|
template< typename Constraint >
|
||||||
expectation& with( const Constraint& c )
|
expectation& with( const Constraint& c )
|
||||||
{
|
{
|
||||||
matcher_ = std::make_shared<
|
matcher_ = std::make_unique<
|
||||||
multi_matcher<
|
multi_matcher<
|
||||||
Constraint,
|
Constraint,
|
||||||
void( BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, T) )
|
void( BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, T) )
|
||||||
|
|
@ -250,8 +250,8 @@ namespace detail
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::shared_ptr< invocation > invocation_;
|
std::unique_ptr< invocation > invocation_;
|
||||||
std::shared_ptr<
|
std::unique_ptr<
|
||||||
matcher_base<
|
matcher_base<
|
||||||
void( BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, T) )
|
void( BOOST_PP_ENUM_PARAMS(MOCK_NUM_ARGS, T) )
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -125,32 +125,32 @@ namespace detail
|
||||||
}
|
}
|
||||||
wrapper& once()
|
wrapper& once()
|
||||||
{
|
{
|
||||||
this->e_->invoke( std::make_shared< detail::once >() );
|
this->e_->invoke( std::make_unique< detail::once >() );
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
wrapper& never()
|
wrapper& never()
|
||||||
{
|
{
|
||||||
this->e_->invoke( std::make_shared< detail::never >() );
|
this->e_->invoke( std::make_unique< detail::never >() );
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
wrapper& exactly( std::size_t count )
|
wrapper& exactly( std::size_t count )
|
||||||
{
|
{
|
||||||
this->e_->invoke( std::make_shared< detail::exactly >( count ) );
|
this->e_->invoke( std::make_unique< detail::exactly >( count ) );
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
wrapper& at_least( std::size_t min )
|
wrapper& at_least( std::size_t min )
|
||||||
{
|
{
|
||||||
this->e_->invoke( std::make_shared< detail::at_least >( min ) );
|
this->e_->invoke( std::make_unique< detail::at_least >( min ) );
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
wrapper& at_most( std::size_t max )
|
wrapper& at_most( std::size_t max )
|
||||||
{
|
{
|
||||||
this->e_->invoke( std::make_shared< detail::at_most >( max ) );
|
this->e_->invoke( std::make_unique< detail::at_most >( max ) );
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
wrapper& between( std::size_t min, std::size_t max )
|
wrapper& between( std::size_t min, std::size_t max )
|
||||||
{
|
{
|
||||||
this->e_->invoke( std::make_shared< detail::between >( min, max ) );
|
this->e_->invoke( std::make_unique< detail::between >( min, max ) );
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -217,14 +217,14 @@ namespace detail
|
||||||
wrapper expect( const char* file, int line )
|
wrapper expect( const char* file, int line )
|
||||||
{
|
{
|
||||||
lock _( mutex_ );
|
lock _( mutex_ );
|
||||||
expectations_.push_back( expectation_type( file, line ) );
|
expectations_.emplace_back( file, line );
|
||||||
valid_ = true;
|
valid_ = true;
|
||||||
return wrapper( mutex_, expectations_.back() );
|
return wrapper( mutex_, expectations_.back() );
|
||||||
}
|
}
|
||||||
wrapper expect()
|
wrapper expect()
|
||||||
{
|
{
|
||||||
lock _( mutex_ );
|
lock _( mutex_ );
|
||||||
expectations_.push_back( expectation_type() );
|
expectations_.emplace_back( );
|
||||||
valid_ = true;
|
valid_ = true;
|
||||||
return wrapper( mutex_, expectations_.back() );
|
return wrapper( mutex_, expectations_.back() );
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -45,9 +45,12 @@ namespace detail
|
||||||
const char* name = info.name();
|
const char* name = info.name();
|
||||||
#ifdef __GNUC__
|
#ifdef __GNUC__
|
||||||
int status = 0;
|
int status = 0;
|
||||||
std::shared_ptr< char > demangled(
|
struct Deleter
|
||||||
abi::__cxa_demangle( name, 0, 0, &status ),
|
{
|
||||||
&std::free );
|
void operator()(const void* p) { std::free(const_cast<void*>(p)); }
|
||||||
|
};
|
||||||
|
std::unique_ptr< const char, Deleter > demangled(
|
||||||
|
abi::__cxa_demangle( name, 0, 0, &status ));
|
||||||
if( ! status && demangled )
|
if( ! status && demangled )
|
||||||
serialize( s, demangled.get() );
|
serialize( s, demangled.get() );
|
||||||
else
|
else
|
||||||
|
|
|
||||||
|
|
@ -535,6 +535,19 @@ BOOST_FIXTURE_TEST_CASE( triggering_an_expectation_returns_the_set_auto_ptr_valu
|
||||||
BOOST_CHECK( ! f().get() );
|
BOOST_CHECK( ! f().get() );
|
||||||
CHECK_CALLS( 2 );
|
CHECK_CALLS( 2 );
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
mock::detail::function< std::auto_ptr< int >() > f;
|
||||||
|
f.expect().once().returns( new int( 1 ) );
|
||||||
|
f.expect().once().returns( new int( 2 ) );
|
||||||
|
f.expect().once().returns( new int( 3 ) );
|
||||||
|
f.expect().returns( new int( 4 ) );
|
||||||
|
BOOST_CHECK_EQUAL( 1, *f() );
|
||||||
|
BOOST_CHECK_EQUAL( 2, *f() );
|
||||||
|
BOOST_CHECK_EQUAL( 3, *f() );
|
||||||
|
BOOST_CHECK_EQUAL( 4, *f() );
|
||||||
|
BOOST_CHECK( ! f().get() );
|
||||||
|
CHECK_CALLS( 5 );
|
||||||
|
}
|
||||||
{
|
{
|
||||||
mock::detail::function< std::auto_ptr< int >() > f;
|
mock::detail::function< std::auto_ptr< int >() > f;
|
||||||
f.expect().returns( std::auto_ptr< int >( new int( 3 ) ) );
|
f.expect().returns( std::auto_ptr< int >( new int( 3 ) ) );
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue