fix mock method in super class ignored in association scope

This commit is contained in:
金戟 2021-05-01 19:28:26 +08:00
parent 0ae5163435
commit 350802fc9b
6 changed files with 36 additions and 6 deletions

View File

@ -22,4 +22,5 @@ public class ConstPool {
public static final String KOTLIN_POSTFIX_COMPANION = "$Companion";
public static final String KOTLIN_PREFIX_ACCESS = "access$";
public static final String CLASS_OBJECT = "java/lang/Object";
}

View File

@ -5,6 +5,7 @@ import com.alibaba.testable.agent.constant.ConstPool;
import com.alibaba.testable.agent.tool.ImmutablePair;
import com.alibaba.testable.agent.util.*;
import com.alibaba.testable.core.model.MockScope;
import com.alibaba.testable.core.util.MockAssociationUtil;
import org.objectweb.asm.Label;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.*;
@ -13,6 +14,7 @@ import java.util.List;
import static com.alibaba.testable.agent.constant.ByteCodeConst.TYPE_ARRAY;
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.util.ClassUtil.toJavaStyleClassName;
import static com.alibaba.testable.core.constant.ConstPool.CONSTRUCTOR;
@ -41,6 +43,10 @@ public class MockClassHandler extends BaseClassWithContextHandler {
@Override
protected void transform(ClassNode cn) {
if (!CLASS_OBJECT.equals(cn.superName)) {
MockAssociationUtil.recordSubMockContainer(ClassUtil.toDotSeparatedName(cn.superName),
ClassUtil.toDotSeparatedName(cn.name));
}
injectRefFieldAndGetInstanceMethod(cn);
for (MethodNode mn : cn.methods) {
if (isMockMethod(mn)) {
@ -269,7 +275,7 @@ public class MockClassHandler extends BaseClassWithContextHandler {
List<Byte> types = MethodUtil.getParameterTypes(mn.desc);
int size = types.size();
il.add(getIntInsn(size));
il.add(new TypeInsnNode(ANEWARRAY, ClassUtil.CLASS_OBJECT));
il.add(new TypeInsnNode(ANEWARRAY, CLASS_OBJECT));
int parameterOffset = MethodUtil.isStatic(mn) ? 0 : 1;
for (int i = 0; i < size; i++) {
il.add(new InsnNode(DUP));

View File

@ -9,7 +9,7 @@ import org.objectweb.asm.tree.*;
import java.util.List;
import static com.alibaba.testable.agent.util.ClassUtil.CLASS_OBJECT;
import static com.alibaba.testable.agent.constant.ConstPool.CLASS_OBJECT;
import static com.alibaba.testable.core.constant.ConstPool.CONSTRUCTOR;
import static com.alibaba.testable.core.constant.ConstPool.THIS_REF;
import static com.alibaba.testable.core.util.CollectionUtil.contains;

View File

@ -16,14 +16,13 @@ import org.objectweb.asm.tree.MethodNode;
import java.util.ArrayList;
import java.util.List;
import static com.alibaba.testable.agent.constant.ConstPool.CLASS_OBJECT;
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;
public class MockClassParser {
private static final String CLASS_OBJECT = "java/lang/Object";
/**
* Get information of all mock methods
* @param className mock class name

View File

@ -18,7 +18,6 @@ import static org.objectweb.asm.Opcodes.*;
*/
public class ClassUtil {
public static final String CLASS_OBJECT = "java/lang/Object";
private static final String CLASS_BYTE = "java/lang/Byte";
private static final String CLASS_CHARACTER = "java/lang/Character";
private static final String CLASS_DOUBLE = "java/lang/Double";

View File

@ -16,6 +16,12 @@ public class MockAssociationUtil {
*/
public static final int INDEX_OF_MOCK_CLASS = 2;
/**
* Sub-class of specified mock class
* SuperMockClassName (dot-separated) Set of [SubMockClassName (dot-separated)]
*/
public static Map<String, Set<String>> subMockContainers = UnnullableMap.of(new HashSet<String>());
/**
* Mock class referred by @MockWith annotation to list of its test classes
* MockClassName (dot-separated) Set of associated [TestClassNames (dot-separated)]
@ -35,9 +41,24 @@ public class MockAssociationUtil {
}
String testClassName = mockContext.testClassName;
String mockClassName = Thread.currentThread().getStackTrace()[INDEX_OF_MOCK_CLASS].getClassName();
return recursiveAssociationCheck(testClassName, mockClassName);
}
private static boolean recursiveAssociationCheck(String testClassName, String mockClassName) {
return isAssociatedByInnerMockClass(testClassName, mockClassName) ||
isAssociatedByOuterMockClass(testClassName, mockClassName) ||
isAssociatedByMockWithAnnotation(testClassName, mockClassName);
isAssociatedByMockWithAnnotation(testClassName, mockClassName) ||
(subMockContainers.containsKey(mockClassName) &&
recursiveAssociationCheck(testClassName, subMockContainers.get(mockClassName)));
}
private static boolean recursiveAssociationCheck(String testClassName, Set<String> mockClassNames) {
for (String name : mockClassNames) {
if (recursiveAssociationCheck(testClassName, name)) {
return true;
}
}
return false;
}
/**
@ -54,6 +75,10 @@ public class MockAssociationUtil {
}
}
public static void recordSubMockContainer(String superClassName, String subClassName) {
subMockContainers.get(superClassName).add(subClassName);
}
private static boolean isAssociatedByInnerMockClass(String testClassName, String mockClassName) {
return mockClassName.equals(String.format("%s$%s", testClassName, MOCK_POSTFIX));
}