Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
112 changes: 95 additions & 17 deletions include/fakeit/StubbingProgress.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,40 +71,62 @@ namespace fakeit {
return Do([&r](const typename fakeit::test_arg<arglist>::type...) -> R { return r; });
}

template <typename U = R>
// The std::enable_if is only there to disambiguate with the deprecated version of .Return<type>(val), and
// can be removed once that deprecated version is removed.
template <typename U = R, typename std::enable_if<std::is_reference<U>::value, bool>::type = true>
MethodStubbingProgress<R, arglist...>& Return(fk_remove_cvref_t<R>&& 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<arglist>::type...) -> R { return r; });
AlwaysDo([&r](const typename fakeit::test_arg<arglist>::type...) -> R { return r; });
}

template <typename U = R>
// The std::enable_if is only there to disambiguate with the deprecated version of .AlwaysReturn<type>(val), and
// can be removed once that deprecated version is removed.
template <typename U = R, typename std::enable_if<std::is_reference<U>::value, bool>::type = true>
void AlwaysReturn(fk_remove_cvref_t<R>&&) {
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<typename T>
MethodStubbingProgress<R, arglist...>& ReturnCapture(T&& r) {
static_assert(std::is_constructible<fk_remove_cvref_t<R>&, fk_remove_cvref_t<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<fk_remove_cvref_t<T>>(std::forward<T>(r));
template<typename T = R>
MethodStubbingProgress<R, arglist...>& 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<R>&, fk_remove_cvref_t<T>&>::value,
fk_remove_cvref_t<T>,
fk_remove_cvref_t<R>>::type;
auto store = std::make_shared<StoredType>(std::forward<T>(r));
return Do([store](const typename fakeit::test_arg<arglist>::type...) mutable -> R {
return std::forward<R>(*store);
});
}

template<typename T>
void AlwaysReturnCapture(T&& r) {
static_assert(std::is_constructible<fk_remove_cvref_t<R>&, fk_remove_cvref_t<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<fk_remove_cvref_t<T>>(std::forward<T>(r));
return AlwaysDo([store](const typename fakeit::test_arg<arglist>::type...) mutable -> R {
template<typename T = R>
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<R>&, fk_remove_cvref_t<T>&>::value,
fk_remove_cvref_t<T>,
fk_remove_cvref_t<R>>::type;
auto store = std::make_shared<StoredType>(std::forward<T>(r));
AlwaysDo([store](const typename fakeit::test_arg<arglist>::type...) mutable -> R {
return std::forward<R>(*store);
});
}

template<typename T>
MethodStubbingProgress<R, arglist...>& ReturnRefCapt(T&& r) {
return Return(std::forward<T>(r));
}

template<typename T>
void AlwaysReturnRefCapt(T&& r) {
AlwaysReturn(std::forward<T>(r));
}
};

// If R is not a reference.
Expand All @@ -125,7 +147,31 @@ namespace fakeit {
}

void AlwaysReturn(const R &r) {
return AlwaysDo([r](const typename fakeit::test_arg<arglist>::type...) -> R { return r; });
AlwaysDo([r](const typename fakeit::test_arg<arglist>::type...) -> R { return r; });
}

MethodStubbingProgress<R, arglist...>& ReturnValCapt(const R& r) {
return Return(r);
}

MethodStubbingProgress<R, arglist...>& ReturnValCapt(R&& r) {
return Return(std::move(r));
}

void AlwaysReturnValCapt(const R &r) {
AlwaysReturn(r);
}

template<typename T>
MethodStubbingProgress<R, arglist...>& ReturnRefCapt(T&& r) {
static_assert(std::is_lvalue_reference<T>::value, "ReturnRefCapt() cannot take an rvalue references because it would make it dangling, use ReturnValCapt() instead.");
return Do([&r](const typename fakeit::test_arg<arglist>::type...) -> R { return r; });
}

template<typename T>
void AlwaysReturnRefCapt(T&& r) {
static_assert(std::is_lvalue_reference<T>::value, "AlwaysReturnRefCapt() cannot take an rvalue references because it would make it dangling, use AlwaysReturnValCapt() instead.");
AlwaysDo([&r](const typename fakeit::test_arg<arglist>::type...) -> R { return r; });
}
};

Expand All @@ -146,6 +192,38 @@ namespace fakeit {
using helper::BasicReturnImplHelper<R, arglist...>::Return;
using helper::BasicReturnImplHelper<R, arglist...>::AlwaysReturn;

// DEPRECATED: This should ideally be removed, it allows writing .Return<std::string>("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<typename TypeUsedToForceCapture, typename RealType, typename std::enable_if<!std::is_reference<TypeUsedToForceCapture>::value, bool>::type = true>
MethodStubbingProgress<R, arglist...>& Return(RealType&& ret) {
return this->ReturnValCapt(TypeUsedToForceCapture(std::forward<RealType>(ret)));
}

// DEPRECATED: This should ideally be removed, it allows writing .AlwaysReturn<std::string>("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<typename TypeUsedToForceCapture, typename RealType, typename std::enable_if<!std::is_reference<TypeUsedToForceCapture>::value, bool>::type = true>
void AlwaysReturn(RealType&& ret) {
this->AlwaysReturnValCapt(TypeUsedToForceCapture(std::forward<RealType>(ret)));
}

// DEPRECATED: This should ideally be removed, it allows writing .Return<std::string&>(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<typename TypeUsedToForceCapture, typename RealType, typename std::enable_if<std::is_reference<TypeUsedToForceCapture>::value, bool>::type = true>
MethodStubbingProgress<R, arglist...>& Return(RealType&& ret) {
return this->ReturnRefCapt(std::forward<RealType>(ret));
}

// DEPRECATED: This should ideally be removed, it allows writing .AlwaysReturn<std::string&>(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<typename TypeUsedToForceCapture, typename RealType, typename std::enable_if<std::is_reference<TypeUsedToForceCapture>::value, bool>::type = true>
void AlwaysReturn(RealType&& ret) {
this->AlwaysReturnRefCapt(std::forward<RealType>(ret));
}

MethodStubbingProgress<R, arglist...> &
Return(const Quantifier<R> &q) {
const R &value = q.value;
Expand Down
1 change: 1 addition & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
72 changes: 36 additions & 36 deletions tests/referece_types_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -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());
Expand Down Expand Up @@ -311,13 +311,13 @@ struct ReferenceTypesTests: tpunit::TestFixture {
Mock<ReferenceInterface> 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<std::string>(new std::string{"aPtrString"}));
When(Method(mock, returnMoveOnlyByRef)).ReturnCapture(std::unique_ptr<std::string>(new std::string{"bPtrString"}));
When(Method(mock, returnMoveOnlyByRValRef)).ReturnCapture(std::unique_ptr<std::string>(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<std::string>(new std::string{"aPtrString"}));
When(Method(mock, returnMoveOnlyByRef)).ReturnValCapt(std::unique_ptr<std::string>(new std::string{"bPtrString"}));
When(Method(mock, returnMoveOnlyByRValRef)).ReturnValCapt(std::unique_ptr<std::string>(new std::string{"cPtrString"}));
When(Method(mock, returnAbstractTypeByRef)).ReturnValCapt(ConcreteType{"myConcreteType"});
}

ReferenceInterface& i = mock.get();
Expand All @@ -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";
Expand Down Expand Up @@ -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());
Expand Down Expand Up @@ -453,13 +453,13 @@ struct ReferenceTypesTests: tpunit::TestFixture {
Mock<ReferenceInterface> 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<std::string>(new std::string{"aPtrString"}));
When(Method(mock, returnMoveOnlyByRef)).AlwaysReturnCapture(std::unique_ptr<std::string>(new std::string{"bPtrString"}));
When(Method(mock, returnMoveOnlyByRValRef)).AlwaysReturnCapture(std::unique_ptr<std::string>(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<std::string>(new std::string{"aPtrString"}));
When(Method(mock, returnMoveOnlyByRef)).AlwaysReturnValCapt(std::unique_ptr<std::string>(new std::string{"bPtrString"}));
When(Method(mock, returnMoveOnlyByRValRef)).AlwaysReturnValCapt(std::unique_ptr<std::string>(new std::string{"cPtrString"}));
When(Method(mock, returnAbstractTypeByRef)).AlwaysReturnValCapt(ConcreteType{"myConcreteType"});
}

ReferenceInterface& i = mock.get();
Expand Down
Loading