View Javadoc
1   ///////////////////////////////////////////////////////////////////////////////////////////////
2   // checkstyle: Checks Java source code and other text files for adherence to a set of rules.
3   // Copyright (C) 2001-2024 the original author or authors.
4   //
5   // This library is free software; you can redistribute it and/or
6   // modify it under the terms of the GNU Lesser General Public
7   // License as published by the Free Software Foundation; either
8   // version 2.1 of the License, or (at your option) any later version.
9   //
10  // This library is distributed in the hope that it will be useful,
11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  // Lesser General Public License for more details.
14  //
15  // You should have received a copy of the GNU Lesser General Public
16  // License along with this library; if not, write to the Free Software
17  // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  ///////////////////////////////////////////////////////////////////////////////////////////////
19  
20  package com.puppycrawl.tools.checkstyle.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     protected 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").get(0);
358         final EqualsVerifierReport ev = EqualsVerifier
359                 .forClass(tag.getClass()).usingGetClass().report();
360         assertWithMessage("Error: " + ev.getMessage())
361                 .that(ev.isSuccessful())
362                 .isTrue();
363     }
364 
365     private void verifySuppressedWithParser(String fileName, String... suppressed)
366             throws Exception {
367         verifyFilterWithInlineConfigParser(fileName, ALL_MESSAGES,
368                                            removeSuppressed(ALL_MESSAGES, suppressed));
369     }
370 
371     private void verifySuppressedWithParser(String fileName, String[] messages,
372                                             String... suppressed)
373             throws Exception {
374         verifyFilterWithInlineConfigParser(fileName, messages,
375                                            removeSuppressed(messages, suppressed));
376     }
377 
378     @Test
379     public void testInvalidInfluenceFormat() throws Exception {
380         final DefaultConfiguration treeWalkerConfig =
381             createModuleConfig(TreeWalker.class);
382         final DefaultConfiguration filterConfig =
383             createModuleConfig(SuppressWithNearbyCommentFilter.class);
384         filterConfig.addProperty("influenceFormat", "a");
385         final DefaultConfiguration checkConfig =
386             createModuleConfig(MemberNameCheck.class);
387         treeWalkerConfig.addChild(filterConfig);
388         treeWalkerConfig.addChild(checkConfig);
389 
390         try {
391             execute(treeWalkerConfig,
392                     getPath("InputSuppressWithNearbyCommentFilterByCheckAndInfluence.java"));
393             assertWithMessage("Exception is expected").fail();
394         }
395         catch (CheckstyleException ex) {
396             assertWithMessage("Invalid exception message")
397                 .that(ex)
398                 .hasCauseThat()
399                 .hasMessageThat()
400                 .isEqualTo("unable to parse influence"
401                         + " from 'SUPPRESS CHECKSTYLE MemberNameCheck' using a");
402         }
403     }
404 
405     @Test
406     public void testInfluenceFormat() throws Exception {
407         final String[] suppressed = {
408             "46:17: "
409                 + getCheckMessage(AbstractNameCheck.class,
410                     MSG_INVALID_PATTERN, "A1", "^[a-z][a-zA-Z0-9]*$"),
411             "49:17: "
412                 + getCheckMessage(AbstractNameCheck.class,
413                     MSG_INVALID_PATTERN, "A2", "^[a-z][a-zA-Z0-9]*$"),
414             "50:59: "
415                 + getCheckMessage(AbstractNameCheck.class,
416                     MSG_INVALID_PATTERN, "A3", "^[a-z][a-zA-Z0-9]*$"),
417             "53:17: "
418                 + getCheckMessage(AbstractNameCheck.class,
419                     MSG_INVALID_PATTERN, "B1", "^[a-z][a-zA-Z0-9]*$"),
420             "56:17: "
421                 + getCheckMessage(AbstractNameCheck.class,
422                     MSG_INVALID_PATTERN, "B2", "^[a-z][a-zA-Z0-9]*$"),
423             "57:59: "
424                 + getCheckMessage(AbstractNameCheck.class,
425                     MSG_INVALID_PATTERN, "B3", "^[a-z][a-zA-Z0-9]*$"),
426             "117:59: "
427                 + getCheckMessage(AbstractNameCheck.class,
428                     MSG_INVALID_PATTERN, "A2", "^[a-z][a-zA-Z0-9]*$"),
429             "118:17: "
430                 + getCheckMessage(AbstractNameCheck.class,
431                     MSG_INVALID_PATTERN, "A1", "^[a-z][a-zA-Z0-9]*$"),
432         };
433         verifySuppressedWithParser(
434             getPath("InputSuppressWithNearbyCommentFilterInfluenceFormat.java"),
435             suppressed);
436     }
437 
438     @Test
439     public void testInvalidCheckFormat() throws Exception {
440         final DefaultConfiguration treeWalkerConfig =
441             createModuleConfig(TreeWalker.class);
442         final DefaultConfiguration filterConfig =
443             createModuleConfig(SuppressWithNearbyCommentFilter.class);
444         filterConfig.addProperty("checkFormat", "a[l");
445         final DefaultConfiguration checkConfig =
446             createModuleConfig(MemberNameCheck.class);
447         treeWalkerConfig.addChild(filterConfig);
448         treeWalkerConfig.addChild(checkConfig);
449 
450         try {
451             execute(treeWalkerConfig,
452                     getPath("InputSuppressWithNearbyCommentFilterByCheckAndInfluence.java"));
453             assertWithMessage("Exception is expected").fail();
454         }
455         catch (CheckstyleException ex) {
456             final IllegalArgumentException cause = (IllegalArgumentException) ex.getCause();
457             assertWithMessage("Invalid exception message")
458                 .that(cause)
459                 .hasMessageThat()
460                 .isEqualTo("unable to parse expanded comment a[l");
461         }
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").get(0);
493         assertWithMessage("Invalid toString result")
494             .that(tag.toString())
495             .isEqualTo("Tag[text='SUPPRESS CHECKSTYLE ignore', firstLine=1, lastLine=1, "
496                     + "tagCheckRegexp=.*, tagMessageRegexp=null, tagIdRegexp=null]");
497     }
498 
499     @Test
500     public void testToStringOfTagClassWithId() {
501         final SuppressWithNearbyCommentFilter filter = new SuppressWithNearbyCommentFilter();
502         filter.setIdFormat(".*");
503         final Object tag =
504                 getTagsAfterExecution(filter, "filename", "//SUPPRESS CHECKSTYLE ignore").get(0);
505         assertWithMessage("Invalid toString result")
506             .that(tag.toString())
507             .isEqualTo("Tag[text='SUPPRESS CHECKSTYLE ignore', firstLine=1, lastLine=1, "
508                     + "tagCheckRegexp=.*, tagMessageRegexp=null, tagIdRegexp=.*]");
509     }
510 
511     @Test
512     public void testUsingTagMessageRegexp() throws Exception {
513         final String[] suppressed = CommonUtil.EMPTY_STRING_ARRAY;
514         verifySuppressedWithParser(
515             getPath("InputSuppressWithNearbyCommentFilterUsingTagMessageRegexp.java"),
516             suppressed);
517     }
518 
519     @Test
520     public void testSuppressByCheck() throws Exception {
521         final String[] suppressedViolationMessages = {
522             "41:17: "
523                 + getCheckMessage(AbstractNameCheck.class,
524                     MSG_INVALID_PATTERN, "A1", "^[a-z][a-zA-Z0-9]*$"),
525             "47:9: "
526                 + getCheckMessage(AbstractNameCheck.class,
527                     MSG_INVALID_PATTERN, "line_length", "^[a-z][a-zA-Z0-9]*$"),
528             "52:57: "
529                 + getCheckMessage(AbstractNameCheck.class,
530                     MSG_INVALID_PATTERN, "ID3", "^[a-z][a-zA-Z0-9]*$"),
531         };
532         final String[] expectedViolationMessages = {
533             "41:17: "
534                 + getCheckMessage(AbstractNameCheck.class,
535                     MSG_INVALID_PATTERN, "A1", "^[a-z][a-zA-Z0-9]*$"),
536             "44:30: "
537                 + getCheckMessage(AbstractNameCheck.class,
538                     MSG_INVALID_PATTERN, "abc", "^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$"),
539             "47:9: "
540                 + getCheckMessage(AbstractNameCheck.class,
541                     MSG_INVALID_PATTERN, "line_length", "^[a-z][a-zA-Z0-9]*$"),
542             "50:18: "
543                 + getCheckMessage(AbstractNameCheck.class,
544                     MSG_INVALID_PATTERN, "ID", "^[a-z][a-zA-Z0-9]*$"),
545             "52:57: "
546                 + getCheckMessage(AbstractNameCheck.class,
547                     MSG_INVALID_PATTERN, "ID3", "^[a-z][a-zA-Z0-9]*$"),
548             "55:17: "
549                 + getCheckMessage(AbstractNameCheck.class,
550                     MSG_INVALID_PATTERN, "DEF", "^[a-z][a-zA-Z0-9]*$"),
551             "58:17: "
552                 + getCheckMessage(AbstractNameCheck.class,
553                     MSG_INVALID_PATTERN, "XYZ", "^[a-z][a-zA-Z0-9]*$"),
554         };
555 
556         verifySuppressedWithParser(getPath("InputSuppressWithNearbyCommentFilterByCheck.java"),
557                                    expectedViolationMessages, suppressedViolationMessages);
558     }
559 
560     @Test
561     public void testSuppressById() throws Exception {
562         final String[] suppressedViolationMessages = {
563             "41:17: "
564                 + getCheckMessage(AbstractNameCheck.class,
565                     MSG_INVALID_PATTERN, "A1", "^[a-z][a-zA-Z0-9]*$"),
566             "47:9: "
567                 + getCheckMessage(AbstractNameCheck.class,
568                     MSG_INVALID_PATTERN, "line_length", "^[a-z][a-zA-Z0-9]*$"),
569             "52:57: "
570                 + getCheckMessage(AbstractNameCheck.class,
571                     MSG_INVALID_PATTERN, "ID3", "^[a-z][a-zA-Z0-9]*$"),
572         };
573         final String[] expectedViolationMessages = {
574             "41:17: "
575                 + getCheckMessage(AbstractNameCheck.class,
576                     MSG_INVALID_PATTERN, "A1", "^[a-z][a-zA-Z0-9]*$"),
577             "44:30: "
578                 + getCheckMessage(AbstractNameCheck.class,
579                     MSG_INVALID_PATTERN, "abc", "^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$"),
580             "47:9: "
581                 + getCheckMessage(AbstractNameCheck.class,
582                     MSG_INVALID_PATTERN, "line_length", "^[a-z][a-zA-Z0-9]*$"),
583             "50:18: "
584                 + getCheckMessage(AbstractNameCheck.class,
585                     MSG_INVALID_PATTERN, "ID", "^[a-z][a-zA-Z0-9]*$"),
586             "52:57: "
587                 + getCheckMessage(AbstractNameCheck.class,
588                     MSG_INVALID_PATTERN, "ID3", "^[a-z][a-zA-Z0-9]*$"),
589             "55:17: "
590                 + getCheckMessage(AbstractNameCheck.class,
591                     MSG_INVALID_PATTERN, "DEF", "^[a-z][a-zA-Z0-9]*$"),
592             "58:17: "
593                 + getCheckMessage(AbstractNameCheck.class,
594                     MSG_INVALID_PATTERN, "XYZ", "^[a-z][a-zA-Z0-9]*$"),
595         };
596 
597         verifySuppressedWithParser(getPath("InputSuppressWithNearbyCommentFilterById.java"),
598                                    expectedViolationMessages, suppressedViolationMessages);
599     }
600 
601     @Test
602     public void testSuppressByCheckAndId() throws Exception {
603         final String[] suppressedViolationMessages = {
604             "41:17: "
605                 + getCheckMessage(AbstractNameCheck.class,
606                     MSG_INVALID_PATTERN, "A1", "^[a-z][a-zA-Z0-9]*$"),
607             "47:9: "
608                 + getCheckMessage(AbstractNameCheck.class,
609                     MSG_INVALID_PATTERN, "line_length", "^[a-z][a-zA-Z0-9]*$"),
610             "52:57: "
611                 + getCheckMessage(AbstractNameCheck.class,
612                     MSG_INVALID_PATTERN, "ID3", "^[a-z][a-zA-Z0-9]*$"),
613         };
614         final String[] expectedViolationMessages = {
615             "41:17: "
616                 + getCheckMessage(AbstractNameCheck.class,
617                     MSG_INVALID_PATTERN, "A1", "^[a-z][a-zA-Z0-9]*$"),
618             "44:30: "
619                 + getCheckMessage(AbstractNameCheck.class,
620                     MSG_INVALID_PATTERN, "abc", "^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$"),
621             "47:9: "
622                 + getCheckMessage(AbstractNameCheck.class,
623                     MSG_INVALID_PATTERN, "line_length", "^[a-z][a-zA-Z0-9]*$"),
624             "50:18: "
625                 + getCheckMessage(AbstractNameCheck.class,
626                     MSG_INVALID_PATTERN, "ID", "^[a-z][a-zA-Z0-9]*$"),
627             "52:57: "
628                 + getCheckMessage(AbstractNameCheck.class,
629                     MSG_INVALID_PATTERN, "ID3", "^[a-z][a-zA-Z0-9]*$"),
630             "55:17: "
631                 + getCheckMessage(AbstractNameCheck.class,
632                     MSG_INVALID_PATTERN, "DEF", "^[a-z][a-zA-Z0-9]*$"),
633             "58:17: "
634                 + getCheckMessage(AbstractNameCheck.class,
635                     MSG_INVALID_PATTERN, "XYZ", "^[a-z][a-zA-Z0-9]*$"),
636         };
637 
638         verifySuppressedWithParser(
639             getPath("InputSuppressWithNearbyCommentFilterByCheckAndId.java"),
640                                    expectedViolationMessages, suppressedViolationMessages);
641     }
642 
643     @Test
644     public void testSuppressByCheckAndNonMatchingId() throws Exception {
645         final String[] suppressedViolationMessages = CommonUtil.EMPTY_STRING_ARRAY;
646         final String[] expectedViolationMessages = {
647             "41:17: "
648                 + getCheckMessage(AbstractNameCheck.class,
649                     MSG_INVALID_PATTERN, "A1", "^[a-z][a-zA-Z0-9]*$"),
650             "44:30: "
651                 + getCheckMessage(AbstractNameCheck.class,
652                     MSG_INVALID_PATTERN, "abc", "^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$"),
653             "47:9: "
654                 + getCheckMessage(AbstractNameCheck.class,
655                     MSG_INVALID_PATTERN, "line_length", "^[a-z][a-zA-Z0-9]*$"),
656             "50:18: "
657                 + getCheckMessage(AbstractNameCheck.class,
658                     MSG_INVALID_PATTERN, "ID", "^[a-z][a-zA-Z0-9]*$"),
659             "52:57: "
660                 + getCheckMessage(AbstractNameCheck.class,
661                     MSG_INVALID_PATTERN, "ID3", "^[a-z][a-zA-Z0-9]*$"),
662             "55:17: "
663                 + getCheckMessage(AbstractNameCheck.class,
664                     MSG_INVALID_PATTERN, "DEF", "^[a-z][a-zA-Z0-9]*$"),
665             "58:17: "
666                 + getCheckMessage(AbstractNameCheck.class,
667                     MSG_INVALID_PATTERN, "XYZ", "^[a-z][a-zA-Z0-9]*$"),
668         };
669 
670         verifySuppressedWithParser(
671             getPath("InputSuppressWithNearbyCommentFilterByCheckAndNonMatchingId.java"),
672             expectedViolationMessages, suppressedViolationMessages);
673     }
674 
675     @Test
676     public void tesSuppressByIdAndMessage() throws Exception {
677         final String[] suppressedViolationMessages = {
678             "55:17: "
679                 + getCheckMessage(AbstractNameCheck.class,
680                     MSG_INVALID_PATTERN, "DEF", "^[a-z][a-zA-Z0-9]*$"),
681         };
682         final String[] expectedViolationMessages = {
683             "41:17: "
684                 + getCheckMessage(AbstractNameCheck.class,
685                     MSG_INVALID_PATTERN, "A1", "^[a-z][a-zA-Z0-9]*$"),
686             "44:30: "
687                 + getCheckMessage(AbstractNameCheck.class,
688                     MSG_INVALID_PATTERN, "abc", "^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$"),
689             "47:9: "
690                 + getCheckMessage(AbstractNameCheck.class,
691                     MSG_INVALID_PATTERN, "line_length", "^[a-z][a-zA-Z0-9]*$"),
692             "50:18: "
693                 + getCheckMessage(AbstractNameCheck.class,
694                     MSG_INVALID_PATTERN, "ID", "^[a-z][a-zA-Z0-9]*$"),
695             "52:57: "
696                 + getCheckMessage(AbstractNameCheck.class,
697                     MSG_INVALID_PATTERN, "ID3", "^[a-z][a-zA-Z0-9]*$"),
698             "55:17: "
699                 + getCheckMessage(AbstractNameCheck.class,
700                     MSG_INVALID_PATTERN, "DEF", "^[a-z][a-zA-Z0-9]*$"),
701             "58:17: "
702                 + getCheckMessage(AbstractNameCheck.class,
703                     MSG_INVALID_PATTERN, "XYZ", "^[a-z][a-zA-Z0-9]*$"),
704         };
705 
706         verifySuppressedWithParser(
707             getPath("InputSuppressWithNearbyCommentFilterByIdAndMessage.java"),
708             expectedViolationMessages, suppressedViolationMessages);
709     }
710 
711     @Test
712     public void tesSuppressByCheckAndMessage() throws Exception {
713         final String[] suppressedViolationMessages = {
714             "55:17: "
715                 + getCheckMessage(AbstractNameCheck.class,
716                     MSG_INVALID_PATTERN, "DEF", "^[a-z][a-zA-Z0-9]*$"),
717         };
718         final String[] expectedViolationMessages = {
719             "41:17: "
720                 + getCheckMessage(AbstractNameCheck.class,
721                     MSG_INVALID_PATTERN, "A1", "^[a-z][a-zA-Z0-9]*$"),
722             "44:30: "
723                 + getCheckMessage(AbstractNameCheck.class,
724                     MSG_INVALID_PATTERN, "abc", "^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$"),
725             "47:9: "
726                 + getCheckMessage(AbstractNameCheck.class,
727                     MSG_INVALID_PATTERN, "line_length", "^[a-z][a-zA-Z0-9]*$"),
728             "50:18: "
729                 + getCheckMessage(AbstractNameCheck.class,
730                     MSG_INVALID_PATTERN, "ID", "^[a-z][a-zA-Z0-9]*$"),
731             "52:57: "
732                 + getCheckMessage(AbstractNameCheck.class,
733                     MSG_INVALID_PATTERN, "ID3", "^[a-z][a-zA-Z0-9]*$"),
734             "55:17: "
735                 + getCheckMessage(AbstractNameCheck.class,
736                     MSG_INVALID_PATTERN, "DEF", "^[a-z][a-zA-Z0-9]*$"),
737             "58:17: "
738                 + getCheckMessage(AbstractNameCheck.class,
739                     MSG_INVALID_PATTERN, "XYZ", "^[a-z][a-zA-Z0-9]*$"),
740         };
741 
742         verifySuppressedWithParser(
743             getPath("InputSuppressWithNearbyCommentFilterByCheckAndMessage.java"),
744             expectedViolationMessages, suppressedViolationMessages);
745     }
746 
747     @Test
748     public void testTagsAreClearedEachRun() {
749         final SuppressWithNearbyCommentFilter suppressionCommentFilter =
750                 new SuppressWithNearbyCommentFilter();
751         final List<?> tags1 = getTagsAfterExecution(suppressionCommentFilter,
752                 "filename1", "//SUPPRESS CHECKSTYLE ignore this");
753         assertWithMessage("Invalid tags size")
754             .that(tags1)
755             .hasSize(1);
756         final List<?> tags2 = getTagsAfterExecution(suppressionCommentFilter,
757                 "filename2", "No comments in this file");
758         assertWithMessage("Invalid tags size")
759             .that(tags2)
760             .isEmpty();
761     }
762 
763     /**
764      * Calls the filter with a minimal set of inputs and returns a list of
765      * {@link SuppressWithNearbyCommentFilter} internal type {@code Tag}.
766      * Our goal is 100% test coverage, for this we use white-box testing.
767      * So we need access to the implementation details. For this reason,
768      * it is necessary to use reflection to gain access to the inner field here.
769      *
770      * @return {@code Tag} list
771      */
772     private static List<?> getTagsAfterExecution(SuppressWithNearbyCommentFilter filter,
773             String filename, String... lines) {
774         final FileContents contents = new FileContents(
775                 new FileText(new File(filename), Arrays.asList(lines)));
776         contents.reportSingleLineComment(1, 0);
777         final TreeWalkerAuditEvent dummyEvent = new TreeWalkerAuditEvent(contents, filename,
778                 new Violation(1, null, null, null, null, Object.class, null), null);
779         filter.accept(dummyEvent);
780         return TestUtil.getInternalState(filter, "tags");
781     }
782 
783 }