Merge pull request #8 from mat007/protected-mock-method

Protected mock method
This commit is contained in:
Mathieu Champlon 2015-04-09 07:12:20 +02:00
commit 41de7236c4
7 changed files with 188 additions and 33 deletions

View file

@ -31,7 +31,10 @@
<ClCompile Include="..\..\test\test_constraint.cpp" /> <ClCompile Include="..\..\test\test_constraint.cpp" />
<ClCompile Include="..\..\test\test_constraints.cpp" /> <ClCompile Include="..\..\test\test_constraints.cpp" />
<ClCompile Include="..\..\test\test_exception.cpp" /> <ClCompile Include="..\..\test\test_exception.cpp" />
<ClCompile Include="..\..\test\test_integration.cpp" /> <ClCompile Include="..\..\test\test_integration.cpp">
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='release|x64'">BOOST_AUTO_TEST_MAIN;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='debug|x64'">BOOST_AUTO_TEST_MAIN;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<ClCompile Include="..\..\test\test_log.cpp" /> <ClCompile Include="..\..\test\test_log.cpp" />
<ClCompile Include="..\..\test\test_matcher.cpp" /> <ClCompile Include="..\..\test\test_matcher.cpp" />
<ClCompile Include="..\..\test\test_max_args.cpp" /> <ClCompile Include="..\..\test\test_max_args.cpp" />
@ -84,6 +87,22 @@
<IntDir Condition="'$(Configuration)|$(Platform)'=='release|Win32'">../../out/vc100/$(Configuration)/tests/$(ProjectName)\</IntDir> <IntDir Condition="'$(Configuration)|$(Platform)'=='release|Win32'">../../out/vc100/$(Configuration)/tests/$(ProjectName)\</IntDir>
<IntDir Condition="'$(Configuration)|$(Platform)'=='release|x64'">../../out/vc100_x64/$(Configuration)/tests/$(ProjectName)\</IntDir> <IntDir Condition="'$(Configuration)|$(Platform)'=='release|x64'">../../out/vc100_x64/$(Configuration)/tests/$(ProjectName)\</IntDir>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='debug|Win32'">
<IncludePath>c:\dev\include;$(VCInstallDir)include;$(VCInstallDir)atlmfc\include;$(WindowsSdkDir)include;$(FrameworkSDKDir)\include;</IncludePath>
<LibraryPath>c:\dev\lib\vc100_x64;$(VCInstallDir)lib;$(VCInstallDir)atlmfc\lib;$(WindowsSdkDir)lib;$(FrameworkSDKDir)\lib</LibraryPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='release|Win32'">
<IncludePath>c:\dev\include;$(VCInstallDir)include;$(VCInstallDir)atlmfc\include;$(WindowsSdkDir)include;$(FrameworkSDKDir)\include;</IncludePath>
<LibraryPath>c:\dev\lib\vc100_x64;$(VCInstallDir)lib;$(VCInstallDir)atlmfc\lib;$(WindowsSdkDir)lib;$(FrameworkSDKDir)\lib</LibraryPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='debug|x64'">
<IncludePath>c:\dev\include;$(VCInstallDir)include;$(VCInstallDir)atlmfc\include;$(WindowsSdkDir)include;$(FrameworkSDKDir)\include;</IncludePath>
<LibraryPath>c:\dev\lib\vc100_x64;$(VCInstallDir)lib\amd64;$(VCInstallDir)atlmfc\lib\amd64;$(WindowsSdkDir)lib\x64;</LibraryPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='release|x64'">
<IncludePath>c:\dev\include;$(VCInstallDir)include;$(VCInstallDir)atlmfc\include;$(WindowsSdkDir)include;$(FrameworkSDKDir)\include;</IncludePath>
<LibraryPath>c:\dev\lib\vc100_x64;$(VCInstallDir)lib\amd64;$(VCInstallDir)atlmfc\lib\amd64;$(WindowsSdkDir)lib\x64;</LibraryPath>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile> <ClCompile>
<AdditionalOptions>/Zm172 %(AdditionalOptions)</AdditionalOptions> <AdditionalOptions>/Zm172 %(AdditionalOptions)</AdditionalOptions>
@ -145,8 +164,7 @@
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
</Link> </Link>
<PostBuildEvent> <PostBuildEvent>
<Command>cd ../../run/vc100 <Command>"$(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)
</Command> </Command>
</PostBuildEvent> </PostBuildEvent>
</ItemDefinitionGroup> </ItemDefinitionGroup>
@ -211,8 +229,7 @@
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
</Link> </Link>
<PostBuildEvent> <PostBuildEvent>
<Command>cd ../../run/vc100 <Command>"$(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)
</Command> </Command>
</PostBuildEvent> </PostBuildEvent>
</ItemDefinitionGroup> </ItemDefinitionGroup>

View file

@ -12,6 +12,9 @@ Not yet released
* Dropped support for obsolete Boost.Phoenix V2 * Dropped support for obsolete Boost.Phoenix V2
* Added support for multiple parameters constraints * 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] [section 1.2.6]
Released 24 May 2014 Released 24 May 2014

