Skip to content

Commit

Permalink
Merge 435de0f into cd3a742
Browse files Browse the repository at this point in the history
  • Loading branch information
FranckRJ committed Apr 16, 2023
2 parents cd3a742 + 435de0f commit 16a5113
Show file tree
Hide file tree
Showing 4 changed files with 195 additions and 39 deletions.
78 changes: 51 additions & 27 deletions include/fakeit/Mock.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,23 @@

namespace fakeit {
namespace internal {
template<typename T, typename = void>
struct WithCommonVoid {
using type = T;
};

// The goal of this specialization is to replace all kinds of void (e.g. "const void") by a common type, "void".
// This is because some other parts of the code have specialization for "void", but these specializations only
// handle "void", and not "const void", so instead of modifying all these specialization to handle both types,
// we replace "const void" by "void" here.
template<typename T>
struct WithCommonVoid<T, typename std::enable_if<std::is_void<T>::value, void>::type> {
using type = void;
};

template<typename T>
using WithCommonVoid_t = typename WithCommonVoid<T>::type;
}
using namespace fakeit::internal;

template<typename C, typename ... baseclasses>
class Mock : public ActualInvocationsSource {
Expand All @@ -38,7 +53,7 @@ namespace fakeit {
// std::shared_ptr<C> getShared() {
// return impl.getShared();
// }

C &operator()() {
return get();
}
Expand All @@ -57,58 +72,67 @@ namespace fakeit {
return impl.stubDataMember(member, ctorargs...);
}

// const
template<int id, typename R, typename T, typename ... arglist, class = typename std::enable_if<
!std::is_void<R>::value && std::is_base_of<T, C>::value>::type>
MockingContext<R, arglist...> stub(R (T::*vMethod)(arglist...) const) {
auto methodWithoutConstVolatile = reinterpret_cast<R (T::*)(arglist...)>(vMethod);
std::is_base_of<T, C>::value>::type>
MockingContext<internal::WithCommonVoid_t<R>, arglist...> stub(R (T::*vMethod)(arglist...) const) {
auto methodWithoutConstVolatile = reinterpret_cast<internal::WithCommonVoid_t<R> (T::*)(arglist...)>(vMethod);
return impl.template stubMethod<id>(methodWithoutConstVolatile);
}

// volatile
template<int id, typename R, typename T, typename... arglist, class = typename std::enable_if<
!std::is_void<R>::value && std::is_base_of<T, C>::value>::type>
MockingContext<R, arglist...> stub(R(T::*vMethod)(arglist...) volatile) {
auto methodWithoutConstVolatile = reinterpret_cast<R(T::*)(arglist...)>(vMethod);
std::is_base_of<T, C>::value>::type>
MockingContext<internal::WithCommonVoid_t<R>, arglist...> stub(R(T::*vMethod)(arglist...) volatile) {
auto methodWithoutConstVolatile = reinterpret_cast<internal::WithCommonVoid_t<R>(T::*)(arglist...)>(vMethod);
return impl.template stubMethod<id>(methodWithoutConstVolatile);
}

// const volatile
template<int id, typename R, typename T, typename... arglist, class = typename std::enable_if<
!std::is_void<R>::value && std::is_base_of<T, C>::value>::type>
MockingContext<R, arglist...> stub(R(T::*vMethod)(arglist...) const volatile) {
auto methodWithoutConstVolatile = reinterpret_cast<R(T::*)(arglist...)>(vMethod);
std::is_base_of<T, C>::value>::type>
MockingContext<internal::WithCommonVoid_t<R>, arglist...> stub(R(T::*vMethod)(arglist...) const volatile) {
auto methodWithoutConstVolatile = reinterpret_cast<internal::WithCommonVoid_t<R>(T::*)(arglist...)>(vMethod);
return impl.template stubMethod<id>(methodWithoutConstVolatile);
}

// no qualifier
template<int id, typename R, typename T, typename... arglist, class = typename std::enable_if<
!std::is_void<R>::value && std::is_base_of<T, C>::value>::type>
MockingContext<R, arglist...> stub(R(T::*vMethod)(arglist...)) {
return impl.template stubMethod<id>(vMethod);
std::is_base_of<T, C>::value>::type>
MockingContext<internal::WithCommonVoid_t<R>, arglist...> stub(R(T::*vMethod)(arglist...)) {
auto methodWithoutConstVolatile = reinterpret_cast<internal::WithCommonVoid_t<R>(T::*)(arglist...)>(vMethod);
return impl.template stubMethod<id>(methodWithoutConstVolatile);
}

// ref
template<int id, typename R, typename T, typename... arglist, class = typename std::enable_if<
std::is_void<R>::value && std::is_base_of<T, C>::value>::type>
MockingContext<void, arglist...> stub(R(T::*vMethod)(arglist...) const) {
auto methodWithoutConstVolatile = reinterpret_cast<void (T::*)(arglist...)>(vMethod);
std::is_base_of<T, C>::value>::type>
MockingContext<internal::WithCommonVoid_t<R>, arglist...> stub(R(T::* vMethod)(arglist...) &) {
auto methodWithoutConstVolatile = reinterpret_cast<internal::WithCommonVoid_t<R>(T::*)(arglist...)>(vMethod);
return impl.template stubMethod<id>(methodWithoutConstVolatile);
}

// const ref
template<int id, typename R, typename T, typename... arglist, class = typename std::enable_if<
std::is_void<R>::value && std::is_base_of<T, C>::value>::type>
MockingContext<void, arglist...> stub(R(T::*vMethod)(arglist...) volatile) {
auto methodWithoutConstVolatile = reinterpret_cast<void (T::*)(arglist...)>(vMethod);
std::is_base_of<T, C>::value>::type>
MockingContext<internal::WithCommonVoid_t<R>, arglist...> stub(R(T::* vMethod)(arglist...) const&) {
auto methodWithoutConstVolatile = reinterpret_cast<internal::WithCommonVoid_t<R>(T::*)(arglist...)>(vMethod);
return impl.template stubMethod<id>(methodWithoutConstVolatile);
}

// rref
template<int id, typename R, typename T, typename... arglist, class = typename std::enable_if<
std::is_void<R>::value && std::is_base_of<T, C>::value>::type>
MockingContext<void, arglist...> stub(R(T::*vMethod)(arglist...) const volatile) {
auto methodWithoutConstVolatile = reinterpret_cast<void (T::*)(arglist...)>(vMethod);
std::is_base_of<T, C>::value>::type>
MockingContext<internal::WithCommonVoid_t<R>, arglist...> stub(R(T::* vMethod)(arglist...) &&) {
auto methodWithoutConstVolatile = reinterpret_cast<internal::WithCommonVoid_t<R>(T::*)(arglist...)>(vMethod);
return impl.template stubMethod<id>(methodWithoutConstVolatile);
}

// const rref
template<int id, typename R, typename T, typename... arglist, class = typename std::enable_if<
std::is_void<R>::value && std::is_base_of<T, C>::value>::type>
MockingContext<void, arglist...> stub(R(T::*vMethod)(arglist...)) {
auto methodWithoutConstVolatile = reinterpret_cast<void (T::*)(arglist...)>(vMethod);
std::is_base_of<T, C>::value>::type>
MockingContext<internal::WithCommonVoid_t<R>, arglist...> stub(R(T::* vMethod)(arglist...) const&&) {
auto methodWithoutConstVolatile = reinterpret_cast<internal::WithCommonVoid_t<R>(T::*)(arglist...)>(vMethod);
return impl.template stubMethod<id>(methodWithoutConstVolatile);
}

Expand All @@ -122,4 +146,4 @@ namespace fakeit {

};

}
}
33 changes: 24 additions & 9 deletions include/fakeit/Prototype.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,37 @@ namespace fakeit {
template<typename R, typename... Args>
struct Prototype<R(Args...)> {

typedef R Type(Args...);

typedef R ConstType(Args...) const;

template<class C>
struct MemberType {

typedef Type(C::*type);
typedef ConstType(C::*cosntType);
using Type = R (C::*)(Args...);
using ConstType = R (C::*)(Args...) const;
using RefType = R (C::*)(Args...) &;
using ConstRefType = R (C::*)(Args...) const&;
using RRefType = R (C::*)(Args...) &&;
using ConstRRefType = R (C::*)(Args...) const&&;

static Type get(Type t) {
return t;
}

static ConstType getConst(ConstType t) {
return t;
}

static type get(type t) {
static RefType getRef(RefType t) {
return t;
}

static cosntType getconst(cosntType t) {
static ConstRefType getConstRef(ConstRefType t) {
return t;
}

static RRefType getRRef(RRefType t) {
return t;
}

static ConstRRefType getConstRRef(ConstRRefType t) {
return t;
}

Expand All @@ -46,4 +62,3 @@ namespace fakeit {
};

}

28 changes: 26 additions & 2 deletions include/fakeit/api_macros.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,19 @@
fakeit::Prototype<prototype>::template MemberType<typename MOCK_TYPE(mock)>::get(&MOCK_TYPE(mock)::method)

#define CONST_OVERLOADED_METHOD_PTR(mock, method, prototype) \
fakeit::Prototype<prototype>::template MemberType<typename MOCK_TYPE(mock)>::getconst(&MOCK_TYPE(mock)::method)
fakeit::Prototype<prototype>::template MemberType<typename MOCK_TYPE(mock)>::getConst(&MOCK_TYPE(mock)::method)

#define REF_OVERLOADED_METHOD_PTR(mock, method, prototype) \
fakeit::Prototype<prototype>::MemberType<typename MOCK_TYPE(mock)>::getRef(&MOCK_TYPE(mock)::method)

#define CONST_REF_OVERLOADED_METHOD_PTR(mock, method, prototype) \
fakeit::Prototype<prototype>::MemberType<typename MOCK_TYPE(mock)>::getConstRef(&MOCK_TYPE(mock)::method)

#define RREF_OVERLOADED_METHOD_PTR(mock, method, prototype) \
fakeit::Prototype<prototype>::MemberType<typename MOCK_TYPE(mock)>::getRRef(&MOCK_TYPE(mock)::method)

#define CONST_RREF_OVERLOADED_METHOD_PTR(mock, method, prototype) \
fakeit::Prototype<prototype>::MemberType<typename MOCK_TYPE(mock)>::getConstRRef(&MOCK_TYPE(mock)::method)

#define Dtor(mock) \
(mock).dtor().setMethodDetails(#mock,"destructor")
Expand All @@ -25,6 +37,19 @@
#define ConstOverloadedMethod(mock, method, prototype) \
(mock).template stub<__COUNTER__>(CONST_OVERLOADED_METHOD_PTR( mock , method, prototype )).setMethodDetails(#mock,#method)

#define RefOverloadedMethod(mock, method, prototype) \
(mock).template stub<__COUNTER__>(REF_OVERLOADED_METHOD_PTR( mock , method, prototype )).setMethodDetails(#mock,#method)

#define ConstRefOverloadedMethod(mock, method, prototype) \
(mock).template stub<__COUNTER__>(CONST_REF_OVERLOADED_METHOD_PTR( mock , method, prototype )).setMethodDetails(#mock,#method)

#define RRefOverloadedMethod(mock, method, prototype) \
(mock).template stub<__COUNTER__>(RREF_OVERLOADED_METHOD_PTR( mock , method, prototype )).setMethodDetails(#mock,#method)

#define ConstRRefOverloadedMethod(mock, method, prototype) \
(mock).template stub<__COUNTER__>(CONST_RREF_OVERLOADED_METHOD_PTR( mock , method, prototype )).setMethodDetails(#mock,#method)


#define Verify(...) \
Verify( __VA_ARGS__ ).setFileInfo(__FILE__, __LINE__, __func__)

Expand All @@ -39,4 +64,3 @@

#define When(call) \
When(call)

95 changes: 94 additions & 1 deletion tests/overloadded_methods_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,12 @@ struct OverloadedMethods : tpunit::TestFixture {
tpunit::TestFixture(
TEST(OverloadedMethods::stub_overloaded_methods),
TEST(OverloadedMethods::stub_const_overloaded_methods),
TEST(OverloadedMethods::stub_overloaded_methods_with_templates<SomeInterface>)) {
TEST(OverloadedMethods::stub_overloaded_methods_with_templates<SomeInterface>),
TEST(OverloadedMethods::stub_modern_overloaded_methods),
TEST(OverloadedMethods::stub_modern_rref_overloaded_method),
TEST(OverloadedMethods::stub_modern_constrref_overloaded_method),
TEST(OverloadedMethods::stub_modern_overloaded_proc)
) {
}

void stub_overloaded_methods() {
Expand Down Expand Up @@ -94,4 +99,92 @@ struct OverloadedMethods : tpunit::TestFixture {
ASSERT_EQUAL(45, i.func(1));
}

struct SomeModernCppInterface {
virtual int func() & = 0;

virtual int func(int) & = 0;
virtual int func(int) const& = 0;
virtual int func(int) && = 0;
virtual int func(int) const&& = 0;

virtual void proc(int) & = 0;
virtual void proc(int) const& = 0;
virtual void proc(int) && = 0;
virtual void proc(int) const&& = 0;
};

void stub_modern_overloaded_methods() {
Mock<SomeModernCppInterface> mock;
When(RefOverloadedMethod(mock, func, int(int))).Return(1);
When(ConstRefOverloadedMethod(mock, func, int(int))).Return(2);

SomeModernCppInterface& refObj = mock.get();
const SomeModernCppInterface& refConstObj = mock.get();

ASSERT_EQUAL(1, refObj.func(10));
ASSERT_EQUAL(2, refConstObj.func(20));

Verify(RefOverloadedMethod(mock, func, int(int)).Using(10)).Exactly(1);
Verify(ConstRefOverloadedMethod(mock, func, int(int)).Using(20)).Exactly(1);

VerifyNoOtherInvocations(mock);
}

void stub_modern_rref_overloaded_method() {
Mock<SomeModernCppInterface> mock;
When(RefOverloadedMethod(mock, func, int(int))).Return(1);
When(RRefOverloadedMethod(mock, func, int(int))).Return(3);

SomeModernCppInterface& refObj = mock.get();

ASSERT_EQUAL(1, refObj.func(1));
ASSERT_EQUAL(3, std::move(refObj).func(1));

Verify(RefOverloadedMethod(mock, func, int(int))).Exactly(1);
Verify(RRefOverloadedMethod(mock, func, int(int))).Exactly(1);

VerifyNoOtherInvocations(mock);
}

void stub_modern_constrref_overloaded_method() {
Mock<SomeModernCppInterface> mock;
When(ConstRRefOverloadedMethod(mock, func, int(int))).Return(4);

const SomeModernCppInterface& refConstObj = mock.get();
ASSERT_EQUAL(4, std::move(refConstObj).func(1));

Verify(ConstRRefOverloadedMethod(mock, func, int(int)).Using(1)).Exactly(1);

VerifyNoOtherInvocations(mock);
}

void stub_modern_overloaded_proc() {
Mock<SomeModernCppInterface> mock;
int ret = 0;

When(ConstRRefOverloadedMethod(mock, proc, void(int))).Do([&](int){ret = 4;});
When(ConstRefOverloadedMethod(mock, proc, void(int))).Do([&](int){ret = 3;});
When(RRefOverloadedMethod(mock, proc, void(int))).Do([&](int){ret = 2;});
When(RefOverloadedMethod(mock, proc, void(int))).Do([&](int){ret = 1;});

SomeModernCppInterface& refObj = mock.get();
const SomeModernCppInterface& refConstObj = mock.get();

refObj.proc(0);
ASSERT_EQUAL(1, ret);
std::move(refObj).proc(0);
ASSERT_EQUAL(2, ret);
refConstObj.proc(0);
ASSERT_EQUAL(3, ret);
std::move(refConstObj).proc(0);
ASSERT_EQUAL(4, ret);

Verify(RefOverloadedMethod(mock, proc, void(int))).Exactly(1);
Verify(RRefOverloadedMethod(mock, proc, void(int))).Exactly(1);
Verify(ConstRefOverloadedMethod(mock, proc, void(int))).Exactly(1);
Verify(ConstRRefOverloadedMethod(mock, proc, void(int))).Exactly(1);

VerifyNoOtherInvocations(mock);
}

} __OverloadedMethods;

0 comments on commit 16a5113

Please sign in to comment.