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