diff --git a/src/main/java/com/alibaba/testable/accessor/PrivateAccessor.java b/src/main/java/com/alibaba/testable/accessor/PrivateAccessor.java new file mode 100644 index 0000000..2f6506e --- /dev/null +++ b/src/main/java/com/alibaba/testable/accessor/PrivateAccessor.java @@ -0,0 +1,47 @@ +package com.alibaba.testable.accessor; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; + +/** + * @author flin + */ +public class PrivateAccessor { + + public static T get(Object ref, String field) { + try { + Field declaredField = ref.getClass().getDeclaredField(field); + declaredField.setAccessible(true); + return (T)declaredField.get(ref); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + public static void set(Object ref, String field, T value) { + try { + Field declaredField = ref.getClass().getDeclaredField(field); + declaredField.setAccessible(true); + declaredField.set(ref, value); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public static T invoke(Object ref, String method, Object... args) { + try { + Class[] cls = new Class[args.length]; + for (int i = 0; i < args.length; i++) { + cls[i] = args[i].getClass(); + } + Method declaredMethod = ref.getClass().getDeclaredMethod(method, cls); + declaredMethod.setAccessible(true); + return (T)declaredMethod.invoke(ref, args); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + +} diff --git a/src/main/java/com/alibaba/testable/generator/BaseGenerator.java b/src/main/java/com/alibaba/testable/generator/BaseGenerator.java new file mode 100644 index 0000000..0c92595 --- /dev/null +++ b/src/main/java/com/alibaba/testable/generator/BaseGenerator.java @@ -0,0 +1,26 @@ +package com.alibaba.testable.generator; + +import com.alibaba.testable.model.TestableContext; +import com.sun.tools.javac.tree.JCTree.*; + +/** + * @author flin + */ +public abstract class BaseGenerator { + + protected final TestableContext cx; + + protected BaseGenerator(TestableContext cx) { + this.cx = cx; + } + + protected JCExpression nameToExpression(String dotName) { + String[] nameParts = dotName.split("\\."); + JCExpression e = cx.treeMaker.Ident(cx.names.fromString(nameParts[0])); + for (int i = 1; i < nameParts.length; i++) { + e = cx.treeMaker.Select(e, cx.names.fromString(nameParts[i])); + } + return e; + } + +} diff --git a/src/main/java/com/alibaba/testable/generator/PrivateAccessStatementGenerator.java b/src/main/java/com/alibaba/testable/generator/PrivateAccessStatementGenerator.java new file mode 100644 index 0000000..1acd098 --- /dev/null +++ b/src/main/java/com/alibaba/testable/generator/PrivateAccessStatementGenerator.java @@ -0,0 +1,24 @@ +package com.alibaba.testable.generator; + +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; + +/** + * @author flin + */ +public class PrivateAccessStatementGenerator extends BaseGenerator { + + public PrivateAccessStatementGenerator(TestableContext cx) { + super(cx); + } + + public JCExpression fetchSetterStatement(JCExpressionStatement jcExpressionStatement) { + JCAssign assign = (JCAssign)jcExpressionStatement.expr; + JCFieldAccess setter = cx.treeMaker.Select(nameToExpression(ConstPool.TESTABLE_PRIVATE_ACCESSOR), + cx.names.fromString("set")); + return cx.treeMaker.Apply(List.nil(), setter, List.of(((JCFieldAccess)assign.lhs).selected, + cx.treeMaker.Literal(((JCFieldAccess)assign.lhs).name.toString()), assign.rhs)); + } +} diff --git a/src/main/java/com/alibaba/testable/generator/StaticNewClassGenerator.java b/src/main/java/com/alibaba/testable/generator/StaticNewClassGenerator.java index acb76aa..16da51a 100644 --- a/src/main/java/com/alibaba/testable/generator/StaticNewClassGenerator.java +++ b/src/main/java/com/alibaba/testable/generator/StaticNewClassGenerator.java @@ -11,12 +11,10 @@ import java.nio.file.Files; * * @author flin */ -public class StaticNewClassGenerator { - - private final TestableContext cx; +public class StaticNewClassGenerator extends BaseGenerator { public StaticNewClassGenerator(TestableContext cx) { - this.cx = cx; + super(cx); } public String fetch() { diff --git a/src/main/java/com/alibaba/testable/generator/TestSetupMethodGenerator.java b/src/main/java/com/alibaba/testable/generator/TestSetupMethodGenerator.java index d3f6560..dc14249 100644 --- a/src/main/java/com/alibaba/testable/generator/TestSetupMethodGenerator.java +++ b/src/main/java/com/alibaba/testable/generator/TestSetupMethodGenerator.java @@ -18,10 +18,9 @@ import java.lang.reflect.Modifier; * * @author flin */ -public class TestSetupMethodGenerator { +public class TestSetupMethodGenerator extends BaseGenerator { private static final String TYPE_CLASS = "Class"; - private final TestableContext cx; /** * MethodName -> (ResultType -> ParameterTypes) @@ -32,7 +31,7 @@ public class TestSetupMethodGenerator { public final ListBuffer memberMethods = new ListBuffer<>(); public TestSetupMethodGenerator(TestableContext cx) { - this.cx = cx; + super(cx); } public JCMethodDecl fetch() { @@ -63,14 +62,6 @@ public class TestSetupMethodGenerator { return cx.treeMaker.Block(0, statements.toList()); } - private JCExpression nameToExpression(String dotName) { - String[] nameParts = dotName.split("\\."); - JCExpression e = cx.treeMaker.Ident(cx.names.fromString(nameParts[0])); - for (int i = 1; i < nameParts.length; i++) { - e = cx.treeMaker.Select(e, cx.names.fromString(nameParts[i])); - } - return e; - } private boolean isMemberMethod(Pair>> m) { for (Method method : memberMethods) { diff --git a/src/main/java/com/alibaba/testable/generator/TestableClassGenerator.java b/src/main/java/com/alibaba/testable/generator/TestableClassGenerator.java index 772a092..77330c1 100644 --- a/src/main/java/com/alibaba/testable/generator/TestableClassGenerator.java +++ b/src/main/java/com/alibaba/testable/generator/TestableClassGenerator.java @@ -9,10 +9,13 @@ import com.squareup.javapoet.*; 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.JCTree.JCExpression; +import com.sun.tools.javac.tree.JCTree.JCMethodDecl; +import com.sun.tools.javac.tree.JCTree.JCModifiers; +import com.sun.tools.javac.tree.JCTree.JCVariableDecl; import javax.lang.model.element.Element; import javax.lang.model.element.Modifier; -import java.lang.reflect.Field; import java.util.ArrayList; import java.util.HashSet; import java.util.List; @@ -37,7 +40,7 @@ public class TestableClassGenerator { tree.accept(translator); List methodSpecs = new ArrayList<>(); - for (JCTree.JCMethodDecl method : translator.getMethods()) { + for (JCMethodDecl method : translator.getMethods()) { if (isNoncallableMethod(method)) { continue; } @@ -47,10 +50,6 @@ public class TestableClassGenerator { methodSpecs.add(buildMemberMethod(clazz, method)); } } - for (JCTree.JCVariableDecl field : translator.getFields()) { - methodSpecs.add(buildFieldGetter(clazz, field)); - methodSpecs.add(buildFieldSetter(clazz, field)); - } TypeSpec.Builder builder = TypeSpec.classBuilder(className) .addModifiers(Modifier.PUBLIC, Modifier.FINAL) @@ -63,50 +62,18 @@ public class TestableClassGenerator { return javaFile.toString(); } - private MethodSpec buildFieldGetter(Symbol.ClassSymbol classElement, JCTree.JCVariableDecl field) { - String fieldName = field.name.toString(); - return MethodSpec.methodBuilder(fieldName + ConstPool.TESTABLE_GET_METHOD_PREFIX) - .addModifiers(Modifier.PUBLIC) - .returns(TypeName.get(field.vartype.type)) - .beginControlFlow("try") - .addStatement("$T field = $T.class.getDeclaredField(\"$N\")", Field.class, classElement.type, fieldName) - .addStatement("field.setAccessible(true)") - .addStatement("return ($T)field.get(this)", field.vartype.type) - .nextControlFlow("catch ($T e)", Exception.class) - .addStatement("e.printStackTrace()") - .addStatement("return null") - .endControlFlow() - .build(); - } - - private MethodSpec buildFieldSetter(Symbol.ClassSymbol classElement, JCTree.JCVariableDecl field) { - String fieldName = field.name.toString(); - return MethodSpec.methodBuilder(fieldName + ConstPool.TESTABLE_SET_METHOD_PREFIX) - .addModifiers(Modifier.PUBLIC) - .addParameter(getParameterSpec(field)) - .returns(TypeName.VOID) - .beginControlFlow("try") - .addStatement("$T field = $T.class.getDeclaredField(\"$N\")", Field.class, classElement.type, fieldName) - .addStatement("field.setAccessible(true)") - .addStatement("field.set(this, $N)", fieldName) - .nextControlFlow("catch ($T e)", Exception.class) - .addStatement("e.printStackTrace()") - .endControlFlow() - .build(); - } - - private MethodSpec buildMemberMethod(Element classElement, JCTree.JCMethodDecl method) { + private MethodSpec buildMemberMethod(Element classElement, JCMethodDecl method) { MethodSpec.Builder builder = MethodSpec.methodBuilder(method.name.toString()) .addModifiers(toPublicFlags(method.getModifiers())) .returns(TypeName.get(((Type.MethodType)method.sym.type).restype)); - for (JCTree.JCVariableDecl p : method.getParameters()) { + for (JCVariableDecl p : method.getParameters()) { builder.addParameter(getParameterSpec(p)); } if (method.getModifiers().getFlags().contains(Modifier.PRIVATE)) { builder.addException(Exception.class); } else { builder.addAnnotation(Override.class); - for (JCTree.JCExpression exception : method.getThrows()) { + for (JCExpression exception : method.getThrows()) { builder.addException(TypeName.get(exception.type)); } } @@ -114,16 +81,16 @@ public class TestableClassGenerator { return builder.build(); } - private MethodSpec buildConstructorMethod(Element classElement, JCTree.JCMethodDecl method) { + private MethodSpec buildConstructorMethod(Element classElement, JCMethodDecl method) { MethodSpec.Builder builder = MethodSpec.constructorBuilder().addModifiers(Modifier.PUBLIC); - for (JCTree.JCVariableDecl p : method.getParameters()) { + for (JCVariableDecl p : method.getParameters()) { builder.addParameter(getParameterSpec(p)); } addCallSuperStatements(builder, classElement, method); return builder.build(); } - private void addCallSuperStatements(MethodSpec.Builder builder, Element classElement, JCTree.JCMethodDecl method) { + private void addCallSuperStatements(MethodSpec.Builder builder, Element classElement, JCMethodDecl method) { String className = classElement.getSimpleName().toString(); Statement[] statements = new CallSuperMethodStatementGenerator().fetch(className, method); for (Statement s : statements) { @@ -131,15 +98,15 @@ public class TestableClassGenerator { } } - private boolean isConstructorMethod(JCTree.JCMethodDecl method) { + private boolean isConstructorMethod(JCMethodDecl method) { return method.name.toString().equals(ConstPool.CONSTRUCTOR_NAME); } - private boolean isNoncallableMethod(JCTree.JCMethodDecl method) { + private boolean isNoncallableMethod(JCMethodDecl method) { return method.getModifiers().getFlags().contains(Modifier.ABSTRACT); } - private Set toPublicFlags(JCTree.JCModifiers modifiers) { + private Set toPublicFlags(JCModifiers modifiers) { Set flags = new HashSet<>(modifiers.getFlags()); flags.remove(Modifier.PRIVATE); flags.remove(Modifier.PROTECTED); @@ -147,7 +114,7 @@ public class TestableClassGenerator { return flags; } - private ParameterSpec getParameterSpec(JCTree.JCVariableDecl type) { + private ParameterSpec getParameterSpec(JCVariableDecl type) { return ParameterSpec.builder(TypeName.get(type.sym.type), type.name.toString()).build(); } diff --git a/src/main/java/com/alibaba/testable/generator/statement/CallSuperMethodStatementGenerator.java b/src/main/java/com/alibaba/testable/generator/statement/CallSuperMethodStatementGenerator.java index a9d7802..5eba964 100644 --- a/src/main/java/com/alibaba/testable/generator/statement/CallSuperMethodStatementGenerator.java +++ b/src/main/java/com/alibaba/testable/generator/statement/CallSuperMethodStatementGenerator.java @@ -3,7 +3,7 @@ package com.alibaba.testable.generator.statement; import com.alibaba.testable.generator.model.Statement; import com.alibaba.testable.util.ConstPool; import com.alibaba.testable.util.StringUtil; -import com.sun.tools.javac.tree.JCTree; +import com.sun.tools.javac.tree.JCTree.*; import java.lang.reflect.Method; import javax.lang.model.element.Modifier; import java.util.ArrayList; @@ -16,7 +16,7 @@ import java.util.List; */ public class CallSuperMethodStatementGenerator { - public Statement[] fetch(String className, JCTree.JCMethodDecl method) { + public Statement[] fetch(String className, JCMethodDecl method) { if (method.getModifiers().getFlags().contains(Modifier.PRIVATE)) { return reflectCall(className, method); } else { @@ -24,11 +24,11 @@ public class CallSuperMethodStatementGenerator { } } - private Statement[] commonCall(JCTree.JCMethodDecl method) { + private Statement[] commonCall(JCMethodDecl method) { List args = new ArrayList<>(); StringBuilder code = new StringBuilder(); List placeholders = new ArrayList<>(); - for (JCTree.JCVariableDecl p : method.params) { + for (JCVariableDecl p : method.params) { args.add(p.name.toString()); placeholders.add("$N"); } @@ -40,7 +40,7 @@ public class CallSuperMethodStatementGenerator { return new Statement[] { returnStatement(method, new Statement(code.toString(), args.toArray())) }; } - private Statement[] reflectCall(String className, JCTree.JCMethodDecl method) { + private Statement[] reflectCall(String className, JCMethodDecl method) { List statements = new ArrayList<>(); statements.add(getMethodStatement(className, method)); statements.add(setAccessibleStatement()); @@ -48,20 +48,20 @@ public class CallSuperMethodStatementGenerator { return statements.toArray(new Statement[0]); } - private Statement returnStatement(JCTree.JCMethodDecl method, Statement statement) { + private Statement returnStatement(JCMethodDecl method, Statement statement) { if (method.restype != null && !method.restype.toString().equals(ConstPool.TYPE_VOID)) { statement.setLine("return " + statement.getLine()); } return statement; } - private Statement getMethodStatement(String className, JCTree.JCMethodDecl method) { + private Statement getMethodStatement(String className, JCMethodDecl method) { List args = new ArrayList<>(); StringBuilder code = new StringBuilder(); code.append("$T m = "); args.add(Method.class); code.append(className).append(".class.getDeclaredMethod(\"").append(method.name).append("\""); - for (JCTree.JCVariableDecl p : method.params) { + for (JCVariableDecl p : method.params) { code.append(", $T.class"); args.add(p.sym.type); } @@ -73,13 +73,13 @@ public class CallSuperMethodStatementGenerator { return new Statement("m.setAccessible(true)", new Object[0]); } - private Statement invokeStatement(JCTree.JCMethodDecl method) { + private Statement invokeStatement(JCMethodDecl method) { StringBuilder code = new StringBuilder(); if (!method.restype.toString().equals(ConstPool.TYPE_VOID)) { code.append("(").append(method.restype).append(")"); } code.append("m.invoke(this"); - for (JCTree.JCVariableDecl p : method.params) { + for (JCVariableDecl p : method.params) { code.append(", ").append(p.name); } code.append(")"); diff --git a/src/main/java/com/alibaba/testable/translator/EnableTestableInjectTranslator.java b/src/main/java/com/alibaba/testable/translator/EnableTestableInjectTranslator.java index 9a8c753..c17039f 100644 --- a/src/main/java/com/alibaba/testable/translator/EnableTestableInjectTranslator.java +++ b/src/main/java/com/alibaba/testable/translator/EnableTestableInjectTranslator.java @@ -2,8 +2,7 @@ package com.alibaba.testable.translator; 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.JCMethodDecl; +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; @@ -26,13 +25,13 @@ public class EnableTestableInjectTranslator extends TreeTranslator { /** * Fields to wrap */ - private List fields = List.nil(); + private List fields = List.nil(); public List getMethods() { return methods; } - public List getFields() { + public List getFields() { return fields; } @@ -54,7 +53,7 @@ public class EnableTestableInjectTranslator extends TreeTranslator { * Case: member() */ @Override - public void visitExec(JCTree.JCExpressionStatement jcExpressionStatement) { + public void visitExec(JCExpressionStatement jcExpressionStatement) { jcExpressionStatement.expr = checkAndExchange(jcExpressionStatement.expr); super.visitExec(jcExpressionStatement); } @@ -64,7 +63,7 @@ public class EnableTestableInjectTranslator extends TreeTranslator { * Case: call(new Demo()) */ @Override - public void visitApply(JCTree.JCMethodInvocation tree) { + public void visitApply(JCMethodInvocation tree) { tree.args = checkAndExchange(tree.args); super.visitApply(tree); } @@ -74,7 +73,7 @@ public class EnableTestableInjectTranslator extends TreeTranslator { * Case: return member() */ @Override - public void visitReturn(JCTree.JCReturn jcReturn) { + public void visitReturn(JCReturn jcReturn) { jcReturn.expr = checkAndExchange(jcReturn.expr); super.visitReturn(jcReturn); } @@ -85,7 +84,7 @@ public class EnableTestableInjectTranslator extends TreeTranslator { * Case: Demo d = member() */ @Override - public void visitVarDef(JCTree.JCVariableDecl jcVariableDecl) { + public void visitVarDef(JCVariableDecl jcVariableDecl) { if (isStubbornField(jcVariableDecl.mods)) { fields = fields.append(jcVariableDecl); } @@ -98,7 +97,7 @@ public class EnableTestableInjectTranslator extends TreeTranslator { * Case: member().call() */ @Override - public void visitSelect(JCTree.JCFieldAccess jcFieldAccess) { + public void visitSelect(JCFieldAccess jcFieldAccess) { jcFieldAccess.selected = checkAndExchange(jcFieldAccess.selected); super.visitSelect(jcFieldAccess); } @@ -107,7 +106,7 @@ public class EnableTestableInjectTranslator extends TreeTranslator { * For new operation break point */ @Override - public void visitNewClass(JCTree.JCNewClass jcNewClass) { + public void visitNewClass(JCNewClass jcNewClass) { super.visitNewClass(jcNewClass); } @@ -115,18 +114,18 @@ public class EnableTestableInjectTranslator extends TreeTranslator { * For new operation break point */ @Override - public void visitNewArray(JCTree.JCNewArray jcNewArray) { + public void visitNewArray(JCNewArray jcNewArray) { super.visitNewArray(jcNewArray); } - private boolean isStubbornField(JCTree.JCModifiers mods) { + private boolean isStubbornField(JCModifiers mods) { return mods.getFlags().contains(javax.lang.model.element.Modifier.PRIVATE) || mods.getFlags().contains(javax.lang.model.element.Modifier.FINAL); } - private List checkAndExchange(List args) { + private List checkAndExchange(List args) { if (args != null) { - JCTree.JCExpression[] es = new JCTree.JCExpression[args.length()]; + JCExpression[] es = new JCExpression[args.length()]; for (int i = 0; i < args.length(); i++) { es[i] = checkAndExchange(args.get(i)); } @@ -135,51 +134,51 @@ public class EnableTestableInjectTranslator extends TreeTranslator { return null; } - private JCTree.JCExpression checkAndExchange(JCTree.JCExpression expr) { + private JCExpression checkAndExchange(JCExpression expr) { if (isNewOperation(expr)) { - JCTree.JCNewClass newClassExpr = (JCTree.JCNewClass)expr; - Name className = ((JCTree.JCIdent)newClassExpr.clazz).name; + JCNewClass newClassExpr = (JCNewClass)expr; + Name className = ((JCIdent)newClassExpr.clazz).name; try { return getGlobalNewInvocation(newClassExpr, className); } catch (Exception e) { e.printStackTrace(); } } else if (isMemberMethodInvocation(expr)) { - Name methodName = ((JCTree.JCIdent)((JCTree.JCMethodInvocation)expr).meth).name; - List args = ((JCTree.JCMethodInvocation)expr).args; + Name methodName = ((JCIdent)((JCMethodInvocation)expr).meth).name; + List args = ((JCMethodInvocation)expr).args; return getGlobalMemberInvocation(methodName, args); } 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 isMemberMethodInvocation(JCExpression expr) { + return expr != null && expr.getClass().equals(JCMethodInvocation.class) && + ((JCMethodInvocation)expr).meth.getClass().equals(JCIdent.class); } - private boolean isNewOperation(JCTree.JCExpression expr) { - return expr != null && expr.getClass().equals(JCTree.JCNewClass.class); + private boolean isNewOperation(JCExpression expr) { + return expr != null && expr.getClass().equals(JCNewClass.class); } - private JCTree.JCMethodInvocation getGlobalNewInvocation(JCTree.JCNewClass newClassExpr, Name className) { - JCTree.JCFieldAccess snClass = cx.treeMaker.Select(cx.treeMaker.Ident(cx.names.fromString(ConstPool.NE_PKG)), + private JCMethodInvocation getGlobalNewInvocation(JCNewClass newClassExpr, Name className) { + 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_NEW)); - JCTree.JCExpression classType = cx.treeMaker.Select(cx.treeMaker.Ident(className), + JCFieldAccess snMethod = cx.treeMaker.Select(snClass, cx.names.fromString(ConstPool.NE_NEW)); + JCExpression classType = cx.treeMaker.Select(cx.treeMaker.Ident(className), cx.names.fromString(ConstPool.TYPE_TO_CLASS)); - ListBuffer args = ListBuffer.of(classType); + ListBuffer args = ListBuffer.of(classType); args.addAll(newClassExpr.args); - return cx.treeMaker.Apply(List.nil(), snMethod, args.toList()); + return cx.treeMaker.Apply(List.nil(), snMethod, args.toList()); } - private JCTree.JCMethodInvocation getGlobalMemberInvocation(Name methodName, List param) { - JCTree.JCFieldAccess snClass = cx.treeMaker.Select(cx.treeMaker.Ident(cx.names.fromString(ConstPool.NE_PKG)), + private JCMethodInvocation getGlobalMemberInvocation(Name methodName, List param) { + 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_FUN)); - ListBuffer args = new ListBuffer(); + JCFieldAccess snMethod = cx.treeMaker.Select(snClass, cx.names.fromString(ConstPool.NE_FUN)); + ListBuffer 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.nil(), snMethod, args.toList()); + return cx.treeMaker.Apply(List.nil(), snMethod, args.toList()); } } diff --git a/src/main/java/com/alibaba/testable/translator/EnableTestableTranslator.java b/src/main/java/com/alibaba/testable/translator/EnableTestableTranslator.java index 30a3dec..f866f59 100644 --- a/src/main/java/com/alibaba/testable/translator/EnableTestableTranslator.java +++ b/src/main/java/com/alibaba/testable/translator/EnableTestableTranslator.java @@ -1,13 +1,17 @@ package com.alibaba.testable.translator; +import com.alibaba.testable.generator.PrivateAccessStatementGenerator; import com.alibaba.testable.generator.TestSetupMethodGenerator; import com.alibaba.testable.model.TestLibType; 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.TreeTranslator; -import com.sun.tools.javac.util.*; 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.Modifier; @@ -25,11 +29,13 @@ public class EnableTestableTranslator extends TreeTranslator { private final ListBuffer sourceClassIns = new ListBuffer<>(); private final ListBuffer stubbornFields = new ListBuffer<>(); private final TestSetupMethodGenerator testSetupMethodGenerator; + private final PrivateAccessStatementGenerator privateAccessStatementGenerator; public EnableTestableTranslator(String pkgName, String className, TestableContext cx) { this.sourceClassName = className; this.cx = cx; this.testSetupMethodGenerator = new TestSetupMethodGenerator(cx); + this.privateAccessStatementGenerator = new PrivateAccessStatementGenerator(cx); try { Class cls = Class.forName(pkgName + "." + className); Field[] fields = cls.getDeclaredFields(); @@ -69,17 +75,13 @@ public class EnableTestableTranslator extends TreeTranslator { } /** - * d.privateField = val -> d.privateFieldTestableSet(val) + * d.privateField = val -> PrivateAccessor.set(d, "privateField", val) */ @Override public void visitExec(JCExpressionStatement jcExpressionStatement) { if (jcExpressionStatement.expr.getClass().equals(JCAssign.class) && isAssignStubbornField((JCAssign)jcExpressionStatement.expr)) { - JCAssign assign = (JCAssign)jcExpressionStatement.expr; - JCFieldAccess stubbornSetter = cx.treeMaker.Select(((JCFieldAccess)assign.lhs).selected, - getStubbornSetterMethodName(assign)); - jcExpressionStatement.expr = cx.treeMaker.Apply(List.nil(), stubbornSetter, - com.sun.tools.javac.util.List.of(assign.rhs)); + jcExpressionStatement.expr = privateAccessStatementGenerator.fetchSetterStatement(jcExpressionStatement); } super.visitExec(jcExpressionStatement); } @@ -162,11 +164,6 @@ public class EnableTestableTranslator extends TreeTranslator { return nb.toList(); } - private Name getStubbornSetterMethodName(JCAssign assign) { - String name = ((JCFieldAccess)assign.lhs).name.toString() + ConstPool.TESTABLE_SET_METHOD_PREFIX; - return cx.names.fromString(name); - } - private boolean isAssignStubbornField(JCAssign expr) { return expr.lhs.getClass().equals(JCFieldAccess.class) && sourceClassIns.contains(((JCIdent)((JCFieldAccess)(expr).lhs).selected).name) && diff --git a/src/main/java/com/alibaba/testable/util/ConstPool.java b/src/main/java/com/alibaba/testable/util/ConstPool.java index e1a26dc..cd06a90 100644 --- a/src/main/java/com/alibaba/testable/util/ConstPool.java +++ b/src/main/java/com/alibaba/testable/util/ConstPool.java @@ -16,10 +16,9 @@ public final class ConstPool { public static final String NE_POOL = "n.e.p"; public static final String NE_ADD_W = "n.e.aw"; public static final String NE_ADD_F = "n.e.af"; - public static final String TESTABLE_GET_METHOD_PREFIX = "TestableGet"; - public static final String TESTABLE_SET_METHOD_PREFIX = "TestableSet"; public static final String TYPE_TO_CLASS = "class"; public static final String REF_THIS = "this"; + public static final String TESTABLE_PRIVATE_ACCESSOR = "com.alibaba.testable.accessor.PrivateAccessor"; public static final String ANNOTATION_TESTABLE_INJECT = "com.alibaba.testable.annotation.TestableInject"; public static final String ANNOTATION_JUNIT5_SETUP = "org.junit.jupiter.api.BeforeEach"; public static final String ANNOTATION_JUNIT5_TEST = "org.junit.jupiter.api.Test";