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.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; // skip various inapplicable method variations
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 }