From b92314ec07f59902fd191aac879d84ee1f4ea88f Mon Sep 17 00:00:00 2001 From: Mathieu Champlon Date: Tue, 7 Apr 2015 07:40:26 +0200 Subject: [PATCH 1/4] Tweaked project configuration --- build/vc100/turtle_test.vcxproj | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/build/vc100/turtle_test.vcxproj b/build/vc100/turtle_test.vcxproj index 520272b..82f561e 100644 --- a/build/vc100/turtle_test.vcxproj +++ b/build/vc100/turtle_test.vcxproj @@ -31,7 +31,10 @@ - + + BOOST_AUTO_TEST_MAIN;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + BOOST_AUTO_TEST_MAIN;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + @@ -84,6 +87,22 @@ ../../out/vc100/$(Configuration)/tests/$(ProjectName)\ ../../out/vc100_x64/$(Configuration)/tests/$(ProjectName)\ + + c:\dev\include;$(VCInstallDir)include;$(VCInstallDir)atlmfc\include;$(WindowsSdkDir)include;$(FrameworkSDKDir)\include; + c:\dev\lib\vc100_x64;$(VCInstallDir)lib;$(VCInstallDir)atlmfc\lib;$(WindowsSdkDir)lib;$(FrameworkSDKDir)\lib + + + c:\dev\include;$(VCInstallDir)include;$(VCInstallDir)atlmfc\include;$(WindowsSdkDir)include;$(FrameworkSDKDir)\include; + c:\dev\lib\vc100_x64;$(VCInstallDir)lib;$(VCInstallDir)atlmfc\lib;$(WindowsSdkDir)lib;$(FrameworkSDKDir)\lib + + + c:\dev\include;$(VCInstallDir)include;$(VCInstallDir)atlmfc\include;$(WindowsSdkDir)include;$(FrameworkSDKDir)\include; + c:\dev\lib\vc100_x64;$(VCInstallDir)lib\amd64;$(VCInstallDir)atlmfc\lib\amd64;$(WindowsSdkDir)lib\x64; + + + c:\dev\include;$(VCInstallDir)include;$(VCInstallDir)atlmfc\include;$(WindowsSdkDir)include;$(FrameworkSDKDir)\include; + c:\dev\lib\vc100_x64;$(VCInstallDir)lib\amd64;$(VCInstallDir)atlmfc\lib\amd64;$(WindowsSdkDir)lib\x64; + /Zm172 %(AdditionalOptions) @@ -145,8 +164,7 @@ Console - cd ../../run/vc100 -"$(TargetDir)$(TargetName).exe" --result_code=no --report_level=no --log_level=warning --data_directory=../../data/tests/$(ProjectName) + "$(TargetDir)$(TargetName).exe" --result_code=no --report_level=no --log_level=warning --data_directory=../../data/tests/$(ProjectName) @@ -211,8 +229,7 @@ Console - cd ../../run/vc100 -"$(TargetDir)$(TargetName).exe" --result_code=no --report_level=no --log_level=warning --data_directory=../../data/tests/$(ProjectName) + "$(TargetDir)$(TargetName).exe" --result_code=no --report_level=no --log_level=warning --data_directory=../../data/tests/$(ProjectName) From 712653eb9982318d830ea844b40e7f0a3c551c8c Mon Sep 17 00:00:00 2001 From: Mathieu Champlon Date: Tue, 7 Apr 2015 07:52:37 +0200 Subject: [PATCH 2/4] Added inline to generated MOCK_FUNCTION --- doc/changelog.qbk | 1 + include/turtle/mock.hpp | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/doc/changelog.qbk b/doc/changelog.qbk index 2dd926a..c13a15b 100644 --- a/doc/changelog.qbk +++ b/doc/changelog.qbk @@ -12,6 +12,7 @@ Not yet released * Dropped support for obsolete Boost.Phoenix V2 * Added support for multiple parameters constraints +* Added inline to generated MOCK_FUNCTION [section 1.2.6] Released 24 May 2014 diff --git a/include/turtle/mock.hpp b/include/turtle/mock.hpp index 49142c9..a120650 100644 --- a/include/turtle/mock.hpp +++ b/include/turtle/mock.hpp @@ -163,7 +163,7 @@ #define MOCK_FUNCTION_AUX(F, n, S, t, s, tpn) \ MOCK_FUNCTION_HELPER(S, t, s, tpn) \ - s MOCK_DECL(F, n, S,,tpn) \ + s inline MOCK_DECL(F, n, S,,tpn) \ { \ BOOST_MPL_ASSERT_RELATION( n, ==, \ boost::function_types::function_arity< \ @@ -212,7 +212,8 @@ #define MOCK_STATIC_METHOD(F, n, ...) \ MOCK_FUNCTION_AUX(F, n, \ MOCK_VARIADIC_ELEM_0(__VA_ARGS__), \ - MOCK_VARIADIC_ELEM_1(__VA_ARGS__, F), static,) + MOCK_VARIADIC_ELEM_1(__VA_ARGS__, F), \ + static,) #define MOCK_STATIC_METHOD_TPL(F, n, ...) \ MOCK_FUNCTION_AUX(F, n, \ From 12a252a850f70959a0a94810d745e38450e21a29 Mon Sep 17 00:00:00 2001 From: Mathieu Champlon Date: Tue, 7 Apr 2015 07:39:52 +0200 Subject: [PATCH 3/4] Documented limitation concerning MOCK_METHOD_TPL --- doc/changelog.qbk | 1 + ...limitations_template_base_class_method.cpp | 78 +++++++++++++++++++ doc/limitations.qbk | 38 ++++++--- doc/reference.qbk | 14 ++-- test/test_mock.cpp | 27 ++++++- 5 files changed, 142 insertions(+), 16 deletions(-) create mode 100644 doc/example/limitations_template_base_class_method.cpp 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 From ed36823235ce1d0d847ee3d180ede9b3cdc00df8 Mon Sep 17 00:00:00 2001 From: Mathieu Champlon Date: Tue, 7 Apr 2015 07:21:14 +0200 Subject: [PATCH 4/4] Added support for mocking protected member function --- doc/changelog.qbk | 1 + include/turtle/mock.hpp | 24 ++++++++++++++---------- test/test_mock.cpp | 5 +++++ 3 files changed, 20 insertions(+), 10 deletions(-) diff --git a/doc/changelog.qbk b/doc/changelog.qbk index c95e588..7563dde 100644 --- a/doc/changelog.qbk +++ b/doc/changelog.qbk @@ -14,6 +14,7 @@ Not yet released * Added support for multiple parameters constraints * Added inline to generated MOCK_FUNCTION * Documented limitation concerning MOCK_METHOD_TPL +* Fixed mocking protected member function [section 1.2.6] Released 24 May 2014 diff --git a/include/turtle/mock.hpp b/include/turtle/mock.hpp index a120650..9f27d0a 100644 --- a/include/turtle/mock.hpp +++ b/include/turtle/mock.hpp @@ -43,8 +43,8 @@ #else // MOCK_VARIADIC_MACROS -#define MOCK_BASE_CLASS(T, I) \ - struct T : I, mock::object, mock::detail::base< I > +#define MOCK_BASE_CLASS(T, B) \ + struct T : B, mock::object, mock::detail::base< B > #define MOCK_FUNCTOR(f, S) \ mock::detail::functor< MOCK_FUNCTION_TYPE(S,) > f, f##_mock @@ -177,29 +177,32 @@ #define MOCK_VARIADIC_ELEM_1(e0, e1, ...) e1 #define MOCK_VARIADIC_ELEM_2(e0, e1, e2, ...) e2 -#define MOCK_METHOD(M, ... ) \ - MOCK_METHOD_EXT(M, \ +#define MOCK_METHOD_SIGNATURE(M, n, S, t) \ + typedef MOCK_FUNCTION_TYPE(S,) BOOST_PP_CAT(t,_sig_type); \ + MOCK_METHOD_EXT(M, n, BOOST_PP_CAT(t,_sig_type), t) +#define MOCK_METHOD(M, ...) \ + MOCK_METHOD_SIGNATURE(M, \ MOCK_VARIADIC_ELEM_0(__VA_ARGS__ ), \ MOCK_VARIADIC_ELEM_1(__VA_ARGS__, MOCK_SIGNATURE(M)), \ MOCK_VARIADIC_ELEM_2(__VA_ARGS__, M, M)) -#define MOCK_CONST_METHOD(M, n, ... ) \ +#define MOCK_CONST_METHOD(M, n, ...) \ MOCK_CONST_METHOD_EXT(M, n, \ MOCK_VARIADIC_ELEM_0(__VA_ARGS__), \ MOCK_VARIADIC_ELEM_1(__VA_ARGS__, M)) -#define MOCK_NON_CONST_METHOD(M, n, ... ) \ +#define MOCK_NON_CONST_METHOD(M, n, ...) \ MOCK_NON_CONST_METHOD_EXT(M, n, \ MOCK_VARIADIC_ELEM_0(__VA_ARGS__), \ MOCK_VARIADIC_ELEM_1(__VA_ARGS__, M)) -#define MOCK_METHOD_TPL(M, n, ... ) \ +#define MOCK_METHOD_TPL(M, n, ...) \ MOCK_METHOD_EXT_TPL(M, n, \ MOCK_VARIADIC_ELEM_0(__VA_ARGS__), \ MOCK_VARIADIC_ELEM_1(__VA_ARGS__, M)) -#define MOCK_CONST_METHOD_TPL(M, n, ... ) \ +#define MOCK_CONST_METHOD_TPL(M, n, ...) \ MOCK_CONST_METHOD_EXT_TPL(M, n, \ MOCK_VARIADIC_ELEM_0(__VA_ARGS__), \ MOCK_VARIADIC_ELEM_1(__VA_ARGS__, M)) -#define MOCK_NON_CONST_METHOD_TPL(M, n, ... ) \ +#define MOCK_NON_CONST_METHOD_TPL(M, n, ...) \ MOCK_NON_CONST_METHOD_EXT_TPL(M, n, \ MOCK_VARIADIC_ELEM_0(__VA_ARGS__), \ MOCK_VARIADIC_ELEM_1(__VA_ARGS__, M)) @@ -224,7 +227,8 @@ #else // MOCK_VARIADIC_MACROS #define MOCK_METHOD(M, n) \ - MOCK_METHOD_EXT(M, n, MOCK_SIGNATURE(M), M) + typedef MOCK_SIGNATURE(M) M##_sig_type; \ + MOCK_METHOD_EXT(M, n, M##_sig_type, M) #define MOCK_FUNCTION(F, n, S, t) \ MOCK_FUNCTION_AUX(F, n, S, t,,) diff --git a/test/test_mock.cpp b/test/test_mock.cpp index 0961b0d..7a41f6f 100644 --- a/test/test_mock.cpp +++ b/test/test_mock.cpp @@ -361,6 +361,7 @@ namespace { virtual ~base() {} + protected: virtual void m1() = 0; }; @@ -439,6 +440,10 @@ namespace stdcall { struct base { + virtual ~base() + {} + + protected: virtual void MOCK_STDCALL m1() = 0; };