diff --git a/build/boost/doc/changelog.qbk b/build/boost/doc/changelog.qbk index d6602a4..3941891 100644 --- a/build/boost/doc/changelog.qbk +++ b/build/boost/doc/changelog.qbk @@ -5,7 +5,7 @@ Not yet released * Added support for C++11 lambdas as constraints * Return actions now accept by copy types derived from abstract base types -* Officially documented MOCK_UNARY_CONSTRAINT and MOCK_BINARY_CONSTRAINT +* Added MOCK_CONSTRAINT helper macro * Added support for several sequences in 'in' * Added support for nullptr as constraint * Added mock::close, mock::close_fraction, mock::small and mock::near constraints diff --git a/build/boost/doc/customization.qbk b/build/boost/doc/customization.qbk index e4f0044..01b56e0 100644 --- a/build/boost/doc/customization.qbk +++ b/build/boost/doc/customization.qbk @@ -64,7 +64,7 @@ Simple enough, however this constraint isn't serializable and thus yields a rath Just like a parameter, a constraint can be displayed in a readable form using its serialization operator, see [link turtle.customization.logging logging]. -Thus a widely used constraint (for instance one shipped with the code of a library) is likely better to be defined like this : +Thus a widely used constraint (for instance one shipped with the code of a library) is likely better defined like this : [custom_constraint_functor] @@ -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_unary_constraint MOCK_UNARY_CONSTRAINT] and [link turtle.reference.helpers.mock_binary_constraint MOCK_BINARY_CONSTRAINT] macros replace the need to write the constraints explicitly for the most trivial cases.] +[note The [link turtle.reference.helpers.mock_constraint MOCK_CONSTRAINT] 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 b59ded4..4c4711e 100644 --- a/build/boost/doc/example/reference.cpp +++ b/build/boost/doc/example/reference.cpp @@ -759,22 +759,42 @@ BOOST_AUTO_TEST_CASE( demonstrates_resetting_a_static_mock_method ) namespace helpers_example_1 { //[ helpers_example_1 -MOCK_UNARY_CONSTRAINT( any, true ) // this is (almost) how mock::any is defined -MOCK_UNARY_CONSTRAINT( forty_two, actual == 42 ) // this defines a 'forty_two' constraint +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 + +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_2 { //[ helpers_example_2 -MOCK_BINARY_CONSTRAINT( equal, actual == expected ) // this is how mock::equal is defined -MOCK_BINARY_CONSTRAINT( near, std::abs( actual - expected ) < 0.01 ) // this defines a 'near' constraint which can be used as 'near( 42 )' +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 )' + +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_3 { //[ helpers_example_3 -MOCK_TERNARY_CONSTRAINT( near, std::abs( actual - expected ) < arg ) // this defines a 'near' constraint which can be used as 'near( 42, 0.01 )' +MOCK_CONSTRAINT( 2, near, std::abs( actual - expected_0 ) < expected_1 ) // this is how mock::near is defined + +BOOST_AUTO_TEST_CASE( mock_constraint_2_arity ) +{ + MOCK_FUNCTOR( f, void( int ) ); + MOCK_EXPECT( f ).with( near( 42, 0.001 ) ); +} //] } diff --git a/build/boost/doc/reference.qbk b/build/boost/doc/reference.qbk index 4d4111c..145cc7f 100644 --- a/build/boost/doc/reference.qbk +++ b/build/boost/doc/reference.qbk @@ -323,10 +323,10 @@ Constraints : [[mock::greater( ['expected] )] [['actual] > ['expected]] [compares ['actual] to ['expected] using operator >]] [[mock::less_equal( ['expected] )] [['actual] <= ['expected]] [compares ['actual] to ['expected] using operator <=]] [[mock::greater_equal( ['expected] )] [['actual] >= ['expected]] [compares ['actual] to ['expected] using operator >=]] - [[mock::near] [std::abs( ['actual] - ['expected] ) < ['arg]] [checks whether ['actual] is near ['expected]]] - [[mock::close] [boost::test_tools::check_is_close( ['actual], ['expected], boost::test_tools::percent_tolerance( ['arg] ) )] [checks whether ['actual] is close to ['expected], see [@http://www.boost.org/libs/test/doc/html/utf/testing-tools/floating_point_comparison.html Floating-point comparison algorithms] ]] - [[mock::close_fraction] [boost::test_tools::check_is_close( ['actual], ['expected], boost::test_tools::fraction_tolerance( ['arg] ) )] [checks whether ['actual] is close to ['expected], see [@http://www.boost.org/libs/test/doc/html/utf/testing-tools/floating_point_comparison.html Floating-point comparison algorithms] ]] - [[mock::small] [boost::test_tools::check_is_small( ['actual], ['expected] ) )] [checks whether ['actual] is small with a tolerance of ['expected], see [@http://www.boost.org/libs/test/doc/html/utf/testing-tools/floating_point_comparison.html Floating-point comparison algorithms] ]] + [[mock::near( ['expected], ['tolerance] )] [std::abs( ['actual] - ['expected] ) < ['tolerance]] [checks whether ['actual] is near ['expected] within ['tolerance]]] + [[mock::close( ['expected], ['tolerance] )] [boost::test_tools::check_is_close( ['actual], ['expected], boost::test_tools::percent_tolerance( ['arg] ) )] [checks whether ['actual] is close to ['expected], see [@http://www.boost.org/libs/test/doc/html/utf/testing-tools/floating_point_comparison.html Floating-point comparison algorithms] ]] + [[mock::close_fraction( ['expected], ['tolerance] )] [boost::test_tools::check_is_close( ['actual], ['expected], boost::test_tools::fraction_tolerance( ['arg] ) )] [checks whether ['actual] is close to ['expected], see [@http://www.boost.org/libs/test/doc/html/utf/testing-tools/floating_point_comparison.html Floating-point comparison algorithms] ]] + [[mock::small( ['tolerance] )] [boost::test_tools::check_is_small( ['actual], ['expected] ) )] [checks whether ['actual] is small within ['tolerance], see [@http://www.boost.org/libs/test/doc/html/utf/testing-tools/floating_point_comparison.html Floating-point comparison algorithms] ]] [[mock::call( ['expected] )] [['expected]( ['actual] )] [calls ['expected] as a functor returning a ['bool] and accepting ['actual] as parameter]] [[mock::same( ['expected] )] [&['actual] == &['expected]] [compares ['actual] to ['expected] by comparing their pointers]] [[mock::assign( ['expected] )] [['actual] = ['expected], true @@ -490,49 +490,27 @@ Example : [section Helpers] -This section presents macros used to help with defining custom constraints. +This section presents various useful tools. -[section MOCK_UNARY_CONSTRAINT] +[section MOCK_CONSTRAINT] Synopsis : - MOCK_UNARY_CONSTRAINT( name, expression ) // defines a constraint 'name' based on the given 'expression' + MOCK_CONSTRAINT( arity, name, expression ) // defines a constraint 'name' based on the given 'expression' -The expression manipulates the received parameter 'actual' in order to implement the constraint. +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... -Example : +[note The type of all expected arguments must be copy-constructible and assignable.] + +Example without any extra argument : [helpers_example_1] -[endsect] - -[section MOCK_BINARY_CONSTRAINT] - -Synopsis : - - MOCK_BINARY_CONSTRAINT( name, expression ) // defines a constraint 'name' based on the given 'expression' - -The expression manipulates the received parameter 'actual' as well as the passed argument 'expected' in order to implement the constraint. - -[note The type of expected must be copy-constructible and assignable.] - -Example : +Example with one extra argument : [helpers_example_2] -[endsect] - -[section MOCK_TERNARY_CONSTRAINT] - -Synopsis : - - MOCK_TERNARY_CONSTRAINT( name, expression ) // defines a constraint 'name' based on the given 'expression' - -The expression manipulates the received parameter 'actual' as well as the passed arguments 'expected' and 'arg' in order to implement the constraint. - -[note The types of expected and arg must be copy-constructible and assignable.] - -Example : +Example with two extra arguments : [helpers_example_3] diff --git a/turtle/constraint.hpp b/turtle/constraint.hpp index bf06548..90881b3 100644 --- a/turtle/constraint.hpp +++ b/turtle/constraint.hpp @@ -12,6 +12,11 @@ #include "config.hpp" #include "log.hpp" #include +#include +#include +#include +#include +#include namespace mock { @@ -119,94 +124,79 @@ namespace detail } } // mock -#define MOCK_UNARY_CONSTRAINT(N, Expr) \ +#define MOCK_UNARY_CONSTRAINT(n, Name, Expr) \ namespace detail \ { \ - struct N \ + struct Name \ { \ template< typename Actual > \ bool operator()( const Actual& actual ) const \ { \ return Expr; \ } \ - friend std::ostream& operator<<( std::ostream& s, const N& ) \ + friend std::ostream& operator<<( std::ostream& s, const Name& ) \ { \ - return s << BOOST_STRINGIZE(N); \ + return s << BOOST_STRINGIZE(Name); \ } \ }; \ } \ - const mock::constraint< detail::N > N; + const mock::constraint< detail::Name > Name; -#define MOCK_BINARY_CONSTRAINT(N, Expr) \ +#define MOCK_CONSTRAINT_ASSIGN(z, n, d) \ + expected##n( e##n ) + +#define MOCK_CONSTRAINT_UNWRAP_REF(z, n, d) \ + boost::unwrap_ref( expected##n ) + +#define MOCK_CONSTRAINT_FORMAT(z, n, d) \ + BOOST_PP_IF(n, << ", " <<,) mock::format( c.expected##n ) + +#define MOCK_CONSTRAINT_MEMBER(z, n, d) \ + Expected_##n expected##n; + +#define MOCK_NARY_CONSTRAINT(n, Name, Expr) \ namespace detail \ { \ - template< typename Expected > \ - struct N \ + template< BOOST_PP_ENUM_PARAMS(n, typename Expected_) > \ + struct Name \ { \ - explicit N( const Expected& expected ) \ - : expected_( expected ) \ + explicit Name( \ + 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::unwrap_ref( expected_ ) ); \ + return test( actual, \ + BOOST_PP_ENUM(n, MOCK_CONSTRAINT_UNWRAP_REF, _ ) ); \ } \ - template< typename Actual, typename T > \ - bool test( const Actual& actual, const T& expected ) const \ - { \ - return Expr; \ - } \ - friend std::ostream& operator<<( std::ostream& s, const N& n ) \ - { \ - return s << BOOST_STRINGIZE(N) \ - << "( " << mock::format( n.expected_ ) << " )"; \ - } \ - Expected expected_; \ - }; \ - } \ - template< typename Expected > \ - mock::constraint< detail::N< Expected > > N( Expected expected ) \ - { \ - return detail::N< Expected >( expected ); \ - } - -#define MOCK_TERNARY_CONSTRAINT(N, Expr) \ - namespace detail \ - { \ - template< typename Expected, typename Arg > \ - struct N \ - { \ - explicit N( const Expected& expected, const Arg& arg ) \ - : expected_( expected ) \ - , arg_( arg ) \ - {} \ - template< typename Actual > \ - bool operator()( const Actual& actual ) const \ - { \ - return test( actual, boost::unwrap_ref( expected_ ), \ - boost::unwrap_ref( arg_ ) ); \ - } \ - template< typename Actual, typename T1, typename T2 > \ + template< typename Actual, BOOST_PP_ENUM_PARAMS(n, typename T) > \ bool test( const Actual& actual, \ - const T1& expected, const T2& arg ) const \ + BOOST_PP_ENUM_BINARY_PARAMS(n, const T, & expected_ ) ) const \ { \ return Expr; \ } \ - friend std::ostream& operator<<( std::ostream& s, const N& n ) \ + friend std::ostream& operator<<( std::ostream& s, const Name& c ) \ { \ - return s << BOOST_STRINGIZE(N) \ - << "( " << mock::format( n.expected_ ) \ - << ", " << mock::format( n.arg_ ) << " )"; \ + return s << BOOST_STRINGIZE(Name) << "( " \ + << BOOST_PP_REPEAT(n, MOCK_CONSTRAINT_FORMAT, _) \ + << " )"; \ } \ - Expected expected_; \ - Arg arg_; \ + BOOST_PP_REPEAT(n, MOCK_CONSTRAINT_MEMBER, _) \ }; \ } \ - template< typename Expected, typename Arg > \ - mock::constraint< detail::N< Expected, Arg > > N( \ - Expected expected, Arg arg ) \ + 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_ ) ) \ { \ - return detail::N< Expected, Arg >( expected, arg ); \ + return detail::Name< BOOST_PP_ENUM_PARAMS(n, Expected_) >( \ + BOOST_PP_ENUM_PARAMS(n, expected_ ) ); \ } +#define MOCK_CONSTRAINT(n, Name, Expr) \ + BOOST_PP_IF(n, \ + MOCK_NARY_CONSTRAINT, \ + MOCK_UNARY_CONSTRAINT)(n, Name, Expr) + #endif // MOCK_CONSTRAINT_HPP_INCLUDED diff --git a/turtle/constraints.hpp b/turtle/constraints.hpp index 7f2a241..655fbc6 100644 --- a/turtle/constraints.hpp +++ b/turtle/constraints.hpp @@ -14,37 +14,33 @@ #include "detail/addressof.hpp" #include #include -#include #include #include namespace mock { - MOCK_UNARY_CONSTRAINT( any, true && &actual ) - MOCK_UNARY_CONSTRAINT( affirm, !! actual ) - MOCK_UNARY_CONSTRAINT( negate, ! actual ) - MOCK_UNARY_CONSTRAINT( evaluate, actual() ) + MOCK_CONSTRAINT( 0, any, true && &actual ) + MOCK_CONSTRAINT( 0, affirm, !! actual ) + MOCK_CONSTRAINT( 0, negate, ! actual ) + MOCK_CONSTRAINT( 0, evaluate, actual() ) - MOCK_BINARY_CONSTRAINT( equal, actual == expected ) - MOCK_BINARY_CONSTRAINT( less, actual < expected ) - MOCK_BINARY_CONSTRAINT( greater, actual > expected ) - MOCK_BINARY_CONSTRAINT( less_equal, actual <= expected ) - MOCK_BINARY_CONSTRAINT( greater_equal, actual >= expected ) + 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_BINARY_CONSTRAINT( small, \ - ( boost::test_tools::check_is_small( actual, expected ) ) ); - - MOCK_TERNARY_CONSTRAINT( close, \ + MOCK_CONSTRAINT( 1, small, \ + ( boost::test_tools::check_is_small( actual, expected_0 ) ) ) + MOCK_CONSTRAINT( 2, close, \ ( boost::test_tools::check_is_close( \ - actual, expected, \ - boost::test_tools::percent_tolerance( arg ) ) ) ); - - MOCK_TERNARY_CONSTRAINT( close_fraction, \ + actual, expected_0, \ + boost::test_tools::percent_tolerance( expected_1 ) ) ) ) + MOCK_CONSTRAINT( 2, close_fraction, \ ( boost::test_tools::check_is_close( \ - actual, expected, \ - boost::test_tools::fraction_tolerance( arg ) ) ) ); - - MOCK_TERNARY_CONSTRAINT( near, std::abs( actual - expected ) < arg ); + actual, expected_0, \ + boost::test_tools::fraction_tolerance( expected_1 ) ) ) ) + MOCK_CONSTRAINT( 2, near, std::abs( actual - expected_0 ) < expected_1 ) namespace detail { diff --git a/turtle/detail/expectation_template.hpp b/turtle/detail/expectation_template.hpp index ccd6de2..8084ffb 100644 --- a/turtle/detail/expectation_template.hpp +++ b/turtle/detail/expectation_template.hpp @@ -32,6 +32,7 @@ #define MOCK_EXPECTATION_IN_ADD(z, n, d ) \ add( s##n.impl_ ); + #define MOCK_EXPECTATION_IN(z, n, d) \ expectation& in( BOOST_PP_ENUM_PARAMS(n, sequence& s) ) \ { \