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