View Javadoc
1   ///////////////////////////////////////////////////////////////////////////////////////////////
2   // checkstyle: Checks Java source code and other text files for adherence to a set of rules.
3   // Copyright (C) 2001-2024 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       * <p>Configures the environment for each test.</p>
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              "68: " + getCheckMessage(MSG_JAVADOC_PARSE_RULE_ERROR, 13,
85                      "mismatched input '}' expecting {LEADING_ASTERISK, WS, NEWLINE}",
86                      "JAVADOC_INLINE_TAG"),
87              "78: " + getCheckMessage(MSG_JAVADOC_PARSE_RULE_ERROR, 19,
88                      "no viable alternative at input '}'", "REFERENCE"),
89          };
90          verifyWithInlineConfigParser(
91                  getPath("InputAbstractJavadocJavadocTagsWithoutArgs.java"), expected);
92      }
93  
94      @Test
95      public void testNumberFormatException() throws Exception {
96          final String[] expected = {
97              "8: " + getCheckMessage(MSG_JAVADOC_PARSE_RULE_ERROR, 52,
98                      "mismatched input ';' expecting MEMBER", "REFERENCE"),
99          };
100         verifyWithInlineConfigParser(
101                 getPath("InputAbstractJavadocNumberFormatException.java"), expected);
102     }
103 
104     @Test
105     public void testCustomTag() throws Exception {
106         final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
107         verifyWithInlineConfigParser(getPath("InputAbstractJavadocCustomTag.java"), expected);
108     }
109 
110     @Test
111     public void testParsingErrors(@SysErr Capturable systemErr) throws Exception {
112         final String[] expected = {
113             "9: " + getCheckMessage(MSG_JAVADOC_MISSED_HTML_CLOSE, 4, "unclosedTag"),
114             "16: " + getCheckMessage(MSG_JAVADOC_WRONG_SINGLETON_TAG, 35, "img"),
115         };
116         verifyWithInlineConfigParser(getPath("InputAbstractJavadocParsingErrors.java"), expected);
117         assertWithMessage("Error is unexpected")
118             .that(systemErr.getCapturedData())
119             .isEqualTo("");
120     }
121 
122     @Test
123     public void testWithMultipleChecksOne() throws Exception {
124         verifyWithInlineConfigParser(
125                 getPath("InputAbstractJavadocCorrectParagraphOne.java"),
126                 CommonUtil.EMPTY_STRING_ARRAY);
127     }
128 
129     @Test
130     public void testWithMultipleChecksTwo() throws Exception {
131         verifyWithInlineConfigParser(
132                 getPath("InputAbstractJavadocCorrectParagraphTwo.java"),
133                 CommonUtil.EMPTY_STRING_ARRAY);
134     }
135 
136     @Test
137     public void testAntlrError(@SysErr Capturable systemErr) throws Exception {
138         final String[] expected = {
139             "9: " + getCheckMessage(MSG_JAVADOC_PARSE_RULE_ERROR, 78,
140                     "mismatched input '(' expecting <EOF>", "JAVADOC"),
141         };
142         verifyWithInlineConfigParser(
143                 getPath("InputAbstractJavadocInvalidAtSeeReference.java"), expected);
144         assertWithMessage("Error is unexpected")
145             .that(systemErr.getCapturedData())
146             .isEqualTo("");
147     }
148 
149     @Test
150     public void testCheckReuseAfterParseErrorWithFollowingAntlrErrorInTwoFiles(
151             @SysErr Capturable systemErr) throws Exception {
152         final String[] expectedMessagesForFile1 = {
153             "9: " + getCheckMessage(MSG_JAVADOC_MISSED_HTML_CLOSE, 4, "unclosedTag"),
154             "16: " + getCheckMessage(MSG_JAVADOC_WRONG_SINGLETON_TAG, 35, "img"),
155         };
156         verifyWithInlineConfigParser(getPath(
157                 "InputAbstractJavadocParsingErrors2.java"), expectedMessagesForFile1);
158 
159         final String[] expectedMessagesForFile2 = {
160             "9: " + getCheckMessage(MSG_JAVADOC_PARSE_RULE_ERROR, 78,
161                     "mismatched input '(' expecting <EOF>", "JAVADOC"),
162         };
163         verifyWithInlineConfigParser(getPath(
164                 "InputAbstractJavadocInvalidAtSeeReference2.java"), expectedMessagesForFile2);
165 
166         assertWithMessage("Error is unexpected")
167                 .that(systemErr.getCapturedData())
168                 .isEqualTo("");
169     }
170 
171     @Test
172     public void testCheckReuseAfterParseErrorWithFollowingAntlrErrorInSingleFile()
173             throws Exception {
174         final String[] expected = {
175             "9: " + getCheckMessage(MSG_JAVADOC_MISSED_HTML_CLOSE, 4, "unclosedTag"),
176             "16: " + getCheckMessage(MSG_JAVADOC_PARSE_RULE_ERROR, 82,
177                     "mismatched input '(' expecting <EOF>", "JAVADOC"),
178         };
179         verifyWithInlineConfigParser(
180             getPath("InputAbstractJavadocUnclosedTagAndInvalidAtSeeReference.java"), expected);
181     }
182 
183     @Test
184     public void testCache() throws Exception {
185         final String[] expected = {
186             "12: " + getCheckMessage(SummaryJavadocCheck.class, MSG_SUMMARY_FIRST_SENTENCE),
187         };
188         verifyWithInlineConfigParser(getPath("InputAbstractJavadocCache1.java"),
189             getPath("InputAbstractJavadocCache2.java"), expected);
190     }
191 
192     @Test
193     public void testPositionOne() throws Exception {
194         JavadocCatchCheck.clearCounter();
195         final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
196         verifyWithInlineConfigParser(getPath("InputAbstractJavadocPositionOne.java"), expected);
197         assertWithMessage("Invalid number of javadocs")
198             .that(JavadocCatchCheck.javadocsNumber)
199             .isEqualTo(21);
200     }
201 
202     @Test
203     public void testPositionTwo() throws Exception {
204         JavadocCatchCheck.clearCounter();
205         final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
206         verifyWithInlineConfigParser(getPath("InputAbstractJavadocPositionTwo.java"), expected);
207         assertWithMessage("Invalid number of javadocs")
208             .that(JavadocCatchCheck.javadocsNumber)
209             .isEqualTo(29);
210     }
211 
212     @Test
213     public void testPositionThree() throws Exception {
214         JavadocCatchCheck.clearCounter();
215         final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
216         verifyWithInlineConfigParser(getPath("InputAbstractJavadocPositionThree.java"), expected);
217         assertWithMessage("Invalid number of javadocs")
218             .that(JavadocCatchCheck.javadocsNumber)
219             .isEqualTo(15);
220     }
221 
222     @Test
223     public void testPositionWithSinglelineCommentsOne() throws Exception {
224         JavadocCatchCheck.clearCounter();
225         final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
226         verifyWithInlineConfigParser(
227                 getPath("InputAbstractJavadocPositionWithSinglelineCommentsOne.java"), expected);
228         assertWithMessage("Invalid number of javadocs")
229             .that(JavadocCatchCheck.javadocsNumber)
230             .isEqualTo(21);
231     }
232 
233     @Test
234     public void testPositionWithSinglelineCommentsTwo() throws Exception {
235         JavadocCatchCheck.clearCounter();
236         final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
237         verifyWithInlineConfigParser(
238                 getPath("InputAbstractJavadocPositionWithSinglelineCommentsTwo.java"), expected);
239         assertWithMessage("Invalid number of javadocs")
240             .that(JavadocCatchCheck.javadocsNumber)
241             .isEqualTo(29);
242     }
243 
244     @Test
245     public void testPositionWithSinglelineCommentsThree() throws Exception {
246         JavadocCatchCheck.clearCounter();
247         final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
248         verifyWithInlineConfigParser(
249                 getPath("InputAbstractJavadocPositionWithSinglelineCommentsThree.java"), expected);
250         assertWithMessage("Invalid number of javadocs")
251             .that(JavadocCatchCheck.javadocsNumber)
252             .isEqualTo(15);
253     }
254 
255     @Test
256     public void testPositionOnlyComments() throws Exception {
257         JavadocCatchCheck.clearCounter();
258         final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
259         verifyWithInlineConfigParser(
260                 getPath("InputAbstractJavadocPositionOnlyComments.java"), expected);
261         assertWithMessage("Invalid number of javadocs")
262             .that(JavadocCatchCheck.javadocsNumber)
263             .isEqualTo(0);
264     }
265 
266     @Test
267     public void testTokens() {
268         final int[] defaultJavadocTokens = {JavadocTokenTypes.JAVADOC};
269         final AbstractJavadocCheck check = new AbstractJavadocCheck() {
270             @Override
271             public void visitJavadocToken(DetailNode ast) {
272                 // no code necessary
273             }
274 
275             @Override
276             public int[] getDefaultJavadocTokens() {
277                 return defaultJavadocTokens;
278             }
279         };
280 
281         assertWithMessage("Default tokens should not be null")
282             .that(check.getDefaultTokens())
283             .isNotNull();
284         assertWithMessage("Acceptable tokens should be equal to default")
285             .that(check.getAcceptableTokens())
286             .isEqualTo(check.getDefaultTokens());
287         assertWithMessage("Required tokens should be equal to default")
288             .that(check.getRequiredTokens())
289             .isEqualTo(check.getDefaultTokens());
290         assertWithMessage("Invalid default javadoc tokens")
291             .that(check.getDefaultJavadocTokens())
292             .isEqualTo(defaultJavadocTokens);
293         assertWithMessage("Invalid acceptable javadoc tokens")
294             .that(check.getAcceptableJavadocTokens())
295             .isEqualTo(defaultJavadocTokens);
296         assertWithMessage("Invalid required javadoc tokens")
297             .that(check.getRequiredJavadocTokens())
298             .isNotEqualTo(defaultJavadocTokens);
299     }
300 
301     @Test
302     public void testTokensFail() {
303         final int[] defaultJavadocTokens = {JavadocTokenTypes.JAVADOC,
304             JavadocTokenTypes.AREA_HTML_TAG_NAME,
305             JavadocTokenTypes.PARAGRAPH,
306             JavadocTokenTypes.HR_TAG,
307             JavadocTokenTypes.RETURN_LITERAL,
308             JavadocTokenTypes.BR_TAG};
309         final AbstractJavadocCheck check = new AbstractJavadocCheck() {
310             @Override
311             public void visitJavadocToken(DetailNode ast) {
312                 // no code necessary
313             }
314 
315             @Override
316             public int[] getDefaultJavadocTokens() {
317                 return defaultJavadocTokens;
318             }
319         };
320         check.setJavadocTokens("RETURN_LITERAL");
321         assertDoesNotThrow(check::init);
322     }
323 
324     @Test
325     public void testAcceptableTokensFail() throws Exception {
326         final String path = getPath("InputAbstractJavadocTokensFail.java");
327         try {
328             final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
329             verifyWithInlineConfigParser(path, expected);
330             assertWithMessage("CheckstyleException is expected").fail();
331         }
332         catch (IllegalStateException ex) {
333             final String expected = "Javadoc Token "
334                     + "\"RETURN_LITERAL\" was not found in "
335                     + "Acceptable javadoc tokens list in check "
336                     + TokenIsNotInAcceptablesCheck.class.getName();
337             assertWithMessage("Invalid exception, should start with: " + expected)
338                     .that(ex.getMessage())
339                     .startsWith(expected);
340         }
341     }
342 
343     @Test
344     public void testAcceptableTokensPass() throws Exception {
345         final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
346         verifyWithInlineConfigParser(getPath("InputAbstractJavadocTokensPass.java"), expected);
347     }
348 
349     @Test
350     public void testRequiredTokenIsNotInDefaultTokens() throws Exception {
351         final DefaultConfiguration checkConfig =
352             createModuleConfig(RequiredTokenIsNotInDefaultsJavadocCheck.class);
353         final String uniqueFileName = "empty_" + UUID.randomUUID() + ".java";
354         final File pathToEmptyFile = new File(temporaryFolder, uniqueFileName);
355 
356         try {
357             execute(checkConfig, pathToEmptyFile.toString());
358             assertWithMessage("CheckstyleException is expected").fail();
359         }
360         catch (IllegalStateException ex) {
361             final String expected = "Javadoc Token \""
362                     + JavadocTokenTypes.RETURN_LITERAL + "\" from required"
363                     + " javadoc tokens was not found in default javadoc tokens list in check "
364                     + RequiredTokenIsNotInDefaultsJavadocCheck.class.getName();
365             assertWithMessage("Invalid exception, should start with: " + expected)
366                     .that(ex.getMessage())
367                     .startsWith(expected);
368         }
369     }
370 
371     @Test
372     public void testVisitLeaveTokenOne() throws Exception {
373         JavadocVisitLeaveCheck.clearCounter();
374         final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
375         verifyWithInlineConfigParser(getPath("InputAbstractJavadocLeaveTokenOne.java"), expected);
376         assertWithMessage("Javadoc visit count should be greater than zero")
377                 .that(JavadocVisitLeaveCheck.visitCount)
378                 .isGreaterThan(0);
379         assertWithMessage("Javadoc visit and leave count should be equal")
380             .that(JavadocVisitLeaveCheck.leaveCount)
381             .isEqualTo(JavadocVisitLeaveCheck.visitCount);
382     }
383 
384     @Test
385     public void testVisitLeaveTokenTwo() throws Exception {
386         JavadocVisitLeaveCheck.clearCounter();
387         final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
388         verifyWithInlineConfigParser(getPath("InputAbstractJavadocLeaveTokenTwo.java"), expected);
389         assertWithMessage("Javadoc visit count should be greater than zero")
390                 .that(JavadocVisitLeaveCheck.visitCount)
391                 .isGreaterThan(0);
392         assertWithMessage("Javadoc visit and leave count should be equal")
393             .that(JavadocVisitLeaveCheck.leaveCount)
394             .isEqualTo(JavadocVisitLeaveCheck.visitCount);
395     }
396 
397     @Test
398     public void testVisitLeaveTokenThree() throws Exception {
399         JavadocVisitLeaveCheck.clearCounter();
400         final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
401         verifyWithInlineConfigParser(getPath("InputAbstractJavadocLeaveTokenThree.java"), expected);
402         assertWithMessage("Javadoc visit count should be greater than zero")
403                 .that(JavadocVisitLeaveCheck.visitCount)
404                 .isGreaterThan(0);
405         assertWithMessage("Javadoc visit and leave count should be equal")
406             .that(JavadocVisitLeaveCheck.leaveCount)
407             .isEqualTo(JavadocVisitLeaveCheck.visitCount);
408     }
409 
410     @Test
411     public void testNoWsBeforeDescriptionInJavadocTags() throws Exception {
412         final String[] expected = {
413             "18: " + getCheckMessage(MSG_JAVADOC_PARSE_RULE_ERROR,
414                     23, "mismatched input 'd' expecting <EOF>", "JAVADOC"),
415             "29: " + getCheckMessage(MSG_JAVADOC_PARSE_RULE_ERROR,
416                     30, "mismatched input '-' expecting <EOF>", "JAVADOC"),
417             "37: " + getCheckMessage(MSG_JAVADOC_PARSE_RULE_ERROR,
418                     39, "mismatched input '-' expecting <EOF>", "JAVADOC"),
419             "51: " + getCheckMessage(MSG_JAVADOC_PARSE_RULE_ERROR,
420                     34, "mismatched input '-' expecting <EOF>", "JAVADOC"),
421             "61: " + getCheckMessage(MSG_JAVADOC_PARSE_RULE_ERROR,
422                     31, "mismatched input '-' expecting <EOF>", "JAVADOC"),
423             "72: " + getCheckMessage(MSG_JAVADOC_PARSE_RULE_ERROR,
424                     15, "mismatched input '-' expecting <EOF>", "JAVADOC"),
425             "81: " + getCheckMessage(MSG_JAVADOC_PARSE_RULE_ERROR,
426                     32, "mismatched input '-' expecting <EOF>", "JAVADOC"),
427             "92: " + getCheckMessage(MSG_JAVADOC_PARSE_RULE_ERROR,
428                     17, "mismatched input '<' expecting <EOF>", "JAVADOC"),
429             "99: " + getCheckMessage(MSG_JAVADOC_PARSE_RULE_ERROR,
430                     34, "no viable alternative at input '-'", "JAVADOC_INLINE_TAG"),
431             "106: " + getCheckMessage(MSG_JAVADOC_PARSE_RULE_ERROR,
432                     39, "no viable alternative at input '-'", "JAVADOC_INLINE_TAG"),
433             "114: " + getCheckMessage(MSG_JAVADOC_PARSE_RULE_ERROR,
434                     19, "no viable alternative at input '<'", "JAVADOC_INLINE_TAG"),
435         };
436         verifyWithInlineConfigParser(
437                 getPath("InputAbstractJavadocNoWsBeforeDescriptionInJavadocTags.java"),
438                 expected);
439     }
440 
441     @Test
442     public void testWrongSingletonTagInJavadoc() throws Exception {
443         final String[] expected = {
444             "10: " + getCheckMessage(MSG_JAVADOC_WRONG_SINGLETON_TAG, 9, "embed"),
445             "17: " + getCheckMessage(MSG_JAVADOC_WRONG_SINGLETON_TAG, 9, "keygen"),
446             "24: " + getCheckMessage(MSG_JAVADOC_WRONG_SINGLETON_TAG, 9, "SOURCE"),
447             "31: " + getCheckMessage(MSG_JAVADOC_WRONG_SINGLETON_TAG, 9, "TRACK"),
448             "38: " + getCheckMessage(MSG_JAVADOC_WRONG_SINGLETON_TAG, 9, "WBR"),
449         };
450         verifyWithInlineConfigParser(getPath("InputAbstractJavadocWrongSingletonTagInJavadoc.java"),
451                 expected);
452     }
453 
454     @Test
455     public void testNonTightHtmlTagIntolerantCheckOne() throws Exception {
456         final String[] expected = {
457             "12: " + getCheckMessage(MSG_UNCLOSED_HTML_TAG, "p"),
458             "19: " + getCheckMessage(MSG_UNCLOSED_HTML_TAG, "p"),
459             "22: " + getCheckMessage(MSG_UNCLOSED_HTML_TAG, "li"),
460             "28: " + getCheckMessage(MSG_UNCLOSED_HTML_TAG, "p"),
461             "35: " + getCheckMessage(MSG_UNCLOSED_HTML_TAG, "tr"),
462             "54: " + getCheckMessage(MSG_UNCLOSED_HTML_TAG, "p"),
463             "64: " + getCheckMessage(MSG_UNCLOSED_HTML_TAG, "tr"),
464         };
465         verifyWithInlineConfigParser(
466                 getPath("InputAbstractJavadocNonTightHtmlTagsOne.java"), expected);
467     }
468 
469     @Test
470     public void testNonTightHtmlTagIntolerantCheckTwo() throws Exception {
471         final String[] expected = {
472             "12: " + getCheckMessage(MSG_UNCLOSED_HTML_TAG, "p"),
473             "19: " + getCheckMessage(MSG_UNCLOSED_HTML_TAG, "p"),
474             "25: " + getCheckMessage(MSG_UNCLOSED_HTML_TAG, "li"),
475             "46: " + getCheckMessage(MSG_UNCLOSED_HTML_TAG, "li"),
476             "80: " + getCheckMessage(MSG_UNCLOSED_HTML_TAG, "p"),
477         };
478         verifyWithInlineConfigParser(
479                 getPath("InputAbstractJavadocNonTightHtmlTagsTwo.java"), expected);
480     }
481 
482     @Test
483     public void testNonTightHtmlTagIntolerantCheckReportingNoViolationOne() throws Exception {
484         final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
485         verifyWithInlineConfigParser(
486                 getPath("InputAbstractJavadocNonTightHtmlTagsNoViolationOne.java"), expected);
487     }
488 
489     @Test
490     public void testNonTightHtmlTagIntolerantCheckReportingNoViolationTwo() throws Exception {
491         final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
492         verifyWithInlineConfigParser(
493                 getPath("InputAbstractJavadocNonTightHtmlTagsNoViolationTwo.java"), expected);
494     }
495 
496     @Test
497     public void testNonTightHtmlTagIntolerantCheckVisitCountOne() throws Exception {
498         final String[] expected = {
499             "13: " + getCheckMessage(MSG_UNCLOSED_HTML_TAG, "p"),
500             "20: " + getCheckMessage(MSG_UNCLOSED_HTML_TAG, "p"),
501             "23: " + getCheckMessage(MSG_UNCLOSED_HTML_TAG, "li"),
502             "29: " + getCheckMessage(MSG_UNCLOSED_HTML_TAG, "p"),
503             "36: " + getCheckMessage(MSG_UNCLOSED_HTML_TAG, "tr"),
504             "46:13: " + getCheckMessage(NonTightHtmlTagCheck.MSG_KEY, "LI_TAG_START"),
505             "56: " + getCheckMessage(MSG_UNCLOSED_HTML_TAG, "p"),
506             "66: " + getCheckMessage(MSG_UNCLOSED_HTML_TAG, "tr"),
507         };
508         verifyWithInlineConfigParser(
509                 getPath("InputAbstractJavadocNonTightHtmlTagsVisitCountOne.java"),
510                 expected);
511     }
512 
513     @Test
514     public void testNonTightHtmlTagIntolerantCheckVisitCountTwo() throws Exception {
515         final String[] expected = {
516             "13: " + getCheckMessage(MSG_UNCLOSED_HTML_TAG, "p"),
517             "20: " + getCheckMessage(MSG_UNCLOSED_HTML_TAG, "p"),
518             "27: " + getCheckMessage(MSG_UNCLOSED_HTML_TAG, "li"),
519             "35:8: " + getCheckMessage(NonTightHtmlTagCheck.MSG_KEY, "BODY_TAG_START"),
520             "49: " + getCheckMessage(MSG_UNCLOSED_HTML_TAG, "li"),
521             "58:8: " + getCheckMessage(NonTightHtmlTagCheck.MSG_KEY, "P_TAG_START"),
522             "65:8: " + getCheckMessage(NonTightHtmlTagCheck.MSG_KEY, "LI_TAG_START"),
523             "69:8: " + getCheckMessage(NonTightHtmlTagCheck.MSG_KEY, "BODY_TAG_START"),
524             "86: " + getCheckMessage(MSG_UNCLOSED_HTML_TAG, "p"),
525         };
526         verifyWithInlineConfigParser(
527                 getPath("InputAbstractJavadocNonTightHtmlTagsVisitCountTwo.java"),
528                 expected);
529     }
530 
531     @Test
532     public void testVisitCountForCheckAcceptingJavadocWithNonTightHtml() throws Exception {
533         final String[] expected = {
534             "11:4: " + getCheckMessage(NonTightHtmlTagCheck.MSG_KEY, "BODY_TAG_START"),
535             "12:4: " + getCheckMessage(NonTightHtmlTagCheck.MSG_KEY, "P_TAG_START"),
536             "14: " + getCheckMessage(MSG_UNCLOSED_HTML_TAG, "p"),
537             "14:4: " + getCheckMessage(NonTightHtmlTagCheck.MSG_KEY, "P_TAG_START"),
538             "15:4: " + getCheckMessage(NonTightHtmlTagCheck.MSG_KEY, "LI_TAG_START"),
539             "15:39: " + getCheckMessage(NonTightHtmlTagCheck.MSG_KEY, "P_TAG_START"),
540             "30: " + getCheckMessage(MSG_UNCLOSED_HTML_TAG, "p"),
541             "30:9: " + getCheckMessage(NonTightHtmlTagCheck.MSG_KEY, "P_TAG_START"),
542             "30:13: " + getCheckMessage(NonTightHtmlTagCheck.MSG_KEY, "P_TAG_START"),
543             "37: " + getCheckMessage(MSG_UNCLOSED_HTML_TAG, "li"),
544             "37:8: " + getCheckMessage(NonTightHtmlTagCheck.MSG_KEY, "LI_TAG_START"),
545             "44:8: " + getCheckMessage(NonTightHtmlTagCheck.MSG_KEY, "P_TAG_START"),
546             "45: " + getCheckMessage(MSG_UNCLOSED_HTML_TAG, "p"),
547             "45:8: " + getCheckMessage(NonTightHtmlTagCheck.MSG_KEY, "LI_TAG_START"),
548             "45:25: " + getCheckMessage(NonTightHtmlTagCheck.MSG_KEY, "P_TAG_START"),
549             "55:8: " + getCheckMessage(NonTightHtmlTagCheck.MSG_KEY, "LI_TAG_START"),
550             "55:22: " + getCheckMessage(NonTightHtmlTagCheck.MSG_KEY, "P_TAG_START"),
551             "56: " + getCheckMessage(MSG_UNCLOSED_HTML_TAG, "tr"),
552             "65:8: " + getCheckMessage(NonTightHtmlTagCheck.MSG_KEY, "P_TAG_START"),
553             "66:8: " + getCheckMessage(NonTightHtmlTagCheck.MSG_KEY, "P_TAG_START"),
554             "67: " + getCheckMessage(MSG_UNCLOSED_HTML_TAG, "li"),
555             "67:8: " + getCheckMessage(NonTightHtmlTagCheck.MSG_KEY, "LI_TAG_START"),
556             "67:23: " + getCheckMessage(NonTightHtmlTagCheck.MSG_KEY, "LI_TAG_START"),
557             "78:8: " + getCheckMessage(NonTightHtmlTagCheck.MSG_KEY, "BODY_TAG_START"),
558             "78:20: " + getCheckMessage(NonTightHtmlTagCheck.MSG_KEY, "P_TAG_START"),
559             "78:34: " + getCheckMessage(NonTightHtmlTagCheck.MSG_KEY, "LI_TAG_START"),
560             "80: " + getCheckMessage(MSG_UNCLOSED_HTML_TAG, "li"),
561             "80:16: " + getCheckMessage(NonTightHtmlTagCheck.MSG_KEY, "LI_TAG_START"),
562             "80:21: " + getCheckMessage(NonTightHtmlTagCheck.MSG_KEY, "LI_TAG_START"),
563             "96:8: " + getCheckMessage(NonTightHtmlTagCheck.MSG_KEY, "P_TAG_START"),
564             "98: " + getCheckMessage(MSG_UNCLOSED_HTML_TAG, "p"),
565             "98:22: " + getCheckMessage(NonTightHtmlTagCheck.MSG_KEY, "P_TAG_START"),
566             "107:8: " + getCheckMessage(NonTightHtmlTagCheck.MSG_KEY, "P_TAG_START"),
567             "108:8: " + getCheckMessage(NonTightHtmlTagCheck.MSG_KEY, "LI_TAG_START"),
568             "111: " + getCheckMessage(MSG_UNCLOSED_HTML_TAG, "tr"),
569         };
570         verifyWithInlineConfigParser(
571                 getPath("InputAbstractJavadocNonTightHtmlTags2.java"), expected);
572     }
573 
574     @Test
575     public void testVisitCountForCheckAcceptingJavadocWithNonTightHtml3() throws Exception {
576         final String[] expected = {
577             "29:8: " + getCheckMessage(NonTightHtmlTagCheck.MSG_KEY, "P_TAG_START"),
578             "36: " + getCheckMessage(MSG_UNCLOSED_HTML_TAG, "p"),
579             "36:9: " + getCheckMessage(NonTightHtmlTagCheck.MSG_KEY, "P_TAG_START"),
580             "36:13: " + getCheckMessage(NonTightHtmlTagCheck.MSG_KEY, "LI_TAG_START"),
581             "36:33: " + getCheckMessage(NonTightHtmlTagCheck.MSG_KEY, "BODY_TAG_START"),
582         };
583         verifyWithInlineConfigParser(
584                 getPath("InputAbstractJavadocNonTightHtmlTags3.java"), expected);
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[] {JavadocTokenTypes.JAVADOC};
611         }
612 
613         @Override
614         public void visitJavadocToken(DetailNode ast) {
615             assertWithMessage(ast.toString())
616                 .that(ast.getText())
617                 .isEqualTo("JAVADOC");
618             final DetailNode text = JavadocUtil.findFirstToken(ast, JavadocTokenTypes.TEXT);
619             assertWithMessage("Empty javadoc text at " + 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[] {JavadocTokenTypes.RETURN_LITERAL};
635         }
636 
637         @Override
638         public int[] getDefaultJavadocTokens() {
639             return new int[] {JavadocTokenTypes.DEPRECATED_LITERAL};
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[] {JavadocTokenTypes.DEPRECATED_LITERAL};
659         }
660 
661         @Override
662         public int[] getDefaultJavadocTokens() {
663             return new int[] {JavadocTokenTypes.DEPRECATED_LITERAL};
664         }
665 
666         @Override
667         public int[] getAcceptableJavadocTokens() {
668             return new int[] {JavadocTokenTypes.DEPRECATED_LITERAL};
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[] {JavadocTokenTypes.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                 JavadocTokenTypes.P_TAG_START,
730                 JavadocTokenTypes.LI_TAG_START,
731                 JavadocTokenTypes.BODY_TAG_START,
732             };
733         }
734 
735         @Override
736         public void visitJavadocToken(DetailNode ast) {
737             if (reportVisitJavadocToken) {
738                 // We reusing messages from JavadocTypeCheck
739                 // it is not possible to use test specific bundle of messages
740                 log(ast.getLineNumber(), ast.getColumnNumber(), MSG_TAG_FORMAT, ast.getText());
741             }
742         }
743 
744         @Override
745         public boolean acceptJavadocWithNonTightHtml() {
746             return false;
747         }
748     }
749 
750     public static class NonTightHtmlTagTolerantCheck extends AbstractJavadocCheck {
751         // extra variable to make it explicit in test expected array
752         // that message is from NonTightHtmlTagCheck
753         public static final String MSG_KEY = MSG_TAG_FORMAT;
754 
755         private boolean reportVisitJavadocToken;
756 
757         public final void setReportVisitJavadocToken(boolean reportVisitJavadocToken) {
758             this.reportVisitJavadocToken = reportVisitJavadocToken;
759         }
760 
761         @Override
762         public int[] getDefaultJavadocTokens() {
763             return new int[] {
764                 JavadocTokenTypes.P_TAG_START,
765                 JavadocTokenTypes.LI_TAG_START,
766                 JavadocTokenTypes.BODY_TAG_START,
767             };
768         }
769 
770         @Override
771         public void visitJavadocToken(DetailNode ast) {
772             if (reportVisitJavadocToken) {
773                 // We reusing messages from JavadocTypeCheck
774                 // it is not possible to use test specific bundle of messages
775                 log(ast.getLineNumber(), ast.getColumnNumber(), MSG_TAG_FORMAT, ast.getText());
776             }
777         }
778 
779     }
780 }