View Javadoc

1   package net.sourceforge.pmd.lang.java.rule.junit;
2   
3   import java.util.List;
4   
5   import net.sourceforge.pmd.lang.ast.Node;
6   import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;
7   import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceType;
8   import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit;
9   import net.sourceforge.pmd.lang.java.ast.ASTExtendsList;
10  import net.sourceforge.pmd.lang.java.ast.ASTMarkerAnnotation;
11  import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration;
12  import net.sourceforge.pmd.lang.java.ast.ASTName;
13  import net.sourceforge.pmd.lang.java.ast.ASTResultType;
14  import net.sourceforge.pmd.lang.java.ast.ASTTypeParameters;
15  import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule;
16  import net.sourceforge.pmd.lang.java.typeresolution.TypeHelper;
17  
18  @SuppressWarnings("PMD.AvoidCatchingThrowable")
19  // Don't think we can otherwise here...
20  public abstract class AbstractJUnitRule extends AbstractJavaRule {
21  
22      public static final Class<?> JUNIT4_CLASS;
23  
24      public static final Class<?> JUNIT3_CLASS;
25  
26      private boolean isJUnit3Class;
27      private boolean isJUnit4Class;
28  
29      static {
30  	Class<?> c;
31  	try {
32  	    c = Class.forName("org.junit.Test");
33  	} catch (Throwable t) {
34  	    c = null;
35  	}
36  	JUNIT4_CLASS = c;
37  
38  	try {
39  	    c = Class.forName("junit.framework.TestCase");
40  	} catch (Throwable t) {
41  	    c = null;
42  	}
43  	JUNIT3_CLASS = c;
44      }
45  
46      @Override
47      public Object visit(ASTCompilationUnit node, Object data) {
48  
49  	isJUnit3Class = isJUnit4Class = false;
50  
51  	isJUnit3Class = isJUnit3Class(node);
52  	if (!isJUnit3Class) {
53  	    isJUnit4Class = isJUnit4Class(node);
54  	}
55  
56  	if (isJUnit3Class || isJUnit4Class) {
57  	    return super.visit(node, data);
58  	}
59  	return data;
60      }
61  
62      public boolean isJUnitMethod(ASTMethodDeclaration method, Object data) {
63  
64  	if (!method.isPublic() || method.isAbstract() || method.isNative() || method.isStatic()) {
65  	    return false; // skip various inapplicable method variations
66  	}
67  
68  	if (isJUnit3Class) {
69  	    return isJUnit3Method(method);
70  	} else {
71  	    return isJUnit4Method(method);
72  	}
73      }
74  
75      private boolean isJUnit4Method(ASTMethodDeclaration method) {
76  	return doesNodeContainJUnitAnnotation(method.jjtGetParent());
77      }
78  
79      private boolean isJUnit3Method(ASTMethodDeclaration method) {
80  	Node node = method.jjtGetChild(0);
81  	if (node instanceof ASTTypeParameters) {
82  	    node = method.jjtGetChild(1);
83  	}
84  	return ((ASTResultType) node).isVoid() && method.getMethodName().startsWith("test");
85      }
86  
87      private boolean isJUnit3Class(ASTCompilationUnit node) {
88  	if (node.getType() != null && TypeHelper.isA(node, JUNIT3_CLASS)) {
89  	    return true;
90  
91  	} else if (node.getType() == null) {
92  	    ASTClassOrInterfaceDeclaration cid = node.getFirstDescendantOfType(ASTClassOrInterfaceDeclaration.class);
93  	    if (cid == null) {
94  		return false;
95  	    }
96  	    ASTExtendsList extendsList = cid.getFirstChildOfType(ASTExtendsList.class);
97  	    if (extendsList == null) {
98  		return false;
99  	    }
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 }