From 190cf4cc3c6bcf06c3808f2cb1e739767499002c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=87=91=E6=88=9F?= Date: Wed, 24 Feb 2021 14:31:50 +0800 Subject: [PATCH] should handle frame byte code when mock substitutions --- .../testable/agent/handler/SourceClassHandler.java | 12 ++++++++++++ .../alibaba/testable/agent/model/MethodInfo.java | 13 ++++++++++++- .../testable/agent/transformer/MockClassParser.java | 11 ++++++----- 3 files changed, 30 insertions(+), 6 deletions(-) diff --git a/testable-agent/src/main/java/com/alibaba/testable/agent/handler/SourceClassHandler.java b/testable-agent/src/main/java/com/alibaba/testable/agent/handler/SourceClassHandler.java index 5d83544..d82218c 100644 --- a/testable-agent/src/main/java/com/alibaba/testable/agent/handler/SourceClassHandler.java +++ b/testable-agent/src/main/java/com/alibaba/testable/agent/handler/SourceClassHandler.java @@ -84,6 +84,7 @@ public class SourceClassHandler extends BaseClassHandler { // it's a member or static method and an inject method for it exist int rangeStart = getMemberMethodStart(instructions, i); if (rangeStart >= 0) { + handleFrameStackChange(mn, mockMethod, rangeStart, i); instructions = replaceMemberCallOps(mn, mockMethod, instructions, node.owner, node.getOpcode(), rangeStart, i); i = rangeStart; @@ -249,6 +250,17 @@ public class SourceClassHandler extends BaseClassHandler { return mn.instructions.toArray(); } + private void handleFrameStackChange(MethodNode mn, MethodInfo mockMethod, int start, int end) { + AbstractInsnNode curInsn = mn.instructions.get(start); + AbstractInsnNode endInsn = mn.instructions.get(end); + do { + if (curInsn instanceof FrameNode && ((FrameNode)curInsn).type == F_FULL) { + ((FrameNode)curInsn).stack.add(0, mockMethod.getMockClass()); + } + curInsn = curInsn.getNext(); + } while (!curInsn.equals(endInsn)); + } + private boolean isCompanionMethod(String ownerClass, int opcode) { return Opcodes.INVOKEVIRTUAL == opcode && ClassUtil.isCompanionClassName(ownerClass); } diff --git a/testable-agent/src/main/java/com/alibaba/testable/agent/model/MethodInfo.java b/testable-agent/src/main/java/com/alibaba/testable/agent/model/MethodInfo.java index b30138e..0b67912 100644 --- a/testable-agent/src/main/java/com/alibaba/testable/agent/model/MethodInfo.java +++ b/testable-agent/src/main/java/com/alibaba/testable/agent/model/MethodInfo.java @@ -17,6 +17,10 @@ public class MethodInfo { * parameter and return value of the source method */ private final String desc; + /** + * name of the class where this mock method defined (in slash-separate format) + */ + private final String mockClass; /** * name of the mock method */ @@ -30,10 +34,11 @@ public class MethodInfo { */ private final boolean isStatic; - public MethodInfo(String clazz, String name, String desc, String mockName, String mockDesc, boolean isStatic) { + public MethodInfo(String clazz, String name, String desc, String mockClass, String mockName, String mockDesc, boolean isStatic) { this.clazz = clazz; this.name = name; this.desc = desc; + this.mockClass = mockClass; this.mockName = mockName; this.mockDesc = mockDesc; this.isStatic = isStatic; @@ -51,6 +56,10 @@ public class MethodInfo { return desc; } + public String getMockClass() { + return mockClass; + } + public String getMockName() { return mockName; } @@ -74,6 +83,7 @@ public class MethodInfo { if (!clazz.equals(that.clazz)) { return false; } if (!name.equals(that.name)) { return false; } if (!desc.equals(that.desc)) { return false; } + if (!mockClass.equals(that.mockClass)) { return false; } if (!mockName.equals(that.mockName)) { return false; } return mockDesc.equals(that.mockDesc); } @@ -83,6 +93,7 @@ public class MethodInfo { int result = clazz.hashCode(); result = 31 * result + name.hashCode(); result = 31 * result + desc.hashCode(); + result = 31 * result + mockClass.hashCode(); result = 31 * result + mockName.hashCode(); result = 31 * result + mockDesc.hashCode(); result = 31 * result + (isStatic ? 1 : 0); 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 f3385c9..4464d28 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 @@ -96,7 +96,7 @@ public class MockClassParser { if (CONSTRUCTOR.equals(targetMethod)) { addMockConstructor(methodInfos, cn, mn); } else { - MethodInfo mi = getMethodInfo(mn, an, targetMethod); + MethodInfo mi = getMethodInfo(cn, mn, an, targetMethod); if (mi != null) { methodInfos.add(mi); } @@ -112,7 +112,7 @@ public class MockClassParser { return type == null ? MethodUtil.removeFirstParameter(mn.desc) : mn.desc; } - private MethodInfo getMethodInfo(MethodNode mn, AnnotationNode an, String targetMethod) { + private MethodInfo getMethodInfo(ClassNode cn, MethodNode mn, AnnotationNode an, String targetMethod) { Type targetType = AnnotationUtil.getAnnotationParameter(an, ConstPool.FIELD_TARGET_CLASS, null, Type.class); boolean isStatic = isStatic(mn); if (targetType == null) { @@ -121,18 +121,19 @@ public class MockClassParser { if (methodDescPair == null) { return null; } - return new MethodInfo(methodDescPair.left, targetMethod, methodDescPair.right, mn.name, mn.desc, isStatic); + return new MethodInfo(methodDescPair.left, targetMethod, methodDescPair.right, cn.name, mn.name, mn.desc, + isStatic); } else { // "targetClass" found, use it as target class type String slashSeparatedName = ClassUtil.toSlashSeparatedName(targetType.getClassName()); - return new MethodInfo(slashSeparatedName, targetMethod, mn.desc, mn.name, + return new MethodInfo(slashSeparatedName, targetMethod, mn.desc, cn.name, mn.name, MethodUtil.addParameterAtBegin(mn.desc, ClassUtil.toByteCodeClassName(slashSeparatedName)), isStatic); } } private void addMockConstructor(List methodInfos, ClassNode cn, MethodNode mn) { String sourceClassName = ClassUtil.getSourceClassName(cn.name); - methodInfos.add(new MethodInfo(sourceClassName, CONSTRUCTOR, mn.desc, mn.name, mn.desc, isStatic(mn))); + methodInfos.add(new MethodInfo(sourceClassName, CONSTRUCTOR, mn.desc, cn.name, mn.name, mn.desc, isStatic(mn))); } /**