From e52538acf34e5830126285a31ad98e3357952b5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=87=91=E6=88=9F?= Date: Mon, 21 Nov 2022 00:41:27 +0800 Subject: [PATCH] feat: parse mock class considering MockContainer annotation --- .../demo/inherit/DemoMultipleInherit.java | 4 +-- .../demo/inherit/DemoMultipleInheritTest.java | 2 +- .../agent/handler/MockClassHandler.java | 13 ++++----- .../agent/transformer/MockClassParser.java | 29 +++++++++++++++++-- 4 files changed, 35 insertions(+), 13 deletions(-) diff --git a/demo/java-demo/src/main/java/com/alibaba/demo/inherit/DemoMultipleInherit.java b/demo/java-demo/src/main/java/com/alibaba/demo/inherit/DemoMultipleInherit.java index 25d78cc..6d48a98 100644 --- a/demo/java-demo/src/main/java/com/alibaba/demo/inherit/DemoMultipleInherit.java +++ b/demo/java-demo/src/main/java/com/alibaba/demo/inherit/DemoMultipleInherit.java @@ -14,12 +14,12 @@ public class DemoMultipleInherit { return "gin"; } - private String suffix() { + private String suffix(int some, String more, Object[] parameters) { return "_al"; } public String entry() { - return prefix() + middle() + suffix(); + return prefix() + middle() + suffix(0, null, null); } } diff --git a/demo/java-demo/src/test/java/com/alibaba/demo/inherit/DemoMultipleInheritTest.java b/demo/java-demo/src/test/java/com/alibaba/demo/inherit/DemoMultipleInheritTest.java index 8208eee..62aa684 100644 --- a/demo/java-demo/src/test/java/com/alibaba/demo/inherit/DemoMultipleInheritTest.java +++ b/demo/java-demo/src/test/java/com/alibaba/demo/inherit/DemoMultipleInheritTest.java @@ -24,7 +24,7 @@ class DemoMultipleInheritTest { public static class SuffixMock { @MockInvoke(targetClass = DemoMultipleInherit.class) - private String suffix() { + private String suffix(int some, String more, Object[] parameters) { return "_it"; } } diff --git a/testable-agent/src/main/java/com/alibaba/testable/agent/handler/MockClassHandler.java b/testable-agent/src/main/java/com/alibaba/testable/agent/handler/MockClassHandler.java index 4642c52..6d06a5c 100644 --- a/testable-agent/src/main/java/com/alibaba/testable/agent/handler/MockClassHandler.java +++ b/testable-agent/src/main/java/com/alibaba/testable/agent/handler/MockClassHandler.java @@ -85,11 +85,8 @@ public class MockClassHandler extends BaseClassWithContextHandler { } } } - for (int i = 0; i < inheritedTypes.size(); i++) { - String className = inheritedTypes.get(i).getClassName(); - String fieldName = INHERITED_REF + i; - cn.fields.add(new FieldNode(ACC_PRIVATE | ACC_FINAL, fieldName, - ClassUtil.toByteCodeClassName(className), null, null)); + for (Type inheritedType : inheritedTypes) { + String className = inheritedType.getClassName(); ClassNode inheritedClassNode = ClassUtil.getClassNode(className); if (inheritedClassNode == null) { throw new IllegalArgumentException("Failed to load class " + className); @@ -104,14 +101,14 @@ public class MockClassHandler extends BaseClassWithContextHandler { Type targetClass = AnnotationUtil.getAnnotationParameter(an, FIELD_TARGET_CLASS, null, Type.class); String targetMethod = AnnotationUtil.getAnnotationParameter(an, FIELD_TARGET_METHOD, null, String.class); String desc = (targetClass == null) ? mn.desc : - MethodUtil.addParameterAtBegin(mn.desc, ClassUtil.toByteCodeClassName(targetClass.getClassName())); + MethodUtil.addParameterAtBegin(mn.desc, ClassUtil.toByteCodeClassName(targetClass.getClassName())); String name = (targetMethod == null) ? mn.name : targetMethod; MethodNode mockMethod = new MethodNode(ACC_PUBLIC, name, desc, null, null); List parameters = MethodUtil.getParameterTypes(mn.desc); int maxStack = 2; InsnList il = new InsnList(); - il.add(new VarInsnNode(ALOAD, 0)); - il.add(new FieldInsnNode(GETFIELD, ClassUtil.toSlashSeparatedName(cn.name), fieldName, ClassUtil.toByteCodeClassName(className))); + il.add(new MethodInsnNode(INVOKESTATIC, ClassUtil.toSlashSeparatedName(className), + GET_TESTABLE_REF, VOID_ARGS + ClassUtil.toByteCodeClassName(className), false)); il.add(new VarInsnNode(ALOAD, 1)); for (int pi = 2; pi < parameters.size() + 2; pi++) { ImmutablePair codeAndStack = BytecodeUtil.getLoadParameterByteCode(parameters.get(pi - 2)); diff --git a/testable-agent/src/main/java/com/alibaba/testable/agent/transformer/MockClassParser.java b/testable-agent/src/main/java/com/alibaba/testable/agent/transformer/MockClassParser.java index 33325c8..3a784b1 100644 --- a/testable-agent/src/main/java/com/alibaba/testable/agent/transformer/MockClassParser.java +++ b/testable-agent/src/main/java/com/alibaba/testable/agent/transformer/MockClassParser.java @@ -13,11 +13,11 @@ import org.objectweb.asm.tree.InnerClassNode; import org.objectweb.asm.tree.MethodNode; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import static com.alibaba.testable.agent.constant.ByteCodeConst.TYPE_CLASS; -import static com.alibaba.testable.agent.constant.ConstPool.CLASS_OBJECT; -import static com.alibaba.testable.agent.constant.ConstPool.KOTLIN_POSTFIX_COMPANION; +import static com.alibaba.testable.agent.constant.ConstPool.*; import static com.alibaba.testable.agent.util.ClassUtil.toJavaStyleClassName; import static com.alibaba.testable.agent.util.MethodUtil.isStatic; import static com.alibaba.testable.core.constant.ConstPool.CONSTRUCTOR; @@ -39,6 +39,7 @@ public class MockClassParser { for (MethodNode mn : getAllMethods(cn)) { addMethodWithAnnotationCheck(methodInfos, cn, mn); } + handleMockContainerInherits(methodInfos, cn); return methodInfos; } @@ -92,6 +93,30 @@ public class MockClassParser { return mns; } + /** + * Take care of @MockContainer annotation + */ + private void handleMockContainerInherits(List methodInfos, ClassNode cn) { + if (cn.visibleAnnotations != null) { + for (AnnotationNode an : cn.visibleAnnotations) { + if ((ClassUtil.toByteCodeClassName(ConstPool.MOCK_CONTAINER)).equals(an.desc)) { + for (Object st : AnnotationUtil.getAnnotationParameter(an, FIELD_INHERITS, + Collections.emptyList(), List.class)) { + String superClassName = ((Type)st).getClassName(); + ClassNode superCn = ClassUtil.getClassNode(superClassName); + if (superCn == null) { + LogUtil.warn("failed to load class '%s' inherited by '%s'", superClassName, cn.name); + continue; + } + for (MethodNode mn : getAllMethods(superCn)) { + addMethodWithAnnotationCheck(methodInfos, cn, mn); + } + } + } + } + } + } + private void addMethodWithAnnotationCheck(List methodInfos, ClassNode cn, MethodNode mn) { if (mn.visibleAnnotations == null) { return;