diff --git a/testable-agent/src/main/java/com/alibaba/testable/agent/constant/ConstPool.java b/testable-agent/src/main/java/com/alibaba/testable/agent/constant/ConstPool.java index 1587073..2096cff 100644 --- a/testable-agent/src/main/java/com/alibaba/testable/agent/constant/ConstPool.java +++ b/testable-agent/src/main/java/com/alibaba/testable/agent/constant/ConstPool.java @@ -17,6 +17,7 @@ public class ConstPool { public static final String FIELD_TARGET_CLASS = "targetClass"; public static final String MOCK_WITH = "com.alibaba.testable.core.annotation.MockWith"; + public static final String MOCK_DIAGNOSE = "com.alibaba.testable.core.annotation.MockDiagnose"; public static final String MOCK_METHOD = "com.alibaba.testable.core.annotation.MockMethod"; public static final String MOCK_CONSTRUCTOR = "com.alibaba.testable.core.annotation.MockConstructor"; diff --git a/testable-agent/src/main/java/com/alibaba/testable/agent/transformer/TestableClassTransformer.java b/testable-agent/src/main/java/com/alibaba/testable/agent/transformer/TestableClassTransformer.java index 6050910..669a77b 100644 --- a/testable-agent/src/main/java/com/alibaba/testable/agent/transformer/TestableClassTransformer.java +++ b/testable-agent/src/main/java/com/alibaba/testable/agent/transformer/TestableClassTransformer.java @@ -11,7 +11,7 @@ import com.alibaba.testable.agent.util.ClassUtil; import com.alibaba.testable.agent.util.GlobalConfig; import com.alibaba.testable.agent.util.StringUtil; import com.alibaba.testable.core.model.ClassType; -import com.alibaba.testable.core.model.MockDiagnose; +import com.alibaba.testable.core.model.LogLevel; import com.alibaba.testable.core.util.LogUtil; import com.alibaba.testable.core.util.MockContextUtil; import org.objectweb.asm.ClassReader; @@ -48,12 +48,11 @@ public class TestableClassTransformer implements ClassFileTransformer { private static final String CLASS_OBJECT = "java/lang/Object"; /** - * Just avoid spend time to scan those surely non-user classes - * Should keep these lists as tiny as possible + * Just avoid spend time to scan those surely non-user classes Should keep these lists as tiny as possible */ - private final String[] WHITELIST_PREFIXES = new String[] { "com/alibaba/testable/demo/" }; - private final String[] BLACKLIST_PREFIXES = new String[] { "jdk/", "java/", "javax/", "com/sun/", - "org/apache/maven/", "com/alibaba/testable/", "junit/", "org/junit/", "org/testng/" }; + private final String[] WHITELIST_PREFIXES = new String[] {"com/alibaba/testable/demo/"}; + private final String[] BLACKLIST_PREFIXES = new String[] {"jdk/", "java/", "javax/", "com/sun/", + "org/apache/maven/", "com/alibaba/testable/", "junit/", "org/junit/", "org/testng/"}; @Override public byte[] transform(ClassLoader loader, String className, Class classBeingRedefined, @@ -103,7 +102,8 @@ public class TestableClassTransformer implements ClassFileTransformer { return; } try { - String dumpFile = StringUtil.joinPath(dumpDir, className.replace(SLASH, DOT).replace(DOLLAR, UNDERLINE) + ".class"); + String dumpFile = StringUtil.joinPath(dumpDir, + className.replace(SLASH, DOT).replace(DOLLAR, UNDERLINE) + ".class"); LogUtil.verbose("Dump class: " + dumpFile); FileOutputStream stream = new FileOutputStream(dumpFile); stream.write(bytes); @@ -241,6 +241,7 @@ public class TestableClassTransformer implements ClassFileTransformer { /** * Read @MockWith annotation upon class to fetch mock class + * * @param className class that need to explore * @return name of mock class, null for not found */ @@ -254,6 +255,7 @@ public class TestableClassTransformer implements ClassFileTransformer { /** * Read @MockWith annotation upon class and inner class "Mock" to fetch mock class + * * @param className class that need to explore * @return name of mock class, null for not found */ @@ -283,14 +285,15 @@ public class TestableClassTransformer implements ClassFileTransformer { /** * Get mock class from @MockWith annotation + * * @param cn class that may have @MockWith annotation * @return mock class name */ private String parseMockWithAnnotation(ClassNode cn, ClassType expectedType) { if (cn.visibleAnnotations != null) { for (AnnotationNode an : cn.visibleAnnotations) { + setupDiagnose(an); if (toDotSeparateFullClassName(an.desc).equals(ConstPool.MOCK_WITH)) { - setupDiagnose(an); ClassType type = AnnotationUtil.getAnnotationParameter(an, FIELD_TREAT_AS, ClassType.GuessByName, ClassType.class); if (isExpectedType(cn.name, type, expectedType)) { @@ -316,6 +319,7 @@ public class TestableClassTransformer implements ClassFileTransformer { /** * Check whether any method in specified class has mock-related annotation + * * @param className class that need to explore * @return found annotation or not */ @@ -324,6 +328,7 @@ public class TestableClassTransformer implements ClassFileTransformer { if (cn == null) { return false; } + setupDiagnose(cn); for (MethodNode mn : cn.methods) { if (mn.visibleAnnotations != null) { for (AnnotationNode an : mn.visibleAnnotations) { @@ -352,11 +357,29 @@ public class TestableClassTransformer implements ClassFileTransformer { return cn; } + private void setupDiagnose(ClassNode cn) { + if (cn.visibleAnnotations == null) { + return; + } + for (AnnotationNode an : cn.visibleAnnotations) { + setupDiagnose(an); + } + } + private void setupDiagnose(AnnotationNode an) { - MockDiagnose diagnose = AnnotationUtil.getAnnotationParameter(an, FIELD_DIAGNOSE, null, MockDiagnose.class); - if (diagnose != null) { - LogUtil.setLevel(diagnose == MockDiagnose.ENABLE ? LogUtil.LogLevel.LEVEL_DIAGNOSE : - (diagnose == MockDiagnose.VERBOSE ? LogUtil.LogLevel.LEVEL_VERBOSE : LogUtil.LogLevel.LEVEL_MUTE)); + if (toDotSeparateFullClassName(an.desc).equals(MOCK_WITH)) { + setupDianose(an, FIELD_DIAGNOSE); + } + if (toDotSeparateFullClassName(an.desc).equals(ConstPool.MOCK_DIAGNOSE)) { + setupDianose(an, FIELD_VALUE); + } + } + + private void setupDianose(AnnotationNode an, String fieldDiagnose) { + LogLevel level = AnnotationUtil.getAnnotationParameter(an, fieldDiagnose, null, LogLevel.class); + if (level != null) { + LogUtil.setLevel(level == LogLevel.ENABLE ? LogUtil.LogLevel.LEVEL_DIAGNOSE : + (level == LogLevel.VERBOSE ? LogUtil.LogLevel.LEVEL_VERBOSE : LogUtil.LogLevel.LEVEL_MUTE)); } } diff --git a/testable-core/src/main/java/com/alibaba/testable/core/annotation/MockDiagnose.java b/testable-core/src/main/java/com/alibaba/testable/core/annotation/MockDiagnose.java new file mode 100644 index 0000000..f91d316 --- /dev/null +++ b/testable-core/src/main/java/com/alibaba/testable/core/annotation/MockDiagnose.java @@ -0,0 +1,23 @@ +package com.alibaba.testable.core.annotation; + +import com.alibaba.testable.core.model.LogLevel; + +import java.lang.annotation.*; + +/** + * Set extra mock parameter to test class + * + * @author flin + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +@Documented +public @interface MockDiagnose { + + /** + * switch of mock diagnose information of current test class + * @return enable or disable + */ + LogLevel value() default LogLevel.DISABLE; + +} diff --git a/testable-core/src/main/java/com/alibaba/testable/core/annotation/MockWith.java b/testable-core/src/main/java/com/alibaba/testable/core/annotation/MockWith.java index a089221..4bd719b 100644 --- a/testable-core/src/main/java/com/alibaba/testable/core/annotation/MockWith.java +++ b/testable-core/src/main/java/com/alibaba/testable/core/annotation/MockWith.java @@ -1,7 +1,7 @@ package com.alibaba.testable.core.annotation; import com.alibaba.testable.core.model.ClassType; -import com.alibaba.testable.core.model.MockDiagnose; +import com.alibaba.testable.core.model.LogLevel; import javax.lang.model.type.NullType; import java.lang.annotation.*; @@ -30,8 +30,9 @@ public @interface MockWith { /** * switch of mock diagnose information of current test class + * @deprecated to be removed in v0.6, use @MockDiagnose annotation instead * @return enable or disable */ - MockDiagnose diagnose() default MockDiagnose.DISABLE; + LogLevel diagnose() default LogLevel.DISABLE; } diff --git a/testable-core/src/main/java/com/alibaba/testable/core/model/MockDiagnose.java b/testable-core/src/main/java/com/alibaba/testable/core/model/LogLevel.java similarity index 89% rename from testable-core/src/main/java/com/alibaba/testable/core/model/MockDiagnose.java rename to testable-core/src/main/java/com/alibaba/testable/core/model/LogLevel.java index 7e78ca1..db8e962 100644 --- a/testable-core/src/main/java/com/alibaba/testable/core/model/MockDiagnose.java +++ b/testable-core/src/main/java/com/alibaba/testable/core/model/LogLevel.java @@ -4,7 +4,7 @@ package com.alibaba.testable.core.model; * @author flin */ -public enum MockDiagnose { +public enum LogLevel { /** * Be quiet