mirror of
https://github.com/alibaba/testable-mock.git
synced 2025-01-10 20:30:11 +08:00
use global invoke replace testable class method
This commit is contained in:
parent
229477a336
commit
c905acf44f
@ -4,6 +4,7 @@ import com.alibaba.testable.model.TestableContext;
|
||||
import com.alibaba.testable.util.ConstPool;
|
||||
import com.sun.tools.javac.tree.JCTree.*;
|
||||
import com.sun.tools.javac.util.List;
|
||||
import com.sun.tools.javac.util.ListBuffer;
|
||||
|
||||
/**
|
||||
* @author flin
|
||||
@ -14,11 +15,19 @@ public class PrivateAccessStatementGenerator extends BaseGenerator {
|
||||
super(cx);
|
||||
}
|
||||
|
||||
public JCExpression fetchSetterStatement(JCExpressionStatement jcExpressionStatement) {
|
||||
JCAssign assign = (JCAssign)jcExpressionStatement.expr;
|
||||
public JCExpression fetchSetterStatement(JCAssign assign) {
|
||||
JCFieldAccess setter = cx.treeMaker.Select(nameToExpression(ConstPool.TESTABLE_PRIVATE_ACCESSOR),
|
||||
cx.names.fromString("set"));
|
||||
return cx.treeMaker.Apply(List.<JCExpression>nil(), setter, List.of(((JCFieldAccess)assign.lhs).selected,
|
||||
cx.treeMaker.Literal(((JCFieldAccess)assign.lhs).name.toString()), assign.rhs));
|
||||
}
|
||||
|
||||
public JCExpression fetchInvokeStatement(JCMethodInvocation expr) {
|
||||
JCFieldAccess invoker = cx.treeMaker.Select(nameToExpression(ConstPool.TESTABLE_PRIVATE_ACCESSOR),
|
||||
cx.names.fromString("invoke"));
|
||||
ListBuffer<JCExpression> params = ListBuffer.of(((JCFieldAccess)expr.meth).selected);
|
||||
params.add(cx.treeMaker.Literal(((JCFieldAccess)expr.meth).name.toString()));
|
||||
params.addAll(expr.args);
|
||||
return cx.treeMaker.Apply(List.<JCExpression>nil(), invoker, params.toList());
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,25 @@
|
||||
package com.alibaba.testable.translator;
|
||||
|
||||
import com.sun.tools.javac.tree.JCTree.*;
|
||||
import com.sun.tools.javac.tree.TreeTranslator;
|
||||
import com.sun.tools.javac.util.List;
|
||||
|
||||
/**
|
||||
* @author flin
|
||||
*/
|
||||
public abstract class BaseTranslator extends TreeTranslator {
|
||||
|
||||
protected List<JCExpression> checkAndExchange(List<JCExpression> args) {
|
||||
if (args != null) {
|
||||
JCExpression[] es = new JCExpression[args.length()];
|
||||
for (int i = 0; i < args.length(); i++) {
|
||||
es[i] = checkAndExchange(args.get(i));
|
||||
}
|
||||
return List.from(es);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected abstract JCExpression checkAndExchange(JCExpression expr);
|
||||
|
||||
}
|
@ -13,7 +13,7 @@ import com.sun.tools.javac.util.Name;
|
||||
*
|
||||
* @author flin
|
||||
*/
|
||||
public class EnableTestableInjectTranslator extends TreeTranslator {
|
||||
public class EnableTestableInjectTranslator extends BaseTranslator {
|
||||
|
||||
private final TestableContext cx;
|
||||
|
||||
@ -123,18 +123,8 @@ public class EnableTestableInjectTranslator extends TreeTranslator {
|
||||
mods.getFlags().contains(javax.lang.model.element.Modifier.FINAL);
|
||||
}
|
||||
|
||||
private List<JCExpression> checkAndExchange(List<JCExpression> args) {
|
||||
if (args != null) {
|
||||
JCExpression[] es = new JCExpression[args.length()];
|
||||
for (int i = 0; i < args.length(); i++) {
|
||||
es[i] = checkAndExchange(args.get(i));
|
||||
}
|
||||
return List.from(es);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private JCExpression checkAndExchange(JCExpression expr) {
|
||||
@Override
|
||||
protected JCExpression checkAndExchange(JCExpression expr) {
|
||||
if (isNewOperation(expr)) {
|
||||
JCNewClass newClassExpr = (JCNewClass)expr;
|
||||
Name className = ((JCIdent)newClassExpr.clazz).name;
|
||||
@ -175,7 +165,7 @@ public class EnableTestableInjectTranslator extends TreeTranslator {
|
||||
JCFieldAccess snClass = cx.treeMaker.Select(cx.treeMaker.Ident(cx.names.fromString(ConstPool.NE_PKG)),
|
||||
cx.names.fromString(ConstPool.NE_CLS));
|
||||
JCFieldAccess snMethod = cx.treeMaker.Select(snClass, cx.names.fromString(ConstPool.NE_FUN));
|
||||
ListBuffer<JCExpression> args = new ListBuffer();
|
||||
ListBuffer<JCExpression> args = new ListBuffer<>();
|
||||
args.add(cx.treeMaker.Ident(cx.names.fromString(ConstPool.REF_THIS)));
|
||||
args.add(cx.treeMaker.Literal(methodName.toString()));
|
||||
args.addAll(param);
|
||||
|
@ -7,13 +7,13 @@ import com.alibaba.testable.model.TestableContext;
|
||||
import com.alibaba.testable.util.ConstPool;
|
||||
import com.sun.tools.javac.tree.JCTree;
|
||||
import com.sun.tools.javac.tree.JCTree.*;
|
||||
import com.sun.tools.javac.tree.TreeTranslator;
|
||||
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.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.Arrays;
|
||||
|
||||
@ -22,12 +22,13 @@ import java.util.Arrays;
|
||||
*
|
||||
* @author flin
|
||||
*/
|
||||
public class EnableTestableTranslator extends TreeTranslator {
|
||||
public class EnableTestableTranslator extends BaseTranslator {
|
||||
|
||||
private final TestableContext cx;
|
||||
private String sourceClassName = "";
|
||||
private final ListBuffer<Name> sourceClassIns = new ListBuffer<>();
|
||||
private final ListBuffer<String> stubbornFields = new ListBuffer<>();
|
||||
private final ListBuffer<String> privateOrFinalFields = new ListBuffer<>();
|
||||
private final ListBuffer<String> privateMethods = new ListBuffer<>();
|
||||
private final TestSetupMethodGenerator testSetupMethodGenerator;
|
||||
private final PrivateAccessStatementGenerator privateAccessStatementGenerator;
|
||||
|
||||
@ -41,7 +42,13 @@ public class EnableTestableTranslator extends TreeTranslator {
|
||||
Field[] fields = cls.getDeclaredFields();
|
||||
for (Field f : fields) {
|
||||
if (Modifier.isFinal(f.getModifiers()) || Modifier.isPrivate(f.getModifiers())) {
|
||||
stubbornFields.add(f.getName());
|
||||
privateOrFinalFields.add(f.getName());
|
||||
}
|
||||
}
|
||||
Method[] methods = cls.getDeclaredMethods();
|
||||
for (Method m : methods) {
|
||||
if (Modifier.isPrivate(m.getModifiers())) {
|
||||
privateMethods.add(m.getName());
|
||||
}
|
||||
}
|
||||
testSetupMethodGenerator.memberMethods.addAll(Arrays.asList(cls.getDeclaredMethods()));
|
||||
@ -50,39 +57,27 @@ public class EnableTestableTranslator extends TreeTranslator {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Demo d = new Demo() -> DemoTestable d = new Demo()
|
||||
*/
|
||||
@Override
|
||||
public void visitVarDef(JCVariableDecl jcVariableDecl) {
|
||||
super.visitVarDef(jcVariableDecl);
|
||||
if (jcVariableDecl.vartype.getClass().equals(JCIdent.class) &&
|
||||
((JCIdent)jcVariableDecl.vartype).name.toString().equals(sourceClassName)) {
|
||||
jcVariableDecl.vartype = getTestableClassIdent(jcVariableDecl.vartype);
|
||||
sourceClassIns.add(jcVariableDecl.name);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Demo d = new Demo() -> Demo d = new DemoTestable()
|
||||
*/
|
||||
@Override
|
||||
public void visitNewClass(JCNewClass jcNewClass) {
|
||||
super.visitNewClass(jcNewClass);
|
||||
if (getSimpleClassName(jcNewClass).equals(sourceClassName)) {
|
||||
jcNewClass.clazz = getTestableClassIdent(jcNewClass.clazz);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* d.privateField = val -> PrivateAccessor.set(d, "privateField", val)
|
||||
* d.privateMethod(args) -> PrivateAccessor.invoke(d, "privateMethod", args)
|
||||
*/
|
||||
@Override
|
||||
public void visitExec(JCExpressionStatement jcExpressionStatement) {
|
||||
if (jcExpressionStatement.expr.getClass().equals(JCAssign.class) &&
|
||||
isAssignStubbornField((JCAssign)jcExpressionStatement.expr)) {
|
||||
jcExpressionStatement.expr = privateAccessStatementGenerator.fetchSetterStatement(jcExpressionStatement);
|
||||
isPrivateField((JCAssign)jcExpressionStatement.expr)) {
|
||||
jcExpressionStatement.expr = privateAccessStatementGenerator.fetchSetterStatement(
|
||||
(JCAssign)jcExpressionStatement.expr);
|
||||
}
|
||||
jcExpressionStatement.expr = checkAndExchange(jcExpressionStatement.expr);
|
||||
super.visitExec(jcExpressionStatement);
|
||||
}
|
||||
|
||||
@ -129,7 +124,16 @@ public class EnableTestableTranslator extends TreeTranslator {
|
||||
}
|
||||
|
||||
/**
|
||||
* For setter break point
|
||||
* For private invoke invocation break point
|
||||
*/
|
||||
@Override
|
||||
public void visitApply(JCMethodInvocation tree) {
|
||||
tree.args = checkAndExchange(tree.args);
|
||||
super.visitApply(tree);
|
||||
}
|
||||
|
||||
/**
|
||||
* For private setter break point
|
||||
*/
|
||||
@Override
|
||||
public void visitAssign(JCAssign jcAssign) {
|
||||
@ -137,21 +141,20 @@ public class EnableTestableTranslator extends TreeTranslator {
|
||||
}
|
||||
|
||||
/**
|
||||
* For getter break point
|
||||
* For private getter break point
|
||||
*/
|
||||
@Override
|
||||
public void visitSelect(JCFieldAccess jcFieldAccess) {
|
||||
super.visitSelect(jcFieldAccess);
|
||||
}
|
||||
|
||||
private String getSimpleClassName(JCNewClass jcNewClass) {
|
||||
if (jcNewClass.clazz.getClass().equals(JCIdent.class)) {
|
||||
return ((JCIdent)jcNewClass.clazz).name.toString();
|
||||
} else if (jcNewClass.clazz.getClass().equals(JCFieldAccess.class)) {
|
||||
return ((JCFieldAccess)jcNewClass.clazz).name.toString();
|
||||
} else {
|
||||
return "";
|
||||
@Override
|
||||
protected JCExpression checkAndExchange(JCExpression expr) {
|
||||
if (expr.getClass().equals(JCMethodInvocation.class) &&
|
||||
isPrivateMethod((JCMethodInvocation)expr)) {
|
||||
expr = privateAccessStatementGenerator.fetchInvokeStatement((JCMethodInvocation)expr);
|
||||
}
|
||||
return expr;
|
||||
}
|
||||
|
||||
private List<JCAnnotation> removeAnnotation(List<JCAnnotation> annotations, String target) {
|
||||
@ -164,15 +167,18 @@ public class EnableTestableTranslator extends TreeTranslator {
|
||||
return nb.toList();
|
||||
}
|
||||
|
||||
private boolean isAssignStubbornField(JCAssign expr) {
|
||||
private boolean isPrivateField(JCAssign expr) {
|
||||
return expr.lhs.getClass().equals(JCFieldAccess.class) &&
|
||||
((JCFieldAccess)(expr).lhs).selected.getClass().equals(JCIdent.class) &&
|
||||
sourceClassIns.contains(((JCIdent)((JCFieldAccess)(expr).lhs).selected).name) &&
|
||||
stubbornFields.contains(((JCFieldAccess)(expr).lhs).name.toString());
|
||||
privateOrFinalFields.contains(((JCFieldAccess)(expr).lhs).name.toString());
|
||||
}
|
||||
|
||||
private JCIdent getTestableClassIdent(JCExpression clazz) {
|
||||
Name className = ((JCIdent)clazz).name;
|
||||
return cx.treeMaker.Ident(cx.names.fromString(className + ConstPool.TESTABLE));
|
||||
private boolean isPrivateMethod(JCMethodInvocation expr) {
|
||||
return expr.meth.getClass().equals(JCFieldAccess.class) &&
|
||||
((JCFieldAccess)(expr).meth).selected.getClass().equals(JCIdent.class) &&
|
||||
sourceClassIns.contains(((JCIdent)((JCFieldAccess)(expr).meth).selected).name) &&
|
||||
privateMethods.contains(((JCFieldAccess)(expr).meth).name.toString());
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user