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