Skip to content

Instantly share code, notes, and snippets.

@Rene-Damm
Created November 26, 2015 11:25
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save Rene-Damm/dd135239730badad03a4 to your computer and use it in GitHub Desktop.
Save Rene-Damm/dd135239730badad03a4 to your computer and use it in GitHub Desktop.
#pragma once
// This provides a library for stubbing and mocking C++ code as is. It works by requiring
// explicit hooks to be inserted into the code that is to be mocked. In a regular build,
// these hooks will do nothing. In a testing build, they will expand to calls into the
// framework here to allow the code being executed to be hijacked from outside.
//
// NOTE: Thread-safety! Arranging fakes must be done on a single thread. Using fakes can
// be done from multiple threads concurrently.
//
// NOTE: Unfortunately, this code currently requires C++11 as it uses decltype(). Working
// around this dependency requires annotating all macros with explicit type information.
// There is no way (at least that I know of) to otherwise write the required template
// machinery pre-C++11 (you need to be able to convert a function/method call expression
// into a respective type).
//
// NOTE: This code requires C++ RTTI to be enabled. It is used to distinguish between overloads
// at runtime.
//
// LIMITATIONS:
// - You cannot fake variadic functions/methods.
// - The current max number of supported arguments is 5; can easily be increased
// (expand the templates in this file and in DeconstructFunctionType).
// -----------------------------------------------------------------------------------------------
// ** How To Use This **
//
// 1. Insert __FAKEABLE_FUNCTION__ or __FAKEABLE_METHOD__ calls at the top of the functions/methods
// that you want to hijack in your tests (if these calls aren't already there).
//
// #include "Runtime/Testing/Faking.h"
//
// int SomeGlobalFunction (const std::string& arg1, float arg2)
// {
// __FAKEABLE_FUNCTION__ (SomeGlobalFunction, (arg1, arg2));
//
// ... normal code of the function start here ...
// }
//
// If the function or method is overloaded, use __FAKEABLE_FUNCTION_OVERLOADED__ and
// __FAKEABLE_METHOD_OVERLOADED__ instead.
//
// 2. Set up a fake in your test.
//
// TEST (MyTest)
// {
// FAKE_FUNCTION (SomeGlobalFunction, (const std::string&, float); // Do this here or in fixture. Scope==lifetime of fake.
//
// SomeGlobalFunction.Returns ("test");
//
// 3. Run the code that uses the faked functionality.
//
// MyOtherFunctionWhichCallsSomeGlobalFunction ();
//
// 4. Verify the state of the fake.
//
// CHECK_EQUAL (1, SomeGlobalFunction.CallCount ());
//
// To see a concrete example, take a look at Editor/Src/AssetPipeline/PluginImporterTests.cpp.
#if ENABLE_UNIT_TESTS_WITH_FAKES
#include <vector>
#include <typeinfo>
#include "Runtime/Threads/ThreadSpecificValue.h"
#include "Runtime/Utilities/TypeUtilities.h"
#include "Runtime/Utilities/DeconstructFunctionType.h"
#include "TestFixtures.h"
////TODO: namespace support
////REVIEW: implement a strict faking mode where we hook into every fake that's available and error out if it hasn't been set up?
#define FAKEABLE_METHOD_IMPL(className, methodName, args, type, this) \
if (::testing::g_IsCurrentlyFaking) \
{ \
static testing::Fakeable _registration(#className "::" #methodName, typeid (DeconstructFunctionType<type>::Signature)); \
if (_registration.installedFakes.size()) \
{ \
::testing::g_FakeCallObject = this; \
for (int i = 0; i < _registration.installedFakes.size(); ++i) \
{ \
::testing::FakeCallResult callResult = \
(_registration.installedFakes[i].instance->* \
((DeconstructFunctionType< \
DeconstructFunctionType<type> \
::MakeMethodOf<::testing::FakeFunctionBase>::ResultType> \
::ReplaceReturnTypeWith<::testing::FakeCallResult>::ResultType) \
_registration.installedFakes[i].handler)) \
args; \
if (callResult == ::testing::kFakeCallSucceeded) \
{ \
::testing::FakeMethod<className, DeconstructFunctionType<type>::Signature>* fakeMethod = \
(::testing::FakeMethod<className, DeconstructFunctionType<type>::Signature>*) \
_registration.installedFakes[i].instance; \
::testing::g_FakeCallObject = 0; \
return fakeMethod->Returns(); \
} \
else if (callResult == ::testing::kFakeCallOriginal) \
break; \
} \
::testing::g_FakeCallObject = 0; \
} \
}
#define FAKEABLE_FUNCTION_IMPL(functionName, args, type) \
if (::testing::g_IsCurrentlyFaking) \
{ \
static testing::Fakeable _registration(#functionName, typeid (DeconstructFunctionType<type>::Signature)); \
for (int i = 0; i < _registration.installedFakes.size(); ++i) \
{ \
::testing::FakeCallResult callResult = \
(_registration.installedFakes[i].instance->* \
((DeconstructFunctionType< \
DeconstructFunctionType<type>::MakeMethodOf<::testing::FakeFunctionBase>::ResultType> \
::ReplaceReturnTypeWith<::testing::FakeCallResult>::ResultType) \
_registration.installedFakes[i].handler)) \
args; \
if (callResult == ::testing::kFakeCallSucceeded) \
{ \
::testing::FakeFunction<DeconstructFunctionType<type>::Signature>* fakeFunction = \
(::testing::FakeFunction<DeconstructFunctionType<type>::Signature>*) \
_registration.installedFakes[i].instance; \
return fakeFunction->Returns(); \
} \
else if (callResult == ::testing::kFakeCallOriginal) \
break; \
} \
}
////REVIEW: Could leave return type out of overloaded signatures?
////REVIEW: The __XXX__ naming style is to make the macros *not* blend in with the other code in functions/methods. Otherwise it
//// seems confusing that what appears to be the first statement in a function or method actually isn't a relevant statement
//// at all but rather just what to the function itself is noise. We have to see whether we like it or not and can always
//// rename these if we don't.
// Mark the current method/function as fakeable with the fake being able to return a value.
// NOTE: Method cannot be overloaded. Use __FAKEABLE_METHOD_OVERLOADED__ if needed.
// NOTE: className must be fully qualified including namespaces!
#define __FAKEABLE_METHOD__(className, methodName, args) \
FAKEABLE_METHOD_IMPL(className, methodName, args, decltype (&className::methodName), (void*) this)
#define __FAKEABLE_METHOD_OVERLOADED__(className, methodName, args, signature) \
FAKEABLE_METHOD_IMPL(className, methodName, args, DeconstructFunctionType<ToPointerType<signature>::ResultType>::MakeMethodOf<className>::ResultType, (void*) this)
#define __FAKEABLE_STATIC_METHOD__(className, methodName, args) \
FAKEABLE_METHOD_IMPL(className, methodName, args, decltype (&className::methodName), NULL)
#define __FAKEABLE_STATIC_METHOD_OVERLOADED__(className, methodName, args, signature) \
FAKEABLE_METHOD_IMPL(className, methodName, args, DeconstructFunctionType<ToPointerType<signature>::ResultType>::MakeMethodOf<className>::ResultType, NULL)
#define __FAKEABLE_FUNCTION__(functionName, args) \
FAKEABLE_FUNCTION_IMPL(functionName, args, decltype (&functionName))
#define __FAKEABLE_FUNCTION_OVERLOADED__(functionName, args, signature) \
FAKEABLE_FUNCTION_IMPL(functionName, args, ToPointerType<signature>::ResultType)
#define FAKE_CLASS(className) \
class __Fake ## className \
{ \
public: \
typedef className FakedClassType; \
__Fake ## className() \
{ \
::memset(__data, 0, sizeof (__data)); \
::testing::g_FakeObjectCurrentlyBeingSetUp = this; \
} \
operator className& () \
{ \
return reinterpret_cast<className&>(*this); \
} \
operator const className& () const \
{ \
return reinterpret_cast<const className&>(*this); \
} \
static const char* __GetFakedClassName() { return #className; } \
private: \
char __data[sizeof(className)]; \
}; \
struct Fake ## className : public __Fake ## className
#define FAKE_METHOD_IMPL(localName, staticClassName, dynamicClassName, classType, methodName, signature) \
struct __Fake ## localName : public ::testing::FakeMethod<classType, signature> \
{ \
__Fake ## localName() \
: ::testing::FakeMethod<classType, signature>(dynamicClassName, #methodName) \
{ \
this->m_Instance = NULL; \
} \
}; \
__Fake ## localName localName
#define FAKE_FUNCTION_IMPL(localName, functionName, signature) \
struct __Fake ## localName : public ::testing::FakeFunction<signature> \
{ \
__Fake ## localName() \
: ::testing::FakeFunction<signature>(#functionName) {} \
}; \
__Fake ## localName localName
// We cannot currently use type inference for methods/functions as VS2010's decltype() support is too broken to handle it.
// So for now, we need to always pass explicit signatures. Hopefully we can change this once we switch away from VS2010.
//#define FAKE_METHOD_WITH_TYPE(className, methodName, signature) \
// FAKE_METHOD_WITH_TYPE_AND_LOCAL_NAME (className ## _ ## methodName, className, methodName, signature)
//#define FAKE_METHOD(className, methodName) \
// FAKE_METHOD_WITH_TYPE (className, methodName, DeconstructFunctionType<decltype (&className::methodName)>::Signature)
#define FAKE_METHOD(className, methodName, signature) \
FAKE_METHOD_IMPL(className ## _ ## methodName, className, #className, className, methodName, signature)
#define FAKE_METHOD_WITH_LOCAL_NAME(localName, className, methodName, signature) \
FAKE_METHOD_IMPL(localName, className, #className, className, methodName, signature)
#define FAKE_CLASS_METHOD(methodName, signature) \
FAKE_METHOD_IMPL(methodName, , __GetFakedClassName(), FakedClassType, methodName, signature)
#define FAKE_CLASS_METHOD_WITH_LOCAL_NAME(localName, methodName, signature) \
FAKE_METHOD_IMPL(localName, , __GetFakedClassName(), FakedClassType, methodName, signature)
#define FAKE_FUNCTION_WITH_LOCAL_NAME(localName, functionName, signature) \
FAKE_FUNCTION_IMPL(localName, functionName, signature)
#define FAKE_FUNCTION(functionName, signature) \
FAKE_FUNCTION_IMPL(functionName, functionName, signature)
namespace testing
{
enum FakeCallResult
{
kFakeCallSucceeded, // Fake overrode original call.
kFakeCallOriginal, // Fake wants original code to be executed.
kFakeCallHadNoEffect // Fake didn't apply.
};
// True if any fake methods/functions are currently active.
extern bool g_IsCurrentlyFaking;
// 'this' pointer of the FAKE_CLASS instance currently being set up. Used by the FAKE_METHOD macro
// to know which fake instance it belongs to.
// NOTE: Not cleared to NULL again after a fake instance has finished initializing.
extern void* g_FakeObjectCurrentlyBeingSetUp;
// 'this' pointer of FAKE_METHOD currently being executed.
extern UNITY_TLS_VALUE (void*) g_FakeCallObject; ///TODO: remove the global and route this through an additional argument or something
// Base class for all fake method/function objects.
struct FakeFunctionBase
{
FakeFunctionBase (const char* functionName)
: m_FunctionName (functionName)
, m_CallCount (0) {}
int CallCount () const { return m_CallCount; }
bool WasNotCalled () const { return (m_CallCount == 0); }
bool WasCalled () const { return !WasNotCalled (); }
protected:
const char* m_FunctionName;
int m_CallCount;
};
typedef FakeCallResult (FakeFunctionBase::*FakeFunctionHandler) ();
struct Fakeable;
void RegisterFakeable (Fakeable* fakeable);
Fakeable* FindFakeable (const std::string& name, const std::type_info& type);
void InstallFake (const std::string& fakeableName, const std::type_info& fakeableType, FakeFunctionBase* instance, FakeFunctionHandler fakeFunction);
void UninstallFake (const std::string& fakeableName, const std::type_info& fakeableType, FakeFunctionBase* instance, FakeFunctionHandler fakeFunction);
struct InstalledFake
{
FakeFunctionHandler handler;
FakeFunctionBase* instance;
};
// Statically registered instances that are placed at __FAKEABLE_XXX__ sites.
struct Fakeable
{
std::string name;
const std::type_info& type; // typeid() of the signature, *not* the pointer type.
std::vector<InstalledFake> installedFakes;
Fakeable (const std::string& name, const std::type_info& type)
: name (name)
, type (type)
{
RegisterFakeable (this);
}
};
template<typename T>
struct __FakeReturnValue
{
T value;
__FakeReturnValue () {}
__FakeReturnValue (const T& value)
: value (value) {}
T const& Get () const
{
return value;
}
};
// Work around copy constraints on reference type values by internally turning them into
// pointer values.
template<typename T>
struct __FakeReturnValue<T&>
{
T* value;
__FakeReturnValue ()
: value (NULL) {}
__FakeReturnValue (T& value)
: value (&value) {}
T& Get () const
{
AssertMsg (value != NULL, "Return value for reference type has not been set up! Call Returns(val) on the fake!");
return *value;
}
};
template<typename T>
struct __FakeReturnValue<const T&>
{
const T* value;
__FakeReturnValue ()
: value (NULL) {}
__FakeReturnValue (const T& value)
: value (&value) {}
const T& Get () const
{
AssertMsg (value != NULL, "Return value for reference type has not been set up! Call Returns(val) on the fake!");
return *value;
}
};
// Make local copies of std::strings as otherwise we probably end up grabbing pointers to temporary
// std::strings constructed from literals.
template<>
struct __FakeReturnValue<std::string&>
{
std::string value;
__FakeReturnValue () {}
__FakeReturnValue (const std::string& value)
: value (value) {}
const std::string& Get () const
{
return value;
}
};
template<>
struct __FakeReturnValue<const std::string&>
{
std::string value;
__FakeReturnValue () {}
__FakeReturnValue (const std::string& value)
: value (value) {}
const std::string& Get () const
{
return value;
}
};
template<>
struct __FakeReturnValue<void>
{
__FakeReturnValue () {}
void Get () const {}
};
template<typename F>
struct __FakeArgs
{
};
template<typename R, typename A1>
struct __FakeArgs<R (A1)>
{
__FakeReturnValue<A1> a1;
};
template<typename R, typename A1, typename A2>
struct __FakeArgs<R (A1, A2)>
{
__FakeReturnValue<A1> a1;
__FakeReturnValue<A2> a2;
};
template<typename R, typename A1, typename A2, typename A3>
struct __FakeArgs<R (A1, A2, A3)>
{
__FakeReturnValue<A1> a1;
__FakeReturnValue<A2> a2;
__FakeReturnValue<A3> a3;
};
template<typename R, typename A1, typename A2, typename A3, typename A4>
struct __FakeArgs<R (A1, A2, A3, A4)>
{
__FakeReturnValue<A1> a1;
__FakeReturnValue<A2> a2;
__FakeReturnValue<A3> a3;
__FakeReturnValue<A4> a4;
};
template<typename R, typename A1, typename A2, typename A3, typename A4, typename A5>
struct __FakeArgs<R (A1, A2, A3, A4, A5)>
{
__FakeReturnValue<A1> a1;
__FakeReturnValue<A2> a2;
__FakeReturnValue<A3> a3;
__FakeReturnValue<A4> a4;
__FakeReturnValue<A5> a5;
};
template<typename R, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6>
struct __FakeArgs<R (A1, A2, A3, A4, A5, A6)>
{
__FakeReturnValue<A1> a1;
__FakeReturnValue<A2> a2;
__FakeReturnValue<A3> a3;
__FakeReturnValue<A4> a4;
__FakeReturnValue<A5> a5;
__FakeReturnValue<A6> a6;
};
// Adds function type to FakeFunctionType and gathers faking functionality that is independent
// of argument and return types.
template<typename F, typename R>
struct __FakeFunctionBaseWrapper : public FakeFunctionBase
{
__FakeFunctionBaseWrapper (const char* functionName)
: FakeFunctionBase (functionName)
, m_CallOriginal (false) {}
void CallsOriginal ()
{
m_CallOriginal = true;
}
void Calls (F* function)
{
m_CallInstead.function = function;
}
// Turn F into a member function pointer on class TestFixtureBase.
typedef typename DeconstructFunctionType<typename ToPointerType<F>::ResultType>::
template MakeMethodOf<TestFixtureBase>::ResultType TestFixtureMethodHandler;
// Accept a method on an arbitrary fixture class (or any class that is) and store it
// as a member function pointer and 'this' pointer for class TestFixtureBase.
template<typename Fixture>
void Calls (Fixture* fixture, typename DeconstructFunctionType<typename ToPointerType<F>::ResultType>::template MakeMethodOf<Fixture>::ResultType handler)
{
m_CallInstead.fixture = (TestFixtureBase*) fixture;
m_CallInstead.handler = (TestFixtureMethodHandler) handler;
}
const __FakeArgs<F>& LastCallArguments () const
{
return m_LastArgs;
}
protected:
__FakeArgs<F> m_LastArgs;
void ClearLastArgs ()
{
m_LastArgs = __FakeArgs<F> ();
}
bool m_CallOriginal;
// Callable wrapper that redirects either directly to a function or to a member function
// on a fixture.
struct CallInstead
{
F* function;
TestFixtureBase* fixture;
TestFixtureMethodHandler handler;
CallInstead ()
: function (NULL)
, fixture (NULL)
, handler (NULL) {}
operator bool () const
{
return (function != NULL || fixture != NULL);
}
R operator () ()
{
if (function)
return function ();
else
return (fixture->*handler) ();
}
template<typename A1>
R operator () (A1 a1)
{
if (function)
return function (a1);
else
return (fixture->*handler) (a1);
}
template<typename A1, typename A2>
R operator () (A1 a1, A2 a2)
{
if (function)
return function (a1, a2);
else
return (fixture->*handler) (a1, a2);
}
template<typename A1, typename A2, typename A3>
R operator () (A1 a1, A2 a2, A3 a3)
{
if (function)
return function (a1, a2, a3);
else
return (fixture->*handler) (a1, a2, a3);
}
template<typename A1, typename A2, typename A3, typename A4>
R operator () (A1 a1, A2 a2, A3 a3, A4 a4)
{
if (function)
return function (a1, a2, a3, a4);
else
return (fixture->*handler) (a1, a2, a3, a4);
}
template<typename A1, typename A2, typename A3, typename A4, typename A5>
R operator () (A1 a1, A2 a2, A3 a3, A4 a4, A5 a5)
{
if (function)
return function (a1, a2, a3, a4, a5);
else
return (fixture->*handler) (a1, a2, a3, a4, a5);
}
template<typename A1, typename A2, typename A3, typename A4, typename A5, typename A6>
R operator () (A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6)
{
if (function)
return function (a1, a2, a3, a4, a5, a6);
else
return (fixture->*handler) (a1, a2, a3, a4, a5, a6);
}
};
// This should be using std::function when we can move to c++11.
CallInstead m_CallInstead;
};
// NOTE: The explicit type parameters on the various call expressions is to prevent stripping of reference types
// during template parameter type deduction.
// VC2010 breaks on seeing 'template' keyword below which is otherwise required. Hopefully newer VCs accept it.
#if defined(_MSC_VER)
#define DEPENDENT_TEMPLATE
#else
#define DEPENDENT_TEMPLATE template
#endif
template<typename F, typename R>
struct __FakeFunction : __FakeFunctionBaseWrapper<F, R>
{
__FakeFunction (const char* functionName)
: __FakeFunctionBaseWrapper<F, R> (functionName) {}
R Returns () const
{
return m_ReturnValue.Get ();
}
void Returns (const R& value)
{
m_ReturnValue = __FakeReturnValue<R> (value);
}
R LastCallReturnValue () const
{
AssertMsg (this->WasCalled (), "Function has not been called and thus has not generated a return value!");
return m_ReturnValue.Get ();
}
protected:
// Helper to deal with case of void returns. See __FakeFunction specialization
// for void return below.
template<typename Callable>
void Invoke (Callable& c)
{
Returns (c ());
}
template<typename Callable, typename A1>
void Invoke (Callable& c, A1 a1)
{
Returns (c.DEPENDENT_TEMPLATE operator ()<A1> (a1));
}
template<typename Callable, typename A1, typename A2>
void Invoke (Callable& c, A1 a1, A2 a2)
{
Returns (c.DEPENDENT_TEMPLATE operator ()<A1, A2> (a1, a2));
}
template<typename Callable, typename A1, typename A2, typename A3>
void Invoke (Callable& c, A1 a1, A2 a2, A3 a3)
{
Returns (c.DEPENDENT_TEMPLATE operator ()<A1, A2, A3> (a1, a2, a3));
}
template<typename Callable, typename A1, typename A2, typename A3, typename A4>
void Invoke (Callable& c, A1 a1, A2 a2, A3 a3, A4 a4)
{
Returns (c.DEPENDENT_TEMPLATE operator ()<A1, A2, A3, A4> (a1, a2, a3, a4));
}
template<typename Callable, typename A1, typename A2, typename A3, typename A4, typename A5>
void Invoke (Callable& c, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5)
{
Returns (c.DEPENDENT_TEMPLATE operator ()<A1, A2, A3, A4, A5> (a1, a2, a3, a4, a5));
}
template<typename Callable, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6>
void Invoke (Callable& c, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6)
{
Returns (c.DEPENDENT_TEMPLATE operator ()<A1, A2, A3, A4, A5, A5> (a1, a2, a3, a4, a5, a6));
}
private:
__FakeReturnValue<R> m_ReturnValue;
};
template<typename F>
struct __FakeFunction<F, void> : __FakeFunctionBaseWrapper<F, void>
{
__FakeFunction (const char* functionName)
: __FakeFunctionBaseWrapper<F, void> (functionName) {}
void Returns () {}
protected:
template<typename Callable>
void Invoke (Callable& c)
{
c ();
}
template<typename Callable, typename A1>
void Invoke (Callable& c, A1 a1)
{
c.DEPENDENT_TEMPLATE operator ()<A1> (a1);
}
template<typename Callable, typename A1, typename A2>
void Invoke (Callable& c, A1 a1, A2 a2)
{
c.DEPENDENT_TEMPLATE operator ()<A1, A2> (a1, a2);
}
template<typename Callable, typename A1, typename A2, typename A3>
void Invoke (Callable& c, A1 a1, A2 a2, A3 a3)
{
c.DEPENDENT_TEMPLATE operator ()<A1, A2, A3> (a1, a2, a3);
}
template<typename Callable, typename A1, typename A2, typename A3, typename A4>
void Invoke (Callable& c, A1 a1, A2 a2, A3 a3, A4 a4)
{
c.DEPENDENT_TEMPLATE operator ()<A1, A2, A3, A4> (a1, a2, a3, a4);
}
template<typename Callable, typename A1, typename A2, typename A3, typename A4, typename A5>
void Invoke (Callable& c, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5)
{
c.DEPENDENT_TEMPLATE operator ()<A1, A2, A3, A4, A5> (a1, a2, a3, a4, a5);
}
template<typename Callable, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6>
void Invoke (Callable& c, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6)
{
c.DEPENDENT_TEMPLATE operator ()<A1, A2, A3, A4, A5, A6> (a1, a2, a3, a4, a5, a6);
}
};
template<typename C, typename F, typename R>
struct __FakeMethod : public __FakeFunction<F, R>
{
__FakeMethod (const char* className, const char* methodName)
: __FakeFunction<F, R> (methodName)
, m_Instance (static_cast<C*> ((void*) g_FakeObjectCurrentlyBeingSetUp))
, m_ClassName (className) {}
void WhenInstanceIs (C* instance)
{
m_Instance = instance;
}
protected:
C* m_Instance;
const char* m_ClassName;
};
template<typename F>
struct FakeFunction
{
};
template<typename R>
struct FakeFunction<R ()> : __FakeFunction<R (), R>
{
typedef __FakeFunction<R (), R> Base;
FakeFunction (const char* functionName)
: Base (functionName)
{
InstallFake (this->m_FunctionName, typeid (R ()), this, reinterpret_cast<FakeFunctionHandler> (&FakeFunction::FakeIt));
}
~FakeFunction ()
{
UninstallFake (this->m_FunctionName, typeid (R ()), this, reinterpret_cast<FakeFunctionHandler> (&FakeFunction::FakeIt));
}
protected:
FakeCallResult FakeIt ()
{
++this->m_CallCount;
if (this->m_CallOriginal)
return kFakeCallOriginal;
if (this->m_CallInstead)
this->Invoke (this->m_CallInstead);
return kFakeCallSucceeded;
}
};
template<typename R, typename A1>
struct FakeFunction<R (A1)> : __FakeFunction<R (A1), R>
{
typedef __FakeFunction<R (A1), R> Base;
FakeFunction (const char* functionName)
: Base (functionName)
{
InstallFake (this->m_FunctionName, typeid (R (A1)), this, reinterpret_cast<FakeFunctionHandler> (&FakeFunction::FakeIt));
}
~FakeFunction ()
{
UninstallFake (this->m_FunctionName, typeid (R (A1)), this, reinterpret_cast<FakeFunctionHandler> (&FakeFunction::FakeIt));
}
protected:
FakeCallResult FakeIt (A1 a1)
{
++this->m_CallCount;
this->ClearLastArgs ();
this->m_LastArgs.a1 = a1;
if (this->m_CallOriginal)
return kFakeCallOriginal;
if (this->m_CallInstead)
this->template Invoke<typename Base::CallInstead, A1> (this->m_CallInstead, a1);
return kFakeCallSucceeded;
}
};
template<typename R, typename A1, typename A2>
struct FakeFunction<R (A1, A2)> : __FakeFunction<R (A1, A2), R>
{
typedef __FakeFunction<R (A1, A2), R> Base;
FakeFunction (const char* functionName)
: Base (functionName)
{
InstallFake (this->m_FunctionName, typeid (R (A1, A2)), this, reinterpret_cast<FakeFunctionHandler> (&FakeFunction::FakeIt));
}
~FakeFunction ()
{
UninstallFake (this->m_FunctionName, typeid (R (A1, A2)), this, reinterpret_cast<FakeFunctionHandler> (&FakeFunction::FakeIt));
}
protected:
FakeCallResult FakeIt (A1 a1, A2 a2)
{
++this->m_CallCount;
this->ClearLastArgs ();
this->m_LastArgs.a1 = a1;
this->m_LastArgs.a2 = a2;
if (this->m_CallOriginal)
return kFakeCallOriginal;
if (this->m_CallInstead)
this->template Invoke<typename Base::CallInstead, A1, A2> (this->m_CallInstead, a1, a2);
return kFakeCallSucceeded;
}
};
template<typename R, typename A1, typename A2, typename A3>
struct FakeFunction<R (A1, A2, A3)> : __FakeFunction<R (A1, A2, A3), R>
{
typedef __FakeFunction<R (A1, A2, A3), R> Base;
FakeFunction (const char* functionName)
: Base (functionName)
{
InstallFake (this->m_FunctionName, typeid (R (A1, A2, A3)), this, reinterpret_cast<FakeFunctionHandler> (&FakeFunction::FakeIt));
}
~FakeFunction ()
{
UninstallFake (this->m_FunctionName, typeid (R (A1, A2, A3)), this, reinterpret_cast<FakeFunctionHandler> (&FakeFunction::FakeIt));
}
protected:
FakeCallResult FakeIt (A1 a1, A2 a2, A3 a3)
{
++this->m_CallCount;
this->ClearLastArgs ();
this->m_LastArgs.a1 = a1;
this->m_LastArgs.a2 = a2;
this->m_LastArgs.a3 = a3;
if (this->m_CallOriginal)
return kFakeCallOriginal;
if (this->m_CallInstead)
this->template Invoke<typename Base::CallInstead, A1, A2, A3> (this->m_CallInstead, a1, a2, a3);
return kFakeCallSucceeded;
}
};
template<typename R, typename A1, typename A2, typename A3, typename A4>
struct FakeFunction<R (A1, A2, A3, A4)> : __FakeFunction<R (A1, A2, A3, A4), R>
{
typedef __FakeFunction<R (A1, A2, A3, A4), R> Base;
FakeFunction (const char* functionName)
: Base (functionName)
{
InstallFake (this->m_FunctionName, typeid (R (A1, A2, A3, A4)), this, reinterpret_cast<FakeFunctionHandler> (&FakeFunction::FakeIt));
}
~FakeFunction ()
{
UninstallFake (this->m_FunctionName, typeid (R (A1, A2, A3, A4)), this, reinterpret_cast<FakeFunctionHandler> (&FakeFunction::FakeIt));
}
protected:
FakeCallResult FakeIt (A1 a1, A2 a2, A3 a3, A4 a4)
{
++this->m_CallCount;
this->ClearLastArgs ();
this->m_LastArgs.a1 = a1;
this->m_LastArgs.a2 = a2;
this->m_LastArgs.a3 = a3;
this->m_LastArgs.a4 = a4;
if (this->m_CallOriginal)
return kFakeCallOriginal;
if (this->m_CallInstead)
this->template Invoke<typename Base::CallInstead, A1, A2, A3, A4> (this->m_CallInstead, a1, a2, a3, a4);
return kFakeCallSucceeded;
}
};
template<typename R, typename A1, typename A2, typename A3, typename A4, typename A5>
struct FakeFunction<R (A1, A2, A3, A4, A5)> : __FakeFunction<R (A1, A2, A3, A4, A5), R>
{
typedef __FakeFunction<R (A1, A2, A3, A4, A5), R> Base;
FakeFunction (const char* functionName)
: Base (functionName)
{
InstallFake (this->m_FunctionName, typeid (R (A1, A2, A3, A4, A5)), this, reinterpret_cast<FakeFunctionHandler> (&FakeFunction::FakeIt));
}
~FakeFunction ()
{
UninstallFake (this->m_FunctionName, typeid (R (A1, A2, A3, A4, A5)), this, reinterpret_cast<FakeFunctionHandler> (&FakeFunction::FakeIt));
}
protected:
FakeCallResult FakeIt (A1 a1, A2 a2, A3 a3, A4 a4, A5 a5)
{
++this->m_CallCount;
this->ClearLastArgs ();
this->m_LastArgs.a1 = a1;
this->m_LastArgs.a2 = a2;
this->m_LastArgs.a3 = a3;
this->m_LastArgs.a4 = a4;
this->m_LastArgs.a5 = a5;
if (this->m_CallOriginal)
return kFakeCallOriginal;
if (this->m_CallInstead)
this->template Invoke<typename Base::CallInstead, A1, A2, A3, A4, A5> (this->m_CallInstead, a1, a2, a3, a4, a5);
return kFakeCallSucceeded;
}
};
template<typename C, typename F>
struct FakeMethod
{
};
template<typename C, typename R>
struct FakeMethod<C, R ()> : __FakeMethod<C, R (C*), R>
{
typedef __FakeMethod<C, R (C*), R> Base;
FakeMethod (const char* className, const char* methodName)
: Base (className, methodName)
{
InstallFake (std::string (className) + "::" + methodName, typeid (R ()), this, reinterpret_cast<FakeFunctionHandler> (&FakeMethod::FakeIt));
}
~FakeMethod ()
{
UninstallFake (std::string (this->m_ClassName) + "::" + this->m_FunctionName, typeid (R ()), this, reinterpret_cast<FakeFunctionHandler> (&FakeMethod::FakeIt));
}
protected:
FakeCallResult FakeIt ()
{
if (this->m_Instance && g_FakeCallObject != this->m_Instance)
return kFakeCallHadNoEffect;
++this->m_CallCount;
this->ClearLastArgs ();
this->m_LastArgs.a1 = (C*) (void*) g_FakeCallObject;
if (this->m_CallOriginal)
return kFakeCallOriginal;
if (this->m_CallInstead)
this->Invoke (this->m_CallInstead, (C*) (void*) g_FakeCallObject);
return kFakeCallSucceeded;
}
};
template<typename C, typename R, typename A1>
struct FakeMethod<C, R (A1)> : __FakeMethod<C, R (C*, A1), R>
{
typedef __FakeMethod<C, R (C*, A1), R> Base;
FakeMethod (const char* className, const char* methodName)
: Base (className, methodName)
{
InstallFake (std::string (className) + "::" + methodName, typeid (R (A1)), this, reinterpret_cast<FakeFunctionHandler> (&FakeMethod::FakeIt));
}
~FakeMethod ()
{
UninstallFake (std::string (this->m_ClassName) + "::" + this->m_FunctionName, typeid (R (A1)), this, reinterpret_cast<FakeFunctionHandler> (&FakeMethod::FakeIt));
}
protected:
FakeCallResult FakeIt (A1 a1)
{
if (this->m_Instance && g_FakeCallObject != this->m_Instance)
return kFakeCallHadNoEffect;
++this->m_CallCount;
this->ClearLastArgs ();
this->m_LastArgs.a1 = (C*) (void*) g_FakeCallObject;
this->m_LastArgs.a2 = a1;
if (this->m_CallOriginal)
return kFakeCallOriginal;
if (this->m_CallInstead)
this->template Invoke<typename Base::CallInstead, C*, A1> (this->m_CallInstead, (C*) (void*) g_FakeCallObject, a1);
return kFakeCallSucceeded;
}
};
template<typename C, typename R, typename A1, typename A2>
struct FakeMethod<C, R (A1, A2)> : __FakeMethod<C, R (C*, A1, A2), R>
{
typedef __FakeMethod<C, R (C*, A1, A2), R> Base;
FakeMethod (const char* className, const char* methodName)
: Base (className, methodName)
{
InstallFake (std::string (className) + "::" + methodName, typeid (R (A1, A2)), this, reinterpret_cast<FakeFunctionHandler> (&FakeMethod::FakeIt));
}
~FakeMethod ()
{
UninstallFake (std::string (this->m_ClassName) + "::" + this->m_FunctionName, typeid (R (A1, A2)), this, reinterpret_cast<FakeFunctionHandler> (&FakeMethod::FakeIt));
}
protected:
FakeCallResult FakeIt (A1 a1, A2 a2)
{
if (this->m_Instance && g_FakeCallObject != this->m_Instance)
return kFakeCallHadNoEffect;
++this->m_CallCount;
this->ClearLastArgs ();
this->m_LastArgs.a1 = (C*) (void*) g_FakeCallObject;
this->m_LastArgs.a2 = a1;
this->m_LastArgs.a3 = a2;
if (this->m_CallOriginal)
return kFakeCallOriginal;
if (this->m_CallInstead)
this->template Invoke<typename Base::CallInstead, C*, A1, A2> (this->m_CallInstead, (C*) (void*) g_FakeCallObject, a1, a2);
return kFakeCallSucceeded;
}
};
template<typename C, typename R, typename A1, typename A2, typename A3>
struct FakeMethod<C, R (A1, A2, A3)> : __FakeMethod<C, R (C*, A1, A2, A3), R>
{
typedef __FakeMethod<C, R (C*, A1, A2, A3), R> Base;
FakeMethod (const char* className, const char* methodName)
: Base (className, methodName)
{
InstallFake (std::string (className) + "::" + methodName, typeid (R (A1, A2, A3)), this, reinterpret_cast<FakeFunctionHandler> (&FakeMethod::FakeIt));
}
~FakeMethod ()
{
UninstallFake (std::string (this->m_ClassName) + "::" + this->m_FunctionName, typeid (R (A1, A2, A3)), this, reinterpret_cast<FakeFunctionHandler> (&FakeMethod::FakeIt));
}
protected:
FakeCallResult FakeIt (A1 a1, A2 a2, A3 a3)
{
if (this->m_Instance && g_FakeCallObject != this->m_Instance)
return kFakeCallHadNoEffect;
++this->m_CallCount;
this->ClearLastArgs ();
this->m_LastArgs.a1 = (C*) (void*) g_FakeCallObject;
this->m_LastArgs.a2 = a1;
this->m_LastArgs.a3 = a2;
this->m_LastArgs.a4 = a3;
if (this->m_CallOriginal)
return kFakeCallOriginal;
if (this->m_CallInstead)
this->template Invoke<typename Base::CallInstead, C*, A1, A2, A3> (this->m_CallInstead, (C*) (void*) g_FakeCallObject, a1, a2, a3);
return kFakeCallSucceeded;
}
};
template<typename C, typename R, typename A1, typename A2, typename A3, typename A4>
struct FakeMethod<C, R (A1, A2, A3, A4)> : __FakeMethod<C, R (C*, A1, A2, A3, A4), R>
{
typedef __FakeMethod<C, R (C*, A1, A2, A3, A4), R> Base;
FakeMethod (const char* className, const char* methodName)
: Base (className, methodName)
{
InstallFake (std::string (className) + "::" + methodName, typeid (R (A1, A2, A3, A4)), this, reinterpret_cast<FakeFunctionHandler> (&FakeMethod::FakeIt));
}
~FakeMethod ()
{
UninstallFake (std::string (this->m_ClassName) + "::" + this->m_FunctionName, typeid (R (A1, A2, A3, A4)), this, reinterpret_cast<FakeFunctionHandler> (&FakeMethod::FakeIt));
}
protected:
FakeCallResult FakeIt (A1 a1, A2 a2, A3 a3, A4 a4)
{
if (this->m_Instance && g_FakeCallObject != this->m_Instance)
return kFakeCallHadNoEffect;
++this->m_CallCount;
this->ClearLastArgs ();
this->m_LastArgs.a1 = (C*) (void*) g_FakeCallObject;
this->m_LastArgs.a2 = a1;
this->m_LastArgs.a3 = a2;
this->m_LastArgs.a4 = a3;
this->m_LastArgs.a5 = a4;
if (this->m_CallOriginal)
return kFakeCallOriginal;
if (this->m_CallInstead)
this->template Invoke<typename Base::CallInstead, C*, A1, A2, A3, A4> (this->m_CallInstead, (C*) (void*) g_FakeCallObject, a1, a2, a3, a4);
return kFakeCallSucceeded;
}
};
template<typename C, typename R, typename A1, typename A2, typename A3, typename A4, typename A5>
struct FakeMethod<C, R (A1, A2, A3, A4, A5)> : __FakeMethod<C, R (C*, A1, A2, A3, A4, A5), R>
{
typedef __FakeMethod<C, R (C*, A1, A2, A3, A4, A5), R> Base;
FakeMethod (const char* className, const char* methodName)
: Base (className, methodName)
{
InstallFake (std::string (className) + "::" + methodName, typeid (R (A1, A2, A3, A4, A5)), this, reinterpret_cast<FakeFunctionHandler> (&FakeMethod::FakeIt));
}
~FakeMethod ()
{
UninstallFake (std::string (this->m_ClassName) + "::" + this->m_FunctionName, typeid (R (A1, A2, A3, A4, A5)), this, reinterpret_cast<FakeFunctionHandler> (&FakeMethod::FakeIt));
}
protected:
FakeCallResult FakeIt (A1 a1, A2 a2, A3 a3, A4 a4, A5 a5)
{
if (this->m_Instance && g_FakeCallObject != this->m_Instance)
return kFakeCallHadNoEffect;
++this->m_CallCount;
this->ClearLastArgs ();
this->m_LastArgs.a1 = (C*) (void*) g_FakeCallObject;
this->m_LastArgs.a2 = a1;
this->m_LastArgs.a3 = a2;
this->m_LastArgs.a4 = a3;
this->m_LastArgs.a5 = a4;
this->m_LastArgs.a6 = a5;
if (this->m_CallOriginal)
return kFakeCallOriginal;
if (this->m_CallInstead)
this->template Invoke<typename Base::CallInstead, C*, A1, A2, A3, A4, A5> (this->m_CallInstead, (C*) (void*) g_FakeCallObject, a1, a2, a3, a4, a5);
return kFakeCallSucceeded;
}
};
}
#undef DEPENDENT_TEMPLATE
#else // !ENABLE_UNIT_TESTS_WITH_FAKES
#define __FAKEABLE_METHOD__(className, methodName, args)
#define __FAKEABLE_FUNCTION__(functionName, args)
#define __FAKEABLE_METHOD_OVERLOADED__(className, methodName, args, signature)
#define __FAKEABLE_FUNCTION_OVERLOADED__(functionName, args, signature)
#define __FAKEABLE_STATIC_METHOD__(className, methodName, args)
#define __FAKEABLE_STATIC_METHOD_OVERLOADED__(className, methodName, args, signature)
#endif // ENABLE_UNIT_TESTS_WITH_FAKES
@baek-jinoo
Copy link

@Rene-Damm Can you provide the the imported files as well? It doesn't have to be perfect, but it would be very helpful to be able to get this type of testing up and running quickly on my legacy codebase.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment