Fix C++98 compatibility

This commit is contained in:
Alexander Grund 2018-11-19 11:25:09 +01:00
parent 2cde572532
commit f402c6161e
13 changed files with 146 additions and 37 deletions

View file

@ -49,6 +49,10 @@ namespace
{ {
MOCK_METHOD( method, 0 ) MOCK_METHOD( method, 0 )
}; };
void set_bool(bool& b)
{
b = true;
}
} }
BOOST_AUTO_TEST_CASE( method_is_called ) BOOST_AUTO_TEST_CASE( method_is_called )
@ -56,7 +60,14 @@ BOOST_AUTO_TEST_CASE( method_is_called )
mock_base_class m; mock_base_class m;
my_class c( m ); my_class c( m );
bool done = false; bool done = false;
MOCK_EXPECT( m.method ).once().calls( boost::lambda::var( done ) = true ); // when method is called it will set done to true // when method is called it will set done to true
// Note: Boost 1.57 introduced a bug preventing usage of the lambda with clang in C++98
// See: https://svn.boost.org/trac10/ticket/10785
#if defined(BOOST_CLANG) && (BOOST_VERSION >= 105700)
MOCK_EXPECT( m.method ).once().calls( boost::bind(&set_bool, done) );
#else
MOCK_EXPECT( m.method ).once().calls( boost::lambda::var( done ) = true );
#endif
check( done, boost::bind( &my_class::flush, &c ) ); // just wait on done, flushing from time to time check( done, boost::bind( &my_class::flush, &c ) ); // just wait on done, flushing from time to time
} }
//] //]

View file

