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