1
2
3
4 package net.sourceforge.pmd.lang.java.rule.junit;
5
6 import java.util.List;
7
8 import net.sourceforge.pmd.lang.ast.Node;
9 import net.sourceforge.pmd.lang.java.ast.ASTAnnotation;
10 import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;
11 import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceType;
12 import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit;
13 import net.sourceforge.pmd.lang.java.ast.ASTExtendsList;
14 import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration;
15 import net.sourceforge.pmd.lang.java.ast.ASTName;
16 import net.sourceforge.pmd.lang.java.ast.ASTResultType;
17 import net.sourceforge.pmd.lang.java.ast.ASTTypeParameters;
18 import net.sourceforge.pmd.lang.java.ast.TypeNode;
19 import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule;
20 import net.sourceforge.pmd.lang.java.typeresolution.TypeHelper;
21
22 public abstract class AbstractJUnitRule extends AbstractJavaRule {
23
24 public static final Class<?> JUNIT4_CLASS;
25
26 public static final Class<?> JUNIT3_CLASS;
27
28 private boolean isJUnit3Class;
29 private boolean isJUnit4Class;
30
31 static {
32 Class<?> c;
33 try {
34 c = Class.forName("org.junit.Test");
35 } catch (ClassNotFoundException t) {
36 c = null;
37 }
38 JUNIT4_CLASS = c;
39
40 try {
41 c = Class.forName("junit.framework.TestCase");
42 } catch (ClassNotFoundException t) {
43 c = null;
44 }
45 JUNIT3_CLASS = c;
46 }
47
48 @Override
49 public Object visit(ASTCompilationUnit node, Object data) {
50
51 isJUnit3Class = isJUnit4Class = false;
52
53 isJUnit3Class = isJUnit3Class(node);
54 if (!isJUnit3Class) {
55 isJUnit4Class = isJUnit4Class(node);
56 }
57
58 if (isJUnit3Class || isJUnit4Class) {
59 return super.visit(node, data);
60 }
61 return data;
62 }
63
64 public boolean isJUnitMethod(ASTMethodDeclaration method, Object data) {
65
66 if (!method.isPublic() || method.isAbstract() || method.isNative() || method.isStatic()) {
67 return false;
68 }
69
70 if (isJUnit3Class) {
71 return isJUnit3Method(method);
72 } else {
73 return isJUnit4Method(method);
74 }
75 }
76
77 private boolean isJUnit4Method(ASTMethodDeclaration method) {
78 return doesNodeContainJUnitAnnotation(method.jjtGetParent());
79 }
80
81 private boolean isJUnit3Method(ASTMethodDeclaration method) {
82 Node node = method.jjtGetChild(0);
83 if (node instanceof ASTTypeParameters) {
84 node = method.jjtGetChild(1);
85 }
86 return ((ASTResultType) node).isVoid() && method.getMethodName().startsWith("test");
87 }
88
89 private boolean isJUnit3Class(ASTCompilationUnit node) {
90 if (node.getType() != null && TypeHelper.isA(node, JUNIT3_CLASS)) {
91 return true;
92
93 } else if (node.getType() == null) {
94 ASTClassOrInterfaceDeclaration cid = node.getFirstDescendantOfType(ASTClassOrInterfaceDeclaration.class);
95 if (cid == null) {
96 return false;
97 }
98 ASTExtendsList extendsList = cid.getFirstChildOfType(ASTExtendsList.class);
99 if (extendsList == null) {
100 return false;
101 }
102 if (((ASTClassOrInterfaceType) extendsList.jjtGetChild(0)).getImage().endsWith("TestCase")) {
103 return true;
104 }
105 String className = cid.getImage();
106 return className.endsWith("Test");
107 }
108 return false;
109 }
110
111 private boolean isJUnit4Class(ASTCompilationUnit node) {
112 return doesNodeContainJUnitAnnotation(node);
113 }
114
115 private boolean doesNodeContainJUnitAnnotation(Node node) {
116 List<ASTAnnotation> annotations = node.findDescendantsOfType(ASTAnnotation.class);
117 for (ASTAnnotation annotation : annotations) {
118 Node annotationTypeNode = annotation.jjtGetChild(0);
119 TypeNode annotationType = (TypeNode) annotationTypeNode;
120 if (annotationType.getType() == null) {
121 ASTName name = annotationTypeNode.getFirstChildOfType(ASTName.class);
122 if (name != null && "Test".equals(name.getImage())) {
123 return true;
124 }
125 } else if (annotationType.getType().equals(JUNIT4_CLASS)) {
126 return true;
127 }
128 }
129 return false;
130 }
131 }