@ -20,6 +20,7 @@
#include <boost/preprocessor/repetition/enum.hpp> #include <boost/preprocessor/repetition/enum.hpp>
#include <boost/preprocessor/array.hpp> #include <boost/preprocessor/array.hpp>
#include <boost/move/move.hpp> #include <boost/move/move.hpp>
#include <boost/type_traits/decay.hpp>
namespace mock namespace mock
{ {
@ -146,7 +147,7 @@ namespace detail
const mock::constraint< detail::Name > Name; const mock::constraint< detail::Name > Name;
#define MOCK_CONSTRAINT_ASSIGN(z, n, d) \ #define MOCK_CONSTRAINT_ASSIGN(z, n, d) \
expected##n( e##n ) expected##n( boost::forward< T##n >(e##n) )
#define MOCK_CONSTRAINT_UNWRAP_REF(z, n, d) \ #define MOCK_CONSTRAINT_UNWRAP_REF(z, n, d) \
boost::unwrap_ref( expected##n ) boost::unwrap_ref( expected##n )
@ -157,6 +158,9 @@ namespace detail
#define MOCK_CONSTRAINT_MEMBER(z, n, d) \ #define MOCK_CONSTRAINT_MEMBER(z, n, d) \
Expected_##n expected##n; Expected_##n expected##n;
#define MOCK_CONSTRAINT_TPL_TYPE(z, n, d) \
typename boost::decay< const T##n >::type
#define MOCK_CONSTRAINT_CREF_PARAM(z, n, Args) \ #define MOCK_CONSTRAINT_CREF_PARAM(z, n, Args) \
const typename boost::unwrap_reference< Expected_##n >::type& \ const typename boost::unwrap_reference< Expected_##n >::type& \
BOOST_PP_ARRAY_ELEM(n, Args) BOOST_PP_ARRAY_ELEM(n, Args)
@ -164,6 +168,9 @@ namespace detail
#define MOCK_CONSTRAINT_ARG(z, n, Args) \ #define MOCK_CONSTRAINT_ARG(z, n, Args) \
BOOST_FWD_REF(T##n) BOOST_PP_ARRAY_ELEM(n, Args) BOOST_FWD_REF(T##n) BOOST_PP_ARRAY_ELEM(n, Args)
#define MOCK_CONSTRAINT_ARGS(z, n, Args) \
BOOST_FWD_REF(T##n) e##n
#define MOCK_CONSTRAINT_PARAM(z, n, Args) \ #define MOCK_CONSTRAINT_PARAM(z, n, Args) \
boost::forward< T##n >( BOOST_PP_ARRAY_ELEM(n, Args) ) boost::forward< T##n >( BOOST_PP_ARRAY_ELEM(n, Args) )
@ -173,8 +180,9 @@ namespace detail
template< BOOST_PP_ENUM_PARAMS(n, typename Expected_) > \ template< BOOST_PP_ENUM_PARAMS(n, typename Expected_) > \
struct Name \ struct Name \
{ \ { \
template< BOOST_PP_ENUM_PARAMS(n, typename T) > \
explicit Name( \ explicit Name( \
BOOST_PP_ENUM_BINARY_PARAMS(n, Expected_, e) ) \ BOOST_PP_ENUM(n, MOCK_CONSTRAINT_ARGS, _) ) \
: BOOST_PP_ENUM(n, MOCK_CONSTRAINT_ASSIGN, _) \ : BOOST_PP_ENUM(n, MOCK_CONSTRAINT_ASSIGN, _) \
{} \ {} \
template< typename Actual > \ template< typename Actual > \
@ -201,10 +209,10 @@ namespace detail
} \ } \
template< BOOST_PP_ENUM_PARAMS(n, typename T) > \ template< BOOST_PP_ENUM_PARAMS(n, typename T) > \
mock::constraint< \ mock::constraint< \
detail::Name< BOOST_PP_ENUM_PARAMS(n, T) > \ detail::Name< BOOST_PP_ENUM(n, MOCK_CONSTRAINT_TPL_TYPE, _) > \
> Name( BOOST_PP_ENUM(n, MOCK_CONSTRAINT_ARG, (n, Args)) ) \ > Name( BOOST_PP_ENUM(n, MOCK_CONSTRAINT_ARG, (n, Args)) ) \
{ \ { \
return detail::Name< BOOST_PP_ENUM_PARAMS(n, T) >( \ return detail::Name< BOOST_PP_ENUM(n, MOCK_CONSTRAINT_TPL_TYPE, _) >( \
BOOST_PP_ENUM(n, MOCK_CONSTRAINT_PARAM, (n, Args)) ); \ BOOST_PP_ENUM(n, MOCK_CONSTRAINT_PARAM, (n, Args)) ); \
} }

View file

@ -12,6 +12,7 @@
#include "config.hpp" #include "config.hpp"
#include "constraint.hpp" #include "constraint.hpp"
#include "detail/addressof.hpp" #include "detail/addressof.hpp"
#include "detail/move_helper.hpp"
#include <boost/ref.hpp> #include <boost/ref.hpp>
#include <boost/version.hpp> #include <boost/version.hpp>
#include <boost/utility/enable_if.hpp> #include <boost/utility/enable_if.hpp>
@ -269,9 +270,9 @@ namespace detail
} }
template< typename T > template< typename T >
constraint< detail::equal< T > > equal( BOOST_FWD_REF(T) t ) constraint< detail::equal< typename detail::forward_type< T >::type > > equal( BOOST_FWD_REF(T) t )
{ {
return detail::equal< T >( boost::forward< T >( t ) ); return detail::equal< typename detail::forward_type< T >::type >( boost::forward< T >( t ) );
} }
template< typename T > template< typename T >

View file

@ -109,17 +109,16 @@ namespace detail
{ {
this->set( this->set(
boost::bind( boost::bind(
&move< Value >, &move< typename boost::remove_reference< Value >::type >,
boost::ref( store( boost::move( v ) ) ) ) ); boost::ref( store( boost::move( v ) ) ) ) );
} }
private: private:
template< typename T > template< typename Value >
static T&& move( T& t ) static BOOST_RV_REF(Value) move( Value& t )
{ {
return std::move( t ); return boost::move( t );
} }
struct value : boost::noncopyable struct value : boost::noncopyable
{ {
virtual ~value() virtual ~value()
@ -138,7 +137,7 @@ namespace detail
value_imp( BOOST_RV_REF(value_type) t ) value_imp( BOOST_RV_REF(value_type) t )
: t_( boost::move( t ) ) : t_( boost::move( t ) )
{} {}
value_imp( const T& t ) value_imp( const value_type& t )
: t_( t ) : t_( t )
{} {}
template< typename Y > template< typename Y >

View file

@ -15,7 +15,7 @@
matcher< T##n, Constraint_##n > c##n##_; matcher< T##n, Constraint_##n > c##n##_;
#define MOCK_EXPECTATION_IS_VALID(z, n, d) \ #define MOCK_EXPECTATION_IS_VALID(z, n, d) \
BOOST_PP_IF(n, &&,) c##n##_( boost::forward< T##n >( a##n ) ) BOOST_PP_IF(n, &&,) c##n##_( mock::detail::move_if_not_lvalue_reference< T##n >( a##n ) )
#define MOCK_EXPECTATION_SERIALIZE(z, n, d) \ #define MOCK_EXPECTATION_SERIALIZE(z, n, d) \
BOOST_PP_IF(n, << ", " <<,) c##n##_ BOOST_PP_IF(n, << ", " <<,) c##n##_
@ -24,10 +24,10 @@
BOOST_PP_IF(n, << ", " <<,) "any" BOOST_PP_IF(n, << ", " <<,) "any"
#define MOCK_EXPECTATION_PARAM(z, n, Args) \ #define MOCK_EXPECTATION_PARAM(z, n, Args) \
boost::forward< T##n >( a##n ) mock::detail::move_if_not_lvalue_reference< T##n >( a##n )
#define MOCK_RV_REF_ARG(z, n, d) \ #define MOCK_REF_ARG(z, n, d) \
BOOST_RV_REF(T##n) a##n typename ref_arg< T##n >::type a##n
namespace mock namespace mock
{ {
@ -42,7 +42,7 @@ namespace detail
{ {
private: private:
virtual bool operator()( virtual bool operator()(
BOOST_PP_ENUM(MOCK_NUM_ARGS, MOCK_RV_REF, _) ) BOOST_PP_ENUM(MOCK_NUM_ARGS, MOCK_REF_ARG, _) )
{ {
return true; return true;
} }
@ -76,7 +76,7 @@ namespace detail
private: private:
virtual bool operator()( virtual bool operator()(
BOOST_PP_ENUM(MOCK_NUM_ARGS, MOCK_RV_REF_ARG, _) ) BOOST_PP_ENUM(MOCK_NUM_ARGS, MOCK_REF_ARG, _) )
{ {
return BOOST_PP_REPEAT(MOCK_NUM_ARGS, return BOOST_PP_REPEAT(MOCK_NUM_ARGS,
MOCK_EXPECTATION_IS_VALID, _); MOCK_EXPECTATION_IS_VALID, _);
@ -106,7 +106,7 @@ namespace detail
private: private:
virtual bool operator()( virtual bool operator()(
BOOST_PP_ENUM(MOCK_NUM_ARGS, MOCK_RV_REF_ARG, _) ) BOOST_PP_ENUM(MOCK_NUM_ARGS, MOCK_REF_ARG, _) )
{ {
return f_( BOOST_PP_ENUM(MOCK_NUM_ARGS, MOCK_EXPECTATION_PARAM, _) ); return f_( BOOST_PP_ENUM(MOCK_NUM_ARGS, MOCK_EXPECTATION_PARAM, _) );
} }
@ -204,7 +204,7 @@ namespace detail
} }
bool is_valid( bool is_valid(
BOOST_PP_ENUM(MOCK_NUM_ARGS, MOCK_RV_REF_ARG, _) ) const BOOST_PP_ENUM(MOCK_NUM_ARGS, MOCK_REF_ARG, _) ) const
{ {
return !invocation_->exhausted() return !invocation_->exhausted()
&& (*matcher_)( BOOST_PP_ENUM(MOCK_NUM_ARGS, MOCK_EXPECTATION_PARAM, _) ); && (*matcher_)( BOOST_PP_ENUM(MOCK_NUM_ARGS, MOCK_EXPECTATION_PARAM, _) );
@ -268,5 +268,5 @@ namespace detail
#undef MOCK_EXPECTATION_SERIALIZE #undef MOCK_EXPECTATION_SERIALIZE
#undef MOCK_EXPECTATION_SERIALIZE_ANY #undef MOCK_EXPECTATION_SERIALIZE_ANY
#undef MOCK_EXPECTATION_PARAM #undef MOCK_EXPECTATION_PARAM
#undef MOCK_RV_REF_ARG #undef MOCK_REF_ARG
#undef MOCK_RV_REF #undef MOCK_RV_REF

View file

@ -21,6 +21,7 @@
#include "type_name.hpp" #include "type_name.hpp"
#include "context.hpp" #include "context.hpp"
#include "mutex.hpp" #include "mutex.hpp"
#include "move_helper.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>

View file

@ -24,6 +24,9 @@
<< ')' \ << ')' \
<< lazy_expectations( this ) << lazy_expectations( this )
#define MOCK_MOVE(z, n, d) \
mock::detail::move_if_not_lvalue_reference< T##n >( t##n )
namespace mock namespace mock
{ {
namespace detail namespace detail
@ -217,7 +220,7 @@ namespace detail
for( expectations_cit it = expectations_.begin(); for( expectations_cit it = expectations_.begin();
it != expectations_.end(); ++it ) it != expectations_.end(); ++it )
if( it->is_valid( if( it->is_valid(
BOOST_PP_ENUM(MOCK_NUM_ARGS, MOCK_FORWARD, _) ) ) BOOST_PP_ENUM(MOCK_NUM_ARGS, MOCK_MOVE, _) ) )
{ {
if( ! it->invoke() ) if( ! it->invoke() )
{ {
@ -236,7 +239,7 @@ namespace detail
MOCK_FUNCTION_CONTEXT, it->file(), it->line() ); MOCK_FUNCTION_CONTEXT, it->file(), it->line() );
if( it->functor() ) if( it->functor() )
return it->functor()( return it->functor()(
BOOST_PP_ENUM(MOCK_NUM_ARGS, MOCK_FORWARD, _) ); BOOST_PP_ENUM(MOCK_NUM_ARGS, MOCK_MOVE, _) );
return it->trigger(); return it->trigger();
} }
error_type::fail( "unexpected call", MOCK_FUNCTION_CONTEXT ); error_type::fail( "unexpected call", MOCK_FUNCTION_CONTEXT );
@ -309,3 +312,4 @@ namespace detail
#undef MOCK_FUNCTION_FORMAT #undef MOCK_FUNCTION_FORMAT
#undef MOCK_FUNCTION_CONTEXT #undef MOCK_FUNCTION_CONTEXT
#undef MOCK_MOVE

View file

@ -8,8 +8,8 @@
#include "function_impl_template.hpp" #include "function_impl_template.hpp"
#define MOCK_FORWARD(z, n, d) \ #define MOCK_MOVE(z, n, d) \
boost::forward< T##n >( t##n ) mock::detail::move_if_not_lvalue_reference< T##n >( t##n )
namespace mock namespace mock
{ {
@ -74,7 +74,7 @@ namespace detail
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
{ {
return (*impl_)( BOOST_PP_ENUM(MOCK_NUM_ARGS, MOCK_FORWARD, _) ); return (*impl_)( BOOST_PP_ENUM(MOCK_NUM_ARGS, MOCK_MOVE, _) );
} }
friend std::ostream& operator<<( std::ostream& s, const function& f ) friend std::ostream& operator<<( std::ostream& s, const function& f )
@ -102,3 +102,5 @@ namespace detail
}; };
} }
} // mock } // mock
#undef MOCK_MOVE

View file

@ -6,8 +6,8 @@
// (See accompanying file LICENSE_1_0.txt or copy at // (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt) // http://www.boost.org/LICENSE_1_0.txt)
#define MOCK_RV_REF(z, n, d) \ #define MOCK_REF_ARG(z, n, d) \
BOOST_RV_REF(T##n) typename ref_arg< T##n >::type
namespace mock namespace mock
{ {
@ -24,7 +24,7 @@ namespace detail
virtual ~matcher_base() {} virtual ~matcher_base() {}
virtual bool operator()( virtual bool operator()(
BOOST_PP_ENUM(MOCK_NUM_ARGS, MOCK_RV_REF, _) ) = 0; BOOST_PP_ENUM(MOCK_NUM_ARGS, MOCK_REF_ARG, _) ) = 0;
friend std::ostream& operator<<( friend std::ostream& operator<<(
std::ostream& s, const matcher_base& m ) std::ostream& s, const matcher_base& m )
@ -38,3 +38,5 @@ namespace detail
}; };
} }
} // mock } // mock
#undef MOCK_REF_ARG

View file

@ -0,0 +1,78 @@
// http://turtle.sourceforge.net
//
// Copyright Mathieu Champlon 2018
//
// 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_MOVE_HELPER_HPP_INCLUDED
#define MOCK_MOVE_HELPER_HPP_INCLUDED
#include "../config.hpp"
#include <boost/type_traits/conditional.hpp>
#include <boost/type_traits/is_reference.hpp>
#include <boost/type_traits/remove_reference.hpp>
#include <boost/type_traits/add_reference.hpp>
#include <boost/type_traits/add_rvalue_reference.hpp>
#include <boost/type_traits/decay.hpp>
namespace mock
{
namespace detail
{
#ifdef MOCK_RVALUE_REFERENCES
template< typename T >
struct forward_type
{
typedef T type;
};
template< typename T >
struct ref_arg
{
typedef typename boost::conditional<
boost::is_reference< T >::value,
T,
typename boost::add_rvalue_reference< T >::type >::type type;
};
template< typename T >
inline T&& move_if_not_lvalue_reference(typename boost::remove_reference< T >::type& t)
{
return static_cast< T&& >(t);
}
template< typename T >
inline T&& move_if_not_lvalue_reference(typename boost::remove_reference< T >::type&& t)
{
return static_cast< T&& >(t);
}
#else
template< typename T >
struct forward_type
{
typedef typename boost::decay< const T >::type type;
};
template< class T>
struct forward_type< boost::rv< T > >
{
typedef T type;
};
template< typename T >
struct ref_arg
{
typedef typename boost::conditional<
boost::is_reference< T >::value,
T,
const typename boost::add_reference< T >::type >::type type;
};
template< typename T >
inline typename boost::remove_reference< T >::type& move_if_not_lvalue_reference(typename boost::remove_reference< T >::type& t)
{
return t;
}
#endif
}
}
#endif // MOCK_MOVE_HELPER_HPP_INCLUDED

View file

@ -13,7 +13,9 @@
#include "log.hpp" #include "log.hpp"
#include "constraints.hpp" #include "constraints.hpp"
#include "detail/is_functor.hpp" #include "detail/is_functor.hpp"
#include "detail/move_helper.hpp"
#include <boost/utility/enable_if.hpp> #include <boost/utility/enable_if.hpp>
#include <boost/type_traits/add_reference.hpp>
#include <boost/ref.hpp> #include <boost/ref.hpp>
#include <cstring> #include <cstring>
@ -26,7 +28,7 @@ namespace mock
explicit matcher( Expected expected ) explicit matcher( Expected expected )
: expected_( expected ) : expected_( expected )
{} {}
bool operator()( const Actual& actual ) bool operator()( typename boost::add_reference< const Actual >::type actual )
{ {
return mock::equal( return mock::equal(
boost::unwrap_ref( expected_ ) ).c_( actual ); boost::unwrap_ref( expected_ ) ).c_( actual );
@ -67,9 +69,9 @@ namespace mock
explicit matcher( const constraint< Constraint >& c ) explicit matcher( const constraint< Constraint >& c )
: c_( c.c_ ) : c_( c.c_ )
{} {}
bool operator()( BOOST_RV_REF(Actual) actual ) bool operator()( typename detail::ref_arg< Actual >::type actual )
{ {
return c_( boost::forward< Actual >( actual ) ); return c_( mock::detail::move_if_not_lvalue_reference< typename detail::ref_arg< Actual >::type >( actual ) );
} }
friend std::ostream& operator<<( friend std::ostream& operator<<(
std::ostream& s, const matcher& m ) std::ostream& s, const matcher& m )
@ -91,9 +93,9 @@ namespace mock
explicit matcher( const Functor& f ) explicit matcher( const Functor& f )
: c_( f ) : c_( f )
{} {}
bool operator()( BOOST_RV_REF(Actual) actual ) bool operator()( typename detail::ref_arg< Actual >::type actual )
{ {
return c_( boost::forward< Actual >( actual ) ); return c_( mock::detail::move_if_not_lvalue_reference< typename detail::ref_arg< Actual >::type >( actual ) );
} }
friend std::ostream& operator<<( friend std::ostream& operator<<(
std::ostream& s, const matcher& m ) std::ostream& s, const matcher& m )

View file

@ -87,7 +87,7 @@
BOOST_PP_COMMA_IF(n) d, n >::type >( p##n ) BOOST_PP_COMMA_IF(n) d, n >::type >( p##n )
#define MOCK_FORWARD_PARAMS(n, S, tpn) \ #define MOCK_FORWARD_PARAMS(n, S, tpn) \
BOOST_PP_REPEAT(n, MOCK_FORWARD_PARAM, \ BOOST_PP_REPEAT(n, MOCK_FORWARD_PARAM, \
boost::forward< MOCK_PARAM(S, tpn)) mock::detail::move_if_not_lvalue_reference< MOCK_PARAM(S, tpn))
#define MOCK_METHOD_AUX(M, n, S, t, c, tpn) \ #define MOCK_METHOD_AUX(M, n, S, t, c, tpn) \
MOCK_DECL(M, n, S, c, tpn) \ MOCK_DECL(M, n, S, c, tpn) \
{ \ { \

View file

@ -8,6 +8,7 @@
#include <turtle/constraints.hpp> #include <turtle/constraints.hpp>
#include <boost/test/auto_unit_test.hpp> #include <boost/test/auto_unit_test.hpp>
#include <boost/typeof/typeof.hpp>
BOOST_AUTO_TEST_CASE( all_comparison_constraints_can_be_instanciated ) BOOST_AUTO_TEST_CASE( all_comparison_constraints_can_be_instanciated )
{ {
@ -47,7 +48,7 @@ BOOST_AUTO_TEST_CASE( equal_constraint )
BOOST_CHECK( ! mock::equal( std::string( "string" ) ).c_( "not string" ) ); BOOST_CHECK( ! mock::equal( std::string( "string" ) ).c_( "not string" ) );
{ {
std::string s; std::string s;
auto c = mock::equal( boost::cref( s ) ); BOOST_AUTO( c, mock::equal( boost::cref( s ) ) );
s = "string"; s = "string";
BOOST_CHECK( c.c_( "string" ) ); BOOST_CHECK( c.c_( "string" ) );
} }