More unit tests

This commit is contained in:
Nullptr 2022-02-18 15:35:53 +08:00
parent bdb668751b
commit db91f83f3e
5 changed files with 111 additions and 2 deletions

View File

@ -3,15 +3,45 @@ package org.lsposed.lsplant;
import android.support.test.runner.AndroidJUnit4;
import org.junit.Assert;
import org.junit.FixMethodOrder;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.MethodSorters;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
@RunWith(AndroidJUnit4.class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class UnitTest {
private final List<Hooker> hookers = new ArrayList<>();
@Test
public void initTest() {
public void t00_initTest() {
boolean result = LSPTest.initHooker();
Assert.assertTrue(result);
}
@Test
public void t01_hookTest() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
var staticMethod = LSPTest.class.getDeclaredMethod("staticMethod");
var staticMethodReplacement = Replacement.class.getDeclaredMethod("staticMethodReplacement");
Assert.assertFalse(LSPTest.staticMethod());
Hooker hooker1 = Hooker.hook(staticMethod, staticMethodReplacement);
hookers.add(hooker1);
Assert.assertNotNull(hooker1);
Assert.assertTrue(LSPTest.staticMethod());
Assert.assertFalse((Boolean) ((Method) hooker1.backup).invoke(null));
}
@Test
public void t02_unhookTest() {
for (Hooker hooker : hookers) {
Assert.assertTrue(hooker.unhook());
}
Assert.assertFalse(LSPTest.staticMethod());
}
}

View File

@ -0,0 +1,55 @@
package org.lsposed.lsplant;
import java.lang.reflect.Constructor;
import java.lang.reflect.Executable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Arrays;
public class Hooker {
public Executable backup;
private boolean isStatic;
private Executable replacement;
private Hooker() {
}
private native Executable doHook(Executable original, Executable callback);
private native boolean doUnhook(Executable replacement);
public Object callback(Object[] args) throws InvocationTargetException, IllegalAccessException, InstantiationException {
if (replacement instanceof Method) {
if (isStatic) {
return ((Method) replacement).invoke(null, args);
} else {
return ((Method) replacement).invoke(args[0], Arrays.copyOfRange(args, 1, args.length));
}
} else if (replacement instanceof Constructor) {
return ((Constructor<?>) replacement).newInstance(args);
} else {
throw new IllegalArgumentException("Unsupported executable type");
}
}
public boolean unhook() {
return doUnhook(replacement);
}
public static Hooker hook(Executable original, Executable replacement) {
Hooker hooker = new Hooker();
try {
var callbackMethod = Hooker.class.getDeclaredMethod("callback", Object[].class);
var result = hooker.doHook(original, callbackMethod);
if (result == null) return null;
hooker.isStatic = (replacement.getModifiers() & Modifier.STATIC) != 0;
hooker.backup = result;
hooker.replacement = replacement;
} catch (NoSuchMethodException ignored) {
}
return hooker;
}
}

View File

@ -7,4 +7,8 @@ public class LSPTest {
}
native static boolean initHooker();
static boolean staticMethod() {
return false;
}
}

View File

@ -0,0 +1,8 @@
package org.lsposed.lsplant;
public class Replacement {
static boolean staticMethodReplacement() {
return true;
}
}

View File

@ -37,6 +37,18 @@ Java_org_lsposed_lsplant_LSPTest_initHooker(JNIEnv*, jclass) {
return init_result;
}
extern "C"
JNIEXPORT jobject JNICALL
Java_org_lsposed_lsplant_Hooker_doHook(JNIEnv* env, jobject thiz, jobject original, jobject callback) {
return lsplant::Hook(env, original, thiz, callback);
}
extern "C"
JNIEXPORT jboolean JNICALL
Java_org_lsposed_lsplant_Hooker_doUnhook(JNIEnv* env, jobject, jobject replacement) {
return lsplant::UnHook(env, replacement);
}
JNIEXPORT jint JNICALL
JNI_OnLoad(JavaVM* vm, void* reserved) {
JNIEnv* env;
@ -48,7 +60,7 @@ JNI_OnLoad(JavaVM* vm, void* reserved) {
.inline_hooker = InlineHooker,
.inline_unhooker = InlineUnhooker,
.art_symbol_resolver = [&art](std::string_view symbol) -> void* {
auto *out = reinterpret_cast<void*>(art.getSymbAddress(symbol));
auto* out = reinterpret_cast<void*>(art.getSymbAddress(symbol));
return out;
}
};