AbstractJUnitRule.java
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 ((ASTResultTypenode).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 (((ASTClassOrInterfaceTypeextendsList.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 = (ASTNameannotation.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 }