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 testEqualsAndHashCodeOfTagClass() {
356         final SuppressWithNearbyCommentFilter filter = new SuppressWithNearbyCommentFilter();
357         final Object tag =
358                 getTagsAfterExecution(filter, "filename", "//SUPPRESS CHECKSTYLE ignore")
359                         .getFirst();
360         final EqualsVerifierReport ev = EqualsVerifier
361                 .forClass(tag.getClass()).usingGetClass().report();
362         assertWithMessage("Error: %s", ev.getMessage())
363                 .that(ev.isSuccessful())
364                 .isTrue();
365     }
366 
367     private void verifySuppressedWithParser(String fileName, String... suppressed)
368             throws Exception {
369         verifyFilterWithInlineConfigParser(fileName, ALL_MESSAGES,
370                                            removeSuppressed(ALL_MESSAGES, suppressed));
371     }
372 
373     private void verifySuppressedWithParser(String fileName, String[] messages,
374                                             String... suppressed)
375             throws Exception {
376         verifyFilterWithInlineConfigParser(fileName, messages,
377                                            removeSuppressed(messages, suppressed));
378     }
379 
380     @Test
381     public void testInvalidInfluenceFormat() {
382         final DefaultConfiguration treeWalkerConfig =
383             createModuleConfig(TreeWalker.class);
384         final DefaultConfiguration filterConfig =
385             createModuleConfig(SuppressWithNearbyCommentFilter.class);
386         filterConfig.addProperty("influenceFormat", "a");
387         final DefaultConfiguration checkConfig =
388             createModuleConfig(MemberNameCheck.class);
389         treeWalkerConfig.addChild(filterConfig);
390         treeWalkerConfig.addChild(checkConfig);
391 
392         final CheckstyleException exc = getExpectedThrowable(
393                 CheckstyleException.class,
394                 () -> {
395                     execute(treeWalkerConfig, getPath(
396                             "InputSuppressWithNearbyCommentFilterByCheckAndInfluence.java"));
397                 });
398         assertWithMessage("Invalid exception message")
399             .that(exc)
400             .hasCauseThat()
401             .hasMessageThat()
402             .isEqualTo("unable to parse influence"
403                     + " from 'SUPPRESS CHECKSTYLE MemberNameCheck' using a");
404     }
405 
406     @Test
407     public void testInfluenceFormat() throws Exception {
408         final String[] suppressed = {
409             "46:17: "
410                 + getCheckMessage(AbstractNameCheck.class,
411                     MSG_INVALID_PATTERN, "A1", "^[a-z][a-zA-Z0-9]*$"),
412             "49:17: "
413                 + getCheckMessage(AbstractNameCheck.class,
414                     MSG_INVALID_PATTERN, "A2", "^[a-z][a-zA-Z0-9]*$"),
415             "50:59: "
416                 + getCheckMessage(AbstractNameCheck.class,
417                     MSG_INVALID_PATTERN, "A3", "^[a-z][a-zA-Z0-9]*$"),
418             "53:17: "
419                 + getCheckMessage(AbstractNameCheck.class,
420                     MSG_INVALID_PATTERN, "B1", "^[a-z][a-zA-Z0-9]*$"),
421             "56:17: "
422                 + getCheckMessage(AbstractNameCheck.class,
423                     MSG_INVALID_PATTERN, "B2", "^[a-z][a-zA-Z0-9]*$"),
424             "57:59: "
425                 + getCheckMessage(AbstractNameCheck.class,
426                     MSG_INVALID_PATTERN, "B3", "^[a-z][a-zA-Z0-9]*$"),
427             "117:59: "
428                 + getCheckMessage(AbstractNameCheck.class,
429                     MSG_INVALID_PATTERN, "A2", "^[a-z][a-zA-Z0-9]*$"),
430             "118:17: "
431                 + getCheckMessage(AbstractNameCheck.class,
432                     MSG_INVALID_PATTERN, "A1", "^[a-z][a-zA-Z0-9]*$"),
433         };
434         verifySuppressedWithParser(
435             getPath("InputSuppressWithNearbyCommentFilterInfluenceFormat.java"),
436             suppressed);
437     }
438 
439     @Test
440     public void testInvalidCheckFormat() {
441         final DefaultConfiguration treeWalkerConfig =
442             createModuleConfig(TreeWalker.class);
443         final DefaultConfiguration filterConfig =
444             createModuleConfig(SuppressWithNearbyCommentFilter.class);
445         filterConfig.addProperty("checkFormat", "a[l");
446         final DefaultConfiguration checkConfig =
447             createModuleConfig(MemberNameCheck.class);
448         treeWalkerConfig.addChild(filterConfig);
449         treeWalkerConfig.addChild(checkConfig);
450 
451         final CheckstyleException exc = getExpectedThrowable(
452                 CheckstyleException.class,
453                 () -> {
454                     execute(treeWalkerConfig, getPath(
455                             "InputSuppressWithNearbyCommentFilterByCheckAndInfluence.java"));
456                 });
457         final IllegalArgumentException cause = (IllegalArgumentException) exc.getCause();
458         assertWithMessage("Invalid exception message")
459             .that(cause)
460             .hasMessageThat()
461             .isEqualTo("unable to parse expanded comment a[l");
462     }
463 
464     @Test
465     public void testAcceptNullViolation() {
466         final SuppressWithNearbyCommentFilter filter = new SuppressWithNearbyCommentFilter();
467         final FileContents contents = new FileContents(new FileText(new File("filename"),
468                 Collections.singletonList("//SUPPRESS CHECKSTYLE ignore")));
469         contents.reportSingleLineComment(1, 0);
470         final TreeWalkerAuditEvent auditEvent =
471                 new TreeWalkerAuditEvent(contents, null, null, null);
472         assertWithMessage("Filter should accept null violation")
473                 .that(filter.accept(auditEvent))
474                 .isTrue();
475     }
476 
477     @Test
478     public void testAcceptNullFileContents() {
479         final SuppressWithNearbyCommentFilter filter = new SuppressWithNearbyCommentFilter();
480         final FileContents contents = null;
481         final TreeWalkerAuditEvent auditEvent = new TreeWalkerAuditEvent(contents, null,
482                 new Violation(1, null, null, null, null, Object.class, null), null);
483         assertWithMessage("Filter should accept audit event")
484                 .that(filter.accept(auditEvent))
485                 .isTrue();
486     }
487 
488     @Test
489     public void testToStringOfTagClass() {
490         final SuppressWithNearbyCommentFilter filter = new SuppressWithNearbyCommentFilter();
491         final Object tag =
492                 getTagsAfterExecution(filter, "filename", "//SUPPRESS CHECKSTYLE ignore")
493                         .getFirst();
494         assertWithMessage("Invalid toString result")
495             .that(tag.toString())
496             .isEqualTo("Tag[text='SUPPRESS CHECKSTYLE ignore', firstLine=1, lastLine=1, "
497                     + "tagCheckRegexp=.*, tagMessageRegexp=null, tagIdRegexp=null]");
498     }
499 
500     @Test
501     public void testToStringOfTagClassWithId() {
502         final SuppressWithNearbyCommentFilter filter = new SuppressWithNearbyCommentFilter();
503         filter.setIdFormat(".*");
504         final Object tag =
505                 getTagsAfterExecution(filter, "filename", "//SUPPRESS CHECKSTYLE ignore")
506                         .getFirst();
507         assertWithMessage("Invalid toString result")
508             .that(tag.toString())
509             .isEqualTo("Tag[text='SUPPRESS CHECKSTYLE ignore', firstLine=1, lastLine=1, "
510                     + "tagCheckRegexp=.*, tagMessageRegexp=null, tagIdRegexp=.*]");
511     }
512 
513     /**
514      * {@link #verifySuppressedWithParser(String, String...)} does not invoke
515      * {@code Tag#toString()}. Direct assertion is required to kill the mutation
516      */
517     @Test
518     public void testToStringOfTagClassWithMessage() {
519         final SuppressWithNearbyCommentFilter filter = new SuppressWithNearbyCommentFilter();
520         filter.setMessageFormat("msg");
521         filter.setCheckFormat("IGNORE");
522         final Object tag =
523                 getTagsAfterExecution(filter, "filename", "//SUPPRESS CHECKSTYLE ignore")
524                         .getFirst();
525         assertWithMessage("Invalid toString result")
526             .that(tag.toString())
527             .isEqualTo("Tag[text='SUPPRESS CHECKSTYLE ignore', firstLine=1, lastLine=1, "
528                     + "tagCheckRegexp=IGNORE, tagMessageRegexp=msg, tagIdRegexp=null]");
529     }
530 
531     @Test
532     public void testUsingTagMessageRegexp() throws Exception {
533         final String[] suppressed = CommonUtil.EMPTY_STRING_ARRAY;
534         verifySuppressedWithParser(
535             getPath("InputSuppressWithNearbyCommentFilterUsingTagMessageRegexp.java"),
536             suppressed);
537     }
538 
539     @Test
540     public void testSuppressByCheck() throws Exception {
541         final String[] suppressedViolationMessages = {
542             "41:17: "
543                 + getCheckMessage(AbstractNameCheck.class,
544                     MSG_INVALID_PATTERN, "A1", "^[a-z][a-zA-Z0-9]*$"),
545             "47:9: "
546                 + getCheckMessage(AbstractNameCheck.class,
547                     MSG_INVALID_PATTERN, "line_length", "^[a-z][a-zA-Z0-9]*$"),
548             "52:57: "
549                 + getCheckMessage(AbstractNameCheck.class,
550                     MSG_INVALID_PATTERN, "ID3", "^[a-z][a-zA-Z0-9]*$"),
551         };
552         final String[] expectedViolationMessages = {
553             "41:17: "
554                 + getCheckMessage(AbstractNameCheck.class,
555                     MSG_INVALID_PATTERN, "A1", "^[a-z][a-zA-Z0-9]*$"),
556             "44:30: "
557                 + getCheckMessage(AbstractNameCheck.class,
558                     MSG_INVALID_PATTERN, "abc", "^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$"),
559             "47:9: "
560                 + getCheckMessage(AbstractNameCheck.class,
561                     MSG_INVALID_PATTERN, "line_length", "^[a-z][a-zA-Z0-9]*$"),
562             "50:18: "
563                 + getCheckMessage(AbstractNameCheck.class,
564                     MSG_INVALID_PATTERN, "ID", "^[a-z][a-zA-Z0-9]*$"),
565             "52:57: "
566                 + getCheckMessage(AbstractNameCheck.class,
567                     MSG_INVALID_PATTERN, "ID3", "^[a-z][a-zA-Z0-9]*$"),
568             "55:17: "
569                 + getCheckMessage(AbstractNameCheck.class,
570                     MSG_INVALID_PATTERN, "DEF", "^[a-z][a-zA-Z0-9]*$"),
571             "58:17: "
572                 + getCheckMessage(AbstractNameCheck.class,
573                     MSG_INVALID_PATTERN, "XYZ", "^[a-z][a-zA-Z0-9]*$"),
574         };
575 
576         verifySuppressedWithParser(getPath("InputSuppressWithNearbyCommentFilterByCheck.java"),
577                                    expectedViolationMessages, suppressedViolationMessages);
578     }
579 
580     @Test
581     public void testSuppressById() throws Exception {
582         final String[] suppressedViolationMessages = {
583             "41:17: "
584                 + getCheckMessage(AbstractNameCheck.class,
585                     MSG_INVALID_PATTERN, "A1", "^[a-z][a-zA-Z0-9]*$"),
586             "47:9: "
587                 + getCheckMessage(AbstractNameCheck.class,
588                     MSG_INVALID_PATTERN, "line_length", "^[a-z][a-zA-Z0-9]*$"),
589             "52:57: "
590                 + getCheckMessage(AbstractNameCheck.class,
591                     MSG_INVALID_PATTERN, "ID3", "^[a-z][a-zA-Z0-9]*$"),
592         };
593         final String[] expectedViolationMessages = {
594             "41:17: "
595                 + getCheckMessage(AbstractNameCheck.class,
596                     MSG_INVALID_PATTERN, "A1", "^[a-z][a-zA-Z0-9]*$"),
597             "44:30: "
598                 + getCheckMessage(AbstractNameCheck.class,
599                     MSG_INVALID_PATTERN, "abc", "^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$"),
600             "47:9: "
601                 + getCheckMessage(AbstractNameCheck.class,
602                     MSG_INVALID_PATTERN, "line_length", "^[a-z][a-zA-Z0-9]*$"),
603             "50:18: "
604                 + getCheckMessage(AbstractNameCheck.class,
605                     MSG_INVALID_PATTERN, "ID", "^[a-z][a-zA-Z0-9]*$"),
606             "52:57: "
607                 + getCheckMessage(AbstractNameCheck.class,
608                     MSG_INVALID_PATTERN, "ID3", "^[a-z][a-zA-Z0-9]*$"),
609             "55:17: "
610                 + getCheckMessage(AbstractNameCheck.class,
611                     MSG_INVALID_PATTERN, "DEF", "^[a-z][a-zA-Z0-9]*$"),
612             "58:17: "
613                 + getCheckMessage(AbstractNameCheck.class,
614                     MSG_INVALID_PATTERN, "XYZ", "^[a-z][a-zA-Z0-9]*$"),
615         };
616 
617         verifySuppressedWithParser(getPath("InputSuppressWithNearbyCommentFilterById.java"),
618                                    expectedViolationMessages, suppressedViolationMessages);
619     }
620 
621     @Test
622     public void testSuppressByCheckAndId() throws Exception {
623         final String[] suppressedViolationMessages = {
624             "41:17: "
625                 + getCheckMessage(AbstractNameCheck.class,
626                     MSG_INVALID_PATTERN, "A1", "^[a-z][a-zA-Z0-9]*$"),
627             "47:9: "
628                 + getCheckMessage(AbstractNameCheck.class,
629                     MSG_INVALID_PATTERN, "line_length", "^[a-z][a-zA-Z0-9]*$"),
630             "52:57: "
631                 + getCheckMessage(AbstractNameCheck.class,
632                     MSG_INVALID_PATTERN, "ID3", "^[a-z][a-zA-Z0-9]*$"),
633         };
634         final String[] expectedViolationMessages = {
635             "41:17: "
636                 + getCheckMessage(AbstractNameCheck.class,
637                     MSG_INVALID_PATTERN, "A1", "^[a-z][a-zA-Z0-9]*$"),
638             "44:30: "
639                 + getCheckMessage(AbstractNameCheck.class,
640                     MSG_INVALID_PATTERN, "abc", "^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$"),
641             "47:9: "
642                 + getCheckMessage(AbstractNameCheck.class,
643                     MSG_INVALID_PATTERN, "line_length", "^[a-z][a-zA-Z0-9]*$"),
644             "50:18: "
645                 + getCheckMessage(AbstractNameCheck.class,
646                     MSG_INVALID_PATTERN, "ID", "^[a-z][a-zA-Z0-9]*$"),
647             "52:57: "
648                 + getCheckMessage(AbstractNameCheck.class,
649                     MSG_INVALID_PATTERN, "ID3", "^[a-z][a-zA-Z0-9]*$"),
650             "55:17: "
651                 + getCheckMessage(AbstractNameCheck.class,
652                     MSG_INVALID_PATTERN, "DEF", "^[a-z][a-zA-Z0-9]*$"),
653             "58:17: "
654                 + getCheckMessage(AbstractNameCheck.class,
655                     MSG_INVALID_PATTERN, "XYZ", "^[a-z][a-zA-Z0-9]*$"),
656         };
657 
658         verifySuppressedWithParser(
659             getPath("InputSuppressWithNearbyCommentFilterByCheckAndId.java"),
660                                    expectedViolationMessages, suppressedViolationMessages);
661     }
662 
663     @Test
664     public void testSuppressByCheckAndNonMatchingId() throws Exception {
665         final String[] suppressedViolationMessages = CommonUtil.EMPTY_STRING_ARRAY;
666         final String[] expectedViolationMessages = {
667             "41:17: "
668                 + getCheckMessage(AbstractNameCheck.class,
669                     MSG_INVALID_PATTERN, "A1", "^[a-z][a-zA-Z0-9]*$"),
670             "44:30: "
671                 + getCheckMessage(AbstractNameCheck.class,
672                     MSG_INVALID_PATTERN, "abc", "^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$"),
673             "47:9: "
674                 + getCheckMessage(AbstractNameCheck.class,
675                     MSG_INVALID_PATTERN, "line_length", "^[a-z][a-zA-Z0-9]*$"),
676             "50:18: "
677                 + getCheckMessage(AbstractNameCheck.class,
678                     MSG_INVALID_PATTERN, "ID", "^[a-z][a-zA-Z0-9]*$"),
679             "52:57: "
680                 + getCheckMessage(AbstractNameCheck.class,
681                     MSG_INVALID_PATTERN, "ID3", "^[a-z][a-zA-Z0-9]*$"),
682             "55:17: "
683                 + getCheckMessage(AbstractNameCheck.class,
684                     MSG_INVALID_PATTERN, "DEF", "^[a-z][a-zA-Z0-9]*$"),
685             "58:17: "
686                 + getCheckMessage(AbstractNameCheck.class,
687                     MSG_INVALID_PATTERN, "XYZ", "^[a-z][a-zA-Z0-9]*$"),
688         };
689 
690         verifySuppressedWithParser(
691             getPath("InputSuppressWithNearbyCommentFilterByCheckAndNonMatchingId.java"),
692             expectedViolationMessages, suppressedViolationMessages);
693     }
694 
695     @Test
696     public void tesSuppressByIdAndMessage() throws Exception {
697         final String[] suppressedViolationMessages = {
698             "55:17: "
699                 + getCheckMessage(AbstractNameCheck.class,
700                     MSG_INVALID_PATTERN, "DEF", "^[a-z][a-zA-Z0-9]*$"),
701         };
702         final String[] expectedViolationMessages = {
703             "41:17: "
704                 + getCheckMessage(AbstractNameCheck.class,
705                     MSG_INVALID_PATTERN, "A1", "^[a-z][a-zA-Z0-9]*$"),
706             "44:30: "
707                 + getCheckMessage(AbstractNameCheck.class,
708                     MSG_INVALID_PATTERN, "abc", "^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$"),
709             "47:9: "
710                 + getCheckMessage(AbstractNameCheck.class,
711                     MSG_INVALID_PATTERN, "line_length", "^[a-z][a-zA-Z0-9]*$"),
712             "50:18: "
713                 + getCheckMessage(AbstractNameCheck.class,
714                     MSG_INVALID_PATTERN, "ID", "^[a-z][a-zA-Z0-9]*$"),
715             "52:57: "
716                 + getCheckMessage(AbstractNameCheck.class,
717                     MSG_INVALID_PATTERN, "ID3", "^[a-z][a-zA-Z0-9]*$"),
718             "55:17: "
719                 + getCheckMessage(AbstractNameCheck.class,
720                     MSG_INVALID_PATTERN, "DEF", "^[a-z][a-zA-Z0-9]*$"),
721             "58:17: "
722                 + getCheckMessage(AbstractNameCheck.class,
723                     MSG_INVALID_PATTERN, "XYZ", "^[a-z][a-zA-Z0-9]*$"),
724         };
725 
726         verifySuppressedWithParser(
727             getPath("InputSuppressWithNearbyCommentFilterByIdAndMessage.java"),
728             expectedViolationMessages, suppressedViolationMessages);
729     }
730 
731     @Test
732     public void tesSuppressByCheckAndMessage() throws Exception {
733         final String[] suppressedViolationMessages = {
734             "55:17: "
735                 + getCheckMessage(AbstractNameCheck.class,
736                     MSG_INVALID_PATTERN, "DEF", "^[a-z][a-zA-Z0-9]*$"),
737         };
738         final String[] expectedViolationMessages = {
739             "41:17: "
740                 + getCheckMessage(AbstractNameCheck.class,
741                     MSG_INVALID_PATTERN, "A1", "^[a-z][a-zA-Z0-9]*$"),
742             "44:30: "
743                 + getCheckMessage(AbstractNameCheck.class,
744                     MSG_INVALID_PATTERN, "abc", "^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$"),
745             "47:9: "
746                 + getCheckMessage(AbstractNameCheck.class,
747                     MSG_INVALID_PATTERN, "line_length", "^[a-z][a-zA-Z0-9]*$"),
748             "50:18: "
749                 + getCheckMessage(AbstractNameCheck.class,
750                     MSG_INVALID_PATTERN, "ID", "^[a-z][a-zA-Z0-9]*$"),
751             "52:57: "
752                 + getCheckMessage(AbstractNameCheck.class,
753                     MSG_INVALID_PATTERN, "ID3", "^[a-z][a-zA-Z0-9]*$"),
754             "55:17: "
755                 + getCheckMessage(AbstractNameCheck.class,
756                     MSG_INVALID_PATTERN, "DEF", "^[a-z][a-zA-Z0-9]*$"),
757             "58:17: "
758                 + getCheckMessage(AbstractNameCheck.class,
759                     MSG_INVALID_PATTERN, "XYZ", "^[a-z][a-zA-Z0-9]*$"),
760         };
761 
762         verifySuppressedWithParser(
763             getPath("InputSuppressWithNearbyCommentFilterByCheckAndMessage.java"),
764             expectedViolationMessages, suppressedViolationMessages);
765     }
766 
767     @Test
768     public void testTagsAreClearedEachRun() {
769         final SuppressWithNearbyCommentFilter suppressionCommentFilter =
770                 new SuppressWithNearbyCommentFilter();
771         final List<?> tags1 = getTagsAfterExecution(suppressionCommentFilter,
772                 "filename1", "//SUPPRESS CHECKSTYLE ignore this");
773         assertWithMessage("Invalid tags size")
774             .that(tags1)
775             .hasSize(1);
776         final List<?> tags2 = getTagsAfterExecution(suppressionCommentFilter,
777                 "filename2", "No comments in this file");
778         assertWithMessage("Invalid tags size")
779             .that(tags2)
780             .isEmpty();
781     }
782 
783     /**
784      * Calls the filter with a minimal set of inputs and returns a list of
785      * {@link SuppressWithNearbyCommentFilter} internal type {@code Tag}.
786      * Our goal is 100% test coverage, for this we use white-box testing.
787      * So we need access to the implementation details. For this reason,
788      * it is necessary to use reflection to gain access to the inner field here.
789      *
790      * @return {@code Tag} list
791      */
792     private static List<?> getTagsAfterExecution(SuppressWithNearbyCommentFilter filter,
793             String filename, String... lines) {
794         final FileContents contents = new FileContents(
795                 new FileText(new File(filename), Arrays.asList(lines)));
796         contents.reportSingleLineComment(1, 0);
797         final TreeWalkerAuditEvent dummyEvent = new TreeWalkerAuditEvent(contents, filename,
798                 new Violation(1, null, null, null, null, Object.class, null), null);
799         filter.accept(dummyEvent);
800         return TestUtil.getInternalState(filter, "tags", List.class);
801     }
802 
803 }