diff --git a/include/fakeit/StubbingProgress.hpp b/include/fakeit/StubbingProgress.hpp index 6e025594..0cfe3757 100644 --- a/include/fakeit/StubbingProgress.hpp +++ b/include/fakeit/StubbingProgress.hpp @@ -71,40 +71,62 @@ namespace fakeit { return Do([&r](const typename fakeit::test_arg::type...) -> R { return r; }); } - template + // The std::enable_if is only there to disambiguate with the deprecated version of .Return(val), and + // can be removed once that deprecated version is removed. + template ::value, bool>::type = true> MethodStubbingProgress& Return(fk_remove_cvref_t&& r) { - static_assert(sizeof(U) != sizeof(U), "Return() cannot take an rvalue references for functions returning a reference because it would make it dangling, use ReturnCapture() instead."); + static_assert(sizeof(U) != sizeof(U), "Return() cannot take an rvalue references for functions returning a reference because it would make it dangling, use ReturnValCapt() instead."); return Return(r); // Only written to silence warning about not returning from a non-void function, but will never be executed. } void AlwaysReturn(const R &r) { - return AlwaysDo([&r](const typename fakeit::test_arg::type...) -> R { return r; }); + AlwaysDo([&r](const typename fakeit::test_arg::type...) -> R { return r; }); } - template + // The std::enable_if is only there to disambiguate with the deprecated version of .AlwaysReturn(val), and + // can be removed once that deprecated version is removed. + template ::value, bool>::type = true> void AlwaysReturn(fk_remove_cvref_t&&) { - static_assert(sizeof(U) != sizeof(U), "AlwaysReturn() cannot take an rvalue references for functions returning a reference because it would make it dangling, use AlwaysReturnCapture() instead."); + static_assert(sizeof(U) != sizeof(U), "AlwaysReturn() cannot take an rvalue references for functions returning a reference because it would make it dangling, use AlwaysReturnValCapt() instead."); } - template - MethodStubbingProgress& ReturnCapture(T&& r) { - static_assert(std::is_constructible&, fk_remove_cvref_t&>::value, - "The type captured by ReturnCapture() (named T) must be compatible with the return type of the function (named R), i.e. T t{...}; R& r = t; must compile without creating temporaries."); - auto store = std::make_shared>(std::forward(r)); + template + MethodStubbingProgress& ReturnValCapt(T&& r) { + // If a ref to T can be cast to a ref to R, then store T. + // Otherwise, create an object R constructed from the received T and store it. + using StoredType = typename std::conditional< + std::is_constructible&, fk_remove_cvref_t&>::value, + fk_remove_cvref_t, + fk_remove_cvref_t>::type; + auto store = std::make_shared(std::forward(r)); return Do([store](const typename fakeit::test_arg::type...) mutable -> R { return std::forward(*store); }); } - template - void AlwaysReturnCapture(T&& r) { - static_assert(std::is_constructible&, fk_remove_cvref_t&>::value, - "The type captured by AlwaysReturnCapture() (named T) must be compatible with the return type of the function (named R), i.e. T t{...}; R& r = t; must compile without creating temporaries."); - auto store = std::make_shared>(std::forward(r)); - return AlwaysDo([store](const typename fakeit::test_arg::type...) mutable -> R { + template + void AlwaysReturnValCapt(T&& r) { + // If a ref to T can be cast to a ref to R, then store T. + // Otherwise, create an object R constructed from the received T and store it. + using StoredType = typename std::conditional< + std::is_constructible&, fk_remove_cvref_t&>::value, + fk_remove_cvref_t, + fk_remove_cvref_t>::type; + auto store = std::make_shared(std::forward(r)); + AlwaysDo([store](const typename fakeit::test_arg::type...) mutable -> R { return std::forward(*store); }); } + + template + MethodStubbingProgress& ReturnRefCapt(T&& r) { + return Return(std::forward(r)); + } + + template + void AlwaysReturnRefCapt(T&& r) { + AlwaysReturn(std::forward(r)); + } }; // If R is not a reference. @@ -125,7 +147,31 @@ namespace fakeit { } void AlwaysReturn(const R &r) { - return AlwaysDo([r](const typename fakeit::test_arg::type...) -> R { return r; }); + AlwaysDo([r](const typename fakeit::test_arg::type...) -> R { return r; }); + } + + MethodStubbingProgress& ReturnValCapt(const R& r) { + return Return(r); + } + + MethodStubbingProgress& ReturnValCapt(R&& r) { + return Return(std::move(r)); + } + + void AlwaysReturnValCapt(const R &r) { + AlwaysReturn(r); + } + + template + MethodStubbingProgress& ReturnRefCapt(T&& r) { + static_assert(std::is_lvalue_reference::value, "ReturnRefCapt() cannot take an rvalue references because it would make it dangling, use ReturnValCapt() instead."); + return Do([&r](const typename fakeit::test_arg::type...) -> R { return r; }); + } + + template + void AlwaysReturnRefCapt(T&& r) { + static_assert(std::is_lvalue_reference::value, "AlwaysReturnRefCapt() cannot take an rvalue references because it would make it dangling, use AlwaysReturnValCapt() instead."); + AlwaysDo([&r](const typename fakeit::test_arg::type...) -> R { return r; }); } }; @@ -146,6 +192,38 @@ namespace fakeit { using helper::BasicReturnImplHelper::Return; using helper::BasicReturnImplHelper::AlwaysReturn; + // DEPRECATED: This should ideally be removed, it allows writing .Return("ok") when a function + // returns "const std::string&" (for example) to have the same behavior has .ReturnValCapt("ok"). But it is prone + // to errors (because you have to specify the type). .ReturnValCapt("ok") is superior and should be used instead. + template::value, bool>::type = true> + MethodStubbingProgress& Return(RealType&& ret) { + return this->ReturnValCapt(TypeUsedToForceCapture(std::forward(ret))); + } + + // DEPRECATED: This should ideally be removed, it allows writing .AlwaysReturn("ok") when a function + // returns "const std::string&" (for example) to have the same behavior has .AlwaysReturnValCapt("ok"). But it is prone + // to errors (because you have to specify the type). .AlwaysReturnValCapt("ok") is superior and should be used instead. + template::value, bool>::type = true> + void AlwaysReturn(RealType&& ret) { + this->AlwaysReturnValCapt(TypeUsedToForceCapture(std::forward(ret))); + } + + // DEPRECATED: This should ideally be removed, it allows writing .Return(str) when a function + // returns "std::string" (for example) to have the same behavior has .ReturnRefCapt(str). But it is prone + // to errors (because you have to specify the type). .ReturnRefCapt(str) is superior and should be used instead. + template::value, bool>::type = true> + MethodStubbingProgress& Return(RealType&& ret) { + return this->ReturnRefCapt(std::forward(ret)); + } + + // DEPRECATED: This should ideally be removed, it allows writing .AlwaysReturn(str) when a function + // returns "std::string" (for example) to have the same behavior has .AlwaysReturnRefCapt(str). But it is prone + // to errors (because you have to specify the type). .AlwaysReturnRefCapt(str) is superior and should be used instead. + template::value, bool>::type = true> + void AlwaysReturn(RealType&& ret) { + this->AlwaysReturnRefCapt(std::forward(ret)); + } + MethodStubbingProgress & Return(const Quantifier &q) { const R &value = q.value; diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 02af1c4b..881ecbb3 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -18,6 +18,7 @@ add_executable(FakeIt_tests overloadded_methods_tests.cpp referece_types_tests.cpp remove_const_volatile_tests.cpp + return_template_specialization.cpp rvalue_arguments_tests.cpp sequence_verification_tests.cpp spying_tests.cpp diff --git a/tests/referece_types_tests.cpp b/tests/referece_types_tests.cpp index 48ef2373..66013839 100644 --- a/tests/referece_types_tests.cpp +++ b/tests/referece_types_tests.cpp @@ -240,10 +240,10 @@ struct ReferenceTypesTests: tpunit::TestFixture { ConcreteType concrete{"myConcreteType"}; // explicit copy here - When(Method(mock, returnStringByConstRef)).ReturnCapture(aString); - When(Method(mock, returnStringByRValRef)).ReturnCapture(bString); - When(Method(mock, returnIntByRef)).ReturnCapture(num); - When(Method(mock, returnAbstractTypeByRef)).ReturnCapture(concrete); + When(Method(mock, returnStringByConstRef)).ReturnValCapt(aString); + When(Method(mock, returnStringByRValRef)).ReturnValCapt(bString); + When(Method(mock, returnIntByRef)).ReturnValCapt(num); + When(Method(mock, returnAbstractTypeByRef)).ReturnValCapt(concrete); // modify now so know whether or not is was copied aString = "modified"; @@ -276,13 +276,13 @@ struct ReferenceTypesTests: tpunit::TestFixture { ConcreteType concrete{"myConcreteType"}; // explicit move here - When(Method(mock, returnStringByConstRef)).ReturnCapture(std::move(aString)); - When(Method(mock, returnStringByRef)).ReturnCapture(std::move(bString)); - When(Method(mock, returnStringByRValRef)).ReturnCapture(std::move(cString)); - When(Method(mock, returnMoveOnlyByConstRef)).ReturnCapture(std::move(aPtrString)); - When(Method(mock, returnMoveOnlyByRef)).ReturnCapture(std::move(bPtrString)); - When(Method(mock, returnMoveOnlyByRValRef)).ReturnCapture(std::move(cPtrString)); - When(Method(mock, returnAbstractTypeByRef)).ReturnCapture(std::move(concrete)); + When(Method(mock, returnStringByConstRef)).ReturnValCapt(std::move(aString)); + When(Method(mock, returnStringByRef)).ReturnValCapt(std::move(bString)); + When(Method(mock, returnStringByRValRef)).ReturnValCapt(std::move(cString)); + When(Method(mock, returnMoveOnlyByConstRef)).ReturnValCapt(std::move(aPtrString)); + When(Method(mock, returnMoveOnlyByRef)).ReturnValCapt(std::move(bPtrString)); + When(Method(mock, returnMoveOnlyByRValRef)).ReturnValCapt(std::move(cPtrString)); + When(Method(mock, returnAbstractTypeByRef)).ReturnValCapt(std::move(concrete)); // Verify objects were moved. EXPECT_TRUE(aString.empty()); @@ -311,13 +311,13 @@ struct ReferenceTypesTests: tpunit::TestFixture { Mock mock; { - When(Method(mock, returnStringByConstRef)).ReturnCapture(std::string{"aString"}); - When(Method(mock, returnStringByRef)).ReturnCapture(std::string{"bString"}); - When(Method(mock, returnStringByRValRef)).ReturnCapture(std::string{"cString"}); - When(Method(mock, returnMoveOnlyByConstRef)).ReturnCapture(std::unique_ptr(new std::string{"aPtrString"})); - When(Method(mock, returnMoveOnlyByRef)).ReturnCapture(std::unique_ptr(new std::string{"bPtrString"})); - When(Method(mock, returnMoveOnlyByRValRef)).ReturnCapture(std::unique_ptr(new std::string{"cPtrString"})); - When(Method(mock, returnAbstractTypeByRef)).ReturnCapture(ConcreteType{"myConcreteType"}); + When(Method(mock, returnStringByConstRef)).ReturnValCapt(std::string{"aString"}); + When(Method(mock, returnStringByRef)).ReturnValCapt(std::string{"bString"}); + When(Method(mock, returnStringByRValRef)).ReturnValCapt(std::string{"cString"}); + When(Method(mock, returnMoveOnlyByConstRef)).ReturnValCapt(std::unique_ptr(new std::string{"aPtrString"})); + When(Method(mock, returnMoveOnlyByRef)).ReturnValCapt(std::unique_ptr(new std::string{"bPtrString"})); + When(Method(mock, returnMoveOnlyByRValRef)).ReturnValCapt(std::unique_ptr(new std::string{"cPtrString"})); + When(Method(mock, returnAbstractTypeByRef)).ReturnValCapt(ConcreteType{"myConcreteType"}); } ReferenceInterface& i = mock.get(); @@ -344,10 +344,10 @@ struct ReferenceTypesTests: tpunit::TestFixture { ConcreteType concrete{"myConcreteType"}; // explicit copy here - When(Method(mock, returnStringByConstRef)).AlwaysReturnCapture(aString); - When(Method(mock, returnStringByRValRef)).AlwaysReturnCapture(bString); - When(Method(mock, returnIntByRef)).AlwaysReturnCapture(num); - When(Method(mock, returnAbstractTypeByRef)).AlwaysReturnCapture(concrete); + When(Method(mock, returnStringByConstRef)).AlwaysReturnValCapt(aString); + When(Method(mock, returnStringByRValRef)).AlwaysReturnValCapt(bString); + When(Method(mock, returnIntByRef)).AlwaysReturnValCapt(num); + When(Method(mock, returnAbstractTypeByRef)).AlwaysReturnValCapt(concrete); // modify now so know whether or not is was copied aString = "modified"; @@ -395,13 +395,13 @@ struct ReferenceTypesTests: tpunit::TestFixture { ConcreteType concrete{"myConcreteType"}; // explicit move here - When(Method(mock, returnStringByConstRef)).AlwaysReturnCapture(std::move(aString)); - When(Method(mock, returnStringByRef)).AlwaysReturnCapture(std::move(bString)); - When(Method(mock, returnStringByRValRef)).AlwaysReturnCapture(std::move(cString)); - When(Method(mock, returnMoveOnlyByConstRef)).AlwaysReturnCapture(std::move(aPtrString)); - When(Method(mock, returnMoveOnlyByRef)).AlwaysReturnCapture(std::move(bPtrString)); - When(Method(mock, returnMoveOnlyByRValRef)).AlwaysReturnCapture(std::move(cPtrString)); - When(Method(mock, returnAbstractTypeByRef)).AlwaysReturnCapture(std::move(concrete)); + When(Method(mock, returnStringByConstRef)).AlwaysReturnValCapt(std::move(aString)); + When(Method(mock, returnStringByRef)).AlwaysReturnValCapt(std::move(bString)); + When(Method(mock, returnStringByRValRef)).AlwaysReturnValCapt(std::move(cString)); + When(Method(mock, returnMoveOnlyByConstRef)).AlwaysReturnValCapt(std::move(aPtrString)); + When(Method(mock, returnMoveOnlyByRef)).AlwaysReturnValCapt(std::move(bPtrString)); + When(Method(mock, returnMoveOnlyByRValRef)).AlwaysReturnValCapt(std::move(cPtrString)); + When(Method(mock, returnAbstractTypeByRef)).AlwaysReturnValCapt(std::move(concrete)); // Verify objects were moved. EXPECT_TRUE(aString.empty()); @@ -453,13 +453,13 @@ struct ReferenceTypesTests: tpunit::TestFixture { Mock mock; { - When(Method(mock, returnStringByConstRef)).AlwaysReturnCapture(std::string{"aString"}); - When(Method(mock, returnStringByRef)).AlwaysReturnCapture(std::string{"bString"}); - When(Method(mock, returnStringByRValRef)).AlwaysReturnCapture(std::string{"cString"}); - When(Method(mock, returnMoveOnlyByConstRef)).AlwaysReturnCapture(std::unique_ptr(new std::string{"aPtrString"})); - When(Method(mock, returnMoveOnlyByRef)).AlwaysReturnCapture(std::unique_ptr(new std::string{"bPtrString"})); - When(Method(mock, returnMoveOnlyByRValRef)).AlwaysReturnCapture(std::unique_ptr(new std::string{"cPtrString"})); - When(Method(mock, returnAbstractTypeByRef)).AlwaysReturnCapture(ConcreteType{"myConcreteType"}); + When(Method(mock, returnStringByConstRef)).AlwaysReturnValCapt(std::string{"aString"}); + When(Method(mock, returnStringByRef)).AlwaysReturnValCapt(std::string{"bString"}); + When(Method(mock, returnStringByRValRef)).AlwaysReturnValCapt(std::string{"cString"}); + When(Method(mock, returnMoveOnlyByConstRef)).AlwaysReturnValCapt(std::unique_ptr(new std::string{"aPtrString"})); + When(Method(mock, returnMoveOnlyByRef)).AlwaysReturnValCapt(std::unique_ptr(new std::string{"bPtrString"})); + When(Method(mock, returnMoveOnlyByRValRef)).AlwaysReturnValCapt(std::unique_ptr(new std::string{"cPtrString"})); + When(Method(mock, returnAbstractTypeByRef)).AlwaysReturnValCapt(ConcreteType{"myConcreteType"}); } ReferenceInterface& i = mock.get(); diff --git a/tests/return_template_specialization.cpp b/tests/return_template_specialization.cpp new file mode 100644 index 00000000..63cbae9e --- /dev/null +++ b/tests/return_template_specialization.cpp @@ -0,0 +1,863 @@ +/* + * Copyright (c) 2014 Eran Pe'er. + * + * This program is made available under the terms of the MIT License. + * + * Created on Mar 10, 2014 + */ + +#include "tpunit++.hpp" +#include "fakeit.hpp" + +using namespace fakeit; + +struct ReturnTemplateSpecializationTests : tpunit::TestFixture { + + ReturnTemplateSpecializationTests() + : tpunit::TestFixture( + TEST(ReturnTemplateSpecializationTests::return_default_from_same_type_temp), + TEST(ReturnTemplateSpecializationTests::return_valspecialization_from_same_type_temp), + TEST(ReturnTemplateSpecializationTests::return_valcapt_from_same_type_temp), + TEST(ReturnTemplateSpecializationTests::return_default_from_other_type_temp), + TEST(ReturnTemplateSpecializationTests::return_valspecialization_from_other_type_temp), + TEST(ReturnTemplateSpecializationTests::return_valcapt_from_other_type_temp), + TEST(ReturnTemplateSpecializationTests::return_default_from_same_type_variable), + TEST(ReturnTemplateSpecializationTests::return_valspecialization_from_same_type_variable), + TEST(ReturnTemplateSpecializationTests::return_refspecialization_from_same_type_variable), + TEST(ReturnTemplateSpecializationTests::return_valcapt_from_same_type_variable), + TEST(ReturnTemplateSpecializationTests::return_refcapt_from_same_type_variable), + TEST(ReturnTemplateSpecializationTests::return_default_from_other_type_variable), + TEST(ReturnTemplateSpecializationTests::return_valspecialization_from_other_type_variable), + TEST(ReturnTemplateSpecializationTests::return_refspecialization_from_other_type_variable), + TEST(ReturnTemplateSpecializationTests::return_valcapt_from_other_type_variable), + TEST(ReturnTemplateSpecializationTests::return_refcapt_from_other_type_variable), + TEST(ReturnTemplateSpecializationTests::always_return_default_from_same_type_temp), + TEST(ReturnTemplateSpecializationTests::always_return_valspecialization_from_same_type_temp), + TEST(ReturnTemplateSpecializationTests::always_return_valcapt_from_same_type_temp), + TEST(ReturnTemplateSpecializationTests::always_return_default_from_other_type_temp), + TEST(ReturnTemplateSpecializationTests::always_return_valspecialization_from_other_type_temp), + TEST(ReturnTemplateSpecializationTests::always_return_valcapt_from_other_type_temp), + TEST(ReturnTemplateSpecializationTests::always_return_default_from_same_type_variable), + TEST(ReturnTemplateSpecializationTests::always_return_valspecialization_from_same_type_variable), + TEST(ReturnTemplateSpecializationTests::always_return_refspecialization_from_same_type_variable), + TEST(ReturnTemplateSpecializationTests::always_return_valcapt_from_same_type_variable), + TEST(ReturnTemplateSpecializationTests::always_return_refcapt_from_same_type_variable), + TEST(ReturnTemplateSpecializationTests::always_return_default_from_other_type_variable), + TEST(ReturnTemplateSpecializationTests::always_return_valspecialization_from_other_type_variable), + TEST(ReturnTemplateSpecializationTests::always_return_refspecialization_from_other_type_variable), + TEST(ReturnTemplateSpecializationTests::always_return_valcapt_from_other_type_variable), + TEST(ReturnTemplateSpecializationTests::always_return_refcapt_from_other_type_variable), + TEST(ReturnTemplateSpecializationTests::test_implicitly_deduced_type) + ) { + } + + struct MoveOnly { + int i = 0; + MoveOnly(int pi) : i{pi} {} + MoveOnly(const MoveOnly&) = delete; + MoveOnly(MoveOnly&&) = default; + }; + + struct SomeStruct { + virtual ~SomeStruct() = default; + + virtual const std::string& returnRef() = 0; + + virtual const MoveOnly& returnRefMo() = 0; + + virtual std::string returnVal() = 0; + + virtual MoveOnly returnValMo() = 0; + + virtual std::pair returnPair() = 0; + + virtual const std::pair& returnRefPair() = 0; + }; + + void return_default_from_same_type_temp() { + Mock mock; + + When(Method(mock, returnVal)).Return(std::string("something")); + ASSERT_EQUAL(mock.get().returnVal(), "something"); + Verify(Method(mock, returnVal)).Once(); + + When(Method(mock, returnValMo)).Return(MoveOnly{5}); + ASSERT_EQUAL(mock.get().returnValMo().i, 5); + Verify(Method(mock, returnValMo)).Once(); + } + + void return_valspecialization_from_same_type_temp() { + Mock mock; + + When(Method(mock, returnRef)).Return(std::string("something")); + ASSERT_EQUAL(mock.get().returnRef(), "something"); + Verify(Method(mock, returnRef)).Once(); + + When(Method(mock, returnRefMo)).Return(MoveOnly{5}); + ASSERT_EQUAL(mock.get().returnRefMo().i, 5); + Verify(Method(mock, returnRefMo)).Once(); + + When(Method(mock, returnVal)).Return(std::string("something")); + ASSERT_EQUAL(mock.get().returnVal(), "something"); + Verify(Method(mock, returnVal)).Once(); + + When(Method(mock, returnValMo)).Return(MoveOnly{5}); + ASSERT_EQUAL(mock.get().returnValMo().i, 5); + Verify(Method(mock, returnValMo)).Once(); + } + + void return_valcapt_from_same_type_temp() { + Mock mock; + + When(Method(mock, returnRef)).ReturnValCapt(std::string("something")); + ASSERT_EQUAL(mock.get().returnRef(), "something"); + Verify(Method(mock, returnRef)).Once(); + + When(Method(mock, returnRefMo)).ReturnValCapt(MoveOnly{5}); + ASSERT_EQUAL(mock.get().returnRefMo().i, 5); + Verify(Method(mock, returnRefMo)).Once(); + + When(Method(mock, returnVal)).ReturnValCapt(std::string("something")); + ASSERT_EQUAL(mock.get().returnVal(), "something"); + Verify(Method(mock, returnVal)).Once(); + + When(Method(mock, returnValMo)).ReturnValCapt(MoveOnly{5}); + ASSERT_EQUAL(mock.get().returnValMo().i, 5); + Verify(Method(mock, returnValMo)).Once(); + } + + void return_default_from_other_type_temp() { + Mock mock; + + When(Method(mock, returnVal)).Return("something"); + ASSERT_EQUAL(mock.get().returnVal(), "something"); + Verify(Method(mock, returnVal)).Once(); + + When(Method(mock, returnValMo)).Return(5); + ASSERT_EQUAL(mock.get().returnValMo().i, 5); + Verify(Method(mock, returnValMo)).Once(); + } + + void return_valspecialization_from_other_type_temp() { + Mock mock; + + When(Method(mock, returnRef)).Return("something"); + ASSERT_EQUAL(mock.get().returnRef(), "something"); + Verify(Method(mock, returnRef)).Once(); + + When(Method(mock, returnRefMo)).Return(5); + ASSERT_EQUAL(mock.get().returnRefMo().i, 5); + Verify(Method(mock, returnRefMo)).Once(); + + When(Method(mock, returnVal)).Return("something"); + ASSERT_EQUAL(mock.get().returnVal(), "something"); + Verify(Method(mock, returnVal)).Once(); + + When(Method(mock, returnValMo)).Return(5); + ASSERT_EQUAL(mock.get().returnValMo().i, 5); + Verify(Method(mock, returnValMo)).Once(); + } + + void return_valcapt_from_other_type_temp() { + Mock mock; + + When(Method(mock, returnRef)).ReturnValCapt("something"); + ASSERT_EQUAL(mock.get().returnRef(), "something"); + Verify(Method(mock, returnRef)).Once(); + + When(Method(mock, returnRefMo)).ReturnValCapt(5); + ASSERT_EQUAL(mock.get().returnRefMo().i, 5); + Verify(Method(mock, returnRefMo)).Once(); + + When(Method(mock, returnVal)).ReturnValCapt("something"); + ASSERT_EQUAL(mock.get().returnVal(), "something"); + Verify(Method(mock, returnVal)).Once(); + + When(Method(mock, returnValMo)).ReturnValCapt(5); + ASSERT_EQUAL(mock.get().returnValMo().i, 5); + Verify(Method(mock, returnValMo)).Once(); + } + + void return_default_from_same_type_variable() { + Mock mock; + + { + std::string something = "something"; + MoveOnly mo = 5; + + When(Method(mock, returnRef)).Return(something); + something = "a different thing"; + ASSERT_EQUAL(mock.get().returnRef(), "a different thing"); + Verify(Method(mock, returnRef)).Once(); + + When(Method(mock, returnRefMo)).Return(mo); + mo.i = 10; + ASSERT_EQUAL(mock.get().returnRefMo().i, 10); + Verify(Method(mock, returnRefMo)).Once(); + } + + { + std::string something = "something"; + MoveOnly mo = 5; + + When(Method(mock, returnVal)).Return(something); + something = "a different thing"; + ASSERT_EQUAL(mock.get().returnVal(), "something"); + Verify(Method(mock, returnVal)).Once(); + + When(Method(mock, returnValMo)).Return(std::move(mo)); + mo.i = 10; + ASSERT_EQUAL(mock.get().returnValMo().i, 5); + Verify(Method(mock, returnValMo)).Once(); + } + } + + void return_valspecialization_from_same_type_variable() { + Mock mock; + + { + std::string something = "something"; + MoveOnly mo = 5; + + When(Method(mock, returnRef)).Return(something); + something = "a different thing"; + ASSERT_EQUAL(mock.get().returnRef(), "something"); + Verify(Method(mock, returnRef)).Once(); + + When(Method(mock, returnRefMo)).Return(std::move(mo)); + mo.i = 10; + ASSERT_EQUAL(mock.get().returnRefMo().i, 5); + Verify(Method(mock, returnRefMo)).Once(); + } + + { + std::string something = "something"; + MoveOnly mo = 5; + + When(Method(mock, returnVal)).Return(something); + something = "a different thing"; + ASSERT_EQUAL(mock.get().returnVal(), "something"); + Verify(Method(mock, returnVal)).Once(); + + When(Method(mock, returnValMo)).Return(std::move(mo)); + mo.i = 10; + ASSERT_EQUAL(mock.get().returnValMo().i, 5); + Verify(Method(mock, returnValMo)).Once(); + } + } + + void return_refspecialization_from_same_type_variable() { + Mock mock; + + { + std::string something = "something"; + MoveOnly mo = 5; + + When(Method(mock, returnRef)).Return(something); + something = "a different thing"; + ASSERT_EQUAL(mock.get().returnRef(), "a different thing"); + Verify(Method(mock, returnRef)).Once(); + + When(Method(mock, returnRefMo)).Return(mo); + mo.i = 10; + ASSERT_EQUAL(mock.get().returnRefMo().i, 10); + Verify(Method(mock, returnRefMo)).Once(); + } + + { + std::string something = "something"; + + When(Method(mock, returnVal)).Return(something); + something = "a different thing"; + ASSERT_EQUAL(mock.get().returnVal(), "a different thing"); + Verify(Method(mock, returnVal)).Once(); + } + } + + void return_valcapt_from_same_type_variable() { + Mock mock; + + { + std::string something = "something"; + MoveOnly mo = 5; + + When(Method(mock, returnRef)).ReturnValCapt(something); + something = "a different thing"; + ASSERT_EQUAL(mock.get().returnRef(), "something"); + Verify(Method(mock, returnRef)).Once(); + + When(Method(mock, returnRefMo)).ReturnValCapt(std::move(mo)); + mo.i = 10; + ASSERT_EQUAL(mock.get().returnRefMo().i, 5); + Verify(Method(mock, returnRefMo)).Once(); + } + + { + std::string something = "something"; + MoveOnly mo = 5; + + When(Method(mock, returnVal)).ReturnValCapt(something); + something = "a different thing"; + ASSERT_EQUAL(mock.get().returnVal(), "something"); + Verify(Method(mock, returnVal)).Once(); + + When(Method(mock, returnValMo)).ReturnValCapt(std::move(mo)); + mo.i = 10; + ASSERT_EQUAL(mock.get().returnValMo().i, 5); + Verify(Method(mock, returnValMo)).Once(); + } + } + + void return_refcapt_from_same_type_variable() { + Mock mock; + + { + std::string something = "something"; + MoveOnly mo = 5; + + When(Method(mock, returnRef)).ReturnRefCapt(something); + something = "a different thing"; + ASSERT_EQUAL(mock.get().returnRef(), "a different thing"); + Verify(Method(mock, returnRef)).Once(); + + When(Method(mock, returnRefMo)).ReturnRefCapt(mo); + mo.i = 10; + ASSERT_EQUAL(mock.get().returnRefMo().i, 10); + Verify(Method(mock, returnRefMo)).Once(); + } + + { + std::string something = "something"; + + When(Method(mock, returnVal)).ReturnRefCapt(something); + something = "a different thing"; + ASSERT_EQUAL(mock.get().returnVal(), "a different thing"); + Verify(Method(mock, returnVal)).Once(); + } + } + + void return_default_from_other_type_variable() { + Mock mock; + + { + const char* something = "something"; + int num = 5; + + When(Method(mock, returnVal)).Return(something); + something = "a different thing"; + ASSERT_EQUAL(mock.get().returnVal(), "something"); + Verify(Method(mock, returnVal)).Once(); + + When(Method(mock, returnValMo)).Return(num); + num = 10; + ASSERT_EQUAL(mock.get().returnValMo().i, 5); + Verify(Method(mock, returnValMo)).Once(); + } + } + + void return_valspecialization_from_other_type_variable() { + Mock mock; + + { + const char* something = "something"; + int num = 5; + + When(Method(mock, returnRef)).Return(something); + something = "a different thing"; + ASSERT_EQUAL(mock.get().returnRef(), "something"); + Verify(Method(mock, returnRef)).Once(); + + When(Method(mock, returnRefMo)).Return(num); + num = 10; + ASSERT_EQUAL(mock.get().returnRefMo().i, 5); + Verify(Method(mock, returnRefMo)).Once(); + } + + { + const char* something = "something"; + int num = 5; + + When(Method(mock, returnVal)).Return(something); + something = "a different thing"; + ASSERT_EQUAL(mock.get().returnVal(), "something"); + Verify(Method(mock, returnVal)).Once(); + + When(Method(mock, returnValMo)).Return(num); + num = 10; + ASSERT_EQUAL(mock.get().returnValMo().i, 5); + Verify(Method(mock, returnValMo)).Once(); + } + } + + void return_refspecialization_from_other_type_variable() { + Mock mock; + + { + const char* something = "something"; + int num = 5; + + When(Method(mock, returnVal)).Return(something); + something = "a different thing"; + ASSERT_EQUAL(mock.get().returnVal(), "a different thing"); + Verify(Method(mock, returnVal)).Once(); + + When(Method(mock, returnValMo)).Return(num); + num = 10; + ASSERT_EQUAL(mock.get().returnValMo().i, 10); + Verify(Method(mock, returnValMo)).Once(); + } + } + + void return_valcapt_from_other_type_variable() { + Mock mock; + + { + const char* something = "something"; + int num = 5; + + When(Method(mock, returnRef)).ReturnValCapt(something); + something = "a different thing"; + ASSERT_EQUAL(mock.get().returnRef(), "something"); + Verify(Method(mock, returnRef)).Once(); + + When(Method(mock, returnRefMo)).ReturnValCapt(num); + num = 10; + ASSERT_EQUAL(mock.get().returnRefMo().i, 5); + Verify(Method(mock, returnRefMo)).Once(); + } + + { + const char* something = "something"; + int num = 5; + + When(Method(mock, returnVal)).ReturnValCapt(something); + something = "a different thing"; + ASSERT_EQUAL(mock.get().returnVal(), "something"); + Verify(Method(mock, returnVal)).Once(); + + When(Method(mock, returnValMo)).ReturnValCapt(num); + num = 10; + ASSERT_EQUAL(mock.get().returnValMo().i, 5); + Verify(Method(mock, returnValMo)).Once(); + } + } + + void return_refcapt_from_other_type_variable() { + Mock mock; + + { + const char* something = "something"; + int num = 5; + + When(Method(mock, returnVal)).ReturnRefCapt(something); + something = "a different thing"; + ASSERT_EQUAL(mock.get().returnVal(), "a different thing"); + Verify(Method(mock, returnVal)).Once(); + + When(Method(mock, returnValMo)).ReturnRefCapt(num); + num = 10; + ASSERT_EQUAL(mock.get().returnValMo().i, 10); + Verify(Method(mock, returnValMo)).Once(); + } + } + + void always_return_default_from_same_type_temp() { + Mock mock; + + When(Method(mock, returnVal)).AlwaysReturn(std::string("something")); + ASSERT_EQUAL(mock.get().returnVal(), "something"); + ASSERT_EQUAL(mock.get().returnVal(), "something"); + Verify(Method(mock, returnVal)).Exactly(2); + } + + void always_return_valspecialization_from_same_type_temp() { + Mock mock; + + When(Method(mock, returnRef)).AlwaysReturn(std::string("something")); + ASSERT_EQUAL(mock.get().returnRef(), "something"); + ASSERT_EQUAL(mock.get().returnRef(), "something"); + Verify(Method(mock, returnRef)).Exactly(2); + + When(Method(mock, returnRefMo)).AlwaysReturn(MoveOnly{5}); + ASSERT_EQUAL(mock.get().returnRefMo().i, 5); + ASSERT_EQUAL(mock.get().returnRefMo().i, 5); + Verify(Method(mock, returnRefMo)).Exactly(2); + + When(Method(mock, returnVal)).AlwaysReturn(std::string("something")); + ASSERT_EQUAL(mock.get().returnVal(), "something"); + ASSERT_EQUAL(mock.get().returnVal(), "something"); + Verify(Method(mock, returnVal)).Exactly(2); + } + + void always_return_valcapt_from_same_type_temp() { + Mock mock; + + When(Method(mock, returnRef)).AlwaysReturnValCapt(std::string("something")); + ASSERT_EQUAL(mock.get().returnRef(), "something"); + ASSERT_EQUAL(mock.get().returnRef(), "something"); + Verify(Method(mock, returnRef)).Exactly(2); + + When(Method(mock, returnRefMo)).AlwaysReturnValCapt(MoveOnly{5}); + ASSERT_EQUAL(mock.get().returnRefMo().i, 5); + ASSERT_EQUAL(mock.get().returnRefMo().i, 5); + Verify(Method(mock, returnRefMo)).Exactly(2); + + When(Method(mock, returnVal)).AlwaysReturnValCapt(std::string("something")); + ASSERT_EQUAL(mock.get().returnVal(), "something"); + ASSERT_EQUAL(mock.get().returnVal(), "something"); + Verify(Method(mock, returnVal)).Exactly(2); + } + + void always_return_default_from_other_type_temp() { + Mock mock; + + When(Method(mock, returnVal)).AlwaysReturn("something"); + ASSERT_EQUAL(mock.get().returnVal(), "something"); + ASSERT_EQUAL(mock.get().returnVal(), "something"); + Verify(Method(mock, returnVal)).Exactly(2); + } + + void always_return_valspecialization_from_other_type_temp() { + Mock mock; + + When(Method(mock, returnRef)).AlwaysReturn("something"); + ASSERT_EQUAL(mock.get().returnRef(), "something"); + ASSERT_EQUAL(mock.get().returnRef(), "something"); + Verify(Method(mock, returnRef)).Exactly(2); + + When(Method(mock, returnRefMo)).AlwaysReturn(5); + ASSERT_EQUAL(mock.get().returnRefMo().i, 5); + ASSERT_EQUAL(mock.get().returnRefMo().i, 5); + Verify(Method(mock, returnRefMo)).Exactly(2); + + When(Method(mock, returnVal)).AlwaysReturn("something"); + ASSERT_EQUAL(mock.get().returnVal(), "something"); + ASSERT_EQUAL(mock.get().returnVal(), "something"); + Verify(Method(mock, returnVal)).Exactly(2); + } + + void always_return_valcapt_from_other_type_temp() { + Mock mock; + + When(Method(mock, returnRef)).AlwaysReturnValCapt("something"); + ASSERT_EQUAL(mock.get().returnRef(), "something"); + ASSERT_EQUAL(mock.get().returnRef(), "something"); + Verify(Method(mock, returnRef)).Exactly(2); + + When(Method(mock, returnRefMo)).AlwaysReturnValCapt(5); + ASSERT_EQUAL(mock.get().returnRefMo().i, 5); + ASSERT_EQUAL(mock.get().returnRefMo().i, 5); + Verify(Method(mock, returnRefMo)).Exactly(2); + + When(Method(mock, returnVal)).AlwaysReturnValCapt("something"); + ASSERT_EQUAL(mock.get().returnVal(), "something"); + ASSERT_EQUAL(mock.get().returnVal(), "something"); + Verify(Method(mock, returnVal)).Exactly(2); + } + + void always_return_default_from_same_type_variable() { + Mock mock; + + { + std::string something = "something"; + MoveOnly mo = 5; + + When(Method(mock, returnRef)).AlwaysReturn(something); + something = "a different thing"; + ASSERT_EQUAL(mock.get().returnRef(), "a different thing"); + something = "another different thing"; + ASSERT_EQUAL(mock.get().returnRef(), "another different thing"); + Verify(Method(mock, returnRef)).Exactly(2); + + When(Method(mock, returnRefMo)).AlwaysReturn(mo); + mo.i = 10; + ASSERT_EQUAL(mock.get().returnRefMo().i, 10); + mo.i = 50; + ASSERT_EQUAL(mock.get().returnRefMo().i, 50); + Verify(Method(mock, returnRefMo)).Exactly(2); + } + + { + std::string something = "something"; + + When(Method(mock, returnVal)).AlwaysReturn(something); + something = "a different thing"; + ASSERT_EQUAL(mock.get().returnVal(), "something"); + something = "another different thing"; + ASSERT_EQUAL(mock.get().returnVal(), "something"); + Verify(Method(mock, returnVal)).Exactly(2); + } + } + + void always_return_valspecialization_from_same_type_variable() { + Mock mock; + + { + std::string something = "something"; + MoveOnly mo = 5; + + When(Method(mock, returnRef)).AlwaysReturn(something); + something = "a different thing"; + ASSERT_EQUAL(mock.get().returnRef(), "something"); + something = "another different thing"; + ASSERT_EQUAL(mock.get().returnRef(), "something"); + Verify(Method(mock, returnRef)).Exactly(2); + + When(Method(mock, returnRefMo)).AlwaysReturn(std::move(mo)); + mo.i = 10; + ASSERT_EQUAL(mock.get().returnRefMo().i, 5); + mo.i = 50; + ASSERT_EQUAL(mock.get().returnRefMo().i, 5); + Verify(Method(mock, returnRefMo)).Exactly(2); + } + + { + std::string something = "something"; + + When(Method(mock, returnVal)).AlwaysReturn(something); + something = "a different thing"; + ASSERT_EQUAL(mock.get().returnVal(), "something"); + something = "another different thing"; + ASSERT_EQUAL(mock.get().returnVal(), "something"); + Verify(Method(mock, returnVal)).Exactly(2); + } + } + + void always_return_refspecialization_from_same_type_variable() { + Mock mock; + + { + std::string something = "something"; + MoveOnly mo = 5; + + When(Method(mock, returnRef)).AlwaysReturn(something); + something = "a different thing"; + ASSERT_EQUAL(mock.get().returnRef(), "a different thing"); + something = "another different thing"; + ASSERT_EQUAL(mock.get().returnRef(), "another different thing"); + Verify(Method(mock, returnRef)).Exactly(2); + + When(Method(mock, returnRefMo)).AlwaysReturn(mo); + mo.i = 10; + ASSERT_EQUAL(mock.get().returnRefMo().i, 10); + mo.i = 50; + ASSERT_EQUAL(mock.get().returnRefMo().i, 50); + Verify(Method(mock, returnRefMo)).Exactly(2); + } + + { + std::string something = "something"; + + When(Method(mock, returnVal)).AlwaysReturn(something); + something = "a different thing"; + ASSERT_EQUAL(mock.get().returnVal(), "a different thing"); + something = "another different thing"; + ASSERT_EQUAL(mock.get().returnVal(), "another different thing"); + Verify(Method(mock, returnVal)).Exactly(2); + } + } + + void always_return_valcapt_from_same_type_variable() { + Mock mock; + + { + std::string something = "something"; + MoveOnly mo = 5; + + When(Method(mock, returnRef)).AlwaysReturnValCapt(something); + something = "a different thing"; + ASSERT_EQUAL(mock.get().returnRef(), "something"); + something = "another different thing"; + ASSERT_EQUAL(mock.get().returnRef(), "something"); + Verify(Method(mock, returnRef)).Exactly(2); + + When(Method(mock, returnRefMo)).AlwaysReturnValCapt(std::move(mo)); + mo.i = 10; + ASSERT_EQUAL(mock.get().returnRefMo().i, 5); + mo.i = 50; + ASSERT_EQUAL(mock.get().returnRefMo().i, 5); + Verify(Method(mock, returnRefMo)).Exactly(2); + } + + { + std::string something = "something"; + + When(Method(mock, returnVal)).AlwaysReturnValCapt(something); + something = "a different thing"; + ASSERT_EQUAL(mock.get().returnVal(), "something"); + something = "another different thing"; + ASSERT_EQUAL(mock.get().returnVal(), "something"); + Verify(Method(mock, returnVal)).Exactly(2); + } + } + + void always_return_refcapt_from_same_type_variable() { + Mock mock; + + { + std::string something = "something"; + MoveOnly mo = 5; + + When(Method(mock, returnRef)).AlwaysReturnRefCapt(something); + something = "a different thing"; + ASSERT_EQUAL(mock.get().returnRef(), "a different thing"); + something = "another different thing"; + ASSERT_EQUAL(mock.get().returnRef(), "another different thing"); + Verify(Method(mock, returnRef)).Exactly(2); + + When(Method(mock, returnRefMo)).AlwaysReturnRefCapt(mo); + mo.i = 10; + ASSERT_EQUAL(mock.get().returnRefMo().i, 10); + mo.i = 50; + ASSERT_EQUAL(mock.get().returnRefMo().i, 50); + Verify(Method(mock, returnRefMo)).Exactly(2); + } + + { + std::string something = "something"; + + When(Method(mock, returnVal)).AlwaysReturnRefCapt(something); + something = "a different thing"; + ASSERT_EQUAL(mock.get().returnVal(), "a different thing"); + something = "another different thing"; + ASSERT_EQUAL(mock.get().returnVal(), "another different thing"); + Verify(Method(mock, returnVal)).Exactly(2); + } + } + + void always_return_default_from_other_type_variable() { + Mock mock; + + { + const char* something = "something"; + + When(Method(mock, returnVal)).AlwaysReturn(something); + something = "a different thing"; + ASSERT_EQUAL(mock.get().returnVal(), "something"); + something = "another different thing"; + ASSERT_EQUAL(mock.get().returnVal(), "something"); + Verify(Method(mock, returnVal)).Exactly(2); + } + } + + void always_return_valspecialization_from_other_type_variable() { + Mock mock; + + { + const char* something = "something"; + int num = 5; + + When(Method(mock, returnRef)).AlwaysReturn(something); + something = "a different thing"; + ASSERT_EQUAL(mock.get().returnRef(), "something"); + something = "another different thing"; + ASSERT_EQUAL(mock.get().returnRef(), "something"); + Verify(Method(mock, returnRef)).Exactly(2); + + When(Method(mock, returnRefMo)).AlwaysReturn(num); + num = 10; + ASSERT_EQUAL(mock.get().returnRefMo().i, 5); + num = 50; + ASSERT_EQUAL(mock.get().returnRefMo().i, 5); + Verify(Method(mock, returnRefMo)).Exactly(2); + } + + { + const char* something = "something"; + + When(Method(mock, returnVal)).AlwaysReturn(something); + something = "a different thing"; + ASSERT_EQUAL(mock.get().returnVal(), "something"); + something = "another different thing"; + ASSERT_EQUAL(mock.get().returnVal(), "something"); + Verify(Method(mock, returnVal)).Exactly(2); + } + } + + void always_return_refspecialization_from_other_type_variable() { + Mock mock; + + { + const char* something = "something"; + + When(Method(mock, returnVal)).AlwaysReturn(something); + something = "a different thing"; + ASSERT_EQUAL(mock.get().returnVal(), "a different thing"); + something = "another different thing"; + ASSERT_EQUAL(mock.get().returnVal(), "another different thing"); + Verify(Method(mock, returnVal)).Exactly(2); + } + } + + void always_return_valcapt_from_other_type_variable() { + Mock mock; + + { + const char* something = "something"; + int num = 5; + + When(Method(mock, returnRef)).AlwaysReturnValCapt(something); + something = "a different thing"; + ASSERT_EQUAL(mock.get().returnRef(), "something"); + something = "another different thing"; + ASSERT_EQUAL(mock.get().returnRef(), "something"); + Verify(Method(mock, returnRef)).Exactly(2); + + When(Method(mock, returnRefMo)).AlwaysReturnValCapt(num); + num = 10; + ASSERT_EQUAL(mock.get().returnRefMo().i, 5); + num = 50; + ASSERT_EQUAL(mock.get().returnRefMo().i, 5); + Verify(Method(mock, returnRefMo)).Exactly(2); + } + + { + const char* something = "something"; + + When(Method(mock, returnVal)).AlwaysReturnValCapt(something); + something = "a different thing"; + ASSERT_EQUAL(mock.get().returnVal(), "something"); + something = "another different thing"; + ASSERT_EQUAL(mock.get().returnVal(), "something"); + Verify(Method(mock, returnVal)).Exactly(2); + } + } + + void always_return_refcapt_from_other_type_variable() { + Mock mock; + + { + const char* something = "something"; + + When(Method(mock, returnVal)).AlwaysReturnRefCapt(something); + something = "a different thing"; + ASSERT_EQUAL(mock.get().returnVal(), "a different thing"); + something = "another different thing"; + ASSERT_EQUAL(mock.get().returnVal(), "another different thing"); + Verify(Method(mock, returnVal)).Exactly(2); + } + } + + void test_implicitly_deduced_type() { + Mock mock; + + When(Method(mock, returnPair)).ReturnValCapt({1, 2}); + ASSERT_EQUAL(mock.get().returnPair(), (std::pair{1, 2})); + Verify(Method(mock, returnPair)).Once(); + + When(Method(mock, returnRefPair)).ReturnValCapt({10, 20}); + ASSERT_EQUAL(mock.get().returnRefPair(), (std::pair{10, 20})); + Verify(Method(mock, returnRefPair)).Once(); + + When(Method(mock, returnPair)).AlwaysReturnValCapt({3, 4}); + ASSERT_EQUAL(mock.get().returnPair(), (std::pair{3, 4})); + ASSERT_EQUAL(mock.get().returnPair(), (std::pair{3, 4})); + Verify(Method(mock, returnPair)).Exactly(3); + + When(Method(mock, returnRefPair)).AlwaysReturnValCapt({30, 40}); + ASSERT_EQUAL(mock.get().returnRefPair(), (std::pair{30, 40})); + ASSERT_EQUAL(mock.get().returnRefPair(), (std::pair{30, 40})); + Verify(Method(mock, returnRefPair)).Exactly(3); + } + +} __ReturnTemplateSpecializationTests;