View Javadoc
1   /*
2    * SPDX-FileCopyrightText: Copyright (c) 2011-2025 Yegor Bugayenko
3    * SPDX-License-Identifier: MIT
4    */
5   package com.qulice.pmd.rules;
6   
7   import net.sourceforge.pmd.lang.ast.Node;
8   import net.sourceforge.pmd.lang.java.ast.ASTImportDeclaration;
9   import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration;
10  import net.sourceforge.pmd.lang.java.ast.ASTName;
11  import net.sourceforge.pmd.lang.java.ast.ASTPrimaryExpression;
12  import net.sourceforge.pmd.lang.java.ast.ASTPrimaryPrefix;
13  import net.sourceforge.pmd.lang.java.ast.ASTStatementExpression;
14  
15  /**
16   * Rule to check plain assertions in JUnit tests.
17   * @since 0.17
18   */
19  @SuppressWarnings("deprecation")
20  public final class ProhibitPlainJunitAssertionsRule
21      extends net.sourceforge.pmd.lang.java.rule.AbstractJUnitRule {
22  
23      /**
24       * Mask of prohibited imports.
25       */
26      private static final String[] PROHIBITED = {
27          "org.junit.Assert.assert",
28          "junit.framework.Assert.assert",
29      };
30  
31      @Override
32      public Object visit(final ASTMethodDeclaration method, final Object data) {
33          if (this.isJUnitMethod(method, data)
34              && this.containsPlainJunitAssert(method.getBody())) {
35              this.asCtx(data).addViolation(method);
36          }
37          return data;
38      }
39  
40      @Override
41      public Object visit(final ASTImportDeclaration imp, final Object data) {
42          for (final String element : ProhibitPlainJunitAssertionsRule
43              .PROHIBITED) {
44              if (imp.getImportedName().contains(element)) {
45                  this.asCtx(data).addViolation(imp);
46                  break;
47              }
48          }
49          return super.visit(imp, data);
50      }
51  
52      /**
53       * Recursively verifies if node contains plain JUnit assert statements.
54       * @param node Root statement node to search
55       * @return True if statement contains plain JUnit assertions, false
56       *  otherwise
57       */
58      private boolean containsPlainJunitAssert(final Node node) {
59          boolean found = false;
60          if (node instanceof ASTStatementExpression
61              && ProhibitPlainJunitAssertionsRule.isPlainJunitAssert(node)) {
62              found = true;
63          }
64          if (!found) {
65              for (int iter = 0; iter < node.jjtGetNumChildren(); iter += 1) {
66                  final Node child = node.jjtGetChild(iter);
67                  if (this.containsPlainJunitAssert(child)) {
68                      found = true;
69                      break;
70                  }
71              }
72          }
73          return found;
74      }
75  
76      /**
77       * Tells if the statement is an assert statement or not.
78       * @param statement Root node to search assert statements
79       * @return True is statement is assert, false otherwise
80       */
81      private static boolean isPlainJunitAssert(final Node statement) {
82          final ASTPrimaryExpression expression =
83              ProhibitPlainJunitAssertionsRule.getChildNodeWithType(
84                  statement, ASTPrimaryExpression.class
85              );
86          final ASTPrimaryPrefix prefix =
87              ProhibitPlainJunitAssertionsRule.getChildNodeWithType(
88                  expression, ASTPrimaryPrefix.class
89              );
90          final ASTName name = ProhibitPlainJunitAssertionsRule
91              .getChildNodeWithType(prefix, ASTName.class);
92          boolean assrt = false;
93          if (name != null) {
94              final String img = name.getImage();
95              assrt = img != null && (img.startsWith("assert")
96                  || img.startsWith("Assert.assert"));
97          }
98          return assrt;
99      }
100 
101     /**
102      * Gets child node with specified type.
103      * @param node Parent node
104      * @param clazz Specified class
105      * @param <T> Node type
106      * @return Child node if exists, null otherwise
107      */
108     private static <T extends Node> T getChildNodeWithType(final Node node,
109         final Class<T> clazz) {
110         T expression = null;
111         if (node != null && node.jjtGetNumChildren() > 0
112             && clazz.isInstance(node.jjtGetChild(0))) {
113             expression = clazz.cast(node.jjtGetChild(0));
114         }
115         return expression;
116     }
117 
118 }