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