Include examples in CI tests

Also fix and update examples and documentation where required
This allows to make sure examples are actually runnable avoiding them to
become outdated
This commit is contained in:
Alexander Grund 2020-07-11 14:01:18 +02:00
parent a6aa140148
commit 5ef17d0e33
No known key found for this signature in database
GPG key ID: AA48A0760367A42B
42 changed files with 400 additions and 285 deletions

View file

@ -11,6 +11,9 @@
Released - Released -
* Allow auto-deducing signature in `MOCK_METHOD_(NON_)CONST` * Allow auto-deducing signature in `MOCK_METHOD_(NON_)CONST`
* Replaced Boost facilities with std:: equivalents where existing in C++14
* Deprecated MOCK_FUNCTOR_TPL as no longer required, use the non _TPL variant even for templates
* Added MOCK_PROTECT_FUNCTION_SIG to pass function signatures with commas in the return type
[endsect] [endsect]

View file

@ -98,7 +98,7 @@ The purpose of the 'near' template function is to :
* remove the burden of specifying the template parameter when instantiating near_constraint * remove the burden of specifying the template parameter when instantiating near_constraint
* wrap the constraint in a mock::constraint so that it plays nicely with !, && and ||. * wrap the constraint in a mock::constraint so that it plays nicely with !, && and ||.
The use of boost::unwrap_ref provides support for passing arguments as references with boost::ref and boost::cref and delaying their initialization, for instance : The use of mock::unwrap_ref provides support for passing arguments as references with std::ref and std::cref and delaying their initialization, for instance :
[near_constraint_cref_test] [near_constraint_cref_test]

View file

@ -9,15 +9,16 @@
#ifndef CALCULATOR #ifndef CALCULATOR
#define CALCULATOR #define CALCULATOR
class view; #include "view.hpp"
//[ calculator //[ calculator
class calculator class calculator
{ {
view& v;
public: public:
calculator( view& v ); calculator( view& v ): v(v){}
void add( int a, int b ); // the result will be sent to the view 'v' void add( int a, int b ){ v.display(a + b); } // the result will be sent to the view 'v'
}; };
//] //]

View file

