mirror of
https://github.com/alibaba/testable-mock.git
synced 2025-01-25 03:40:38 +08:00
handle static member access
This commit is contained in:
parent
6b4467a03b
commit
03253e529d
@ -32,14 +32,14 @@ class DemoPrivateAccessTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
void should_able_to_access_private_static_method() {
|
void should_able_to_access_private_static_method() {
|
||||||
//assertEquals("hello + 1", DemoPrivateAccess.privateStaticFunc("hello", 1));
|
assertEquals("hello + 1", DemoPrivateAccess.privateStaticFunc("hello", 1));
|
||||||
assertEquals("hello + 1", PrivateAccessor.invokeStatic(DemoPrivateAccess.class, "privateStaticFunc", "hello", 1));
|
assertEquals("hello + 1", PrivateAccessor.invokeStatic(DemoPrivateAccess.class, "privateStaticFunc", "hello", 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void should_able_to_access_private_static_field() {
|
void should_able_to_access_private_static_field() {
|
||||||
//DemoPrivateAccess.staticCount = 2;
|
DemoPrivateAccess.staticCount = 2;
|
||||||
//assertEquals(new Integer(2), DemoPrivateAccess.staticCount);
|
assertEquals(new Integer(2), DemoPrivateAccess.staticCount);
|
||||||
|
|
||||||
PrivateAccessor.setStatic(DemoPrivateAccess.class, "staticCount", 3);
|
PrivateAccessor.setStatic(DemoPrivateAccess.class, "staticCount", 3);
|
||||||
assertEquals(new Integer(3), PrivateAccessor.getStatic(DemoPrivateAccess.class, "staticCount"));
|
assertEquals(new Integer(3), PrivateAccessor.getStatic(DemoPrivateAccess.class, "staticCount"));
|
||||||
|
@ -37,4 +37,32 @@ public class PrivateAccessStatementGenerator extends BaseGenerator {
|
|||||||
params.addAll(expr.args);
|
params.addAll(expr.args);
|
||||||
return cx.treeMaker.Apply(List.<JCExpression>nil(), invoker, params.toList());
|
return cx.treeMaker.Apply(List.<JCExpression>nil(), invoker, params.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public JCExpression fetchStaticGetterStatement(JCFieldAccess access) {
|
||||||
|
JCFieldAccess getter = cx.treeMaker.Select(nameToExpression(ConstPool.TESTABLE_PRIVATE_ACCESSOR),
|
||||||
|
cx.names.fromString("getStatic"));
|
||||||
|
JCExpression classField = cx.treeMaker.Select(access.selected, cx.names.fromString("class"));
|
||||||
|
return cx.treeMaker.Apply(List.<JCExpression>nil(), getter, List.of(classField,
|
||||||
|
cx.treeMaker.Literal(access.name.toString())));
|
||||||
|
}
|
||||||
|
|
||||||
|
public JCExpression fetchStaticSetterStatement(JCAssign assign) {
|
||||||
|
JCFieldAccess setter = cx.treeMaker.Select(nameToExpression(ConstPool.TESTABLE_PRIVATE_ACCESSOR),
|
||||||
|
cx.names.fromString("setStatic"));
|
||||||
|
JCExpression selected = ((JCFieldAccess)assign.lhs).selected;
|
||||||
|
JCExpression classField = cx.treeMaker.Select(selected, cx.names.fromString("class"));
|
||||||
|
return cx.treeMaker.Apply(List.<JCExpression>nil(), setter, List.of(classField,
|
||||||
|
cx.treeMaker.Literal(((JCFieldAccess)assign.lhs).name.toString()), assign.rhs));
|
||||||
|
}
|
||||||
|
|
||||||
|
public JCExpression fetchStaticInvokeStatement(JCMethodInvocation expr) {
|
||||||
|
JCFieldAccess invoker = cx.treeMaker.Select(nameToExpression(ConstPool.TESTABLE_PRIVATE_ACCESSOR),
|
||||||
|
cx.names.fromString("invokeStatic"));
|
||||||
|
JCExpression selected = ((JCFieldAccess)expr.meth).selected;
|
||||||
|
JCExpression classField = cx.treeMaker.Select(selected, cx.names.fromString("class"));
|
||||||
|
ListBuffer<JCExpression> params = ListBuffer.of(classField);
|
||||||
|
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,20 @@
|
|||||||
|
package com.alibaba.testable.processor.model;
|
||||||
|
|
||||||
|
public enum MemberType {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Private member or final member
|
||||||
|
*/
|
||||||
|
PRIVATE_OR_FINAL,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Static private member or Static final member
|
||||||
|
*/
|
||||||
|
STATIC_PRIVATE,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* None private member
|
||||||
|
*/
|
||||||
|
NONE_PRIVATE
|
||||||
|
|
||||||
|
}
|
@ -2,6 +2,7 @@ package com.alibaba.testable.processor.translator;
|
|||||||
|
|
||||||
import com.alibaba.testable.processor.constant.ConstPool;
|
import com.alibaba.testable.processor.constant.ConstPool;
|
||||||
import com.alibaba.testable.processor.generator.PrivateAccessStatementGenerator;
|
import com.alibaba.testable.processor.generator.PrivateAccessStatementGenerator;
|
||||||
|
import com.alibaba.testable.processor.model.MemberType;
|
||||||
import com.alibaba.testable.processor.model.TestableContext;
|
import com.alibaba.testable.processor.model.TestableContext;
|
||||||
import com.sun.tools.javac.tree.JCTree.*;
|
import com.sun.tools.javac.tree.JCTree.*;
|
||||||
import com.sun.tools.javac.util.ListBuffer;
|
import com.sun.tools.javac.util.ListBuffer;
|
||||||
@ -23,7 +24,7 @@ public class EnablePrivateAccessTranslator extends BaseTranslator {
|
|||||||
/**
|
/**
|
||||||
* Name of source class
|
* Name of source class
|
||||||
*/
|
*/
|
||||||
private final String sourceClassName;
|
private final Name sourceClassName;
|
||||||
/**
|
/**
|
||||||
* Fields of source class instance in the test class
|
* Fields of source class instance in the test class
|
||||||
*/
|
*/
|
||||||
@ -40,11 +41,12 @@ public class EnablePrivateAccessTranslator extends BaseTranslator {
|
|||||||
private final PrivateAccessStatementGenerator privateAccessStatementGenerator;
|
private final PrivateAccessStatementGenerator privateAccessStatementGenerator;
|
||||||
|
|
||||||
public EnablePrivateAccessTranslator(String pkgName, String testClassName, TestableContext cx) {
|
public EnablePrivateAccessTranslator(String pkgName, String testClassName, TestableContext cx) {
|
||||||
this.sourceClassName = testClassName.substring(0, testClassName.length() - ConstPool.TEST_POSTFIX.length());
|
String sourceClass = testClassName.substring(0, testClassName.length() - ConstPool.TEST_POSTFIX.length());
|
||||||
this.privateAccessStatementGenerator = new PrivateAccessStatementGenerator(cx);
|
this.privateAccessStatementGenerator = new PrivateAccessStatementGenerator(cx);
|
||||||
|
this.sourceClassName = cx.names.fromString(sourceClass);
|
||||||
try {
|
try {
|
||||||
Class<?> cls = null;
|
Class<?> cls = null;
|
||||||
String sourceClassFullName = pkgName + "." + sourceClassName;
|
String sourceClassFullName = pkgName + "." + sourceClass;
|
||||||
try {
|
try {
|
||||||
cls = Class.forName(sourceClassFullName);
|
cls = Class.forName(sourceClassFullName);
|
||||||
} catch (ClassNotFoundException e) {
|
} catch (ClassNotFoundException e) {
|
||||||
@ -77,7 +79,7 @@ public class EnablePrivateAccessTranslator extends BaseTranslator {
|
|||||||
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.equals(sourceClassName)) {
|
||||||
sourceClassIns.add(jcVariableDecl.name);
|
sourceClassIns.add(jcVariableDecl.name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -89,10 +91,15 @@ public class EnablePrivateAccessTranslator extends BaseTranslator {
|
|||||||
@Override
|
@Override
|
||||||
public void visitExec(JCExpressionStatement jcExpressionStatement) {
|
public void visitExec(JCExpressionStatement jcExpressionStatement) {
|
||||||
// visitExec could be an assign statement to a private field
|
// visitExec could be an assign statement to a private field
|
||||||
if (jcExpressionStatement.expr.getClass().equals(JCAssign.class) &&
|
if (jcExpressionStatement.expr.getClass().equals(JCAssign.class)) {
|
||||||
isPrivateField((JCAssign)jcExpressionStatement.expr)) {
|
MemberType memberType = checkSetterType((JCAssign)jcExpressionStatement.expr);
|
||||||
jcExpressionStatement.expr = privateAccessStatementGenerator.fetchSetterStatement(
|
if (memberType.equals(MemberType.PRIVATE_OR_FINAL)) {
|
||||||
(JCAssign)jcExpressionStatement.expr);
|
jcExpressionStatement.expr = privateAccessStatementGenerator.fetchSetterStatement(
|
||||||
|
(JCAssign)jcExpressionStatement.expr);
|
||||||
|
} else if (memberType.equals(MemberType.STATIC_PRIVATE)) {
|
||||||
|
jcExpressionStatement.expr = privateAccessStatementGenerator.fetchStaticSetterStatement(
|
||||||
|
(JCAssign)jcExpressionStatement.expr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// visitExec could be an invoke
|
// visitExec could be an invoke
|
||||||
jcExpressionStatement.expr = checkAndExchange(jcExpressionStatement.expr);
|
jcExpressionStatement.expr = checkAndExchange(jcExpressionStatement.expr);
|
||||||
@ -129,36 +136,59 @@ public class EnablePrivateAccessTranslator extends BaseTranslator {
|
|||||||
@Override
|
@Override
|
||||||
protected JCExpression checkAndExchange(JCExpression expr) {
|
protected JCExpression checkAndExchange(JCExpression expr) {
|
||||||
// check is accessing a private field of source class
|
// check is accessing a private field of source class
|
||||||
if (expr.getClass().equals(JCFieldAccess.class) &&
|
if (expr.getClass().equals(JCFieldAccess.class)) {
|
||||||
isPrivateField((JCFieldAccess)expr)) {
|
MemberType memberType = checkGetterType((JCFieldAccess)expr);
|
||||||
expr = privateAccessStatementGenerator.fetchGetterStatement((JCFieldAccess)expr);
|
if (memberType.equals(MemberType.PRIVATE_OR_FINAL)) {
|
||||||
|
expr = privateAccessStatementGenerator.fetchGetterStatement((JCFieldAccess)expr);
|
||||||
|
} else if (memberType.equals(MemberType.STATIC_PRIVATE)) {
|
||||||
|
expr = privateAccessStatementGenerator.fetchStaticGetterStatement((JCFieldAccess)expr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// check is invoking a private method of source class
|
// check is invoking a private method of source class
|
||||||
if (expr.getClass().equals(JCMethodInvocation.class) &&
|
if (expr.getClass().equals(JCMethodInvocation.class)) {
|
||||||
isPrivateMethod((JCMethodInvocation)expr)) {
|
MemberType memberType = checkInvokeType((JCMethodInvocation)expr);
|
||||||
expr = privateAccessStatementGenerator.fetchInvokeStatement((JCMethodInvocation)expr);
|
if (memberType.equals(MemberType.PRIVATE_OR_FINAL)) {
|
||||||
|
expr = privateAccessStatementGenerator.fetchInvokeStatement((JCMethodInvocation)expr);
|
||||||
|
} else if (memberType.equals(MemberType.STATIC_PRIVATE)) {
|
||||||
|
expr = privateAccessStatementGenerator.fetchStaticInvokeStatement((JCMethodInvocation)expr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return expr;
|
return expr;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isPrivateField(JCFieldAccess access) {
|
private MemberType checkGetterType(JCFieldAccess access) {
|
||||||
return access.selected.getClass().equals(JCIdent.class) &&
|
if (access.selected.getClass().equals(JCIdent.class) &&
|
||||||
sourceClassIns.contains(((JCIdent)access.selected).name) &&
|
privateOrFinalFields.contains(access.name.toString())) {
|
||||||
privateOrFinalFields.contains(access.name.toString());
|
return checkSourceClassOrIns(((JCIdent)access.selected).name);
|
||||||
|
}
|
||||||
|
return MemberType.NONE_PRIVATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isPrivateField(JCAssign assign) {
|
private MemberType checkSetterType(JCAssign assign) {
|
||||||
return assign.lhs.getClass().equals(JCFieldAccess.class) &&
|
if (assign.lhs.getClass().equals(JCFieldAccess.class) &&
|
||||||
((JCFieldAccess)(assign).lhs).selected.getClass().equals(JCIdent.class) &&
|
((JCFieldAccess)(assign).lhs).selected.getClass().equals(JCIdent.class) &&
|
||||||
sourceClassIns.contains(((JCIdent)((JCFieldAccess)(assign).lhs).selected).name) &&
|
privateOrFinalFields.contains(((JCFieldAccess)(assign).lhs).name.toString())) {
|
||||||
privateOrFinalFields.contains(((JCFieldAccess)(assign).lhs).name.toString());
|
return checkSourceClassOrIns(((JCIdent)((JCFieldAccess)(assign).lhs).selected).name);
|
||||||
|
}
|
||||||
|
return MemberType.NONE_PRIVATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isPrivateMethod(JCMethodInvocation expr) {
|
private MemberType checkInvokeType(JCMethodInvocation expr) {
|
||||||
return expr.meth.getClass().equals(JCFieldAccess.class) &&
|
if (expr.meth.getClass().equals(JCFieldAccess.class) &&
|
||||||
((JCFieldAccess)(expr).meth).selected.getClass().equals(JCIdent.class) &&
|
((JCFieldAccess)(expr).meth).selected.getClass().equals(JCIdent.class) &&
|
||||||
sourceClassIns.contains(((JCIdent)((JCFieldAccess)(expr).meth).selected).name) &&
|
privateMethods.contains(((JCFieldAccess)(expr).meth).name.toString())) {
|
||||||
privateMethods.contains(((JCFieldAccess)(expr).meth).name.toString());
|
return checkSourceClassOrIns(((JCIdent)((JCFieldAccess)(expr).meth).selected).name);
|
||||||
|
}
|
||||||
|
return MemberType.NONE_PRIVATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
private MemberType checkSourceClassOrIns(Name name) {
|
||||||
|
if (sourceClassName.equals(name)) {
|
||||||
|
return MemberType.STATIC_PRIVATE;
|
||||||
|
} else if (sourceClassIns.contains(name)) {
|
||||||
|
return MemberType.PRIVATE_OR_FINAL;
|
||||||
|
}
|
||||||
|
return MemberType.NONE_PRIVATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user