mirror of
https://github.com/alibaba/testable-mock.git
synced 2025-01-11 04:40:12 +08:00
able to inject member methods
This commit is contained in:
parent
973ca937f6
commit
fecaafca88
@ -5,7 +5,6 @@ import com.alibaba.testable.generator.statement.CallSuperMethodStatementGenerato
|
|||||||
import com.alibaba.testable.model.TestableContext;
|
import com.alibaba.testable.model.TestableContext;
|
||||||
import com.alibaba.testable.translator.TestableClassDevRoleTranslator;
|
import com.alibaba.testable.translator.TestableClassDevRoleTranslator;
|
||||||
import com.alibaba.testable.util.ConstPool;
|
import com.alibaba.testable.util.ConstPool;
|
||||||
import com.alibaba.testable.util.StringUtil;
|
|
||||||
import com.squareup.javapoet.*;
|
import com.squareup.javapoet.*;
|
||||||
import com.sun.tools.javac.code.Symbol;
|
import com.sun.tools.javac.code.Symbol;
|
||||||
import com.sun.tools.javac.code.Type;
|
import com.sun.tools.javac.code.Type;
|
||||||
@ -52,7 +51,6 @@ public class TestableClassDevRoleGenerator {
|
|||||||
methodSpecs.add(buildFieldGetter(clazz, field));
|
methodSpecs.add(buildFieldGetter(clazz, field));
|
||||||
methodSpecs.add(buildFieldSetter(clazz, field));
|
methodSpecs.add(buildFieldSetter(clazz, field));
|
||||||
}
|
}
|
||||||
methodSpecs.add(buildStubbornFieldMethod(translator.getFields()));
|
|
||||||
|
|
||||||
TypeSpec.Builder builder = TypeSpec.classBuilder(className)
|
TypeSpec.Builder builder = TypeSpec.classBuilder(className)
|
||||||
.addModifiers(Modifier.PUBLIC, Modifier.FINAL)
|
.addModifiers(Modifier.PUBLIC, Modifier.FINAL)
|
||||||
@ -65,18 +63,6 @@ public class TestableClassDevRoleGenerator {
|
|||||||
return javaFile.toString();
|
return javaFile.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
private MethodSpec buildStubbornFieldMethod(List<JCTree.JCVariableDecl> fields) {
|
|
||||||
List<String> fieldNames = new ArrayList<>();
|
|
||||||
for (JCTree.JCVariableDecl f : fields) {
|
|
||||||
fieldNames.add("\"" + f.name.toString() + "\"");
|
|
||||||
}
|
|
||||||
return MethodSpec.methodBuilder(ConstPool.STUBBORN_FIELD_METHOD)
|
|
||||||
.addModifiers(Modifier.PUBLIC).addModifiers(Modifier.STATIC)
|
|
||||||
.addStatement("return new $T[]{" + StringUtil.join(fieldNames, ",") + "}", String.class)
|
|
||||||
.returns(ArrayTypeName.of(String.class))
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
private MethodSpec buildFieldGetter(Symbol.ClassSymbol classElement, JCTree.JCVariableDecl field) {
|
private MethodSpec buildFieldGetter(Symbol.ClassSymbol classElement, JCTree.JCVariableDecl field) {
|
||||||
String fieldName = field.name.toString();
|
String fieldName = field.name.toString();
|
||||||
return MethodSpec.methodBuilder(fieldName + ConstPool.TESTABLE_GET_METHOD_PREFIX)
|
return MethodSpec.methodBuilder(fieldName + ConstPool.TESTABLE_GET_METHOD_PREFIX)
|
||||||
|
@ -53,7 +53,7 @@ public class TestableProcessor extends BaseProcessor {
|
|||||||
private void createStaticNewClass() {
|
private void createStaticNewClass() {
|
||||||
if (!isStaticNewClassExist()) {
|
if (!isStaticNewClassExist()) {
|
||||||
try {
|
try {
|
||||||
writeSourceFile(ConstPool.SN_PKG_CLS, new StaticNewClassGenerator(cx).fetch());
|
writeSourceFile(ConstPool.NE_PKG_CLS, new StaticNewClassGenerator(cx).fetch());
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
@ -62,8 +62,8 @@ public class TestableProcessor extends BaseProcessor {
|
|||||||
|
|
||||||
private boolean isStaticNewClassExist() {
|
private boolean isStaticNewClassExist() {
|
||||||
try {
|
try {
|
||||||
FileObject staticNewClassFile = cx.filter.getResource(SOURCE_OUTPUT, ConstPool.SN_PKG,
|
FileObject staticNewClassFile = cx.filter.getResource(SOURCE_OUTPUT, ConstPool.NE_PKG,
|
||||||
ConstPool.SN_CLS + JAVA_POSTFIX);
|
ConstPool.NE_CLS + JAVA_POSTFIX);
|
||||||
return isCompilingTestClass(staticNewClassFile) || staticNewClassFile.getLastModified() > 0;
|
return isCompilingTestClass(staticNewClassFile) || staticNewClassFile.getLastModified() > 0;
|
||||||
} catch (FilerException e) {
|
} catch (FilerException e) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
package com.alibaba.testable.translator;
|
package com.alibaba.testable.translator;
|
||||||
|
|
||||||
import com.alibaba.testable.model.TestableContext;
|
import com.alibaba.testable.model.TestableContext;
|
||||||
import com.alibaba.testable.translator.tree.TestableFieldAccess;
|
|
||||||
import com.alibaba.testable.translator.tree.TestableMethodInvocation;
|
|
||||||
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.JCMethodDecl;
|
import com.sun.tools.javac.tree.JCTree.JCMethodDecl;
|
||||||
@ -11,8 +9,6 @@ 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 java.lang.reflect.Modifier;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Travel AST
|
* Travel AST
|
||||||
*
|
*
|
||||||
@ -44,12 +40,6 @@ public class TestableClassDevRoleTranslator extends TreeTranslator {
|
|||||||
this.cx = cx;
|
this.cx = cx;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visitClassDef(JCTree.JCClassDecl jcClassDecl) {
|
|
||||||
super.visitClassDef(jcClassDecl);
|
|
||||||
jcClassDecl.mods.flags = jcClassDecl.mods.flags & (~Modifier.FINAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Record all methods
|
* Record all methods
|
||||||
*/
|
*/
|
||||||
@ -61,46 +51,60 @@ public class TestableClassDevRoleTranslator extends TreeTranslator {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Case: new Demo()
|
* Case: new Demo()
|
||||||
|
* Case: member()
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void visitExec(JCTree.JCExpressionStatement jcExpressionStatement) {
|
public void visitExec(JCTree.JCExpressionStatement jcExpressionStatement) {
|
||||||
jcExpressionStatement.expr = checkAndExchangeNewOperation(jcExpressionStatement.expr);
|
jcExpressionStatement.expr = checkAndExchange(jcExpressionStatement.expr);
|
||||||
super.visitExec(jcExpressionStatement);
|
super.visitExec(jcExpressionStatement);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* For member method invocation break point
|
||||||
* Case: call(new Demo())
|
* Case: call(new Demo())
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void visitApply(JCTree.JCMethodInvocation tree) {
|
public void visitApply(JCTree.JCMethodInvocation tree) {
|
||||||
tree.args = checkAndExchangeNewOperation(tree.args);
|
tree.args = checkAndExchange(tree.args);
|
||||||
super.visitApply(tree);
|
super.visitApply(tree);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Case: return new Demo()
|
||||||
|
* Case: return member()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void visitReturn(JCTree.JCReturn jcReturn) {
|
||||||
|
jcReturn.expr = checkAndExchange(jcReturn.expr);
|
||||||
|
super.visitReturn(jcReturn);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Record all private fields
|
* Record all private fields
|
||||||
* Case: Demo d = new Demo()
|
* Case: Demo d = new Demo()
|
||||||
|
* Case: Demo d = member()
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void visitVarDef(JCTree.JCVariableDecl jcVariableDecl) {
|
public void visitVarDef(JCTree.JCVariableDecl jcVariableDecl) {
|
||||||
if (isStubbornField(jcVariableDecl.mods)) {
|
if (isStubbornField(jcVariableDecl.mods)) {
|
||||||
fields = fields.append(jcVariableDecl);
|
fields = fields.append(jcVariableDecl);
|
||||||
}
|
}
|
||||||
jcVariableDecl.init = checkAndExchangeNewOperation(jcVariableDecl.init);
|
jcVariableDecl.init = checkAndExchange(jcVariableDecl.init);
|
||||||
super.visitVarDef(jcVariableDecl);
|
super.visitVarDef(jcVariableDecl);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Case: new Demo().call()
|
* Case: new Demo().call()
|
||||||
|
* Case: member().call()
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void visitSelect(JCTree.JCFieldAccess jcFieldAccess) {
|
public void visitSelect(JCTree.JCFieldAccess jcFieldAccess) {
|
||||||
jcFieldAccess.selected = checkAndExchangeNewOperation(jcFieldAccess.selected);
|
jcFieldAccess.selected = checkAndExchange(jcFieldAccess.selected);
|
||||||
super.visitSelect(jcFieldAccess);
|
super.visitSelect(jcFieldAccess);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* For break point
|
* For new operation break point
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void visitNewClass(JCTree.JCNewClass jcNewClass) {
|
public void visitNewClass(JCTree.JCNewClass jcNewClass) {
|
||||||
@ -108,7 +112,7 @@ public class TestableClassDevRoleTranslator extends TreeTranslator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* For break point
|
* For new operation break point
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void visitNewArray(JCTree.JCNewArray jcNewArray) {
|
public void visitNewArray(JCTree.JCNewArray jcNewArray) {
|
||||||
@ -120,43 +124,62 @@ public class TestableClassDevRoleTranslator extends TreeTranslator {
|
|||||||
mods.getFlags().contains(javax.lang.model.element.Modifier.FINAL);
|
mods.getFlags().contains(javax.lang.model.element.Modifier.FINAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<JCTree.JCExpression> checkAndExchangeNewOperation(List<JCTree.JCExpression> args) {
|
private List<JCTree.JCExpression> checkAndExchange(List<JCTree.JCExpression> args) {
|
||||||
if (args != null) {
|
if (args != null) {
|
||||||
JCTree.JCExpression[] es = new JCTree.JCExpression[args.length()];
|
JCTree.JCExpression[] es = new JCTree.JCExpression[args.length()];
|
||||||
for (int i = 0; i < args.length(); i++) {
|
for (int i = 0; i < args.length(); i++) {
|
||||||
es[i] = checkAndExchangeNewOperation(args.get(i));
|
es[i] = checkAndExchange(args.get(i));
|
||||||
}
|
}
|
||||||
return List.from(es);
|
return List.from(es);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private JCTree.JCExpression checkAndExchangeNewOperation(JCTree.JCExpression expr) {
|
private JCTree.JCExpression checkAndExchange(JCTree.JCExpression expr) {
|
||||||
if (isNewOperation(expr)) {
|
if (isNewOperation(expr)) {
|
||||||
JCTree.JCNewClass newClassExpr = (JCTree.JCNewClass)expr;
|
JCTree.JCNewClass newClassExpr = (JCTree.JCNewClass)expr;
|
||||||
Name className = ((JCTree.JCIdent)newClassExpr.clazz).name;
|
Name className = ((JCTree.JCIdent)newClassExpr.clazz).name;
|
||||||
try {
|
try {
|
||||||
return getStaticNewCall(newClassExpr, className);
|
return getGlobalNewInvocation(newClassExpr, className);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
} else if (isMemberMethodInvocation(expr)) {
|
||||||
|
Name methodName = ((JCTree.JCIdent)((JCTree.JCMethodInvocation)expr).meth).name;
|
||||||
|
List<JCTree.JCExpression> args = ((JCTree.JCMethodInvocation)expr).args;
|
||||||
|
return getGlobalMemberInvocation(methodName, args);
|
||||||
}
|
}
|
||||||
return expr;
|
return expr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isMemberMethodInvocation(JCTree.JCExpression expr) {
|
||||||
|
return expr != null && expr.getClass().equals(JCTree.JCMethodInvocation.class) &&
|
||||||
|
((JCTree.JCMethodInvocation)expr).meth.getClass().equals(JCTree.JCIdent.class);
|
||||||
|
}
|
||||||
|
|
||||||
private boolean isNewOperation(JCTree.JCExpression expr) {
|
private boolean isNewOperation(JCTree.JCExpression expr) {
|
||||||
return expr != null && expr.getClass().equals(JCTree.JCNewClass.class);
|
return expr != null && expr.getClass().equals(JCTree.JCNewClass.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
private TestableMethodInvocation getStaticNewCall(JCTree.JCNewClass newClassExpr, Name className) {
|
private JCTree.JCMethodInvocation getGlobalNewInvocation(JCTree.JCNewClass newClassExpr, Name className) {
|
||||||
TestableFieldAccess snClass = new TestableFieldAccess(cx.treeMaker.Ident(cx.names.fromString(ConstPool.SN_PKG)),
|
JCTree.JCFieldAccess snClass = cx.treeMaker.Select(cx.treeMaker.Ident(cx.names.fromString(ConstPool.NE_PKG)),
|
||||||
cx.names.fromString(ConstPool.SN_CLS), null);
|
cx.names.fromString(ConstPool.NE_CLS));
|
||||||
TestableFieldAccess snMethod = new TestableFieldAccess(snClass,
|
JCTree.JCFieldAccess snMethod = cx.treeMaker.Select(snClass, cx.names.fromString(ConstPool.NE_NEW));
|
||||||
cx.names.fromString(ConstPool.SN_METHOD), null);
|
JCTree.JCExpression classType = cx.treeMaker.Select(cx.treeMaker.Ident(className),
|
||||||
JCTree.JCExpression classType = new TestableFieldAccess(cx.treeMaker.Ident(className),
|
cx.names.fromString(ConstPool.TYPE_TO_CLASS));
|
||||||
cx.names.fromString(ConstPool.TYPE_TO_CLASS), null);
|
|
||||||
ListBuffer<JCTree.JCExpression> args = ListBuffer.of(classType);
|
ListBuffer<JCTree.JCExpression> args = ListBuffer.of(classType);
|
||||||
args.addAll(newClassExpr.args);
|
args.addAll(newClassExpr.args);
|
||||||
return new TestableMethodInvocation(null, snMethod, args.toList());
|
return cx.treeMaker.Apply(List.<JCTree.JCExpression>nil(), snMethod, args.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
private JCTree.JCMethodInvocation getGlobalMemberInvocation(Name methodName, List<JCTree.JCExpression> param) {
|
||||||
|
JCTree.JCFieldAccess snClass = cx.treeMaker.Select(cx.treeMaker.Ident(cx.names.fromString(ConstPool.NE_PKG)),
|
||||||
|
cx.names.fromString(ConstPool.NE_CLS));
|
||||||
|
JCTree.JCFieldAccess snMethod = cx.treeMaker.Select(snClass, cx.names.fromString(ConstPool.NE_INK));
|
||||||
|
ListBuffer<JCTree.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);
|
||||||
|
return cx.treeMaker.Apply(List.<JCTree.JCExpression>nil(), snMethod, args.toList());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,8 +2,6 @@ package com.alibaba.testable.translator;
|
|||||||
|
|
||||||
import com.alibaba.testable.model.TestLibType;
|
import com.alibaba.testable.model.TestLibType;
|
||||||
import com.alibaba.testable.model.TestableContext;
|
import com.alibaba.testable.model.TestableContext;
|
||||||
import com.alibaba.testable.translator.tree.TestableFieldAccess;
|
|
||||||
import com.alibaba.testable.translator.tree.TestableMethodInvocation;
|
|
||||||
import com.alibaba.testable.util.ConstPool;
|
import com.alibaba.testable.util.ConstPool;
|
||||||
import com.sun.tools.javac.code.Type;
|
import com.sun.tools.javac.code.Type;
|
||||||
import com.sun.tools.javac.tree.JCTree;
|
import com.sun.tools.javac.tree.JCTree;
|
||||||
@ -27,11 +25,11 @@ public class TestableClassTestRoleTranslator extends TreeTranslator {
|
|||||||
private static final String ANNOTATION_JUNIT5_SETUP = "org.junit.jupiter.api.BeforeEach";
|
private static final String ANNOTATION_JUNIT5_SETUP = "org.junit.jupiter.api.BeforeEach";
|
||||||
private static final String ANNOTATION_JUNIT5_TEST = "org.junit.jupiter.api.Test";
|
private static final String ANNOTATION_JUNIT5_TEST = "org.junit.jupiter.api.Test";
|
||||||
private static final String TYPE_CLASS = "Class";
|
private static final String TYPE_CLASS = "Class";
|
||||||
private static final String REF_THIS = "this";
|
|
||||||
private final TestableContext cx;
|
private final TestableContext cx;
|
||||||
private String sourceClassName = "";
|
private String sourceClassName = "";
|
||||||
private ListBuffer<Name> sourceClassIns = new ListBuffer();
|
private final ListBuffer<Name> sourceClassIns = new ListBuffer();
|
||||||
private List<String> stubbornFields = List.nil();
|
private final ListBuffer<String> stubbornFields = new ListBuffer();
|
||||||
|
private final ListBuffer<Method> memberMethods = new ListBuffer();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* MethodName -> (ResultType -> ParameterTypes)
|
* MethodName -> (ResultType -> ParameterTypes)
|
||||||
@ -44,10 +42,14 @@ public class TestableClassTestRoleTranslator extends TreeTranslator {
|
|||||||
this.sourceClassName = className;
|
this.sourceClassName = className;
|
||||||
this.cx = cx;
|
this.cx = cx;
|
||||||
try {
|
try {
|
||||||
stubbornFields = List.from(
|
Class<?> cls = Class.forName(pkgName + "." + className);
|
||||||
(String[])Class.forName(pkgName + "." + className + ConstPool.TESTABLE)
|
Field[] fields = cls.getDeclaredFields();
|
||||||
.getMethod(ConstPool.STUBBORN_FIELD_METHOD)
|
for (Field f : fields) {
|
||||||
.invoke(null));
|
if (Modifier.isFinal(f.getModifiers()) || Modifier.isPrivate(f.getModifiers())) {
|
||||||
|
stubbornFields.add(f.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
memberMethods.addAll(Arrays.asList(cls.getDeclaredMethods()));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
@ -85,10 +87,9 @@ public class TestableClassTestRoleTranslator extends TreeTranslator {
|
|||||||
if (jcExpressionStatement.expr.getClass().equals(JCAssign.class) &&
|
if (jcExpressionStatement.expr.getClass().equals(JCAssign.class) &&
|
||||||
isAssignStubbornField((JCAssign)jcExpressionStatement.expr)) {
|
isAssignStubbornField((JCAssign)jcExpressionStatement.expr)) {
|
||||||
JCAssign assign = (JCAssign)jcExpressionStatement.expr;
|
JCAssign assign = (JCAssign)jcExpressionStatement.expr;
|
||||||
// TODO: Use treeMaker.Apply() and treeMaker.Select()
|
JCFieldAccess stubbornSetter = cx.treeMaker.Select(((JCFieldAccess)assign.lhs).selected,
|
||||||
TestableFieldAccess stubbornSetter = new TestableFieldAccess(((JCFieldAccess)assign.lhs).selected,
|
getStubbornSetterMethodName(assign));
|
||||||
getStubbornSetterMethodName(assign), null);
|
jcExpressionStatement.expr = cx.treeMaker.Apply(List.<JCExpression>nil(), stubbornSetter,
|
||||||
jcExpressionStatement.expr = new TestableMethodInvocation(null, stubbornSetter,
|
|
||||||
com.sun.tools.javac.util.List.of(assign.rhs));
|
com.sun.tools.javac.util.List.of(assign.rhs));
|
||||||
}
|
}
|
||||||
super.visitExec(jcExpressionStatement);
|
super.visitExec(jcExpressionStatement);
|
||||||
@ -103,12 +104,14 @@ public class TestableClassTestRoleTranslator extends TreeTranslator {
|
|||||||
for (JCVariableDecl p : jcMethodDecl.params) {
|
for (JCVariableDecl p : jcMethodDecl.params) {
|
||||||
args.add(cx.treeMaker.Select(p.vartype, cx.names.fromString(ConstPool.TYPE_TO_CLASS)));
|
args.add(cx.treeMaker.Select(p.vartype, cx.names.fromString(ConstPool.TYPE_TO_CLASS)));
|
||||||
}
|
}
|
||||||
JCExpression retType = cx.treeMaker.Select(jcMethodDecl.restype, cx.names.fromString(ConstPool.TYPE_TO_CLASS));
|
JCExpression retType = jcMethodDecl.restype == null ? null :
|
||||||
|
cx.treeMaker.Select(jcMethodDecl.restype, cx.names.fromString(ConstPool.TYPE_TO_CLASS));
|
||||||
injectMethods.add(Pair.of(jcMethodDecl.name, Pair.of(retType, args.toList())));
|
injectMethods.add(Pair.of(jcMethodDecl.name, Pair.of(retType, args.toList())));
|
||||||
break;
|
break;
|
||||||
case ANNOTATION_JUNIT5_SETUP:
|
case ANNOTATION_JUNIT5_SETUP:
|
||||||
testSetupMethodName = jcMethodDecl.name.toString();
|
testSetupMethodName = jcMethodDecl.name.toString();
|
||||||
jcMethodDecl.mods.annotations = removeAnnotation(jcMethodDecl.mods.annotations, ANNOTATION_JUNIT5_SETUP);
|
jcMethodDecl.mods.annotations = removeAnnotation(jcMethodDecl.mods.annotations,
|
||||||
|
ANNOTATION_JUNIT5_SETUP);
|
||||||
break;
|
break;
|
||||||
case ANNOTATION_JUNIT5_TEST:
|
case ANNOTATION_JUNIT5_TEST:
|
||||||
testLibType = TestLibType.JUnit5;
|
testLibType = TestLibType.JUnit5;
|
||||||
@ -155,7 +158,7 @@ public class TestableClassTestRoleTranslator extends TreeTranslator {
|
|||||||
private JCExpression nameToExpression(String dotName) {
|
private JCExpression nameToExpression(String dotName) {
|
||||||
String[] nameParts = dotName.split("\\.");
|
String[] nameParts = dotName.split("\\.");
|
||||||
JCExpression e = cx.treeMaker.Ident(cx.names.fromString(nameParts[0]));
|
JCExpression e = cx.treeMaker.Ident(cx.names.fromString(nameParts[0]));
|
||||||
for (int i = 1 ; i < nameParts.length ; i++) {
|
for (int i = 1; i < nameParts.length; i++) {
|
||||||
e = cx.treeMaker.Select(e, cx.names.fromString(nameParts[i]));
|
e = cx.treeMaker.Select(e, cx.names.fromString(nameParts[i]));
|
||||||
}
|
}
|
||||||
return e;
|
return e;
|
||||||
@ -164,7 +167,11 @@ public class TestableClassTestRoleTranslator extends TreeTranslator {
|
|||||||
private JCBlock testableSetupBlock() {
|
private JCBlock testableSetupBlock() {
|
||||||
ListBuffer<JCStatement> statements = new ListBuffer<>();
|
ListBuffer<JCStatement> statements = new ListBuffer<>();
|
||||||
for (Pair<Name, Pair<JCExpression, List<JCExpression>>> m : injectMethods.toList()) {
|
for (Pair<Name, Pair<JCExpression, List<JCExpression>>> m : injectMethods.toList()) {
|
||||||
statements.append(toGlobalNewStatement(m));
|
if (isMemberMethod(m)) {
|
||||||
|
statements.append(toGlobalInvokeStatement(m));
|
||||||
|
} else {
|
||||||
|
statements.append(toGlobalNewStatement(m));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (!testSetupMethodName.isEmpty()) {
|
if (!testSetupMethodName.isEmpty()) {
|
||||||
statements.append(cx.treeMaker.Exec(cx.treeMaker.Apply(List.<JCExpression>nil(),
|
statements.append(cx.treeMaker.Exec(cx.treeMaker.Apply(List.<JCExpression>nil(),
|
||||||
@ -173,20 +180,59 @@ public class TestableClassTestRoleTranslator extends TreeTranslator {
|
|||||||
return cx.treeMaker.Block(0, statements.toList());
|
return cx.treeMaker.Block(0, statements.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
private JCStatement toGlobalNewStatement(
|
private boolean isMemberMethod(Pair<Name, Pair<JCExpression, List<JCExpression>>> m) {
|
||||||
Pair<Name, Pair<JCExpression, List<JCExpression>>> m) {
|
for (Method method : memberMethods) {
|
||||||
JCExpression key = nameToExpression(ConstPool.NS_W_KEY);
|
if (method.getName().equals(m.fst.toString()) && parameterEquals(m.snd.snd, method.getParameterTypes())) {
|
||||||
JCExpression classType = m.snd.fst;
|
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 toGlobalInvokeStatement(Pair<Name, Pair<JCExpression, List<JCExpression>>> m) {
|
||||||
|
JCExpression key = nameToExpression(ConstPool.NE_X_KEY);
|
||||||
|
JCExpression value = nameToExpression(ConstPool.NE_X_VAL);
|
||||||
|
JCExpression methodName = cx.treeMaker.Literal(m.fst.toString());
|
||||||
|
JCExpression thisIns = cx.treeMaker.Ident(cx.names.fromString(ConstPool.REF_THIS));
|
||||||
|
JCExpression returnClassType = m.snd.fst;
|
||||||
JCExpression parameterTypes = cx.treeMaker.NewArray(cx.treeMaker.Ident(cx.names.fromString(TYPE_CLASS)),
|
JCExpression parameterTypes = cx.treeMaker.NewArray(cx.treeMaker.Ident(cx.names.fromString(TYPE_CLASS)),
|
||||||
List.<JCExpression>nil(), m.snd.snd);
|
List.<JCExpression>nil(), m.snd.snd);
|
||||||
JCNewClass keyClass = cx.treeMaker.NewClass(null, List.<JCExpression>nil(), key,
|
JCNewClass keyClass = cx.treeMaker.NewClass(null, List.<JCExpression>nil(), key,
|
||||||
List.of(classType, parameterTypes), null);
|
List.of(methodName, parameterTypes), null);
|
||||||
JCExpression value = nameToExpression(ConstPool.NS_VAL);
|
JCNewClass valClass = cx.treeMaker.NewClass(null, List.<JCExpression>nil(), value,
|
||||||
JCExpression thisIns = cx.treeMaker.Ident(cx.names.fromString(REF_THIS));
|
List.of(thisIns, returnClassType), null);
|
||||||
|
JCExpression addInjectMethod = nameToExpression(ConstPool.NE_X_ADD);
|
||||||
|
JCMethodInvocation apply = cx.treeMaker.Apply(List.<JCExpression>nil(), addInjectMethod,
|
||||||
|
List.from(new JCExpression[] {keyClass, valClass}));
|
||||||
|
return cx.treeMaker.Exec(apply);
|
||||||
|
}
|
||||||
|
|
||||||
|
private JCStatement toGlobalNewStatement(Pair<Name, Pair<JCExpression, List<JCExpression>>> m) {
|
||||||
|
JCExpression key = nameToExpression(ConstPool.NE_W_KEY);
|
||||||
|
JCExpression value = nameToExpression(ConstPool.NE_W_VAL);
|
||||||
|
JCExpression classType = m.snd.fst;
|
||||||
|
JCExpression parameterTypes = cx.treeMaker.NewArray(cx.treeMaker.Ident(cx.names.fromString(TYPE_CLASS)),
|
||||||
|
List.<JCExpression>nil(), m.snd.snd);
|
||||||
|
JCExpression thisIns = cx.treeMaker.Ident(cx.names.fromString(ConstPool.REF_THIS));
|
||||||
JCExpression methodName = cx.treeMaker.Literal(m.fst.toString());
|
JCExpression methodName = cx.treeMaker.Literal(m.fst.toString());
|
||||||
|
JCNewClass keyClass = cx.treeMaker.NewClass(null, List.<JCExpression>nil(), key,
|
||||||
|
List.of(classType, parameterTypes), null);
|
||||||
JCNewClass valClass = cx.treeMaker.NewClass(null, List.<JCExpression>nil(), value,
|
JCNewClass valClass = cx.treeMaker.NewClass(null, List.<JCExpression>nil(), value,
|
||||||
List.of(thisIns, methodName), null);
|
List.of(thisIns, methodName), null);
|
||||||
JCExpression addInjectMethod = nameToExpression(ConstPool.NS_W_ADD);
|
JCExpression addInjectMethod = nameToExpression(ConstPool.NE_W_ADD);
|
||||||
JCMethodInvocation apply = cx.treeMaker.Apply(List.<JCExpression>nil(), addInjectMethod,
|
JCMethodInvocation apply = cx.treeMaker.Apply(List.<JCExpression>nil(), addInjectMethod,
|
||||||
List.from(new JCExpression[] {keyClass, valClass}));
|
List.from(new JCExpression[] {keyClass, valClass}));
|
||||||
return cx.treeMaker.Exec(apply);
|
return cx.treeMaker.Exec(apply);
|
||||||
|
@ -1,16 +0,0 @@
|
|||||||
package com.alibaba.testable.translator.tree;
|
|
||||||
|
|
||||||
import com.sun.tools.javac.code.Symbol;
|
|
||||||
import com.sun.tools.javac.tree.JCTree;
|
|
||||||
import com.sun.tools.javac.util.Name;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author flin
|
|
||||||
*/
|
|
||||||
public class TestableFieldAccess extends JCTree.JCFieldAccess {
|
|
||||||
|
|
||||||
public TestableFieldAccess(JCExpression selected, Name name, Symbol sym) {
|
|
||||||
super(selected, name, sym);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,15 +0,0 @@
|
|||||||
package com.alibaba.testable.translator.tree;
|
|
||||||
|
|
||||||
import com.sun.tools.javac.tree.JCTree;
|
|
||||||
import com.sun.tools.javac.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author flin
|
|
||||||
*/
|
|
||||||
public class TestableMethodInvocation extends JCTree.JCMethodInvocation {
|
|
||||||
|
|
||||||
public TestableMethodInvocation(List<JCExpression> typeargs, JCExpression meth, List<JCExpression> args) {
|
|
||||||
super(typeargs, meth, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -8,16 +8,20 @@ public final class ConstPool {
|
|||||||
public static final String CONSTRUCTOR_NAME = "<init>";
|
public static final String CONSTRUCTOR_NAME = "<init>";
|
||||||
public static final String TYPE_VOID = "void";
|
public static final String TYPE_VOID = "void";
|
||||||
public static final String TESTABLE = "Testable";
|
public static final String TESTABLE = "Testable";
|
||||||
public static final String SN_PKG = "n";
|
public static final String NE_PKG = "n";
|
||||||
public static final String SN_CLS = "e";
|
public static final String NE_CLS = "e";
|
||||||
public static final String SN_METHOD = "w";
|
public static final String NE_NEW = "w";
|
||||||
public static final String SN_PKG_CLS = "n.e";
|
public static final String NE_INK = "x";
|
||||||
public static final String NS_W_KEY = "n.e.wk";
|
public static final String NE_PKG_CLS = "n.e";
|
||||||
public static final String NS_VAL = "n.e.v";
|
public static final String NE_W_KEY = "n.e.wk";
|
||||||
public static final String NS_W_ADD = "n.e.wa";
|
public static final String NE_X_KEY = "n.e.xk";
|
||||||
public static final String STUBBORN_FIELD_METHOD = "stubbornField";
|
public static final String NE_W_VAL = "n.e.wv";
|
||||||
|
public static final String NE_X_VAL = "n.e.xv";
|
||||||
|
public static final String NE_W_ADD = "n.e.wa";
|
||||||
|
public static final String NE_X_ADD = "n.e.xa";
|
||||||
public static final String TESTABLE_GET_METHOD_PREFIX = "TestableGet";
|
public static final String TESTABLE_GET_METHOD_PREFIX = "TestableGet";
|
||||||
public static final String TESTABLE_SET_METHOD_PREFIX = "TestableSet";
|
public static final String TESTABLE_SET_METHOD_PREFIX = "TestableSet";
|
||||||
public static final String TYPE_TO_CLASS = "class";
|
public static final String TYPE_TO_CLASS = "class";
|
||||||
|
public static final String REF_THIS = "this";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -57,33 +57,46 @@ public final class e {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* value for contructor and method pool
|
* value for contructor pool
|
||||||
*/
|
*/
|
||||||
public static class v {
|
public static class wv {
|
||||||
public Object o; // object which provides substitution
|
public Object o; // object which provides substitution
|
||||||
public String m; // substitutional method name
|
public String m; // substitutional method name
|
||||||
|
|
||||||
public v(Object o, String m) {
|
public wv(Object o, String m) {
|
||||||
this.o = o;
|
this.o = o;
|
||||||
this.m = m;
|
this.m = m;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Map<wk, v> wp = new HashMap<>();
|
/**
|
||||||
private static Map<xk, v> xp = new HashMap<>();
|
* value for member method pool
|
||||||
|
*/
|
||||||
|
public static class xv {
|
||||||
|
public Object o; // object which provides substitution
|
||||||
|
public Class c; // method return type
|
||||||
|
|
||||||
|
public xv(Object o, Class c) {
|
||||||
|
this.o = o;
|
||||||
|
this.c = c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Map<wk, wv> wp = new HashMap<>();
|
||||||
|
private static Map<xk, xv> xp = new HashMap<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* add item to contructor pool
|
* add item to contructor pool
|
||||||
*/
|
*/
|
||||||
public static void wa(wk k, v vv) {
|
public static void wa(wk k, wv v) {
|
||||||
wp.put(k, vv);
|
wp.put(k, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* add item to method pool
|
* add item to method pool
|
||||||
*/
|
*/
|
||||||
public static void xa(xk k, v vv) {
|
public static void xa(xk k, xv v) {
|
||||||
xp.put(k, vv);
|
xp.put(k, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -96,7 +109,7 @@ public final class e {
|
|||||||
}
|
}
|
||||||
if (!wp.isEmpty()) {
|
if (!wp.isEmpty()) {
|
||||||
try {
|
try {
|
||||||
Pair<wk, v> p = gwp(new wk(ct, cs));
|
Pair<wk, wv> p = gwp(new wk(ct, cs));
|
||||||
if (p != null) {
|
if (p != null) {
|
||||||
Method m = p.snd.o.getClass().getDeclaredMethod(p.snd.m, p.fst.a);
|
Method m = p.snd.o.getClass().getDeclaredMethod(p.snd.m, p.fst.a);
|
||||||
m.setAccessible(true);
|
m.setAccessible(true);
|
||||||
@ -120,24 +133,25 @@ public final class e {
|
|||||||
/**
|
/**
|
||||||
* subsitituion entry for member call
|
* subsitituion entry for member call
|
||||||
*/
|
*/
|
||||||
public static Object x(Object obj, String method, Object... as) {
|
public static <T> T x(Object obj, String method, Object... as) {
|
||||||
Class[] cs = gcs(as);
|
Class[] cs = gcs(as);
|
||||||
if (!xp.isEmpty()) {
|
if (!xp.isEmpty()) {
|
||||||
try {
|
try {
|
||||||
Pair<xk, v> p = gxp(new xk(method, cs));
|
Pair<xk, xv> p = gxp(new xk(method, cs));
|
||||||
if (p != null) {
|
if (p != null) {
|
||||||
Method m = p.snd.o.getClass().getDeclaredMethod(p.snd.m, p.fst.a);
|
Method m = p.snd.o.getClass().getDeclaredMethod(p.fst.m, p.fst.a);
|
||||||
m.setAccessible(true);
|
m.setAccessible(true);
|
||||||
return m.invoke(p.snd.o, as);
|
return (T)m.invoke(p.snd.o, as);
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
Method m = gm(obj.getClass().getMethods(), cs);
|
Method m = gm(obj.getClass().getDeclaredMethods(), method, cs);
|
||||||
if (m != null) {
|
if (m != null) {
|
||||||
return m.invoke(obj, as);
|
m.setAccessible(true);
|
||||||
|
return (T)m.invoke(obj, as);
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
return null;
|
return null;
|
||||||
@ -159,9 +173,9 @@ public final class e {
|
|||||||
/**
|
/**
|
||||||
* get method by parameter matching
|
* get method by parameter matching
|
||||||
*/
|
*/
|
||||||
private static Method gm(Method[] methods, Class[] cs) {
|
private static Method gm(Method[] methods, String name, Class[] cs) {
|
||||||
for (Method m : methods) {
|
for (Method m : methods) {
|
||||||
if (te(m.getParameterTypes(), cs)) {
|
if (m.getName().equals(name) && te(m.getParameterTypes(), cs)) {
|
||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -171,7 +185,7 @@ public final class e {
|
|||||||
/**
|
/**
|
||||||
* get from method pool by key
|
* get from method pool by key
|
||||||
*/
|
*/
|
||||||
private static Pair<xk, v> gxp(xk k1) {
|
private static Pair<xk, xv> gxp(xk k1) {
|
||||||
for (xk k2 : xp.keySet()) {
|
for (xk k2 : xp.keySet()) {
|
||||||
if (k1.m.equals(k2.m) && te(k2.a, k1.a)) {
|
if (k1.m.equals(k2.m) && te(k2.a, k1.a)) {
|
||||||
return Pair.of(k2, xp.get(k2));
|
return Pair.of(k2, xp.get(k2));
|
||||||
@ -195,7 +209,7 @@ public final class e {
|
|||||||
/**
|
/**
|
||||||
* get from contructor pool by key
|
* get from contructor pool by key
|
||||||
*/
|
*/
|
||||||
private static Pair<wk, v> gwp(wk k1) {
|
private static Pair<wk, wv> gwp(wk k1) {
|
||||||
for (wk k2 : wp.keySet()) {
|
for (wk k2 : wp.keySet()) {
|
||||||
if (k1.c.equals(k2.c) && te(k2.a, k1.a)) {
|
if (k1.c.equals(k2.c) && te(k2.a, k1.a)) {
|
||||||
return Pair.of(k2, wp.get(k2));
|
return Pair.of(k2, wp.get(k2));
|
||||||
|
Loading…
Reference in New Issue
Block a user