View Javadoc
1   ///////////////////////////////////////////////////////////////////////////////////////////////
2   // checkstyle: Checks Java source code and other text files for adherence to a set of rules.
3   // Copyright (C) 2001-2026 the original author or authors.
4   //
5   // This library is free software; you can redistribute it and/or
6   // modify it under the terms of the GNU Lesser General Public
7   // License as published by the Free Software Foundation; either
8   // version 2.1 of the License, or (at your option) any later version.
9   //
10  // This library is distributed in the hope that it will be useful,
11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  // Lesser General Public License for more details.
14  //
15  // You should have received a copy of the GNU Lesser General Public
16  // License along with this library; if not, write to the Free Software
17  // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  ///////////////////////////////////////////////////////////////////////////////////////////////
19  
20  package com.puppycrawl.tools.checkstyle.utils;
21  
22  import static com.google.common.truth.Truth.assertWithMessage;
23  import static com.puppycrawl.tools.checkstyle.checks.annotation.SuppressWarningsCheck.MSG_KEY_SUPPRESSED_WARNING_NOT_ALLOWED;
24  import static com.puppycrawl.tools.checkstyle.internal.utils.TestUtil.getExpectedThrowable;
25  import static com.puppycrawl.tools.checkstyle.internal.utils.TestUtil.instantiate;
26  
27  import java.util.Set;
28  
29  import org.junit.jupiter.api.Test;
30  
31  import com.puppycrawl.tools.checkstyle.AbstractModuleTestSupport;
32  import com.puppycrawl.tools.checkstyle.DetailAstImpl;
33  import com.puppycrawl.tools.checkstyle.api.DetailAST;
34  import com.puppycrawl.tools.checkstyle.api.TokenTypes;
35  import com.puppycrawl.tools.checkstyle.checks.annotation.SuppressWarningsCheck;
36  
37  public class AnnotationUtilTest extends AbstractModuleTestSupport {
38  
39      @Override
40      public String getPackageLocation() {
41          return "com/puppycrawl/tools/checkstyle/utils/annotationutil";
42      }
43  
44      @Test
45      public void testIsProperUtilsClass() {
46          final ReflectiveOperationException exc =
47                  getExpectedThrowable(ReflectiveOperationException.class, () -> {
48                      instantiate(AnnotationUtil.class);
49                  });
50          assertWithMessage("Invalid exception message")
51              .that(exc)
52              .hasCauseThat()
53              .hasMessageThat()
54              .isEqualTo("do not instantiate.");
55      }
56  
57      @Test
58      public void testContainsAnnotationNull() {
59          final IllegalArgumentException exc =
60                  getExpectedThrowable(IllegalArgumentException.class, () -> {
61                      AnnotationUtil.containsAnnotation(null);
62                  });
63          assertWithMessage("Invalid exception message")
64              .that(exc.getMessage())
65              .isEqualTo("the ast is null");
66      }
67  
68      @Test
69      public void testContainsAnnotationNull2() {
70          final IllegalArgumentException exc =
71                  getExpectedThrowable(IllegalArgumentException.class, () -> {
72                      AnnotationUtil.containsAnnotation(null, "");
73                  });
74          assertWithMessage("Invalid exception message")
75              .that(exc.getMessage())
76              .isEqualTo("the ast is null");
77      }
78  
79      @Test
80      public void testContainsAnnotationFalse() {
81          final DetailAstImpl ast = new DetailAstImpl();
82          ast.setType(1);
83          assertWithMessage("AnnotationUtil should not contain %s", ast)
84                  .that(AnnotationUtil.containsAnnotation(ast))
85                  .isFalse();
86      }
87  
88      @Test
89      public void testContainsAnnotationFalse2() {
90          final DetailAstImpl ast = new DetailAstImpl();
91          ast.setType(1);
92          final DetailAstImpl ast2 = new DetailAstImpl();
93          ast2.setType(TokenTypes.MODIFIERS);
94          ast.addChild(ast2);
95          assertWithMessage("AnnotationUtil should not contain %s", ast)
96                  .that(AnnotationUtil.containsAnnotation(ast))
97                  .isFalse();
98      }
99  
100     @Test
101     public void testContainsAnnotationTrue() {
102         final DetailAstImpl ast = new DetailAstImpl();
103         ast.setType(1);
104         final DetailAstImpl ast2 = new DetailAstImpl();
105         ast2.setType(TokenTypes.MODIFIERS);
106         ast.addChild(ast2);
107         final DetailAstImpl ast3 = new DetailAstImpl();
108         ast3.setType(TokenTypes.ANNOTATION);
109         ast2.addChild(ast3);
110         assertWithMessage("AnnotationUtil should contain %s", ast)
111                 .that(AnnotationUtil.containsAnnotation(ast))
112                 .isTrue();
113     }
114 
115     @Test
116     public void testAnnotationHolderNull() {
117         final IllegalArgumentException exc =
118                 getExpectedThrowable(IllegalArgumentException.class, () -> {
119                     AnnotationUtil.getAnnotationHolder(null);
120                 });
121         assertWithMessage("Invalid exception message")
122             .that(exc.getMessage())
123             .isEqualTo("the ast is null");
124     }
125 
126     @Test
127     public void testAnnotationNull() {
128         final IllegalArgumentException exc =
129                 getExpectedThrowable(IllegalArgumentException.class, () -> {
130                     AnnotationUtil.getAnnotation(null, null);
131                 });
132         assertWithMessage("Invalid exception message")
133             .that(exc.getMessage())
134             .isEqualTo("the ast is null");
135     }
136 
137     @Test
138     public void testAnnotationNull2() {
139         final IllegalArgumentException exc =
140                 getExpectedThrowable(IllegalArgumentException.class, () -> {
141                     AnnotationUtil.getAnnotation(new DetailAstImpl(), null);
142                 });
143         assertWithMessage("Invalid exception message")
144             .that(exc.getMessage())
145             .isEqualTo("the annotation is null");
146     }
147 
148     @Test
149     public void testAnnotationEmpty() {
150         final IllegalArgumentException exc =
151                 getExpectedThrowable(IllegalArgumentException.class, () -> {
152                     AnnotationUtil.getAnnotation(new DetailAstImpl(), "");
153                 });
154         assertWithMessage("Invalid exception message")
155             .that(exc.getMessage())
156             .isEqualTo("the annotation is empty or spaces");
157     }
158 
159     @Test
160     public void testContainsAnnotationWithNull() {
161         final IllegalArgumentException exc =
162                 getExpectedThrowable(IllegalArgumentException.class, () -> {
163                     AnnotationUtil.getAnnotation(null, "");
164                 });
165         assertWithMessage("Invalid exception message")
166             .that(exc.getMessage())
167             .isEqualTo("the ast is null");
168     }
169 
170     @Test
171     public void testContainsAnnotationListWithNullAst() {
172         final IllegalArgumentException exc =
173                 getExpectedThrowable(IllegalArgumentException.class, () -> {
174                     AnnotationUtil.containsAnnotation(null, Set.of("Override"));
175                 });
176         assertWithMessage("Invalid exception message")
177             .that(exc.getMessage())
178             .isEqualTo("the ast is null");
179     }
180 
181     @Test
182     public void testContainsAnnotationListWithNullList() {
183         final DetailAST ast = new DetailAstImpl();
184         final Set<String> annotations = null;
185         final IllegalArgumentException exc =
186                 getExpectedThrowable(IllegalArgumentException.class, () -> {
187                     AnnotationUtil.containsAnnotation(ast, annotations);
188                 });
189         assertWithMessage("Invalid exception message")
190             .that(exc.getMessage())
191             .isEqualTo("annotations cannot be null");
192     }
193 
194     @Test
195     public void testContainsAnnotationListWithEmptyList() {
196         final DetailAST ast = new DetailAstImpl();
197         final Set<String> annotations = Set.of();
198         final boolean result = AnnotationUtil.containsAnnotation(ast, annotations);
199         assertWithMessage("An empty set should lead to a false result")
200             .that(result)
201             .isFalse();
202     }
203 
204     @Test
205     public void testContainsAnnotationListWithNoAnnotationNode() {
206         final DetailAstImpl ast = new DetailAstImpl();
207         final DetailAstImpl modifiersAst = new DetailAstImpl();
208         modifiersAst.setType(TokenTypes.MODIFIERS);
209         ast.addChild(modifiersAst);
210         final Set<String> annotations = Set.of("Override");
211         final boolean result = AnnotationUtil.containsAnnotation(ast, annotations);
212         assertWithMessage("An empty ast should lead to a false result")
213             .that(result)
214             .isFalse();
215     }
216 
217     @Test
218     public void testContainsAnnotationListWithNoMatchingAnnotation() throws Exception {
219         final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
220         verifyWithInlineConfigParser(
221             getPath("InputAnnotationUtilNoMatchingAnnotation.java"), expected);
222     }
223 
224     @Test
225     public void testContainsAnnotation() {
226         final DetailAstImpl astForTest = new DetailAstImpl();
227         astForTest.setType(TokenTypes.PACKAGE_DEF);
228         final DetailAstImpl child = new DetailAstImpl();
229         final DetailAstImpl annotations = new DetailAstImpl();
230         final DetailAstImpl annotation = new DetailAstImpl();
231         final DetailAstImpl annotationNameHolder = new DetailAstImpl();
232         final DetailAstImpl annotationName = new DetailAstImpl();
233         annotations.setType(TokenTypes.ANNOTATIONS);
234         annotation.setType(TokenTypes.ANNOTATION);
235         annotationNameHolder.setType(TokenTypes.AT);
236         annotationName.setText("Annotation");
237 
238         annotationNameHolder.setNextSibling(annotationName);
239         annotation.setFirstChild(annotationNameHolder);
240         annotations.setFirstChild(annotation);
241         child.setNextSibling(annotations);
242         astForTest.setFirstChild(child);
243 
244         assertWithMessage("Annotation should contain %s", astForTest)
245                 .that(AnnotationUtil.containsAnnotation(astForTest, "Annotation"))
246                 .isTrue();
247     }
248 
249     @Test
250     public void testContainsAnnotationWithStringFalse() {
251         final DetailAstImpl astForTest = new DetailAstImpl();
252         astForTest.setType(TokenTypes.PACKAGE_DEF);
253         final DetailAstImpl child = new DetailAstImpl();
254         final DetailAstImpl annotations = new DetailAstImpl();
255         final DetailAstImpl annotation = new DetailAstImpl();
256         final DetailAstImpl annotationNameHolder = new DetailAstImpl();
257         final DetailAstImpl annotationName = new DetailAstImpl();
258         annotations.setType(TokenTypes.ANNOTATIONS);
259         annotation.setType(TokenTypes.ANNOTATION);
260         annotationNameHolder.setType(TokenTypes.AT);
261         annotationName.setText("Annotation");
262 
263         annotationNameHolder.setNextSibling(annotationName);
264         annotation.setFirstChild(annotationNameHolder);
265         annotations.setFirstChild(annotation);
266         child.setNextSibling(annotations);
267         astForTest.setFirstChild(child);
268 
269         assertWithMessage("Annotation should not contain %s", astForTest)
270                 .that(AnnotationUtil.containsAnnotation(astForTest, "AnnotationBad"))
271                 .isFalse();
272     }
273 
274     @Test
275     public void testContainsAnnotationWithComment() {
276         final DetailAstImpl astForTest = new DetailAstImpl();
277         astForTest.setType(TokenTypes.PACKAGE_DEF);
278         final DetailAstImpl child = new DetailAstImpl();
279         final DetailAstImpl annotations = new DetailAstImpl();
280         final DetailAstImpl annotation = new DetailAstImpl();
281         final DetailAstImpl annotationNameHolder = new DetailAstImpl();
282         final DetailAstImpl annotationName = new DetailAstImpl();
283         final DetailAstImpl comment = new DetailAstImpl();
284         annotations.setType(TokenTypes.ANNOTATIONS);
285         annotation.setType(TokenTypes.ANNOTATION);
286         annotationNameHolder.setType(TokenTypes.AT);
287         comment.setType(TokenTypes.BLOCK_COMMENT_BEGIN);
288         annotationName.setText("Annotation");
289 
290         annotationNameHolder.setNextSibling(annotationName);
291         annotation.setFirstChild(comment);
292         comment.setNextSibling(annotationNameHolder);
293         annotations.setFirstChild(annotation);
294         child.setNextSibling(annotations);
295         astForTest.setFirstChild(child);
296 
297         assertWithMessage("Annotation should contain %s", astForTest)
298                 .that(AnnotationUtil.containsAnnotation(astForTest, "Annotation"))
299                 .isTrue();
300     }
301 
302     @Test
303     public void testCompactNoUnchecked() throws Exception {
304 
305         final String[] expected = {
306             "16:20: " + getCheckMessage(SuppressWarningsCheck.class,
307                     MSG_KEY_SUPPRESSED_WARNING_NOT_ALLOWED, "unchecked"),
308             "22:28: " + getCheckMessage(SuppressWarningsCheck.class,
309                     MSG_KEY_SUPPRESSED_WARNING_NOT_ALLOWED, "unchecked"),
310             "40:36: " + getCheckMessage(SuppressWarningsCheck.class,
311                     MSG_KEY_SUPPRESSED_WARNING_NOT_ALLOWED, "unchecked"),
312             "69:28: " + getCheckMessage(SuppressWarningsCheck.class,
313                     MSG_KEY_SUPPRESSED_WARNING_NOT_ALLOWED, "unchecked"),
314             "72:49: " + getCheckMessage(SuppressWarningsCheck.class,
315                     MSG_KEY_SUPPRESSED_WARNING_NOT_ALLOWED, "unchecked"),
316         };
317 
318         verifyWithInlineConfigParser(
319                 getPath("InputAnnotationUtil1.java"), expected);
320     }
321 
322     @Test
323     public void testValuePairAnnotation() throws Exception {
324 
325         final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
326 
327         verifyWithInlineConfigParser(
328                 getPath("InputAnnotationUtil2.java"), expected);
329     }
330 
331 }