Moved limitation workarounds code to compiled source file

git-svn-id: https://svn.code.sf.net/p/turtle/code/trunk@673 860be788-9bd5-4423-9f1e-828f051e677b
This commit is contained in:
mat007 2013-07-06 21:19:29 +00:00
parent 4f5090c109
commit 095add46f8
8 changed files with 257 additions and 129 deletions

View file

@ -52,3 +52,7 @@ compile example/patterns_retrieve_cref.cpp ;
compile example/patterns_invoke_functor.cpp ; compile example/patterns_invoke_functor.cpp ;
compile example/patterns_quick_constraint.cpp ; compile example/patterns_quick_constraint.cpp ;
compile example/reference.cpp ; compile example/reference.cpp ;
compile example/limitations_throw_specifier.cpp ;
compile example/limitations_literal_zero.cpp ;
compile example/limitations_template_method.cpp ;
compile example/limitations_private_method.cpp ;

View file

@ -0,0 +1,40 @@
#define BOOST_AUTO_TEST_MAIN
#include <boost/test/auto_unit_test.hpp>
#include <turtle/mock.hpp>
namespace
{
//[ limitations_comma_in_macro_problem
template< typename T1, typename T2 >
struct my_base_class
{};
//]
}
namespace limitations_comma_in_macro_solution_1
{
//[ limitations_comma_in_macro_solution_1
typedef my_base_class< int, int > my_base_type;
MOCK_BASE_CLASS( my_mock, my_base_type )
{};
//]
}
namespace limitations_comma_in_macro_solution_2
{
//[ limitations_comma_in_macro_solution_2
template< typename T1, typename T2 >
MOCK_BASE_CLASS( my_mock, my_base_type< T1 BOOST_PP_COMMA() T2 > )
{};
//]
}
namespace limitations_comma_in_macro_solution_3
{
//[ limitations_comma_in_macro_solution_3
template< typename T1, typename T2 >
struct my_mock : my_base_type< T1, T2 >, mock::object
{};
//]
}

View file

@ -0,0 +1,42 @@
#define BOOST_AUTO_TEST_MAIN
#include <boost/test/auto_unit_test.hpp>
#include <turtle/mock.hpp>
namespace
{
//[ limitations_const_parameter_warning_problem
class base
{
public:
virtual void method( const int ) = 0;
};
//]
}
namespace limitations_const_parameter_warning_explanation
{
//[ limitations_const_parameter_warning_explanation
class derived : public base
{
public:
virtual void method( const int );
};
void derived::method( int )
{}
//]
}
namespace limitations_const_parameter_warning_solution
{
//[ limitations_const_parameter_warning_solution
MOCK_BASE_CLASS( mock_base, base )
{
void method( const int i )
{
method_stub( i );
}
MOCK_METHOD( method_stub, 1, void( int ), method )
};
//]
}

View file

@ -0,0 +1,35 @@
#define BOOST_AUTO_TEST_MAIN
#include <boost/test/auto_unit_test.hpp>
#include <turtle/mock.hpp>
namespace
{
//[ limitations_literal_zero_problem
class base
{
public:
virtual void method( int* i ) = 0;
};
MOCK_BASE_CLASS( mock_base, base )
{
MOCK_METHOD( method, 1 )
};
//]
}
BOOST_AUTO_TEST_CASE( literal_zero )
{
mock_base m;
//[ limitations_literal_zero_solution_1
MOCK_EXPECT( m.method ).with( mock::equal< int* >( 0 ) ); // this compiles
//]
//[ limitations_literal_zero_solution_2
MOCK_EXPECT( m.method ).with( mock::negate );
//]
#ifdef MOCK_NULLPTR
//[ limitations_literal_zero_solution_3
MOCK_EXPECT( m.method ).with( nullptr );
//]
#endif
}

View file

@ -0,0 +1,21 @@
#define BOOST_AUTO_TEST_MAIN
#include <boost/test/auto_unit_test.hpp>
#include <turtle/mock.hpp>
namespace
{
//[ limitations_private_method_problem
class base
{
private:
virtual void method() = 0;
};
//]
//[ limitations_private_method_solution
MOCK_BASE_CLASS( mock_base, base )
{
MOCK_METHOD( method, 0, void() )
};
//]
}

View file

@ -0,0 +1,33 @@
#define BOOST_AUTO_TEST_MAIN
#include <boost/test/auto_unit_test.hpp>
#include <turtle/mock.hpp>
//[ limitations_template_method_problem
class concept
{
public:
template< typename T >
void method( T t )
{}
};
template< typename T >
class client
{
public:
client( T t ) // T is supposed to model the previous concept
{
t.method( 42 );
t.method( "string" );
}
};
//]
//[ limitations_template_method_solution
MOCK_CLASS( mock_concept )
{
MOCK_METHOD( method, 1, void( int ), method_int )
MOCK_METHOD( method, 1, void( const char* ), method_string )
};
//]

