Reworked MOCK_CONSTRAINT to be able to provide names to parameters

git-svn-id: https://svn.code.sf.net/p/turtle/code/trunk@667 860be788-9bd5-4423-9f1e-828f051e677b
This commit is contained in:
mat007 2013-06-04 22:01:57 +00:00
parent bd2fc97bb9
commit 8d08012cdf
10 changed files with 195 additions and 51 deletions

View file

@ -1,5 +1,12 @@
[section Changelog] [section Changelog]
[section trunk]
Not yet released
* Reworked MOCK_CONSTRAINT to be able to provide names to parameters
[endsect]
[section 1.2.3] [section 1.2.3]
Released 20 May 2013 Released 20 May 2013

View file

@ -99,7 +99,7 @@ See [link turtle.reference.expectation.constraints constraints] for an explanati
For more information about the serialization operator and the use of mock::format, refer to [link turtle.customization.logging loggin]. For more information about the serialization operator and the use of mock::format, refer to [link turtle.customization.logging loggin].
[note The [link turtle.reference.helpers.mock_constraint MOCK_CONSTRAINT] macro takes care of everything for simple cases.] [note The [link turtle.reference.constraint constraint helper macro] takes care of everything for simple cases.]
[endsect] [endsect]

View file

@ -759,8 +759,8 @@ BOOST_AUTO_TEST_CASE( demonstrates_resetting_a_static_mock_method )
namespace helpers_example_1 namespace helpers_example_1
{ {
//[ helpers_example_1 //[ helpers_example_1
MOCK_CONSTRAINT( 0, any, true ) // this is (almost) how mock::any is defined MOCK_CONSTRAINT( any, true ) // this is how mock::any could be defined
MOCK_CONSTRAINT( 0, forty_two, actual == 42 ) // this defines a 'forty_two' constraint MOCK_CONSTRAINT( forty_two, actual == 42 ) // this defines a 'forty_two' constraint
BOOST_AUTO_TEST_CASE( mock_constraint_0_arity ) BOOST_AUTO_TEST_CASE( mock_constraint_0_arity )
{ {
@ -774,8 +774,8 @@ BOOST_AUTO_TEST_CASE( mock_constraint_0_arity )
namespace helpers_example_2 namespace helpers_example_2
{ {
//[ helpers_example_2 //[ helpers_example_2
MOCK_CONSTRAINT( 1, equal, actual == expected_0 ) // this is how mock::equal is defined MOCK_CONSTRAINT( equal, expected, actual == expected ) // this is how mock::equal could be defined
MOCK_CONSTRAINT( 1, near, std::abs( actual - expected_0 ) < 0.01 ) // this defines a 'near' constraint which can be used as 'near( 42 )' MOCK_CONSTRAINT( near, expected, std::abs( actual - expected ) < 0.01 ) // this defines a 'near' constraint which can be used as 'near( 42 )'
BOOST_AUTO_TEST_CASE( mock_constraint_1_arity ) BOOST_AUTO_TEST_CASE( mock_constraint_1_arity )
{ {
@ -789,7 +789,50 @@ BOOST_AUTO_TEST_CASE( mock_constraint_1_arity )
namespace helpers_example_3 namespace helpers_example_3
{ {
//[ helpers_example_3 //[ helpers_example_3
MOCK_CONSTRAINT( 2, near, std::abs( actual - expected_0 ) < expected_1 ) // this is how mock::near is defined MOCK_CONSTRAINT( near, expected, tolerance, std::abs( actual - expected ) < tolerance ) // this is how mock::near could be defined
BOOST_AUTO_TEST_CASE( mock_constraint_2_arity )
{
MOCK_FUNCTOR( f, void( int ) );
MOCK_EXPECT( f ).with( near( 42, 0.001 ) );
}
//]
}
namespace helpers_example_4
{
//[ helpers_example_4
MOCK_CONSTRAINT_EXT( any, 0,, true ) // this is (almost) how mock::any is defined
MOCK_CONSTRAINT_EXT( forty_two, 0,, actual == 42 ) // this defines a 'forty_two' constraint
BOOST_AUTO_TEST_CASE( mock_constraint_0_arity )
{
MOCK_FUNCTOR( f, void( int ) );
MOCK_EXPECT( f ).with( forty_two );
MOCK_EXPECT( f ).with( any );
}
//]
}
namespace helpers_example_5
{
//[ helpers_example_5
MOCK_CONSTRAINT_EXT( equal, 1, ( expected ), actual == expected ) // this is how mock::equal is defined
MOCK_CONSTRAINT_EXT( near, 1, ( expected ), std::abs( actual - expected ) < 0.01 ) // this defines a 'near' constraint which can be used as 'near( 42 )'
BOOST_AUTO_TEST_CASE( mock_constraint_1_arity )
{
MOCK_FUNCTOR( f, void( int ) );
MOCK_EXPECT( f ).with( near( 42 ) );
MOCK_EXPECT( f ).with( equal( 42 ) );
}
//]
}
namespace helpers_example_6
{
//[ helpers_example_6
MOCK_CONSTRAINT_EXT( near, 2, ( expected, tolerance ), std::abs( actual - expected ) < tolerance ) // this is how mock::near is defined
BOOST_AUTO_TEST_CASE( mock_constraint_2_arity ) BOOST_AUTO_TEST_CASE( mock_constraint_2_arity )
{ {

View file

@ -96,7 +96,7 @@ Synopsis :
[note [link turtle.reference.creation.constructor Constructors], [link turtle.reference.creation.destructor destructors] and [link turtle.reference.creation.conversion_operator conversion operators] require special care.] [note [link turtle.reference.creation.constructor Constructors], [link turtle.reference.creation.destructor destructors] and [link turtle.reference.creation.conversion_operator conversion operators] require special care.]
With a compiler without support for variadic macros the signature and the identifier cannot be specified, thus in case of ambiguity another set of macros must be used. For compilers without support for variadic macros the signature and the identifier cannot be specified, thus in case of ambiguity another set of macros must be used.
Synopsis : Synopsis :
@ -150,7 +150,7 @@ Synopsis :
[note A static object is used behind the scene in order to keep track of the expectations of a mock static method, therefore to ensure all tests run in isolation it is strongly suggested to manually [link turtle.reference.verification verify] and [link turtle.reference.reset reset] the static method at the end of each test.] [note A static object is used behind the scene in order to keep track of the expectations of a mock static method, therefore to ensure all tests run in isolation it is strongly suggested to manually [link turtle.reference.verification verify] and [link turtle.reference.reset reset] the static method at the end of each test.]
[warning With a compiler without support for variadic macros the identifier cannot be ommitted and must be given explicitly.] [warning For compilers without support for variadic macros the identifier cannot be ommitted and must be given explicitly.]
Example : Example :
@ -244,7 +244,7 @@ Synopsis :
[note A static object is used behind the scene in order to keep track of the expectations of a mock function, therefore to ensure all tests run in isolation it is strongly suggested to manually [link turtle.reference.verification verify] and [link turtle.reference.reset reset] the mock function at the end of each test.] [note A static object is used behind the scene in order to keep track of the expectations of a mock function, therefore to ensure all tests run in isolation it is strongly suggested to manually [link turtle.reference.verification verify] and [link turtle.reference.reset reset] the mock function at the end of each test.]
[warning With a compiler without support for variadic macros the identifier cannot be ommitted and must be given explicitly.] [warning For compilers without support for variadic macros the identifier cannot be ommitted and must be given explicitly.]
Example : Example :
@ -308,6 +308,8 @@ Synopsis :
MOCK_EXPECT( identifier ).with( constraint_1, constraint_2, ... ); MOCK_EXPECT( identifier ).with( constraint_1, constraint_2, ... );
The number of constraints must match the number of mocked parameters.
Constraints : Constraints :
[table [table
@ -395,7 +397,7 @@ A sequence enforces a given order between two or more expectations.
Synopsis : Synopsis :
MOCK_EXPECT( identifier_1 ).in( sequence_1 [, sequence_2 [, ...]] ); MOCK_EXPECT( identifier_1 ).in( sequence_1, sequence_2, ... );
Each sequence is an instance of mock::sequence. Each sequence is an instance of mock::sequence.
@ -488,33 +490,47 @@ Example :
[endsect] [endsect]
[section Helpers] [section Constraint]
This section presents various useful tools. This section presents a simple means of creating a new constraint.
[section MOCK_CONSTRAINT]
Synopsis : Synopsis :
MOCK_CONSTRAINT( arity, name, expression ) // defines a constraint 'name' based on the given 'expression' MOCK_CONSTRAINT( name, expected_1, expected_2, ..., expression ) // defines a constraint 'name' based on the given 'expression'
The expression manipulates the received parameter ['actual] in order to implement the constraint, as well as ['arity] extra expected arguments ['expected_0], ['expected_1], etc... The expression manipulates a received parameter ['actual] in order to implement the constraint, as well as extra optional arguments named ['expected_1], ['expected_2], ...
[note The type of all expected arguments must be copy-constructible and assignable.] For compilers without supporting variadic macros the alternate following macro must be used.
Synopsis :
MOCK_CONSTRAINT_EXT( name, arity, ( expected_1, expected_2, ... ), expression ) // defines a constraint 'name' based on the given 'expression'
Of course this macro is also available for compilers which support variadic macros.
Example without any extra argument : Example without any extra argument :
[helpers_example_1] [helpers_example_1]
or with the alternate more portable macro :
[helpers_example_4]
Example with one extra argument : Example with one extra argument :
[helpers_example_2] [helpers_example_2]
or with the alternate more portable macro :
[helpers_example_5]
Example with two extra arguments : Example with two extra arguments :
[helpers_example_3] [helpers_example_3]
[endsect] or with the alternate more portable macro :
[helpers_example_6]
[endsect] [endsect]

View file

@ -18,6 +18,7 @@ rule run-test ( name )
} }
alias mock_tests : alias mock_tests :
[ run-test test_constraint ]
[ run-test test_constraints ] [ run-test test_constraints ]
[ run-test test_error ] [ run-test test_error ]
[ run-test test_integration ] [ run-test test_integration ]

View file

@ -28,6 +28,7 @@
<ClCompile Include="..\..\test\detail\test_is_functor.cpp" /> <ClCompile Include="..\..\test\detail\test_is_functor.cpp" />
<ClCompile Include="..\..\test\detail\test_signature.cpp" /> <ClCompile Include="..\..\test\detail\test_signature.cpp" />
<ClCompile Include="..\..\test\detail\test_type_name.cpp" /> <ClCompile Include="..\..\test\detail\test_type_name.cpp" />
<ClCompile Include="..\..\test\test_constraint.cpp" />
<ClCompile Include="..\..\test\test_constraints.cpp" /> <ClCompile Include="..\..\test\test_constraints.cpp" />
<ClCompile Include="..\..\test\test_error.cpp" /> <ClCompile Include="..\..\test\test_error.cpp" />
<ClCompile Include="..\..\test\test_integration.cpp" /> <ClCompile Include="..\..\test\test_integration.cpp" />

View file

@ -63,5 +63,8 @@
<ClCompile Include="..\..\test\undefined.cpp"> <ClCompile Include="..\..\test\undefined.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\test\test_constraint.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
</Project> </Project>

28
test/test_constraint.cpp Normal file
View file

@ -0,0 +1,28 @@
// http://turtle.sourceforge.net
//
// Copyright Mathieu Champlon 2013
//
// 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)
#include <turtle/constraint.hpp>
#include <boost/test/auto_unit_test.hpp>
#ifndef BOOST_NO_VARIADIC_MACROS
namespace
{
MOCK_CONSTRAINT( constraint_0, actual == 0 )
MOCK_CONSTRAINT( constraint_1, expected, actual == expected )
MOCK_CONSTRAINT( constraint_2, expected_0, expected_1, actual == expected_0 || actual == expected_1 )
}
BOOST_AUTO_TEST_CASE( mock_constraint_is_supported_by_compilers_with_variadic_macros )
{
BOOST_CHECK( constraint_0.c_( 0 ) );
BOOST_CHECK( constraint_1( 0 ).c_( 0 ) );
BOOST_CHECK( constraint_2( 0, 0 ).c_( 0 ) );
}
#endif // BOOST_NO_VARIADIC_MACROS

View file

@ -11,12 +11,14 @@
#include "config.hpp" #include "config.hpp"
#include "log.hpp" #include "log.hpp"
#include <boost/ref.hpp>
#include <boost/preprocessor/stringize.hpp> #include <boost/preprocessor/stringize.hpp>
#include <boost/preprocessor/control/if.hpp> #include <boost/preprocessor/control/if.hpp>
#include <boost/preprocessor/variadic/to_array.hpp>
#include <boost/preprocessor/repetition/enum_binary_params.hpp> #include <boost/preprocessor/repetition/enum_binary_params.hpp>
#include <boost/preprocessor/repetition/enum_params.hpp> #include <boost/preprocessor/repetition/enum_params.hpp>
#include <boost/preprocessor/repetition/enum.hpp> #include <boost/preprocessor/repetition/enum.hpp>
#include <boost/preprocessor/repetition/repeat.hpp> #include <boost/preprocessor/array.hpp>
namespace mock namespace mock
{ {
@ -124,7 +126,7 @@ namespace detail
} }
} // mock } // mock
#define MOCK_UNARY_CONSTRAINT(n, Name, Expr) \ #define MOCK_UNARY_CONSTRAINT(Name, n, Args, Expr) \
namespace detail \ namespace detail \
{ \ { \
struct Name \ struct Name \
@ -154,7 +156,15 @@ 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_NARY_CONSTRAINT(n, Name, Expr) \ #define MOCK_CONSTRAINT_CREF_PARAM(z, n, Args) \
BOOST_DEDUCED_TYPENAME \
boost::unwrap_reference< Expected_##n >::type \
BOOST_PP_ARRAY_ELEM(n, Args)
#define MOCK_CONSTRAINT_PARAM(z, n, Args) \
T##n BOOST_PP_ARRAY_ELEM(n, Args)
#define MOCK_NARY_CONSTRAINT(Name, n, Args, Expr) \
namespace detail \ namespace detail \
{ \ { \
template< BOOST_PP_ENUM_PARAMS(n, typename Expected_) > \ template< BOOST_PP_ENUM_PARAMS(n, typename Expected_) > \
@ -170,9 +180,10 @@ namespace detail
return test( actual, \ return test( actual, \
BOOST_PP_ENUM(n, MOCK_CONSTRAINT_UNWRAP_REF, _) ); \ BOOST_PP_ENUM(n, MOCK_CONSTRAINT_UNWRAP_REF, _) ); \
} \ } \
template< typename Actual, BOOST_PP_ENUM_PARAMS(n, typename T) > \ template< typename Actual > \
bool test( const Actual& actual, \ bool test( const Actual& actual, \
BOOST_PP_ENUM_BINARY_PARAMS(n, const T, & expected_ ) ) const \ BOOST_PP_ENUM(n, \
MOCK_CONSTRAINT_CREF_PARAM, (n, Args)) ) const \
{ \ { \
return Expr; \ return Expr; \
} \ } \
@ -185,18 +196,52 @@ namespace detail
BOOST_PP_REPEAT(n, MOCK_CONSTRAINT_MEMBER, _) \ BOOST_PP_REPEAT(n, MOCK_CONSTRAINT_MEMBER, _) \
}; \ }; \
} \ } \
template< BOOST_PP_ENUM_PARAMS(n, typename Expected_) > \ template< BOOST_PP_ENUM_PARAMS(n, typename T) > \
mock::constraint< detail::Name< \ mock::constraint< \
BOOST_PP_ENUM_PARAMS(n, Expected_) > \ detail::Name< BOOST_PP_ENUM_PARAMS(n, T) > \
> Name( BOOST_PP_ENUM_BINARY_PARAMS(n, Expected_, expected_ ) ) \ > Name( BOOST_PP_ENUM(n, MOCK_CONSTRAINT_PARAM, (n, Args)) ) \
{ \ { \
return detail::Name< BOOST_PP_ENUM_PARAMS(n, Expected_) >( \ return detail::Name< BOOST_PP_ENUM_PARAMS(n, T) > Args; \
BOOST_PP_ENUM_PARAMS(n, expected_ ) ); \
} }
#define MOCK_CONSTRAINT(n, Name, Expr) \ #define MOCK_CONSTRAINT_EXT(Name, n, Args, Expr) \
BOOST_PP_IF(n, \ BOOST_PP_IF(n, \
MOCK_NARY_CONSTRAINT, \ MOCK_NARY_CONSTRAINT, \
MOCK_UNARY_CONSTRAINT)(n, Name, Expr) MOCK_UNARY_CONSTRAINT)(Name, n, Args, Expr)
#ifndef BOOST_NO_VARIADIC_MACROS
#if BOOST_MSVC
# define MOCK_VARIADIC_SIZE(...) \
BOOST_PP_CAT(MOCK_VARIADIC_SIZE_I(__VA_ARGS__, \
32, 31, 30, 29, 28, 27, 26, 25, 24, 23, \
22, 21, 20, 19, 18, 17, 16, 15, 14, 13, \
12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1,),)
#else // BOOST_MSVC
# define MOCK_VARIADIC_SIZE(...) \
MOCK_VARIADIC_SIZE_I(__VA_ARGS__, \
32, 31, 30, 29, 28, 27, 26, 25, 24, 23, \
22, 21, 20, 19, 18, 17, 16, 15, 14, 13, \
12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1,)
#endif // BOOST_MSVC
#define MOCK_VARIADIC_SIZE_I( \
e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, \
e13, e14, e15, e16, e17, e18, e19, e20, e21, e22, e23, e24, \
e25, e26, e27, e28, e29, e30, e31, size, ...) size
#define MOCK_CONSTRAINT_AUX_AUX(Name, n, Array) \
MOCK_CONSTRAINT_EXT( \
Name, n, \
BOOST_PP_ARRAY_TO_TUPLE(BOOST_PP_ARRAY_POP_BACK(Array)), \
BOOST_PP_ARRAY_ELEM(n, Array))
#define MOCK_CONSTRAINT_AUX(Name, Size, Tuple) \
MOCK_CONSTRAINT_AUX_AUX(Name, BOOST_PP_DEC(Size), (Size,Tuple))
#define MOCK_CONSTRAINT(Name, ...) \
MOCK_CONSTRAINT_AUX( \
Name, MOCK_VARIADIC_SIZE(__VA_ARGS__), (__VA_ARGS__))
#endif // BOOST_NO_VARIADIC_MACROS
#endif // MOCK_CONSTRAINT_HPP_INCLUDED #endif // MOCK_CONSTRAINT_HPP_INCLUDED

View file

@ -19,28 +19,28 @@
namespace mock namespace mock
{ {
MOCK_CONSTRAINT( 0, any, true && &actual ) MOCK_CONSTRAINT_EXT( any, 0,, true && &actual )
MOCK_CONSTRAINT( 0, affirm, !! actual ) MOCK_CONSTRAINT_EXT( affirm, 0,, !! actual )
MOCK_CONSTRAINT( 0, negate, ! actual ) MOCK_CONSTRAINT_EXT( negate, 0,, ! actual )
MOCK_CONSTRAINT( 0, evaluate, actual() ) MOCK_CONSTRAINT_EXT( evaluate, 0,, actual() )
MOCK_CONSTRAINT( 1, equal, actual == expected_0 ) MOCK_CONSTRAINT_EXT( equal, 1, ( expected ), actual == expected )
MOCK_CONSTRAINT( 1, less, actual < expected_0 ) MOCK_CONSTRAINT_EXT( less, 1, ( expected ), actual < expected )
MOCK_CONSTRAINT( 1, greater, actual > expected_0 ) MOCK_CONSTRAINT_EXT( greater, 1, ( expected ), actual > expected )
MOCK_CONSTRAINT( 1, less_equal, actual <= expected_0 ) MOCK_CONSTRAINT_EXT( less_equal, 1, ( expected ), actual <= expected )
MOCK_CONSTRAINT( 1, greater_equal, actual >= expected_0 ) MOCK_CONSTRAINT_EXT( greater_equal, 1, ( expected ), actual >= expected )
MOCK_CONSTRAINT( 1, small, \ MOCK_CONSTRAINT_EXT( small, 1, ( expected ), \
( boost::test_tools::check_is_small( actual, expected_0 ) ) ) ( boost::test_tools::check_is_small( actual, expected ) ) )
MOCK_CONSTRAINT( 2, close, \ MOCK_CONSTRAINT_EXT( close, 2, ( expected, tolerance ), \
( boost::test_tools::check_is_close( \ ( boost::test_tools::check_is_close( \
actual, expected_0, \ actual, expected, \
boost::test_tools::percent_tolerance( expected_1 ) ) ) ) boost::test_tools::percent_tolerance( tolerance ) ) ) )
MOCK_CONSTRAINT( 2, close_fraction, \ MOCK_CONSTRAINT_EXT( close_fraction, 2, ( expected, tolerance ), \
( boost::test_tools::check_is_close( \ ( boost::test_tools::check_is_close( \
actual, expected_0, \ actual, expected, \
boost::test_tools::fraction_tolerance( expected_1 ) ) ) ) boost::test_tools::fraction_tolerance( tolerance ) ) ) )
MOCK_CONSTRAINT( 2, near, std::abs( actual - expected_0 ) < expected_1 ) MOCK_CONSTRAINT_EXT( near, 2, ( expected, tolerance ), std::abs( actual - expected ) < tolerance )
namespace detail namespace detail
{ {