diff --git a/core-legacy/sourcehook/test/test1.cpp b/core-legacy/sourcehook/test/test1.cpp index d55e7af..6632090 100644 --- a/core-legacy/sourcehook/test/test1.cpp +++ b/core-legacy/sourcehook/test/test1.cpp @@ -426,9 +426,7 @@ bool TestBasic(std::string &error) // 1) SH_CALL it and call it normally - return true; SH_CALL(pTest, &Test::F1)(); - pTest->F1(); @@ -472,16 +470,23 @@ bool TestBasic(std::string &error) // 4) Test source-level compat with callclasses SourceHook::CallClass *pCC = SH_GET_CALLCLASS(pTest); + // bug 4210 + SH_CALL(pCC, &Test::F1)(); + + CHECK_STATES((&g_States, + new State_F1_Called, + NULL), "bug 4210"); + SH_CALL(pCC, &Test::F1)(); pTest->F1(); - SH_RELEASE_CALLCLASS(pCC); - CHECK_STATES((&g_States, new State_F1_Called, new State_F1_PreHandler_Called(&f1_handlers), NULL), "Part 4"); + SH_RELEASE_CALLCLASS(pCC); + // 5) Check ignore / supercede g_F1Pre_WhatToDo = MRES_SUPERCEDE; SH_CALL(pTest, &Test::F1)(); diff --git a/core-legacy/sourcehook/test/testevents.h b/core-legacy/sourcehook/test/testevents.h index ef7c891..9123469 100644 --- a/core-legacy/sourcehook/test/testevents.h +++ b/core-legacy/sourcehook/test/testevents.h @@ -86,6 +86,14 @@ namespace } } + if (!ok && g_Verbose) + { + std::cout << std::endl << "FAIL: Should be:" << std::endl; + DumpStates(&requiredstates); + std::cout << std::endl << "FAIL: Is:" << std::endl; + DumpStates(sl); + } + for (StateList::iterator iter = requiredstates.begin(); iter != requiredstates.end(); ++iter) delete *iter; for (StateList::iterator iter = sl->begin(); iter != sl->end(); ++iter) diff --git a/core-legacy/sourcehook/test/testvphooks.cpp b/core-legacy/sourcehook/test/testvphooks.cpp new file mode 100644 index 0000000..acbeff8 --- /dev/null +++ b/core-legacy/sourcehook/test/testvphooks.cpp @@ -0,0 +1,260 @@ +#include +#include "sourcehook.h" +#include "sourcehook_test.h" +#include "testevents.h" + +// TEST VP HOOKS +// Test vfnptr-wide hooks + +namespace +{ + StateList g_States; + SourceHook::ISourceHook *g_SHPtr; + SourceHook::Plugin g_PLID; + + class IBase; + + MAKE_STATE_1(State_D1_Func1, IBase *); + MAKE_STATE_1(State_D2_Func1, IBase *); + MAKE_STATE_1(State_Func1_Pre, IBase *); + MAKE_STATE_1(State_Func1_Post, IBase *); + + MAKE_STATE_1(State_D1_Func2, IBase *); + MAKE_STATE_1(State_D2_Func2, IBase *); + MAKE_STATE_1(State_Func2_Pre, IBase *); + MAKE_STATE_1(State_Func2_Post, IBase *); + + MAKE_STATE_2(State_D1_Func3, IBase *, int); + MAKE_STATE_2(State_D2_Func3, IBase *, int); + MAKE_STATE_2(State_Func3_Pre, IBase *, int); + MAKE_STATE_2(State_Func3_Post, IBase *, int); + + class IBase + { + public: + virtual void Func1() = 0; + virtual void Func2() = 0; + virtual void Func3(int x) = 0; + }; + + class CDerived1 : public IBase + { + public: + virtual void Func1() + { + ADD_STATE(State_D1_Func1(this)); + } + virtual void Func2() + { + ADD_STATE(State_D1_Func2(this)); + } + virtual void Func3(int x) + { + ADD_STATE(State_D1_Func3(this, x)); + } + }; + + class CDerived2 : public IBase + { + public: + virtual void Func1() + { + ADD_STATE(State_D2_Func1(this)); + } + virtual void Func2() + { + ADD_STATE(State_D2_Func2(this)); + } + virtual void Func3(int x) + { + ADD_STATE(State_D2_Func3(this, x)); + } + }; + + void Handler_Func1_Pre() + { + ADD_STATE(State_Func1_Pre(META_IFACEPTR(IBase))); + } + void Handler_Func1_Post() + { + ADD_STATE(State_Func1_Post(META_IFACEPTR(IBase))); + } + int g_F2_Pre_HookToRemove = 0; + void Handler_Func2_Pre() + { + ADD_STATE(State_Func2_Pre(META_IFACEPTR(IBase))); + SH_REMOVE_HOOK_ID(g_F2_Pre_HookToRemove); + } + void Handler_Func2_Post() + { + ADD_STATE(State_Func2_Post(META_IFACEPTR(IBase))); + } + + + void Handler_Func3_Pre(int x) + { + ADD_STATE(State_Func3_Pre(META_IFACEPTR(IBase), x)); + + RETURN_META_NEWPARAMS(MRES_IGNORED, &IBase::Func3, (x+1)); + } + void Handler_Func3_Post(int x) + { + ADD_STATE(State_Func3_Post(META_IFACEPTR(IBase), x)); + } + + SH_DECL_HOOK0_void(IBase, Func1, SH_NOATTRIB, 0); + SH_DECL_HOOK0_void(IBase, Func2, SH_NOATTRIB, 0); + SH_DECL_HOOK1_void(IBase, Func3, SH_NOATTRIB, 0, int); + + SH_DECL_MANUALHOOK1_void(IBase_Func3_Manual, 2, 0, 0, int); +} + +bool TestVPHooks(std::string &error) +{ + GET_SHPTR(g_SHPtr); + g_PLID = 1337; + + CDerived1 d1i1; + CDerived1 d1i2; + CDerived2 d2i1; + + IBase *p_d1i1 = &d1i1; + IBase *p_d1i2 = &d1i2; + IBase *p_d2i1 = &d2i1; + + int hook1 = SH_ADD_VPHOOK(IBase, Func1, p_d1i1, SH_STATIC(Handler_Func1_Pre), false); + + p_d1i1->Func1(); + p_d1i2->Func1(); + p_d2i1->Func1(); + + CHECK_STATES((&g_States, + new State_Func1_Pre(p_d1i1), + new State_D1_Func1(p_d1i1), + + new State_Func1_Pre(p_d1i2), + new State_D1_Func1(p_d1i2), + + new State_D2_Func1(p_d2i1), + NULL), "Part 1"); + + SH_REMOVE_HOOK_ID(hook1); + + p_d1i1->Func1(); + p_d1i2->Func1(); + p_d2i1->Func1(); + + CHECK_STATES((&g_States, + new State_D1_Func1(p_d1i1), + + new State_D1_Func1(p_d1i2), + + new State_D2_Func1(p_d2i1), + NULL), "Part 2"); + + + // Normal hook, then vp hook + + int hook2 = SH_ADD_HOOK(IBase, Func1, p_d1i1, SH_STATIC(Handler_Func1_Pre), false); + hook1 = SH_ADD_VPHOOK(IBase, Func1, p_d1i1, SH_STATIC(Handler_Func1_Pre), false); + + p_d1i1->Func1(); + p_d1i2->Func1(); + p_d2i1->Func1(); + + CHECK_STATES((&g_States, + new State_Func1_Pre(p_d1i1), + new State_Func1_Pre(p_d1i1), + new State_D1_Func1(p_d1i1), + + new State_Func1_Pre(p_d1i2), + new State_D1_Func1(p_d1i2), + + new State_D2_Func1(p_d2i1), + NULL), "Part 3"); + + SH_REMOVE_HOOK_ID(hook1); + + p_d1i1->Func1(); + p_d1i2->Func1(); + p_d2i1->Func1(); + + CHECK_STATES((&g_States, + new State_Func1_Pre(p_d1i1), + new State_D1_Func1(p_d1i1), + + new State_D1_Func1(p_d1i2), + + new State_D2_Func1(p_d2i1), + NULL), "Part 4"); + + SH_REMOVE_HOOK_ID(hook2); + + p_d1i1->Func1(); + p_d1i2->Func1(); + p_d2i1->Func1(); + + CHECK_STATES((&g_States, + new State_D1_Func1(p_d1i1), + + new State_D1_Func1(p_d1i2), + + new State_D2_Func1(p_d2i1), + NULL), "Part 5"); + + // Test this: + // Normal hook AND vp hook on Func2 + // Func2's pre handler removes the VP hook. + + hook1 = SH_ADD_VPHOOK(IBase, Func2, p_d1i1, SH_STATIC(Handler_Func2_Pre), false); + hook2 = SH_ADD_HOOK(IBase, Func2, p_d1i1, SH_STATIC(Handler_Func2_Pre), false); + + g_F2_Pre_HookToRemove = hook1; + p_d1i1->Func2(); + p_d1i1->Func2(); + + CHECK_STATES((&g_States, + new State_Func2_Pre(p_d1i1), + new State_D1_Func2(p_d1i1), + + new State_Func2_Pre(p_d1i1), + new State_D1_Func2(p_d1i1), + + NULL), "Part 6"); + + SH_REMOVE_HOOK_ID(hook1); + + // Hook function 3: + // Using manualhook, VP + hook1 = SH_ADD_MANUALVPHOOK(IBase_Func3_Manual, p_d1i1, SH_STATIC(Handler_Func3_Pre), false); + + // Normally, VP + hook2 = SH_ADD_VPHOOK(IBase, Func3, p_d1i1, SH_STATIC(Handler_Func3_Pre), false); + + // Normally, no VP + int hook3 = SH_ADD_HOOK(IBase, Func3, p_d1i1, SH_STATIC(Handler_Func3_Pre), false); + + p_d1i1->Func3(1); + + CHECK_STATES((&g_States, + new State_Func3_Pre(p_d1i1, 1), // manual vp hook + new State_Func3_Pre(p_d1i1, 2), // normal vp hook + new State_Func3_Pre(p_d1i1, 3), // normal non-vp hook + + new State_D1_Func3(p_d1i1, 4), // function + + NULL), "Part 7.1"); + + p_d1i2->Func3(1); + + CHECK_STATES((&g_States, + new State_Func3_Pre(p_d1i2, 1), // manual vp hook + new State_Func3_Pre(p_d1i2, 2), // normal vp hook + + new State_D1_Func3(p_d1i2, 3), // function + + NULL), "Part 7.2"); + + return true; +} +