mirror of
https://github.com/LSPosed/LSPlant.git
synced 2025-05-04 20:42:02 +08:00
More unit tests
This commit is contained in:
parent
68c6b5f96b
commit
d99a17b449
@ -9,38 +9,66 @@ 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 static final List<Hooker> hookers = new ArrayList<>();
|
||||
|
||||
@Test
|
||||
public void t00_initTest() {
|
||||
public void t00_init() {
|
||||
Assert.assertTrue(LSPTest.initHooker());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void t01_hookTest() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
|
||||
public void t01_staticMethod() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
|
||||
var staticMethod = LSPTest.class.getDeclaredMethod("staticMethod");
|
||||
var staticMethodReplacement = Replacement.class.getDeclaredMethod("staticMethodReplacement");
|
||||
var staticMethodReplacement = Replacement.class.getDeclaredMethod("staticMethodReplacement", Hooker.MethodCallback.class);
|
||||
Assert.assertFalse(LSPTest.staticMethod());
|
||||
Hooker hooker1 = Hooker.hook(staticMethod, staticMethodReplacement);
|
||||
hookers.add(hooker1);
|
||||
Assert.assertNotNull(hooker1);
|
||||
|
||||
Hooker hooker = Hooker.hook(staticMethod, staticMethodReplacement, null);
|
||||
Assert.assertNotNull(hooker);
|
||||
Assert.assertTrue(LSPTest.staticMethod());
|
||||
Assert.assertFalse((Boolean) ((Method) hooker1.backup).invoke(null));
|
||||
Assert.assertFalse((boolean) hooker.backup.invoke(null));
|
||||
|
||||
Assert.assertTrue(hooker.unhook());
|
||||
Assert.assertFalse(LSPTest.staticMethod());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void t02_unhookTest() {
|
||||
for (Hooker hooker : hookers) {
|
||||
Assert.assertTrue(hooker.unhook());
|
||||
}
|
||||
Assert.assertFalse(LSPTest.staticMethod());
|
||||
public void t02_normalMethod() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
|
||||
var normalMethod = LSPTest.class.getDeclaredMethod("normalMethod", String.class, int.class, long.class);
|
||||
var normalMethodReplacement = Replacement.class.getDeclaredMethod("normalMethodReplacement", Hooker.MethodCallback.class);
|
||||
var a = "test";
|
||||
var b = 114514;
|
||||
var c = 1919810L;
|
||||
var o = a + b + c;
|
||||
var r = a + b + c + "replace";
|
||||
LSPTest test = new LSPTest();
|
||||
Assert.assertEquals(o, test.normalMethod(a, b, c));
|
||||
|
||||
Hooker hooker = Hooker.hook(normalMethod, normalMethodReplacement, new Replacement());
|
||||
Assert.assertNotNull(hooker);
|
||||
Assert.assertEquals(r, test.normalMethod(a, b, c));
|
||||
Assert.assertEquals(o, hooker.backup.invoke(test, a, b, c));
|
||||
|
||||
Assert.assertTrue(hooker.unhook());
|
||||
Assert.assertEquals(o, test.normalMethod(a, b, c));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void t03_constructor() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException {
|
||||
var constructor = LSPTest.class.getDeclaredConstructor();
|
||||
var constructorReplacement = Replacement.class.getDeclaredMethod("constructorReplacement", Hooker.MethodCallback.class);
|
||||
Assert.assertFalse(new LSPTest().field);
|
||||
Assert.assertFalse(constructor.newInstance().field);
|
||||
|
||||
Hooker hooker = Hooker.hook(constructor, constructorReplacement, new Replacement());
|
||||
Assert.assertNotNull(hooker);
|
||||
Assert.assertTrue(new LSPTest().field);
|
||||
Assert.assertTrue(constructor.newInstance().field);
|
||||
|
||||
Assert.assertTrue(hooker.unhook());
|
||||
Assert.assertFalse(new LSPTest().field);
|
||||
Assert.assertFalse(constructor.newInstance().field);
|
||||
}
|
||||
}
|
||||
|
@ -1,54 +1,53 @@
|
||||
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;
|
||||
static class MethodCallback {
|
||||
Method backup;
|
||||
Object[] args;
|
||||
|
||||
private boolean isStatic;
|
||||
private Executable target, replacement;
|
||||
MethodCallback(Method backup, Object[] args) {
|
||||
this.backup = backup;
|
||||
this.args = args;
|
||||
}
|
||||
}
|
||||
|
||||
public Method backup;
|
||||
|
||||
private Executable target;
|
||||
private Method replacement;
|
||||
private Object owner = null;
|
||||
|
||||
private Hooker() {
|
||||
}
|
||||
|
||||
private native Executable doHook(Executable original, Executable callback);
|
||||
private native Method doHook(Executable original, Method callback);
|
||||
|
||||
private native boolean doUnhook(Executable target);
|
||||
|
||||
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 Object callback(Object[] args) throws InvocationTargetException, IllegalAccessException {
|
||||
var methodCallback = new MethodCallback(backup, args);
|
||||
return replacement.invoke(owner, methodCallback);
|
||||
}
|
||||
|
||||
public boolean unhook() {
|
||||
return doUnhook(target);
|
||||
}
|
||||
|
||||
public static Hooker hook(Executable target, Executable replacement) {
|
||||
public static Hooker hook(Executable target, Method replacement, Object owner) {
|
||||
Hooker hooker = new Hooker();
|
||||
try {
|
||||
var callbackMethod = Hooker.class.getDeclaredMethod("callback", Object[].class);
|
||||
var result = hooker.doHook(target, callbackMethod);
|
||||
if (result == null) return null;
|
||||
hooker.isStatic = (replacement.getModifiers() & Modifier.STATIC) != 0;
|
||||
hooker.backup = result;
|
||||
hooker.target = target;
|
||||
hooker.replacement = replacement;
|
||||
hooker.owner = owner;
|
||||
} catch (NoSuchMethodException ignored) {
|
||||
}
|
||||
return hooker;
|
||||
|
@ -6,9 +6,19 @@ public class LSPTest {
|
||||
System.loadLibrary("test");
|
||||
}
|
||||
|
||||
boolean field;
|
||||
|
||||
LSPTest() {
|
||||
field = false;
|
||||
}
|
||||
|
||||
native static boolean initHooker();
|
||||
|
||||
static boolean staticMethod() {
|
||||
return false;
|
||||
}
|
||||
|
||||
String normalMethod(String a, int b, long c) {
|
||||
return a + b + c;
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,23 @@
|
||||
package org.lsposed.lsplant;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
|
||||
public class Replacement {
|
||||
|
||||
static boolean staticMethodReplacement() {
|
||||
static boolean staticMethodReplacement(Hooker.MethodCallback callback) {
|
||||
return true;
|
||||
}
|
||||
|
||||
String normalMethodReplacement(Hooker.MethodCallback callback) {
|
||||
var a = (String) callback.args[1];
|
||||
var b = (int) callback.args[2];
|
||||
var c = (long) callback.args[3];
|
||||
return a + b + c + "replace";
|
||||
}
|
||||
|
||||
void constructorReplacement(Hooker.MethodCallback callback) throws InvocationTargetException, IllegalAccessException {
|
||||
var test = (LSPTest) callback.args[0];
|
||||
callback.backup.invoke(test);
|
||||
test.field = true;
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user