From 4afe1d32d46ce883655608c8f58295100af30e19 Mon Sep 17 00:00:00 2001 From: mat007 Date: Thu, 11 Apr 2013 16:24:26 +0000 Subject: [PATCH] Added support for C++11 lambdas as constraints git-svn-id: https://svn.code.sf.net/p/turtle/code/trunk@620 860be788-9bd5-4423-9f1e-828f051e677b --- build/boost/doc/limitations.qbk | 6 ++++++ build/boost/doc/reference.qbk | 8 +++++++ test/detail/test_is_functor.cpp | 37 ++++++++++++++++++++++++++------- turtle/config.hpp | 5 +++++ turtle/detail/is_functor.hpp | 29 ++++++++++++++++++++++++-- turtle/matcher.hpp | 2 +- 6 files changed, 77 insertions(+), 10 deletions(-) diff --git a/build/boost/doc/limitations.qbk b/build/boost/doc/limitations.qbk index 4bb9450..470bb73 100644 --- a/build/boost/doc/limitations.qbk +++ b/build/boost/doc/limitations.qbk @@ -261,4 +261,10 @@ This is actually a bug in the compiler, for more information see [@http://connec [endsect] +[section Using C++11 lambda as constraints requires decltype compiler support] + +The technique used in order to detect whether a constraint is a C++11 lambda or not is based on decltype, which means the library can fail to detect a lambda in case the compiler does not support it. + +[endsect] + [endsect] diff --git a/build/boost/doc/reference.qbk b/build/boost/doc/reference.qbk index a357888..40663e4 100644 --- a/build/boost/doc/reference.qbk +++ b/build/boost/doc/reference.qbk @@ -590,6 +590,14 @@ Example using [@http://www.boost.org/libs/phoenix Boost.Phoenix] : MOCK_EXPECT( c.method ).with( boost::phoenix::arg_names::_1 == 42 ); } +Example using C++11 lambdas : + + BOOST_AUTO_TEST_CASE( demonstrates_adding_a_constraint_with_cxx11_lambda ) + { + mock_class c; + MOCK_EXPECT( c.method ).with( []( int actual ) { return 42 == actual; } ); + } + Example using &&, || and ! : BOOST_AUTO_TEST_CASE( demonstrates_combining_constraints ) diff --git a/test/detail/test_is_functor.cpp b/test/detail/test_is_functor.cpp index 1134b6c..c4e458f 100644 --- a/test/detail/test_is_functor.cpp +++ b/test/detail/test_is_functor.cpp @@ -22,19 +22,29 @@ namespace { struct declared_but_not_defined; - BOOST_MPL_ASSERT_NOT(( mock::detail::is_functor< declared_but_not_defined > )); + BOOST_MPL_ASSERT_NOT(( mock::detail::is_functor< declared_but_not_defined, int > )); template< typename T > void is_functor( T ) { - BOOST_MPL_ASSERT(( mock::detail::is_functor< T > )); + BOOST_MPL_ASSERT(( mock::detail::is_functor< T, int > )); + } + template< typename T > + void is_not_functor( T ) + { + BOOST_MPL_ASSERT_NOT(( mock::detail::is_functor< T, int > )); } - void f0 () {} + void f0() {} bool f1( int ) { return false; } bool f2( std::string, int ) { return false; } } +BOOST_AUTO_TEST_CASE( data_is_not_functor ) +{ + is_not_functor( 42 ); +} + BOOST_AUTO_TEST_CASE( function_is_functor ) { is_functor( f0 ); @@ -63,12 +73,11 @@ BOOST_AUTO_TEST_CASE( std_bind_first_is_functor ) namespace { struct unary_functor0 : public std::unary_function< void, void > - { - }; + {}; struct unary_functor1 : public std::unary_function< int, void > - { - }; + {}; } + BOOST_AUTO_TEST_CASE( std_unary_functor_is_functor ) { is_functor( unary_functor0() ); @@ -105,6 +114,7 @@ namespace typedef void result_type; }; } + BOOST_AUTO_TEST_CASE( class_with_result_type_is_functor ) { is_functor( result_type_functor() ); @@ -121,7 +131,20 @@ namespace }; }; } + BOOST_AUTO_TEST_CASE( class_with_sig_is_functor ) { is_functor( sig_functor() ); } + +#if !defined(BOOST_NO_CXX11_LAMBDAS) && !defined(BOOST_NO_LAMBDAS) + +BOOST_AUTO_TEST_CASE( cxx11_lambda_is_functor ) +{ + is_not_functor( []() {} ); + is_functor( []( int ) {} ); + is_not_functor( []( const std::string&, int ) {} ); + is_not_functor( []( int, const std::string& ) {} ); +} + +#endif diff --git a/turtle/config.hpp b/turtle/config.hpp index 8d9f04d..0ac8e25 100644 --- a/turtle/config.hpp +++ b/turtle/config.hpp @@ -9,6 +9,7 @@ #ifndef MOCK_CONFIG_HPP_INCLUDED #define MOCK_CONFIG_HPP_INCLUDED +#include #include #include @@ -48,4 +49,8 @@ # endif #endif +#if !defined(BOOST_NO_CXX11_DECLTYPE) && !defined(BOOST_NO_DECLTYPE) +# define MOCK_DECLTYPE +#endif + #endif // MOCK_CONFIG_HPP_INCLUDED diff --git a/turtle/detail/is_functor.hpp b/turtle/detail/is_functor.hpp index f8c96ce..e4d46bf 100644 --- a/turtle/detail/is_functor.hpp +++ b/turtle/detail/is_functor.hpp @@ -9,9 +9,11 @@ #ifndef MOCK_IS_FUNCTOR_HPP_INCLUDED #define MOCK_IS_FUNCTOR_HPP_INCLUDED +#include "../config.hpp" #include +#include +#include #include -#include #include namespace mock @@ -22,10 +24,33 @@ namespace detail BOOST_MPL_HAS_XXX_TEMPLATE_DEF( sig ) BOOST_MPL_HAS_XXX_TEMPLATE_DEF( result ) - template< typename T > +#ifdef MOCK_DECLTYPE + + template< typename T, typename P > + struct is_callable + { + typedef boost::type_traits::yes_type yes_type; + typedef boost::type_traits::no_type no_type; + + template< typename T > + static yes_type check( + decltype( boost::declval< T >()( boost::declval< P >() ) )* ); + template< typename T > + static no_type check( ... ); + + typedef boost::mpl::bool_< + sizeof( check< T >( 0 ) ) == sizeof( yes_type ) > type; + }; + +#endif // MOCK_DECLTYPE + + template< typename T, typename P > struct is_functor : boost::mpl::or_< boost::function_types::is_callable_builtin< T >, +#ifdef MOCK_DECLTYPE + is_callable< T, P >, +#endif has_result_type< T >, has_result< T >, has_sig< T > diff --git a/turtle/matcher.hpp b/turtle/matcher.hpp index 34bd83b..3c4dd07 100644 --- a/turtle/matcher.hpp +++ b/turtle/matcher.hpp @@ -84,7 +84,7 @@ namespace mock template< typename Actual, typename Functor > class matcher< Actual, Functor, BOOST_DEDUCED_TYPENAME boost::enable_if< - detail::is_functor< Functor > + detail::is_functor< Functor, Actual > >::type > : public detail::matcher_base< Actual > {