@ -12,6 +12,7 @@
//] //]
#include "calculator.hpp" #include "calculator.hpp"
#include "mock_view.hpp" #include "mock_view.hpp"
#include <boost/test/unit_test.hpp>
//[ mock_stream_user_type //[ mock_stream_user_type
namespace user_namespace namespace user_namespace
@ -36,7 +37,7 @@ bool custom_constraint( int actual )
//] //]
//[ custom_constraint_free_function_test //[ custom_constraint_free_function_test
BOOST_AUTO_TEST_CASE( forty_one_plus_one_is_forty_two ) BOOST_AUTO_TEST_CASE( forty_one_plus_one_is_forty_two_free_function )
{ {
mock_view v; mock_view v;
calculator c( v ); calculator c( v );
@ -64,7 +65,7 @@ struct custom_constraint
//] //]
//[ custom_constraint_functor_test //[ custom_constraint_functor_test
BOOST_AUTO_TEST_CASE( forty_one_plus_one_is_forty_two ) BOOST_AUTO_TEST_CASE( forty_one_plus_one_is_forty_two_custom_constraint )
{ {
mock_view v; mock_view v;
calculator c( v ); calculator c( v );
@ -86,8 +87,7 @@ struct near_constraint
template< typename Actual > template< typename Actual >
bool operator()( Actual actual ) const bool operator()( Actual actual ) const
{ {
return std::abs( actual - unwrap_ref( expected_ ) ) return std::abs( actual - expected_ ) < threshold_ ;
< unwrap_ref( threshold_ );
} }
friend std::ostream& operator<<( std::ostream& s, const near_constraint& c ) friend std::ostream& operator<<( std::ostream& s, const near_constraint& c )
@ -109,7 +109,7 @@ mock::constraint< near_constraint< Expected > > near( Expected expected, Expecte
namespace near_constraint_test namespace near_constraint_test
{ {
//[ near_constraint_test //[ near_constraint_test
BOOST_AUTO_TEST_CASE( forty_one_plus_one_is_forty_two_plus_or_minus_one ) BOOST_AUTO_TEST_CASE( forty_one_plus_one_is_forty_two_plus_or_minus_one_near )
{ {
mock_view v; mock_view v;
calculator c( v ); calculator c( v );
@ -122,7 +122,7 @@ BOOST_AUTO_TEST_CASE( forty_one_plus_one_is_forty_two_plus_or_minus_one )
namespace near_constraint_cref_test namespace near_constraint_cref_test
{ {
//[ near_constraint_cref_test //[ near_constraint_cref_test
BOOST_AUTO_TEST_CASE( forty_one_plus_one_is_forty_two_plus_or_minus_one ) BOOST_AUTO_TEST_CASE( forty_one_plus_one_is_forty_two_plus_or_minus_one_near_cref )
{ {
mock_view v; mock_view v;
calculator c( v ); calculator c( v );

View file

@ -6,14 +6,69 @@
// (See accompanying file LICENSE_1_0.txt or copy at // (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt) // http://www.boost.org/LICENSE_1_0.txt)
#include <functional>
#include <string>
#include <sstream>
std::function<void()> error_handler_abort;
std::function<void(const char*, int)> error_handler_pass;
std::function<void(const std::string&, const char*, int)> error_handler_call;
std::function<void(const char* message, const std::string&, const char*, int)> error_handler_fail;
template< typename Result >
struct configurable_mock_error
{
static Result abort()
{
error_handler_abort();
return Result();
}
static void pass( const char* file, int line )
{
error_handler_pass(file, line);
}
template< typename Context >
static void call( const Context& context, const char* file, int line )
{
std::stringstream s;
s << context;
error_handler_call( s.str(), file, line );
}
template< typename Context >
static void fail( const char* message, const Context& context, const char* file = "", int line = 0 )
{
std::stringstream s;
s << context;
error_handler_fail( message, s.str(), file, line );
}
};
#define MOCK_ERROR_POLICY configurable_mock_error
#define MOCK_USE_BOOST_TEST
//[ prerequisite //[ prerequisite
#define BOOST_AUTO_TEST_MAIN
#include <boost/test/auto_unit_test.hpp> #include <boost/test/auto_unit_test.hpp>
#include <turtle/mock.hpp> #include <turtle/mock.hpp>
//] //]
#include "calculator.hpp" #include "calculator.hpp"
#include "mock_view.hpp" #include "mock_view.hpp"
struct Fixture
{
Fixture()
{
error_handler_abort = mock::error<void>::abort;
error_handler_pass = mock::error<void>::pass;
error_handler_call = mock::error<void>::call<std::string>;
error_handler_fail = mock::error<void>::fail<std::string>;
}
};
BOOST_FIXTURE_TEST_SUITE(GettingStarted, Fixture)
namespace phases namespace phases
{ {
//[ phases //[ phases
@ -30,7 +85,7 @@ BOOST_AUTO_TEST_CASE( zero_plus_zero_is_zero )
namespace verify_reset namespace verify_reset
{ {
//[ verify_reset //[ verify_reset
BOOST_AUTO_TEST_CASE( zero_plus_zero_is_zero ) BOOST_AUTO_TEST_CASE( zero_plus_zero_is_zero_reset )
{ {
mock_view v; mock_view v;
calculator c( v ); calculator c( v );
@ -49,7 +104,7 @@ BOOST_AUTO_TEST_CASE( zero_plus_zero_is_zero )
namespace expectations namespace expectations
{ {
//[ expectations //[ expectations
BOOST_AUTO_TEST_CASE( zero_plus_zero_is_zero ) BOOST_AUTO_TEST_CASE( zero_plus_zero_is_zero_expect )
{ {
mock_view v; mock_view v;
calculator c( v ); calculator c( v );
@ -63,7 +118,7 @@ BOOST_AUTO_TEST_CASE( zero_plus_zero_is_zero )
namespace sequence namespace sequence
{ {
//[ sequence //[ sequence
BOOST_AUTO_TEST_CASE( zero_plus_zero_is_zero ) BOOST_AUTO_TEST_CASE( zero_plus_zero_is_zero_then_1_plus_0_is_1 )
{ {
mock_view v; mock_view v;
calculator c( v ); calculator c( v );
@ -79,7 +134,7 @@ BOOST_AUTO_TEST_CASE( zero_plus_zero_is_zero )
namespace several_sequences namespace several_sequences
{ {
//[ several_sequences //[ several_sequences
BOOST_AUTO_TEST_CASE( zero_plus_zero_is_zero ) BOOST_AUTO_TEST_CASE( add_several_numbers_in_sequences )
{ {
mock_view v; mock_view v;
calculator c( v ); calculator c( v );
@ -112,18 +167,49 @@ MOCK_BASE_CLASS( mock_view, view )
class calculator class calculator
{ {
view& v;
public: public:
calculator( view& v ); calculator( view& v ): v(v) {}
void add( int a, int b ); void add( int a, int b ){ v.display(a + b); }
}; };
struct CatchFailureFixture
{
static bool aborted;
static std::string fail_msg;
static void abort()
{
aborted = true;
}
static void fail( const std::string& message, const std::string&, const char* = "", int = 0 ){
fail_msg = message;
}
CatchFailureFixture()
{
error_handler_abort = abort;
error_handler_fail = fail;
}
void assert_failure(const std::string& required_message)
{
BOOST_CHECK(aborted);
BOOST_CHECK(fail_msg.find(required_message) != std::string::npos);
}
};
bool CatchFailureFixture::aborted = false;
std::string CatchFailureFixture::fail_msg;
//[ action_test //[ action_test
BOOST_AUTO_TEST_CASE( zero_plus_zero_is_zero ) BOOST_FIXTURE_TEST_CASE( zero_plus_zero_is_zero_with_action, CatchFailureFixture )
{ {
mock_view v; mock_view v;
calculator c( v ); calculator c( v );
MOCK_EXPECT( v.display ).once().with( 0 ); // missing returns( true ) MOCK_EXPECT( v.display ).once().with( 0 ); // missing returns( true )
c.add( 0, 0 ); c.add( 0, 0 );
assert_failure("missing action");
} }
//] //]
} }
BOOST_AUTO_TEST_SUITE_END()

View file

@ -1,48 +0,0 @@
// 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_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_class< 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_class< T1, T2 >, mock::object
{};
//]
}

View file

@ -6,7 +6,6 @@
// (See accompanying file LICENSE_1_0.txt or copy at // (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt) // http://www.boost.org/LICENSE_1_0.txt)
#define BOOST_AUTO_TEST_MAIN
#include <boost/test/auto_unit_test.hpp> #include <boost/test/auto_unit_test.hpp>
#include <turtle/mock.hpp> #include <turtle/mock.hpp>
@ -35,7 +34,7 @@ namespace limitations_const_parameter_warning_explanation
//] //]
} }
namespace limitations_const_parameter_warning_solution namespace
{ {
//[ limitations_const_parameter_warning_solution //[ limitations_const_parameter_warning_solution
MOCK_BASE_CLASS( mock_base, base ) MOCK_BASE_CLASS( mock_base, base )
@ -48,3 +47,10 @@ namespace limitations_const_parameter_warning_solution
}; };
//] //]
} }
BOOST_AUTO_TEST_CASE(check_method_stub_is_called)
{
mock_base b;
MOCK_EXPECT(b.method).once().with(1);
static_cast<base*>(&b)->method(1);
}

View file

@ -6,7 +6,6 @@
// (See accompanying file LICENSE_1_0.txt or copy at // (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt) // http://www.boost.org/LICENSE_1_0.txt)
#define BOOST_AUTO_TEST_MAIN
#include <boost/test/auto_unit_test.hpp> #include <boost/test/auto_unit_test.hpp>
#include <turtle/mock.hpp> #include <turtle/mock.hpp>

View file

@ -6,7 +6,6 @@
// (See accompanying file LICENSE_1_0.txt or copy at // (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt) // http://www.boost.org/LICENSE_1_0.txt)
#define BOOST_AUTO_TEST_MAIN
#include <boost/test/auto_unit_test.hpp> #include <boost/test/auto_unit_test.hpp>
#include <turtle/mock.hpp> #include <turtle/mock.hpp>
@ -25,3 +24,10 @@ MOCK_BASE_CLASS( mock_base, base )
MOCK_METHOD( method, 0 ) MOCK_METHOD( method, 0 )
}; };
//] //]
BOOST_AUTO_TEST_CASE(method_not_called_through_base)
{
mock_base b;
MOCK_EXPECT(b.method).never();
static_cast<base*>(&b)->method(); // Doesn't call the mocked method
}

View file

@ -6,7 +6,6 @@
// (See accompanying file LICENSE_1_0.txt or copy at // (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt) // http://www.boost.org/LICENSE_1_0.txt)
#define BOOST_AUTO_TEST_MAIN
#include <boost/test/auto_unit_test.hpp> #include <boost/test/auto_unit_test.hpp>
#include <turtle/mock.hpp> #include <turtle/mock.hpp>
@ -15,6 +14,8 @@ namespace
//[ limitations_protected_private_method_problem //[ limitations_protected_private_method_problem
class base class base
{ {
public:
void call(){ method_1(); method_2(); }
protected: protected:
virtual void method_1() = 0; virtual void method_1() = 0;
private: private:
@ -30,3 +31,11 @@ namespace
}; };
//] //]
} }
BOOST_AUTO_TEST_CASE(mocked_methods_are_called)
{
mock_base b;
MOCK_EXPECT(b.method_1).once();
MOCK_EXPECT(b.method_2).once();
static_cast<base*>(&b)->call();
}

View file

@ -6,7 +6,6 @@
// (See accompanying file LICENSE_1_0.txt or copy at // (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt) // http://www.boost.org/LICENSE_1_0.txt)
#define BOOST_AUTO_TEST_MAIN
#include <boost/test/auto_unit_test.hpp> #include <boost/test/auto_unit_test.hpp>
#include <turtle/mock.hpp> #include <turtle/mock.hpp>
@ -27,7 +26,14 @@ namespace
template< typename T > template< typename T >
MOCK_BASE_CLASS( mock_base, base< T > ) MOCK_BASE_CLASS( mock_base, base< T > )
{ {
MOCK_METHOD( method, 1, void() ) MOCK_METHOD( method, 0, void() )
}; };
//] //]
} }
BOOST_AUTO_TEST_CASE(call_method_from_templated_class)
{
mock_base<int> b;
MOCK_EXPECT(b.method).once();
static_cast<base<int>*>(&b)->method();
}

View file

@ -6,7 +6,6 @@
// (See accompanying file LICENSE_1_0.txt or copy at // (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt) // http://www.boost.org/LICENSE_1_0.txt)
#define BOOST_AUTO_TEST_MAIN
#include <boost/test/auto_unit_test.hpp> #include <boost/test/auto_unit_test.hpp>
#include <turtle/mock.hpp> #include <turtle/mock.hpp>
@ -17,8 +16,7 @@ class concept
{ {
public: public:
template< typename T > template< typename T >
void method( T t ) void method( T t );
{}
}; };
template< typename T > template< typename T >
@ -36,6 +34,14 @@ MOCK_CLASS( mock_concept )
MOCK_METHOD( method, 1, void( const char* ), method_string ) MOCK_METHOD( method, 1, void( const char* ), method_string )
}; };
//] //]
BOOST_AUTO_TEST_CASE(mocked_templated_methods_are_called)
{
mock_concept b;
MOCK_EXPECT(b.method_int).once().with(42);
MOCK_EXPECT(b.method_string).once().with(mock::equal(std::string("string")));
function_under_test(b);
}
} }
namespace limitations_template_method_problem_2 namespace limitations_template_method_problem_2
@ -80,4 +86,12 @@ std::string mock_concept::create< std::string >()
return create_string(); return create_string();
} }
//] //]
BOOST_AUTO_TEST_CASE(dispatch_methods_are_called)
{
mock_concept b;
MOCK_EXPECT(b.create_int).once().returns(int{});
MOCK_EXPECT(b.create_string).once().returns(std::string{});
function_under_test(b);
}
} }

View file

@ -6,7 +6,6 @@
// (See accompanying file LICENSE_1_0.txt or copy at // (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt) // http://www.boost.org/LICENSE_1_0.txt)
#define BOOST_AUTO_TEST_MAIN
#include <boost/test/auto_unit_test.hpp> #include <boost/test/auto_unit_test.hpp>
#include <turtle/mock.hpp> #include <turtle/mock.hpp>
@ -17,14 +16,14 @@ namespace
{ {
virtual ~base_class() = default; virtual ~base_class() = default;
virtual void method() throw (); virtual void method() throw() = 0;
}; };
//] //]
//[ limitations_throw_specifier_solution //[ limitations_throw_specifier_solution
MOCK_BASE_CLASS( mock_class, base_class ) MOCK_BASE_CLASS( mock_class, base_class )
{ {
void method() throw () void method() throw() override
{ {
method_proxy(); method_proxy();
} }
@ -32,3 +31,10 @@ namespace
}; };
//] //]
} }
BOOST_AUTO_TEST_CASE(call_method_proxy)
{
mock_class b;
MOCK_EXPECT(b.method).once();
static_cast<base_class*>(&b)->method();
}

View file

@ -6,7 +6,6 @@
// (See accompanying file LICENSE_1_0.txt or copy at // (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt) // http://www.boost.org/LICENSE_1_0.txt)
#define BOOST_AUTO_TEST_MAIN
#include <boost/test/auto_unit_test.hpp> #include <boost/test/auto_unit_test.hpp>
#include <turtle/mock.hpp> #include <turtle/mock.hpp>
#include "calculator.hpp" #include "calculator.hpp"
@ -22,6 +21,8 @@ public:
}; };
//] //]
int calculator::add( int a, int b ){ return a + b; }
//[ simple_zero_plus_zero_is_zero //[ simple_zero_plus_zero_is_zero
BOOST_AUTO_TEST_CASE( zero_plus_zero_is_zero ) BOOST_AUTO_TEST_CASE( zero_plus_zero_is_zero )
{ {
@ -51,7 +52,7 @@ public:
//] //]
//[ zero_plus_zero_is_zero_without_mock_object //[ zero_plus_zero_is_zero_without_mock_object
BOOST_AUTO_TEST_CASE( zero_plus_zero_is_zero ) BOOST_AUTO_TEST_CASE( zero_plus_zero_is_zero_without_mock_object )
{ {
my_view v; my_view v;
calculator c( v ); calculator c( v );
@ -65,7 +66,7 @@ BOOST_AUTO_TEST_CASE( zero_plus_zero_is_zero )
namespace with_mock_object namespace with_mock_object
{ {
//[ zero_plus_zero_is_zero_with_mock_object //[ zero_plus_zero_is_zero_with_mock_object
BOOST_AUTO_TEST_CASE( zero_plus_zero_is_zero ) BOOST_AUTO_TEST_CASE( zero_plus_zero_is_zero_with_mock_object )
{ {
mock_view v; mock_view v;
calculator c( v ); calculator c( v );

View file

@ -7,7 +7,7 @@
// http://www.boost.org/LICENSE_1_0.txt) // http://www.boost.org/LICENSE_1_0.txt)
//[ async_call_problem //[ async_call_problem
namespace namespace mock_test
{ {
class base_class class base_class
{ {
@ -17,6 +17,7 @@ namespace
class my_class class my_class
{ {
base_class& b;
public: public:
explicit my_class( base_class& ); explicit my_class( base_class& );
@ -25,14 +26,23 @@ namespace
} }
//] //]
namespace mock_test
{
my_class::my_class( base_class& b): b(b){}
void my_class::flush()
{
static int secret_value = 7;
if(--secret_value == 0)
b.method();
}
}
//[ async_call_solution //[ async_call_solution
#define BOOST_AUTO_TEST_MAIN
#include <boost/test/auto_unit_test.hpp> #include <boost/test/auto_unit_test.hpp>
#include <boost/lambda/lambda.hpp>
#include <boost/thread.hpp> #include <boost/thread.hpp>
#include <turtle/mock.hpp> #include <turtle/mock.hpp>
namespace namespace mock_test
{ {
template< typename F > template< typename F >
void check( bool& condition, F flush, int attempts = 100, int sleep = 100 ) void check( bool& condition, F flush, int attempts = 100, int sleep = 100 )
@ -49,25 +59,15 @@ namespace
{ {
MOCK_METHOD( method, 0 ) MOCK_METHOD( method, 0 )
}; };
void set_bool(bool& b)
{
b = true;
}
} }
BOOST_AUTO_TEST_CASE( method_is_called ) BOOST_AUTO_TEST_CASE( method_is_called )
{ {
using namespace mock_test;
mock_base_class m; mock_base_class m;
my_class c( m ); my_class c( m );
bool done = false; bool done = false;
// when method is called it will set done to true MOCK_EXPECT( m.method ).once().calls( [&done](){ done = true; } );
// Note: Boost 1.57 introduced a bug preventing usage of the lambda with clang in C++98 check( done, [&c](){ c.flush(); } ); // just wait on done, flushing from time to time
// See: https://svn.boost.org/trac10/ticket/10785
#if defined(BOOST_CLANG) && (BOOST_VERSION >= 105700)
MOCK_EXPECT( m.method ).once().calls( std::bind(&set_bool, done) );
#else
MOCK_EXPECT( m.method ).once().calls( boost::lambda::var( done ) = true );
#endif
check( done, std::bind( &my_class::flush, &c ) ); // just wait on done, flushing from time to time
} }
//] //]

View file

@ -9,8 +9,6 @@
//[ invoke_functor_problem //[ invoke_functor_problem
#include <functional> #include <functional>
namespace
{
class base_class class base_class
{ {
public: public:
@ -18,14 +16,24 @@ namespace
}; };
void function( base_class& ); // the function will call 'method' with a functor to be applied void function( base_class& ); // the function will call 'method' with a functor to be applied
}
//] //]
namespace
{
int receivedValue = 0;
void setx(int newValue)
{
receivedValue = newValue;
}
}
void function( base_class& c)
{
c.method(setx);
}
//[ invoke_functor_solution //[ invoke_functor_solution
#define BOOST_AUTO_TEST_MAIN
#include <boost/test/auto_unit_test.hpp> #include <boost/test/auto_unit_test.hpp>
#include <turtle/mock.hpp> #include <turtle/mock.hpp>
#include <functional>
namespace namespace
{ {
@ -40,5 +48,6 @@ BOOST_AUTO_TEST_CASE( how_to_invoke_a_functor_passed_as_parameter_of_a_mock_meth
mock_class mock; mock_class mock;
MOCK_EXPECT( mock.method ).calls( [](const auto &functor){ functor(42); } ); // whenever 'method' is called, invoke the functor with 42 MOCK_EXPECT( mock.method ).calls( [](const auto &functor){ functor(42); } ); // whenever 'method' is called, invoke the functor with 42
function( mock ); function( mock );
BOOST_CHECK(receivedValue == 42);
} }
//] //]

View file

@ -7,7 +7,6 @@
// http://www.boost.org/LICENSE_1_0.txt) // http://www.boost.org/LICENSE_1_0.txt)
//[ quick_constraint_problem //[ quick_constraint_problem
#define BOOST_AUTO_TEST_MAIN
#include <boost/test/auto_unit_test.hpp> #include <boost/test/auto_unit_test.hpp>
#include <turtle/mock.hpp> #include <turtle/mock.hpp>
#include <iostream> #include <iostream>

View file

@ -7,7 +7,7 @@
// http://www.boost.org/LICENSE_1_0.txt) // http://www.boost.org/LICENSE_1_0.txt)
//[ retrieve_cref_problem //[ retrieve_cref_problem
namespace namespace mock_test
{ {
class base_class class base_class
{ {
@ -17,6 +17,7 @@ namespace
class my_class class my_class
{ {
base_class& b;
public: public:
explicit my_class( base_class& ); explicit my_class( base_class& );
@ -25,12 +26,22 @@ namespace
} }
//] //]
namespace mock_test
{
my_class::my_class( base_class& b): b(b){}
void my_class::process()
{
int secret_value = 42;
b.method(secret_value);
b.method(secret_value);
}
}
//[ retrieve_cref_solution //[ retrieve_cref_solution
#define BOOST_AUTO_TEST_MAIN
#include <boost/test/auto_unit_test.hpp> #include <boost/test/auto_unit_test.hpp>
#include <turtle/mock.hpp> #include <turtle/mock.hpp>
namespace namespace mock_test
{ {
MOCK_BASE_CLASS( mock_base_class, base_class ) MOCK_BASE_CLASS( mock_base_class, base_class )
{ {
@ -40,6 +51,7 @@ namespace
BOOST_AUTO_TEST_CASE( method_is_called_two_times_with_the_same_value ) BOOST_AUTO_TEST_CASE( method_is_called_two_times_with_the_same_value )
{ {
using namespace mock_test;
mock_base_class mock; mock_base_class mock;
my_class c( mock ); my_class c( mock );
int value; int value;

View file

@ -6,8 +6,10 @@
// (See accompanying file LICENSE_1_0.txt or copy at // (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt) // http://www.boost.org/LICENSE_1_0.txt)
// Used to make this test file pass. Define to empty to see other tests fail
#define ASSERT_VERIFY_FAIL() mock::reset()
//[ static_objects_problem //[ static_objects_problem
#define BOOST_AUTO_TEST_MAIN
#include <boost/test/auto_unit_test.hpp> #include <boost/test/auto_unit_test.hpp>
#include <turtle/mock.hpp> #include <turtle/mock.hpp>
#include <ostream> #include <ostream>
@ -16,8 +18,7 @@ namespace
{ {
struct my_class struct my_class
{ {
my_class( int i ) my_class( int i ) : i_( i )
: i_( i )
{} {}
int i_; int i_;
@ -28,13 +29,14 @@ namespace
return os << "my_class " << c->i_; // the 'c' pointer must be valid when logging return os << "my_class " << c->i_; // the 'c' pointer must be valid when logging
} }
MOCK_FUNCTION( f, 1, void( my_class* ) ) // being static 'f' outlive the test case MOCK_FUNCTION( f, 1, void( my_class* ) ) // being static 'f' outlives the test case
} }
BOOST_AUTO_TEST_CASE( static_objects_problem ) BOOST_AUTO_TEST_CASE( static_objects_problem )
{ {
my_class c( 42 ); my_class c( 42 );
MOCK_EXPECT( f ).once().with( &c ); // the set expectation will also outlive the test case and leak into other test cases using 'f' MOCK_EXPECT( f ).once().with( &c ); // the set expectation will also outlive the test case and leak into other test cases using 'f'
ASSERT_VERIFY_FAIL(); // Check that mock::verify fails, but that means other test fail too
} // the 'c' instance goes out of scope and the '&c' pointer becomes dangling } // the 'c' instance goes out of scope and the '&c' pointer becomes dangling
//] //]

View file

@ -9,6 +9,19 @@
#include <turtle/mock.hpp> #include <turtle/mock.hpp>
#include "calculator.hpp" #include "calculator.hpp"
#include "mock_view.hpp" #include "mock_view.hpp"
#include <boost/test/unit_test.hpp>
#include <iostream>
#include <limits>
#include <stdexcept>
// Dummy to detect if the assertion unexpectedly succeeded to test what is explained
#undef BOOST_CHECK_THROW
#define BOOST_CHECK_THROW(expr, exc) \
try { \
expr; \
} catch(const exc&) { \
std::cerr << "Exception thrown but should not"; \
}
//[ overflow_throws //[ overflow_throws
BOOST_AUTO_TEST_CASE( overflow_throws ) BOOST_AUTO_TEST_CASE( overflow_throws )

View file

@ -6,7 +6,6 @@
// (See accompanying file LICENSE_1_0.txt or copy at // (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt) // http://www.boost.org/LICENSE_1_0.txt)
#define BOOST_AUTO_TEST_MAIN
#include <boost/test/auto_unit_test.hpp> #include <boost/test/auto_unit_test.hpp>
#include <turtle/mock.hpp> #include <turtle/mock.hpp>
@ -374,10 +373,11 @@ MOCK_CLASS( mock_class )
namespace function_example_1 namespace function_example_1
{ {
//[ function_example_1 //[ function_example_1
MOCK_FUNCTION( f, 1, float( int ) ) MOCK_FUNCTION( f, 1, void( int ) )
BOOST_AUTO_TEST_CASE( demonstrates_instantiating_a_mock_function ) BOOST_AUTO_TEST_CASE( demonstrates_instantiating_a_mock_function )
{ {
MOCK_EXPECT(f).once().with(3);
f( 3 ); f( 3 );
} }
//] //]
@ -398,6 +398,7 @@ namespace functor_example_1
BOOST_AUTO_TEST_CASE( demonstrates_instantiating_a_mock_functor ) BOOST_AUTO_TEST_CASE( demonstrates_instantiating_a_mock_functor )
{ {
MOCK_FUNCTOR( f, void( int ) ); MOCK_FUNCTOR( f, void( int ) );
MOCK_EXPECT(f).once().with(3);
f( 3 ); f( 3 );
} }
//] //]
@ -409,12 +410,13 @@ namespace functor_example_2
template< typename T > template< typename T >
struct mock_class struct mock_class
{ {
MOCK_FUNCTOR_TPL( f, void( T ) ); MOCK_FUNCTOR( f, void( T ) );
}; };
BOOST_AUTO_TEST_CASE( demonstrates_instantiating_a_mock_functor ) BOOST_AUTO_TEST_CASE( demonstrates_instantiating_a_mock_functor_inside_a_class )
{ {
mock_class< int > c; mock_class< int > c;
MOCK_EXPECT(c.f).once().with(3);
c.f( 3 ); c.f( 3 );
} }
//] //]
@ -436,6 +438,9 @@ BOOST_AUTO_TEST_CASE( demonstrates_configuring_mock_objects )
MOCK_EXPECT( c.method ).once().with( 0 ).in( s ).returns( 42 ); MOCK_EXPECT( c.method ).once().with( 0 ).in( s ).returns( 42 );
MOCK_EXPECT( c.method2 ).never().with( "ok", mock::any ); MOCK_EXPECT( c.method2 ).never().with( "ok", mock::any );
MOCK_EXPECT( c.method2 ).at_least( 2 ).in( s ).throws( std::runtime_error( "error !" ) ); MOCK_EXPECT( c.method2 ).at_least( 2 ).in( s ).throws( std::runtime_error( "error !" ) );
BOOST_CHECK(c.method(0) == 42);
BOOST_CHECK_THROW(c.method("notok", 1.f), std::runtime_error);
BOOST_CHECK_THROW(c.method("notok", 2.f), std::runtime_error);
} }
//] //]
} }
@ -446,13 +451,18 @@ namespace invocation_example_1
MOCK_CLASS( mock_class ) MOCK_CLASS( mock_class )
{ {
MOCK_METHOD( method, 2, void( int, const std::string& ) ) MOCK_METHOD( method, 2, void( int, const std::string& ) )
MOCK_METHOD( method2, 1, void( int ) )
}; };
BOOST_AUTO_TEST_CASE( demonstrates_setting_up_invocations_on_a_mock_method ) BOOST_AUTO_TEST_CASE( demonstrates_setting_up_invocations_on_a_mock_method )
{ {
mock_class c; mock_class c;
MOCK_EXPECT( c.method ).once(); // can only be called once MOCK_EXPECT( c.method ).once(); // can only be called once
MOCK_EXPECT( c.method ); // can be called an unlimited number of times MOCK_EXPECT( c.method2 ); // can be called an unlimited number of times
c.method(42, "Hello world!");
c.method2(42);
c.method2(42);
c.method2(42);
} }
//] //]
} }
@ -464,6 +474,7 @@ BOOST_AUTO_TEST_CASE( demonstrates_setting_up_an_invocation_on_a_mock_functor )
{ {
MOCK_FUNCTOR( f, void( int, const std::string& ) ); MOCK_FUNCTOR( f, void( int, const std::string& ) );
MOCK_EXPECT( f ).once(); MOCK_EXPECT( f ).once();
f(42, "Hello world!");
} }
//] //]
} }
@ -476,6 +487,7 @@ MOCK_FUNCTION( f, 1, void( int ) )
BOOST_AUTO_TEST_CASE( demonstrates_setting_up_an_invocation_on_a_mock_function ) BOOST_AUTO_TEST_CASE( demonstrates_setting_up_an_invocation_on_a_mock_function )
{ {
MOCK_EXPECT( f ).once(); MOCK_EXPECT( f ).once();
f(42);
} }
//] //]
} }
@ -485,14 +497,17 @@ namespace invocation_example_4
//[ invocation_example_4 //[ invocation_example_4
MOCK_CLASS( mock_class ) MOCK_CLASS( mock_class )
{ {
MOCK_STATIC_METHOD( method, 1, void( int ) ) MOCK_STATIC_METHOD( method1, 1, void( int ) )
MOCK_STATIC_METHOD( method2, 1, void( int ) )
}; };
BOOST_AUTO_TEST_CASE( demonstrates_setting_up_an_invocation_on_a_mock_static_method ) BOOST_AUTO_TEST_CASE( demonstrates_setting_up_an_invocation_on_a_mock_static_method )
{ {
mock_class c; mock_class c;
MOCK_EXPECT( c.method ).once(); MOCK_EXPECT( c.method1 ).once();
MOCK_EXPECT( mock_class::method ).once(); // does the same MOCK_EXPECT( mock_class::method2 ).once(); // does the same
c.method1(42);
c.method2(42);
} }
//] //]
} }
@ -502,14 +517,17 @@ namespace constraints_example_1
//[ constraints_example_1 //[ constraints_example_1
MOCK_CLASS( mock_class ) MOCK_CLASS( mock_class )
{ {
MOCK_METHOD( method, 2, void( int, const std::string& ) ) MOCK_METHOD( method1, 2, void( int, const std::string& ) )
MOCK_METHOD( method2, 2, void( int, const std::string& ) )
}; };
BOOST_AUTO_TEST_CASE( demonstrates_adding_builtin_constraints ) BOOST_AUTO_TEST_CASE( demonstrates_adding_builtin_constraints )
{ {
mock_class c; mock_class c;
MOCK_EXPECT( c.method ).with( mock::equal( 3 ), mock::equal( "some string" ) ); MOCK_EXPECT( c.method1 ).with( mock::equal( 3 ), mock::equal( "some string" ) );
MOCK_EXPECT( c.method ).with( 3, "some string" ); // equivalent to the previous one using short-cuts MOCK_EXPECT( c.method2 ).with( 3, "some string" ); // equivalent to the previous one using short-cuts
c.method1(3, "some string");
c.method2(3, "some string");
} }
//] //]
} }
@ -531,6 +549,7 @@ BOOST_AUTO_TEST_CASE( demonstrates_adding_a_custom_constraint_with_a_free_functi
{ {
mock_class c; mock_class c;
MOCK_EXPECT( c.method ).with( &custom_constraint ); MOCK_EXPECT( c.method ).with( &custom_constraint );
c.method(42);
} }
//] //]
} }
@ -552,6 +571,7 @@ BOOST_AUTO_TEST_CASE( demonstrates_adding_a_custom_constraint_with_a_standard_li
{ {
mock_class c; mock_class c;
MOCK_EXPECT( c.method ).with( std::bind1st( std::ptr_fun( &custom_constraint ), 42 ) ); // std::ptr_fun creates an std::unary_function MOCK_EXPECT( c.method ).with( std::bind1st( std::ptr_fun( &custom_constraint ), 42 ) ); // std::ptr_fun creates an std::unary_function
c.method(42);
} }
//] //]
} }
@ -569,10 +589,12 @@ bool custom_constraint( int expected, int actual )
return expected == actual; return expected == actual;
} }
BOOST_AUTO_TEST_CASE( demonstrates_adding_a_custom_constraint_with_boost_bind ) BOOST_AUTO_TEST_CASE( demonstrates_adding_a_custom_constraint_with_std_bind )
{ {
mock_class c; mock_class c;
using namespace std::placeholders;
MOCK_EXPECT( c.method ).with( std::bind( &custom_constraint, 42, _1 ) ); MOCK_EXPECT( c.method ).with( std::bind( &custom_constraint, 42, _1 ) );
c.method(42);
} }
//] //]
} }
@ -593,6 +615,7 @@ BOOST_AUTO_TEST_CASE( demonstrates_adding_a_custom_constraint_with_boost_lambda
{ {
mock_class c; mock_class c;
MOCK_EXPECT( c.method ).with( boost::lambda::_1 == 42 ); MOCK_EXPECT( c.method ).with( boost::lambda::_1 == 42 );
c.method(42);
} }
//] //]
} }
@ -606,14 +629,17 @@ namespace constraints_example_6
//[ constraints_example_6 //[ constraints_example_6
MOCK_CLASS( mock_class ) MOCK_CLASS( mock_class )
{ {
MOCK_METHOD( method, 1, void( int ) ) MOCK_METHOD( method1, 1, void( int ) )
MOCK_METHOD( method2, 1, void( int ) )
}; };
BOOST_AUTO_TEST_CASE( demonstrates_adding_a_custom_constraint_with_boost_phoenix ) BOOST_AUTO_TEST_CASE( demonstrates_adding_a_custom_constraint_with_boost_phoenix )
{ {
mock_class c; mock_class c;
MOCK_EXPECT( c.method ).with( boost::phoenix::arg_names::arg1 == 42 ); MOCK_EXPECT( c.method1 ).with( boost::phoenix::arg_names::arg1 == 42 );
MOCK_EXPECT( c.method ).with( boost::phoenix::arg_names::_1 == 42 ); MOCK_EXPECT( c.method2 ).with( boost::phoenix::arg_names::_1 == 42 );
c.method1(42);
c.method2(42);
} }
//] //]
} }
@ -630,6 +656,7 @@ BOOST_AUTO_TEST_CASE( demonstrates_adding_a_constraint_with_cxx11_lambda )
{ {
mock_class c; mock_class c;
MOCK_EXPECT( c.method ).with( []( int actual ) { return 42 == actual; } ); MOCK_EXPECT( c.method ).with( []( int actual ) { return 42 == actual; } );
c.method(42);
} }
//] //]
} }
@ -646,6 +673,7 @@ BOOST_AUTO_TEST_CASE( demonstrates_combining_constraints )
{ {
mock_class c; mock_class c;
MOCK_EXPECT( c.method ).with( mock::less( 4 ) && mock::greater( 2 ), ! mock::equal( "" ) ); MOCK_EXPECT( c.method ).with( mock::less( 4 ) && mock::greater( 2 ), ! mock::equal( "" ) );
c.method(3, "Hello World!");
} }
//] //]
} }
@ -667,6 +695,7 @@ BOOST_AUTO_TEST_CASE( demonstrates_one_constraint_for_all_arguments )
{ {
mock_class c; mock_class c;
MOCK_EXPECT( c.method ).with( &custom_constraint ); MOCK_EXPECT( c.method ).with( &custom_constraint );
c.method("1234", 4);
} }
//] //]
} }
@ -698,6 +727,9 @@ BOOST_AUTO_TEST_CASE( demonstrates_enforcing_several_expectation_orders )
MOCK_EXPECT( c_1.method_1 ).in( s_1 ); MOCK_EXPECT( c_1.method_1 ).in( s_1 );
MOCK_EXPECT( c_2.method_2 ).in( s_2 ); // c_1.method_1 and c_2.method_2 are in different sequences and can be called in any order MOCK_EXPECT( c_2.method_2 ).in( s_2 ); // c_1.method_1 and c_2.method_2 are in different sequences and can be called in any order
MOCK_EXPECT( c_3.method_3 ).in( s_1, s_2 ); // c_3.method_3 must be called after both c_1.method_1 and c_2.method_2 MOCK_EXPECT( c_3.method_3 ).in( s_1, s_2 ); // c_3.method_3 must be called after both c_1.method_1 and c_2.method_2
c_2.method_2();
c_1.method_1();
c_3.method_3();
} }
//] //]
} }
@ -718,12 +750,18 @@ int function( int i )
BOOST_AUTO_TEST_CASE( demonstrates_configuring_actions ) BOOST_AUTO_TEST_CASE( demonstrates_configuring_actions )
{ {
mock_class c; mock_class c;
MOCK_EXPECT( c.method ).returns( 42 ); MOCK_EXPECT( c.method ).once().returns( 42 );
MOCK_EXPECT( c.method ).moves( 42 ); // returns by moving the value MOCK_EXPECT( c.method ).once().moves( 42 ); // returns by moving the value
MOCK_EXPECT( c.method ).throws( std::runtime_error( "error !" ) ); MOCK_EXPECT( c.method ).once().throws( std::runtime_error( "error !" ) );
MOCK_EXPECT( c.method ).calls( &function ); // forwards 'method' parameter to 'function' MOCK_EXPECT( c.method ).once().calls( &function ); // forwards 'method' parameter to 'function'
MOCK_EXPECT( c.method ).calls( std::bind( &function, 42 ) ); // drops 'method' parameter and binds 42 as parameter to 'function' MOCK_EXPECT( c.method ).once().calls( std::bind( &function, 42 ) ); // drops 'method' parameter and binds 42 as parameter to 'function'
MOCK_EXPECT( c.method ).calls( []( int i ) { return i; } ); // uses a C++11 lambda MOCK_EXPECT( c.method ).once().calls( []( int i ) { return i; } ); // uses a C++11 lambda
BOOST_CHECK(c.method(0) == 42);
BOOST_CHECK(c.method(1) == 42);
BOOST_CHECK_THROW(c.method(0), std::runtime_error);
BOOST_CHECK(c.method(2) == 2);
BOOST_CHECK(c.method(3) == 42);
BOOST_CHECK(c.method(4) == 4);
} }
//] //]
} }
@ -913,46 +951,3 @@ BOOST_AUTO_TEST_CASE( mock_constraint_2_arity )
} }
//] //]
} }
namespace helpers_example_4
{
//[ helpers_example_4
MOCK_CONSTRAINT_EXT( any, 0,, true ) // this is (almost) how mock::any is defined
MOCK_CONSTRAINT_EXT( forty_two, 0,, actual == 42 ) // this defines a 'forty_two' constraint
BOOST_AUTO_TEST_CASE( mock_constraint_0_arity )
{
MOCK_FUNCTOR( f, void( int ) );
MOCK_EXPECT( f ).with( forty_two );
MOCK_EXPECT( f ).with( any );
}
//]
}
namespace helpers_example_5
{
//[ helpers_example_5
MOCK_CONSTRAINT_EXT( equal, 1, ( expected ), actual == expected ) // this is how mock::equal is defined
MOCK_CONSTRAINT_EXT( near, 1, ( expected ), std::abs( actual - expected ) < 0.01 ) // this defines a 'near' constraint which can be used as 'near( 42 )'
BOOST_AUTO_TEST_CASE( mock_constraint_1_arity )
{
MOCK_FUNCTOR( f, void( int ) );
MOCK_EXPECT( f ).with( near( 42 ) );
MOCK_EXPECT( f ).with( equal( 42 ) );
}
//]
}
namespace helpers_example_6
{
//[ helpers_example_6
MOCK_CONSTRAINT_EXT( near, 2, ( expected, tolerance ), std::abs( actual - expected ) < tolerance ) // this is how mock::near is defined
BOOST_AUTO_TEST_CASE( mock_constraint_2_arity )
{
MOCK_FUNCTOR( f, void( int ) );
MOCK_EXPECT( f ).with( near( 42, 0.001 ) );
}
//]
}

