mirror of
https://git.recroomarchive.org/Radium/libradhook.git
synced 2026-08-07 09:10:59 +00:00
api changes, check README
This commit is contained in:
68
tests/test_queue.cpp
Normal file
68
tests/test_queue.cpp
Normal file
@@ -0,0 +1,68 @@
|
||||
#include <cassert>
|
||||
#include "radhook/radhook.h"
|
||||
|
||||
static int fnA() { return 1; }
|
||||
static int detourA() { return 100; }
|
||||
|
||||
static int fnB() { return 2; }
|
||||
static int detourB() { return 200; }
|
||||
|
||||
static int fnC() { return 3; }
|
||||
static int detourC() { return 300; }
|
||||
|
||||
int main() {
|
||||
RadHookHandle hA = nullptr;
|
||||
RadHookHandle hB = nullptr;
|
||||
|
||||
assert(RadHookCreate((void*)fnA, (void*)detourA, &hA) == RadHookResult::Success);
|
||||
assert(RadHookCreate((void*)fnB, (void*)detourB, &hB) == RadHookResult::Success);
|
||||
|
||||
// start both from a known, disabled state
|
||||
assert(RadHookDisable(hA) == RadHookResult::Success);
|
||||
assert(RadHookDisable(hB) == RadHookResult::Success);
|
||||
assert(fnA() == 1);
|
||||
assert(fnB() == 2);
|
||||
|
||||
// queueing must not apply immediately
|
||||
assert(RadHookQueueEnable(hA) == RadHookResult::Success);
|
||||
assert(RadHookQueueEnable(hB) == RadHookResult::Success);
|
||||
assert(!RadHookIsEnabled(hA));
|
||||
assert(!RadHookIsEnabled(hB));
|
||||
assert(fnA() == 1);
|
||||
assert(fnB() == 2);
|
||||
|
||||
// apply enables both together
|
||||
assert(RadHookApplyQueued() == RadHookResult::Success);
|
||||
assert(RadHookIsEnabled(hA));
|
||||
assert(RadHookIsEnabled(hB));
|
||||
assert(fnA() == 100);
|
||||
assert(fnB() == 200);
|
||||
|
||||
// last queued action before apply wins
|
||||
assert(RadHookQueueDisable(hA) == RadHookResult::Success);
|
||||
assert(RadHookQueueEnable(hA) == RadHookResult::Success);
|
||||
assert(RadHookApplyQueued() == RadHookResult::Success);
|
||||
assert(RadHookIsEnabled(hA));
|
||||
|
||||
// an apply with nothing queued is a no-op
|
||||
assert(RadHookApplyQueued() == RadHookResult::Success);
|
||||
|
||||
// queueing a redundant transition (already enabled) still applies cleanly
|
||||
assert(RadHookQueueEnable(hA) == RadHookResult::Success);
|
||||
assert(RadHookApplyQueued() == RadHookResult::Success);
|
||||
assert(RadHookIsEnabled(hA));
|
||||
|
||||
// invalid handles
|
||||
assert(RadHookQueueEnable(nullptr) == RadHookResult::InvalidHandle);
|
||||
assert(RadHookQueueDisable(nullptr) == RadHookResult::InvalidHandle);
|
||||
|
||||
// a destroyed hook can no longer be queued
|
||||
RadHookHandle hC = nullptr;
|
||||
assert(RadHookCreate((void*)fnC, (void*)detourC, &hC) == RadHookResult::Success);
|
||||
RadHookDestroy(hC);
|
||||
assert(RadHookQueueEnable(hC) == RadHookResult::InvalidHandle);
|
||||
|
||||
RadHookDestroy(hA);
|
||||
RadHookDestroy(hB);
|
||||
return 0;
|
||||
}
|
||||
20
tests/test_version.cpp
Normal file
20
tests/test_version.cpp
Normal file
@@ -0,0 +1,20 @@
|
||||
#include <cassert>
|
||||
#include "radhook/radhook.h"
|
||||
|
||||
int main() {
|
||||
int major = -1, minor = -1, patch = -1;
|
||||
RadHookGetVersion(&major, &minor, &patch);
|
||||
|
||||
assert(major == RADHOOK_VERSION_MAJOR);
|
||||
assert(minor == RADHOOK_VERSION_MINOR);
|
||||
assert(patch == RADHOOK_VERSION_PATCH);
|
||||
|
||||
// individual out params may be omitted independently
|
||||
int onlyMajor = -1;
|
||||
RadHookGetVersion(&onlyMajor, nullptr, nullptr);
|
||||
assert(onlyMajor == RADHOOK_VERSION_MAJOR);
|
||||
|
||||
// must not crash
|
||||
RadHookGetVersion(nullptr, nullptr, nullptr);
|
||||
return 0;
|
||||
}
|
||||
68
tests/test_vtable.cpp
Normal file
68
tests/test_vtable.cpp
Normal file
@@ -0,0 +1,68 @@
|
||||
#include <cassert>
|
||||
#include "radhook/radhook.h"
|
||||
|
||||
struct IFoo {
|
||||
virtual int Value() { return 7; }
|
||||
virtual ~IFoo() = default;
|
||||
};
|
||||
|
||||
static int DetourValue(IFoo* /*self*/) { return 777; }
|
||||
|
||||
using Fn = int(*)(IFoo*);
|
||||
|
||||
int main() {
|
||||
IFoo obj;
|
||||
void** vtable = *reinterpret_cast<void***>(&obj);
|
||||
|
||||
RadHookHandle h = nullptr;
|
||||
assert(RadHookVTableCreate(vtable, 0, (void*)DetourValue, &h) == RadHookResult::Success);
|
||||
assert(RadHookIsValid(h));
|
||||
assert(RadHookIsEnabled(h));
|
||||
|
||||
// handle is created enabled, so the swap must already be visible
|
||||
assert(obj.Value() == 777);
|
||||
assert(reinterpret_cast<Fn>(vtable[0])(&obj) == 777);
|
||||
|
||||
void* originalEntry = RadHookGetTarget(h);
|
||||
assert(originalEntry != nullptr);
|
||||
assert(RadHookGetDetour(h) == reinterpret_cast<void*>(DetourValue));
|
||||
|
||||
// disable restores the original vtable entry
|
||||
assert(RadHookDisable(h) == RadHookResult::Success);
|
||||
assert(!RadHookIsEnabled(h));
|
||||
assert(obj.Value() == 7);
|
||||
assert(vtable[0] == originalEntry);
|
||||
|
||||
// re-enable re-applies the swap
|
||||
assert(RadHookEnable(h) == RadHookResult::Success);
|
||||
assert(obj.Value() == 777);
|
||||
|
||||
// no relocation is needed for vtable hooks -- the trampoline is the
|
||||
// original entry itself and can be called directly while the hook is live
|
||||
auto original = RadHookGetOriginalAs<Fn>(h);
|
||||
assert(reinterpret_cast<void*>(original) == originalEntry);
|
||||
assert(original(&obj) == 7);
|
||||
|
||||
RadHookDestroy(h);
|
||||
assert(!RadHookIsValid(h));
|
||||
assert(obj.Value() == 7);
|
||||
|
||||
// queueing works uniformly across inline and vtable hook kinds
|
||||
RadHookHandle h2 = nullptr;
|
||||
assert(RadHookVTableCreate(vtable, 0, (void*)DetourValue, &h2) == RadHookResult::Success);
|
||||
assert(RadHookQueueDisable(h2) == RadHookResult::Success);
|
||||
assert(RadHookIsEnabled(h2)); // not applied yet
|
||||
assert(RadHookApplyQueued() == RadHookResult::Success);
|
||||
assert(!RadHookIsEnabled(h2));
|
||||
assert(obj.Value() == 7);
|
||||
RadHookDestroy(h2);
|
||||
|
||||
// invalid inputs
|
||||
RadHookHandle bad = nullptr;
|
||||
assert(RadHookVTableCreate(nullptr, 0, (void*)DetourValue, &bad) == RadHookResult::InvalidTarget);
|
||||
assert(bad == nullptr);
|
||||
assert(RadHookVTableCreate(vtable, 0, nullptr, &bad) == RadHookResult::InvalidDetour);
|
||||
assert(bad == nullptr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user