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 } catch (NoClassDefFoundError t) {
38 c = null;
39 }
40 JUNIT4_CLASS = c;
41
42 try {
43 c = Class.forName("junit.framework.TestCase");
44 } catch (ClassNotFoundException t) {
45 c = null;
46 } catch (NoClassDefFoundError t) {
47 c = null;
48 }
49 JUNIT3_CLASS = c;
50 }
51
52 @Override
53 public Object visit(ASTCompilationUnit node, Object data) {
54
55 isJUnit3Class = isJUnit4Class = false;
56
57 isJUnit3Class = isJUnit3Class(node);
58 if (!isJUnit3Class) {
59 isJUnit4Class = isJUnit4Class(node);
60 }
61
62 if (isJUnit3Class || isJUnit4Class) {
63 return super.visit(node, data);
64 }
65 return data;
66 }
67
68 public boolean isJUnitMethod(ASTMethodDeclaration method, Object data) {
69
70 if (!method.isPublic() || method.isAbstract() || method.isNative() || method.isStatic()) {
71 return false;
72 }
73
74 if (isJUnit3Class) {
75 return isJUnit3Method(method);
76 } else {
77 return isJUnit4Method(method);
78 }
79 }
80
81 private boolean isJUnit4Method(ASTMethodDeclaration method) {
82 return doesNodeContainJUnitAnnotation(method.jjtGetParent());
83 }
84
85 private boolean isJUnit3Method(ASTMethodDeclaration method) {
86 Node node = method.jjtGetChild(0);
87 if (node instanceof ASTTypeParameters) {
88 node = method.jjtGetChild(1);
89 }
90 return ((ASTResultType) node).isVoid() && method.getMethodName().startsWith("test");
91 }
92
93 private boolean isJUnit3Class(ASTCompilationUnit node) {
94 if (node.getType() != null && TypeHelper.isA(node, JUNIT3_CLASS)) {
95 return true;
96
97 } else if (node.getType() == null) {
98 ASTClassOrInterfaceDeclaration cid = node.getFirstDescendantOfType(ASTClassOrInterfaceDeclaration.class);
99 if (cid == null) {
100 return false;
101 }
102 ASTExtendsList extendsList = cid.getFirstChildOfType(ASTExtendsList.class);
103 if (extendsList == null) {
104 return false;
105 }
106 if (((ASTClassOrInterfaceType) extendsList.jjtGetChild(0)).getImage().endsWith("TestCase")) {
107 return true;
108 }
109 String className = cid.getImage();
110 return className.endsWith("Test");
111 }
112 return false;
113 }
114
115 private boolean isJUnit4Class(ASTCompilationUnit node) {
116 return doesNodeContainJUnitAnnotation(node);
117 }
118
119 private boolean doesNodeContainJUnitAnnotation(Node node) {
120 List<ASTAnnotation> annotations = node.findDescendantsOfType(ASTAnnotation.class);
121 for (ASTAnnotation annotation : annotations) {
122 Node annotationTypeNode = annotation.jjtGetChild(0);
123 TypeNode annotationType = (TypeNode) annotationTypeNode;
124 if (annotationType.getType() == null) {
125 ASTName name = annotationTypeNode.getFirstChildOfType(ASTName.class);
126 if (name != null && "Test".equals(name.getImage())) {
127 return true;
128 }
129 } else if (annotationType.getType().equals(JUNIT4_CLASS)) {
130 return true;
131 }
132 }
133 return false;
134 }
135 }