mirror of
https://github.com/alibaba/testable-mock.git
synced 2025-01-25 11:51:15 +08:00
avoid source class be re-transformed
This commit is contained in:
parent
13fa8a76ce
commit
28bb6454c8
@ -1,17 +1,35 @@
|
||||
package com.alibaba.testable.agent.handler;
|
||||
|
||||
import com.alibaba.testable.core.util.LogUtil;
|
||||
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.tree.FieldNode;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* @author flin
|
||||
*/
|
||||
abstract public class BaseClassHandler implements Opcodes {
|
||||
|
||||
protected static final String TESTABLE_MARK_FIELD = "__testable";
|
||||
|
||||
protected boolean wasTransformed(ClassNode cn) {
|
||||
Iterator<FieldNode> iterator = cn.fields.iterator();
|
||||
if (iterator.hasNext()) {
|
||||
if (TESTABLE_MARK_FIELD.equals(iterator.next().name)) {
|
||||
// avoid duplicate injection
|
||||
LogUtil.verbose("Duplicate injection found, ignore " + cn.name);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
cn.fields.add(new FieldNode(ACC_PRIVATE, TESTABLE_MARK_FIELD, "I", null, null));
|
||||
return false;
|
||||
}
|
||||
|
||||
public byte[] getBytes(byte[] classFileBuffer) throws IOException {
|
||||
ClassReader cr = new ClassReader(classFileBuffer);
|
||||
ClassNode cn = new ClassNode();
|
||||
|
@ -36,6 +36,9 @@ public class SourceClassHandler extends BaseClassHandler {
|
||||
*/
|
||||
@Override
|
||||
protected void transform(ClassNode cn) {
|
||||
if (wasTransformed(cn)) {
|
||||
return;
|
||||
}
|
||||
Set<MethodInfo> memberInjectMethods = new HashSet<MethodInfo>();
|
||||
Set<MethodInfo> newOperatorInjectMethods = new HashSet<MethodInfo>();
|
||||
for (MethodInfo mi : injectMethods) {
|
||||
|
@ -7,7 +7,6 @@ import com.alibaba.testable.agent.util.ClassUtil;
|
||||
import com.alibaba.testable.core.util.LogUtil;
|
||||
import org.objectweb.asm.tree.*;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import static com.alibaba.testable.agent.util.ClassUtil.toDotSeparateFullClassName;
|
||||
@ -20,7 +19,6 @@ public class TestClassHandler extends BaseClassHandler {
|
||||
private static final String CLASS_TESTABLE_TOOL = "com/alibaba/testable/core/tool/TestableTool";
|
||||
private static final String CLASS_TESTABLE_UTIL = "com/alibaba/testable/core/util/TestableUtil";
|
||||
private static final String CLASS_INVOKE_RECORD_UTIL = "com/alibaba/testable/core/util/InvokeRecordUtil";
|
||||
private static final String TESTABLE_MARK_FIELD = "__testable";
|
||||
private static final String FIELD_TEST_CASE = "TEST_CASE";
|
||||
private static final String FIELD_SOURCE_METHOD = "SOURCE_METHOD";
|
||||
private static final String METHOD_CURRENT_TEST_CASE_NAME = "currentTestCaseName";
|
||||
@ -40,32 +38,19 @@ public class TestClassHandler extends BaseClassHandler {
|
||||
return;
|
||||
}
|
||||
for (MethodNode mn : cn.methods) {
|
||||
handleMockMethod(mn);
|
||||
handleMockMethod(cn, mn);
|
||||
handleInstruction(cn, mn);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean wasTransformed(ClassNode cn) {
|
||||
Iterator<FieldNode> iterator = cn.fields.iterator();
|
||||
if (iterator.hasNext()) {
|
||||
if (TESTABLE_MARK_FIELD.equals(iterator.next().name)) {
|
||||
// avoid duplicate injection
|
||||
LogUtil.verbose("Duplicate injection found, ignore " + cn.name);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
cn.fields.add(new FieldNode(ACC_PRIVATE, TESTABLE_MARK_FIELD, "I", null, null));
|
||||
return false;
|
||||
}
|
||||
|
||||
private void handleMockMethod(MethodNode mn) {
|
||||
private void handleMockMethod(ClassNode cn, MethodNode mn) {
|
||||
if (isMockMethod(mn)) {
|
||||
toPublicStatic(mn);
|
||||
toPublicStatic(cn, mn);
|
||||
injectInvokeRecorder(mn);
|
||||
}
|
||||
}
|
||||
|
||||
private void toPublicStatic(MethodNode mn) {
|
||||
private void toPublicStatic(ClassNode cn, MethodNode mn) {
|
||||
mn.access &= ~ACC_PRIVATE;
|
||||
mn.access &= ~ACC_PROTECTED;
|
||||
mn.access |= ACC_PUBLIC;
|
||||
|
@ -45,7 +45,6 @@ public class TestableClassTransformer implements ClassFileTransformer {
|
||||
ProtectionDomain protectionDomain, byte[] classFileBuffer) {
|
||||
if (isSystemClass(className)) {
|
||||
// Ignore system class and reloaded class
|
||||
LogUtil.verbose("Ignore class: " + (className == null ? "<lambda>" : className));
|
||||
return null;
|
||||
}
|
||||
LogUtil.verbose("Handle class: " + className);
|
||||
@ -65,8 +64,9 @@ public class TestableClassTransformer implements ClassFileTransformer {
|
||||
dumpByte(className, bytes);
|
||||
resetMockContext();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
} catch (Throwable t) {
|
||||
LogUtil.warn("Failed to transform class " + className);
|
||||
LogUtil.diagnose(t.toString());
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
@ -77,7 +77,8 @@ public class TestableClassTransformer implements ClassFileTransformer {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
String dumpFile = StringUtil.joinPath(dumpDir, className.replaceAll("/", "_") + ".class");
|
||||
String dumpFile = StringUtil.joinPath(dumpDir, className.replaceAll("/", ".") + ".class");
|
||||
LogUtil.verbose("Dump class: " + dumpFile);
|
||||
FileOutputStream stream = new FileOutputStream(dumpFile);
|
||||
stream.write(bytes);
|
||||
stream.close();
|
||||
|
Loading…
Reference in New Issue
Block a user