From 8d08012cdf3e6f28d5cd69b749ab56d2ddafff34 Mon Sep 17 00:00:00 2001 From: mat007 Date: Tue, 4 Jun 2013 22:01:57 +0000 Subject: [PATCH] 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 --- build/boost/doc/changelog.qbk | 7 +++ build/boost/doc/customization.qbk | 2 +- build/boost/doc/example/reference.cpp | 53 +++++++++++++++-- build/boost/doc/reference.qbk | 40 +++++++++---- build/boost/test/Jamfile.jam | 1 + build/vc100/turtle_test.vcxproj | 1 + build/vc100/turtle_test.vcxproj.filters | 3 + test/test_constraint.cpp | 28 +++++++++ turtle/constraint.hpp | 75 ++++++++++++++++++++----- turtle/constraints.hpp | 36 ++++++------ 10 files changed, 195 insertions(+), 51 deletions(-) create mode 100644 test/test_constraint.cpp diff --git a/build/boost/doc/changelog.qbk b/build/boost/doc/changelog.qbk index 7ed16c5..c6d733e 100644 --- a/build/boost/doc/changelog.qbk +++ b/build/boost/doc/changelog.qbk @@ -1,5 +1,12 @@ [section Changelog] +[section trunk] +Not yet released + +* Reworked MOCK_CONSTRAINT to be able to provide names to parameters + +[endsect] + [section 1.2.3] Released 20 May 2013 diff --git a/build/boost/doc/customization.qbk b/build/boost/doc/customization.qbk index 01b56e0..9e99f77 100644 --- a/build/boost/doc/customization.qbk +++ b/build/boost/doc/customization.qbk @@ -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]. -[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] diff --git a/build/boost/doc/example/reference.cpp b/build/boost/doc/example/reference.cpp index 4c4711e..2cd9462 100644 --- a/build/boost/doc/example/reference.cpp +++ b/build/boost/doc/example/reference.cpp @@ -759,8 +759,8 @@ BOOST_AUTO_TEST_CASE( demonstrates_resetting_a_static_mock_method ) namespace helpers_example_1 { //[ helpers_example_1 -MOCK_CONSTRAINT( 0, any, true ) // this is (almost) how mock::any is defined -MOCK_CONSTRAINT( 0, forty_two, actual == 42 ) // this defines a 'forty_two' constraint +MOCK_CONSTRAINT( any, true ) // this is how mock::any could be defined +MOCK_CONSTRAINT( forty_two, actual == 42 ) // this defines a 'forty_two' constraint BOOST_AUTO_TEST_CASE( mock_constraint_0_arity ) { @@ -774,8 +774,8 @@ BOOST_AUTO_TEST_CASE( mock_constraint_0_arity ) namespace helpers_example_2 { //[ helpers_example_2 -MOCK_CONSTRAINT( 1, equal, actual == expected_0 ) // this is how mock::equal is 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( equal, expected, actual == expected ) // this is how mock::equal could be defined +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 ) { @@ -789,7 +789,50 @@ BOOST_AUTO_TEST_CASE( mock_constraint_1_arity ) namespace 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 ) { diff --git a/build/boost/doc/reference.qbk b/build/boost/doc/reference.qbk index 145cc7f..b082d9d 100644 --- a/build/boost/doc/reference.qbk +++ b/build/boost/doc/reference.qbk @@ -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.] -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 : @@ -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.] -[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 : @@ -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.] -[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 : @@ -308,6 +308,8 @@ Synopsis : MOCK_EXPECT( identifier ).with( constraint_1, constraint_2, ... ); +The number of constraints must match the number of mocked parameters. + Constraints : [table @@ -395,7 +397,7 @@ A sequence enforces a given order between two or more expectations. 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. @@ -488,33 +490,47 @@ Example : [endsect] -[section Helpers] +[section Constraint] -This section presents various useful tools. - -[section MOCK_CONSTRAINT] +This section presents a simple means of creating a new constraint. 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 : [helpers_example_1] +or with the alternate more portable macro : + +[helpers_example_4] + Example with one extra argument : [helpers_example_2] +or with the alternate more portable macro : + +[helpers_example_5] + Example with two extra arguments : [helpers_example_3] -[endsect] +or with the alternate more portable macro : + +[helpers_example_6] [endsect] diff --git a/build/boost/test/Jamfile.jam b/build/boost/test/Jamfile.jam index 83222d8..447f5a9 100644 --- a/build/boost/test/Jamfile.jam +++ b/build/boost/test/Jamfile.jam @@ -18,6 +18,7 @@ rule run-test ( name ) } alias mock_tests : + [ run-test test_constraint ] [ run-test test_constraints ] [ run-test test_error ] [ run-test test_integration ] diff --git a/build/vc100/turtle_test.vcxproj b/build/vc100/turtle_test.vcxproj index 72ab186..50ed852 100644 --- a/build/vc100/turtle_test.vcxproj +++ b/build/vc100/turtle_test.vcxproj @@ -28,6 +28,7 @@ + diff --git a/build/vc100/turtle_test.vcxproj.filters b/build/vc100/turtle_test.vcxproj.filters index 9d769d5..8e5240c 100644 --- a/build/vc100/turtle_test.vcxproj.filters +++ b/build/vc100/turtle_test.vcxproj.filters @@ -63,5 +63,8 @@ Source Files + + Source Files + \ No newline at end of file diff --git a/test/test_constraint.cpp b/test/test_constraint.cpp new file mode 100644 index 0000000..d748eb0 --- /dev/null +++ b/test/test_constraint.cpp @@ -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 +#include + +#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 diff --git a/turtle/constraint.hpp b/turtle/constraint.hpp index a7f885a..6f3a6bf 100644 --- a/turtle/constraint.hpp +++ b/turtle/constraint.hpp @@ -11,12 +11,14 @@ #include "config.hpp" #include "log.hpp" +#include #include #include +#include #include #include #include -#include +#include namespace mock { @@ -124,7 +126,7 @@ namespace detail } } // mock -#define MOCK_UNARY_CONSTRAINT(n, Name, Expr) \ +#define MOCK_UNARY_CONSTRAINT(Name, n, Args, Expr) \ namespace detail \ { \ struct Name \ @@ -154,25 +156,34 @@ namespace detail #define MOCK_CONSTRAINT_MEMBER(z, n, d) \ 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 \ { \ template< BOOST_PP_ENUM_PARAMS(n, typename Expected_) > \ struct Name \ { \ explicit Name( \ - BOOST_PP_ENUM_BINARY_PARAMS(n, const Expected_, & e ) ) \ + BOOST_PP_ENUM_BINARY_PARAMS(n, const Expected_, & e) ) \ : BOOST_PP_ENUM(n, MOCK_CONSTRAINT_ASSIGN, _) \ {} \ template< typename Actual > \ bool operator()( const Actual& actual ) const \ { \ 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, \ - BOOST_PP_ENUM_BINARY_PARAMS(n, const T, & expected_ ) ) const \ + BOOST_PP_ENUM(n, \ + MOCK_CONSTRAINT_CREF_PARAM, (n, Args)) ) const \ { \ return Expr; \ } \ @@ -185,18 +196,52 @@ namespace detail BOOST_PP_REPEAT(n, MOCK_CONSTRAINT_MEMBER, _) \ }; \ } \ - template< BOOST_PP_ENUM_PARAMS(n, typename Expected_) > \ - mock::constraint< detail::Name< \ - BOOST_PP_ENUM_PARAMS(n, Expected_) > \ - > Name( BOOST_PP_ENUM_BINARY_PARAMS(n, Expected_, expected_ ) ) \ + template< BOOST_PP_ENUM_PARAMS(n, typename T) > \ + mock::constraint< \ + detail::Name< BOOST_PP_ENUM_PARAMS(n, T) > \ + > Name( BOOST_PP_ENUM(n, MOCK_CONSTRAINT_PARAM, (n, Args)) ) \ { \ - return detail::Name< BOOST_PP_ENUM_PARAMS(n, Expected_) >( \ - BOOST_PP_ENUM_PARAMS(n, expected_ ) ); \ + return detail::Name< BOOST_PP_ENUM_PARAMS(n, T) > Args; \ } -#define MOCK_CONSTRAINT(n, Name, Expr) \ +#define MOCK_CONSTRAINT_EXT(Name, n, Args, Expr) \ BOOST_PP_IF(n, \ 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 diff --git a/turtle/constraints.hpp b/turtle/constraints.hpp index 655fbc6..b1a7827 100644 --- a/turtle/constraints.hpp +++ b/turtle/constraints.hpp @@ -19,28 +19,28 @@ namespace mock { - MOCK_CONSTRAINT( 0, any, true && &actual ) - MOCK_CONSTRAINT( 0, affirm, !! actual ) - MOCK_CONSTRAINT( 0, negate, ! actual ) - MOCK_CONSTRAINT( 0, evaluate, actual() ) + MOCK_CONSTRAINT_EXT( any, 0,, true && &actual ) + MOCK_CONSTRAINT_EXT( affirm, 0,, !! actual ) + MOCK_CONSTRAINT_EXT( negate, 0,, ! actual ) + MOCK_CONSTRAINT_EXT( evaluate, 0,, actual() ) - MOCK_CONSTRAINT( 1, equal, actual == expected_0 ) - MOCK_CONSTRAINT( 1, less, actual < expected_0 ) - MOCK_CONSTRAINT( 1, greater, actual > expected_0 ) - MOCK_CONSTRAINT( 1, less_equal, actual <= expected_0 ) - MOCK_CONSTRAINT( 1, greater_equal, actual >= expected_0 ) + MOCK_CONSTRAINT_EXT( equal, 1, ( expected ), actual == expected ) + MOCK_CONSTRAINT_EXT( less, 1, ( expected ), actual < expected ) + MOCK_CONSTRAINT_EXT( greater, 1, ( expected ), actual > expected ) + MOCK_CONSTRAINT_EXT( less_equal, 1, ( expected ), actual <= expected ) + MOCK_CONSTRAINT_EXT( greater_equal, 1, ( expected ), actual >= expected ) - MOCK_CONSTRAINT( 1, small, \ - ( boost::test_tools::check_is_small( actual, expected_0 ) ) ) - MOCK_CONSTRAINT( 2, close, \ + MOCK_CONSTRAINT_EXT( small, 1, ( expected ), \ + ( boost::test_tools::check_is_small( actual, expected ) ) ) + MOCK_CONSTRAINT_EXT( close, 2, ( expected, tolerance ), \ ( boost::test_tools::check_is_close( \ - actual, expected_0, \ - boost::test_tools::percent_tolerance( expected_1 ) ) ) ) - MOCK_CONSTRAINT( 2, close_fraction, \ + actual, expected, \ + boost::test_tools::percent_tolerance( tolerance ) ) ) ) + MOCK_CONSTRAINT_EXT( close_fraction, 2, ( expected, tolerance ), \ ( boost::test_tools::check_is_close( \ - actual, expected_0, \ - boost::test_tools::fraction_tolerance( expected_1 ) ) ) ) - MOCK_CONSTRAINT( 2, near, std::abs( actual - expected_0 ) < expected_1 ) + actual, expected, \ + boost::test_tools::fraction_tolerance( tolerance ) ) ) ) + MOCK_CONSTRAINT_EXT( near, 2, ( expected, tolerance ), std::abs( actual - expected ) < tolerance ) namespace detail {