Skip to content

Commit

Permalink
Merge 63b8208 into fa53ef2
Browse files Browse the repository at this point in the history
  • Loading branch information
FranckRJ committed Apr 14, 2024
2 parents fa53ef2 + 63b8208 commit c5ded46
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 61 deletions.
80 changes: 48 additions & 32 deletions include/fakeit/StubbingProgress.hpp
Expand Up @@ -38,35 +38,60 @@ namespace fakeit {
template<int N>
struct ParamWalker;

} // namespace helper
template<typename Self, typename R, typename ... arglist>
struct BasicDoImplHelper {
virtual ~BasicDoImplHelper() FAKEIT_THROWS {
}

virtual Self& Do(std::function<R(const typename fakeit::test_arg<arglist>::type...)> method) {
return DoImpl(new Repeat<R, arglist...>(method));
}

template<typename R, typename ... arglist>
struct MethodStubbingProgress {
protected:
virtual Self& DoImpl(Action<R, arglist...> *action) = 0;
};

virtual ~MethodStubbingProgress() FAKEIT_THROWS {
}
template<typename Self, typename R, bool RIsARef, typename ... arglist>
struct BasicReturnImplHelper {};

template<typename U = R>
typename std::enable_if<!std::is_reference<U>::value, MethodStubbingProgress<R, arglist...> &>::type
Return(const R &r) {
return Do([r](const typename fakeit::test_arg<arglist>::type...) -> R { return r; });
}
// If R is a reference.
template<typename Self, typename R, typename ... arglist>
struct BasicReturnImplHelper<Self, R, true, arglist...> : public BasicDoImplHelper<Self, R, arglist...> {
using BasicDoImplHelper<Self, R, arglist...>::Do;

template<typename U = R>
typename std::enable_if<std::is_reference<U>::value, MethodStubbingProgress<R, arglist...> &>::type
Return(const R &r) {
return Do([&r](const typename fakeit::test_arg<arglist>::type...) -> R { return r; });
}
Self& Return(const R& r) {
return Do([&r](const typename fakeit::test_arg<arglist>::type...) -> R { return r; });
}
};

template<typename U = R>
typename std::enable_if<!std::is_copy_constructible<U>::value, MethodStubbingProgress<R, arglist...>&>::type
Return(R&& r) {
auto store = std::make_shared<R>(std::move(r)); // work around for lack of move_only_funciton( C++23) - move into a shared_ptr which we can copy.
return Do([store](const typename fakeit::test_arg<arglist>::type...) mutable -> R {
return std::move(*store);
});
}
// If R is not a reference.
template<typename Self, typename R, typename ... arglist>
struct BasicReturnImplHelper<Self, R, false, arglist...> : public BasicDoImplHelper<Self, R, arglist...> {
using BasicDoImplHelper<Self, R, arglist...>::Do;

Self& Return(const R& r) {
return Do([r](const typename fakeit::test_arg<arglist>::type...) -> R { return r; });
}

Self& Return(R&& r) {
auto store = std::make_shared<R>(std::move(r)); // work around for lack of move_only_funciton( C++23) - move into a shared_ptr which we can copy.
return Do([store](const typename fakeit::test_arg<arglist>::type...) mutable -> R {
return std::move(*store);
});
}
};
} // namespace helper


template<typename R, typename ... arglist>
struct MethodStubbingProgress : public helper::BasicReturnImplHelper<MethodStubbingProgress<R, arglist...>, R, std::is_reference<R>::value, arglist...> {

protected:
using helper::BasicReturnImplHelper<MethodStubbingProgress<R, arglist...>, R, std::is_reference<R>::value, arglist...>::DoImpl;

public:
using helper::BasicReturnImplHelper<MethodStubbingProgress<R, arglist...>, R, std::is_reference<R>::value, arglist...>::Do;
using helper::BasicReturnImplHelper<MethodStubbingProgress<R, arglist...>, R, std::is_reference<R>::value, arglist...>::Return;

MethodStubbingProgress<R, arglist...> &
Return(const Quantifier<R> &q) {
Expand Down Expand Up @@ -142,11 +167,6 @@ namespace fakeit {
std::forward<valuelist>(arg_vals)...));
}

virtual MethodStubbingProgress<R, arglist...> &
Do(std::function<R(const typename fakeit::test_arg<arglist>::type...)> method) {
return DoImpl(new Repeat<R, arglist...>(method));
}

