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.alibaba.testable.util.ConstPool;
|
||||||
import com.sun.tools.javac.tree.JCTree.*;
|
import com.sun.tools.javac.tree.JCTree.*;
|
||||||
import com.sun.tools.javac.util.List;
|
import com.sun.tools.javac.util.List;
|
||||||
|
import com.sun.tools.javac.util.ListBuffer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author flin
|
* @author flin
|
||||||
@ -14,11 +15,19 @@ public class PrivateAccessStatementGenerator extends BaseGenerator {
|
|||||||
super(cx);
|
super(cx);
|
||||||
}
|
}
|
||||||
|
|
||||||
public JCExpression fetchSetterStatement(JCExpressionStatement jcExpressionStatement) {
|
public JCExpression fetchSetterStatement(JCAssign assign) {
|
||||||
JCAssign assign = (JCAssign)jcExpressionStatement.expr;
|
|
||||||
JCFieldAccess setter = cx.treeMaker.Select(nameToExpression(ConstPool.TESTABLE_PRIVATE_ACCESSOR),
|
JCFieldAccess setter = cx.treeMaker.Select(nameToExpression(ConstPool.TESTABLE_PRIVATE_ACCESSOR),
|
||||||
cx.names.fromString("set"));
|
cx.names.fromString("set"));
|
||||||
return cx.treeMaker.Apply(List.<JCExpression>nil(), setter, List.of(((JCFieldAccess)assign.lhs).selected,
|
return cx.treeMaker.Apply(List.<JCExpression>nil(), setter, List.of(((JCFieldAccess)assign.lhs).selected,
|
||||||
cx.treeMaker.Literal(((JCFieldAccess)assign.lhs).name.toString()), assign.rhs));
|
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
|
* @author flin
|
||||||
*/
|
*/
|
||||||
public class EnableTestableInjectTranslator extends TreeTranslator {
|
public class EnableTestableInjectTranslator extends BaseTranslator {
|
||||||
|
|
||||||
private final TestableContext cx;
|
private final TestableContext cx;
|
||||||
|
|
||||||
@ -123,18 +123,8 @@ public class EnableTestableInjectTranslator extends TreeTranslator {
|
|||||||
mods.getFlags().contains(javax.lang.model.element.Modifier.FINAL);
|
mods.getFlags().contains(javax.lang.model.element.Modifier.FINAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<JCExpression> checkAndExchange(List<JCExpression> args) {
|
@Override
|
||||||
if (args != null) {
|
protected JCExpression checkAndExchange(JCExpression expr) {
|
||||||
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) {
|
|
||||||
if (isNewOperation(expr)) {
|
if (isNewOperation(expr)) {
|
||||||
JCNewClass newClassExpr = (JCNewClass)expr;
|
JCNewClass newClassExpr = (JCNewClass)expr;
|
||||||
Name className = ((JCIdent)newClassExpr.clazz).name;
|
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)),
|
JCFieldAccess snClass = cx.treeMaker.Select(cx.treeMaker.Ident(cx.names.fromString(ConstPool.NE_PKG)),
|
||||||
cx.names.fromString(ConstPool.NE_CLS));
|
cx.names.fromString(ConstPool.NE_CLS));
|
||||||
JCFieldAccess snMethod = cx.treeMaker.Select(snClass, cx.names.fromString(ConstPool.NE_FUN));
|
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.Ident(cx.names.fromString(ConstPool.REF_THIS)));
|
||||||
args.add(cx.treeMaker.Literal(methodName.toString()));
|
args.add(cx.treeMaker.Literal(methodName.toString()));
|
||||||
args.addAll(param);
|
args.addAll(param);
|
||||||
|
@ -7,13 +7,13 @@ import com.alibaba.testable.model.TestableContext;
|
|||||||
import com.alibaba.testable.util.ConstPool;
|
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.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.List;
|
||||||
import com.sun.tools.javac.util.ListBuffer;
|
import com.sun.tools.javac.util.ListBuffer;
|
||||||
import com.sun.tools.javac.util.Name;
|
import com.sun.tools.javac.util.Name;
|
||||||
import com.sun.tools.javac.util.Pair;
|
import com.sun.tools.javac.util.Pair;
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
import java.lang.reflect.Modifier;
|
import java.lang.reflect.Modifier;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
@ -22,12 +22,13 @@ import java.util.Arrays;
|
|||||||
*
|
*
|
||||||
* @author flin
|
* @author flin
|
||||||
*/
|
*/
|
||||||
public class EnableTestableTranslator extends TreeTranslator {
|
public class EnableTestableTranslator extends BaseTranslator {
|
||||||
|
|
||||||
private final TestableContext cx;
|
private final TestableContext cx;
|
||||||
private String sourceClassName = "";
|
private String sourceClassName = "";
|
||||||
private final ListBuffer<Name> sourceClassIns = new ListBuffer<>();
|
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 TestSetupMethodGenerator testSetupMethodGenerator;
|
||||||
private final PrivateAccessStatementGenerator privateAccessStatementGenerator;
|
private final PrivateAccessStatementGenerator privateAccessStatementGenerator;
|
||||||
|
|
||||||
@ -41,7 +42,13 @@ public class EnableTestableTranslator extends TreeTranslator {
|
|||||||
Field[] fields = cls.getDeclaredFields();
|
Field[] fields = cls.getDeclaredFields();
|
||||||
for (Field f : fields) {
|
for (Field f : fields) {
|
||||||
if (Modifier.isFinal(f.getModifiers()) || Modifier.isPrivate(f.getModifiers())) {
|
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()));
|
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
|
@Override
|
||||||
public void visitVarDef(JCVariableDecl jcVariableDecl) {
|
public void visitVarDef(JCVariableDecl jcVariableDecl) {
|
||||||
super.visitVarDef(jcVariableDecl);
|
super.visitVarDef(jcVariableDecl);
|
||||||
if (jcVariableDecl.vartype.getClass().equals(JCIdent.class) &&
|
if (jcVariableDecl.vartype.getClass().equals(JCIdent.class) &&
|
||||||
((JCIdent)jcVariableDecl.vartype).name.toString().equals(sourceClassName)) {
|
((JCIdent)jcVariableDecl.vartype).name.toString().equals(sourceClassName)) {
|
||||||
jcVariableDecl.vartype = getTestableClassIdent(jcVariableDecl.vartype);
|
|
||||||
sourceClassIns.add(jcVariableDecl.name);
|
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.privateField = val -> PrivateAccessor.set(d, "privateField", val)
|
||||||
|
* d.privateMethod(args) -> PrivateAccessor.invoke(d, "privateMethod", args)
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void visitExec(JCExpressionStatement jcExpressionStatement) {
|
public void visitExec(JCExpressionStatement jcExpressionStatement) {
|
||||||
if (jcExpressionStatement.expr.getClass().equals(JCAssign.class) &&
|
if (jcExpressionStatement.expr.getClass().equals(JCAssign.class) &&
|
||||||
isAssignStubbornField((JCAssign)jcExpressionStatement.expr)) {
|
isPrivateField((JCAssign)jcExpressionStatement.expr)) {
|
||||||
jcExpressionStatement.expr = privateAccessStatementGenerator.fetchSetterStatement(jcExpressionStatement);
|
jcExpressionStatement.expr = privateAccessStatementGenerator.fetchSetterStatement(
|
||||||
|
(JCAssign)jcExpressionStatement.expr);
|
||||||
}
|
}
|
||||||
|
jcExpressionStatement.expr = checkAndExchange(jcExpressionStatement.expr);
|
||||||
super.visitExec(jcExpressionStatement);
|
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
|
@Override
|
||||||
public void visitAssign(JCAssign jcAssign) {
|
public void visitAssign(JCAssign jcAssign) {
|
||||||
@ -137,21 +141,20 @@ public class EnableTestableTranslator extends TreeTranslator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* For getter break point
|
* For private getter break point
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void visitSelect(JCFieldAccess jcFieldAccess) {
|
public void visitSelect(JCFieldAccess jcFieldAccess) {
|
||||||
super.visitSelect(jcFieldAccess);
|
super.visitSelect(jcFieldAccess);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getSimpleClassName(JCNewClass jcNewClass) {
|
@Override
|
||||||
if (jcNewClass.clazz.getClass().equals(JCIdent.class)) {
|
protected JCExpression checkAndExchange(JCExpression expr) {
|
||||||
return ((JCIdent)jcNewClass.clazz).name.toString();
|
if (expr.getClass().equals(JCMethodInvocation.class) &&
|
||||||
} else if (jcNewClass.clazz.getClass().equals(JCFieldAccess.class)) {
|
isPrivateMethod((JCMethodInvocation)expr)) {
|
||||||
return ((JCFieldAccess)jcNewClass.clazz).name.toString();
|
expr = privateAccessStatementGenerator.fetchInvokeStatement((JCMethodInvocation)expr);
|
||||||
} else {
|
|
||||||
return "";
|
|
||||||
}
|
}
|
||||||
|
return expr;
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<JCAnnotation> removeAnnotation(List<JCAnnotation> annotations, String target) {
|
private List<JCAnnotation> removeAnnotation(List<JCAnnotation> annotations, String target) {
|
||||||
@ -164,15 +167,18 @@ public class EnableTestableTranslator extends TreeTranslator {
|
|||||||
return nb.toList();
|
return nb.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isAssignStubbornField(JCAssign expr) {
|
private boolean isPrivateField(JCAssign expr) {
|
||||||
return expr.lhs.getClass().equals(JCFieldAccess.class) &&
|
return expr.lhs.getClass().equals(JCFieldAccess.class) &&
|
||||||
|
((JCFieldAccess)(expr).lhs).selected.getClass().equals(JCIdent.class) &&
|
||||||
sourceClassIns.contains(((JCIdent)((JCFieldAccess)(expr).lhs).selected).name) &&
|
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) {
|
private boolean isPrivateMethod(JCMethodInvocation expr) {
|
||||||
Name className = ((JCIdent)clazz).name;
|
return expr.meth.getClass().equals(JCFieldAccess.class) &&
|
||||||
return cx.treeMaker.Ident(cx.names.fromString(className + ConstPool.TESTABLE));
|
((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