diff --git a/doc/changelog.qbk b/doc/changelog.qbk index c13a15b..c95e588 100644 --- a/doc/changelog.qbk +++ b/doc/changelog.qbk @@ -13,6 +13,7 @@ Not yet released * Dropped support for obsolete Boost.Phoenix V2 * Added support for multiple parameters constraints * Added inline to generated MOCK_FUNCTION +* Documented limitation concerning MOCK_METHOD_TPL [section 1.2.6] Released 24 May 2014 diff --git a/doc/example/limitations_template_base_class_method.cpp b/doc/example/limitations_template_base_class_method.cpp new file mode 100644 index 0000000..e4bfc49 --- /dev/null +++ b/doc/example/limitations_template_base_class_method.cpp @@ -0,0 +1,78 @@ +// http://turtle.sourceforge.net +// +// Copyright Mathieu Champlon 2014 +// +// 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) + +#define BOOST_AUTO_TEST_MAIN +#include +#include + +namespace limitations_template_base_class_method_problem +{ +//[ limitations_template_base_class_method_problem +template< typename T > +class base +{ +public: + virtual ~base() + {} + + virtual void method() = 0; +}; +//] + +//[ limitations_template_base_class_method_solution +template< typename T > +MOCK_BASE_CLASS( mock_base, base< T > ) +{ + MOCK_METHOD( method, 1, void() ) +}; +//] +} + +namespace limitations_template_base_class_method_problem_2 +{ +//[ limitations_template_base_class_method_problem_2 +class concept +{ +public: + template< typename T > + T create() + { + return T(); + } +}; + +template< typename T > +void function_under_test( T t ) // T is supposed to model the previous concept +{ + t.template create< int >(); + t.template create< std::string >(); +} +//] + +//[ limitations_template_base_class_method_solution_2 +MOCK_CLASS( mock_concept ) +{ + template< typename T > + T create(); + + MOCK_METHOD( create_int, 0, int(), create_int ) + MOCK_METHOD( create_string, 0, std::string(), create_string ) +}; + +template<> +int mock_concept::create< int >() +{ + return create_int(); +} +template<> +std::string mock_concept::create< std::string >() +{ + return create_string(); +} +//] +} diff --git a/doc/limitations.qbk b/doc/limitations.qbk index 6f2274c..e8a5c57 100644 --- a/doc/limitations.qbk +++ b/doc/limitations.qbk @@ -53,6 +53,22 @@ or with C++11 nullptr support : [endsect] +[section Non-virtual methods cannot be mocked] + +Given : + +[limitations_non_virtual_method_problem] + +the following code compiles but will not work as expected : + +[limitations_non_virtual_method_problem_2] + +The mock object will never be exercised because the library relies on polymorphism to hook the calls. + +There is no other solution than to refactor the production code, the most simple being to change the method to virtual. + +[endsect] + [section Template methods cannot be mocked] Given : @@ -75,23 +91,27 @@ While still somewhat possible, mocking a template method can indeed prove a bit [endsect] -[section Non-virtual methods cannot be mocked] +[section Template base class methods cannot be mocked without specifying the signature] Given : -[limitations_non_virtual_method_problem] +[limitations_template_base_class_method_problem] -the following code compiles but will not work as expected : +the following code does not compile : -[limitations_non_virtual_method_problem_2] + template< typename T > + MOCK_BASE_CLASS( mock_base, base< T > ) + { + MOCK_METHOD( method, 0 ) // this fails + }; -The mock object will never be exercised because the library relies on polymorphism to hook the calls. +A workaround would be to add the signature to MOCK_METHOD : -There is no other solution than to refactor the production code, the most simple being to change the method to virtual. +[limitations_template_base_class_method_solution] [endsect] -[section Private virtual methods cannot be mocked without spelling out the signature] +[section Private virtual methods cannot be mocked without specifying the signature] Given : @@ -101,7 +121,7 @@ the following code does not compile : MOCK_BASE_CLASS( mock_base, base ) { - MOCK_METHOD( method, 0 ) // this fails because 'method' is not visible + MOCK_METHOD( method, 0 ) // this fails because 'method' is not visible }; A workaround would be to add the signature to MOCK_METHOD : @@ -120,7 +140,7 @@ the following code does not compile : MOCK_BASE_CLASS( mock_class, base_class ) { - MOCK_METHOD( method, 0 ) // this fails because of the throw specifier + MOCK_METHOD( method, 0 ) // this fails because of the throw specifier }; A workaround would be to write a proxy member function : diff --git a/doc/reference.qbk b/doc/reference.qbk index e4d0fb4..fa76cb9 100644 --- a/doc/reference.qbk +++ b/doc/reference.qbk @@ -87,18 +87,20 @@ Deriving from mock::object is optional but provides the additional following ben Synopsis : - MOCK_METHOD( [calling convention] name, arity[, signature[, identifier]] ) // generates both const and non-const methods - MOCK_CONST_METHOD( [calling convention] name, arity[, signature[, identifier]] ) // generates only the const version of the method - MOCK_NON_CONST_METHOD( [calling convention] name, arity[, signature[, identifier]] ) // generates only the non-const version of the method + MOCK_METHOD( [calling convention] name, arity[, signature[, identifier]] ) // generates both const and non-const methods + MOCK_CONST_METHOD( [calling convention] name, arity[, signature[, identifier]] ) // generates only the const version of the method + MOCK_NON_CONST_METHOD( [calling convention] name, arity[, signature[, identifier]] ) // generates only the non-const version of the method - MOCK_METHOD_TPL( [calling convention] name, arity[, signature[, identifier]] ) // must be used if the signature uses a template parameter of the class, generates both const and non-const methods - MOCK_CONST_METHOD_TPL( [calling convention] name, arity[, signature[, identifier]] ) // must be used if the signature uses a template parameter of the class, generates only the const version of the method - MOCK_NON_CONST_METHOD_TPL( [calling convention] name, arity[, signature[, identifier]] ) // must be used if the signature uses a template parameter of the class, generates only the non-const version of the method + MOCK_METHOD_TPL( [calling convention] name, arity, signature[, identifier] ) // must be used if the signature uses a template parameter of the class, generates both const and non-const methods + MOCK_CONST_METHOD_TPL( [calling convention] name, arity, signature[, identifier] ) // must be used if the signature uses a template parameter of the class, generates only the const version of the method + MOCK_NON_CONST_METHOD_TPL( [calling convention] name, arity, signature[, identifier] ) // must be used if the signature uses a template parameter of the class, generates only the non-const version of the method [note If the identifier is omitted it will default to the method name.] [note If the method name is not ambiguous both the signature and the identifier can be omitted in the context of a derived MOCK_BASE_CLASS or base_type typedef.] +[note The signature cannot be omitted for the _TPL familly of macros, see the related [link turtle.limitations.template_base_class_methods_cannot_be_mocked_without_specifying_the_signature limitation section].] + [note The signature must be surrounded with round parenthesis if the return type contains a comma.] [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.] diff --git a/test/test_mock.cpp b/test/test_mock.cpp index 8a15879..0961b0d 100644 --- a/test/test_mock.cpp +++ b/test/test_mock.cpp @@ -378,8 +378,9 @@ namespace }; template< typename T > - MOCK_CLASS( variadic_tpl ) + MOCK_BASE_CLASS( variadic_tpl, base ) { + MOCK_METHOD( m1, 0 ) MOCK_METHOD_TPL( m2, 0, T() ) MOCK_METHOD_TPL( m3, 0, T(), m3 ) MOCK_CONST_METHOD_TPL( m4, 0, T() ) @@ -400,6 +401,30 @@ namespace MOCK_FUNCTOR( f_variadic, std::map< int, int >() ); } +#else // MOCK_VARIADIC_MACROS + +namespace +{ + struct base + { + virtual ~base() + {} + protected: + virtual void m1() = 0; + }; + + MOCK_BASE_CLASS( derived, base ) + { + MOCK_METHOD( m1, 0 ) + }; + + template< typename T > + MOCK_BASE_CLASS( derived_tpl, base ) + { + MOCK_METHOD( m1, 0 ) + }; +} + #endif // MOCK_VARIADIC_MACROS #ifdef BOOST_MSVC