From 5ef17d0e33c839c6dd6852db51ce268883e1d503 Mon Sep 17 00:00:00 2001 From: Alexander Grund Date: Sat, 11 Jul 2020 14:01:18 +0200 Subject: [PATCH] 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 --- doc/changelog.qbk | 3 + doc/customization.qbk | 2 +- doc/example/calculator.hpp | 7 +- doc/example/customization.cpp | 12 +- doc/example/getting_started.cpp | 102 +++++++++++++-- doc/example/limitations_comma_in_macro.cpp | 48 ------- .../limitations_const_parameter_warning.cpp | 10 +- doc/example/limitations_literal_zero.cpp | 1 - .../limitations_non_virtual_method.cpp | 8 +- .../limitations_protected_private_method.cpp | 11 +- ...limitations_template_base_class_method.cpp | 10 +- doc/example/limitations_template_method.cpp | 20 ++- doc/example/limitations_throw_specifier.cpp | 12 +- doc/example/motivation.cpp | 7 +- doc/example/patterns_async_call.cpp | 34 ++--- doc/example/patterns_invoke_functor.cpp | 19 ++- doc/example/patterns_quick_constraint.cpp | 1 - doc/example/patterns_retrieve_cref.cpp | 18 ++- doc/example/patterns_static_objects.cpp | 10 +- doc/example/rationale.cpp | 13 ++ doc/example/reference.cpp | 123 +++++++++--------- doc/limitations.qbk | 38 ------ doc/reference.qbk | 34 +---- include/turtle/constraint.hpp | 8 +- include/turtle/constraints.hpp | 2 +- .../turtle/detail/expectation_template.hpp | 3 +- .../turtle/detail/function_impl_template.hpp | 24 ++-- .../turtle/detail/matcher_base_template.hpp | 3 +- include/turtle/detail/parameter.hpp | 6 +- include/turtle/matcher.hpp | 15 +-- include/turtle/mock.hpp | 2 +- .../turtle/{detail => }/unwrap_reference.hpp | 3 - test/CMakeLists.txt | 34 +++++ test/bench_0_class_10_max_args.cpp | 5 + test/bench_0_class_20_max_args.cpp | 5 + test/bench_0_class_30_max_args.cpp | 5 + ...classes_30_methods_30_args_30_max_args.cpp | 5 + test/bench_30_classes_30_methods_9_args.cpp | 5 + ..._classes_30_methods_9_args_10_max_args.cpp | 5 + ..._classes_30_methods_9_args_20_max_args.cpp | 5 + ..._classes_30_methods_9_args_30_max_args.cpp | 5 + test/test_mock.cpp | 2 +- 42 files changed, 400 insertions(+), 285 deletions(-) delete mode 100644 doc/example/limitations_comma_in_macro.cpp rename include/turtle/{detail => }/unwrap_reference.hpp (97%) diff --git a/doc/changelog.qbk b/doc/changelog.qbk index 9b5700d..20c3d4c 100644 --- a/doc/changelog.qbk +++ b/doc/changelog.qbk @@ -11,6 +11,9 @@ Released - * 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] diff --git a/doc/customization.qbk b/doc/customization.qbk index 577ed88..6946cff 100644 --- a/doc/customization.qbk +++ b/doc/customization.qbk @@ -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 * 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] diff --git a/doc/example/calculator.hpp b/doc/example/calculator.hpp index 23aff87..13c83cd 100644 --- a/doc/example/calculator.hpp +++ b/doc/example/calculator.hpp @@ -9,15 +9,16 @@ #ifndef CALCULATOR #define CALCULATOR -class view; +#include "view.hpp" //[ calculator class calculator { + view& v; 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' }; //] diff --git a/doc/example/customization.cpp b/doc/example/customization.cpp index 78283a3..ddc5324 100644 --- a/doc/example/customization.cpp +++ b/doc/example/customization.cpp @@ -12,6 +12,7 @@ //] #include "calculator.hpp" #include "mock_view.hpp" +#include //[ mock_stream_user_type namespace user_namespace @@ -36,7 +37,7 @@ bool custom_constraint( int actual ) //] //[ 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; calculator c( v ); @@ -64,7 +65,7 @@ struct custom_constraint //] //[ 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; calculator c( v ); @@ -86,8 +87,7 @@ struct near_constraint template< typename Actual > bool operator()( Actual actual ) const { - return std::abs( actual - unwrap_ref( expected_ ) ) - < unwrap_ref( threshold_ ); + return std::abs( actual - expected_ ) < threshold_ ; } 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 { //[ 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; 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 { //[ 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; calculator c( v ); diff --git a/doc/example/getting_started.cpp b/doc/example/getting_started.cpp index ff732c4..140a8a4 100644 --- a/doc/example/getting_started.cpp +++ b/doc/example/getting_started.cpp @@ -6,14 +6,69 @@ // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) +#include +#include +#include + +std::function error_handler_abort; +std::function error_handler_pass; +std::function error_handler_call; +std::function 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 -#define BOOST_AUTO_TEST_MAIN #include #include //] #include "calculator.hpp" #include "mock_view.hpp" +struct Fixture +{ + Fixture() + { + error_handler_abort = mock::error::abort; + error_handler_pass = mock::error::pass; + error_handler_call = mock::error::call; + error_handler_fail = mock::error::fail; + } +}; + +BOOST_FIXTURE_TEST_SUITE(GettingStarted, Fixture) + namespace phases { //[ phases @@ -30,7 +85,7 @@ BOOST_AUTO_TEST_CASE( zero_plus_zero_is_zero ) namespace 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; calculator c( v ); @@ -49,7 +104,7 @@ BOOST_AUTO_TEST_CASE( zero_plus_zero_is_zero ) namespace expectations { //[ expectations -BOOST_AUTO_TEST_CASE( zero_plus_zero_is_zero ) +BOOST_AUTO_TEST_CASE( zero_plus_zero_is_zero_expect ) { mock_view v; calculator c( v ); @@ -63,7 +118,7 @@ BOOST_AUTO_TEST_CASE( zero_plus_zero_is_zero ) namespace 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; calculator c( v ); @@ -79,7 +134,7 @@ BOOST_AUTO_TEST_CASE( zero_plus_zero_is_zero ) namespace 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; calculator c( v ); @@ -112,18 +167,49 @@ MOCK_BASE_CLASS( mock_view, view ) class calculator { + view& v; 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 -BOOST_AUTO_TEST_CASE( zero_plus_zero_is_zero ) +BOOST_FIXTURE_TEST_CASE( zero_plus_zero_is_zero_with_action, CatchFailureFixture ) { mock_view v; calculator c( v ); MOCK_EXPECT( v.display ).once().with( 0 ); // missing returns( true ) c.add( 0, 0 ); + assert_failure("missing action"); } //] } + +BOOST_AUTO_TEST_SUITE_END() diff --git a/doc/example/limitations_comma_in_macro.cpp b/doc/example/limitations_comma_in_macro.cpp deleted file mode 100644 index c19ebdf..0000000 --- a/doc/example/limitations_comma_in_macro.cpp +++ /dev/null @@ -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 -#include - -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 - {}; -//] -} diff --git a/doc/example/limitations_const_parameter_warning.cpp b/doc/example/limitations_const_parameter_warning.cpp index 531bba2..049c123 100644 --- a/doc/example/limitations_const_parameter_warning.cpp +++ b/doc/example/limitations_const_parameter_warning.cpp @@ -6,7 +6,6 @@ // (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 @@ -35,7 +34,7 @@ namespace limitations_const_parameter_warning_explanation //] } -namespace limitations_const_parameter_warning_solution +namespace { //[ limitations_const_parameter_warning_solution 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(&b)->method(1); +} diff --git a/doc/example/limitations_literal_zero.cpp b/doc/example/limitations_literal_zero.cpp index 895f4f5..81ba680 100644 --- a/doc/example/limitations_literal_zero.cpp +++ b/doc/example/limitations_literal_zero.cpp @@ -6,7 +6,6 @@ // (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 diff --git a/doc/example/limitations_non_virtual_method.cpp b/doc/example/limitations_non_virtual_method.cpp index b6f0457..e5fd30e 100644 --- a/doc/example/limitations_non_virtual_method.cpp +++ b/doc/example/limitations_non_virtual_method.cpp @@ -6,7 +6,6 @@ // (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 @@ -25,3 +24,10 @@ MOCK_BASE_CLASS( mock_base, base ) MOCK_METHOD( method, 0 ) }; //] + +BOOST_AUTO_TEST_CASE(method_not_called_through_base) +{ + mock_base b; + MOCK_EXPECT(b.method).never(); + static_cast(&b)->method(); // Doesn't call the mocked method +} diff --git a/doc/example/limitations_protected_private_method.cpp b/doc/example/limitations_protected_private_method.cpp index a3a23f3..ca621a8 100644 --- a/doc/example/limitations_protected_private_method.cpp +++ b/doc/example/limitations_protected_private_method.cpp @@ -6,7 +6,6 @@ // (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 @@ -15,6 +14,8 @@ namespace //[ limitations_protected_private_method_problem class base { + public: + void call(){ method_1(); method_2(); } protected: virtual void method_1() = 0; 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(&b)->call(); +} diff --git a/doc/example/limitations_template_base_class_method.cpp b/doc/example/limitations_template_base_class_method.cpp index b847f68..bbbeb4d 100644 --- a/doc/example/limitations_template_base_class_method.cpp +++ b/doc/example/limitations_template_base_class_method.cpp @@ -6,7 +6,6 @@ // (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 @@ -27,7 +26,14 @@ namespace template< typename 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 b; + MOCK_EXPECT(b.method).once(); + static_cast*>(&b)->method(); +} diff --git a/doc/example/limitations_template_method.cpp b/doc/example/limitations_template_method.cpp index c5c0fa7..f955e80 100644 --- a/doc/example/limitations_template_method.cpp +++ b/doc/example/limitations_template_method.cpp @@ -6,7 +6,6 @@ // (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 @@ -17,8 +16,7 @@ class concept { public: template< typename T > - void method( T t ) - {} + void method( T t ); }; template< typename T > @@ -36,6 +34,14 @@ MOCK_CLASS( mock_concept ) 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 @@ -80,4 +86,12 @@ std::string mock_concept::create< std::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); +} } diff --git a/doc/example/limitations_throw_specifier.cpp b/doc/example/limitations_throw_specifier.cpp index 77b44c8..cccaf58 100644 --- a/doc/example/limitations_throw_specifier.cpp +++ b/doc/example/limitations_throw_specifier.cpp @@ -6,7 +6,6 @@ // (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 @@ -17,14 +16,14 @@ namespace { virtual ~base_class() = default; - virtual void method() throw (); + virtual void method() throw() = 0; }; //] //[ limitations_throw_specifier_solution MOCK_BASE_CLASS( mock_class, base_class ) { - void method() throw () + void method() throw() override { method_proxy(); } @@ -32,3 +31,10 @@ namespace }; //] } + +BOOST_AUTO_TEST_CASE(call_method_proxy) +{ + mock_class b; + MOCK_EXPECT(b.method).once(); + static_cast(&b)->method(); +} diff --git a/doc/example/motivation.cpp b/doc/example/motivation.cpp index 9aef368..614d300 100644 --- a/doc/example/motivation.cpp +++ b/doc/example/motivation.cpp @@ -6,7 +6,6 @@ // (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 #include "calculator.hpp" @@ -22,6 +21,8 @@ public: }; //] +int calculator::add( int a, int b ){ return a + b; } + //[ simple_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 -BOOST_AUTO_TEST_CASE( zero_plus_zero_is_zero ) +BOOST_AUTO_TEST_CASE( zero_plus_zero_is_zero_without_mock_object ) { my_view v; calculator c( v ); @@ -65,7 +66,7 @@ BOOST_AUTO_TEST_CASE( zero_plus_zero_is_zero ) namespace 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; calculator c( v ); diff --git a/doc/example/patterns_async_call.cpp b/doc/example/patterns_async_call.cpp index 918c5d4..2fd3834 100644 --- a/doc/example/patterns_async_call.cpp +++ b/doc/example/patterns_async_call.cpp @@ -7,7 +7,7 @@ // http://www.boost.org/LICENSE_1_0.txt) //[ async_call_problem -namespace +namespace mock_test { class base_class { @@ -17,6 +17,7 @@ namespace class my_class { + base_class& b; public: 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 -#define BOOST_AUTO_TEST_MAIN #include -#include #include #include -namespace +namespace mock_test { template< typename F > void check( bool& condition, F flush, int attempts = 100, int sleep = 100 ) @@ -49,25 +59,15 @@ namespace { MOCK_METHOD( method, 0 ) }; - void set_bool(bool& b) - { - b = true; - } } BOOST_AUTO_TEST_CASE( method_is_called ) { + using namespace mock_test; mock_base_class m; my_class c( m ); bool done = false; - // when method is called it will set done to true - // Note: Boost 1.57 introduced a bug preventing usage of the lambda with clang in C++98 - // 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 + MOCK_EXPECT( m.method ).once().calls( [&done](){ done = true; } ); + check( done, [&c](){ c.flush(); } ); // just wait on done, flushing from time to time } //] diff --git a/doc/example/patterns_invoke_functor.cpp b/doc/example/patterns_invoke_functor.cpp index 5a00f4a..e9f6655 100644 --- a/doc/example/patterns_invoke_functor.cpp +++ b/doc/example/patterns_invoke_functor.cpp @@ -9,8 +9,6 @@ //[ invoke_functor_problem #include -namespace -{ class base_class { public: @@ -18,14 +16,24 @@ namespace }; 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 -#define BOOST_AUTO_TEST_MAIN #include #include -#include 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_EXPECT( mock.method ).calls( [](const auto &functor){ functor(42); } ); // whenever 'method' is called, invoke the functor with 42 function( mock ); + BOOST_CHECK(receivedValue == 42); } //] diff --git a/doc/example/patterns_quick_constraint.cpp b/doc/example/patterns_quick_constraint.cpp index a331bdc..f1ae03b 100644 --- a/doc/example/patterns_quick_constraint.cpp +++ b/doc/example/patterns_quick_constraint.cpp @@ -7,7 +7,6 @@ // http://www.boost.org/LICENSE_1_0.txt) //[ quick_constraint_problem -#define BOOST_AUTO_TEST_MAIN #include #include #include diff --git a/doc/example/patterns_retrieve_cref.cpp b/doc/example/patterns_retrieve_cref.cpp index 0b5aace..16f5a07 100644 --- a/doc/example/patterns_retrieve_cref.cpp +++ b/doc/example/patterns_retrieve_cref.cpp @@ -7,7 +7,7 @@ // http://www.boost.org/LICENSE_1_0.txt) //[ retrieve_cref_problem -namespace +namespace mock_test { class base_class { @@ -17,6 +17,7 @@ namespace class my_class { + base_class& b; public: 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 -#define BOOST_AUTO_TEST_MAIN #include #include -namespace +namespace mock_test { 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 ) { + using namespace mock_test; mock_base_class mock; my_class c( mock ); int value; diff --git a/doc/example/patterns_static_objects.cpp b/doc/example/patterns_static_objects.cpp index c385fbc..6d47362 100644 --- a/doc/example/patterns_static_objects.cpp +++ b/doc/example/patterns_static_objects.cpp @@ -6,8 +6,10 @@ // (See accompanying file LICENSE_1_0.txt or copy at // 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 -#define BOOST_AUTO_TEST_MAIN #include #include #include @@ -16,8 +18,7 @@ namespace { struct my_class { - my_class( int i ) - : i_( i ) + my_class( int i ) : i_( i ) {} int i_; @@ -28,13 +29,14 @@ namespace 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 ) { 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' + 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 //] diff --git a/doc/example/rationale.cpp b/doc/example/rationale.cpp index 170e7e7..9ece937 100644 --- a/doc/example/rationale.cpp +++ b/doc/example/rationale.cpp @@ -9,6 +9,19 @@ #include #include "calculator.hpp" #include "mock_view.hpp" +#include +#include +#include +#include + +// 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 BOOST_AUTO_TEST_CASE( overflow_throws ) diff --git a/doc/example/reference.cpp b/doc/example/reference.cpp index 2c6d7e8..97762a3 100644 --- a/doc/example/reference.cpp +++ b/doc/example/reference.cpp @@ -6,7 +6,6 @@ // (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 @@ -374,10 +373,11 @@ MOCK_CLASS( mock_class ) namespace 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 ) { + MOCK_EXPECT(f).once().with(3); f( 3 ); } //] @@ -398,6 +398,7 @@ namespace functor_example_1 BOOST_AUTO_TEST_CASE( demonstrates_instantiating_a_mock_functor ) { MOCK_FUNCTOR( f, void( int ) ); + MOCK_EXPECT(f).once().with(3); f( 3 ); } //] @@ -409,12 +410,13 @@ namespace functor_example_2 template< typename T > 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_EXPECT(c.f).once().with(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.method2 ).never().with( "ok", mock::any ); 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_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 ) { mock_class c; 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_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 ) { MOCK_EXPECT( f ).once(); + f(42); } //] } @@ -485,14 +497,17 @@ namespace invocation_example_4 //[ invocation_example_4 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 ) { mock_class c; - MOCK_EXPECT( c.method ).once(); - MOCK_EXPECT( mock_class::method ).once(); // does the same + MOCK_EXPECT( c.method1 ).once(); + 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 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 ) { mock_class c; - MOCK_EXPECT( c.method ).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.method1 ).with( mock::equal( 3 ), mock::equal( "some string" ) ); + 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_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_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; } -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; + using namespace std::placeholders; 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_EXPECT( c.method ).with( boost::lambda::_1 == 42 ); + c.method(42); } //] } @@ -606,14 +629,17 @@ namespace constraints_example_6 //[ constraints_example_6 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 ) { mock_class c; - MOCK_EXPECT( c.method ).with( boost::phoenix::arg_names::arg1 == 42 ); - MOCK_EXPECT( c.method ).with( boost::phoenix::arg_names::_1 == 42 ); + MOCK_EXPECT( c.method1 ).with( boost::phoenix::arg_names::arg1 == 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_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_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_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_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 + 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 ) { mock_class c; - MOCK_EXPECT( c.method ).returns( 42 ); - MOCK_EXPECT( c.method ).moves( 42 ); // returns by moving the value - MOCK_EXPECT( c.method ).throws( std::runtime_error( "error !" ) ); - MOCK_EXPECT( c.method ).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 ).calls( []( int i ) { return i; } ); // uses a C++11 lambda + MOCK_EXPECT( c.method ).once().returns( 42 ); + MOCK_EXPECT( c.method ).once().moves( 42 ); // returns by moving the value + MOCK_EXPECT( c.method ).once().throws( std::runtime_error( "error !" ) ); + MOCK_EXPECT( c.method ).once().calls( &function ); // forwards 'method' 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 ).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 ) ); -} -//] -} diff --git a/doc/limitations.qbk b/doc/limitations.qbk index 46926f0..f4bce36 100644 --- a/doc/limitations.qbk +++ b/doc/limitations.qbk @@ -12,7 +12,6 @@ [import example/limitations_template_base_class_method.cpp] [import example/limitations_template_method.cpp] [import example/limitations_protected_private_method.cpp] -[import example/limitations_comma_in_macro.cpp] [import example/limitations_const_parameter_warning.cpp] This section lists the library known limitations. @@ -151,43 +150,6 @@ A workaround would be to write a proxy member function : [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] Example : diff --git a/doc/reference.qbk b/doc/reference.qbk index 434a630..dacce89 100644 --- a/doc/reference.qbk +++ b/doc/reference.qbk @@ -105,8 +105,6 @@ Synopsis : [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 : 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.] -[warning For compilers without support for variadic macros the identifier cannot be omitted and must be given explicitly.] - Example : [static_member_function_example_1] @@ -277,8 +273,6 @@ Synopsis : [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 : [function_example_1] @@ -415,13 +409,13 @@ Constraints : [[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.] [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.] @@ -437,7 +431,7 @@ Example using a standard library functor : [constraints_example_3] -Example using [@http://www.boost.org/libs/bind Boost.Bind] : +Example using std::bind : [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 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 : @@ -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], ... -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 : [helpers_example_1] -or with the alternate more portable macro : - -[helpers_example_4] - Example with one extra argument : [helpers_example_2] -or with the alternate more portable macro : - -[helpers_example_5] - Example with two extra arguments : [helpers_example_3] -or with the alternate more portable macro : - -[helpers_example_6] - [endsect] [endsect] diff --git a/include/turtle/constraint.hpp b/include/turtle/constraint.hpp index b739239..4708cf8 100644 --- a/include/turtle/constraint.hpp +++ b/include/turtle/constraint.hpp @@ -11,7 +11,7 @@ #include "config.hpp" #include "log.hpp" -#include "detail/unwrap_reference.hpp" +#include "unwrap_reference.hpp" #include #include #include @@ -135,7 +135,7 @@ namespace detail template< typename Actual > \ bool operator()( const Actual& actual ) const \ { \ - return Expr; \ + (void) actual; return Expr; \ } \ friend std::ostream& operator<<( std::ostream& s, const Name& ) \ { \ @@ -149,7 +149,7 @@ namespace detail expected##n( std::forward< T##n >(e##n) ) #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) \ BOOST_PP_IF(n, << ", " <<,) mock::format( c.expected##n ) @@ -161,7 +161,7 @@ namespace detail std::decay_t< const T##n > #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) #define MOCK_CONSTRAINT_ARG(z, n, Args) \ diff --git a/include/turtle/constraints.hpp b/include/turtle/constraints.hpp index 97f72fc..0c679b7 100644 --- a/include/turtle/constraints.hpp +++ b/include/turtle/constraints.hpp @@ -12,7 +12,7 @@ #include "config.hpp" #include "constraint.hpp" #include "detail/move_helper.hpp" -#include "detail/unwrap_reference.hpp" +#include "unwrap_reference.hpp" #include #include #if BOOST_VERSION >= 107000 diff --git a/include/turtle/detail/expectation_template.hpp b/include/turtle/detail/expectation_template.hpp index ef8a562..1791e0f 100644 --- a/include/turtle/detail/expectation_template.hpp +++ b/include/turtle/detail/expectation_template.hpp @@ -240,8 +240,7 @@ namespace detail return line_; } - friend std::ostream& operator<<( - std::ostream& s, const expectation& e ) + friend std::ostream& operator<<( std::ostream& s, const expectation& e ) { return s << ( e.invocation_->exhausted() ? 'v' : '.' ) << ' ' << *e.invocation_ diff --git a/include/turtle/detail/function_impl_template.hpp b/include/turtle/detail/function_impl_template.hpp index 2cf73cb..708e122 100644 --- a/include/turtle/detail/function_impl_template.hpp +++ b/include/turtle/detail/function_impl_template.hpp @@ -129,26 +129,22 @@ namespace detail } wrapper& exactly( std::size_t count ) { - this->e_->invoke( - std::make_shared< detail::exactly >( count ) ); + this->e_->invoke( std::make_shared< detail::exactly >( count ) ); return *this; } wrapper& at_least( std::size_t min ) { - this->e_->invoke( - std::make_shared< detail::at_least >( min ) ); + this->e_->invoke( std::make_shared< detail::at_least >( min ) ); return *this; } wrapper& at_most( std::size_t max ) { - this->e_->invoke( - std::make_shared< detail::at_most >( max ) ); + this->e_->invoke( std::make_shared< detail::at_most >( max ) ); return *this; } wrapper& between( std::size_t min, std::size_t max ) { - this->e_->invoke( - std::make_shared< detail::between >( min, max ) ); + this->e_->invoke( std::make_shared< detail::between >( min, max ) ); return *this; } @@ -250,8 +246,7 @@ namespace detail return error_type::abort(); } valid_ = true; - error_type::call( - MOCK_FUNCTION_CONTEXT, it->file(), it->line() ); + error_type::call( MOCK_FUNCTION_CONTEXT, it->file(), it->line() ); if( it->functor() ) return it->functor()( BOOST_PP_ENUM(MOCK_NUM_ARGS, MOCK_MOVE, _) ); @@ -273,8 +268,7 @@ namespace detail context_ = &c; } - friend std::ostream& operator<<( - std::ostream& s, const function_impl& impl ) + friend std::ostream& operator<<( std::ostream& s, const function_impl& impl ) { lock _( impl.mutex_ ); return s << lazy_context( &impl ) << lazy_expectations( &impl ); @@ -285,8 +279,7 @@ namespace detail lazy_context( const function_impl* impl ) : impl_( impl ) {} - friend std::ostream& operator<<( - std::ostream& s, const lazy_context& c ) + friend std::ostream& operator<<( std::ostream& s, const lazy_context& c ) { if( c.impl_->context_ ) c.impl_->context_->serialize( s, *c.impl_ ); @@ -302,8 +295,7 @@ namespace detail lazy_expectations( const function_impl* impl ) : impl_( impl ) {} - friend std::ostream& operator<<( - std::ostream& s, const lazy_expectations& e ) + friend std::ostream& operator<<( std::ostream& s, const lazy_expectations& e ) { for( expectations_cit it = e.impl_->expectations_.begin(); it != e.impl_->expectations_.end(); ++it ) diff --git a/include/turtle/detail/matcher_base_template.hpp b/include/turtle/detail/matcher_base_template.hpp index 2de909e..931b8e9 100644 --- a/include/turtle/detail/matcher_base_template.hpp +++ b/include/turtle/detail/matcher_base_template.hpp @@ -28,8 +28,7 @@ namespace detail virtual bool operator()( BOOST_PP_ENUM(MOCK_NUM_ARGS, MOCK_REF_ARG, _) ) = 0; - friend std::ostream& operator<<( - std::ostream& s, const matcher_base& m ) + friend std::ostream& operator<<( std::ostream& s, const matcher_base& m ) { m.serialize( s ); return s; diff --git a/include/turtle/detail/parameter.hpp b/include/turtle/detail/parameter.hpp index 6c2442c..b37ce58 100644 --- a/include/turtle/detail/parameter.hpp +++ b/include/turtle/detail/parameter.hpp @@ -59,7 +59,11 @@ namespace detail }; template< typename Signature, int n > - using parameter = tuple_element< n, typename parameter_types::type >; + struct parameter + { + static_assert(n < function_arity::value, "Function signature has not that many parameters"); + using type = typename tuple_element< n, typename parameter_types::type >::type; + }; template struct parameter_type; diff --git a/include/turtle/matcher.hpp b/include/turtle/matcher.hpp index e96a970..f6dbd7d 100644 --- a/include/turtle/matcher.hpp +++ b/include/turtle/matcher.hpp @@ -29,11 +29,9 @@ namespace mock {} bool operator()( std::add_lvalue_reference_t< const Actual > actual ) { - return mock::equal( - mock::detail::unwrap_ref( expected_ ) ).c_( actual ); + return mock::equal( mock::unwrap_ref( expected_ ) ).c_( actual ); } - friend std::ostream& operator<<( - std::ostream& s, const matcher& m ) + friend std::ostream& operator<<( std::ostream& s, const matcher& m ) { return s << mock::format( m.expected_ ); } @@ -52,8 +50,7 @@ namespace mock { return std::strcmp( actual, expected_ ) == 0; } - friend std::ostream& operator<<( - std::ostream& s, const matcher& m ) + friend std::ostream& operator<<( std::ostream& s, const matcher& m ) { return s << mock::format( m.expected_ ); } @@ -72,8 +69,7 @@ namespace mock { return c_( std::forward< typename detail::ref_arg< Actual >::type >( actual ) ); } - friend std::ostream& operator<<( - std::ostream& s, const matcher& m ) + friend std::ostream& operator<<( std::ostream& s, const matcher& m ) { return s << mock::format( m.c_ ); } @@ -96,8 +92,7 @@ namespace mock { return c_( std::forward< typename detail::ref_arg< Actual >::type >( actual ) ); } - friend std::ostream& operator<<( - std::ostream& s, const matcher& m ) + friend std::ostream& operator<<( std::ostream& s, const matcher& m ) { return s << mock::format( m.c_ ); } diff --git a/include/turtle/mock.hpp b/include/turtle/mock.hpp index bce7640..a5c8052 100644 --- a/include/turtle/mock.hpp +++ b/include/turtle/mock.hpp @@ -48,7 +48,7 @@ mock::detail::functor< MOCK_FUNCTION_TYPE(__VA_ARGS__) > f, f##_mock /// MOCK_FUNCTOR_TPL( name, signature ) /// 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) \ t##_mock( mock::detail::root, BOOST_PP_STRINGIZE(t) ) diff --git a/include/turtle/detail/unwrap_reference.hpp b/include/turtle/unwrap_reference.hpp similarity index 97% rename from include/turtle/detail/unwrap_reference.hpp rename to include/turtle/unwrap_reference.hpp index 376744f..b450cff 100644 --- a/include/turtle/detail/unwrap_reference.hpp +++ b/include/turtle/unwrap_reference.hpp @@ -13,8 +13,6 @@ #include namespace mock -{ -namespace detail { template struct unwrap_reference @@ -40,6 +38,5 @@ namespace detail return t; } } -} #endif // MOCK_UNWRAP_REFERENCE_HPP_INCLUDED diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 53d0b4a..0b68c99 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -30,6 +30,7 @@ elseif(MSVC) endif() endif() +# Regular unit tests in variations file(GLOB_RECURSE testFiles test_*.cpp) set(testsUsingUndefinedCPP test_function test_integration) 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) 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) 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 $) +# Should fail to compile file(GLOB_RECURSE compileFailureTestFiles fail_*.cpp) foreach(testFile IN LISTS compileFailureTestFiles) 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 $) set_tests_properties(compile-${name} PROPERTIES WILL_FAIL TRUE) 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 $) +endforeach() \ No newline at end of file diff --git a/test/bench_0_class_10_max_args.cpp b/test/bench_0_class_10_max_args.cpp index 0772e7d..99fb400 100644 --- a/test/bench_0_class_10_max_args.cpp +++ b/test/bench_0_class_10_max_args.cpp @@ -8,3 +8,8 @@ #define MOCK_MAX_ARGS 10 #include + +int main() +{ + return 0; +} diff --git a/test/bench_0_class_20_max_args.cpp b/test/bench_0_class_20_max_args.cpp index b236e09..1a52cd5 100644 --- a/test/bench_0_class_20_max_args.cpp +++ b/test/bench_0_class_20_max_args.cpp @@ -8,3 +8,8 @@ #define MOCK_MAX_ARGS 20 #include + +int main() +{ + return 0; +} diff --git a/test/bench_0_class_30_max_args.cpp b/test/bench_0_class_30_max_args.cpp index d87d02f..3eab294 100644 --- a/test/bench_0_class_30_max_args.cpp +++ b/test/bench_0_class_30_max_args.cpp @@ -8,3 +8,8 @@ #define MOCK_MAX_ARGS 30 #include + +int main() +{ + return 0; +} diff --git a/test/bench_30_classes_30_methods_30_args_30_max_args.cpp b/test/bench_30_classes_30_methods_30_args_30_max_args.cpp index d659f6c..021d95b 100644 --- a/test/bench_30_classes_30_methods_30_args_30_max_args.cpp +++ b/test/bench_30_classes_30_methods_30_args_30_max_args.cpp @@ -1132,3 +1132,8 @@ namespace mock_class_29 c_29; mock_class_30 c_30; } + +int main() +{ + return 0; +} diff --git a/test/bench_30_classes_30_methods_9_args.cpp b/test/bench_30_classes_30_methods_9_args.cpp index beb45bf..17c5a52 100644 --- a/test/bench_30_classes_30_methods_9_args.cpp +++ b/test/bench_30_classes_30_methods_9_args.cpp @@ -1071,3 +1071,8 @@ namespace mock_class_29 c_29; mock_class_30 c_30; } + +int main() +{ + return 0; +} diff --git a/test/bench_30_classes_30_methods_9_args_10_max_args.cpp b/test/bench_30_classes_30_methods_9_args_10_max_args.cpp index 20dad20..6a8023c 100644 --- a/test/bench_30_classes_30_methods_9_args_10_max_args.cpp +++ b/test/bench_30_classes_30_methods_9_args_10_max_args.cpp @@ -1072,3 +1072,8 @@ namespace mock_class_29 c_29; mock_class_30 c_30; } + +int main() +{ + return 0; +} diff --git a/test/bench_30_classes_30_methods_9_args_20_max_args.cpp b/test/bench_30_classes_30_methods_9_args_20_max_args.cpp index e720691..c36c91b 100644 --- a/test/bench_30_classes_30_methods_9_args_20_max_args.cpp +++ b/test/bench_30_classes_30_methods_9_args_20_max_args.cpp @@ -1072,3 +1072,8 @@ namespace mock_class_29 c_29; mock_class_30 c_30; } + +int main() +{ + return 0; +} diff --git a/test/bench_30_classes_30_methods_9_args_30_max_args.cpp b/test/bench_30_classes_30_methods_9_args_30_max_args.cpp index 68096ed..c9c4be2 100644 --- a/test/bench_30_classes_30_methods_9_args_30_max_args.cpp +++ b/test/bench_30_classes_30_methods_9_args_30_max_args.cpp @@ -1072,3 +1072,8 @@ namespace mock_class_29 c_29; mock_class_30 c_30; } + +int main() +{ + return 0; +} diff --git a/test/test_mock.cpp b/test/test_mock.cpp index 97adaef..3fb9397 100644 --- a/test/test_mock.cpp +++ b/test/test_mock.cpp @@ -299,7 +299,7 @@ namespace template< typename T > struct tpl_functor_class { - MOCK_FUNCTOR_TPL( f, void( T ) ); + MOCK_FUNCTOR( f, void( T ) ); }; }