View Javadoc
1   /**
2    * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
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; // skip various inapplicable method variations
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 }