diff --git a/build/sources.mk b/build/sources.mk index 45ac736f..21add538 100644 --- a/build/sources.mk +++ b/build/sources.mk @@ -13,6 +13,8 @@ CPP_SRCS += \ miscellaneous_tests.cpp \ msc_stubbing_multiple_values_tests.cpp \ msc_type_info_tests.cpp \ + multiple_translation_units_stub.cpp \ + multiple_translation_units_stub_test.cpp \ overloadded_methods_tests.cpp \ referece_types_tests.cpp \ remove_const_volatile_tests.cpp \ diff --git a/include/fakeit/Mock.hpp b/include/fakeit/Mock.hpp index 30821951..9d94308c 100644 --- a/include/fakeit/Mock.hpp +++ b/include/fakeit/Mock.hpp @@ -57,55 +57,55 @@ namespace fakeit { return impl.stubDataMember(member, ctorargs...); } - template::value && std::is_base_of::value>::type> MockingContext stub(R (T::*vMethod)(arglist...) const) { auto methodWithoutConstVolatile = reinterpret_cast(vMethod); return impl.template stubMethod(methodWithoutConstVolatile); } - template::value && std::is_base_of::value>::type> MockingContext stub(R(T::*vMethod)(arglist...) volatile) { auto methodWithoutConstVolatile = reinterpret_cast(vMethod); return impl.template stubMethod(methodWithoutConstVolatile); } - template::value && std::is_base_of::value>::type> MockingContext stub(R(T::*vMethod)(arglist...) const volatile) { auto methodWithoutConstVolatile = reinterpret_cast(vMethod); return impl.template stubMethod(methodWithoutConstVolatile); } - template::value && std::is_base_of::value>::type> MockingContext stub(R(T::*vMethod)(arglist...)) { return impl.template stubMethod(vMethod); } - template::value && std::is_base_of::value>::type> MockingContext stub(R(T::*vMethod)(arglist...) const) { auto methodWithoutConstVolatile = reinterpret_cast(vMethod); return impl.template stubMethod(methodWithoutConstVolatile); } - template::value && std::is_base_of::value>::type> MockingContext stub(R(T::*vMethod)(arglist...) volatile) { auto methodWithoutConstVolatile = reinterpret_cast(vMethod); return impl.template stubMethod(methodWithoutConstVolatile); } - template::value && std::is_base_of::value>::type> MockingContext stub(R(T::*vMethod)(arglist...) const volatile) { auto methodWithoutConstVolatile = reinterpret_cast(vMethod); return impl.template stubMethod(methodWithoutConstVolatile); } - template::value && std::is_base_of::value>::type> MockingContext stub(R(T::*vMethod)(arglist...)) { auto methodWithoutConstVolatile = reinterpret_cast(vMethod); diff --git a/include/fakeit/MockImpl.hpp b/include/fakeit/MockImpl.hpp index 2b8b63a2..bca8c53b 100644 --- a/include/fakeit/MockImpl.hpp +++ b/include/fakeit/MockImpl.hpp @@ -89,7 +89,7 @@ namespace fakeit { return DataMemberStubbingRoot(); } - template::value>::type> + template::value>::type> MockingContext stubMethod(R(T::*vMethod)(arglist...)) { return MockingContext(new UniqueMethodMockingContextImpl < id, R, arglist... > (*this, vMethod)); @@ -212,7 +212,7 @@ namespace fakeit { }; - template + template class UniqueMethodMockingContextImpl : public MethodMockingContextImpl { protected: @@ -304,7 +304,7 @@ namespace fakeit { return origMethodPtr; } - template + template RecordedMethodBody &stubMethodIfNotStubbed(DynamicProxy &proxy, R (C::*vMethod)(arglist...)) { if (!proxy.isMethodStubbed(vMethod)) { diff --git a/include/fakeit/api_macros.hpp b/include/fakeit/api_macros.hpp index 966b47af..e28d6c76 100644 --- a/include/fakeit/api_macros.hpp +++ b/include/fakeit/api_macros.hpp @@ -1,9 +1,19 @@ #pragma once +#include "mockutils/constexpr_hash.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::type @@ -17,13 +27,13 @@ (mock).dtor().setMethodDetails(#mock,"destructor") #define Method(mock, method) \ - (mock).template stub<__COUNTER__>(&MOCK_TYPE(mock)::method).setMethodDetails(#mock,#method) + (mock).template stub(&MOCK_TYPE(mock)::method).setMethodDetails(#mock,#method) #define OverloadedMethod(mock, method, prototype) \ - (mock).template stub<__COUNTER__>(OVERLOADED_METHOD_PTR( mock , method, prototype )).setMethodDetails(#mock,#method) + (mock).template stub(OVERLOADED_METHOD_PTR( mock , method, prototype )).setMethodDetails(#mock,#method) #define ConstOverloadedMethod(mock, method, prototype) \ - (mock).template stub<__COUNTER__>(CONST_OVERLOADED_METHOD_PTR( mock , method, prototype )).setMethodDetails(#mock,#method) + (mock).template stub(CONST_OVERLOADED_METHOD_PTR( mock , method, prototype )).setMethodDetails(#mock,#method) #define Verify(...) \ Verify( __VA_ARGS__ ).setFileInfo(__FILE__, __LINE__, __func__) diff --git a/include/mockutils/DynamicProxy.hpp b/include/mockutils/DynamicProxy.hpp index f1f62844..d0e71a26 100644 --- a/include/mockutils/DynamicProxy.hpp +++ b/include/mockutils/DynamicProxy.hpp @@ -27,9 +27,9 @@ namespace fakeit { class InvocationHandlers : public InvocationHandlerCollection { std::vector> &_methodMocks; - std::vector &_offsets; + std::vector &_offsets; - unsigned int getOffset(unsigned int id) const + unsigned int getOffset(size_t id) const { unsigned int offset = 0; for (; offset < _offsets.size(); offset++) { @@ -43,15 +43,15 @@ namespace fakeit { public: InvocationHandlers( std::vector> &methodMocks, - std::vector &offsets) : + std::vector &offsets) : _methodMocks(methodMocks), _offsets(offsets) { - for (std::vector::iterator it = _offsets.begin(); it != _offsets.end(); ++it) + for (auto it = _offsets.begin(); it != _offsets.end(); ++it) { *it = std::numeric_limits::max(); } } - Destructible *getInvocatoinHandlerPtrById(unsigned int id) override { + Destructible *getInvocatoinHandlerPtrById(size_t id) override { unsigned int offset = getOffset(id); std::shared_ptr ptr = _methodMocks[offset]; return ptr.get(); @@ -100,7 +100,7 @@ namespace fakeit { { } - template + template void stubMethod(R(C::*vMethod)(arglist...), MethodInvocationHandler *methodInvocationHandler) { auto offset = VTUtils::getOffset(vMethod); MethodProxyCreator creator; @@ -189,7 +189,7 @@ namespace fakeit { // std::vector> _methodMocks; std::vector> _members; - std::vector _offsets; + std::vector _offsets; InvocationHandlers _invocationHandlers; FakeObject &getFake() { diff --git a/include/mockutils/MethodProxy.hpp b/include/mockutils/MethodProxy.hpp index b9945c65..66ee39d6 100644 --- a/include/mockutils/MethodProxy.hpp +++ b/include/mockutils/MethodProxy.hpp @@ -6,7 +6,7 @@ namespace fakeit { struct MethodProxy { - MethodProxy(unsigned int id, unsigned int offset, void *vMethod) : + MethodProxy(size_t id, unsigned int offset, void *vMethod) : _id(id), _offset(offset), _vMethod(vMethod) { @@ -16,7 +16,7 @@ namespace fakeit { return _offset; } - unsigned int getId() const { + size_t getId() const { return _id; } @@ -25,7 +25,7 @@ namespace fakeit { } private: - unsigned int _id; + size_t _id; unsigned int _offset; void *_vMethod; }; diff --git a/include/mockutils/MethodProxyCreator.hpp b/include/mockutils/MethodProxyCreator.hpp index 4ae0dfe5..739d9865 100644 --- a/include/mockutils/MethodProxyCreator.hpp +++ b/include/mockutils/MethodProxyCreator.hpp @@ -11,7 +11,7 @@ namespace fakeit { struct InvocationHandlerCollection { static const unsigned int VT_COOKIE_INDEX = 0; - virtual Destructible *getInvocatoinHandlerPtrById(unsigned int index) = 0; + virtual Destructible *getInvocatoinHandlerPtrById(size_t index) = 0; static InvocationHandlerCollection *getInvocationHandlerCollection(void *instance) { VirtualTableBase &vt = VirtualTableBase::getVTable(instance); @@ -29,14 +29,14 @@ namespace fakeit { public: - template + template MethodProxy createMethodProxy(unsigned int offset) { return MethodProxy(id, offset, union_cast(&MethodProxyCreator::methodProxyX < id > )); } protected: - R methodProxy(unsigned int id, const typename fakeit::production_arg::type... args) { + R methodProxy(size_t id, const typename fakeit::production_arg::type... args) { InvocationHandlerCollection *invocationHandlerCollection = InvocationHandlerCollection::getInvocationHandlerCollection( this); MethodInvocationHandler *invocationHandler = @@ -45,7 +45,7 @@ namespace fakeit { return invocationHandler->handleMethodInvocation(std::forward::type>(args)...); } - template + template R methodProxyX(arglist ... args) { return methodProxy(id, std::forward::type>(args)...); } diff --git a/include/mockutils/VTUtils.hpp b/include/mockutils/VTUtils.hpp index 109fcdac..d85ba07f 100644 --- a/include/mockutils/VTUtils.hpp +++ b/include/mockutils/VTUtils.hpp @@ -63,7 +63,7 @@ namespace fakeit { } template - static unsigned int getVTSize() { + static size_t getVTSize() { struct Derrived : public C { virtual void endOfVt() { } diff --git a/include/mockutils/constexpr_hash.hpp b/include/mockutils/constexpr_hash.hpp new file mode 100644 index 00000000..0a3822c6 --- /dev/null +++ b/include/mockutils/constexpr_hash.hpp @@ -0,0 +1,17 @@ +#pragma once + +namespace fakeit { + + constexpr size_t _FNV_prime = sizeof(size_t) == 4 ? 16777619ULL : 1099511628211ULL; + constexpr size_t _FNV_offset_basis = sizeof(size_t) == 4 ? 2166136261ULL : 14695981039346656037ULL; + + constexpr size_t _constExprHashImpl(const char* str, size_t count) { + return count ? (_constExprHashImpl(str, count - 1) ^ str[count - 1]) * _FNV_prime : _FNV_offset_basis; + } + + template + constexpr size_t constExprHash(const char(&str)[N]) { + return _constExprHashImpl(str, N); + } + +} \ No newline at end of file diff --git a/include/mockutils/mscpp/VirtualTable.hpp b/include/mockutils/mscpp/VirtualTable.hpp index 029b5834..693a79c0 100644 --- a/include/mockutils/mscpp/VirtualTable.hpp +++ b/include/mockutils/mscpp/VirtualTable.hpp @@ -189,7 +189,7 @@ namespace fakeit { } void copyFrom(VirtualTable &from) { - unsigned int size = VTUtils::getVTSize(); + auto size = VTUtils::getVTSize(); for (unsigned int i = 0; i < size; i++) { _firstMethod[i] = from.getMethod(i); } @@ -233,7 +233,7 @@ namespace fakeit { setCookie(numOfCookies - 1, method); // use the last cookie } - unsigned int getSize() { + size_t getSize() { return VTUtils::getVTSize(); } @@ -259,7 +259,7 @@ namespace fakeit { static const unsigned int numOfCookies = 3; static void **buildVTArray() { - int vtSize = VTUtils::getVTSize(); + auto vtSize = VTUtils::getVTSize(); auto array = new void *[vtSize + numOfCookies + 1]{}; RTTICompleteObjectLocator *objectLocator = new RTTICompleteObjectLocator( typeid(C)); diff --git a/tests/FakeIt.vcxproj b/tests/FakeIt.vcxproj index 449a0568..b7c14392 100644 --- a/tests/FakeIt.vcxproj +++ b/tests/FakeIt.vcxproj @@ -78,6 +78,7 @@ + diff --git a/tests/all_tests.vcxproj b/tests/all_tests.vcxproj index 52a71b7b..3e0e0df4 100644 --- a/tests/all_tests.vcxproj +++ b/tests/all_tests.vcxproj @@ -135,6 +135,8 @@ + + @@ -151,6 +153,7 @@ + diff --git a/tests/multiple_translation_units_stub.cpp b/tests/multiple_translation_units_stub.cpp new file mode 100644 index 00000000..6f2dc0bb --- /dev/null +++ b/tests/multiple_translation_units_stub.cpp @@ -0,0 +1,12 @@ +#include "multiple_translation_units_stub.h" + + +void stubFunc2(fakeit::Mock& mock) +{ + fakeit::When(Method(mock, func2)).AlwaysReturn("String"); +} + +void stubFunc(fakeit::Mock& mock) +{ + fakeit::When(Method(mock, func)).AlwaysReturn(3); +} diff --git a/tests/multiple_translation_units_stub.h b/tests/multiple_translation_units_stub.h new file mode 100644 index 00000000..084cf17b --- /dev/null +++ b/tests/multiple_translation_units_stub.h @@ -0,0 +1,13 @@ +#pragma once + +#include + +#include "fakeit.hpp" + +struct SomeInterface { + virtual int func() = 0; + virtual std::string func2() = 0; +}; + +void stubFunc2(fakeit::Mock& mock); +void stubFunc(fakeit::Mock& mock); diff --git a/tests/multiple_translation_units_stub_test.cpp b/tests/multiple_translation_units_stub_test.cpp new file mode 100644 index 00000000..75cf43f4 --- /dev/null +++ b/tests/multiple_translation_units_stub_test.cpp @@ -0,0 +1,24 @@ +#include "tpunit++.hpp" +#include "fakeit.hpp" +#include "multiple_translation_units_stub.h" + +using namespace fakeit; + +struct MultipleTranslationUnitsStub : tpunit::TestFixture { + MultipleTranslationUnitsStub() + : tpunit::TestFixture( + TEST(MultipleTranslationUnitsStub::NoCollidingIds) + ) + {} + + void NoCollidingIds() { + Mock mock; + SomeInterface &i = mock.get(); + + stubFunc2(mock); + When(Method(mock, func)).Return(1); + + mock.get().func2(); // Uncatchable write access violation if ids collide + } + +} __MultipleTranslationUnitsStub;