mirror of
https://git.recroomarchive.org/Radium/libradhook.git
synced 2026-08-07 09:10:59 +00:00
initial commit
This commit is contained in:
16
tests/CMakeLists.txt
Normal file
16
tests/CMakeLists.txt
Normal file
@@ -0,0 +1,16 @@
|
||||
file(GLOB TEST_FILES CONFIGURE_DEPENDS "*.cpp")
|
||||
|
||||
foreach(TEST_FILE ${TEST_FILES})
|
||||
get_filename_component(TEST_NAME ${TEST_FILE} NAME_WE)
|
||||
|
||||
add_executable(${TEST_NAME} ${TEST_FILE})
|
||||
target_link_libraries(${TEST_NAME} PRIVATE radhook)
|
||||
|
||||
add_test(NAME ${TEST_NAME} COMMAND ${TEST_NAME})
|
||||
|
||||
add_custom_command(TARGET ${TEST_NAME} POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||
$<TARGET_FILE:radhook>
|
||||
$<TARGET_FILE_DIR:${TEST_NAME}>
|
||||
)
|
||||
endforeach()
|
||||
18
tests/test_basic.cpp
Normal file
18
tests/test_basic.cpp
Normal file
@@ -0,0 +1,18 @@
|
||||
#include <cassert>
|
||||
#include "radhook/radhook.h"
|
||||
|
||||
static int fn() { return 42; }
|
||||
static int detour() { return 1337; }
|
||||
|
||||
using Fn = int(*)();
|
||||
|
||||
int main() {
|
||||
RadHookHandle h = nullptr;
|
||||
|
||||
auto r = RadHookCreate((void*)fn, (void*)detour, &h);
|
||||
assert(r == RadHookResult::Success);
|
||||
assert(RadHookIsValid(h));
|
||||
|
||||
RadHookDestroy(h);
|
||||
return 0;
|
||||
}
|
||||
24
tests/test_enable_disable.cpp
Normal file
24
tests/test_enable_disable.cpp
Normal file
@@ -0,0 +1,24 @@
|
||||
#include <cassert>
|
||||
#include "radhook/radhook.h"
|
||||
|
||||
static int fn() { return 42; }
|
||||
static int detour() { return 1337; }
|
||||
|
||||
using Fn = int(*)();
|
||||
|
||||
int main() {
|
||||
RadHookHandle h = nullptr;
|
||||
|
||||
RadHookCreate((void*)fn, (void*)detour, &h);
|
||||
|
||||
assert(RadHookIsEnabled(h));
|
||||
|
||||
RadHookDisable(h);
|
||||
assert(!RadHookIsEnabled(h));
|
||||
|
||||
RadHookEnable(h);
|
||||
assert(RadHookIsEnabled(h));
|
||||
|
||||
RadHookDestroy(h);
|
||||
return 0;
|
||||
}
|
||||
30
tests/test_execution_flow.cpp
Normal file
30
tests/test_execution_flow.cpp
Normal file
@@ -0,0 +1,30 @@
|
||||
#include <cassert>
|
||||
#include "radhook/radhook.h"
|
||||
|
||||
static int fn() { return 42; }
|
||||
static int detour() { return 1337; }
|
||||
|
||||
using Fn = int(*)();
|
||||
|
||||
int main() {
|
||||
RadHookHandle h = nullptr;
|
||||
|
||||
RadHookCreate((void*)fn, (void*)detour, &h);
|
||||
|
||||
// must trigger detour
|
||||
assert(fn() == 1337);
|
||||
|
||||
// disable restores original
|
||||
RadHookDisable(h);
|
||||
assert(fn() == 42);
|
||||
|
||||
// re-enable restores hook
|
||||
RadHookEnable(h);
|
||||
assert(fn() == 1337);
|
||||
|
||||
// trampoline correctness
|
||||
auto orig = RadHookGetOriginalAs<Fn>(h);
|
||||
assert(orig() == 42);
|
||||
|
||||
RadHookDestroy(h);
|
||||
}
|
||||
19
tests/test_failure_cases.cpp
Normal file
19
tests/test_failure_cases.cpp
Normal file
@@ -0,0 +1,19 @@
|
||||
#include <cassert>
|
||||
#include "radhook/radhook.h"
|
||||
|
||||
static int fn() { return 42; }
|
||||
static int detour() { return 1337; }
|
||||
|
||||
int main() {
|
||||
RadHookHandle h = nullptr;
|
||||
|
||||
// invalid detour
|
||||
auto r1 = RadHookCreate((void*)fn, nullptr, &h);
|
||||
assert(r1 != RadHookResult::Success);
|
||||
|
||||
// invalid target
|
||||
auto r2 = RadHookCreate(nullptr, (void*)detour, &h);
|
||||
assert(r2 != RadHookResult::Success);
|
||||
|
||||
return 0;
|
||||
}
|
||||
19
tests/test_invalid_inputs.cpp
Normal file
19
tests/test_invalid_inputs.cpp
Normal file
@@ -0,0 +1,19 @@
|
||||
#include <cassert>
|
||||
#include "radhook/radhook.h"
|
||||
|
||||
static int fn() { return 42; }
|
||||
static int detour() { return 1337; }
|
||||
|
||||
int main() {
|
||||
RadHookHandle h = nullptr;
|
||||
|
||||
// invalid detour
|
||||
assert(RadHookCreate((void*)fn, nullptr, &h) != RadHookResult::Success);
|
||||
|
||||
// invalid target
|
||||
assert(RadHookCreate(nullptr, (void*)detour, &h) != RadHookResult::Success);
|
||||
|
||||
// invalid handle operations
|
||||
assert(RadHookEnable(nullptr) == RadHookResult::InvalidHandle || RadHookEnable(nullptr) != RadHookResult::Success);
|
||||
assert(RadHookDisable(nullptr) == RadHookResult::InvalidHandle || RadHookDisable(nullptr) != RadHookResult::Success);
|
||||
}
|
||||
23
tests/test_lifecycle.cpp
Normal file
23
tests/test_lifecycle.cpp
Normal file
@@ -0,0 +1,23 @@
|
||||
#include <cassert>
|
||||
#include "radhook/radhook.h"
|
||||
|
||||
static int fn() { return 42; }
|
||||
static int detour() { return 1337; }
|
||||
|
||||
int main() {
|
||||
RadHookHandle h = nullptr;
|
||||
|
||||
// destroy before create safety
|
||||
assert(RadHookDestroy(nullptr) != RadHookResult::Success);
|
||||
|
||||
RadHookCreate((void*)fn, (void*)detour, &h);
|
||||
|
||||
RadHookDestroy(h);
|
||||
|
||||
// use after destroy safety
|
||||
assert(RadHookEnable(h) != RadHookResult::Success);
|
||||
assert(RadHookDisable(h) != RadHookResult::Success);
|
||||
assert(RadHookIsValid(h) == false || true); // depends on implementation
|
||||
|
||||
return 0;
|
||||
}
|
||||
21
tests/test_memory_integrity.cpp
Normal file
21
tests/test_memory_integrity.cpp
Normal file
@@ -0,0 +1,21 @@
|
||||
#include <cassert>
|
||||
#include "radhook/radhook.h"
|
||||
|
||||
static int fn() { return 42; }
|
||||
static int detour() { return 1337; }
|
||||
|
||||
int main() {
|
||||
RadHookHandle h = nullptr;
|
||||
|
||||
RadHookCreate((void*)fn, (void*)detour, &h);
|
||||
|
||||
for (int i = 0; i < 10000; i++) {
|
||||
RadHookEnable(h);
|
||||
assert(fn() == 1337);
|
||||
|
||||
RadHookDisable(h);
|
||||
assert(fn() == 42);
|
||||
}
|
||||
|
||||
RadHookDestroy(h);
|
||||
}
|
||||
56
tests/test_stability.cpp
Normal file
56
tests/test_stability.cpp
Normal file
@@ -0,0 +1,56 @@
|
||||
#include <cassert>
|
||||
#include <vector>
|
||||
#include "radhook/radhook.h"
|
||||
|
||||
static int fn() { return 42; }
|
||||
static int detour() { return 1337; }
|
||||
|
||||
int main() {
|
||||
RadHookHandle handles[200];
|
||||
size_t count = 0;
|
||||
|
||||
// create many hooks
|
||||
for (int i = 0; i < 200; i++) {
|
||||
RadHookHandle h = nullptr;
|
||||
auto r = RadHookCreate(
|
||||
(void*)fn,
|
||||
(void*)detour,
|
||||
&h
|
||||
);
|
||||
|
||||
assert(r == RadHookResult::Success);
|
||||
assert(h != nullptr);
|
||||
|
||||
handles[count++] = h;
|
||||
}
|
||||
|
||||
// enumerate
|
||||
RadHookHandle listed[200];
|
||||
size_t listedCount = RadHookEnumerate(listed, 200);
|
||||
assert(listedCount == 200);
|
||||
|
||||
// every created handle must still be valid
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
assert(RadHookIsValid(handles[i]));
|
||||
}
|
||||
|
||||
// destroy half of them
|
||||
for (size_t i = 0; i < count; i += 2) {
|
||||
RadHookDestroy(handles[i]);
|
||||
}
|
||||
|
||||
// validate
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
if (i % 2 == 0) {
|
||||
assert(!RadHookIsValid(handles[i]));
|
||||
} else {
|
||||
assert(RadHookIsValid(handles[i]));
|
||||
}
|
||||
}
|
||||
|
||||
// final enumeration must not return destroyed hooks
|
||||
size_t finalCount = RadHookEnumerate(listed, 200);
|
||||
assert(finalCount == 100);
|
||||
|
||||
return 0;
|
||||
}
|
||||
20
tests/test_state_transitions.cpp
Normal file
20
tests/test_state_transitions.cpp
Normal file
@@ -0,0 +1,20 @@
|
||||
#include <cassert>
|
||||
#include "radhook/radhook.h"
|
||||
|
||||
static int fn() { return 42; }
|
||||
static int detour() { return 1337; }
|
||||
|
||||
int main() {
|
||||
RadHookHandle h = nullptr;
|
||||
|
||||
assert(RadHookCreate((void*)fn, (void*)detour, &h) == RadHookResult::Success);
|
||||
|
||||
// idempotent enable/disable behavior
|
||||
assert(RadHookEnable(h) != RadHookResult::Unknown);
|
||||
assert(RadHookEnable(h) == RadHookResult::AlreadyEnabled || RadHookIsEnabled(h));
|
||||
|
||||
assert(RadHookDisable(h) != RadHookResult::Unknown);
|
||||
assert(!RadHookIsEnabled(h) || RadHookDisable(h) == RadHookResult::AlreadyDisabled);
|
||||
|
||||
RadHookDestroy(h);
|
||||
}
|
||||
19
tests/test_stress_churn.cpp
Normal file
19
tests/test_stress_churn.cpp
Normal file
@@ -0,0 +1,19 @@
|
||||
#include <cassert>
|
||||
#include "radhook/radhook.h"
|
||||
|
||||
static int fn() { return 42; }
|
||||
static int detour() { return 1337; }
|
||||
|
||||
int main() {
|
||||
for (int i = 0; i < 1000; i++) {
|
||||
RadHookHandle h = nullptr;
|
||||
|
||||
auto r = RadHookCreate((void*)fn, (void*)detour, &h);
|
||||
assert(r == RadHookResult::Success);
|
||||
|
||||
RadHookEnable(h);
|
||||
RadHookDisable(h);
|
||||
|
||||
RadHookDestroy(h);
|
||||
}
|
||||
}
|
||||
22
tests/test_trampoline.cpp
Normal file
22
tests/test_trampoline.cpp
Normal file
@@ -0,0 +1,22 @@
|
||||
#include <cassert>
|
||||
#include "radhook/radhook.h"
|
||||
|
||||
static int fn() { return 42; }
|
||||
static int detour() { return 1337; }
|
||||
|
||||
using Fn = int(*)();
|
||||
|
||||
int main() {
|
||||
RadHookHandle h = nullptr;
|
||||
|
||||
RadHookCreate((void*)fn, (void*)detour, &h);
|
||||
|
||||
auto orig = RadHookGetOriginalAs<Fn>(h);
|
||||
assert(orig != nullptr);
|
||||
|
||||
// trampoline must bypass hook
|
||||
assert(orig() == 42);
|
||||
|
||||
RadHookDestroy(h);
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user