diff --git a/include/fakeit/Mock.hpp b/include/fakeit/Mock.hpp index 4cae42e3..0368ee1e 100644 --- a/include/fakeit/Mock.hpp +++ b/include/fakeit/Mock.hpp @@ -71,7 +71,7 @@ namespace fakeit { } // const - template::value>::type> MockingContext, arglist...> stub(R (T::*vMethod)(arglist...) const) { auto methodWithoutConstVolatile = reinterpret_cast (T::*)(arglist...)>(vMethod); @@ -79,7 +79,7 @@ namespace fakeit { } // volatile - template::value>::type> MockingContext, arglist...> stub(R(T::*vMethod)(arglist...) volatile) { auto methodWithoutConstVolatile = reinterpret_cast(T::*)(arglist...)>(vMethod); @@ -87,7 +87,7 @@ namespace fakeit { } // const volatile - template::value>::type> MockingContext, arglist...> stub(R(T::*vMethod)(arglist...) const volatile) { auto methodWithoutConstVolatile = reinterpret_cast(T::*)(arglist...)>(vMethod); @@ -95,7 +95,7 @@ namespace fakeit { } // no qualifier - template::value>::type> MockingContext, arglist...> stub(R(T::*vMethod)(arglist...)) { auto methodWithoutConstVolatile = reinterpret_cast(T::*)(arglist...)>(vMethod); @@ -103,7 +103,7 @@ namespace fakeit { } // ref - template::value>::type> MockingContext, arglist...> stub(R(T::*vMethod)(arglist...) &) { auto methodWithoutConstVolatile = reinterpret_cast(T::*)(arglist...)>(vMethod); @@ -111,7 +111,7 @@ namespace fakeit { } // const ref - template::value>::type> MockingContext, arglist...> stub(R(T::*vMethod)(arglist...) const&) { auto methodWithoutConstVolatile = reinterpret_cast(T::*)(arglist...)>(vMethod); @@ -119,7 +119,7 @@ namespace fakeit { } // rval ref - template::value>::type> MockingContext, arglist...> stub(R(T::*vMethod)(arglist...) &&) { auto methodWithoutConstVolatile = reinterpret_cast(T::*)(arglist...)>(vMethod); @@ -127,7 +127,7 @@ namespace fakeit { } // const rval ref - template::value>::type> MockingContext, arglist...> stub(R(T::*vMethod)(arglist...) const&&) { auto methodWithoutConstVolatile = reinterpret_cast(T::*)(arglist...)>(vMethod); diff --git a/include/fakeit/MockImpl.hpp b/include/fakeit/MockImpl.hpp index 891c337f..ee4ce5b6 100644 --- a/include/fakeit/MockImpl.hpp +++ b/include/fakeit/MockImpl.hpp @@ -101,7 +101,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)); @@ -226,7 +226,7 @@ namespace fakeit { }; - template + template class UniqueMethodMockingContextImpl : public MethodMockingContextImpl { protected: @@ -323,7 +323,7 @@ namespace fakeit { return origMethodPtr; } - template + template RecordedMethodBody &stubMethodIfNotStubbed(DynamicProxy &proxy, R (C::*vMethod)(arglist...)) { if (!proxy.isMethodStubbed(vMethod)) { diff --git a/include/fakeit/Prototype.hpp b/include/fakeit/Prototype.hpp index 8b86f08b..4367aca1 100644 --- a/include/fakeit/Prototype.hpp +++ b/include/fakeit/Prototype.hpp @@ -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; } diff --git a/include/fakeit/api_macros.hpp b/include/fakeit/api_macros.hpp index ae89b756..74e18a5d 100644 --- a/include/fakeit/api_macros.hpp +++ b/include/fakeit/api_macros.hpp @@ -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::type @@ -39,25 +31,25 @@ (mock).dtor().setMethodDetails(#mock,"destructor") #define Method(mock, method) \ - (mock).template stub(&MOCK_TYPE(mock)::method).setMethodDetails(#mock,#method) + (mock).template stub<&fakeit::funcIdMethod>(&MOCK_TYPE(mock)::method).setMethodDetails(#mock,#method) #define OverloadedMethod(mock, method, prototype) \ - (mock).template stub(OVERLOADED_METHOD_PTR( mock , method, prototype )).setMethodDetails(#mock,#method) + (mock).template stub<&fakeit::funcIdMethod>(OVERLOADED_METHOD_PTR( mock , method, prototype )).setMethodDetails(#mock,#method) #define ConstOverloadedMethod(mock, method, prototype) \ - (mock).template stub(CONST_OVERLOADED_METHOD_PTR( mock , method, prototype )).setMethodDetails(#mock,#method) + (mock).template stub<&fakeit::funcIdMethod>(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>(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>(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>(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>(CONST_R_VAL_REF_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 e1dcde6c..f103b226 100644 --- a/include/mockutils/DynamicProxy.hpp +++ b/include/mockutils/DynamicProxy.hpp @@ -13,10 +13,8 @@ #include #include #include -#include #include "mockutils/VirtualTable.hpp" -#include "mockutils/union_cast.hpp" #include "mockutils/MethodInvocationHandler.hpp" #include "mockutils/VTUtils.hpp" #include "mockutils/FakeObject.hpp" @@ -28,9 +26,9 @@ namespace fakeit { class InvocationHandlers : public InvocationHandlerCollection { std::vector> &_methodMocks; - std::vector &_offsets; + std::vector &_offsets; - unsigned int getOffset(size_t id) const + unsigned int getOffset(MethodIdType id) const { unsigned int offset = 0; for (; offset < _offsets.size(); offset++) { @@ -42,11 +40,11 @@ namespace fakeit { } public: - InvocationHandlers(std::vector> &methodMocks, std::vector &offsets) + InvocationHandlers(std::vector> &methodMocks, std::vector &offsets) : _methodMocks(methodMocks), _offsets(offsets) { } - Destructible *getInvocatoinHandlerPtrById(size_t id) override { + Destructible *getInvocatoinHandlerPtrById(MethodIdType id) override { unsigned int offset = getOffset(id); std::shared_ptr ptr = _methodMocks[offset]; return ptr.get(); @@ -62,7 +60,7 @@ namespace fakeit { DynamicProxy(C &inst) : _instancePtr(&inst), _methodMocks(VTUtils::getVTSize()), - _offsets(VTUtils::getVTSize(), std::numeric_limits::max()), + _offsets(VTUtils::getVTSize(), &funcIdNotStubbed), _invocationHandlers(_methodMocks, _offsets) { _originalVt.copyFrom(VirtualTable::getVTable(*_instancePtr)); _originalVt.setCookie(InvocationHandlerCollection::VtCookieIndex, &_invocationHandlers); @@ -108,11 +106,11 @@ namespace fakeit { { } - template + template void stubMethod(R(C::*vMethod)(arglist...), MethodInvocationHandler *methodInvocationHandler) { auto offset = VTUtils::getOffset(vMethod); MethodProxyCreator creator; - bind(creator.template createMethodProxy(offset), methodInvocationHandler); + bind(creator.template createMethodProxy(offset), methodInvocationHandler); } void stubDtor(MethodInvocationHandler *methodInvocationHandler) { @@ -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 } @@ -217,7 +215,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 66ee39d6..16f515d8 100644 --- a/include/mockutils/MethodProxy.hpp +++ b/include/mockutils/MethodProxy.hpp @@ -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 + 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) { @@ -16,7 +30,7 @@ namespace fakeit { return _offset; } - size_t getId() const { + MethodIdType getId() const { return _id; } @@ -25,8 +39,8 @@ namespace fakeit { } private: - size_t _id; + MethodIdType _id; unsigned int _offset; void *_vMethod; }; -} \ No newline at end of file +} diff --git a/include/mockutils/MethodProxyCreator.hpp b/include/mockutils/MethodProxyCreator.hpp index 23f64953..464bfa4c 100644 --- a/include/mockutils/MethodProxyCreator.hpp +++ b/include/mockutils/MethodProxyCreator.hpp @@ -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); @@ -29,19 +29,19 @@ namespace fakeit { public: - template + template MethodProxy createMethodProxy(unsigned int offset) { return MethodProxy(id, offset, union_cast(&MethodProxyCreator::methodProxyX < id > )); } - template + template MethodProxy createMethodProxyStatic(unsigned int offset) { return MethodProxy(id, offset, union_cast(&MethodProxyCreator::methodProxyXStatic < id > )); } protected: - R methodProxy(size_t id, const typename fakeit::production_arg::type... args) { + R methodProxy(MethodIdType id, const typename fakeit::production_arg::type... args) { InvocationHandlerCollection *invocationHandlerCollection = InvocationHandlerCollection::getInvocationHandlerCollection( this); MethodInvocationHandler *invocationHandler = @@ -50,12 +50,12 @@ namespace fakeit { return invocationHandler->handleMethodInvocation(std::forward::type>(args)...); } - template + template R methodProxyX(arglist ... args) { return methodProxy(id, std::forward::type>(args)...); } - static R methodProxyStatic(void* instance, unsigned int id, const typename fakeit::production_arg::type... args) { + static R methodProxyStatic(void* instance, MethodIdType id, const typename fakeit::production_arg::type... args) { InvocationHandlerCollection *invocationHandlerCollection = InvocationHandlerCollection::getInvocationHandlerCollection( instance); MethodInvocationHandler *invocationHandler = @@ -64,7 +64,7 @@ namespace fakeit { return invocationHandler->handleMethodInvocation(std::forward::type>(args)...); } - template + template static R methodProxyXStatic(void* instance, arglist ... args) { return methodProxyStatic(instance, id, std::forward::type>(args)...); } diff --git a/include/mockutils/VTUtils.hpp b/include/mockutils/VTUtils.hpp index cc0268e1..3256b711 100644 --- a/include/mockutils/VTUtils.hpp +++ b/include/mockutils/VTUtils.hpp @@ -65,7 +65,7 @@ namespace fakeit { } template - static size_t getVTSize() { + static unsigned int getVTSize() { struct Derrived : public C { virtual void endOfVt() { } diff --git a/include/mockutils/constexpr_hash.hpp b/include/mockutils/constexpr_hash.hpp deleted file mode 100644 index 0a3822c6..00000000 --- a/include/mockutils/constexpr_hash.hpp +++ /dev/null @@ -1,17 +0,0 @@ -#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/gcc/VirtualTable.hpp b/include/mockutils/gcc/VirtualTable.hpp index 03891818..1ed85f7d 100644 --- a/include/mockutils/gcc/VirtualTable.hpp +++ b/include/mockutils/gcc/VirtualTable.hpp @@ -131,7 +131,7 @@ namespace fakeit { private: static void **buildVTArray() { - int size = VTUtils::getVTSize(); + unsigned int size = VTUtils::getVTSize(); auto array = new void *[size + 2 + numOfCookies]{}; array += numOfCookies; // skip cookies array++; // skip top_offset diff --git a/include/mockutils/mscpp/VirtualTable.hpp b/include/mockutils/mscpp/VirtualTable.hpp index 449f6577..ccaca7f7 100644 --- a/include/mockutils/mscpp/VirtualTable.hpp +++ b/include/mockutils/mscpp/VirtualTable.hpp @@ -178,7 +178,7 @@ namespace fakeit { } void copyFrom(VirtualTable &from) { - auto size = VTUtils::getVTSize(); + unsigned int size = VTUtils::getVTSize(); for (unsigned int i = 0; i < size; i++) { _firstMethod[i] = from.getMethod(i); } @@ -234,7 +234,7 @@ namespace fakeit { setCookie(dtorCookieIndex, method); } - size_t getSize() { + unsigned int getSize() { return VTUtils::getVTSize(); } @@ -256,7 +256,7 @@ namespace fakeit { static const unsigned int dtorCookieIndex = numOfCookies - 1; // use the last cookie static void **buildVTArray() { - auto vtSize = VTUtils::getVTSize(); + unsigned int vtSize = VTUtils::getVTSize(); auto array = new void *[vtSize + numOfCookies + 1]{}; RTTICompleteObjectLocator *objectLocator = new RTTICompleteObjectLocator( typeid(C)); diff --git a/tests/multiple_translation_units_stub.cpp b/tests/multiple_translation_units_stub.cpp index 6f2dc0bb..2fa25bfe 100644 --- a/tests/multiple_translation_units_stub.cpp +++ b/tests/multiple_translation_units_stub.cpp @@ -1,12 +1,27 @@ #include "multiple_translation_units_stub.h" +namespace multiple_tu { -void stubFunc2(fakeit::Mock& mock) -{ - fakeit::When(Method(mock, func2)).AlwaysReturn("String"); -} + void stubFunc(fakeit::Mock& mock) + { + fakeit::When(Method(mock, func)).Return(5); + } + + void stubFunc2(fakeit::Mock& mock) + { + fakeit::When(Method(mock, func2)).Return("String"); + } + + void stubMoreFunc(fakeit::Mock& mock) + { + fakeit::When(Method(mock, func).Using(1)).Return(10); + fakeit::When(Method(mock, func).Using(2)).Return(20); + } + + void stubMoreFunc2(fakeit::Mock& mock) + { + fakeit::When(Method(mock, func2).Using(1)).Return("String1"); + fakeit::When(Method(mock, func2).Using(2)).Return("String2"); + } -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 index 084cf17b..28293d63 100644 --- a/tests/multiple_translation_units_stub.h +++ b/tests/multiple_translation_units_stub.h @@ -4,10 +4,16 @@ #include "fakeit.hpp" -struct SomeInterface { - virtual int func() = 0; - virtual std::string func2() = 0; -}; +namespace multiple_tu { -void stubFunc2(fakeit::Mock& mock); -void stubFunc(fakeit::Mock& mock); + struct SomeInterface { + virtual int func(int) = 0; + virtual std::string func2(int) = 0; + }; + + void stubFunc(fakeit::Mock& mock); + void stubFunc2(fakeit::Mock& mock); + void stubMoreFunc(fakeit::Mock& mock); + void stubMoreFunc2(fakeit::Mock& mock); + +} diff --git a/tests/multiple_translation_units_stub_test.cpp b/tests/multiple_translation_units_stub_test.cpp index 75cf43f4..8f954850 100644 --- a/tests/multiple_translation_units_stub_test.cpp +++ b/tests/multiple_translation_units_stub_test.cpp @@ -3,22 +3,126 @@ #include "multiple_translation_units_stub.h" using namespace fakeit; +using namespace multiple_tu; struct MultipleTranslationUnitsStub : tpunit::TestFixture { - MultipleTranslationUnitsStub() - : tpunit::TestFixture( - TEST(MultipleTranslationUnitsStub::NoCollidingIds) - ) - {} - void NoCollidingIds() { + MultipleTranslationUnitsStub() : + tpunit::TestFixture( + TEST(MultipleTranslationUnitsStub::NoCollidingIdsBasics), + TEST(MultipleTranslationUnitsStub::NoCollidingIdsAlternateBasics), + TEST(MultipleTranslationUnitsStub::NoCollidingIdsMoreFunctionsMocked), + TEST(MultipleTranslationUnitsStub::NoCollidingIdsWhenOverridingMocks) + ) + { + } + + void NoCollidingIdsBasics() + { + Mock mock; + + stubFunc(mock); + When(Method(mock, func2)).Return("Something"); + + SomeInterface &i = mock.get(); + + // Uncatchable write access violation if ids collide. + EXPECT_EQUAL(i.func(5), 5); + EXPECT_EQUAL(i.func2(5), "Something"); + + Verify(Method(mock, func).Using(5)).Exactly(1); + Verify(Method(mock, func2).Using(5)).Exactly(1); + } + + void NoCollidingIdsAlternateBasics() + { + Mock mock; + + When(Method(mock, func)).Return(100); + stubFunc2(mock); + + SomeInterface &i = mock.get(); + + // Uncatchable write access violation if ids collide. + EXPECT_EQUAL(i.func(5), 100); + EXPECT_EQUAL(i.func2(5), "String"); + + Verify(Method(mock, func).Using(5)).Exactly(1); + Verify(Method(mock, func2).Using(5)).Exactly(1); + } + + void NoCollidingIdsMoreFunctionsMocked() + { Mock mock; + + stubFunc(mock); + stubFunc2(mock); + + When(Method(mock, func).Using(20)).Return(20); + When(Method(mock, func).Using(50)).Return(50); + + When(Method(mock, func2).Using(20)).Return("Something-20"); + When(Method(mock, func2).Using(50)).Return("Something-50"); + + stubMoreFunc(mock); + stubMoreFunc2(mock); + SomeInterface &i = mock.get(); - + + // Uncatchable write access violation if ids collide. + EXPECT_EQUAL(i.func(1), 10); + EXPECT_EQUAL(i.func(2), 20); + EXPECT_EQUAL(i.func(5), 5); + EXPECT_EQUAL(i.func(20), 20); + EXPECT_EQUAL(i.func(50), 50); + EXPECT_EQUAL(i.func2(1), "String1"); + EXPECT_EQUAL(i.func2(2), "String2"); + EXPECT_EQUAL(i.func2(5), "String"); + EXPECT_EQUAL(i.func2(20), "Something-20"); + EXPECT_EQUAL(i.func2(50), "Something-50"); + + Verify(Method(mock, func).Using(1)).Exactly(1); + Verify(Method(mock, func).Using(2)).Exactly(1); + Verify(Method(mock, func).Using(5)).Exactly(1); + Verify(Method(mock, func).Using(20)).Exactly(1); + Verify(Method(mock, func).Using(50)).Exactly(1); + Verify(Method(mock, func2).Using(1)).Exactly(1); + Verify(Method(mock, func2).Using(2)).Exactly(1); + Verify(Method(mock, func2).Using(5)).Exactly(1); + Verify(Method(mock, func2).Using(20)).Exactly(1); + Verify(Method(mock, func2).Using(50)).Exactly(1); + } + + void NoCollidingIdsWhenOverridingMocks() + { + Mock mock; + + stubFunc(mock); + When(Method(mock, func)).Return(123); + When(Method(mock, func2)).Return("Something"); stubFunc2(mock); - When(Method(mock, func)).Return(1); - mock.get().func2(); // Uncatchable write access violation if ids collide + SomeInterface &i = mock.get(); + + EXPECT_EQUAL(i.func(0), 123); + EXPECT_EQUAL(i.func2(0), "String"); + + try { + i.func(0); + FAIL(); + } catch (const UnexpectedMethodCallException&) { + // There was only one action in the mock for this function. + } + + try { + i.func2(0); + FAIL(); + } catch (const UnexpectedMethodCallException&) { + // There was only one action in the mock for this function. + } + + Verify(Method(mock, func)).Exactly(2); + Verify(Method(mock, func)).Exactly(2); } } __MultipleTranslationUnitsStub;