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.filters;
21  
22  import static com.google.common.truth.Truth.assertWithMessage;
23  import static com.puppycrawl.tools.checkstyle.checks.naming.AbstractNameCheck.MSG_INVALID_PATTERN;
24  import static com.puppycrawl.tools.checkstyle.internal.utils.TestUtil.getExpectedThrowable;
25  
26  import java.io.File;
27  import java.util.Arrays;
28  import java.util.Collections;
29  import java.util.List;
30  
31  import org.junit.jupiter.api.Test;
32  
33  import com.puppycrawl.tools.checkstyle.AbstractModuleTestSupport;
34  import com.puppycrawl.tools.checkstyle.DefaultConfiguration;
35  import com.puppycrawl.tools.checkstyle.TreeWalker;
36  import com.puppycrawl.tools.checkstyle.TreeWalkerAuditEvent;
37  import com.puppycrawl.tools.checkstyle.api.CheckstyleException;
38  import com.puppycrawl.tools.checkstyle.api.FileContents;
39  import com.puppycrawl.tools.checkstyle.api.FileText;
40  import com.puppycrawl.tools.checkstyle.api.Violation;
41  import com.puppycrawl.tools.checkstyle.checks.coding.IllegalCatchCheck;
42  import com.puppycrawl.tools.checkstyle.checks.naming.AbstractNameCheck;
43  import com.puppycrawl.tools.checkstyle.checks.naming.MemberNameCheck;
44  import com.puppycrawl.tools.checkstyle.internal.utils.TestUtil;
45  import com.puppycrawl.tools.checkstyle.utils.CommonUtil;
46  import nl.jqno.equalsverifier.EqualsVerifier;
47  import nl.jqno.equalsverifier.EqualsVerifierReport;
48  
49  public class SuppressWithNearbyCommentFilterTest
50      extends AbstractModuleTestSupport {
51  
52      private static final String[] ALL_MESSAGES = {
53          "46:17: "
54              + getCheckMessage(AbstractNameCheck.class,
55                  MSG_INVALID_PATTERN, "A1", "^[a-z][a-zA-Z0-9]*$"),
56          "49:17: "
57              + getCheckMessage(AbstractNameCheck.class,
58                  MSG_INVALID_PATTERN, "A2", "^[a-z][a-zA-Z0-9]*$"),
59          "50:59: "
60              + getCheckMessage(AbstractNameCheck.class,
61                  MSG_INVALID_PATTERN, "A3", "^[a-z][a-zA-Z0-9]*$"),
62          "53:17: "
63              + getCheckMessage(AbstractNameCheck.class,
64                  MSG_INVALID_PATTERN, "B1", "^[a-z][a-zA-Z0-9]*$"),
65          "56:17: "
66              + getCheckMessage(AbstractNameCheck.class,
67                  MSG_INVALID_PATTERN, "B2", "^[a-z][a-zA-Z0-9]*$"),
68          "57:59: "
69              + getCheckMessage(AbstractNameCheck.class,
70                  MSG_INVALID_PATTERN, "B3", "^[a-z][a-zA-Z0-9]*$"),
71          "59:17: "
72              + getCheckMessage(AbstractNameCheck.class,
73                  MSG_INVALID_PATTERN, "C1", "^[a-z][a-zA-Z0-9]*$"),
74          "61:17: "
75              + getCheckMessage(AbstractNameCheck.class,
76                  MSG_INVALID_PATTERN, "C2", "^[a-z][a-zA-Z0-9]*$"),
77          "62:17: "
78              + getCheckMessage(AbstractNameCheck.class,
79                  MSG_INVALID_PATTERN, "C3", "^[a-z][a-zA-Z0-9]*$"),
80          "64:17: "
81              + getCheckMessage(AbstractNameCheck.class,
82                  MSG_INVALID_PATTERN, "D1", "^[a-z][a-zA-Z0-9]*$"),
83          "65:17: "
84              + getCheckMessage(AbstractNameCheck.class,
85                  MSG_INVALID_PATTERN, "D2", "^[a-z][a-zA-Z0-9]*$"),
86          "67:17: "
87              + getCheckMessage(AbstractNameCheck.class,
88                  MSG_INVALID_PATTERN, "D3", "^[a-z][a-zA-Z0-9]*$"),
89          "69:30: "
90              + getCheckMessage(AbstractNameCheck.class,
91                  MSG_INVALID_PATTERN, "e1", "^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$"),
92          "70:17: "
93              + getCheckMessage(AbstractNameCheck.class,
94                  MSG_INVALID_PATTERN, "E2", "^[a-z][a-zA-Z0-9]*$"),
95          "73:17: "
96              + getCheckMessage(AbstractNameCheck.class,
97                  MSG_INVALID_PATTERN, "E3", "^[a-z][a-zA-Z0-9]*$"),
98          "74:30: "
99              + getCheckMessage(AbstractNameCheck.class,
100                 MSG_INVALID_PATTERN, "e4", "^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$"),
101         "75:17: "
102             + getCheckMessage(AbstractNameCheck.class,
103                 MSG_INVALID_PATTERN, "E5", "^[a-z][a-zA-Z0-9]*$"),
104         "76:30: "
105             + getCheckMessage(AbstractNameCheck.class,
106                 MSG_INVALID_PATTERN, "e6", "^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$"),
107         "77:17: "
108             + getCheckMessage(AbstractNameCheck.class,
109                 MSG_INVALID_PATTERN, "E7", "^[a-z][a-zA-Z0-9]*$"),
110         "78:17: "
111             + getCheckMessage(AbstractNameCheck.class,
112                 MSG_INVALID_PATTERN, "E8", "^[a-z][a-zA-Z0-9]*$"),
113         "80:30: "
114             + getCheckMessage(AbstractNameCheck.class,
115                 MSG_INVALID_PATTERN, "e9", "^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$"),
116         "100:23: "
117             + getCheckMessage(IllegalCatchCheck.class, IllegalCatchCheck.MSG_KEY, "Exception"),
118         "102:23: "
119             + getCheckMessage(IllegalCatchCheck.class, IllegalCatchCheck.MSG_KEY, "Throwable"),
120         "109:11: "
121             + getCheckMessage(IllegalCatchCheck.class, IllegalCatchCheck.MSG_KEY, "Exception"),
122         "117:59: "
123             + getCheckMessage(AbstractNameCheck.class,
124                 MSG_INVALID_PATTERN, "A2", "^[a-z][a-zA-Z0-9]*$"),
125         "118:17: "
126             + getCheckMessage(AbstractNameCheck.class,
127                 MSG_INVALID_PATTERN, "A1", "^[a-z][a-zA-Z0-9]*$"),
128     };
129 
130     @Override
131     public String getPackageLocation() {
132         return "com/puppycrawl/tools/checkstyle/filters/suppresswithnearbycommentfilter";
133     }
134 
135     @Test
136     public void testNone() throws Exception {
137         final String[] suppressed = CommonUtil.EMPTY_STRING_ARRAY;
138         final String[] expected = {
139             "36:17: "
140                 + getCheckMessage(AbstractNameCheck.class,
141                     MSG_INVALID_PATTERN, "A1", "^[a-z][a-zA-Z0-9]*$"),
142             "39:17: "
143                 + getCheckMessage(AbstractNameCheck.class,
144                     MSG_INVALID_PATTERN, "A2", "^[a-z][a-zA-Z0-9]*$"),
145             "40:59: "
146                 + getCheckMessage(AbstractNameCheck.class,
147                     MSG_INVALID_PATTERN, "A3", "^[a-z][a-zA-Z0-9]*$"),
148             "43:17: "
149                 + getCheckMessage(AbstractNameCheck.class,
150                     MSG_INVALID_PATTERN, "B1", "^[a-z][a-zA-Z0-9]*$"),
151             "46:17: "
152                 + getCheckMessage(AbstractNameCheck.class,
153                     MSG_INVALID_PATTERN, "B2", "^[a-z][a-zA-Z0-9]*$"),
154             "47:59: "
155                 + getCheckMessage(AbstractNameCheck.class,
156                     MSG_INVALID_PATTERN, "B3", "^[a-z][a-zA-Z0-9]*$"),
157             "49:17: "
158                 + getCheckMessage(AbstractNameCheck.class,
159                     MSG_INVALID_PATTERN, "C1", "^[a-z][a-zA-Z0-9]*$"),
160             "51:17: "
161                 + getCheckMessage(AbstractNameCheck.class,
162                     MSG_INVALID_PATTERN, "C2", "^[a-z][a-zA-Z0-9]*$"),
163             "52:17: "
164                 + getCheckMessage(AbstractNameCheck.class,
165                     MSG_INVALID_PATTERN, "C3", "^[a-z][a-zA-Z0-9]*$"),
166             "54:17: "
167                 + getCheckMessage(AbstractNameCheck.class,
168                     MSG_INVALID_PATTERN, "D1", "^[a-z][a-zA-Z0-9]*$"),
169             "55:17: "
170                 + getCheckMessage(AbstractNameCheck.class,
171                     MSG_INVALID_PATTERN, "D2", "^[a-z][a-zA-Z0-9]*$"),
172             "57:17: "
173                 + getCheckMessage(AbstractNameCheck.class,
174                     MSG_INVALID_PATTERN, "D3", "^[a-z][a-zA-Z0-9]*$"),
175             "59:30: "
176                 + getCheckMessage(AbstractNameCheck.class,
177                     MSG_INVALID_PATTERN, "e1", "^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$"),
178             "60:17: "
179                 + getCheckMessage(AbstractNameCheck.class,
180                     MSG_INVALID_PATTERN, "E2", "^[a-z][a-zA-Z0-9]*$"),
181             "63:17: "
182                 + getCheckMessage(AbstractNameCheck.class,
183                     MSG_INVALID_PATTERN, "E3", "^[a-z][a-zA-Z0-9]*$"),
184             "64:30: "
185                 + getCheckMessage(AbstractNameCheck.class,
186                     MSG_INVALID_PATTERN, "e4", "^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$"),
187             "65:17: "
188                 + getCheckMessage(AbstractNameCheck.class,
189                     MSG_INVALID_PATTERN, "E5", "^[a-z][a-zA-Z0-9]*$"),
190             "66:30: "
191                 + getCheckMessage(AbstractNameCheck.class,
192                     MSG_INVALID_PATTERN, "e6", "^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$"),
193             "67:17: "
194                 + getCheckMessage(AbstractNameCheck.class,
195                     MSG_INVALID_PATTERN, "E7", "^[a-z][a-zA-Z0-9]*$"),
196             "68:17: "
197                 + getCheckMessage(AbstractNameCheck.class,
198                     MSG_INVALID_PATTERN, "E8", "^[a-z][a-zA-Z0-9]*$"),
199             "70:30: "
200                 + getCheckMessage(AbstractNameCheck.class,
201                     MSG_INVALID_PATTERN, "e9", "^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$"),
202             "90:23: "
203                 + getCheckMessage(IllegalCatchCheck.class, IllegalCatchCheck.MSG_KEY, "Exception"),
204             "92:23: "
205                 + getCheckMessage(IllegalCatchCheck.class, IllegalCatchCheck.MSG_KEY, "Throwable"),
206             "99:11: "
207                 + getCheckMessage(IllegalCatchCheck.class, IllegalCatchCheck.MSG_KEY, "Exception"),
208             "107:59: "
209                 + getCheckMessage(AbstractNameCheck.class,
210                     MSG_INVALID_PATTERN, "A2", "^[a-z][a-zA-Z0-9]*$"),
211             "108:17: "
212                 + getCheckMessage(AbstractNameCheck.class,
213                     MSG_INVALID_PATTERN, "A1", "^[a-z][a-zA-Z0-9]*$"),
214         };
215         verifySuppressedWithParser(
216             getPath("InputSuppressWithNearbyCommentFilterWithoutFilter.java"), expected,
217             suppressed);
218     }
219 
220     @Test
221     public void testDefault() throws Exception {
222         final String[] suppressed = {
223             "46:17: "
224                 + getCheckMessage(AbstractNameCheck.class,
225                     MSG_INVALID_PATTERN, "A1", "^[a-z][a-zA-Z0-9]*$"),
226             "49:17: "
227                 + getCheckMessage(AbstractNameCheck.class,
228                     MSG_INVALID_PATTERN, "A2", "^[a-z][a-zA-Z0-9]*$"),
229             "50:59: "
230                 + getCheckMessage(AbstractNameCheck.class,
231                     MSG_INVALID_PATTERN, "A3", "^[a-z][a-zA-Z0-9]*$"),
232             "53:17: "
233                 + getCheckMessage(AbstractNameCheck.class,
234                     MSG_INVALID_PATTERN, "B1", "^[a-z][a-zA-Z0-9]*$"),
235             "56:17: "
236                 + getCheckMessage(AbstractNameCheck.class,
237                     MSG_INVALID_PATTERN, "B2", "^[a-z][a-zA-Z0-9]*$"),
238             "57:59: "
239                 + getCheckMessage(AbstractNameCheck.class,
240                     MSG_INVALID_PATTERN, "B3", "^[a-z][a-zA-Z0-9]*$"),
241             "117:59: "
242                 + getCheckMessage(AbstractNameCheck.class,
243                     MSG_INVALID_PATTERN, "A2", "^[a-z][a-zA-Z0-9]*$"),
244         };
245         verifySuppressedWithParser(
246             getPath("InputSuppressWithNearbyCommentFilter.java"), suppressed);
247     }
248 
249     @Test
250     public void testCheckC() throws Exception {
251         final String[] suppressed = {
252             "46:17: "
253                 + getCheckMessage(AbstractNameCheck.class,
254                     MSG_INVALID_PATTERN, "A1", "^[a-z][a-zA-Z0-9]*$"),
255             "53:17: "
256                 + getCheckMessage(AbstractNameCheck.class,
257                     MSG_INVALID_PATTERN, "B1", "^[a-z][a-zA-Z0-9]*$"),
258         };
259         verifySuppressedWithParser(
260             getPath("InputSuppressWithNearbyCommentFilterCheckC.java"), suppressed);
261     }
262 
263     @Test
264     public void testCheckCpp() throws Exception {
265         final String[] suppressed = {
266             "49:17: "
267                 + getCheckMessage(AbstractNameCheck.class,
268                     MSG_INVALID_PATTERN, "A2", "^[a-z][a-zA-Z0-9]*$"),
269             "50:59: "
270                 + getCheckMessage(AbstractNameCheck.class,
271                     MSG_INVALID_PATTERN, "A3", "^[a-z][a-zA-Z0-9]*$"),
272             "56:17: "
273                 + getCheckMessage(AbstractNameCheck.class,
274                     MSG_INVALID_PATTERN, "B2", "^[a-z][a-zA-Z0-9]*$"),
275             "57:59: "
276                 + getCheckMessage(AbstractNameCheck.class,
277                     MSG_INVALID_PATTERN, "B3", "^[a-z][a-zA-Z0-9]*$"),
278             "117:59: "
279                 + getCheckMessage(AbstractNameCheck.class,
280                     MSG_INVALID_PATTERN, "A2", "^[a-z][a-zA-Z0-9]*$"),
281         };
282         verifySuppressedWithParser(
283             getPath("InputSuppressWithNearbyCommentFilterCheckCpp.java"), suppressed);
284     }
285 
286     @Test
287     public void testUsingVariableMessage() throws Exception {
288         final String[] suppressed = {
289             "102:23: "
290                 + getCheckMessage(IllegalCatchCheck.class,
291                     IllegalCatchCheck.MSG_KEY, "Throwable"),
292             "109:11: "
293                 + getCheckMessage(IllegalCatchCheck.class,
294                     IllegalCatchCheck.MSG_KEY, "Exception"),
295         };
296         verifySuppressedWithParser(
297             getPath("InputSuppressWithNearbyCommentFilterUsingVariableMessage.java"), suppressed);
298     }
299 
300     @Test
301     public void testUsingNonMatchingVariableMessage() throws Exception {
302         final String[] suppressed = CommonUtil.EMPTY_STRING_ARRAY;
303         verifySuppressedWithParser(
304             getPath("InputSuppressWithNearbyCommentFilterUsingNonMatchingVariableMessage.java"),
305             suppressed);
306     }
307 
308     @Test
309     public void testUsingVariableCheckOnNextLine() throws Exception {
310         final String[] suppressed = {
311             "61:17: "
312                 + getCheckMessage(AbstractNameCheck.class,
313                     MSG_INVALID_PATTERN, "C2", "^[a-z][a-zA-Z0-9]*$"),
314         };
315         verifySuppressedWithParser(
316             getPath("InputSuppressWithNearbyCommentFilterUsingVariableCheckOnNextLine.java"),
317             suppressed);
318     }
319 
320     @Test
321     public void testUsingVariableCheckOnPreviousLine() throws Exception {
322         final String[] suppressed = {
323             "65:17: "
324                 + getCheckMessage(AbstractNameCheck.class,
325                     MSG_INVALID_PATTERN, "D2", "^[a-z][a-zA-Z0-9]*$"),
326         };
327         verifySuppressedWithParser(
328             getPath("InputSuppressWithNearbyCommentFilterUsingVariableCheckOnPreviousLine.java"),
329             suppressed);
330     }
331 
332     @Test
333     public void testVariableCheckOnVariableNumberOfLines() throws Exception {
334         final String[] suppressed = {
335             "74:30: "
336                 + getCheckMessage(AbstractNameCheck.class,
337                     MSG_INVALID_PATTERN, "e4", "^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$"),
338             "75:17: "
339                 + getCheckMessage(AbstractNameCheck.class,
340                     MSG_INVALID_PATTERN, "E5", "^[a-z][a-zA-Z0-9]*$"),
341             "77:17: "
342                 + getCheckMessage(AbstractNameCheck.class,
343                     MSG_INVALID_PATTERN, "E7", "^[a-z][a-zA-Z0-9]*$"),
344             "78:17: "
345                 + getCheckMessage(AbstractNameCheck.class,
346                     MSG_INVALID_PATTERN, "E8", "^[a-z][a-zA-Z0-9]*$"),
347         };
348         verifySuppressedWithParser(
349             getPath("InputSuppressWithNearbyCommentFilterVariableCheckOnVariableNumberOfLines"
350                         + ".java"),
351             suppressed);
352     }
353 
354     @Test
355     public void testUnmatchedInfluenceGroup() {
356         final String[] violationAndSuppressedMessages = {
357             "33:17: "
358                 + getCheckMessage(AbstractNameCheck.class,
359                     MSG_INVALID_PATTERN, "InvalidIfName", "^[a-z][a-zA-Z0-9]*$"),
360             "34:16: "
361                 + getCheckMessage(AbstractNameCheck.class,
362                     MSG_INVALID_PATTERN, "InvalidElseName", "^[a-z][a-zA-Z0-9]*$"),
363         };
364 
365         final CheckstyleException exc = getExpectedThrowable(
366                 CheckstyleException.class,
367                 () -> {
368                     verifyFilterWithInlineConfigParser(
369                         getPath("InputSuppressWithNearbyCommentFilterUnmatchedInfluenceGroup.java"),
370                         violationAndSuppressedMessages
371                     );
372                 });
373         assertWithMessage("Invalid exception message")
374             .that(exc)
375             .hasCauseThat()
376             .hasMessageThat()
377             .isEqualTo("unable to parse influence from "
378                     + "'-@csoff[MoveVariableInside(If|Else)](5) my comment text' using $3");
379     }
380 
381     @Test
382     public void testEqualsAndHashCodeOfTagClass() {
383         final SuppressWithNearbyCommentFilter filter = new SuppressWithNearbyCommentFilter();
384         final Object tag =
385                 getTagsAfterExecution(filter, "filename", "//SUPPRESS CHECKSTYLE ignore")
386                         .getFirst();
387         final EqualsVerifierReport ev = EqualsVerifier
388                 .forClass(tag.getClass()).usingGetClass().report();
389         assertWithMessage("Error: %s", ev.getMessage())
390                 .that(ev.isSuccessful())
391                 .isTrue();
392     }
393 
394     private void verifySuppressedWithParser(String fileName, String... suppressed)
395             throws Exception {
396         verifyFilterWithInlineConfigParser(fileName, ALL_MESSAGES,
397                                            removeSuppressed(ALL_MESSAGES, suppressed));
398     }
399 
400     private void verifySuppressedWithParser(String fileName, String[] messages,
401                                             String... suppressed)
402             throws Exception {
403         verifyFilterWithInlineConfigParser(fileName, messages,
404                                            removeSuppressed(messages, suppressed));
405     }
406 
407     @Test
408     public void testInvalidInfluenceFormat() {
409         final DefaultConfiguration treeWalkerConfig =
410             createModuleConfig(TreeWalker.class);
411         final DefaultConfiguration filterConfig =
412             createModuleConfig(SuppressWithNearbyCommentFilter.class);
413         filterConfig.addProperty("influenceFormat", "a");
414         final DefaultConfiguration checkConfig =
415             createModuleConfig(MemberNameCheck.class);
416         treeWalkerConfig.addChild(filterConfig);
417         treeWalkerConfig.addChild(checkConfig);
418 
419         final CheckstyleException exc = getExpectedThrowable(
420                 CheckstyleException.class,
421                 () -> {
422                     execute(treeWalkerConfig, getPath(
423                             "InputSuppressWithNearbyCommentFilterByCheckAndInfluence.java"));
424                 });
425         assertWithMessage("Invalid exception message")
426             .that(exc)
427             .hasCauseThat()
428             .hasMessageThat()
429             .isEqualTo("unable to parse influence"
430                     + " from 'SUPPRESS CHECKSTYLE MemberNameCheck' using a");
431     }
432 
433     @Test
434     public void testInfluenceFormat() throws Exception {
435         final String[] suppressed = {
436             "46:17: "
437                 + getCheckMessage(AbstractNameCheck.class,
438                     MSG_INVALID_PATTERN, "A1", "^[a-z][a-zA-Z0-9]*$"),
439             "49:17: "
440                 + getCheckMessage(AbstractNameCheck.class,
441                     MSG_INVALID_PATTERN, "A2", "^[a-z][a-zA-Z0-9]*$"),
442             "50:59: "
443                 + getCheckMessage(AbstractNameCheck.class,
444                     MSG_INVALID_PATTERN, "A3", "^[a-z][a-zA-Z0-9]*$"),
445             "53:17: "
446                 + getCheckMessage(AbstractNameCheck.class,
447                     MSG_INVALID_PATTERN, "B1", "^[a-z][a-zA-Z0-9]*$"),
448             "56:17: "
449                 + getCheckMessage(AbstractNameCheck.class,
450                     MSG_INVALID_PATTERN, "B2", "^[a-z][a-zA-Z0-9]*$"),
451             "57:59: "
452                 + getCheckMessage(AbstractNameCheck.class,
453                     MSG_INVALID_PATTERN, "B3", "^[a-z][a-zA-Z0-9]*$"),
454             "117:59: "
455                 + getCheckMessage(AbstractNameCheck.class,
456                     MSG_INVALID_PATTERN, "A2", "^[a-z][a-zA-Z0-9]*$"),
457             "118:17: "
458                 + getCheckMessage(AbstractNameCheck.class,
459                     MSG_INVALID_PATTERN, "A1", "^[a-z][a-zA-Z0-9]*$"),
460         };
461         verifySuppressedWithParser(
462             getPath("InputSuppressWithNearbyCommentFilterInfluenceFormat.java"),
463             suppressed);
464     }
465 
466     @Test
467     public void testInvalidCheckFormat() {
468         final DefaultConfiguration treeWalkerConfig =
469             createModuleConfig(TreeWalker.class);
470         final DefaultConfiguration filterConfig =
471             createModuleConfig(SuppressWithNearbyCommentFilter.class);
472         filterConfig.addProperty("checkFormat", "a[l");
473         final DefaultConfiguration checkConfig =
474             createModuleConfig(MemberNameCheck.class);
475         treeWalkerConfig.addChild(filterConfig);
476         treeWalkerConfig.addChild(checkConfig);
477 
478         final CheckstyleException exc = getExpectedThrowable(
479                 CheckstyleException.class,
480                 () -> {
481                     execute(treeWalkerConfig, getPath(
482                             "InputSuppressWithNearbyCommentFilterByCheckAndInfluence.java"));
483                 });
484         final IllegalArgumentException cause = (IllegalArgumentException) exc.getCause();
485         assertWithMessage("Invalid exception message")
486             .that(cause)
487             .hasMessageThat()
488             .isEqualTo("unable to parse expanded comment a[l");
489     }
490 
491     @Test
492     public void testAcceptNullViolation() {
493         final SuppressWithNearbyCommentFilter filter = new SuppressWithNearbyCommentFilter();
494         final FileContents contents = new FileContents(new FileText(new File("filename"),
495                 Collections.singletonList("//SUPPRESS CHECKSTYLE ignore")));
496         contents.reportSingleLineComment(1, 0);
497         final TreeWalkerAuditEvent auditEvent =
498                 new TreeWalkerAuditEvent(contents, null, null, null);
499         assertWithMessage("Filter should accept null violation")
500                 .that(filter.accept(auditEvent))
501                 .isTrue();
502     }
503 
504     @Test
505     public void testAcceptNullFileContents() {
506         final SuppressWithNearbyCommentFilter filter = new SuppressWithNearbyCommentFilter();
507         final FileContents contents = null;
508         final TreeWalkerAuditEvent auditEvent = new TreeWalkerAuditEvent(contents, null,
509                 new Violation(1, null, null, null, null, Object.class, null), null);
510         assertWithMessage("Filter should accept audit event")
511                 .that(filter.accept(auditEvent))
512                 .isTrue();
513     }
514 
515     @Test
516     public void testToStringOfTagClass() {
517         final SuppressWithNearbyCommentFilter filter = new SuppressWithNearbyCommentFilter();
518         final Object tag =
519                 getTagsAfterExecution(filter, "filename", "//SUPPRESS CHECKSTYLE ignore")
520                         .getFirst();
521         assertWithMessage("Invalid toString result")
522             .that(tag.toString())
523             .isEqualTo("Tag[text='SUPPRESS CHECKSTYLE ignore', firstLine=1, lastLine=1, "
524                     + "tagCheckRegexp=.*, tagMessageRegexp=null, tagIdRegexp=null]");
525     }
526 
527     @Test
528     public void testToStringOfTagClassWithId() {
529         final SuppressWithNearbyCommentFilter filter = new SuppressWithNearbyCommentFilter();
530         filter.setIdFormat(".*");
531         final Object tag =
532                 getTagsAfterExecution(filter, "filename", "//SUPPRESS CHECKSTYLE ignore")
533                         .getFirst();
534         assertWithMessage("Invalid toString result")
535             .that(tag.toString())
536             .isEqualTo("Tag[text='SUPPRESS CHECKSTYLE ignore', firstLine=1, lastLine=1, "
537                     + "tagCheckRegexp=.*, tagMessageRegexp=null, tagIdRegexp=.*]");
538     }
539 
540     /**
541      * {@link #verifySuppressedWithParser(String, String...)} does not invoke
542      * {@code Tag#toString()}. Direct assertion is required to kill the mutation
543      */
544     @Test
545     public void testToStringOfTagClassWithMessage() {
546         final SuppressWithNearbyCommentFilter filter = new SuppressWithNearbyCommentFilter();
547         filter.setMessageFormat("msg");
548         filter.setCheckFormat("IGNORE");
549         final Object tag =
550                 getTagsAfterExecution(filter, "filename", "//SUPPRESS CHECKSTYLE ignore")
551                         .getFirst();
552         assertWithMessage("Invalid toString result")
553             .that(tag.toString())
554             .isEqualTo("Tag[text='SUPPRESS CHECKSTYLE ignore', firstLine=1, lastLine=1, "
555                     + "tagCheckRegexp=IGNORE, tagMessageRegexp=msg, tagIdRegexp=null]");
556     }
557 
558     @Test
559     public void testUsingTagMessageRegexp() throws Exception {
560         final String[] suppressed = CommonUtil.EMPTY_STRING_ARRAY;
561         verifySuppressedWithParser(
562             getPath("InputSuppressWithNearbyCommentFilterUsingTagMessageRegexp.java"),
563             suppressed);
564     }
565 
566     @Test
567     public void testSuppressByCheck() throws Exception {
568         final String[] suppressedViolationMessages = {
569             "41:17: "
570                 + getCheckMessage(AbstractNameCheck.class,
571                     MSG_INVALID_PATTERN, "A1", "^[a-z][a-zA-Z0-9]*$"),
572             "47:9: "
573                 + getCheckMessage(AbstractNameCheck.class,
574                     MSG_INVALID_PATTERN, "line_length", "^[a-z][a-zA-Z0-9]*$"),
575             "52:57: "
576                 + getCheckMessage(AbstractNameCheck.class,
577                     MSG_INVALID_PATTERN, "ID3", "^[a-z][a-zA-Z0-9]*$"),
578         };
579         final String[] expectedViolationMessages = {
580             "41:17: "
581                 + getCheckMessage(AbstractNameCheck.class,
582                     MSG_INVALID_PATTERN, "A1", "^[a-z][a-zA-Z0-9]*$"),
583             "44:30: "
584                 + getCheckMessage(AbstractNameCheck.class,
585                     MSG_INVALID_PATTERN, "abc", "^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$"),
586             "47:9: "
587                 + getCheckMessage(AbstractNameCheck.class,
588                     MSG_INVALID_PATTERN, "line_length", "^[a-z][a-zA-Z0-9]*$"),
589             "50:18: "
590                 + getCheckMessage(AbstractNameCheck.class,
591                     MSG_INVALID_PATTERN, "ID", "^[a-z][a-zA-Z0-9]*$"),
592             "52:57: "
593                 + getCheckMessage(AbstractNameCheck.class,
594                     MSG_INVALID_PATTERN, "ID3", "^[a-z][a-zA-Z0-9]*$"),
595             "55:17: "
596                 + getCheckMessage(AbstractNameCheck.class,
597                     MSG_INVALID_PATTERN, "DEF", "^[a-z][a-zA-Z0-9]*$"),
598             "58:17: "
599                 + getCheckMessage(AbstractNameCheck.class,
600                     MSG_INVALID_PATTERN, "XYZ", "^[a-z][a-zA-Z0-9]*$"),
601         };
602 
603         verifySuppressedWithParser(getPath("InputSuppressWithNearbyCommentFilterByCheck.java"),
604                                    expectedViolationMessages, suppressedViolationMessages);
605     }
606 
607     @Test
608     public void testSuppressById() throws Exception {
609         final String[] suppressedViolationMessages = {
610             "41:17: "
611                 + getCheckMessage(AbstractNameCheck.class,
612                     MSG_INVALID_PATTERN, "A1", "^[a-z][a-zA-Z0-9]*$"),
613             "47:9: "
614                 + getCheckMessage(AbstractNameCheck.class,
615                     MSG_INVALID_PATTERN, "line_length", "^[a-z][a-zA-Z0-9]*$"),
616             "52:57: "
617                 + getCheckMessage(AbstractNameCheck.class,
618                     MSG_INVALID_PATTERN, "ID3", "^[a-z][a-zA-Z0-9]*$"),
619         };
620         final String[] expectedViolationMessages = {
621             "41:17: "
622                 + getCheckMessage(AbstractNameCheck.class,
623                     MSG_INVALID_PATTERN, "A1", "^[a-z][a-zA-Z0-9]*$"),
624             "44:30: "
625                 + getCheckMessage(AbstractNameCheck.class,
626                     MSG_INVALID_PATTERN, "abc", "^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$"),
627             "47:9: "
628                 + getCheckMessage(AbstractNameCheck.class,
629                     MSG_INVALID_PATTERN, "line_length", "^[a-z][a-zA-Z0-9]*$"),
630             "50:18: "
631                 + getCheckMessage(AbstractNameCheck.class,
632                     MSG_INVALID_PATTERN, "ID", "^[a-z][a-zA-Z0-9]*$"),
633             "52:57: "
634                 + getCheckMessage(AbstractNameCheck.class,
635                     MSG_INVALID_PATTERN, "ID3", "^[a-z][a-zA-Z0-9]*$"),
636             "55:17: "
637                 + getCheckMessage(AbstractNameCheck.class,
638                     MSG_INVALID_PATTERN, "DEF", "^[a-z][a-zA-Z0-9]*$"),
639             "58:17: "
640                 + getCheckMessage(AbstractNameCheck.class,
641                     MSG_INVALID_PATTERN, "XYZ", "^[a-z][a-zA-Z0-9]*$"),
642         };
643 
644         verifySuppressedWithParser(getPath("InputSuppressWithNearbyCommentFilterById.java"),
645                                    expectedViolationMessages, suppressedViolationMessages);
646     }
647 
648     @Test
649     public void testSuppressByCheckAndId() throws Exception {
650         final String[] suppressedViolationMessages = {
651             "41:17: "
652                 + getCheckMessage(AbstractNameCheck.class,
653                     MSG_INVALID_PATTERN, "A1", "^[a-z][a-zA-Z0-9]*$"),
654             "47:9: "
655                 + getCheckMessage(AbstractNameCheck.class,
656                     MSG_INVALID_PATTERN, "line_length", "^[a-z][a-zA-Z0-9]*$"),
657             "52:57: "
658                 + getCheckMessage(AbstractNameCheck.class,
659                     MSG_INVALID_PATTERN, "ID3", "^[a-z][a-zA-Z0-9]*$"),
660         };
661         final String[] expectedViolationMessages = {
662             "41:17: "
663                 + getCheckMessage(AbstractNameCheck.class,
664                     MSG_INVALID_PATTERN, "A1", "^[a-z][a-zA-Z0-9]*$"),
665             "44:30: "
666                 + getCheckMessage(AbstractNameCheck.class,
667                     MSG_INVALID_PATTERN, "abc", "^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$"),
668             "47:9: "
669                 + getCheckMessage(AbstractNameCheck.class,
670                     MSG_INVALID_PATTERN, "line_length", "^[a-z][a-zA-Z0-9]*$"),
671             "50:18: "
672                 + getCheckMessage(AbstractNameCheck.class,
673                     MSG_INVALID_PATTERN, "ID", "^[a-z][a-zA-Z0-9]*$"),
674             "52:57: "
675                 + getCheckMessage(AbstractNameCheck.class,
676                     MSG_INVALID_PATTERN, "ID3", "^[a-z][a-zA-Z0-9]*$"),
677             "55:17: "
678                 + getCheckMessage(AbstractNameCheck.class,
679                     MSG_INVALID_PATTERN, "DEF", "^[a-z][a-zA-Z0-9]*$"),
680             "58:17: "
681                 + getCheckMessage(AbstractNameCheck.class,
682                     MSG_INVALID_PATTERN, "XYZ", "^[a-z][a-zA-Z0-9]*$"),
683         };
684 
685         verifySuppressedWithParser(
686             getPath("InputSuppressWithNearbyCommentFilterByCheckAndId.java"),
687                                    expectedViolationMessages, suppressedViolationMessages);
688     }
689 
690     @Test
691     public void testSuppressByCheckAndNonMatchingId() throws Exception {
692         final String[] suppressedViolationMessages = CommonUtil.EMPTY_STRING_ARRAY;
693         final String[] expectedViolationMessages = {
694             "41:17: "
695                 + getCheckMessage(AbstractNameCheck.class,
696                     MSG_INVALID_PATTERN, "A1", "^[a-z][a-zA-Z0-9]*$"),
697             "44:30: "
698                 + getCheckMessage(AbstractNameCheck.class,
699                     MSG_INVALID_PATTERN, "abc", "^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$"),
700             "47:9: "
701                 + getCheckMessage(AbstractNameCheck.class,
702                     MSG_INVALID_PATTERN, "line_length", "^[a-z][a-zA-Z0-9]*$"),
703             "50:18: "
704                 + getCheckMessage(AbstractNameCheck.class,
705                     MSG_INVALID_PATTERN, "ID", "^[a-z][a-zA-Z0-9]*$"),
706             "52:57: "
707                 + getCheckMessage(AbstractNameCheck.class,
708                     MSG_INVALID_PATTERN, "ID3", "^[a-z][a-zA-Z0-9]*$"),
709             "55:17: "
710                 + getCheckMessage(AbstractNameCheck.class,
711                     MSG_INVALID_PATTERN, "DEF", "^[a-z][a-zA-Z0-9]*$"),
712             "58:17: "
713                 + getCheckMessage(AbstractNameCheck.class,
714                     MSG_INVALID_PATTERN, "XYZ", "^[a-z][a-zA-Z0-9]*$"),
715         };
716 
717         verifySuppressedWithParser(
718             getPath("InputSuppressWithNearbyCommentFilterByCheckAndNonMatchingId.java"),
719             expectedViolationMessages, suppressedViolationMessages);
720     }
721 
722     @Test
723     public void tesSuppressByIdAndMessage() throws Exception {
724         final String[] suppressedViolationMessages = {
725             "55:17: "
726                 + getCheckMessage(AbstractNameCheck.class,
727                     MSG_INVALID_PATTERN, "DEF", "^[a-z][a-zA-Z0-9]*$"),
728         };
729         final String[] expectedViolationMessages = {
730             "41:17: "
731                 + getCheckMessage(AbstractNameCheck.class,
732                     MSG_INVALID_PATTERN, "A1", "^[a-z][a-zA-Z0-9]*$"),
733             "44:30: "
734                 + getCheckMessage(AbstractNameCheck.class,
735                     MSG_INVALID_PATTERN, "abc", "^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$"),
736             "47:9: "
737                 + getCheckMessage(AbstractNameCheck.class,
738                     MSG_INVALID_PATTERN, "line_length", "^[a-z][a-zA-Z0-9]*$"),
739             "50:18: "
740                 + getCheckMessage(AbstractNameCheck.class,
741                     MSG_INVALID_PATTERN, "ID", "^[a-z][a-zA-Z0-9]*$"),
742             "52:57: "
743                 + getCheckMessage(AbstractNameCheck.class,
744                     MSG_INVALID_PATTERN, "ID3", "^[a-z][a-zA-Z0-9]*$"),
745             "55:17: "
746                 + getCheckMessage(AbstractNameCheck.class,
747                     MSG_INVALID_PATTERN, "DEF", "^[a-z][a-zA-Z0-9]*$"),
748             "58:17: "
749                 + getCheckMessage(AbstractNameCheck.class,
750                     MSG_INVALID_PATTERN, "XYZ", "^[a-z][a-zA-Z0-9]*$"),
751         };
752 
753         verifySuppressedWithParser(
754             getPath("InputSuppressWithNearbyCommentFilterByIdAndMessage.java"),
755             expectedViolationMessages, suppressedViolationMessages);
756     }
757 
758     @Test
759     public void tesSuppressByCheckAndMessage() throws Exception {
760         final String[] suppressedViolationMessages = {
761             "55:17: "
762                 + getCheckMessage(AbstractNameCheck.class,
763                     MSG_INVALID_PATTERN, "DEF", "^[a-z][a-zA-Z0-9]*$"),
764         };
765         final String[] expectedViolationMessages = {
766             "41:17: "
767                 + getCheckMessage(AbstractNameCheck.class,
768                     MSG_INVALID_PATTERN, "A1", "^[a-z][a-zA-Z0-9]*$"),
769             "44:30: "
770                 + getCheckMessage(AbstractNameCheck.class,
771                     MSG_INVALID_PATTERN, "abc", "^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$"),
772             "47:9: "
773                 + getCheckMessage(AbstractNameCheck.class,
774                     MSG_INVALID_PATTERN, "line_length", "^[a-z][a-zA-Z0-9]*$"),
775             "50:18: "
776                 + getCheckMessage(AbstractNameCheck.class,
777                     MSG_INVALID_PATTERN, "ID", "^[a-z][a-zA-Z0-9]*$"),
778             "52:57: "
779                 + getCheckMessage(AbstractNameCheck.class,
780                     MSG_INVALID_PATTERN, "ID3", "^[a-z][a-zA-Z0-9]*$"),
781             "55:17: "
782                 + getCheckMessage(AbstractNameCheck.class,
783                     MSG_INVALID_PATTERN, "DEF", "^[a-z][a-zA-Z0-9]*$"),
784             "58:17: "
785                 + getCheckMessage(AbstractNameCheck.class,
786                     MSG_INVALID_PATTERN, "XYZ", "^[a-z][a-zA-Z0-9]*$"),
787         };
788 
789         verifySuppressedWithParser(
790             getPath("InputSuppressWithNearbyCommentFilterByCheckAndMessage.java"),
791             expectedViolationMessages, suppressedViolationMessages);
792     }
793 
794     @Test
795     public void testTagsAreClearedEachRun() {
796         final SuppressWithNearbyCommentFilter suppressionCommentFilter =
797                 new SuppressWithNearbyCommentFilter();
798         final List<?> tags1 = getTagsAfterExecution(suppressionCommentFilter,
799                 "filename1", "//SUPPRESS CHECKSTYLE ignore this");
800         assertWithMessage("Invalid tags size")
801             .that(tags1)
802             .hasSize(1);
803         final List<?> tags2 = getTagsAfterExecution(suppressionCommentFilter,
804                 "filename2", "No comments in this file");
805         assertWithMessage("Invalid tags size")
806             .that(tags2)
807             .isEmpty();
808     }
809 
810     /**
811      * Calls the filter with a minimal set of inputs and returns a list of
812      * {@link SuppressWithNearbyCommentFilter} internal type {@code Tag}.
813      * Our goal is 100% test coverage, for this we use white-box testing.
814      * So we need access to the implementation details. For this reason,
815      * it is necessary to use reflection to gain access to the inner field here.
816      *
817      * @return {@code Tag} list
818      */
819     private static List<?> getTagsAfterExecution(SuppressWithNearbyCommentFilter filter,
820             String filename, String... lines) {
821         final FileContents contents = new FileContents(
822                 new FileText(new File(filename), Arrays.asList(lines)));
823         contents.reportSingleLineComment(1, 0);
824         final TreeWalkerAuditEvent dummyEvent = new TreeWalkerAuditEvent(contents, filename,
825                 new Violation(1, null, null, null, null, Object.class, null), null);
826         filter.accept(dummyEvent);
827         return TestUtil.getInternalState(filter, "tags", List.class);
828     }
829 
830 }