template<typename F>
MethodStubbingProgress<R, arglist...> &
Do(const Quantifier<F> &q) {
Expand All @@ -164,10 +184,6 @@ namespace fakeit {
DoImpl(new RepeatForever<R, arglist...>(method));
}

protected:

virtual MethodStubbingProgress<R, arglist...> &DoImpl(Action<R, arglist...> *action) = 0;

private:
MethodStubbingProgress &operator=(const MethodStubbingProgress &other) = delete;

Expand Down
58 changes: 30 additions & 28 deletions tests/move_only_return_tests.cpp
Expand Up @@ -16,35 +16,33 @@ using namespace fakeit;

struct MoveOnlyReturnTests: tpunit::TestFixture {

class AbstractType {
public:
virtual ~AbstractType() = default;
virtual void foo() = 0;
};

class ConcreteType : public AbstractType {
class MoveOnlyType {
public:
int state;
ConcreteType(int value) :
MoveOnlyType(int value) :
state(value) {
}
ConcreteType(const ConcreteType&) = delete;
ConcreteType(ConcreteType&&) = default;

void foo() override {
}
MoveOnlyType(const MoveOnlyType&) = delete;
MoveOnlyType(MoveOnlyType&&) = default;

bool operator==(const ConcreteType& other) const {
bool operator==(const MoveOnlyType& other) const {
return (other.state == this->state);
}

};

struct ReferenceInterface {
struct MoveOnlyInterface {
virtual std::unique_ptr<std::string> returnMoveOnlyUniqueString() = 0;
virtual ConcreteType returnMoveOnlyConcreteTypeByRef() = 0;
virtual MoveOnlyType returnMoveOnlyConcreteType() = 0;
virtual std::vector<MoveOnlyType> returnVectorOfMoveOnly() = 0;
};

static std::vector<MoveOnlyType> constructVectorOfMoveOnly(int i) {
std::vector<MoveOnlyType> vectorOfMoveOnly;
vectorOfMoveOnly.emplace_back(i);
return vectorOfMoveOnly;
}

MoveOnlyReturnTests() :
tpunit::TestFixture(
//
Expand All @@ -55,33 +53,37 @@ struct MoveOnlyReturnTests: tpunit::TestFixture {
}

void explicitStubbingReturnValuesFromTemporary() {
Mock<ReferenceInterface> mock;
Mock<MoveOnlyInterface> mock;

When(Method(mock, returnMoveOnlyUniqueString)).Return(std::unique_ptr<std::string>(new std::string("value")));
When(Method(mock, returnMoveOnlyConcreteTypeByRef)).Return(ConcreteType(10));
When(Method(mock, returnMoveOnlyConcreteType)).Return(MoveOnlyType(10));
When(Method(mock, returnVectorOfMoveOnly)).Return(constructVectorOfMoveOnly(5));

ReferenceInterface & i = mock.get();
MoveOnlyInterface & i = mock.get();

ASSERT_EQUAL("value", *i.returnMoveOnlyUniqueString());

ASSERT_EQUAL(ConcreteType(10), i.returnMoveOnlyConcreteTypeByRef());
ASSERT_EQUAL(MoveOnlyType(10), i.returnMoveOnlyConcreteType());
ASSERT_EQUAL(constructVectorOfMoveOnly(5), i.returnVectorOfMoveOnly());
}

void explicitStubbingReturnValuesFromMove() {
Mock<ReferenceInterface> mock;
Mock<MoveOnlyInterface> mock;

ConcreteType c(10);
MoveOnlyType c(10);
std::unique_ptr<std::string> string(new std::string("value"));
std::vector<MoveOnlyType> vectorOfC = constructVectorOfMoveOnly(5);

When(Method(mock, returnMoveOnlyUniqueString)).Return(std::move(string));
When(Method(mock, returnMoveOnlyConcreteTypeByRef)).Return(std::move(c));
When(Method(mock, returnMoveOnlyConcreteType)).Return(std::move(c));
When(Method(mock, returnVectorOfMoveOnly)).Return(std::move(vectorOfC));

ASSERT_FALSE(string); // check move did happen
ASSERT_EQUAL(string, nullptr); // check move did happen
ASSERT_TRUE(vectorOfC.empty()); // check move did happen

ReferenceInterface& i = mock.get();
MoveOnlyInterface& i = mock.get();

ASSERT_EQUAL(std::string("value"), *i.returnMoveOnlyUniqueString());

ASSERT_EQUAL(ConcreteType(10), i.returnMoveOnlyConcreteTypeByRef());
ASSERT_EQUAL(MoveOnlyType(10), i.returnMoveOnlyConcreteType());
ASSERT_EQUAL(constructVectorOfMoveOnly(5), i.returnVectorOfMoveOnly());
}
} __MoveOnlyReturnTests;
3 changes: 2 additions & 1 deletion tests/stubbing_tests.cpp
Expand Up @@ -412,7 +412,8 @@ struct BasicStubbing : tpunit::TestFixture {
void stub_a_method_with_mutable_lambda_delegate_always() {
Mock<SomeInterface> mock;

When(Method(mock, funcNoArgs)).AlwaysDo([mutableVar = 0]() mutable {
int mutableVar = 0;
When(Method(mock, funcNoArgs)).AlwaysDo([mutableVar]() mutable {
return ++mutableVar;
});

Expand Down

0 comments on commit c5ded46

Please sign in to comment.