mirror of
https://github.com/alibaba/testable-mock.git
synced 2026-08-23 03:33:30 +08:00
extract testable context
This commit is contained in:
@@ -2,16 +2,14 @@ package com.alibaba.testable.generator;
|
||||
|
||||
import com.alibaba.testable.generator.model.Statement;
|
||||
import com.alibaba.testable.generator.statement.CallSuperMethodStatementGenerator;
|
||||
import com.alibaba.testable.model.TestableContext;
|
||||
import com.alibaba.testable.translator.TestableClassDevRoleTranslator;
|
||||
import com.alibaba.testable.util.ConstPool;
|
||||
import com.alibaba.testable.util.StringUtil;
|
||||
import com.squareup.javapoet.*;
|
||||
import com.sun.tools.javac.api.JavacTrees;
|
||||
import com.sun.tools.javac.code.Symbol;
|
||||
import com.sun.tools.javac.code.Type;
|
||||
import com.sun.tools.javac.tree.JCTree;
|
||||
import com.sun.tools.javac.tree.TreeMaker;
|
||||
import com.sun.tools.javac.util.Names;
|
||||
|
||||
import javax.lang.model.element.Element;
|
||||
import javax.lang.model.element.Modifier;
|
||||
@@ -28,19 +26,15 @@ import java.util.Set;
|
||||
*/
|
||||
public class TestableClassDevRoleGenerator {
|
||||
|
||||
private final JavacTrees trees;
|
||||
private final TreeMaker treeMaker;
|
||||
private final Names names;
|
||||
private final TestableContext cx;
|
||||
|
||||
public TestableClassDevRoleGenerator(JavacTrees trees, TreeMaker treeMaker, Names names) {
|
||||
this.trees = trees;
|
||||
this.treeMaker = treeMaker;
|
||||
this.names = names;
|
||||
public TestableClassDevRoleGenerator(TestableContext cx) {
|
||||
this.cx = cx;
|
||||
}
|
||||
|
||||
public String fetch(Symbol.ClassSymbol clazz, String packageName, String className) {
|
||||
JCTree tree = trees.getTree(clazz);
|
||||
TestableClassDevRoleTranslator translator = new TestableClassDevRoleTranslator(treeMaker, names);
|
||||
JCTree tree = cx.trees.getTree(clazz);
|
||||
TestableClassDevRoleTranslator translator = new TestableClassDevRoleTranslator(cx);
|
||||
tree.accept(translator);
|
||||
|
||||
List<MethodSpec> methodSpecs = new ArrayList<>();
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
package com.alibaba.testable.model;
|
||||
|
||||
import com.alibaba.testable.util.TestableLogger;
|
||||
import com.sun.tools.javac.api.JavacTrees;
|
||||
import com.sun.tools.javac.tree.TreeMaker;
|
||||
import com.sun.tools.javac.util.Names;
|
||||
|
||||
import javax.annotation.processing.Filer;
|
||||
import javax.lang.model.util.Elements;
|
||||
import javax.lang.model.util.Types;
|
||||
|
||||
/**
|
||||
* @author flin
|
||||
*/
|
||||
public class TestableContext {
|
||||
|
||||
/**
|
||||
* TestableLogger used for printing log during compilation
|
||||
*/
|
||||
public final TestableLogger logger;
|
||||
|
||||
/**
|
||||
* Filer used for generate source file
|
||||
*/
|
||||
public final Filer filter;
|
||||
|
||||
/**
|
||||
* Elements used for operator element
|
||||
*/
|
||||
public final Elements elementUtils;
|
||||
|
||||
/**
|
||||
* Types used for operator type
|
||||
*/
|
||||
public final Types typeUtils;
|
||||
|
||||
/**
|
||||
* JavacTrees provide the source AST
|
||||
*/
|
||||
public final JavacTrees trees;
|
||||
|
||||
/**
|
||||
* TreeMaker used for creating AST node
|
||||
*/
|
||||
public final TreeMaker treeMaker;
|
||||
|
||||
/**
|
||||
* Names used for creating resource name
|
||||
*/
|
||||
public final Names names;
|
||||
|
||||
public TestableContext(TestableLogger logger, Filer filter, Elements elementUtils,
|
||||
Types typeUtils, JavacTrees trees, TreeMaker treeMaker, Names names) {
|
||||
this.logger = logger;
|
||||
this.filter = filter;
|
||||
this.elementUtils = elementUtils;
|
||||
this.typeUtils = typeUtils;
|
||||
this.trees = trees;
|
||||
this.treeMaker = treeMaker;
|
||||
this.names = names;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.alibaba.testable.processor;
|
||||
|
||||
import com.alibaba.testable.model.TestableContext;
|
||||
import com.alibaba.testable.util.TestableLogger;
|
||||
import com.sun.tools.javac.api.JavacTrees;
|
||||
import com.sun.tools.javac.processing.JavacProcessingEnvironment;
|
||||
import com.sun.tools.javac.tree.TreeMaker;
|
||||
@@ -7,75 +9,22 @@ import com.sun.tools.javac.util.Context;
|
||||
import com.sun.tools.javac.util.Names;
|
||||
|
||||
import javax.annotation.processing.AbstractProcessor;
|
||||
import javax.annotation.processing.Filer;
|
||||
import javax.annotation.processing.Messager;
|
||||
import javax.annotation.processing.ProcessingEnvironment;
|
||||
import javax.lang.model.util.Elements;
|
||||
import javax.lang.model.util.Types;
|
||||
import javax.tools.Diagnostic;
|
||||
|
||||
/**
|
||||
* @author flin
|
||||
*/
|
||||
public abstract class BaseProcessor extends AbstractProcessor {
|
||||
|
||||
/**
|
||||
* Messager used for printing log during compilation
|
||||
*/
|
||||
private Messager messager;
|
||||
|
||||
/**
|
||||
* Filer used for generate source file
|
||||
*/
|
||||
protected Filer filter;
|
||||
|
||||
/**
|
||||
* Elements used for operator element
|
||||
*/
|
||||
protected Elements elementUtils;
|
||||
|
||||
/**
|
||||
* Types used for operator type
|
||||
*/
|
||||
protected Types typeUtils;
|
||||
|
||||
/**
|
||||
* JavacTrees provide the source AST
|
||||
*/
|
||||
protected JavacTrees trees;
|
||||
|
||||
/**
|
||||
* TreeMaker used for creating AST node
|
||||
*/
|
||||
protected TreeMaker treeMaker;
|
||||
|
||||
/**
|
||||
* Names used for creating resource name
|
||||
*/
|
||||
protected Names names;
|
||||
protected TestableContext cx;
|
||||
|
||||
@Override
|
||||
public synchronized void init(ProcessingEnvironment processingEnv) {
|
||||
super.init(processingEnv);
|
||||
Context context = ((JavacProcessingEnvironment)processingEnv).getContext();
|
||||
messager = processingEnv.getMessager();
|
||||
filter = processingEnv.getFiler();
|
||||
elementUtils = processingEnv.getElementUtils();
|
||||
typeUtils = processingEnv.getTypeUtils();
|
||||
trees = JavacTrees.instance(processingEnv);
|
||||
treeMaker = TreeMaker.instance(context);
|
||||
names = Names.instance(context);
|
||||
cx = new TestableContext(new TestableLogger(processingEnv.getMessager()), processingEnv.getFiler(),
|
||||
processingEnv.getElementUtils(), processingEnv.getTypeUtils(), JavacTrees.instance(processingEnv),
|
||||
TreeMaker.instance(context), Names.instance(context));
|
||||
}
|
||||
|
||||
protected void info(String msg) {
|
||||
System.out.println("[INFO] " + msg);
|
||||
}
|
||||
|
||||
protected void warn(String msg) {
|
||||
messager.printMessage(Diagnostic.Kind.MANDATORY_WARNING, msg);
|
||||
}
|
||||
|
||||
protected void error(String msg) {
|
||||
messager.printMessage(Diagnostic.Kind.ERROR, msg);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ public class TestableProcessor extends BaseProcessor {
|
||||
private void createStaticNewClass() {
|
||||
if (!isStaticNewClassExist()) {
|
||||
try {
|
||||
writeSourceFile(ConstPool.SN_PKG_CLS, new StaticNewClassGenerator().fetch());
|
||||
writeSourceFile(ConstPool.SN_PKG_CLS, new StaticNewClassGenerator(cx).fetch());
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
@@ -62,7 +62,7 @@ public class TestableProcessor extends BaseProcessor {
|
||||
|
||||
private boolean isStaticNewClassExist() {
|
||||
try {
|
||||
FileObject staticNewClassFile = filter.getResource(SOURCE_OUTPUT, ConstPool.SN_PKG,
|
||||
FileObject staticNewClassFile = cx.filter.getResource(SOURCE_OUTPUT, ConstPool.SN_PKG,
|
||||
ConstPool.SN_CLS + JAVA_POSTFIX);
|
||||
return isCompilingTestClass(staticNewClassFile) || staticNewClassFile.getLastModified() > 0;
|
||||
} catch (FilerException e) {
|
||||
@@ -81,20 +81,20 @@ public class TestableProcessor extends BaseProcessor {
|
||||
}
|
||||
|
||||
private void processDevRoleClassElement(Symbol.ClassSymbol clazz) {
|
||||
String packageName = elementUtils.getPackageOf(clazz).getQualifiedName().toString();
|
||||
String packageName = cx.elementUtils.getPackageOf(clazz).getQualifiedName().toString();
|
||||
String testableTypeName = getTestableClassName(clazz.getSimpleName());
|
||||
String fullQualityTypeName = packageName + "." + testableTypeName;
|
||||
try {
|
||||
writeSourceFile(fullQualityTypeName,
|
||||
new TestableClassDevRoleGenerator(trees, treeMaker, names).fetch(clazz, packageName, testableTypeName));
|
||||
new TestableClassDevRoleGenerator(cx).fetch(clazz, packageName, testableTypeName));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private void processTestRoleClassElement(Symbol.ClassSymbol clazz) {
|
||||
JCTree tree = trees.getTree(clazz);
|
||||
tree.accept(new TestableClassTestRoleTranslator(getPkgName(clazz), getOriginClassName(clazz), treeMaker, names));
|
||||
JCTree tree = cx.trees.getTree(clazz);
|
||||
tree.accept(new TestableClassTestRoleTranslator(getPkgName(clazz), getOriginClassName(clazz), cx));
|
||||
}
|
||||
|
||||
private String getPkgName(Symbol.ClassSymbol clazz) {
|
||||
@@ -107,7 +107,7 @@ public class TestableProcessor extends BaseProcessor {
|
||||
}
|
||||
|
||||
private void writeSourceFile(String fullQualityTypeName, String content) throws IOException {
|
||||
JavaFileObject jfo = filter.createSourceFile(fullQualityTypeName);
|
||||
JavaFileObject jfo = cx.filter.createSourceFile(fullQualityTypeName);
|
||||
Writer writer = jfo.openWriter();
|
||||
writer.write(content);
|
||||
writer.close();
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
package com.alibaba.testable.translator;
|
||||
|
||||
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.sun.tools.javac.tree.JCTree;
|
||||
import com.sun.tools.javac.tree.JCTree.JCMethodDecl;
|
||||
import com.sun.tools.javac.tree.TreeMaker;
|
||||
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.Names;
|
||||
|
||||
import java.lang.reflect.Modifier;
|
||||
|
||||
@@ -21,8 +20,7 @@ import java.lang.reflect.Modifier;
|
||||
*/
|
||||
public class TestableClassDevRoleTranslator extends TreeTranslator {
|
||||
|
||||
private final TreeMaker treeMaker;
|
||||
private final Names names;
|
||||
private final TestableContext cx;
|
||||
|
||||
/**
|
||||
* Methods to inject
|
||||
@@ -42,9 +40,8 @@ public class TestableClassDevRoleTranslator extends TreeTranslator {
|
||||
return fields;
|
||||
}
|
||||
|
||||
public TestableClassDevRoleTranslator(TreeMaker treeMaker, Names names) {
|
||||
this.treeMaker = treeMaker;
|
||||
this.names = names;
|
||||
public TestableClassDevRoleTranslator(TestableContext cx) {
|
||||
this.cx = cx;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -152,12 +149,12 @@ public class TestableClassDevRoleTranslator extends TreeTranslator {
|
||||
}
|
||||
|
||||
private TestableMethodInvocation getStaticNewCall(JCTree.JCNewClass newClassExpr, Name className) {
|
||||
TestableFieldAccess snClass = new TestableFieldAccess(treeMaker.Ident(names.fromString(ConstPool.SN_PKG)),
|
||||
names.fromString(ConstPool.SN_CLS), null);
|
||||
TestableFieldAccess snClass = new TestableFieldAccess(cx.treeMaker.Ident(cx.names.fromString(ConstPool.SN_PKG)),
|
||||
cx.names.fromString(ConstPool.SN_CLS), null);
|
||||
TestableFieldAccess snMethod = new TestableFieldAccess(snClass,
|
||||
names.fromString(ConstPool.SN_METHOD), null);
|
||||
JCTree.JCExpression classType = new TestableFieldAccess(treeMaker.Ident(className),
|
||||
names.fromString("class"), null);
|
||||
cx.names.fromString(ConstPool.SN_METHOD), null);
|
||||
JCTree.JCExpression classType = new TestableFieldAccess(cx.treeMaker.Ident(className),
|
||||
cx.names.fromString("class"), null);
|
||||
ListBuffer<JCTree.JCExpression> args = ListBuffer.of(classType);
|
||||
args.addAll(newClassExpr.args);
|
||||
return new TestableMethodInvocation(null, snMethod, args.toList());
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
package com.alibaba.testable.translator;
|
||||
|
||||
import com.alibaba.testable.model.TestLibType;
|
||||
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.sun.tools.javac.code.Type;
|
||||
import com.sun.tools.javac.tree.JCTree;
|
||||
import com.sun.tools.javac.tree.TreeMaker;
|
||||
import com.sun.tools.javac.tree.TreeTranslator;
|
||||
import com.sun.tools.javac.util.*;
|
||||
|
||||
@@ -22,8 +22,7 @@ public class TestableClassTestRoleTranslator extends TreeTranslator {
|
||||
private static final String ANNOTATION_TESTABLE_INJECT = "com.alibaba.testable.annotation.TestableInject";
|
||||
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 TreeMaker treeMaker;
|
||||
private Names names;
|
||||
private final TestableContext cx;
|
||||
private String sourceClassName;
|
||||
private ListBuffer<Name> sourceClassIns = new ListBuffer();
|
||||
private List<String> stubbornFields = List.nil();
|
||||
@@ -31,10 +30,9 @@ public class TestableClassTestRoleTranslator extends TreeTranslator {
|
||||
private String testSetupMethodName;
|
||||
private TestLibType testLibType = TestLibType.JUnit4;
|
||||
|
||||
public TestableClassTestRoleTranslator(String pkgName, String className, TreeMaker treeMaker, Names names) {
|
||||
public TestableClassTestRoleTranslator(String pkgName, String className, TestableContext cx) {
|
||||
this.sourceClassName = className;
|
||||
this.treeMaker = treeMaker;
|
||||
this.names = names;
|
||||
this.cx = cx;
|
||||
try {
|
||||
stubbornFields = List.from(
|
||||
(String[])Class.forName(pkgName + "." + className + ConstPool.TESTABLE)
|
||||
@@ -105,24 +103,24 @@ public class TestableClassTestRoleTranslator extends TreeTranslator {
|
||||
super.visitClassDef(jcClassDecl);
|
||||
ListBuffer<JCTree> ndefs = new ListBuffer<>();
|
||||
ndefs.addAll(jcClassDecl.defs);
|
||||
JCTree.JCModifiers mods = treeMaker.Modifiers(Modifier.PUBLIC, makeAnnotations());
|
||||
ndefs.add(treeMaker.MethodDef(mods, names.fromString("testableSetup"), treeMaker.Type(new Type.JCVoidType()),
|
||||
List.<JCTree.JCTypeParameter>nil(), List.<JCTree.JCVariableDecl>nil(), List.<JCTree.JCExpression>nil(),
|
||||
testableSetupBlock(), null));
|
||||
JCTree.JCModifiers mods = cx.treeMaker.Modifiers(Modifier.PUBLIC, makeAnnotations());
|
||||
ndefs.add(cx.treeMaker.MethodDef(mods, cx.names.fromString("testableSetup"),
|
||||
cx.treeMaker.Type(new Type.JCVoidType()), List.<JCTree.JCTypeParameter>nil(),
|
||||
List.<JCTree.JCVariableDecl>nil(), List.<JCTree.JCExpression>nil(), testableSetupBlock(), null));
|
||||
jcClassDecl.defs = ndefs.toList();
|
||||
}
|
||||
|
||||
private List<JCTree.JCAnnotation> makeAnnotations() {
|
||||
String[] elems = ANNOTATION_JUNIT5_TEST.split("\\.");
|
||||
JCTree.JCExpression e = treeMaker.Ident(names.fromString(elems[0]));
|
||||
JCTree.JCExpression e = cx.treeMaker.Ident(cx.names.fromString(elems[0]));
|
||||
for (int i = 1 ; i < elems.length ; i++) {
|
||||
e = treeMaker.Select(e, names.fromString(elems[i]));
|
||||
e = cx.treeMaker.Select(e, cx.names.fromString(elems[i]));
|
||||
}
|
||||
return List.of(treeMaker.Annotation(e, List.<JCTree.JCExpression>nil()));
|
||||
return List.of(cx.treeMaker.Annotation(e, List.<JCTree.JCExpression>nil()));
|
||||
}
|
||||
|
||||
private JCTree.JCBlock testableSetupBlock() {
|
||||
return treeMaker.Block(0, List.<JCTree.JCStatement>nil());
|
||||
return cx.treeMaker.Block(0, List.<JCTree.JCStatement>nil());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -154,7 +152,7 @@ public class TestableClassTestRoleTranslator extends TreeTranslator {
|
||||
|
||||
private Name getStubbornSetterMethodName(JCTree.JCAssign assign) {
|
||||
String name = ((JCTree.JCFieldAccess)assign.lhs).name.toString() + ConstPool.TESTABLE_SET_METHOD_PREFIX;
|
||||
return names.fromString(name);
|
||||
return cx.names.fromString(name);
|
||||
}
|
||||
|
||||
private boolean isAssignStubbornField(JCTree.JCAssign expr) {
|
||||
@@ -165,7 +163,7 @@ public class TestableClassTestRoleTranslator extends TreeTranslator {
|
||||
|
||||
private JCTree.JCIdent getTestableClassIdent(JCTree.JCExpression clazz) {
|
||||
Name className = ((JCTree.JCIdent)clazz).name;
|
||||
return treeMaker.Ident(names.fromString(className + ConstPool.TESTABLE));
|
||||
return cx.treeMaker.Ident(cx.names.fromString(className + ConstPool.TESTABLE));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
30
src/main/java/com/alibaba/testable/util/TestableLogger.java
Normal file
30
src/main/java/com/alibaba/testable/util/TestableLogger.java
Normal file
@@ -0,0 +1,30 @@
|
||||
package com.alibaba.testable.util;
|
||||
|
||||
import javax.annotation.processing.Messager;
|
||||
import javax.tools.Diagnostic;
|
||||
|
||||
/**
|
||||
* practical logger
|
||||
*
|
||||
* @author flin
|
||||
*/
|
||||
public class TestableLogger {
|
||||
|
||||
private Messager messager;
|
||||
|
||||
public TestableLogger(Messager messager) {
|
||||
this.messager = messager;
|
||||
}
|
||||
|
||||
public void info(String msg) {
|
||||
System.out.println("[INFO] " + msg);
|
||||
}
|
||||
|
||||
public void warn(String msg) {
|
||||
messager.printMessage(Diagnostic.Kind.MANDATORY_WARNING, msg);
|
||||
}
|
||||
|
||||
public void error(String msg) {
|
||||
messager.printMessage(Diagnostic.Kind.ERROR, msg);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user