View file

@ -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 <boost/test/auto_unit_test.hpp>
#include <turtle/mock.hpp>
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();
}
//]
}

View file

@ -53,6 +53,22 @@ or with C++11 nullptr support :
[endsect] [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] [section Template methods cannot be mocked]
Given : Given :
@ -75,23 +91,27 @@ While still somewhat possible, mocking a template method can indeed prove a bit
[endsect] [endsect]
[section Non-virtual methods cannot be mocked] [section Template base class methods cannot be mocked without specifying the signature]
Given : 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] [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 : Given :

View file

@ -91,14 +91,16 @@ Synopsis :
MOCK_CONST_METHOD( [calling convention] name, arity[, signature[, identifier]] ) // generates only the const version of the method 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_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_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_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_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 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 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 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.] [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.]

View file

@ -43,8 +43,8 @@
#else // MOCK_VARIADIC_MACROS #else // MOCK_VARIADIC_MACROS
#define MOCK_BASE_CLASS(T, I) \ #define MOCK_BASE_CLASS(T, B) \
struct T : I, mock::object, mock::detail::base< I > struct T : B, mock::object, mock::detail::base< B >
#define MOCK_FUNCTOR(f, S) \ #define MOCK_FUNCTOR(f, S) \
mock::detail::functor< MOCK_FUNCTION_TYPE(S,) > f, f##_mock mock::detail::functor< MOCK_FUNCTION_TYPE(S,) > f, f##_mock
@ -163,7 +163,7 @@
#define MOCK_FUNCTION_AUX(F, n, S, t, s, tpn) \ #define MOCK_FUNCTION_AUX(F, n, S, t, s, tpn) \
MOCK_FUNCTION_HELPER(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_MPL_ASSERT_RELATION( n, ==, \
boost::function_types::function_arity< \ boost::function_types::function_arity< \
@ -177,8 +177,11 @@
#define MOCK_VARIADIC_ELEM_1(e0, e1, ...) e1 #define MOCK_VARIADIC_ELEM_1(e0, e1, ...) e1
#define MOCK_VARIADIC_ELEM_2(e0, e1, e2, ...) e2 #define MOCK_VARIADIC_ELEM_2(e0, e1, e2, ...) e2
#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, ...) \ #define MOCK_METHOD(M, ...) \
MOCK_METHOD_EXT(M, \ MOCK_METHOD_SIGNATURE(M, \
MOCK_VARIADIC_ELEM_0(__VA_ARGS__ ), \ MOCK_VARIADIC_ELEM_0(__VA_ARGS__ ), \
MOCK_VARIADIC_ELEM_1(__VA_ARGS__, MOCK_SIGNATURE(M)), \ MOCK_VARIADIC_ELEM_1(__VA_ARGS__, MOCK_SIGNATURE(M)), \
MOCK_VARIADIC_ELEM_2(__VA_ARGS__, M, M)) MOCK_VARIADIC_ELEM_2(__VA_ARGS__, M, M))
@ -212,7 +215,8 @@
#define MOCK_STATIC_METHOD(F, n, ...) \ #define MOCK_STATIC_METHOD(F, n, ...) \
MOCK_FUNCTION_AUX(F, n, \ MOCK_FUNCTION_AUX(F, n, \
MOCK_VARIADIC_ELEM_0(__VA_ARGS__), \ 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, ...) \ #define MOCK_STATIC_METHOD_TPL(F, n, ...) \
MOCK_FUNCTION_AUX(F, n, \ MOCK_FUNCTION_AUX(F, n, \
@ -223,7 +227,8 @@
#else // MOCK_VARIADIC_MACROS #else // MOCK_VARIADIC_MACROS
#define MOCK_METHOD(M, n) \ #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) \ #define MOCK_FUNCTION(F, n, S, t) \
MOCK_FUNCTION_AUX(F, n, S, t,,) MOCK_FUNCTION_AUX(F, n, S, t,,)

View file

@ -361,6 +361,7 @@ namespace
{ {
virtual ~base() virtual ~base()
{} {}
protected:
virtual void m1() = 0; virtual void m1() = 0;
}; };
@ -378,8 +379,9 @@ namespace
}; };
template< typename T > 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( m2, 0, T() )
MOCK_METHOD_TPL( m3, 0, T(), m3 ) MOCK_METHOD_TPL( m3, 0, T(), m3 )
MOCK_CONST_METHOD_TPL( m4, 0, T() ) MOCK_CONST_METHOD_TPL( m4, 0, T() )
@ -400,6 +402,30 @@ namespace
MOCK_FUNCTOR( f_variadic, std::map< int, int >() ); 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 #endif // MOCK_VARIADIC_MACROS
#ifdef BOOST_MSVC #ifdef BOOST_MSVC
@ -414,6 +440,10 @@ namespace stdcall
{ {
struct base struct base
{ {
virtual ~base()
{}
protected:
virtual void MOCK_STDCALL m1() = 0; virtual void MOCK_STDCALL m1() = 0;
}; };