View Javadoc
1   /**
2    * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
3    */
4   package net.sourceforge.pmd.lang.java.rule.junit;
5   
6   import java.util.List;
7   
8   import net.sourceforge.pmd.lang.ast.Node;
9   import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;
10  import net.sourceforge.pmd.lang.java.ast.ASTMemberValuePair;
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.ASTNormalAnnotation;
14  import net.sourceforge.pmd.lang.java.ast.ASTPrimaryExpression;
15  import net.sourceforge.pmd.lang.java.ast.ASTPrimaryPrefix;
16  import net.sourceforge.pmd.lang.java.ast.ASTStatementExpression;
17  
18  public class JUnitTestsShouldIncludeAssertRule extends AbstractJUnitRule {
19  
20      @Override
21      public Object visit(ASTClassOrInterfaceDeclaration node, Object data) {
22          if (node.isInterface()) {
23              return data;
24          }
25          return super.visit(node, data);
26      }
27  
28      @Override
29      public Object visit(ASTMethodDeclaration method, Object data) {
30          if (isJUnitMethod(method, data)) {
31              if (!containsAssert(method.getBlock(), false) && !containsExpect(method.jjtGetParent())) {
32                  addViolation(data, method);
33              }
34          }
35          return data;
36      }
37  
38      private boolean containsAssert(Node n, boolean assertFound) {
39          if (!assertFound) {
40              if (n instanceof ASTStatementExpression) {
41                  if (isAssertOrFailStatement((ASTStatementExpression) n)) {
42                      return true;
43                  }
44              }
45              if (!assertFound) {
46                  for (int i = 0; i < n.jjtGetNumChildren() && !assertFound; i++) {
47                      Node c = n.jjtGetChild(i);
48                      if (containsAssert(c, assertFound)) {
49                          return true;
50                      }
51                  }
52              }
53          }
54          return false;
55      }
56  
57      /**
58       * Tells if the node contains a Test annotation with an expected exception.
59       */
60      private boolean containsExpect(Node methodParent) {
61          List<ASTNormalAnnotation> annotations = methodParent.findDescendantsOfType(ASTNormalAnnotation.class);
62          for (ASTNormalAnnotation annotation : annotations) {
63              ASTName name = annotation.getFirstChildOfType(ASTName.class);
64              if (name != null
65                      && ("Test".equals(name.getImage()) || name.getType() != null && name.getType().equals(JUNIT4_CLASS))) {
66                  List<ASTMemberValuePair> memberValues = annotation.findDescendantsOfType(ASTMemberValuePair.class);
67                  for (ASTMemberValuePair pair : memberValues) {
68                      if ("expected".equals(pair.getImage())) {
69                          return true;
70                      }
71                  }
72              }
73          }
74          return false;
75      }
76  
77      /**
78       * Tells if the expression is an assert statement or not.
79       */
80      private boolean isAssertOrFailStatement(ASTStatementExpression expression) {
81          if (expression != null && expression.jjtGetNumChildren() > 0
82                  && expression.jjtGetChild(0) instanceof ASTPrimaryExpression) {
83              ASTPrimaryExpression pe = (ASTPrimaryExpression) expression.jjtGetChild(0);
84              if (pe.jjtGetNumChildren() > 0 && pe.jjtGetChild(0) instanceof ASTPrimaryPrefix) {
85                  ASTPrimaryPrefix pp = (ASTPrimaryPrefix) pe.jjtGetChild(0);
86                  if (pp.jjtGetNumChildren() > 0 && pp.jjtGetChild(0) instanceof ASTName) {
87                      String img = ((ASTName) pp.jjtGetChild(0)).getImage();
88                      if (img != null
89                              && (img.startsWith("assert") || img.startsWith("fail") || img.startsWith("Assert.assert") || img
90                                      .startsWith("Assert.fail"))) {
91                          return true;
92                      }
93                  }
94              }
95          }
96          return false;
97      }
98  }