1 /**
2 * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
3 */
4 package net.sourceforge.pmd.rules.migration;
5
6 import net.sourceforge.pmd.ast.ASTAnnotation;
7 import net.sourceforge.pmd.ast.ASTBlock;
8 import net.sourceforge.pmd.ast.ASTBlockStatement;
9 import net.sourceforge.pmd.ast.ASTCatchStatement;
10 import net.sourceforge.pmd.ast.ASTClassOrInterfaceBodyDeclaration;
11 import net.sourceforge.pmd.ast.ASTMethodDeclaration;
12 import net.sourceforge.pmd.ast.ASTName;
13 import net.sourceforge.pmd.ast.ASTThrowStatement;
14 import net.sourceforge.pmd.ast.ASTTryStatement;
15 import net.sourceforge.pmd.ast.Node;
16 import net.sourceforge.pmd.ast.SimpleNode;
17 import net.sourceforge.pmd.rules.junit.AbstractJUnitRule;
18
19 import java.util.ArrayList;
20 import java.util.List;
21
22 /**
23 * This rule finds code like this:
24 *
25 * <pre>
26 * public void testFoo() {
27 * try {
28 * doSomething();
29 * fail("should have thrown an exception");
30 * } catch (Exception e) {
31 * }
32 * }
33 * </pre>
34 *
35 * In JUnit 4, use
36 *
37 * <pre>
38 * @Test(expected = Exception.class)
39 * </pre>
40 *
41 * @author acaplan
42 *
43 */
44 public class JUnitUseExpected extends AbstractJUnitRule {
45
46 public Object visit(ASTClassOrInterfaceBodyDeclaration node, Object data) {
47 boolean inAnnotation = false;
48 for (int i = 0; i < node.jjtGetNumChildren(); i++) {
49 Node child = node.jjtGetChild(i);
50 if (ASTAnnotation.class.equals(child.getClass())) {
51 ASTName annotationName = ((SimpleNode) child).getFirstChildOfType(ASTName.class);
52 if ("Test".equals(annotationName.getImage())) {
53 inAnnotation = true;
54 continue;
55 }
56 }
57 if (ASTMethodDeclaration.class.equals(child.getClass())) {
58 boolean isJUnitMethod = isJUnitMethod((ASTMethodDeclaration) child, data);
59 if (inAnnotation || isJUnitMethod) {
60 List<SimpleNode> found = new ArrayList<SimpleNode>();
61 found.addAll((List<SimpleNode>) visit((ASTMethodDeclaration) child, data));
62 for (SimpleNode name : found) {
63 addViolation(data, name);
64 }
65 }
66 }
67 inAnnotation = false;
68 }
69
70 return super.visit(node, data);
71 }
72
73 public Object visit(ASTMethodDeclaration node, Object data) {
74 List<ASTTryStatement> catches = node.findChildrenOfType(ASTTryStatement.class);
75 List<SimpleNode> found = new ArrayList<SimpleNode>();
76 if (catches.isEmpty()) {
77 return found;
78 }
79 for (ASTTryStatement trySt : catches) {
80 ASTCatchStatement cStatement = getCatch(trySt);
81 if (cStatement != null) {
82 ASTBlock block = (ASTBlock) cStatement.jjtGetChild(1);
83 if (block.jjtGetNumChildren() != 0) {
84 continue;
85 }
86 List<ASTBlockStatement> blocks = ((SimpleNode) trySt.jjtGetChild(0)).findChildrenOfType(ASTBlockStatement.class);
87 if (blocks.isEmpty()) {
88 continue;
89 }
90 ASTBlockStatement st = blocks.get(blocks.size() - 1);
91 ASTName name = st.getFirstChildOfType(ASTName.class);
92 if (name != null && st.equals(name.getNthParent(5)) && "fail".equals(name.getImage())) {
93 found.add(name);
94 continue;
95 }
96 ASTThrowStatement th = st.getFirstChildOfType(ASTThrowStatement.class);
97 if (th != null && st.equals(th.getNthParent(2))) {
98 found.add(th);
99 continue;
100 }
101 }
102 }
103 return found;
104 }
105
106 private ASTCatchStatement getCatch(Node n) {
107 for (int i = 0; i < n.jjtGetNumChildren(); i++) {
108 if (n.jjtGetChild(i) instanceof ASTCatchStatement) {
109 return (ASTCatchStatement) n.jjtGetChild(i);
110 }
111 }
112 return null;
113 }
114 }