Open
Description
核心思想就是为lambda表达式生成独一无二的类和执行函数。
#include <cassert>
#include <utility>
#include "cpp_stub/stub.h"
/***
* FakeFunction 可以封装一个函数或lambda表达式,用于替换目标函数。
* 需要注意的是模板参数中的N和S,对于同一个测试用例中的FakeFunction,一定不能有相同的N、S组合。
* 如果测试用例中只有一个FakeFunction或传入的函数声明都不相同时,可以省略N或S。
* 如果想要通过某个类型区分FakeFunction,请设置模板参数S。
*
* 使用示例:
* auto fun = []() { prstd::size_tf("hehe\n"); };
* FakeFunction<void(void), 1> fl(fun);
*
* decltype(fl)::Exec 即为lambda表达式的函数指针,可以用于Stub::set函数。
*/
template <class T, std::size_t N = 0, class S = void>
class FakeFunction;
template <class Res, class... Args, std::size_t N, class S>
class FakeFunction<Res(Args...), N, S> {
public:
template <class Function>
explicit FakeFunction(Function f)
: m_Call(Call<Function>), m_Release(Release<Function>), m_Function(new Function(f)) {
assert(m_Instance == nullptr);
m_Instance = this;
}
template <class Method, class Function>
explicit FakeFunction(Stub* stub, Method m, Function f) : FakeFunction(f) {
stub->set(m, Exec);
}
template <class Method, class Function, class ExitFunction>
explicit FakeFunction(Stub* stub, Method m, Function f, ExitFunction e) : FakeFunction(stub, m, f) {
m_CallWhenExit = CallWhenExit<ExitFunction>;
m_FunctionCallWhenExit = new ExitFunction(e);
}
~FakeFunction() {
if (m_CallWhenExit != nullptr) {
m_CallWhenExit(this);
m_CallWhenExit = nullptr;
}
m_Release(this);
m_Release = nullptr;
m_Instance = nullptr;
}
FakeFunction(const FakeFunction&) = delete;
FakeFunction& operator=(const FakeFunction&) = delete;
static Res Exec(Args... args) { return m_Instance->m_Call(m_Instance, std::forward<Args>(args)...); }
private:
template <class Function>
static Res Call(FakeFunction* that, Args... args) {
++(that->CallTimes);
Function* f = static_cast<Function*>(that->m_Function);
return (*f)(std::forward<Args>(args)...);
}
template <class Function>
static void Release(FakeFunction* that) {
delete static_cast<Function*>(that->m_Function);
}
template <class Function>
static void CallWhenExit(FakeFunction* that) {
(*static_cast<Function*>(that->m_FunctionCallWhenExit))(that->CallTimes);
delete static_cast<Function*>(that->m_FunctionCallWhenExit);
}
public:
int CallTimes = 0;
private:
static FakeFunction* m_Instance;
Res (*m_Call)(FakeFunction*, Args...) = nullptr;
void (*m_Release)(FakeFunction*) = nullptr;
void (*m_CallWhenExit)(FakeFunction*) = nullptr;
void* m_Function = nullptr;
void* m_FunctionCallWhenExit = nullptr;
};
template <class Res, class... Args, std::size_t N, class S>
FakeFunction<Res(Args...), N, S>* FakeFunction<Res(Args...), N, S>::m_Instance = nullptr;