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)
32                  && !containsExpect(method.jjtGetParent())) {
33                  addViolation(data, method);
34              }
35          }
36  		return data;
37  	}
38  
39      private boolean containsAssert(Node n, boolean assertFound) {
40          if (!assertFound) {
41              if (n instanceof ASTStatementExpression) {
42                  if (isAssertOrFailStatement((ASTStatementExpression)n)) {
43                      return true;
44                  }
45              }
46              if (!assertFound) {
47                  for (int i=0;i<n.jjtGetNumChildren() && ! assertFound;i++) {
48                      Node c = n.jjtGetChild(i);
49                      if (containsAssert(c, assertFound)) {
50                          return true;
51                      }
52                  }
53              }
54          }
55          return false;
56      }
57  
58      /**
59       * Tells if the node contains a Test annotation with an expected exception.
60       */
61      private boolean containsExpect(Node methodParent) {
62          List<ASTNormalAnnotation> annotations = methodParent.findDescendantsOfType(ASTNormalAnnotation.class);
63          for (ASTNormalAnnotation annotation : annotations) {
64              ASTName name = annotation.getFirstChildOfType(ASTName.class);
65              if (name != null && ("Test".equals(name.getImage())
66                      || (name.getType() != null && name.getType().equals(JUNIT4_CLASS)))) {
67                  List<ASTMemberValuePair> memberValues = annotation.findDescendantsOfType(ASTMemberValuePair.class);
68                  for (ASTMemberValuePair pair : memberValues) {
69                      if ("expected".equals(pair.getImage())) {
70                          return true;
71                      }
72                  }
73              }
74          }
75          return false;
76      }
77  
78      /**
79       * Tells if the expression is an assert statement or not.
80       */
81      private boolean isAssertOrFailStatement(ASTStatementExpression expression) {
82          if (expression!=null
83                  && expression.jjtGetNumChildren()>0
84                  && expression.jjtGetChild(0) instanceof ASTPrimaryExpression
85                  ) {
86              ASTPrimaryExpression pe = (ASTPrimaryExpression) expression.jjtGetChild(0);
87              if (pe.jjtGetNumChildren()> 0 && pe.jjtGetChild(0) instanceof ASTPrimaryPrefix) {
88                  ASTPrimaryPrefix pp = (ASTPrimaryPrefix) pe.jjtGetChild(0);
89                  if (pp.jjtGetNumChildren()>0 && pp.jjtGetChild(0) instanceof ASTName) {
90                      String img = ((ASTName) pp.jjtGetChild(0)).getImage();
91                      if (img != null && (img.startsWith("assert") || img.startsWith("fail") || img.startsWith("Assert.assert") || img.startsWith("Assert.fail") )) {
92                          return true;
93                      }
94                  }
95              }
96          }
97          return false;
98      }
99  }