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