Skip to content

Commit

Permalink
Use function pointers (dependent on the mocked function) as id for Me…
Browse files Browse the repository at this point in the history
…thod() instead of a hashed value of a counter.
  • Loading branch information
FranckRJ committed May 12, 2024
1 parent e91d6b8 commit 8e4c979
Show file tree
Hide file tree
Showing 14 changed files with 212 additions and 100 deletions.
16 changes: 8 additions & 8 deletions include/fakeit/Mock.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,63 +71,63 @@ namespace fakeit {
}

// const
template<size_t id, typename R, typename T, typename ... arglist, class = typename std::enable_if<
template<MethodIdType id, typename R, typename T, typename ... arglist, class = typename std::enable_if<
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<size_t id, typename R, typename T, typename... arglist, class = typename std::enable_if<
template<MethodIdType id, typename R, typename T, typename... arglist, class = typename std::enable_if<
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<size_t id, typename R, typename T, typename... arglist, class = typename std::enable_if<
template<MethodIdType id, typename R, typename T, typename... arglist, class = typename std::enable_if<
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<size_t id, typename R, typename T, typename... arglist, class = typename std::enable_if<
template<MethodIdType id, typename R, typename T, typename... arglist, class = typename std::enable_if<
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<size_t id, typename R, typename T, typename... arglist, class = typename std::enable_if<
template<MethodIdType id, typename R, typename T, typename... arglist, class = typename std::enable_if<
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<size_t id, typename R, typename T, typename... arglist, class = typename std::enable_if<
template<MethodIdType id, typename R, typename T, typename... arglist, class = typename std::enable_if<
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);
}

// rval ref
template<size_t id, typename R, typename T, typename... arglist, class = typename std::enable_if<
template<MethodIdType id, typename R, typename T, typename... arglist, class = typename std::enable_if<
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 rval ref
template<size_t id, typename R, typename T, typename... arglist, class = typename std::enable_if<
template<MethodIdType id, typename R, typename T, typename... arglist, class = typename std::enable_if<
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);
Expand Down
6 changes: 3 additions & 3 deletions include/fakeit/MockImpl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ namespace fakeit {
return DataMemberStubbingRoot<T, DataType>();
}

