View Javadoc
1   ///////////////////////////////////////////////////////////////////////////////////////////////
2   // checkstyle: Checks Java source code and other text files for adherence to a set of rules.
3   // Copyright (C) 2001-2025 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.checks.javadoc;
21  
22  import static com.google.common.truth.Truth.assertWithMessage;
23  
24  import org.junit.jupiter.api.Test;
25  
26  import com.puppycrawl.tools.checkstyle.DetailAstImpl;
27  import com.puppycrawl.tools.checkstyle.api.TokenTypes;
28  import com.puppycrawl.tools.checkstyle.internal.utils.TestUtil;
29  
30  public class JavadocTagInfoTest {
31  
32      /* Additional test for jacoco, since valueOf()
33       * is generated by javac and jacoco reports that
34       * valueOf() is uncovered.
35       */
36      @Test
37      public void testJavadocTagInfoValueOf() {
38          final JavadocTagInfo tag = JavadocTagInfo.valueOf("AUTHOR");
39          assertWithMessage("Invalid valueOf result")
40              .that(tag)
41              .isEqualTo(JavadocTagInfo.AUTHOR);
42      }
43  
44      /* Additional test for jacoco, since valueOf()
45       * is generated by javac and jacoco reports that
46       * valueOf() is uncovered.
47       */
48      @Test
49      public void testTypeValueOf() {
50          final JavadocTagInfo.Type type = JavadocTagInfo.Type.valueOf("BLOCK");
51          assertWithMessage("Invalid valueOf result")
52              .that(type)
53              .isEqualTo(JavadocTagInfo.Type.BLOCK);
54      }
55  
56      /* Additional test for jacoco, since values()
57       * is generated by javac and jacoco reports that
58       * values() is uncovered.
59       */
60      @Test
61      public void testTypeValues() {
62          final JavadocTagInfo.Type[] expected = {
63              JavadocTagInfo.Type.BLOCK,
64              JavadocTagInfo.Type.INLINE,
65          };
66          final JavadocTagInfo.Type[] actual = JavadocTagInfo.Type.values();
67          assertWithMessage("Invalid Type values")
68              .that(actual)
69              .isEqualTo(expected);
70      }
71  
72      @Test
73      public void testAuthor() {
74          final DetailAstImpl ast = new DetailAstImpl();
75  
76          final int[] validTypes = {
77              TokenTypes.PACKAGE_DEF,
78              TokenTypes.CLASS_DEF,
79              TokenTypes.INTERFACE_DEF,
80              TokenTypes.ENUM_DEF,
81              TokenTypes.ANNOTATION_DEF,
82          };
83          for (int type: validTypes) {
84              ast.setType(type);
85              assertWithMessage("Invalid ast type for current tag: " + ast.getType())
86                      .that(JavadocTagInfo.AUTHOR.isValidOn(ast))
87                      .isTrue();
88          }
89  
90          ast.setType(TokenTypes.LAMBDA);
91          assertWithMessage("Should return false when ast type is invalid for current tag")
92                  .that(JavadocTagInfo.AUTHOR.isValidOn(ast))
93                  .isFalse();
94      }
95  
96      @Test
97      public void testOthers() throws ReflectiveOperationException {
98          final JavadocTagInfo[] tags = {
99              JavadocTagInfo.CODE,
100             JavadocTagInfo.DOC_ROOT,
101             JavadocTagInfo.LINK,
102             JavadocTagInfo.LINKPLAIN,
103             JavadocTagInfo.LITERAL,
104             JavadocTagInfo.SEE,
105             JavadocTagInfo.SINCE,
106             JavadocTagInfo.VALUE,
107         };
108         for (JavadocTagInfo tagInfo : tags) {
109             final DetailAstImpl astParent = new DetailAstImpl();
110             astParent.setType(TokenTypes.LITERAL_CATCH);
111 
112             final DetailAstImpl ast = new DetailAstImpl();
113             TestUtil.invokeMethod(ast, "setParent", astParent);
114 
115             final int[] validTypes = {
116                 TokenTypes.PACKAGE_DEF,
117                 TokenTypes.CLASS_DEF,
118                 TokenTypes.INTERFACE_DEF,
119                 TokenTypes.ENUM_DEF,
120                 TokenTypes.ANNOTATION_DEF,
121                 TokenTypes.METHOD_DEF,
122                 TokenTypes.CTOR_DEF,
123                 TokenTypes.VARIABLE_DEF,
124             };
125             for (int type: validTypes) {
126                 ast.setType(type);
127                 assertWithMessage("Invalid ast type for current tag: " + ast.getType())
128                         .that(tagInfo.isValidOn(ast))
129                         .isTrue();
130             }
131 
132             astParent.setType(TokenTypes.SLIST);
133             ast.setType(TokenTypes.VARIABLE_DEF);
134             assertWithMessage("Should return false when ast type is invalid for current tag")
135                     .that(tagInfo.isValidOn(ast))
136                     .isFalse();
137 
138             ast.setType(TokenTypes.PARAMETER_DEF);
139             assertWithMessage("Should return false when ast type is invalid for current tag")
140                     .that(tagInfo.isValidOn(ast))
141                     .isFalse();
142         }
143     }
144 
145     @Test
146     public void testDeprecated() throws ReflectiveOperationException {
147         final DetailAstImpl ast = new DetailAstImpl();
148         final DetailAstImpl astParent = new DetailAstImpl();
149         astParent.setType(TokenTypes.LITERAL_CATCH);
150         TestUtil.invokeMethod(ast, "setParent", astParent);
151 
152         final int[] validTypes = {
153             TokenTypes.CLASS_DEF,
154             TokenTypes.INTERFACE_DEF,
155             TokenTypes.ENUM_DEF,
156             TokenTypes.ANNOTATION_DEF,
157             TokenTypes.METHOD_DEF,
158             TokenTypes.CTOR_DEF,
159             TokenTypes.ENUM_CONSTANT_DEF,
160             TokenTypes.ANNOTATION_FIELD_DEF,
161             TokenTypes.VARIABLE_DEF,
162         };
163         for (int type: validTypes) {
164             ast.setType(type);
165             assertWithMessage("Invalid ast type for current tag: " + ast.getType())
166                     .that(JavadocTagInfo.DEPRECATED.isValidOn(ast))
167                     .isTrue();
168         }
169 
170         astParent.setType(TokenTypes.SLIST);
171         ast.setType(TokenTypes.VARIABLE_DEF);
172         assertWithMessage("Should return false when ast type is invalid for current tag")
173                 .that(JavadocTagInfo.DEPRECATED.isValidOn(ast))
174                 .isFalse();
175 
176         ast.setType(TokenTypes.PARAMETER_DEF);
177         assertWithMessage("Should return false when ast type is invalid for current tag")
178                 .that(JavadocTagInfo.DEPRECATED.isValidOn(ast))
179                 .isFalse();
180     }
181 
182     @Test
183     public void testSerial() throws ReflectiveOperationException {
184         final DetailAstImpl ast = new DetailAstImpl();
185         final DetailAstImpl astParent = new DetailAstImpl();
186         astParent.setType(TokenTypes.LITERAL_CATCH);
187         TestUtil.invokeMethod(ast, "setParent", astParent);
188 
189         final int[] validTypes = {
190             TokenTypes.VARIABLE_DEF,
191         };
192         for (int type: validTypes) {
193             ast.setType(type);
194             assertWithMessage("Invalid ast type for current tag: " + ast.getType())
195                     .that(JavadocTagInfo.SERIAL.isValidOn(ast))
196                     .isTrue();
197         }
198 
199         astParent.setType(TokenTypes.SLIST);
200         ast.setType(TokenTypes.VARIABLE_DEF);
201         assertWithMessage("Should return false when ast type is invalid for current tag")
202                 .that(JavadocTagInfo.SERIAL.isValidOn(ast))
203                 .isFalse();
204 
205         ast.setType(TokenTypes.PARAMETER_DEF);
206         assertWithMessage("Should return false when ast type is invalid for current tag")
207                 .that(JavadocTagInfo.SERIAL.isValidOn(ast))
208                 .isFalse();
209     }
210 
211     @Test
212     public void testException() {
213         final DetailAstImpl ast = new DetailAstImpl();
214 
215         final int[] validTypes = {
216             TokenTypes.METHOD_DEF,
217             TokenTypes.CTOR_DEF,
218         };
219         for (int type: validTypes) {
220             ast.setType(type);
221             assertWithMessage("Invalid ast type for current tag: " + ast.getType())
222                     .that(JavadocTagInfo.EXCEPTION.isValidOn(ast))
223                     .isTrue();
224         }
225 
226         ast.setType(TokenTypes.LAMBDA);
227         assertWithMessage("Should return false when ast type is invalid for current tag")
228                 .that(JavadocTagInfo.EXCEPTION.isValidOn(ast))
229                 .isFalse();
230     }
231 
232     @Test
233     public void testThrows() {
234         final DetailAstImpl ast = new DetailAstImpl();
235 
236         final int[] validTypes = {
237             TokenTypes.METHOD_DEF,
238             TokenTypes.CTOR_DEF,
239         };
240         for (int type: validTypes) {
241             ast.setType(type);
242             assertWithMessage("Invalid ast type for current tag: " + ast.getType())
243                     .that(JavadocTagInfo.THROWS.isValidOn(ast))
244                     .isTrue();
245         }
246 
247         ast.setType(TokenTypes.LAMBDA);
248         assertWithMessage("Should return false when ast type is invalid for current tag")
249                 .that(JavadocTagInfo.THROWS.isValidOn(ast))
250                 .isFalse();
251     }
252 
253     @Test
254     public void testVersions() {
255         final DetailAstImpl ast = new DetailAstImpl();
256 
257         final int[] validTypes = {
258             TokenTypes.PACKAGE_DEF,
259             TokenTypes.CLASS_DEF,
260             TokenTypes.INTERFACE_DEF,
261             TokenTypes.ENUM_DEF,
262             TokenTypes.ANNOTATION_DEF,
263         };
264         for (int type: validTypes) {
265             ast.setType(type);
266             assertWithMessage("Invalid ast type for current tag: " + ast.getType())
267                     .that(JavadocTagInfo.VERSION.isValidOn(ast))
268                     .isTrue();
269         }
270 
271         ast.setType(TokenTypes.LAMBDA);
272         assertWithMessage("Should return false when ast type is invalid for current tag")
273                 .that(JavadocTagInfo.VERSION.isValidOn(ast))
274                 .isFalse();
275     }
276 
277     @Test
278     public void testParam() {
279         final DetailAstImpl ast = new DetailAstImpl();
280 
281         final int[] validTypes = {
282             TokenTypes.CLASS_DEF,
283             TokenTypes.INTERFACE_DEF,
284             TokenTypes.METHOD_DEF,
285             TokenTypes.CTOR_DEF,
286         };
287         for (int type: validTypes) {
288             ast.setType(type);
289             assertWithMessage("Invalid ast type for current tag: " + ast.getType())
290                     .that(JavadocTagInfo.PARAM.isValidOn(ast))
291                     .isTrue();
292         }
293 
294         ast.setType(TokenTypes.LAMBDA);
295         assertWithMessage("Should return false when ast type is invalid for current tag")
296                 .that(JavadocTagInfo.PARAM.isValidOn(ast))
297                 .isFalse();
298     }
299 
300     @Test
301     public void testReturn() {
302         final DetailAstImpl ast = new DetailAstImpl();
303         final DetailAstImpl astChild = new DetailAstImpl();
304         astChild.setType(TokenTypes.TYPE);
305         ast.setFirstChild(astChild);
306         final DetailAstImpl astChild2 = new DetailAstImpl();
307         astChild2.setType(TokenTypes.LITERAL_INT);
308         astChild.setFirstChild(astChild2);
309 
310         final int[] validTypes = {
311             TokenTypes.METHOD_DEF,
312         };
313         for (int type: validTypes) {
314             ast.setType(type);
315             assertWithMessage("Invalid ast type for current tag: " + ast.getType())
316                     .that(JavadocTagInfo.RETURN.isValidOn(ast))
317                     .isTrue();
318         }
319 
320         astChild2.setType(TokenTypes.LITERAL_VOID);
321         assertWithMessage("Should return false when ast type is invalid for current tag")
322                 .that(JavadocTagInfo.RETURN.isValidOn(ast))
323                 .isFalse();
324 
325         ast.setType(TokenTypes.LAMBDA);
326         assertWithMessage("Should return false when ast type is invalid for current tag")
327                 .that(JavadocTagInfo.RETURN.isValidOn(ast))
328                 .isFalse();
329 
330         astChild2.setType(TokenTypes.LITERAL_INT);
331         assertWithMessage("Should return false when ast type is invalid for current tag")
332                 .that(JavadocTagInfo.RETURN.isValidOn(ast))
333                 .isFalse();
334     }
335 
336     @Test
337     public void testSerialField() {
338         final DetailAstImpl ast = new DetailAstImpl();
339         final DetailAstImpl astChild = new DetailAstImpl();
340         astChild.setType(TokenTypes.TYPE);
341         ast.setFirstChild(astChild);
342         final DetailAstImpl astChild2 = new DetailAstImpl();
343         astChild2.setType(TokenTypes.ARRAY_DECLARATOR);
344         astChild2.setText("ObjectStreamField");
345         astChild.setFirstChild(astChild2);
346 
347         final int[] validTypes = {
348             TokenTypes.VARIABLE_DEF,
349         };
350         for (int type: validTypes) {
351             ast.setType(type);
352             assertWithMessage("Invalid ast type for current tag: " + ast.getType())
353                     .that(JavadocTagInfo.SERIAL_FIELD.isValidOn(ast))
354                     .isTrue();
355         }
356 
357         astChild2.setText("1111");
358         assertWithMessage("Should return false when ast type is invalid for current tag")
359                 .that(JavadocTagInfo.SERIAL_FIELD.isValidOn(ast))
360                 .isFalse();
361 
362         astChild2.setType(TokenTypes.LITERAL_VOID);
363         assertWithMessage("Should return false when ast type is invalid for current tag")
364                 .that(JavadocTagInfo.SERIAL_FIELD.isValidOn(ast))
365                 .isFalse();
366 
367         ast.setType(TokenTypes.LAMBDA);
368         assertWithMessage("Should return false when ast type is invalid for current tag")
369                 .that(JavadocTagInfo.SERIAL_FIELD.isValidOn(ast))
370                 .isFalse();
371     }
372 
373     @Test
374     public void testSerialData() {
375         final DetailAstImpl ast = new DetailAstImpl();
376         ast.setType(TokenTypes.METHOD_DEF);
377         final DetailAstImpl astChild = new DetailAstImpl();
378         astChild.setType(TokenTypes.IDENT);
379         astChild.setText("writeObject");
380         ast.setFirstChild(astChild);
381 
382         final String[] validNames = {
383             "writeObject",
384             "readObject",
385             "writeExternal",
386             "readExternal",
387             "writeReplace",
388             "readResolve",
389         };
390         for (String name: validNames) {
391             astChild.setText(name);
392             assertWithMessage("Invalid ast type for current tag: " + ast.getType())
393                     .that(JavadocTagInfo.SERIAL_DATA.isValidOn(ast))
394                     .isTrue();
395         }
396 
397         astChild.setText("1111");
398         assertWithMessage("Should return false when ast type is invalid for current tag")
399                 .that(JavadocTagInfo.SERIAL_DATA.isValidOn(ast))
400                 .isFalse();
401 
402         ast.setType(TokenTypes.LAMBDA);
403         assertWithMessage("Should return false when ast type is invalid for current tag")
404                 .that(JavadocTagInfo.SERIAL_DATA.isValidOn(ast))
405                 .isFalse();
406 
407         astChild.setText("writeObject");
408         assertWithMessage("Should return false when ast type is invalid for current tag")
409                  .that(JavadocTagInfo.SERIAL_DATA.isValidOn(ast))
410                  .isFalse();
411     }
412 
413     @Test
414     public void testCoverage() {
415         assertWithMessage("Invalid type")
416             .that(JavadocTagInfo.VERSION.getType())
417             .isEqualTo(JavadocTagInfo.Type.BLOCK);
418 
419         assertWithMessage("Invalid toString result")
420             .that(JavadocTagInfo.VERSION.toString())
421             .isEqualTo("text [@version] name [version] type [BLOCK]");
422 
423         try {
424             JavadocTagInfo.fromName(null);
425             assertWithMessage("IllegalArgumentException is expected").fail();
426         }
427         catch (IllegalArgumentException exc) {
428             assertWithMessage("Invalid exception message")
429                 .that(exc.getMessage())
430                 .isEqualTo("the name is null");
431         }
432 
433         try {
434             JavadocTagInfo.fromName("myname");
435             assertWithMessage("IllegalArgumentException is expected").fail();
436         }
437         catch (IllegalArgumentException exc) {
438             assertWithMessage("Invalid exception message")
439                 .that(exc.getMessage())
440                 .isEqualTo("the name [myname] is not a valid Javadoc tag name");
441         }
442 
443         try {
444             JavadocTagInfo.fromText(null);
445             assertWithMessage("IllegalArgumentException is expected").fail();
446         }
447         catch (IllegalArgumentException exc) {
448             assertWithMessage("Invalid exception message")
449                 .that(exc.getMessage())
450                 .isEqualTo("the text is null");
451         }
452 
453         try {
454             JavadocTagInfo.fromText("myname");
455             assertWithMessage("IllegalArgumentException is expected").fail();
456         }
457         catch (IllegalArgumentException exc) {
458             assertWithMessage("Invalid exception message")
459                 .that(exc.getMessage())
460                 .isEqualTo("the text [myname] is not a valid Javadoc tag text");
461         }
462 
463         assertWithMessage("Invalid fromText result")
464             .that(JavadocTagInfo.fromText("@version"))
465             .isEqualTo(JavadocTagInfo.VERSION);
466     }
467 
468 }