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 }