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  import static com.puppycrawl.tools.checkstyle.JavadocDetailNodeParser.MSG_JAVADOC_PARSE_RULE_ERROR;
24  import static com.puppycrawl.tools.checkstyle.JavadocDetailNodeParser.MSG_UNCLOSED_HTML_TAG;
25  import static com.puppycrawl.tools.checkstyle.checks.javadoc.JavadocTypeCheck.MSG_TAG_FORMAT;
26  import static com.puppycrawl.tools.checkstyle.checks.javadoc.SummaryJavadocCheck.MSG_SUMMARY_FIRST_SENTENCE;
27  import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
28  
29  import java.io.File;
30  import java.util.UUID;
31  
32  import org.itsallcode.io.Capturable;
33  import org.itsallcode.junit.sysextensions.SystemErrGuard;
34  import org.itsallcode.junit.sysextensions.SystemErrGuard.SysErr;
35  import org.junit.jupiter.api.BeforeEach;
36  import org.junit.jupiter.api.Test;
37  import org.junit.jupiter.api.extension.ExtendWith;
38  import org.junit.jupiter.api.io.TempDir;
39  
40  import com.puppycrawl.tools.checkstyle.AbstractModuleTestSupport;
41  import com.puppycrawl.tools.checkstyle.DefaultConfiguration;
42  import com.puppycrawl.tools.checkstyle.api.DetailNode;
43  import com.puppycrawl.tools.checkstyle.api.JavadocCommentsTokenTypes;
44  import com.puppycrawl.tools.checkstyle.utils.CommonUtil;
45  import com.puppycrawl.tools.checkstyle.utils.JavadocUtil;
46  
47  @ExtendWith(SystemErrGuard.class)
48  public class AbstractJavadocCheckTest extends AbstractModuleTestSupport {
49  
50      @TempDir
51      public File temporaryFolder;
52  
53      @Override
54      protected String getPackageLocation() {
55          return "com/puppycrawl/tools/checkstyle/checks/javadoc/abstractjavadoc";
56      }
57  
58      /**
59       * Configures the environment for each test.
60       * <ul>
61       * <li>Start output capture for {@link System#err}</li>
62       * </ul>
63       *
64       * @param systemErr wrapper for {@code System.err}
65       */
66      @BeforeEach
67      public void setUp(@SysErr Capturable systemErr) {
68          systemErr.captureMuted();
69      }
70  
71      @Test
72      public void testJavadocTagsWithoutArgs() throws Exception {
73          final String[] expected = {
74              "16: " + getCheckMessage(MSG_JAVADOC_PARSE_RULE_ERROR, 4,
75                      "no viable alternative at input 'see'", "SEE_TAG"),
76              "65: " + getCheckMessage(MSG_JAVADOC_PARSE_RULE_ERROR, 13,
77                      "no viable alternative at input '}'", "REFERENCE"),
78              "73: " + getCheckMessage(MSG_JAVADOC_PARSE_RULE_ERROR, 19,
79                      "no viable alternative at input '}'", "REFERENCE"),
80          };
81          verifyWithInlineConfigParser(
82                  getPath("InputAbstractJavadocJavadocTagsWithoutArgs.java"), expected);
83      }
84  
85      @Test
86      public void testNumberFormatException() throws Exception {
87          final String[] expected = {
88              "8: " + getCheckMessage(MSG_JAVADOC_PARSE_RULE_ERROR, 52,
89                      "mismatched input '}' expecting IDENTIFIER", "MEMBER_REFERENCE"),
90          };
91          verifyWithInlineConfigParser(
92                  getPath("InputAbstractJavadocNumberFormatException.java"), expected);
93      }
94  
95      @Test
96      public void testCustomTag() throws Exception {
97          final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
98          verifyWithInlineConfigParser(getPath("InputAbstractJavadocCustomTag.java"), expected);
99      }
100 
101     @Test
102     public void testWithMultipleChecksOne() throws Exception {
103         verifyWithInlineConfigParser(
104                 getPath("InputAbstractJavadocCorrectParagraphOne.java"),
105                 CommonUtil.EMPTY_STRING_ARRAY);
106     }
107 
108     @Test
109     public void testWithMultipleChecksTwo() throws Exception {
110         verifyWithInlineConfigParser(
111                 getPath("InputAbstractJavadocCorrectParagraphTwo.java"),
112                 CommonUtil.EMPTY_STRING_ARRAY);
113     }
114 
115     @Test
116     public void testAntlrError(@SysErr Capturable systemErr) throws Exception {
117         final String[] expected = {
118             "9: " + getCheckMessage(MSG_JAVADOC_PARSE_RULE_ERROR, 77,
119                     "mismatched input '(' expecting <EOF>", "JAVADOC"),
120         };
121         verifyWithInlineConfigParser(
122                 getPath("InputAbstractJavadocInvalidAtSeeReference.java"), expected);
123         assertWithMessage("Error is unexpected")
124             .that(systemErr.getCapturedData())
125             .isEqualTo("");
126     }
127 
128     @Test
129     public void testAntlrLexerError(@SysErr Capturable systemErr) throws Exception {
130         final String[] expected = {
131             "10: " + getCheckMessage(MSG_JAVADOC_PARSE_RULE_ERROR,
132                     29, "token recognition error at: '-'", "fieldName"),
133         };
134         verifyWithInlineConfigParser(
135                 getPath("InputAbstractJavadocInvalidLexing.java"), expected);
136         assertWithMessage("Error is unexpected")
137             .that(systemErr.getCapturedData())
138             .isEqualTo("");
139     }
140 
141     @Test
142     public void testCheckReuseAfterParseErrorWithFollowingAntlrErrorInTwoFiles(
143             @SysErr Capturable systemErr) throws Exception {
144         final String[] expectedMessagesForFile1 = {
145             "11: " + getCheckMessage(MSG_JAVADOC_PARSE_RULE_ERROR, 5,
146                     "mismatched input '<EOF>' expecting JAVADOC_INLINE_TAG_END", "INLINE_TAG"),
147         };
148         verifyWithInlineConfigParser(getPath(
149                 "InputAbstractJavadocParsingErrors2.java"), expectedMessagesForFile1);
150 
151         final String[] expectedMessagesForFile2 = {
152             "9: " + getCheckMessage(MSG_JAVADOC_PARSE_RULE_ERROR, 77,
153                     "mismatched input '(' expecting <EOF>", "JAVADOC"),
154         };
155         verifyWithInlineConfigParser(getPath(
156                 "InputAbstractJavadocInvalidAtSeeReference2.java"), expectedMessagesForFile2);
157 
158         assertWithMessage("Error is unexpected")
159                 .that(systemErr.getCapturedData())
160                 .isEqualTo("");
161     }
162 
163     @Test
164     public void testCheckReuseAfterParseErrorWithFollowingAntlrErrorInSingleFile()
165             throws Exception {
166         final String[] expected = {
167             "10: " + getCheckMessage(MSG_JAVADOC_PARSE_RULE_ERROR, 81,
168                     "mismatched input '(' expecting <EOF>", "JAVADOC"),
169         };
170         verifyWithInlineConfigParser(
171             getPath("InputAbstractJavadocUnclosedTagAndInvalidAtSeeReference.java"), expected);
172     }
173 
174     @Test
175     public void testCache() throws Exception {
176         final String[] expected = {
177             "12: " + getCheckMessage(SummaryJavadocCheck.class, MSG_SUMMARY_FIRST_SENTENCE),
178         };
179         verifyWithInlineConfigParser(getPath("InputAbstractJavadocCache1.java"),
180             getPath("InputAbstractJavadocCache2.java"), expected);
181     }
182 
183     @Test
184     public void testCacheWithBlockCommentInSingleLineComment() throws Exception {
185         final String[] expected = {};
186         verifyWithInlineConfigParser(getPath("InputAbstractJavadocCache3.java"), expected);
187     }
188 
189     @Test
190     public void testCacheWithTwoBlockCommentAtSameLine() throws Exception {
191         final String[] expected = {
192             "13: " + getCheckMessage(SummaryJavadocCheck.class, MSG_SUMMARY_FIRST_SENTENCE),
193         };
194         verifyWithInlineConfigParser(getPath("InputAbstractJavadocCache4.java"), expected);
195     }
196 
197     @Test
198     public void testPositionOne() throws Exception {
199         JavadocCatchCheck.clearCounter();
200         final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
201         verifyWithInlineConfigParser(getPath("InputAbstractJavadocPositionOne.java"), expected);
202         assertWithMessage("Invalid number of javadocs")
203             .that(JavadocCatchCheck.javadocsNumber)
204             .isEqualTo(21);
205     }
206 
207     @Test
208     public void testPositionTwo() throws Exception {
209         JavadocCatchCheck.clearCounter();
210         final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
211         verifyWithInlineConfigParser(getPath("InputAbstractJavadocPositionTwo.java"), expected);
212         assertWithMessage("Invalid number of javadocs")
213             .that(JavadocCatchCheck.javadocsNumber)
214             .isEqualTo(29);
215     }
216 
217     @Test
218     public void testPositionThree() throws Exception {
219         JavadocCatchCheck.clearCounter();
220         final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
221         verifyWithInlineConfigParser(getPath("InputAbstractJavadocPositionThree.java"), expected);
222         assertWithMessage("Invalid number of javadocs")
223             .that(JavadocCatchCheck.javadocsNumber)
224             .isEqualTo(15);
225     }
226 
227     @Test
228     public void testPositionWithSinglelineCommentsOne() throws Exception {
229         JavadocCatchCheck.clearCounter();
230         final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
231         verifyWithInlineConfigParser(
232                 getPath("InputAbstractJavadocPositionWithSinglelineCommentsOne.java"), expected);
233         assertWithMessage("Invalid number of javadocs")
234             .that(JavadocCatchCheck.javadocsNumber)
235             .isEqualTo(21);
236     }
237 
238     @Test
239     public void testPositionWithSinglelineCommentsTwo() throws Exception {
240         JavadocCatchCheck.clearCounter();
241         final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
242         verifyWithInlineConfigParser(
243                 getPath("InputAbstractJavadocPositionWithSinglelineCommentsTwo.java"), expected);
244         assertWithMessage("Invalid number of javadocs")
245             .that(JavadocCatchCheck.javadocsNumber)
246             .isEqualTo(29);
247     }
248 
249     @Test
250     public void testPositionWithSinglelineCommentsThree() throws Exception {
251         JavadocCatchCheck.clearCounter();
252         final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
253         verifyWithInlineConfigParser(
254                 getPath("InputAbstractJavadocPositionWithSinglelineCommentsThree.java"), expected);
255         assertWithMessage("Invalid number of javadocs")
256             .that(JavadocCatchCheck.javadocsNumber)
257             .isEqualTo(15);
258     }
259 
260     @Test
261     public void testPositionOnlyComments() throws Exception {
262         JavadocCatchCheck.clearCounter();
263         final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
264         verifyWithInlineConfigParser(
265                 getPath("InputAbstractJavadocPositionOnlyComments.java"), expected);
266         assertWithMessage("Invalid number of javadocs")
267             .that(JavadocCatchCheck.javadocsNumber)
268             .isEqualTo(0);
269     }
270 
271     @Test
272     public void testTokens() {
273         final int[] defaultJavadocTokens = {JavadocCommentsTokenTypes.JAVADOC_CONTENT};
274         final AbstractJavadocCheck check = new AbstractJavadocCheck() {
275             @Override
276             public void visitJavadocToken(DetailNode ast) {
277                 // no code necessary
278             }
279 
280             @Override
281             public int[] getDefaultJavadocTokens() {
282                 return defaultJavadocTokens;
283             }
284         };
285 
286         assertWithMessage("Default tokens should not be null")
287             .that(check.getDefaultTokens())
288             .isNotNull();
289         assertWithMessage("Acceptable tokens should be equal to default")
290             .that(check.getAcceptableTokens())
291             .isEqualTo(check.getDefaultTokens());
292         assertWithMessage("Required tokens should be equal to default")
293             .that(check.getRequiredTokens())
294             .isEqualTo(check.getDefaultTokens());
295         assertWithMessage("Invalid default javadoc tokens")
296             .that(check.getDefaultJavadocTokens())
297             .isEqualTo(defaultJavadocTokens);
298         assertWithMessage("Invalid acceptable javadoc tokens")
299             .that(check.getAcceptableJavadocTokens())
300             .isEqualTo(defaultJavadocTokens);
301         assertWithMessage("Invalid required javadoc tokens")
302             .that(check.getRequiredJavadocTokens())
303             .isNotEqualTo(defaultJavadocTokens);
304     }
305 
306     @Test
307     public void testTokensFail() {
308         final int[] defaultJavadocTokens = {JavadocCommentsTokenTypes.JAVADOC_CONTENT,
309             JavadocCommentsTokenTypes.JAVADOC_INLINE_TAG_END,
310             JavadocCommentsTokenTypes.HTML_COMMENT,
311             JavadocCommentsTokenTypes.HTML_ELEMENT,
312             JavadocCommentsTokenTypes.RETURN_BLOCK_TAG,
313             JavadocCommentsTokenTypes.NEWLINE};
314         final AbstractJavadocCheck check = new AbstractJavadocCheck() {
315             @Override
316             public void visitJavadocToken(DetailNode ast) {
317                 // no code necessary
318             }
319 
320             @Override
321             public int[] getDefaultJavadocTokens() {
322                 return defaultJavadocTokens;
323             }
324         };
325         check.setJavadocTokens("RETURN_BLOCK_TAG");
326         assertDoesNotThrow(check::init);
327     }
328 
329     @Test
330     public void testAcceptableTokensFail() throws Exception {
331         final String path = getPath("InputAbstractJavadocTokensFail.java");
332         try {
333             final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
334             verifyWithInlineConfigParser(path, expected);
335             assertWithMessage("CheckstyleException is expected").fail();
336         }
337         catch (IllegalStateException exc) {
338             final String expected = "Javadoc Token "
339                     + "\"RETURN_BLOCK_TAG\" was not found in "
340                     + "Acceptable javadoc tokens list in check "
341                     + TokenIsNotInAcceptablesCheck.class.getName();
342             assertWithMessage("Invalid exception, should start with: " + expected)
343                     .that(exc.getMessage())
344                     .startsWith(expected);
345         }
346     }
347 
348     @Test
349     public void testAcceptableTokensPass() throws Exception {
350         final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
351         verifyWithInlineConfigParser(getPath("InputAbstractJavadocTokensPass.java"), expected);
352     }
353 
354     @Test
355     public void testRequiredTokenIsNotInDefaultTokens() throws Exception {
356         final DefaultConfiguration checkConfig =
357             createModuleConfig(RequiredTokenIsNotInDefaultsJavadocCheck.class);
358         final String uniqueFileName = "empty_" + UUID.randomUUID() + ".java";
359         final File pathToEmptyFile = new File(temporaryFolder, uniqueFileName);
360 
361         try {
362             execute(checkConfig, pathToEmptyFile.toString());
363             assertWithMessage("CheckstyleException is expected").fail();
364         }
365         catch (IllegalStateException exc) {
366             final String expected = "Javadoc Token \""
367                     + JavadocCommentsTokenTypes.RETURN_BLOCK_TAG + "\" from required"
368                     + " javadoc tokens was not found in default javadoc tokens list in check "
369                     + RequiredTokenIsNotInDefaultsJavadocCheck.class.getName();
370             assertWithMessage("Invalid exception, should start with: " + expected)
371                     .that(exc.getMessage())
372                     .startsWith(expected);
373         }
374     }
375 
376     @Test
377     public void testVisitLeaveTokenOne() throws Exception {
378         JavadocVisitLeaveCheck.clearCounter();
379         final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
380         verifyWithInlineConfigParser(getPath("InputAbstractJavadocLeaveTokenOne.java"), expected);
381         assertWithMessage("Javadoc visit count should be greater than zero")
382                 .that(JavadocVisitLeaveCheck.visitCount)
383                 .isGreaterThan(0);
384         assertWithMessage("Javadoc visit and leave count should be equal")
385             .that(JavadocVisitLeaveCheck.leaveCount)
386             .isEqualTo(JavadocVisitLeaveCheck.visitCount);
387     }
388 
389     @Test
390     public void testVisitLeaveTokenTwo() throws Exception {
391         JavadocVisitLeaveCheck.clearCounter();
392         final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
393         verifyWithInlineConfigParser(getPath("InputAbstractJavadocLeaveTokenTwo.java"), expected);
394         assertWithMessage("Javadoc visit count should be greater than zero")
395                 .that(JavadocVisitLeaveCheck.visitCount)
396                 .isGreaterThan(0);
397         assertWithMessage("Javadoc visit and leave count should be equal")
398             .that(JavadocVisitLeaveCheck.leaveCount)
399             .isEqualTo(JavadocVisitLeaveCheck.visitCount);
400     }
401 
402     @Test
403     public void testVisitLeaveTokenThree() throws Exception {
404         JavadocVisitLeaveCheck.clearCounter();
405         final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
406         verifyWithInlineConfigParser(getPath("InputAbstractJavadocLeaveTokenThree.java"), expected);
407         assertWithMessage("Javadoc visit count should be greater than zero")
408                 .that(JavadocVisitLeaveCheck.visitCount)
409                 .isGreaterThan(0);
410         assertWithMessage("Javadoc visit and leave count should be equal")
411             .that(JavadocVisitLeaveCheck.leaveCount)
412             .isEqualTo(JavadocVisitLeaveCheck.visitCount);
413     }
414 
415     @Test
416     public void testNoWsBeforeDescriptionInJavadocTags() throws Exception {
417         final String[] expected = {
418             "27: " + getCheckMessage(MSG_JAVADOC_PARSE_RULE_ERROR,
419                     29, "token recognition error at: '-'", "fieldName"),
420             "40: " + getCheckMessage(MSG_JAVADOC_PARSE_RULE_ERROR,
421                     30, "token recognition error at: '-'", " "),
422             "72: " + getCheckMessage(MSG_JAVADOC_PARSE_RULE_ERROR,
423                     32, "mismatched input 'description' expecting <EOF>", "JAVADOC"),
424             "88: " + getCheckMessage(MSG_JAVADOC_PARSE_RULE_ERROR,
425                     34, "mismatched input 'description' "
426                              + "expecting JAVADOC_INLINE_TAG_END", "INLINE_TAG"),
427             "95: " + getCheckMessage(MSG_JAVADOC_PARSE_RULE_ERROR,
428                     39, "mismatched input 'description'"
429                             + " expecting JAVADOC_INLINE_TAG_END", "INLINE_TAG"),
430         };
431         verifyWithInlineConfigParser(
432                 getPath("InputAbstractJavadocNoWsBeforeDescriptionInJavadocTags.java"),
433                 expected);
434     }
435 
436     @Test
437     public void testNonTightHtmlTagIntolerantCheckOne() throws Exception {
438         final String[] expected = {
439             "12: " + getCheckMessage(MSG_UNCLOSED_HTML_TAG, "p"),
440             "19: " + getCheckMessage(MSG_UNCLOSED_HTML_TAG, "p"),
441             "22: " + getCheckMessage(MSG_UNCLOSED_HTML_TAG, "li"),
442             "28: " + getCheckMessage(MSG_UNCLOSED_HTML_TAG, "p"),
443             "35: " + getCheckMessage(MSG_UNCLOSED_HTML_TAG, "tr"),
444             "54: " + getCheckMessage(MSG_UNCLOSED_HTML_TAG, "p"),
445             "64: " + getCheckMessage(MSG_UNCLOSED_HTML_TAG, "tr"),
446         };
447         verifyWithInlineConfigParser(
448                 getPath("InputAbstractJavadocNonTightHtmlTagsOne.java"), expected);
449     }
450 
451     @Test
452     public void testNonTightHtmlTagIntolerantCheckTwo() throws Exception {
453         final String[] expected = {
454             "12: " + getCheckMessage(MSG_UNCLOSED_HTML_TAG, "p"),
455             "19: " + getCheckMessage(MSG_UNCLOSED_HTML_TAG, "p"),
456             "25: " + getCheckMessage(MSG_UNCLOSED_HTML_TAG, "li"),
457             "46: " + getCheckMessage(MSG_UNCLOSED_HTML_TAG, "li"),
458             "80: " + getCheckMessage(MSG_UNCLOSED_HTML_TAG, "p"),
459         };
460         verifyWithInlineConfigParser(
461                 getPath("InputAbstractJavadocNonTightHtmlTagsTwo.java"), expected);
462     }
463 
464     @Test
465     public void testNonTightHtmlTagIntolerantCheckReportingNoViolationOne() throws Exception {
466         final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
467         verifyWithInlineConfigParser(
468                 getPath("InputAbstractJavadocNonTightHtmlTagsNoViolationOne.java"), expected);
469     }
470 
471     @Test
472     public void testNonTightHtmlTagIntolerantCheckReportingNoViolationTwo() throws Exception {
473         final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
474         verifyWithInlineConfigParser(
475                 getPath("InputAbstractJavadocNonTightHtmlTagsNoViolationTwo.java"), expected);
476     }
477 
478     @Test
479     public void testNonTightHtmlTagIntolerantCheckVisitCountOne() throws Exception {
480         final String[] expected = {
481             "13: " + getCheckMessage(MSG_UNCLOSED_HTML_TAG, "p"),
482             "28: " + getCheckMessage(MSG_UNCLOSED_HTML_TAG, "p"),
483             "35: " + getCheckMessage(MSG_UNCLOSED_HTML_TAG, "tr"),
484             "47: " + getCheckMessage(MSG_UNCLOSED_HTML_TAG, "p"),
485             "55: " + getCheckMessage(MSG_UNCLOSED_HTML_TAG, "p"),
486             "65: " + getCheckMessage(MSG_UNCLOSED_HTML_TAG, "tr"),
487             "77:8: " + getCheckMessage(NonTightHtmlTagCheck.MSG_KEY, "SEE_BLOCK_TAG"),
488         };
489         verifyWithInlineConfigParser(
490                 getPath("InputAbstractJavadocNonTightHtmlTagsVisitCountOne.java"),
491                 expected);
492     }
493 
494     @Test
495     public void testNonTightHtmlTagIntolerantCheckVisitCountTwo() throws Exception {
496         final String[] expected = {
497             "13: " + getCheckMessage(MSG_UNCLOSED_HTML_TAG, "p"),
498             "47: " + getCheckMessage(MSG_UNCLOSED_HTML_TAG, "li"),
499             "57:8: " + getCheckMessage(NonTightHtmlTagCheck.MSG_KEY, "SEE_BLOCK_TAG"),
500             "82: " + getCheckMessage(MSG_UNCLOSED_HTML_TAG, "p"),
501         };
502         verifyWithInlineConfigParser(
503                 getPath("InputAbstractJavadocNonTightHtmlTagsVisitCountTwo.java"),
504                 expected);
505     }
506 
507     @Test
508     public void testVisitCountForCheckAcceptingJavadocWithNonTightHtml() throws Exception {
509         final String[] expected = {
510             "14: " + getCheckMessage(MSG_UNCLOSED_HTML_TAG, "p"),
511             "23: " + getCheckMessage(MSG_UNCLOSED_HTML_TAG, "p"),
512             "27: " + getCheckMessage(MSG_JAVADOC_PARSE_RULE_ERROR, 68,
513                     "no viable alternative at input '</'", "HTML_ELEMENT"),
514             "34: " + getCheckMessage(MSG_UNCLOSED_HTML_TAG, "p"),
515             "48: " + getCheckMessage(MSG_UNCLOSED_HTML_TAG, "li"),
516             "66: " + getCheckMessage(MSG_UNCLOSED_HTML_TAG, "p"),
517             "66:8: " + getCheckMessage(NonTightHtmlTagCheck.MSG_KEY, "PARAM_BLOCK_TAG"),
518             "78: " + getCheckMessage(MSG_UNCLOSED_HTML_TAG, "tr"),
519         };
520         verifyWithInlineConfigParser(
521                 getPath("InputAbstractJavadocNonTightHtmlTags2.java"), expected);
522     }
523 
524     @Test
525     public void testVisitCountForCheckAcceptingJavadocWithNonTightHtml3() throws Exception {
526         final String[] expected = {
527             "15:8: " + getCheckMessage(NonTightHtmlTagCheck.MSG_KEY, "PARAM_BLOCK_TAG"),
528             "30:8: " + getCheckMessage(NonTightHtmlTagCheck.MSG_KEY, "PARAM_BLOCK_TAG"),
529             "36: " + getCheckMessage(MSG_UNCLOSED_HTML_TAG, "p"),
530             "38:8: " + getCheckMessage(NonTightHtmlTagCheck.MSG_KEY, "PARAM_BLOCK_TAG"),
531         };
532         verifyWithInlineConfigParser(
533                 getPath("InputAbstractJavadocNonTightHtmlTags3.java"), expected);
534     }
535 
536     @Test
537     public void testLeaveJavadocToken() throws Exception {
538         final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
539         verifyWithInlineConfigParser(
540                 getPath("InputAbstractJavadocLeaveToken.java"), expected);
541     }
542 
543     public static class JavadocLeaveTokenCheck extends AbstractJavadocCheck {
544 
545         private static int visitCount;
546         private static int leaveCount;
547 
548         @Override
549         public int[] getDefaultJavadocTokens() {
550             return new int[] {JavadocCommentsTokenTypes.HTML_ELEMENT};
551         }
552 
553         @Override
554         public void visitJavadocToken(DetailNode ast) {
555             visitCount++;
556         }
557 
558         @Override
559         public void leaveJavadocToken(DetailNode ast) {
560             leaveCount++;
561         }
562 
563         @Override
564         public void finishJavadocTree(DetailNode ast) {
565             if (visitCount != leaveCount) {
566                 throw new IllegalStateException("mismatch in visitCount and leaveCount");
567             }
568         }
569     }
570 
571     public static class ParseJavadocOnlyCheck extends AbstractJavadocCheck {
572 
573         @Override
574         public int[] getDefaultJavadocTokens() {
575             return CommonUtil.EMPTY_INT_ARRAY;
576         }
577 
578         @Override
579         public void visitJavadocToken(DetailNode ast) {
580             // do nothing
581         }
582 
583     }
584 
585     public static class JavadocCatchCheck extends AbstractJavadocCheck {
586         private static int javadocsNumber;
587 
588         public static void clearCounter() {
589             javadocsNumber = 0;
590         }
591 
592         @Override
593         public int[] getDefaultJavadocTokens() {
594             return new int[] {JavadocCommentsTokenTypes.JAVADOC_CONTENT};
595         }
596 
597         @Override
598         public void visitJavadocToken(DetailNode ast) {
599             assertWithMessage(ast.toString())
600                 .that(ast.getText())
601                 .isEqualTo("JAVADOC_CONTENT");
602             final DetailNode text = JavadocUtil.findFirstToken(ast, JavadocCommentsTokenTypes.TEXT);
603             assertWithMessage("Empty javadoc text at " + ast)
604                 .that(text)
605                 .isNotNull();
606             assertWithMessage(ast.toString())
607                 .that(text.getText())
608                 .isEqualTo("Javadoc");
609             javadocsNumber++;
610         }
611 
612     }
613 
614     public static class RequiredTokenIsNotInDefaultsJavadocCheck extends AbstractJavadocCheck {
615 
616         @Override
617         public int[] getRequiredJavadocTokens() {
618             return new int[] {JavadocCommentsTokenTypes.RETURN_BLOCK_TAG};
619         }
620 
621         @Override
622         public int[] getDefaultJavadocTokens() {
623             return new int[] {JavadocCommentsTokenTypes.DEPRECATED_BLOCK_TAG};
624         }
625 
626         @Override
627         public int[] getAcceptableJavadocTokens() {
628             return CommonUtil.EMPTY_INT_ARRAY;
629         }
630 
631         @Override
632         public void visitJavadocToken(DetailNode ast) {
633             // not used
634         }
635 
636     }
637 
638     public static class TokenIsNotInAcceptablesCheck extends AbstractJavadocCheck {
639 
640         @Override
641         public int[] getRequiredJavadocTokens() {
642             return new int[] {JavadocCommentsTokenTypes.DEPRECATED_BLOCK_TAG};
643         }
644 
645         @Override
646         public int[] getDefaultJavadocTokens() {
647             return new int[] {JavadocCommentsTokenTypes.DEPRECATED_BLOCK_TAG};
648         }
649 
650         @Override
651         public int[] getAcceptableJavadocTokens() {
652             return new int[] {JavadocCommentsTokenTypes.DEPRECATED_BLOCK_TAG};
653         }
654 
655         @Override
656         public void visitJavadocToken(DetailNode ast) {
657             // not used
658         }
659 
660     }
661 
662     public static class JavadocVisitLeaveCheck extends AbstractJavadocCheck {
663 
664         private static int visitCount;
665         private static int leaveCount;
666 
667         public static void clearCounter() {
668             visitCount = 0;
669             leaveCount = 0;
670         }
671 
672         @Override
673         public int[] getRequiredJavadocTokens() {
674             return new int[] {JavadocCommentsTokenTypes.TEXT};
675         }
676 
677         @Override
678         public int[] getDefaultJavadocTokens() {
679             return getRequiredJavadocTokens();
680         }
681 
682         @Override
683         public int[] getAcceptableJavadocTokens() {
684             return getRequiredJavadocTokens();
685         }
686 
687         @Override
688         public void visitJavadocToken(DetailNode ast) {
689             visitCount++;
690         }
691 
692         @Override
693         public void leaveJavadocToken(DetailNode ast) {
694             leaveCount++;
695         }
696 
697     }
698 
699     public static class NonTightHtmlTagCheck extends AbstractJavadocCheck {
700         // extra variable to make it explicit in test expected array
701         // that message is from NonTightHtmlTagCheck
702         public static final String MSG_KEY = MSG_TAG_FORMAT;
703 
704         private boolean reportVisitJavadocToken;
705 
706         public final void setReportVisitJavadocToken(boolean reportVisitJavadocToken) {
707             this.reportVisitJavadocToken = reportVisitJavadocToken;
708         }
709 
710         @Override
711         public int[] getDefaultJavadocTokens() {
712             return new int[] {
713                 JavadocCommentsTokenTypes.SEE_BLOCK_TAG,
714             };
715         }
716 
717         @Override
718         public void visitJavadocToken(DetailNode ast) {
719             if (reportVisitJavadocToken) {
720                 // We're reusing messages from JavadocTypeCheck
721                 // it is not possible to use test specific bundle of messages
722                 log(ast.getLineNumber(), ast.getColumnNumber(), MSG_TAG_FORMAT, ast.getText());
723             }
724         }
725 
726         @Override
727         public boolean acceptJavadocWithNonTightHtml() {
728             return false;
729         }
730     }
731 
732     public static class NonTightHtmlTagTolerantCheck extends AbstractJavadocCheck {
733         // extra variable to make it explicit in test expected array
734         // that message is from NonTightHtmlTagCheck
735         public static final String MSG_KEY = MSG_TAG_FORMAT;
736 
737         private boolean reportVisitJavadocToken;
738 
739         public final void setReportVisitJavadocToken(boolean reportVisitJavadocToken) {
740             this.reportVisitJavadocToken = reportVisitJavadocToken;
741         }
742 
743         @Override
744         public int[] getDefaultJavadocTokens() {
745             return new int[] {
746                 JavadocCommentsTokenTypes.PARAM_BLOCK_TAG,
747             };
748         }
749 
750         @Override
751         public void visitJavadocToken(DetailNode ast) {
752             if (reportVisitJavadocToken) {
753                 // We reusing messages from JavadocTypeCheck
754                 // it is not possible to use test specific bundle of messages
755                 log(ast.getLineNumber(), ast.getColumnNumber(), MSG_TAG_FORMAT, ast.getText());
756             }
757         }
758 
759     }
760 }