View file

@ -12,7 +12,6 @@
[import example/limitations_template_base_class_method.cpp] [import example/limitations_template_base_class_method.cpp]
[import example/limitations_template_method.cpp] [import example/limitations_template_method.cpp]
[import example/limitations_protected_private_method.cpp] [import example/limitations_protected_private_method.cpp]
[import example/limitations_comma_in_macro.cpp]
[import example/limitations_const_parameter_warning.cpp] [import example/limitations_const_parameter_warning.cpp]
This section lists the library known limitations. This section lists the library known limitations.
@ -151,43 +150,6 @@ A workaround would be to write a proxy member function :
[endsect] [endsect]
[section Compilers without support for variadic macros fail on commas in MOCK_BASE_CLASS]
For compilers without support for variadic macros given :
[limitations_comma_in_macro_problem]
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 :
[limitations_comma_in_macro_solution_1]
Of course this is not always possible, as in :
template< typename T1, typename T2 >
MOCK_BASE_CLASS( my_mock, my_base_type< T1, T2 > )
{};
Another workaround would make use of [@http://www.boost.org/libs/preprocessor Boost.Preprocessor] :
[limitations_comma_in_macro_solution_2]
Actually BOOST_PP_COMMA implementation is quite trivial, being only :
#define BOOST_PP_COMMA() ,
Finally another workaround would be to not use the macro at all :
[limitations_comma_in_macro_solution_3]
Note that [@http://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).
[endsect]
[section Warning C4505: '...' : unreferenced local function has been removed] [section Warning C4505: '...' : unreferenced local function has been removed]
Example : Example :

View file

@ -105,8 +105,6 @@ Synopsis :
[note In case of a calling convention specified, all four parameters must be provided.] [note In case of a calling convention specified, all four parameters must be provided.]
[warning For compilers without support for variadic macros the MOCK_METHOD_EXT familly set of macros must be used.]
Synopsis : Synopsis :
MOCK_METHOD_EXT( [calling convention] name, arity, signature, identifier ) // generates both const and non-const methods MOCK_METHOD_EXT( [calling convention] name, arity, signature, identifier ) // generates both const and non-const methods
@ -167,8 +165,6 @@ Synopsis :
[note In case of a calling convention specified, all four parameters must be provided.] [note In case of a calling convention specified, all four parameters must be provided.]
[warning For compilers without support for variadic macros the identifier cannot be omitted and must be given explicitly.]
Example : Example :
[static_member_function_example_1] [static_member_function_example_1]
@ -277,8 +273,6 @@ Synopsis :
[note In case of a calling convention specified, all four parameters must be provided.] [note In case of a calling convention specified, all four parameters must be provided.]
[warning For compilers without support for variadic macros the identifier cannot be omitted and must be given explicitly.]
Example : Example :
[function_example_1] [function_example_1]
@ -415,13 +409,13 @@ Constraints :
[[mock::evaluate] [['actual]()] [evaluates ['actual] as a functor returning a ['bool] and taking no argument]] [[mock::evaluate] [['actual]()] [evaluates ['actual] as a functor returning a ['bool] and taking no argument]]
] ]
[important When passing ['expected] directly as a shortcut mock::call is implied for a function, a function pointer, an instance of a type with a result_type member typedef (support for standard library, [@http://www.boost.org/libs/bind/bind.html Boost.Bind], [@http://www.boost.org/libs/function Boost.Function] functors), an instance of a type with a sig member (support for [@http://www.boost.org/libs/lambda Boost.Lambda] functors), an instance of a type with a result member (support for [@http://www.boost.org/libs/phoenix Boost.Phoenix] functors); mock::equal is implied for anything else.] [important When passing ['expected] directly as a shortcut mock::call is implied for a callable (function, function pointer, functor, ...); mock::equal is implied for anything else.]
[warning Because mock::assign and mock::retrieve have side effects they may modify ['expected] in unexpected ways. For instance they may be called again after their expectations have already been exhausted because of the way the [link turtle.getting_started.expectation_selection_algorithm expectation selection algorithm] works. Therefore it is probably a good idea to use an [link turtle.reference.expectation.actions action] instead.] [warning Because mock::assign and mock::retrieve have side effects they may modify ['expected] in unexpected ways. For instance they may be called again after their expectations have already been exhausted because of the way the [link turtle.getting_started.expectation_selection_algorithm expectation selection algorithm] works. Therefore it is probably a good idea to use an [link turtle.reference.expectation.actions action] instead.]
[note For mock::assign and mock::retrieve the switch to one form or another is made depending on whichever is the most relevant based on types involved.] [note For mock::assign and mock::retrieve the switch to one form or another is made depending on whichever is the most relevant based on types involved.]
[note All constraints accepting a parameter support the use of boost::ref and boost::cref in order to delay initialization.] [note All constraints accepting a parameter support the use of std::ref and std::cref in order to delay initialization.]
[note All constraints can be combined using the && and || operators, as well as negated with the ! operator.] [note All constraints can be combined using the && and || operators, as well as negated with the ! operator.]
@ -437,7 +431,7 @@ Example using a standard library functor :
[constraints_example_3] [constraints_example_3]
Example using [@http://www.boost.org/libs/bind Boost.Bind] : Example using std::bind :
[constraints_example_4] [constraints_example_4]
@ -497,7 +491,7 @@ Synopsis :
[note The returns and moves actions are not available for mock methods returning void, including constructors and destructors.] [note The returns and moves actions are not available for mock methods returning void, including constructors and destructors.]
[note Actions are captured by copy, boost::ref and boost::cref can however be used to turn the copies into references.] [note Actions are captured by copy, std::ref and std::cref can however be used to turn the copies into references.]
Example : Example :
@ -581,38 +575,18 @@ Synopsis :
The expression manipulates a received parameter ['actual] in order to implement the constraint, as well as extra optional arguments named ['expected_1], ['expected_2], ... The expression manipulates a received parameter ['actual] in order to implement the constraint, as well as extra optional arguments named ['expected_1], ['expected_2], ...
For compilers without support for variadic macros the alternate following macro must be used.
Synopsis :
MOCK_CONSTRAINT_EXT( name, arity, ( expected_1, expected_2, ... ), expression ) // defines a constraint 'name' based on the given 'expression'
Of course this macro is also available for compilers which support variadic macros.
Example without any extra argument : Example without any extra argument :
[helpers_example_1] [helpers_example_1]
or with the alternate more portable macro :
[helpers_example_4]
Example with one extra argument : Example with one extra argument :
[helpers_example_2] [helpers_example_2]
or with the alternate more portable macro :
[helpers_example_5]
Example with two extra arguments : Example with two extra arguments :
[helpers_example_3] [helpers_example_3]
or with the alternate more portable macro :
[helpers_example_6]
[endsect] [endsect]
[endsect] [endsect]

View file

@ -11,7 +11,7 @@
#include "config.hpp" #include "config.hpp"
#include "log.hpp" #include "log.hpp"
#include "detail/unwrap_reference.hpp" #include "unwrap_reference.hpp"
#include <boost/preprocessor/stringize.hpp> #include <boost/preprocessor/stringize.hpp>
#include <boost/preprocessor/control/if.hpp> #include <boost/preprocessor/control/if.hpp>
#include <boost/preprocessor/variadic/to_array.hpp> #include <boost/preprocessor/variadic/to_array.hpp>
@ -135,7 +135,7 @@ namespace detail
template< typename Actual > \ template< typename Actual > \
bool operator()( const Actual& actual ) const \ bool operator()( const Actual& actual ) const \
{ \ { \
return Expr; \ (void) actual; return Expr; \
} \ } \
friend std::ostream& operator<<( std::ostream& s, const Name& ) \ friend std::ostream& operator<<( std::ostream& s, const Name& ) \
{ \ { \
@ -149,7 +149,7 @@ namespace detail
expected##n( std::forward< T##n >(e##n) ) expected##n( std::forward< T##n >(e##n) )
#define MOCK_CONSTRAINT_UNWRAP_REF(z, n, d) \ #define MOCK_CONSTRAINT_UNWRAP_REF(z, n, d) \
mock::detail::unwrap_ref( expected##n ) mock::unwrap_ref( expected##n )
#define MOCK_CONSTRAINT_FORMAT(z, n, d) \ #define MOCK_CONSTRAINT_FORMAT(z, n, d) \
BOOST_PP_IF(n, << ", " <<,) mock::format( c.expected##n ) BOOST_PP_IF(n, << ", " <<,) mock::format( c.expected##n )
@ -161,7 +161,7 @@ namespace detail
std::decay_t< const T##n > std::decay_t< const T##n >
#define MOCK_CONSTRAINT_CREF_PARAM(z, n, Args) \ #define MOCK_CONSTRAINT_CREF_PARAM(z, n, Args) \
const mock::detail::unwrap_reference_t< Expected_##n >& \ const mock::unwrap_reference_t< Expected_##n >& \
BOOST_PP_ARRAY_ELEM(n, Args) BOOST_PP_ARRAY_ELEM(n, Args)
#define MOCK_CONSTRAINT_ARG(z, n, Args) \ #define MOCK_CONSTRAINT_ARG(z, n, Args) \

View file

@ -12,7 +12,7 @@
#include "config.hpp" #include "config.hpp"
#include "constraint.hpp" #include "constraint.hpp"
#include "detail/move_helper.hpp" #include "detail/move_helper.hpp"
#include "detail/unwrap_reference.hpp" #include "unwrap_reference.hpp"
#include <boost/version.hpp> #include <boost/version.hpp>
#include <boost/type_traits/make_void.hpp> #include <boost/type_traits/make_void.hpp>
#if BOOST_VERSION >= 107000 #if BOOST_VERSION >= 107000

View file

@ -240,8 +240,7 @@ namespace detail
return line_; return line_;
} }
friend std::ostream& operator<<( friend std::ostream& operator<<( std::ostream& s, const expectation& e )
std::ostream& s, const expectation& e )
{ {
return s << ( e.invocation_->exhausted() ? 'v' : '.' ) return s << ( e.invocation_->exhausted() ? 'v' : '.' )
<< ' ' << *e.invocation_ << ' ' << *e.invocation_

View file

@ -129,26 +129,22 @@ namespace detail
} }
wrapper& exactly( std::size_t count ) wrapper& exactly( std::size_t count )
{ {
this->e_->invoke( this->e_->invoke( std::make_shared< detail::exactly >( count ) );
std::make_shared< detail::exactly >( count ) );
return *this; return *this;
} }
wrapper& at_least( std::size_t min ) wrapper& at_least( std::size_t min )
{ {
this->e_->invoke( this->e_->invoke( std::make_shared< detail::at_least >( min ) );
std::make_shared< detail::at_least >( min ) );
return *this; return *this;
} }
wrapper& at_most( std::size_t max ) wrapper& at_most( std::size_t max )
{ {
this->e_->invoke( this->e_->invoke( std::make_shared< detail::at_most >( max ) );
std::make_shared< detail::at_most >( max ) );
return *this; return *this;
} }
wrapper& between( std::size_t min, std::size_t max ) wrapper& between( std::size_t min, std::size_t max )
{ {
this->e_->invoke( this->e_->invoke( std::make_shared< detail::between >( min, max ) );
std::make_shared< detail::between >( min, max ) );
return *this; return *this;
} }
@ -250,8 +246,7 @@ namespace detail
return error_type::abort(); return error_type::abort();
} }
valid_ = true; valid_ = true;
error_type::call( error_type::call( MOCK_FUNCTION_CONTEXT, it->file(), it->line() );
MOCK_FUNCTION_CONTEXT, it->file(), it->line() );
if( it->functor() ) if( it->functor() )
return it->functor()( return it->functor()(
BOOST_PP_ENUM(MOCK_NUM_ARGS, MOCK_MOVE, _) ); BOOST_PP_ENUM(MOCK_NUM_ARGS, MOCK_MOVE, _) );
@ -273,8 +268,7 @@ namespace detail
context_ = &c; context_ = &c;
} }
friend std::ostream& operator<<( friend std::ostream& operator<<( std::ostream& s, const function_impl& impl )
std::ostream& s, const function_impl& impl )
{ {
lock _( impl.mutex_ ); lock _( impl.mutex_ );
return s << lazy_context( &impl ) << lazy_expectations( &impl ); return s << lazy_context( &impl ) << lazy_expectations( &impl );
@ -285,8 +279,7 @@ namespace detail
lazy_context( const function_impl* impl ) lazy_context( const function_impl* impl )
: impl_( impl ) : impl_( impl )
{} {}
friend std::ostream& operator<<( friend std::ostream& operator<<( std::ostream& s, const lazy_context& c )
std::ostream& s, const lazy_context& c )
{ {
if( c.impl_->context_ ) if( c.impl_->context_ )
c.impl_->context_->serialize( s, *c.impl_ ); c.impl_->context_->serialize( s, *c.impl_ );
@ -302,8 +295,7 @@ namespace detail
lazy_expectations( const function_impl* impl ) lazy_expectations( const function_impl* impl )
: impl_( impl ) : impl_( impl )
{} {}
friend std::ostream& operator<<( friend std::ostream& operator<<( std::ostream& s, const lazy_expectations& e )
std::ostream& s, const lazy_expectations& e )
{ {
for( expectations_cit it = e.impl_->expectations_.begin(); for( expectations_cit it = e.impl_->expectations_.begin();
it != e.impl_->expectations_.end(); ++it ) it != e.impl_->expectations_.end(); ++it )

View file

@ -28,8 +28,7 @@ namespace detail
virtual bool operator()( virtual bool operator()(
BOOST_PP_ENUM(MOCK_NUM_ARGS, MOCK_REF_ARG, _) ) = 0; BOOST_PP_ENUM(MOCK_NUM_ARGS, MOCK_REF_ARG, _) ) = 0;
friend std::ostream& operator<<( friend std::ostream& operator<<( std::ostream& s, const matcher_base& m )
std::ostream& s, const matcher_base& m )
{ {
m.serialize( s ); m.serialize( s );
return s; return s;

View file

@ -59,7 +59,11 @@ namespace detail
}; };
template< typename Signature, int n > template< typename Signature, int n >
using parameter = tuple_element< n, typename parameter_types<Signature>::type >; struct parameter
{
static_assert(n < function_arity<Signature>::value, "Function signature has not that many parameters");
using type = typename tuple_element< n, typename parameter_types<Signature>::type >::type;
};
template<typename T> template<typename T>
struct parameter_type; struct parameter_type;

View file

@ -29,11 +29,9 @@ namespace mock
{} {}
bool operator()( std::add_lvalue_reference_t< const Actual > actual ) bool operator()( std::add_lvalue_reference_t< const Actual > actual )
{ {
return mock::equal( return mock::equal( mock::unwrap_ref( expected_ ) ).c_( actual );
mock::detail::unwrap_ref( expected_ ) ).c_( actual );
} }
friend std::ostream& operator<<( friend std::ostream& operator<<( std::ostream& s, const matcher& m )
std::ostream& s, const matcher& m )
{ {
return s << mock::format( m.expected_ ); return s << mock::format( m.expected_ );
} }
@ -52,8 +50,7 @@ namespace mock
{ {
return std::strcmp( actual, expected_ ) == 0; return std::strcmp( actual, expected_ ) == 0;
} }
friend std::ostream& operator<<( friend std::ostream& operator<<( std::ostream& s, const matcher& m )
std::ostream& s, const matcher& m )
{ {
return s << mock::format( m.expected_ ); return s << mock::format( m.expected_ );
} }
@ -72,8 +69,7 @@ namespace mock
{ {
return c_( std::forward< typename detail::ref_arg< Actual >::type >( actual ) ); return c_( std::forward< typename detail::ref_arg< Actual >::type >( actual ) );
} }
friend std::ostream& operator<<( friend std::ostream& operator<<( std::ostream& s, const matcher& m )
std::ostream& s, const matcher& m )
{ {
return s << mock::format( m.c_ ); return s << mock::format( m.c_ );
} }
@ -96,8 +92,7 @@ namespace mock
{ {
return c_( std::forward< typename detail::ref_arg< Actual >::type >( actual ) ); return c_( std::forward< typename detail::ref_arg< Actual >::type >( actual ) );
} }
friend std::ostream& operator<<( friend std::ostream& operator<<( std::ostream& s, const matcher& m )
std::ostream& s, const matcher& m )
{ {
return s << mock::format( m.c_ ); return s << mock::format( m.c_ );
} }

View file

@ -48,7 +48,7 @@
mock::detail::functor< MOCK_FUNCTION_TYPE(__VA_ARGS__) > f, f##_mock mock::detail::functor< MOCK_FUNCTION_TYPE(__VA_ARGS__) > f, f##_mock
/// MOCK_FUNCTOR_TPL( name, signature ) /// MOCK_FUNCTOR_TPL( name, signature )
/// Deprecated. Same as MOCK_FUNCTOR /// Deprecated. Same as MOCK_FUNCTOR
#define MOCK_FUNCTOR_TPL(f, ...) MOCK_FUNCTOR(F, __VA_ARGS__) #define MOCK_FUNCTOR_TPL(f, ...) MOCK_FUNCTOR(f, __VA_ARGS__)
#define MOCK_HELPER(t) \ #define MOCK_HELPER(t) \
t##_mock( mock::detail::root, BOOST_PP_STRINGIZE(t) ) t##_mock( mock::detail::root, BOOST_PP_STRINGIZE(t) )

View file

@ -13,8 +13,6 @@
#include <type_traits> #include <type_traits>
namespace mock namespace mock
{
namespace detail
{ {
template<class T> template<class T>
struct unwrap_reference struct unwrap_reference
@ -40,6 +38,5 @@ namespace detail
return t; return t;
} }
} }
}
#endif // MOCK_UNWRAP_REFERENCE_HPP_INCLUDED #endif // MOCK_UNWRAP_REFERENCE_HPP_INCLUDED

View file

@ -30,6 +30,7 @@ elseif(MSVC)
endif() endif()
endif() endif()
# Regular unit tests in variations
file(GLOB_RECURSE testFiles test_*.cpp) file(GLOB_RECURSE testFiles test_*.cpp)
set(testsUsingUndefinedCPP test_function test_integration) set(testsUsingUndefinedCPP test_function test_integration)
foreach(testFile IN LISTS testFiles) foreach(testFile IN LISTS testFiles)
@ -52,10 +53,12 @@ foreach(testFile IN LISTS testFiles)
target_compile_definitions(${name}_thread_safe PRIVATE MOCK_THREAD_SAFE BOOST_THREAD_USES_MOVE) target_compile_definitions(${name}_thread_safe PRIVATE MOCK_THREAD_SAFE BOOST_THREAD_USES_MOVE)
endforeach() endforeach()
# Link test only to check for a regression
add_executable(link-test_defined EXCLUDE_FROM_ALL test_exception.cpp defined_1.cpp defined_2.cpp) add_executable(link-test_defined EXCLUDE_FROM_ALL test_exception.cpp defined_1.cpp defined_2.cpp)
target_link_libraries(link-test_defined PRIVATE turtle::turtle TurtleTestMain) target_link_libraries(link-test_defined PRIVATE turtle::turtle TurtleTestMain)
add_test(NAME link-test_defined COMMAND "${CMAKE_COMMAND}" --build ${CMAKE_BINARY_DIR} --target link-test_defined --config $<CONFIG>) add_test(NAME link-test_defined COMMAND "${CMAKE_COMMAND}" --build ${CMAKE_BINARY_DIR} --target link-test_defined --config $<CONFIG>)
# Should fail to compile
file(GLOB_RECURSE compileFailureTestFiles fail_*.cpp) file(GLOB_RECURSE compileFailureTestFiles fail_*.cpp)
foreach(testFile IN LISTS compileFailureTestFiles) foreach(testFile IN LISTS compileFailureTestFiles)
get_filename_component(name ${testFile} NAME_WE) get_filename_component(name ${testFile} NAME_WE)
@ -65,3 +68,34 @@ foreach(testFile IN LISTS compileFailureTestFiles)
add_test(NAME compile-${name} COMMAND "${CMAKE_COMMAND}" --build ${CMAKE_BINARY_DIR} --target ${name} --config $<CONFIG>) add_test(NAME compile-${name} COMMAND "${CMAKE_COMMAND}" --build ${CMAKE_BINARY_DIR} --target ${name} --config $<CONFIG>)
set_tests_properties(compile-${name} PROPERTIES WILL_FAIL TRUE) set_tests_properties(compile-${name} PROPERTIES WILL_FAIL TRUE)
endforeach() endforeach()
# Examples are runnable tests
file(GLOB_RECURSE exampleFiles ${PROJECT_SOURCE_DIR}/doc/example/*.cpp)
foreach(testFile IN LISTS exampleFiles)
get_filename_component(name ${testFile} NAME_WE)
set(name "example_${name}")
add_executable(${name} ${testFile})
target_link_libraries(${name} PRIVATE turtle::turtle TurtleTestMain)
add_test(NAME ${name} COMMAND ${name})
endforeach()
file(GLOB_RECURSE exampleTargetFiles ${PROJECT_SOURCE_DIR}/doc/example/*.hpp)
foreach(name IN ITEMS customization getting_started motivation rationale)
target_sources(example_${name} PUBLIC ${exampleTargetFiles})
endforeach()
# Expected to trigger a mock failure
set_tests_properties(example_rationale PROPERTIES WILL_FAIL TRUE PASS_REGULAR_EXPRESSION "Exception thrown but should not")
foreach(name IN ITEMS example_patterns_async_call)
target_link_libraries(${name} PRIVATE Boost::thread)
target_compile_definitions(${name} PRIVATE MOCK_THREAD_SAFE BOOST_THREAD_USES_MOVE)
endforeach()
# Compile benchmarks
file(GLOB_RECURSE benchFiles bench_*.cpp)
foreach(testFile IN LISTS benchFiles)
get_filename_component(name ${testFile} NAME_WE)
add_executable(${name} EXCLUDE_FROM_ALL ${testFile})
target_link_libraries(${name} PRIVATE turtle::turtle TurtleTestMain)
add_test(NAME ${name} COMMAND "${CMAKE_COMMAND}" --build ${CMAKE_BINARY_DIR} --target ${name} --config $<CONFIG>)
endforeach()

View file

@ -8,3 +8,8 @@
#define MOCK_MAX_ARGS 10 #define MOCK_MAX_ARGS 10
#include <turtle/mock.hpp> #include <turtle/mock.hpp>
int main()
{
return 0;
}

View file

@ -8,3 +8,8 @@
#define MOCK_MAX_ARGS 20 #define MOCK_MAX_ARGS 20
#include <turtle/mock.hpp> #include <turtle/mock.hpp>
int main()
{
return 0;
}

View file

@ -8,3 +8,8 @@
#define MOCK_MAX_ARGS 30 #define MOCK_MAX_ARGS 30
#include <turtle/mock.hpp> #include <turtle/mock.hpp>
int main()
{
return 0;
}

View file

@ -1132,3 +1132,8 @@ namespace
mock_class_29 c_29; mock_class_29 c_29;
mock_class_30 c_30; mock_class_30 c_30;
} }
int main()
{
return 0;
}

View file

@ -1071,3 +1071,8 @@ namespace
mock_class_29 c_29; mock_class_29 c_29;
mock_class_30 c_30; mock_class_30 c_30;
} }
int main()
{
return 0;
}

View file

@ -1072,3 +1072,8 @@ namespace
mock_class_29 c_29; mock_class_29 c_29;
mock_class_30 c_30; mock_class_30 c_30;
} }
int main()
{
return 0;
}

View file

@ -1072,3 +1072,8 @@ namespace
mock_class_29 c_29; mock_class_29 c_29;
mock_class_30 c_30; mock_class_30 c_30;
} }
int main()
{
return 0;
}

View file

@ -1072,3 +1072,8 @@ namespace
mock_class_29 c_29; mock_class_29 c_29;
mock_class_30 c_30; mock_class_30 c_30;
} }
int main()
{
return 0;
}

View file

@ -299,7 +299,7 @@ namespace
template< typename T > template< typename T >
struct tpl_functor_class struct tpl_functor_class
{ {
MOCK_FUNCTOR_TPL( f, void( T ) ); MOCK_FUNCTOR( f, void( T ) );
}; };
} }