1   ////////////////////////////////////////////////////////////////////////////////
2   // checkstyle: Checks Java source code for adherence to a set of rules.
3   // Copyright (C) 2001-2019 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.puppycrawl.tools.checkstyle.internal.utils.TestUtil.isUtilsClassHasPrivateConstructor;
23  import static org.junit.Assert.assertEquals;
24  import static org.junit.Assert.assertFalse;
25  import static org.junit.Assert.assertTrue;
26  
27  import java.lang.reflect.InvocationTargetException;
28  import java.util.ArrayList;
29  import java.util.Collections;
30  import java.util.List;
31  
32  import org.junit.Assert;
33  import org.junit.Test;
34  
35  import com.puppycrawl.tools.checkstyle.api.DetailAST;
36  import com.puppycrawl.tools.checkstyle.api.TokenTypes;
37  
38  public class AnnotationUtilTest {
39  
40      @Test
41      public void testIsProperUtilsClass() throws ReflectiveOperationException {
42          try {
43              isUtilsClassHasPrivateConstructor(AnnotationUtil.class, true);
44              Assert.fail("Exception is expected");
45          }
46          catch (InvocationTargetException ex) {
47              assertEquals("Invalid exception message",
48                      "do not instantiate.", ex.getCause().getMessage());
49          }
50      }
51  
52      @Test
53      public void testContainsAnnotationNull() {
54          try {
55              AnnotationUtil.containsAnnotation(null);
56              Assert.fail("IllegalArgumentException is expected");
57          }
58          catch (IllegalArgumentException ex) {
59              assertEquals("Invalid exception message",
60                      "the ast is null", ex.getMessage());
61          }
62      }
63  
64      @Test
65      public void testContainsAnnotationNull2() {
66          try {
67              AnnotationUtil.containsAnnotation(null, "");
68              Assert.fail("IllegalArgumentException is expected");
69          }
70          catch (IllegalArgumentException ex) {
71              assertEquals("Invalid exception message",
72                      "the ast is null", ex.getMessage());
73          }
74      }
75  
76      @Test
77      public void testContainsAnnotationFalse() {
78          final DetailAST ast = new DetailAST();
79          ast.setType(1);
80          assertFalse("AnnotationUtil should not contain " + ast,
81                  AnnotationUtil.containsAnnotation(ast));
82      }
83  
84      @Test
85      public void testContainsAnnotationFalse2() {
86          final DetailAST ast = new DetailAST();
87          ast.setType(1);
88          final DetailAST ast2 = new DetailAST();
89          ast2.setType(TokenTypes.MODIFIERS);
90          ast.addChild(ast2);
91          assertFalse("AnnotationUtil should not contain " + ast,
92                  AnnotationUtil.containsAnnotation(ast));
93      }
94  
95      @Test
96      public void testContainsAnnotationTrue() {
97          final DetailAST ast = new DetailAST();
98          ast.setType(1);
99          final DetailAST ast2 = new DetailAST();
100         ast2.setType(TokenTypes.MODIFIERS);
101         ast.addChild(ast2);
102         final DetailAST ast3 = new DetailAST();
103         ast3.setType(TokenTypes.ANNOTATION);
104         ast2.addChild(ast3);
105         assertTrue("AnnotationUtil should contain " + ast,
106                 AnnotationUtil.containsAnnotation(ast));
107     }
108 
109     @Test
110     public void testAnnotationHolderNull() {
111         try {
112             AnnotationUtil.getAnnotationHolder(null);
113             Assert.fail("IllegalArgumentException is expected");
114         }
115         catch (IllegalArgumentException ex) {
116             assertEquals("Invalid exception message",
117                     "the ast is null", ex.getMessage());
118         }
119     }
120 
121     @Test
122     public void testAnnotationNull() {
123         try {
124             AnnotationUtil.getAnnotation(null, null);
125             Assert.fail("IllegalArgumentException is expected");
126         }
127         catch (IllegalArgumentException ex) {
128             assertEquals("Invalid exception message",
129                     "the ast is null", ex.getMessage());
130         }
131     }
132 
133     @Test
134     public void testAnnotationNull2() {
135         try {
136             AnnotationUtil.getAnnotation(new DetailAST(), null);
137             Assert.fail("IllegalArgumentException is expected");
138         }
139         catch (IllegalArgumentException ex) {
140             assertEquals("Invalid exception message",
141                     "the annotation is null", ex.getMessage());
142         }
143     }
144 
145     @Test
146     public void testAnnotationEmpty() {
147         try {
148             AnnotationUtil.getAnnotation(new DetailAST(), "");
149             Assert.fail("IllegalArgumentException is expected");
150         }
151         catch (IllegalArgumentException ex) {
152             assertEquals("Invalid exception message",
153                     "the annotation is empty or spaces", ex.getMessage());
154         }
155     }
156 
157     @Test
158     public void testContainsAnnotationWithNull() {
159         try {
160             AnnotationUtil.getAnnotation(null, "");
161             Assert.fail("IllegalArgumentException is expected");
162         }
163         catch (IllegalArgumentException ex) {
164             assertEquals("Invalid exception message",
165                     "the ast is null", ex.getMessage());
166         }
167     }
168 
169     @Test
170     public void testContainsAnnotationListWithNullAst() {
171         try {
172             AnnotationUtil.containsAnnotation(null, Collections.singletonList("Override"));
173             Assert.fail("IllegalArgumentException is expected");
174         }
175         catch (IllegalArgumentException ex) {
176             assertEquals("Invalid exception message",
177                     "the ast is null", ex.getMessage());
178         }
179     }
180 
181     @Test
182     public void testContainsAnnotationListWithNullList() {
183         final DetailAST ast = new DetailAST();
184         final List<String> annotations = null;
185         try {
186             AnnotationUtil.containsAnnotation(ast, annotations);
187             Assert.fail("IllegalArgumentException is expected");
188         }
189         catch (IllegalArgumentException ex) {
190             assertEquals("Invalid exception message",
191                     "annotations cannot be null", ex.getMessage());
192         }
193     }
194 
195     @Test
196     public void testContainsAnnotationListWithEmptyList() {
197         final DetailAST ast = new DetailAST();
198         final List<String> annotations = new ArrayList<>();
199         final boolean result = AnnotationUtil.containsAnnotation(ast, annotations);
200         assertFalse("An empty list should lead to a false result", result);
201     }
202 
203     @Test
204     public void testContainsAnnotationListWithNoAnnotationNode() {
205         final DetailAST ast = new DetailAST();
206         final DetailAST modifiersAst = new DetailAST();
207         modifiersAst.setType(TokenTypes.MODIFIERS);
208         ast.addChild(modifiersAst);
209         final List<String> annotations = Collections.singletonList("Override");
210         final boolean result = AnnotationUtil.containsAnnotation(ast, annotations);
211         assertFalse("An empty ast should lead to a false result", result);
212     }
213 
214     @Test
215     public void testContainsAnnotationListWithEmptyAnnotationNode() {
216         final DetailAST ast = new DetailAST();
217         final DetailAST modifiersAst = create(
218                 TokenTypes.MODIFIERS,
219                 create(
220                         TokenTypes.ANNOTATION,
221                         create(
222                                 TokenTypes.DOT,
223                                 create(
224                                         TokenTypes.IDENT,
225                                         "Override")
226                         )
227                 )
228         );
229         ast.addChild(modifiersAst);
230         final List<String> annotations = Collections.singletonList("Override");
231         final boolean result = AnnotationUtil.containsAnnotation(ast, annotations);
232         assertTrue("The dot-ident variation should also work", result);
233     }
234 
235     @Test
236     public void testContainsAnnotationListWithNoMatchingAnnotation() {
237         final DetailAST ast = new DetailAST();
238         final DetailAST modifiersAst = create(
239                 TokenTypes.MODIFIERS,
240                 create(
241                         TokenTypes.ANNOTATION,
242                         create(
243                                 TokenTypes.DOT,
244                                 create(
245                                         TokenTypes.IDENT,
246                                         "Override")
247                         )
248                 )
249         );
250         ast.addChild(modifiersAst);
251         final List<String> annotations = Collections.singletonList("Deprecated");
252         final boolean result = AnnotationUtil.containsAnnotation(ast, annotations);
253         assertFalse("No matching annotation found", result);
254     }
255 
256     @Test
257     public void testContainsAnnotation() {
258         final DetailAST astForTest = new DetailAST();
259         astForTest.setType(TokenTypes.PACKAGE_DEF);
260         final DetailAST child = new DetailAST();
261         final DetailAST annotations = new DetailAST();
262         final DetailAST annotation = new DetailAST();
263         final DetailAST annotationNameHolder = new DetailAST();
264         final DetailAST annotationName = new DetailAST();
265         annotations.setType(TokenTypes.ANNOTATIONS);
266         annotation.setType(TokenTypes.ANNOTATION);
267         annotationNameHolder.setType(TokenTypes.AT);
268         annotationName.setText("Annotation");
269 
270         annotationNameHolder.setNextSibling(annotationName);
271         annotation.setFirstChild(annotationNameHolder);
272         annotations.setFirstChild(annotation);
273         child.setNextSibling(annotations);
274         astForTest.setFirstChild(child);
275 
276         assertTrue("Annotation should contain " + astForTest,
277                 AnnotationUtil.containsAnnotation(astForTest, "Annotation"));
278     }
279 
280     @Test
281     public void testContainsAnnotationWithStringFalse() {
282         final DetailAST astForTest = new DetailAST();
283         astForTest.setType(TokenTypes.PACKAGE_DEF);
284         final DetailAST child = new DetailAST();
285         final DetailAST annotations = new DetailAST();
286         final DetailAST annotation = new DetailAST();
287         final DetailAST annotationNameHolder = new DetailAST();
288         final DetailAST annotationName = new DetailAST();
289         annotations.setType(TokenTypes.ANNOTATIONS);
290         annotation.setType(TokenTypes.ANNOTATION);
291         annotationNameHolder.setType(TokenTypes.AT);
292         annotationName.setText("Annotation");
293 
294         annotationNameHolder.setNextSibling(annotationName);
295         annotation.setFirstChild(annotationNameHolder);
296         annotations.setFirstChild(annotation);
297         child.setNextSibling(annotations);
298         astForTest.setFirstChild(child);
299 
300         assertFalse("Annotation should not contain " + astForTest,
301                 AnnotationUtil.containsAnnotation(astForTest, "AnnotationBad"));
302     }
303 
304     @Test
305     public void testContainsAnnotationWithComment() {
306         final DetailAST astForTest = new DetailAST();
307         astForTest.setType(TokenTypes.PACKAGE_DEF);
308         final DetailAST child = new DetailAST();
309         final DetailAST annotations = new DetailAST();
310         final DetailAST annotation = new DetailAST();
311         final DetailAST annotationNameHolder = new DetailAST();
312         final DetailAST annotationName = new DetailAST();
313         final DetailAST comment = new DetailAST();
314         annotations.setType(TokenTypes.ANNOTATIONS);
315         annotation.setType(TokenTypes.ANNOTATION);
316         annotationNameHolder.setType(TokenTypes.AT);
317         comment.setType(TokenTypes.BLOCK_COMMENT_BEGIN);
318         annotationName.setText("Annotation");
319 
320         annotationNameHolder.setNextSibling(annotationName);
321         annotation.setFirstChild(comment);
322         comment.setNextSibling(annotationNameHolder);
323         annotations.setFirstChild(annotation);
324         child.setNextSibling(annotations);
325         astForTest.setFirstChild(child);
326 
327         assertTrue("Annotation should contain " + astForTest,
328                 AnnotationUtil.containsAnnotation(astForTest, "Annotation"));
329     }
330 
331     private static DetailAST create(int tokenType) {
332         final DetailAST ast = new DetailAST();
333         ast.setType(tokenType);
334         return ast;
335     }
336 
337     private static DetailAST create(int tokenType, String text) {
338         final DetailAST ast = create(tokenType);
339         ast.setText(text);
340         return ast;
341     }
342 
343     private static DetailAST create(int tokenType, DetailAST child) {
344         final DetailAST ast = create(tokenType);
345         ast.addChild(child);
346         return ast;
347     }
348 }