invoke via mock singleton instance

This commit is contained in:
金戟 2021-02-10 22:30:38 +08:00
parent cefc5fb1df
commit 6f9accf319
3 changed files with 16 additions and 10 deletions

View File

@ -15,6 +15,10 @@ import java.util.Iterator;
*/
abstract public class BaseClassHandler implements Opcodes {
protected static final String REF_GET_INSTANCE = "getInstance";
protected static final String VOID_ARGS = "()";
protected static final String VOID_RES = "V";
protected String mockClassName;
protected boolean wasTransformed(ClassNode cn, String refName, String refDescriptor) {

View File

@ -11,9 +11,6 @@ import static com.alibaba.testable.agent.constant.ConstPool.CONSTRUCTOR;
public class MockClassHandler extends BaseClassHandler {
private static final String REF_INSTANCE = "_instance";
private static final String REF_GET_INSTANCE = "getInstance";
private static final String VOID_ARGS = "()";
private static final String VOID_RES = "V";
public MockClassHandler(String className) {
this.mockClassName = className;

View File

@ -1,6 +1,5 @@
package com.alibaba.testable.agent.handler;
import com.alibaba.testable.agent.constant.ConstPool;
import com.alibaba.testable.agent.model.MethodInfo;
import com.alibaba.testable.agent.model.ModifiedInsnNodes;
import com.alibaba.testable.agent.tool.ImmutablePair;
@ -14,6 +13,8 @@ import java.util.HashSet;
import java.util.List;
import java.util.Set;
import static com.alibaba.testable.agent.constant.ConstPool.CONSTRUCTOR;
/**
* @author flin
*/
@ -40,13 +41,13 @@ public class SourceClassHandler extends BaseClassHandler {
*/
@Override
protected void transform(ClassNode cn) {
if (wasTransformed(cn, TESTABLE_MARK_FIELD, "I")) {
if (wasTransformed(cn, TESTABLE_MARK_FIELD, ClassUtil.toByteCodeClassName(mockClassName))) {
return;
}
Set<MethodInfo> memberInjectMethods = new HashSet<MethodInfo>();
Set<MethodInfo> newOperatorInjectMethods = new HashSet<MethodInfo>();
for (MethodInfo im : injectMethods) {
if (im.getName().equals(ConstPool.CONSTRUCTOR)) {
if (im.getName().equals(CONSTRUCTOR)) {
newOperatorInjectMethods.add(im);
} else {
memberInjectMethods.add(im);
@ -70,7 +71,7 @@ public class SourceClassHandler extends BaseClassHandler {
do {
if (invokeOps.contains(instructions[i].getOpcode())) {
MethodInsnNode node = (MethodInsnNode)instructions[i];
if (ConstPool.CONSTRUCTOR.equals(node.name)) {
if (CONSTRUCTOR.equals(node.name)) {
LogUtil.verbose(" Line %d, constructing \"%s\" as \"%s\"", getLineNum(instructions, i),
node.owner, node.desc);
String newOperatorInjectMethodName = getNewOperatorInjectMethodName(newOperatorInjectMethods, node);
@ -209,7 +210,9 @@ public class SourceClassHandler extends BaseClassHandler {
String classType = ((TypeInsnNode)instructions[start]).desc;
String constructorDesc = ((MethodInsnNode)instructions[end]).desc;
String testClassName = ClassUtil.getTestClassName(cn.name);
mn.instructions.insertBefore(instructions[end], new MethodInsnNode(INVOKESTATIC, testClassName,
mn.instructions.insertBefore(instructions[start], new MethodInsnNode(INVOKESTATIC, mockClassName,
REF_GET_INSTANCE, VOID_ARGS + ClassUtil.toByteCodeClassName(mockClassName), false));
mn.instructions.insertBefore(instructions[end], new MethodInsnNode(INVOKEVIRTUAL, testClassName,
newOperatorInjectMethodName, getConstructorInjectDesc(constructorDesc, classType), false));
mn.instructions.remove(instructions[start]);
mn.instructions.remove(instructions[start + 1]);
@ -238,6 +241,8 @@ public class SourceClassHandler extends BaseClassHandler {
mockMethod.getMockName());
boolean shouldAppendTypeParameter = !mockMethod.getDesc().equals(mockMethod.getMockDesc());
String testClassName = ClassUtil.getTestClassName(cn.name);
mn.instructions.insertBefore(instructions[start], new MethodInsnNode(INVOKESTATIC, mockClassName,
REF_GET_INSTANCE, VOID_ARGS + ClassUtil.toByteCodeClassName(mockClassName), false));
if (Opcodes.INVOKESTATIC == opcode || isCompanionMethod(ownerClass, opcode)) {
if (shouldAppendTypeParameter) {
// append a null value if it was a static invoke or in kotlin companion class
@ -254,8 +259,8 @@ public class SourceClassHandler extends BaseClassHandler {
mn.instructions.remove(instructions[i]);
}
}
// method with @MockMethod will be modified as public static access, so INVOKESTATIC is used
mn.instructions.insertBefore(instructions[end], new MethodInsnNode(INVOKESTATIC, testClassName,
// method with @MockMethod will be modified as public access, so INVOKEVIRTUAL is used
mn.instructions.insertBefore(instructions[end], new MethodInsnNode(INVOKEVIRTUAL, testClassName,
mockMethod.getMockName(), mockMethod.getMockDesc(), false));
mn.instructions.remove(instructions[end]);
return new ModifiedInsnNodes(mn.instructions.toArray(), 1);