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