template<size_t id, typename R, typename T, typename ... arglist, class = typename std::enable_if<std::is_base_of<T, C>::value>::type>
template<MethodIdType id, typename R, typename T, typename ... arglist, class = typename std::enable_if<std::is_base_of<T, C>::value>::type>
MockingContext<R, arglist...> stubMethod(R(T::*vMethod)(arglist...)) {
return MockingContext<R, arglist...>(new UniqueMethodMockingContextImpl < id, R, arglist... >
(*this, vMethod));
Expand Down Expand Up @@ -226,7 +226,7 @@ namespace fakeit {
};


template<size_t id, typename R, typename ... arglist>
template<MethodIdType id, typename R, typename ... arglist>
class UniqueMethodMockingContextImpl : public MethodMockingContextImpl<R, arglist...> {
protected:

Expand Down Expand Up @@ -323,7 +323,7 @@ namespace fakeit {
return origMethodPtr;
}

template<size_t id, typename R, typename ... arglist>
template<MethodIdType id, typename R, typename ... arglist>
RecordedMethodBody<R, arglist...> &stubMethodIfNotStubbed(DynamicProxy<C, baseclasses...> &proxy,
R (C::*vMethod)(arglist...)) {
if (!proxy.isMethodStubbed(vMethod)) {
Expand Down
12 changes: 6 additions & 6 deletions include/fakeit/Prototype.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,27 +18,27 @@ namespace fakeit {
using RValRefType = R (C::*)(Args...) &&;
using ConstRValRefType = R (C::*)(Args...) const&&;

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

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

static RefType getRef(RefType t) {
static constexpr RefType getRef(RefType t) {
return t;
}

static ConstRefType getConstRef(ConstRefType t) {
static constexpr ConstRefType getConstRef(ConstRefType t) {
return t;
}

static RValRefType getRValRef(RValRefType t) {
static constexpr RValRefType getRValRef(RValRefType t) {
return t;
}

static ConstRValRefType getConstRValRef(ConstRValRefType t) {
static constexpr ConstRValRefType getConstRValRef(ConstRValRefType t) {
return t;
}

Expand Down
24 changes: 8 additions & 16 deletions include/fakeit/api_macros.hpp
Original file line number Diff line number Diff line change
@@ -1,19 +1,11 @@
#pragma once

#include "mockutils/constexpr_hash.hpp"
#include "mockutils/MethodProxy.hpp"

#ifdef _MSC_VER
#define __func__ __FUNCTION__
#endif

#define COUNTER_STRINGIFY( counter ) #counter

#define STUB_ID_STR( counter ) \
__FILE__ COUNTER_STRINGIFY(counter)

#define STUB_ID(counter) \
fakeit::constExprHash(STUB_ID_STR(counter))

#define MOCK_TYPE(mock) \
std::remove_reference<decltype((mock).get())>::type

Expand All @@ -39,25 +31,25 @@
(mock).dtor().setMethodDetails(#mock,"destructor")

#define Method(mock, method) \
(mock).template stub<STUB_ID(__COUNTER__)>(&MOCK_TYPE(mock)::method).setMethodDetails(#mock,#method)
(mock).template stub<&fakeit::funcIdMethod<decltype(&MOCK_TYPE(mock)::method), &MOCK_TYPE(mock)::method>>(&MOCK_TYPE(mock)::method).setMethodDetails(#mock,#method)

#define OverloadedMethod(mock, method, prototype) \
(mock).template stub<STUB_ID(__COUNTER__)>(OVERLOADED_METHOD_PTR( mock , method, prototype )).setMethodDetails(#mock,#method)
(mock).template stub<&fakeit::funcIdMethod<decltype(OVERLOADED_METHOD_PTR( mock , method, prototype )), &MOCK_TYPE(mock)::method>>(OVERLOADED_METHOD_PTR( mock , method, prototype )).setMethodDetails(#mock,#method)

#define ConstOverloadedMethod(mock, method, prototype) \
(mock).template stub<STUB_ID(__COUNTER__)>(CONST_OVERLOADED_METHOD_PTR( mock , method, prototype )).setMethodDetails(#mock,#method)
(mock).template stub<&fakeit::funcIdMethod<decltype(CONST_OVERLOADED_METHOD_PTR( mock , method, prototype )), &MOCK_TYPE(mock)::method>>(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)
(mock).template stub<&fakeit::funcIdMethod<decltype(REF_OVERLOADED_METHOD_PTR( mock , method, prototype )), &MOCK_TYPE(mock)::method>>(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)
(mock).template stub<&fakeit::funcIdMethod<decltype(CONST_REF_OVERLOADED_METHOD_PTR( mock , method, prototype )), &MOCK_TYPE(mock)::method>>(CONST_REF_OVERLOADED_METHOD_PTR( mock , method, prototype )).setMethodDetails(#mock,#method)

#define RValRefOverloadedMethod(mock, method, prototype) \
(mock).template stub<__COUNTER__>(R_VAL_REF_OVERLOADED_METHOD_PTR( mock , method, prototype )).setMethodDetails(#mock,#method)
(mock).template stub<&fakeit::funcIdMethod<decltype(R_VAL_REF_OVERLOADED_METHOD_PTR( mock , method, prototype )), &MOCK_TYPE(mock)::method>>(R_VAL_REF_OVERLOADED_METHOD_PTR( mock , method, prototype )).setMethodDetails(#mock,#method)

#define ConstRValRefOverloadedMethod(mock, method, prototype) \
(mock).template stub<__COUNTER__>(CONST_R_VAL_REF_OVERLOADED_METHOD_PTR( mock , method, prototype )).setMethodDetails(#mock,#method)
(mock).template stub<&fakeit::funcIdMethod<decltype(CONST_R_VAL_REF_OVERLOADED_METHOD_PTR( mock , method, prototype )), &MOCK_TYPE(mock)::method>>(CONST_R_VAL_REF_OVERLOADED_METHOD_PTR( mock , method, prototype )).setMethodDetails(#mock,#method)

#define Verify(...) \
Verify( __VA_ARGS__ ).setFileInfo(__FILE__, __LINE__, __func__)
Expand Down
22 changes: 10 additions & 12 deletions include/mockutils/DynamicProxy.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,8 @@
#include <vector>
#include <array>
#include <new>
#include <limits>

#include "mockutils/VirtualTable.hpp"
#include "mockutils/union_cast.hpp"
#include "mockutils/MethodInvocationHandler.hpp"
#include "mockutils/VTUtils.hpp"
#include "mockutils/FakeObject.hpp"
Expand All @@ -28,9 +26,9 @@ namespace fakeit {

class InvocationHandlers : public InvocationHandlerCollection {
std::vector<std::shared_ptr<Destructible>> &_methodMocks;
std::vector<size_t> &_offsets;
std::vector<MethodIdType> &_offsets;

unsigned int getOffset(size_t id) const
unsigned int getOffset(MethodIdType id) const
{
unsigned int offset = 0;
for (; offset < _offsets.size(); offset++) {
Expand All @@ -42,11 +40,11 @@ namespace fakeit {
}

public:
InvocationHandlers(std::vector<std::shared_ptr<Destructible>> &methodMocks, std::vector<size_t> &offsets)
InvocationHandlers(std::vector<std::shared_ptr<Destructible>> &methodMocks, std::vector<MethodIdType> &offsets)
: _methodMocks(methodMocks), _offsets(offsets) {
}

Destructible *getInvocatoinHandlerPtrById(size_t id) override {
Destructible *getInvocatoinHandlerPtrById(MethodIdType id) override {
unsigned int offset = getOffset(id);
std::shared_ptr<Destructible> ptr = _methodMocks[offset];
return ptr.get();
Expand All @@ -62,7 +60,7 @@ namespace fakeit {
DynamicProxy(C &inst) :
_instancePtr(&inst),
_methodMocks(VTUtils::getVTSize<C>()),
_offsets(VTUtils::getVTSize<C>(), std::numeric_limits<int>::max()),
_offsets(VTUtils::getVTSize<C>(), &funcIdNotStubbed),
_invocationHandlers(_methodMocks, _offsets) {
_originalVt.copyFrom(VirtualTable<C, baseclasses...>::getVTable(*_instancePtr));
_originalVt.setCookie(InvocationHandlerCollection::VtCookieIndex, &_invocationHandlers);
Expand Down Expand Up @@ -108,11 +106,11 @@ namespace fakeit {
{
}

template<size_t id, typename R, typename ... arglist>
template<MethodIdType id, typename R, typename ... arglist>
void stubMethod(R(C::*vMethod)(arglist...), MethodInvocationHandler<R, arglist...> *methodInvocationHandler) {
auto offset = VTUtils::getOffset(vMethod);
MethodProxyCreator<R, arglist...> creator;
bind(creator.template createMethodProxy<id + 1>(offset), methodInvocationHandler);
bind(creator.template createMethodProxy<id>(offset), methodInvocationHandler);
}

void stubDtor(MethodInvocationHandler<void> *methodInvocationHandler) {
Expand All @@ -125,9 +123,9 @@ namespace fakeit {
// For GCC / Clang, the destructor is directly called, like normal methods, so we use the member-function
// version.
#ifdef _MSC_VER
bindDtor(creator.createMethodProxyStatic<0>(offset), methodInvocationHandler);
bindDtor(creator.createMethodProxyStatic<&funcIdDestructor>(offset), methodInvocationHandler);
#else
bindDtor(creator.createMethodProxy<0>(offset), methodInvocationHandler);
bindDtor(creator.createMethodProxy<&funcIdDestructor>(offset), methodInvocationHandler);
#endif
}

Expand Down Expand Up @@ -217,7 +215,7 @@ namespace fakeit {
//
std::vector<std::shared_ptr<Destructible>> _methodMocks;
std::vector<std::shared_ptr<Destructible>> _members;
std::vector<size_t> _offsets;
std::vector<MethodIdType> _offsets;
InvocationHandlers _invocationHandlers;

FakeObject<C, baseclasses...> &getFake() {
Expand Down
22 changes: 18 additions & 4 deletions include/mockutils/MethodProxy.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,23 @@

namespace fakeit {

// A bunch of functions used by the method id mechanism. We use a pointer to them to represent the ID of a unique
// mockable method.
// Those methods are never called, we only use their address, this is why they are excluded from code coverage analysis.
/* LCOV_EXCL_START */
template<typename MethodPtrType, MethodPtrType MethodPtr>
void funcIdMethod() {}

inline void funcIdDestructor() {}

inline void funcIdNotStubbed() {}
/* LCOV_EXCL_STOP */

using MethodIdType = void(*)();

struct MethodProxy {

MethodProxy(size_t id, unsigned int offset, void *vMethod) :
MethodProxy(MethodIdType id, unsigned int offset, void *vMethod) :
_id(id),
_offset(offset),
_vMethod(vMethod) {
Expand All @@ -16,7 +30,7 @@ namespace fakeit {
return _offset;
}

size_t getId() const {
MethodIdType getId() const {
return _id;
}

Expand All @@ -25,8 +39,8 @@ namespace fakeit {
}

private:
size_t _id;
MethodIdType _id;
unsigned int _offset;
void *_vMethod;
};
}
}
14 changes: 7 additions & 7 deletions include/mockutils/MethodProxyCreator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ namespace fakeit {
struct InvocationHandlerCollection {
static const unsigned int VtCookieIndex = 0;

virtual Destructible *getInvocatoinHandlerPtrById(size_t index) = 0;
virtual Destructible *getInvocatoinHandlerPtrById(MethodIdType id) = 0;

static InvocationHandlerCollection *getInvocationHandlerCollection(void *instance) {
VirtualTableBase &vt = VirtualTableBase::getVTable(instance);
Expand All @@ -29,19 +29,19 @@ namespace fakeit {

public:

template<size_t id>
template<MethodIdType id>
MethodProxy createMethodProxy(unsigned int offset) {
return MethodProxy(id, offset, union_cast<void *>(&MethodProxyCreator::methodProxyX < id > ));
}

template<unsigned int id>
template<MethodIdType id>
MethodProxy createMethodProxyStatic(unsigned int offset) {
return MethodProxy(id, offset, union_cast<void *>(&MethodProxyCreator::methodProxyXStatic < id > ));
}

protected:

R methodProxy(size_t id, const typename fakeit::production_arg<arglist>::type... args) {
R methodProxy(MethodIdType id, const typename fakeit::production_arg<arglist>::type... args) {
InvocationHandlerCollection *invocationHandlerCollection = InvocationHandlerCollection::getInvocationHandlerCollection(
this);
MethodInvocationHandler<R, arglist...> *invocationHandler =
Expand All @@ -50,12 +50,12 @@ namespace fakeit {
return invocationHandler->handleMethodInvocation(std::forward<const typename fakeit::production_arg<arglist>::type>(args)...);
}

template<size_t id>
template<MethodIdType id>
R methodProxyX(arglist ... args) {
return methodProxy(id, std::forward<const typename fakeit::production_arg<arglist>::type>(args)...);
}

static R methodProxyStatic(void* instance, unsigned int id, const typename fakeit::production_arg<arglist>::type... args) {
static R methodProxyStatic(void* instance, MethodIdType id, const typename fakeit::production_arg<arglist>::type... args) {
InvocationHandlerCollection *invocationHandlerCollection = InvocationHandlerCollection::getInvocationHandlerCollection(
instance);
MethodInvocationHandler<R, arglist...> *invocationHandler =
Expand All @@ -64,7 +64,7 @@ namespace fakeit {
return invocationHandler->handleMethodInvocation(std::forward<const typename fakeit::production_arg<arglist>::type>(args)...);
}

template<int id>
template<MethodIdType id>
static R methodProxyXStatic(void* instance, arglist ... args) {
return methodProxyStatic(instance, id, std::forward<const typename fakeit::production_arg<arglist>::type>(args)...);
}
Expand Down
2 changes: 1 addition & 1 deletion include/mockutils/VTUtils.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ namespace fakeit {
}

template<typename C>
static size_t getVTSize() {
static unsigned int getVTSize() {
struct Derrived : public C {
virtual void endOfVt() {
}
Expand Down
17 changes: 0 additions & 17 deletions include/mockutils/constexpr_hash.hpp

This file was deleted.

Loading

0 comments on commit 8e4c979

Please sign in to comment.