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)
diff --git a/doc/changelog.qbk b/doc/changelog.qbk
index 2dd926a..7563dde 100644
--- a/doc/changelog.qbk
+++ b/doc/changelog.qbk
@@ -12,6 +12,9 @@ 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
+* Fixed mocking protected member function
[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/include/turtle/mock.hpp b/include/turtle/mock.hpp
index 49142c9..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
@@ -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< \
@@ -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))
@@ -212,7 +215,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, \
@@ -223,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 8a15879..7a41f6f 100644
--- a/test/test_mock.cpp
+++ b/test/test_mock.cpp
@@ -361,6 +361,7 @@ namespace
{
virtual ~base()
{}
+ protected:
virtual void m1() = 0;
};
@@ -378,8 +379,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 +402,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
@@ -414,6 +440,10 @@ namespace stdcall
{
struct base
{
+ virtual ~base()
+ {}
+
+ protected:
virtual void MOCK_STDCALL m1() = 0;
};