View file

@ -0,0 +1,27 @@
#define BOOST_AUTO_TEST_MAIN
#include <boost/test/auto_unit_test.hpp>
#include <turtle/mock.hpp>
namespace
{
//[ limitations_throw_specifier_problem
struct base_class
{
virtual ~base_class()
{}
virtual void method() throw ();
};
//]
//[ limitations_throw_specifier_solution
MOCK_BASE_CLASS( mock_class, base_class )
{
void method() throw ()
{
method_proxy();
}
MOCK_METHOD( method_proxy, 0, void(), method )
};
//]
}

View file

@ -1,4 +1,10 @@
[section Limitations] [section Limitations]
[import example/limitations_literal_zero.cpp]
[import example/limitations_throw_specifier.cpp]
[import example/limitations_template_method.cpp]
[import example/limitations_private_method.cpp]
[import example/limitations_comma_in_macro.cpp]
[import example/limitations_const_parameter_warning.cpp]
This section lists the library known limitations. This section lists the library known limitations.
@ -8,73 +14,46 @@ There is no support for unicode logging mainly because Boost.Test does not suppo
[endsect] [endsect]
[section Litteral 0 cannot be used as null pointer in constraints] [section Literal 0 cannot be used as null pointer in constraints]
Given : Given :
class base [limitations_literal_zero_problem]
{
public:
virtual void method( int i* ) = 0;
};
MOCK_BASE_CLASS( mock_base, base )
{
MOCK_METHOD( method, 1 )
};
The following code does not compile : The following code does not compile :
BOOST_AUTO_TEST_CASE( literal_zero )
{
mock_base m; mock_base m;
MOCK_EXPECT( m.method ).with( mock::equal( 0 ) ); // this fails MOCK_EXPECT( m.method ).with( mock::equal( 0 ) ); // this fails
MOCK_EXPECT( m.method ).with( 0 ); // this fails too ! MOCK_EXPECT( m.method ).with( 0 ); // this fails too !
}
This is due to the fact that the library uses templates pretty heavily, and the litteral 0 is considered as an int when instantiating a template function. This is due to the fact that the library uses templates pretty heavily, and literal 0 is considered as an int when instantiating a template function.
A workaround is : A workaround is :
MOCK_EXPECT( m.method ).with( mock::equal< int* >( 0 ) ); // this compiles [limitations_literal_zero_solution_1]
However a somewhat better solution would be : However a somewhat better solution would be :
MOCK_EXPECT( m.method ).with( mock::negate ); [limitations_literal_zero_solution_2]
or with C++11 nullptr support : or with C++11 nullptr support :
MOCK_EXPECT( m.method ).with( nullptr ); [limitations_literal_zero_solution_3]
[endsect] [endsect]
[section Template methods cannot be mocked] [section Template methods cannot be mocked]
Given the following client code : Given :
class concept [limitations_template_method_problem]
{
public:
template< typename T >
void method( T t )
{}
};
template< typename T > writing a mock object modeling 'concept' requires to list all the possible versions of 'method' :
class client
{
public:
client( T t ) // T is supposed to model the previous concept
{
t.method( 42 );
t.method( "string" );
}
};
Writing a mock object modeling 'concept' requires to list all the possible versions of 'method' : [limitations_template_method_solution]
MOCK_CLASS( mock_concept )
{
MOCK_METHOD( method, 1, void( int ), method_int )
MOCK_METHOD( method, 1, void( const char* ), method_string )
};
While still somewhat possible, mocking a template method is indeed a bit cumbersome. While still somewhat possible, mocking a template method is indeed a bit cumbersome.
@ -82,89 +61,56 @@ While still somewhat possible, mocking a template method is indeed a bit cumbers
[section Private virtual methods cannot be mocked without spelling out the signature] [section Private virtual methods cannot be mocked without spelling out the signature]
The following code does not compile : Given :
class base [limitations_private_method_problem]
{
private: the following code does not compile :
virtual void method() = 0;
};
MOCK_BASE_CLASS( mock_base, base ) MOCK_BASE_CLASS( mock_base, base )
{ {
MOCK_METHOD( method, 0 ) // this fails to compile 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 : A workaround would be to add the signature to MOCK_METHOD :
MOCK_BASE_CLASS( mock_base, base ) [limitations_private_method_solution]
{
MOCK_METHOD_EXT( method, 0, void() )
};
[endsect] [endsect]
[section Methods with a throw specifier cannot be mocked] [section Methods with a throw specifier cannot be mocked]
The following code does not compile : Given :
namespace [limitations_throw_specifier_problem]
{
struct base_class
{
virtual ~base_class()
{}
virtual void method() throw; the following code does not compile :
};
MOCK_BASE_CLASS( mock_class, base_class ) MOCK_BASE_CLASS( mock_class, base_class )
{ {
MOCK_METHOD( method, 0 ) // this fails to compile 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 : A workaround would be to write a proxy member function :
namespace [limitations_throw_specifier_solution]
{
struct base_class
{
virtual ~base_class()
{}
virtual void method() throw;
};
MOCK_BASE_CLASS( mock_class, base_class )
{
void method() throw
{
method_proxy();
}
MOCK_METHOD( method_proxy, 0, void(), method )
};
}
[endsect] [endsect]
[section Compilers without support for variadic macros fail on commas in MOCK_BASE_CLASS] [section Compilers without support for variadic macros fail on commas in MOCK_BASE_CLASS]
For compilers without support for variadic macros the following code does not compile : For compilers without support for variadic macros given :
template< typename T1, typename T2 > [limitations_comma_in_macro_problem]
struct my_base_class
{};
MOCK_BASE_CLASS( my_mock, my_base_class< int, int > ) // this fails to compile because the pre-processor believes the macro to be called with 3 arguments the following code does not compile :
MOCK_BASE_CLASS( my_mock, my_base_class< int, int > ) // this fails because the pre-processor believes the macro to be called with 3 arguments
{}; {};
One workaround is : One workaround is :
typedef my_base_class< int, int > my_base_type; [limitations_comma_in_macro_solution_1]
MOCK_BASE_CLASS( my_mock, my_base_type )
{};
Of course this is not always possible, as in : Of course this is not always possible, as in :
@ -174,9 +120,7 @@ Of course this is not always possible, as in :
Another workaround would make use of [@http://www.boost.org/libs/preprocessor Boost.Preprocessor] : Another workaround would make use of [@http://www.boost.org/libs/preprocessor Boost.Preprocessor] :
template< typename T1, typename T2 > [limitations_comma_in_macro_solution_2]
MOCK_BASE_CLASS( my_mock, my_base_type< T1 BOOST_PP_COMMA() T2 > )
{};
Actually BOOST_PP_COMMA implementation is quite trivial, being only : Actually BOOST_PP_COMMA implementation is quite trivial, being only :
@ -184,9 +128,7 @@ Actually BOOST_PP_COMMA implementation is quite trivial, being only :
Finally another workaround would be to not use the macro at all : Finally another workaround would be to not use the macro at all :
template< typename T1, typename T2 > [limitations_comma_in_macro_solution_3]
struct my_mock : my_base_type< T1, T2 >, mock::object
{};
Note that [@www.boost.org/libs/utility/identity_type/doc/html/index.html Boost.IdentityType] is of little help here because the type is by essence very often abstract, which doesn't work well for some compilers (e.g. gcc). Note that [@www.boost.org/libs/utility/identity_type/doc/html/index.html Boost.IdentityType] is of little help here because the type is by essence very often abstract, which doesn't work well for some compilers (e.g. gcc).
@ -220,13 +162,11 @@ Example :
[c++] [c++]
The following code produces this warning with some versions of the Microsoft Visual Studio compiler : Given :
class base [limitations_const_parameter_warning_problem]
{
public: the following code produces this warning with some versions of the Microsoft Visual Studio compiler :
virtual void method( const int ) = 0;
};
MOCK_BASE_CLASS( mock_base, base ) MOCK_BASE_CLASS( mock_base, base )
{ {
@ -238,27 +178,13 @@ The problem is that the 'const' is actually not part of the function signature a
The first workaround would be to remove the 'const' all together. The first workaround would be to remove the 'const' all together.
This is more sensible than it first sounds, after all the 'const' is useless in this situation, indeed : This is more sensible than it first sounds, after all the 'const' is useless in this situation, indeed the following compiles, links and is valid C++ :
class derived : public base [limitations_const_parameter_warning_explanation]
{
public:
virtual void method( const int );
};
void derived::method( int ) // this compiles, links and is valid C++
{}
Otherwise another workaround would be to provide a proxy method : Otherwise another workaround would be to provide a proxy method :
MOCK_BASE_CLASS( mock_base, base ) [limitations_const_parameter_warning_solution]
{
void method( const int i )
{
method_stub( i );
}
MOCK_METHOD( method_stub, 1, void( int ), method )
};
[endsect] [endsect]