mirror of
https://github.com/alibaba/testable-mock.git
synced 2025-01-25 11:51:15 +08:00
simple dirty way to pass new class test case
This commit is contained in:
parent
a1ee894faf
commit
6f292b6334
@ -1,5 +1,8 @@
|
||||
package com.alibaba.testable.constant;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author flin
|
||||
*/
|
||||
@ -8,4 +11,9 @@ public class Const {
|
||||
public static final String DOT = ".";
|
||||
public static final String SLASH = "/";
|
||||
|
||||
public static final List<String> SYS_CLASSES = new ArrayList<String>();
|
||||
static {
|
||||
SYS_CLASSES.add("java/lang/StringBuilder");
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,22 @@
|
||||
package com.alibaba.testable.model;
|
||||
|
||||
/**
|
||||
* @author flin
|
||||
*/
|
||||
|
||||
public enum TravelStatus {
|
||||
|
||||
/**
|
||||
* Initialized
|
||||
*/
|
||||
INIT,
|
||||
/**
|
||||
* Processing member method replacement
|
||||
*/
|
||||
MEM_REP,
|
||||
/**
|
||||
* Processing member operation replacement
|
||||
*/
|
||||
NEW_REP
|
||||
|
||||
}
|
@ -1,11 +1,17 @@
|
||||
package com.alibaba.testable.transformer;
|
||||
|
||||
import com.alibaba.testable.model.TravelStatus;
|
||||
import org.objectweb.asm.ClassReader;
|
||||
import org.objectweb.asm.ClassWriter;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
import org.objectweb.asm.Type;
|
||||
import org.objectweb.asm.tree.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static com.alibaba.testable.constant.Const.SYS_CLASSES;
|
||||
|
||||
/**
|
||||
* @author flin
|
||||
@ -27,7 +33,63 @@ public class TestableClassTransformer implements Opcodes {
|
||||
}
|
||||
|
||||
private void transform() {
|
||||
List<String> methodNames = new ArrayList<String>();
|
||||
for (MethodNode m : cn.methods) {
|
||||
if (!"<init>".equals(m.name)) {
|
||||
methodNames.add(m.name);
|
||||
}
|
||||
}
|
||||
for (MethodNode m : cn.methods) {
|
||||
transformMethod(m, methodNames);
|
||||
}
|
||||
}
|
||||
|
||||
private void transformMethod(MethodNode mn, List<String> methodNames) {
|
||||
AbstractInsnNode[] instructions = mn.instructions.toArray();
|
||||
TravelStatus status = TravelStatus.INIT;
|
||||
String target = "";
|
||||
int rangeStart = 0;
|
||||
for (int i = 0; i < instructions.length; i++) {
|
||||
if (instructions[i].getOpcode() == Opcodes.NEW) {
|
||||
TypeInsnNode node = (TypeInsnNode)instructions[i];
|
||||
if (!SYS_CLASSES.contains(node.desc) && node.desc.equals("com/alibaba/testable/BlackBox")) {
|
||||
target = node.desc;
|
||||
status = TravelStatus.NEW_REP;
|
||||
rangeStart = i;
|
||||
}
|
||||
}
|
||||
if (instructions[i].getOpcode() == Opcodes.INVOKESPECIAL) {
|
||||
MethodInsnNode node = (MethodInsnNode)instructions[i];
|
||||
if (methodNames.contains(node.name) && cn.name.equals(node.owner)) {
|
||||
status = TravelStatus.MEM_REP;
|
||||
}
|
||||
if (TravelStatus.NEW_REP == status && "<init>".equals(node.name) && target.equals(node.owner)) {
|
||||
replaceNewOps(mn, instructions, rangeStart, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void replaceNewOps(MethodNode mn, AbstractInsnNode[] instructions, int start, int end) {
|
||||
|
||||
InsnList il = new InsnList();
|
||||
il.add(new LdcInsnNode(Type.getType("Lcom/alibaba/testable/BlackBox;")));
|
||||
il.add(new InsnNode(ICONST_1));
|
||||
il.add(new TypeInsnNode(ANEWARRAY, "java/lang/Object"));
|
||||
il.add(new InsnNode(DUP));
|
||||
il.add(new InsnNode(ICONST_0));
|
||||
il.add(new LdcInsnNode("something"));
|
||||
il.add(new InsnNode(AASTORE));
|
||||
il.add(new MethodInsnNode(INVOKESTATIC, "testable_internal/n/e",
|
||||
"w", "(Ljava/lang/Class;[Ljava/lang/Object;)Ljava/lang/Object;", false));
|
||||
il.add(new TypeInsnNode(CHECKCAST, "com/alibaba/testable/BlackBox"));
|
||||
mn.instructions.insert(instructions[end], il);
|
||||
|
||||
for (int z = start; z <= end; z++) {
|
||||
mn.instructions.remove(instructions[z]);
|
||||
}
|
||||
|
||||
mn.maxStack += 4;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -23,8 +23,8 @@ public class TestableFileTransformer implements ClassFileTransformer {
|
||||
|
||||
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined,
|
||||
ProtectionDomain protectionDomain, byte[] classfileBuffer) {
|
||||
if (isSystemClass(loader, className)) {
|
||||
// Ignore system class
|
||||
if (isSystemClass(loader, className) || loadedClassNames.contains(className)) {
|
||||
// Ignore system class and duplicate class
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -36,6 +36,7 @@ public class TestableFileTransformer implements ClassFileTransformer {
|
||||
}
|
||||
|
||||
try {
|
||||
loadedClassNames.add(className);
|
||||
return new TestableClassTransformer(className).getBytes();
|
||||
} catch (IOException e) {
|
||||
return null;
|
||||
|
Loading…
Reference in New Issue
Block a user