remove n.e class and testable setup method

This commit is contained in:
金戟 2020-07-30 00:16:08 +08:00
parent 9321980a68
commit f614690016
9 changed files with 24 additions and 382 deletions

View File

@ -10,7 +10,7 @@ import java.io.IOException;
/**
* @author flin
*/
abstract public class ClassHandler implements Opcodes {
abstract public class BaseClassHandler implements Opcodes {
public byte[] getBytes(String className) throws IOException {
ClassReader cr = new ClassReader(className);

View File

@ -4,20 +4,17 @@ import com.alibaba.testable.agent.constant.ConstPool;
import com.alibaba.testable.agent.model.MethodInfo;
import com.alibaba.testable.agent.util.ClassUtil;
import com.alibaba.testable.agent.util.CollectionUtil;
import com.alibaba.testable.agent.util.StringUtil;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.*;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* @author flin
*/
public class SourceClassHandler extends ClassHandler {
public class SourceClassHandler extends BaseClassHandler {
private static final String CONSTRUCTOR = "<init>";
private final List<MethodInfo> injectMethods;

View File

@ -11,7 +11,7 @@ import java.util.List;
/**
* @author flin
*/
public class TestClassHandler extends ClassHandler {
public class TestClassHandler extends BaseClassHandler {
private static final List<String> TEST_ANNOTATIONS = new ArrayList<String>();

View File

@ -5,16 +5,8 @@ package com.alibaba.testable.core.constant;
*/
public final class ConstPool {
public static final String TYPE_UTIL = "com.alibaba.testable.core.util.TypeUtil";
public static final String CLASS_SUBSTITUTION = TYPE_UTIL + ".TestableSubstitution";
public static final String METHOD_ADD_TO_CON_POLL = TYPE_UTIL + ".addToConstructorPool";
public static final String METHOD_ADD_TO_MEM_POOL = TYPE_UTIL + ".addToMemberMethodPool";
public static final String CLASS_OF_TYPE = "class";
public static final String TYPE_CLASS = "Class";
public static final String REF_THIS = "this";
public static final String TESTABLE_PRIVATE_ACCESSOR = "com.alibaba.testable.core.accessor.PrivateAccessor";
public static final String ANNOTATION_TESTABLE_INJECT = "com.alibaba.testable.core.annotation.TestableInject";
public static final String TESTABLE_SETUP_METHOD_NAME = "testableSetup";
public static final String TESTABLE_REF_FIELD_NAME = "_testableInternalRef";
public static final String TEST_POSTFIX = "Test";

View File

@ -1,88 +0,0 @@
package com.alibaba.testable.core.generator;
import com.alibaba.testable.core.model.TestableContext;
import com.alibaba.testable.core.constant.ConstPool;
import com.sun.tools.javac.code.Type;
import com.sun.tools.javac.tree.JCTree.*;
import com.sun.tools.javac.util.List;
import com.sun.tools.javac.util.ListBuffer;
import com.sun.tools.javac.util.Name;
import com.sun.tools.javac.util.Pair;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
/**
* Generate test class setup method definition
*
* @author flin
*/
public class TestSetupMethodGenerator extends BaseGenerator {
/**
* MethodName -> (ResultType -> ParameterTypes)
*/
public ListBuffer<Pair<Name, Pair<JCExpression, List<JCExpression>>>> injectMethods = new ListBuffer<>();
public final ListBuffer<Method> memberMethods = new ListBuffer<>();
public TestSetupMethodGenerator(TestableContext cx) {
super(cx);
}
public JCMethodDecl fetch() {
JCModifiers mods = cx.treeMaker.Modifiers(Modifier.PUBLIC);
return cx.treeMaker.MethodDef(mods, cx.names.fromString(ConstPool.TESTABLE_SETUP_METHOD_NAME),
cx.treeMaker.Type(new Type.JCVoidType()), List.<JCTypeParameter>nil(),
List.<JCVariableDecl>nil(), List.<JCExpression>nil(), testableSetupBlock(), null);
}
private JCBlock testableSetupBlock() {
ListBuffer<JCStatement> statements = new ListBuffer<>();
for (Pair<Name, Pair<JCExpression, List<JCExpression>>> m : injectMethods.toList()) {
if (isMemberMethod(m)) {
statements.append(addToPoolStatement(m, ConstPool.METHOD_ADD_TO_MEM_POOL));
} else {
statements.append(addToPoolStatement(m, ConstPool.METHOD_ADD_TO_CON_POLL));
}
}
return cx.treeMaker.Block(0, statements.toList());
}
private boolean isMemberMethod(Pair<Name, Pair<JCExpression, List<JCExpression>>> m) {
for (Method method : memberMethods) {
if (method.getName().equals(m.fst.toString()) && parameterEquals(m.snd.snd, method.getParameterTypes())) {
return true;
}
}
return false;
}
private boolean parameterEquals(List<JCExpression> injectMethodArgs, Class<?>[] memberMethodArgs) {
if (injectMethodArgs.length() != memberMethodArgs.length) {
return false;
}
for (int i = 0; i < injectMethodArgs.length(); i++) {
if (!memberMethodArgs[i].getName().equals(((JCFieldAccess)injectMethodArgs.get(i)).selected.type
.toString())) {
return false;
}
}
return true;
}
private JCStatement addToPoolStatement(Pair<Name, Pair<JCExpression, List<JCExpression>>> m, String addPoolMethod) {
JCExpression pool = nameToExpression(ConstPool.CLASS_SUBSTITUTION);
JCExpression classType = m.snd.fst;
JCExpression methodName = cx.treeMaker.Literal(m.fst.toString());
JCExpression parameterTypes = cx.treeMaker.NewArray(cx.treeMaker.Ident(cx.names.fromString(ConstPool.TYPE_CLASS)),
List.<JCExpression>nil(), m.snd.snd);
JCExpression thisIns = cx.treeMaker.Ident(cx.names.fromString(ConstPool.REF_THIS));
JCNewClass poolClass = cx.treeMaker.NewClass(null, List.<JCExpression>nil(), pool,
List.of(classType, methodName, parameterTypes, thisIns), null);
JCExpression addInjectMethod = nameToExpression(addPoolMethod);
JCMethodInvocation apply = cx.treeMaker.Apply(List.<JCExpression>nil(), addInjectMethod,
List.from(new JCExpression[] {poolClass}));
return cx.treeMaker.Exec(apply);
}
}

View File

@ -1,21 +1,18 @@
package com.alibaba.testable.core.translator;
import com.alibaba.testable.core.constant.ConstPool;
import com.alibaba.testable.core.generator.PrivateAccessStatementGenerator;
import com.alibaba.testable.core.generator.TestSetupMethodGenerator;
import com.alibaba.testable.core.generator.TestableRefFieldGenerator;
import com.alibaba.testable.core.model.TestableContext;
import com.alibaba.testable.core.constant.ConstPool;
import com.alibaba.testable.core.util.TypeUtil;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.tree.JCTree.*;
import com.sun.tools.javac.util.ListBuffer;
import com.sun.tools.javac.util.Name;
import com.sun.tools.javac.util.Pair;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Arrays;
/**
* Travel AST
@ -24,21 +21,17 @@ import java.util.Arrays;
*/
public class EnableTestableTranslator extends BaseTranslator {
private final TestableContext cx;
private final String testClassName;
private final String sourceClassName;
private final ListBuffer<Name> sourceClassIns = new ListBuffer<>();
private final ListBuffer<String> privateOrFinalFields = new ListBuffer<>();
private final ListBuffer<String> privateMethods = new ListBuffer<>();
private final TestSetupMethodGenerator testSetupMethodGenerator;
private final PrivateAccessStatementGenerator privateAccessStatementGenerator;
private final TestableRefFieldGenerator testableRefFieldGenerator;
public EnableTestableTranslator(String pkgName, String testClassName, TestableContext cx) {
this.testClassName = testClassName;
this.sourceClassName = testClassName.substring(0, testClassName.length() - ConstPool.TEST_POSTFIX.length());
this.cx = cx;
this.testSetupMethodGenerator = new TestSetupMethodGenerator(cx);
this.privateAccessStatementGenerator = new PrivateAccessStatementGenerator(cx);
this.testableRefFieldGenerator = new TestableRefFieldGenerator(cx, pkgName + "." + testClassName);
try {
@ -55,7 +48,6 @@ public class EnableTestableTranslator extends BaseTranslator {
privateMethods.add(m.getName());
}
}
testSetupMethodGenerator.memberMethods.addAll(Arrays.asList(cls.getDeclaredMethods()));
} catch (Exception e) {
e.printStackTrace();
}
@ -93,13 +85,6 @@ public class EnableTestableTranslator extends BaseTranslator {
for (JCAnnotation a : jcMethodDecl.mods.annotations) {
if (a.type != null && ConstPool.ANNOTATION_TESTABLE_INJECT.equals(a.type.tsym.toString())) {
TypeUtil.toPublicFlags(jcMethodDecl.getModifiers());
ListBuffer<JCExpression> args = new ListBuffer<>();
for (JCVariableDecl p : jcMethodDecl.params) {
args.add(cx.treeMaker.Select(p.vartype, cx.names.fromString(ConstPool.CLASS_OF_TYPE)));
}
JCExpression retType = jcMethodDecl.restype == null ? null :
cx.treeMaker.Select(jcMethodDecl.restype, cx.names.fromString(ConstPool.CLASS_OF_TYPE));
testSetupMethodGenerator.injectMethods.add(Pair.of(jcMethodDecl.name, Pair.of(retType, args.toList())));
}
}
super.visitMethodDef(jcMethodDecl);
@ -114,7 +99,6 @@ public class EnableTestableTranslator extends BaseTranslator {
if (jcClassDecl.name.toString().equals(testClassName)) {
ListBuffer<JCTree> ndefs = new ListBuffer<>();
ndefs.addAll(jcClassDecl.defs);
ndefs.add(testSetupMethodGenerator.fetch());
ndefs.add(testableRefFieldGenerator.fetch());
jcClassDecl.defs = ndefs.toList();
}

View File

@ -1,17 +1,23 @@
package com.alibaba.testable.core.util;
import com.alibaba.testable.core.constant.ConstPool;
/**
* @author flin
*/
public class TestableUtil {
private static final String TESTABLE_NE = "n.e";
public static String currentMemberMethodName(Object testClassRef) {
return currentMemberMethodName(testClassRef.getClass());
}
public static String currentMemberMethodName() {
StackTraceElement[] stack = Thread.currentThread().getStackTrace();
for (int i = 0; i < stack.length; i++) {
if (stack[i].getClassName().equals(TESTABLE_NE)) {
return stack[i + 1].getMethodName();
public static String currentMemberMethodName(Class<?> testClass) {
StackTraceElement[] stack = getMainThread().getStackTrace();
String testClassName = getRealClassName(testClass);
String sourceClassName = testClassName.substring(0, testClassName.length() - ConstPool.TEST_POSTFIX.length());
for (int i = stack.length - 1; i >= 0; i--) {
if (stack[i].getClassName().equals(sourceClassName)) {
return stack[i].getMethodName();
}
}
return "";
@ -21,7 +27,7 @@ public class TestableUtil {
return currentTestCaseName(testClassRef.getClass());
}
public static String currentTestCaseName(Class testClass) {
public static String currentTestCaseName(Class<?> testClass) {
StackTraceElement[] stack = getMainThread().getStackTrace();
String testClassName = getRealClassName(testClass);
for (int i = stack.length - 1; i >= 0; i--) {
@ -32,7 +38,7 @@ public class TestableUtil {
return "";
}
private static String getRealClassName(Class testClass) {
private static String getRealClassName(Class<?> testClass) {
String className = testClass.getName();
int posOfInnerClass = className.lastIndexOf('$');
return posOfInnerClass > 0 ? className.substring(0, posOfInnerClass) : className;

View File

@ -22,126 +22,11 @@ public class TypeUtil {
modifiers.flags |= Modifier.PUBLIC;
}
/**
* Information of substitution method
*/
public static class TestableSubstitution {
public Class type; // target instance type to new / method return type
public Class[] parameterTypes; // constructor parameter types / member method parameter types
public Object targetObject; // object which provides substitution / object which provides substitution
public String methodName; // substitution method name / original member method name
public TestableSubstitution(Class type, String methodName, Class[] parameterTypes, Object targetObject) {
this.type = type;
this.methodName = methodName;
this.parameterTypes = parameterTypes;
this.targetObject = targetObject;
}
}
private static List<TestableSubstitution> mockNewPool = new ArrayList<>();
private static List<TestableSubstitution> mockMemberPool = new ArrayList<>();
/**
* add item to constructor pool
*/
public static void addToConstructorPool(TestableSubstitution substitution) {
mockNewPool.add(substitution);
}
/**
* add item to method pool
*/
public static void addToMemberMethodPool(TestableSubstitution substitution) {
mockMemberPool.add(substitution);
}
/**
* substitution entry for new
*/
public static <T> T wrapNew(Class<T> classType, Object... parameters) {
Class[] cs = TypeUtil.getClassesFromObjects(parameters);
if (!mockNewPool.isEmpty()) {
try {
TestableSubstitution pi = getFromConstructorPool(classType, cs);
if (pi != null) {
Method m = pi.targetObject.getClass().getDeclaredMethod(pi.methodName, pi.parameterTypes);
m.setAccessible(true);
return (T)m.invoke(pi.targetObject, parameters);
}
} catch (Exception e) {
return null;
}
}
try {
Constructor c = TypeUtil.getConstructorByParameterTypes(classType.getConstructors(), cs);
if (c != null) {
return (T)c.newInstance(parameters);
}
} catch (Exception e) {
return null;
}
return null;
}
/**
* substitution entry for member call
*/
public static <T> T wrapCall(Object targetObject, String methodName, Object... parameters) {
Class[] cs = TypeUtil.getClassesFromObjects(parameters);
if (!mockMemberPool.isEmpty()) {
try {
TestableSubstitution pi = getFromMemberMethodPool(methodName, cs);
if (pi != null) {
Method m = pi.targetObject.getClass().getDeclaredMethod(pi.methodName, pi.parameterTypes);
m.setAccessible(true);
return (T)m.invoke(pi.targetObject, parameters);
}
} catch (Exception e) {
return null;
}
}
try {
Method m = TypeUtil.getMethodByNameAndParameterTypes(targetObject.getClass().getDeclaredMethods(), methodName, cs);
if (m != null) {
m.setAccessible(true);
return (T)m.invoke(targetObject, parameters);
}
} catch (Exception e) {
return null;
}
return null;
}
/**
* get from method pool by key
*/
private static TestableSubstitution getFromMemberMethodPool(String methodName, Class[] parameterTypes) {
for (TestableSubstitution f : mockMemberPool) {
if (f.methodName.equals(methodName) && TypeUtil.typeEquals(f.parameterTypes, parameterTypes)) {
return f;
}
}
return null;
}
/**
* get from constructor pool by key
*/
private static TestableSubstitution getFromConstructorPool(Class type, Class[] parameterTypes) {
for (TestableSubstitution w : mockNewPool) {
if (w.type.equals(type) && TypeUtil.typeEquals(w.parameterTypes, parameterTypes)) {
return w;
}
}
return null;
}
/**
* get classes of parameter objects
*/
public static Class[] getClassesFromObjects(Object[] parameterObjects) {
Class[] cs = new Class[parameterObjects.length];
public static Class<?>[] getClassesFromObjects(Object[] parameterObjects) {
Class<?>[] cs = new Class[parameterObjects.length];
for (int i = 0; i < cs.length; i++) {
cs[i] = parameterObjects[i].getClass();
}
@ -153,7 +38,7 @@ public class TypeUtil {
*/
public static Method getMethodByNameAndParameterTypes(Method[] availableMethods,
String methodName,
Class[] parameterTypes) {
Class<?>[] parameterTypes) {
for (Method m : availableMethods) {
if (m.getName().equals(methodName) &&
typeEquals(m.getParameterTypes(), parameterTypes)) {
@ -164,22 +49,9 @@ public class TypeUtil {
}
/**
* get constructor by parameter matching
* type equals
*/
public static Constructor getConstructorByParameterTypes(Constructor<?>[] constructors,
Class[] parameterTypes) {
for (Constructor c : constructors) {
if (typeEquals(c.getParameterTypes(), parameterTypes)) {
return c;
}
}
return null;
}
/**
* type equeals
*/
public static boolean typeEquals(Class[] classesLeft, Class[] classesRight) {
public static boolean typeEquals(Class<?>[] classesLeft, Class<?>[] classesRight) {
if (classesLeft.length != classesRight.length) {
return false;
}
@ -197,7 +69,7 @@ public class TypeUtil {
* @param factTypes fact types (can be primary type)
* @param userTypes user types
*/
private static boolean fuzzyEqual(Class factTypes, Class userTypes) {
private static boolean fuzzyEqual(Class<?> factTypes, Class<?> userTypes) {
return (factTypes.equals(int.class) && userTypes.equals(Integer.class)) ||
(factTypes.equals(long.class) && userTypes.equals(Long.class)) ||
(factTypes.equals(short.class) && userTypes.equals(Short.class)) ||

View File

@ -1,121 +0,0 @@
package n;
import static com.alibaba.testable.core.util.TypeUtil.wrapCall;
import static com.alibaba.testable.core.util.TypeUtil.wrapNew;
public final class e {
public static <T> T w(Class<T> ct) {
return wrapNew(ct);
}
public static <T> T w(Class<T> ct, Object a1) {
return wrapNew(ct, a1);
}
public static <T> T w(Class<T> ct, Object a1, Object a2) {
return wrapNew(ct, a1, a2);
}
public static <T> T w(Class<T> ct, Object a1, Object a2, Object a3) {
return wrapNew(ct, a1, a2, a3);
}
public static <T> T w(Class<T> ct, Object a1, Object a2, Object a3, Object a4) {
return wrapNew(ct, a1, a2, a3, a4);
}
public static <T> T w(Class<T> ct, Object a1, Object a2, Object a3, Object a4, Object a5) {
return wrapNew(ct, a1, a2, a3, a4, a5);
}
public static <T> T w(Class<T> ct, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) {
return wrapNew(ct, a1, a2, a3, a4, a5, a6);
}
public static <T> T w(Class<T> ct, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) {
return wrapNew(ct, a1, a2, a3, a4, a5, a6, a7);
}
public static <T> T w(Class<T> ct, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7,
Object a8) {
return wrapNew(ct, a1, a2, a3, a4, a5, a6, a7, a8);
}
public static <T> T w(Class<T> ct, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7,
Object a8, Object a9) {
return wrapNew(ct, a1, a2, a3, a4, a5, a6, a7, a8, a9);
}
public static <T> T w(Class<T> ct, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7,
Object a8, Object a9, Object a10) {
return wrapNew(ct, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10);
}
public static <T> T w(Class<T> ct, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7,
Object a8, Object a9, Object a10, Object a11) {
return wrapNew(ct, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11);
}
public static <T> T w(Class<T> ct, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7,
Object a8, Object a9, Object a10, Object a11, Object a12) {
return wrapNew(ct, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12);
}
public static <T> T f(Object o, String mn) {
return wrapCall(o, mn);
}
public static <T> T f(Object o, String mn, Object a1) {
return wrapCall(o, mn, a1);
}
public static <T> T f(Object o, String mn, Object a1, Object a2) {
return wrapCall(o, mn, a1, a2);
}
public static <T> T f(Object o, String mn, Object a1, Object a2, Object a3) {
return wrapCall(o, mn, a1, a2, a3);
}
public static <T> T f(Object o, String mn, Object a1, Object a2, Object a3, Object a4) {
return wrapCall(o, mn, a1, a2, a3, a4);
}
public static <T> T f(Object o, String mn, Object a1, Object a2, Object a3, Object a4, Object a5) {
return wrapCall(o, mn, a1, a2, a3, a4, a5);
}
public static <T> T f(Object o, String mn, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) {
return wrapCall(o, mn, a1, a2, a3, a4, a5, a6);
}
public static <T> T f(Object o, String mn, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) {
return wrapCall(o, mn, a1, a2, a3, a4, a5, a6, a7);
}
public static <T> T f(Object o, String mn, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7,
Object a8) {
return wrapCall(o, mn, a1, a2, a3, a4, a5, a6, a7, a8);
}
public static <T> T f(Object o, String mn, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7,
Object a8, Object a9) {
return wrapCall(o, mn, a1, a2, a3, a4, a5, a6, a7, a8, a9);
}
public static <T> T f(Object o, String mn, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7,
Object a8, Object a9, Object a10) {
return wrapCall(o, mn, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10);
}
public static <T> T f(Object o, String mn, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7,
Object a8, Object a9, Object a10, Object a11) {
return wrapCall(o, mn, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11);
}
public static <T> T f(Object o, String mn, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7,
Object a8, Object a9, Object a10, Object a11, Object a12) {
return wrapCall(o, mn, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12);
}
}