001 package net.sourceforge.pmd.lang.java.rule.junit;
002
003 import java.util.List;
004
005 import net.sourceforge.pmd.lang.ast.Node;
006 import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;
007 import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceType;
008 import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit;
009 import net.sourceforge.pmd.lang.java.ast.ASTExtendsList;
010 import net.sourceforge.pmd.lang.java.ast.ASTMarkerAnnotation;
011 import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration;
012 import net.sourceforge.pmd.lang.java.ast.ASTName;
013 import net.sourceforge.pmd.lang.java.ast.ASTResultType;
014 import net.sourceforge.pmd.lang.java.ast.ASTTypeParameters;
015 import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule;
016 import net.sourceforge.pmd.lang.java.typeresolution.TypeHelper;
017
018 @SuppressWarnings("PMD.AvoidCatchingThrowable")
019 // Don't think we can otherwise here...
020 public abstract class AbstractJUnitRule extends AbstractJavaRule {
021
022 public static final Class<?> JUNIT4_CLASS;
023
024 public static final Class<?> JUNIT3_CLASS;
025
026 private boolean isJUnit3Class;
027 private boolean isJUnit4Class;
028
029 static {
030 Class<?> c;
031 try {
032 c = Class.forName("org.junit.Test");
033 } catch (Throwable t) {
034 c = null;
035 }
036 JUNIT4_CLASS = c;
037
038 try {
039 c = Class.forName("junit.framework.TestCase");
040 } catch (Throwable t) {
041 c = null;
042 }
043 JUNIT3_CLASS = c;
044 }
045
046 @Override
047 public Object visit(ASTCompilationUnit node, Object data) {
048
049 isJUnit3Class = isJUnit4Class = false;
050
051 isJUnit3Class = isJUnit3Class(node);
052 if (!isJUnit3Class) {
053 isJUnit4Class = isJUnit4Class(node);
054 }
055
056 if (isJUnit3Class || isJUnit4Class) {
057 return super.visit(node, data);
058 }
059 return data;
060 }
061
062 public boolean isJUnitMethod(ASTMethodDeclaration method, Object data) {
063
064 if (!method.isPublic() || method.isAbstract() || method.isNative() || method.isStatic()) {
065 return false; // skip various inapplicable method variations
066 }
067
068 if (isJUnit3Class) {
069 return isJUnit3Method(method);
070 } else {
071 return isJUnit4Method(method);
072 }
073 }
074
075 private boolean isJUnit4Method(ASTMethodDeclaration method) {
076 return doesNodeContainJUnitAnnotation(method.jjtGetParent());
077 }
078
079 private boolean isJUnit3Method(ASTMethodDeclaration method) {
080 Node node = method.jjtGetChild(0);
081 if (node instanceof ASTTypeParameters) {
082 node = method.jjtGetChild(1);
083 }
084 return ((ASTResultType) node).isVoid() && method.getMethodName().startsWith("test");
085 }
086
087 private boolean isJUnit3Class(ASTCompilationUnit node) {
088 if (node.getType() != null && TypeHelper.isA(node, JUNIT3_CLASS)) {
089 return true;
090
091 } else if (node.getType() == null) {
092 ASTClassOrInterfaceDeclaration cid = node.getFirstDescendantOfType(ASTClassOrInterfaceDeclaration.class);
093 if (cid == null) {
094 return false;
095 }
096 ASTExtendsList extendsList = cid.getFirstChildOfType(ASTExtendsList.class);
097 if (extendsList == null) {
098 return false;
099 }
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 }
|