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.javadoc.JavadocMethodCheck.MSG_EXPECTED_TAG;
24  import static com.puppycrawl.tools.checkstyle.checks.javadoc.JavadocMethodCheck.MSG_RETURN_EXPECTED;
25  import static com.puppycrawl.tools.checkstyle.checks.javadoc.JavadocMethodCheck.MSG_UNUSED_TAG;
26  import static com.puppycrawl.tools.checkstyle.checks.whitespace.FileTabCharacterCheck.MSG_CONTAINS_TAB;
27  import static com.puppycrawl.tools.checkstyle.checks.whitespace.FileTabCharacterCheck.MSG_FILE_CONTAINS_TAB;
28  
29  import java.io.FileNotFoundException;
30  import java.io.IOException;
31  import java.util.Arrays;
32  
33  import org.junit.jupiter.api.Test;
34  
35  import com.puppycrawl.tools.checkstyle.AbstractModuleTestSupport;
36  import com.puppycrawl.tools.checkstyle.DefaultConfiguration;
37  import com.puppycrawl.tools.checkstyle.api.AuditEvent;
38  import com.puppycrawl.tools.checkstyle.api.CheckstyleException;
39  import com.puppycrawl.tools.checkstyle.api.Configuration;
40  import com.puppycrawl.tools.checkstyle.api.SeverityLevel;
41  import com.puppycrawl.tools.checkstyle.api.TokenTypes;
42  import com.puppycrawl.tools.checkstyle.api.Violation;
43  import com.puppycrawl.tools.checkstyle.checks.javadoc.JavadocMethodCheck;
44  import com.puppycrawl.tools.checkstyle.checks.regexp.RegexpSinglelineCheck;
45  import com.puppycrawl.tools.checkstyle.checks.whitespace.FileTabCharacterCheck;
46  import com.puppycrawl.tools.checkstyle.internal.utils.TestUtil;
47  import com.puppycrawl.tools.checkstyle.utils.CommonUtil;
48  import nl.jqno.equalsverifier.EqualsVerifier;
49  import nl.jqno.equalsverifier.EqualsVerifierReport;
50  
51  public class SuppressWithPlainTextCommentFilterTest extends AbstractModuleTestSupport {
52  
53      private static final String MSG_REGEXP_EXCEEDED = "regexp.exceeded";
54  
55      @Override
56      protected String getPackageLocation() {
57          return "com/puppycrawl/tools/checkstyle/filters/suppresswithplaintextcommentfilter";
58      }
59  
60      @Test
61      public void testFilterWithDefaultConfig() throws Exception {
62          final String[] suppressed = {
63              "20:7: " + getCheckMessage(FileTabCharacterCheck.class, MSG_CONTAINS_TAB),
64              "28:1: " + getCheckMessage(FileTabCharacterCheck.class, MSG_CONTAINS_TAB),
65          };
66  
67          final String[] violationMessages = {
68              "20:7: " + getCheckMessage(FileTabCharacterCheck.class, MSG_CONTAINS_TAB),
69              "24:7: " + getCheckMessage(FileTabCharacterCheck.class, MSG_CONTAINS_TAB),
70              "28:1: " + getCheckMessage(FileTabCharacterCheck.class, MSG_CONTAINS_TAB),
71          };
72  
73          verifyFilterWithInlineConfigParser(
74              getPath("InputSuppressWithPlainTextCommentFilterWithDefaultCfg.java"),
75              violationMessages, removeSuppressed(violationMessages, suppressed));
76      }
77  
78      @Test
79      public void testChangeOffAndOnFormat() throws Exception {
80          final String[] suppressed = {
81              "20:7: " + getCheckMessage(FileTabCharacterCheck.class, MSG_CONTAINS_TAB),
82              "27:30: " + getCheckMessage(FileTabCharacterCheck.class, MSG_CONTAINS_TAB),
83          };
84  
85          final String[] violationMessage = {
86              "20:7: " + getCheckMessage(FileTabCharacterCheck.class, MSG_CONTAINS_TAB),
87              "24:7: " + getCheckMessage(FileTabCharacterCheck.class, MSG_CONTAINS_TAB),
88              "27:30: " + getCheckMessage(FileTabCharacterCheck.class, MSG_CONTAINS_TAB),
89              "30:13: " + getCheckMessage(FileTabCharacterCheck.class, MSG_CONTAINS_TAB),
90          };
91  
92          verifyFilterWithInlineConfigParser(
93              getPath("InputSuppressWithPlainTextCommentFilterWithCustomOnAndOffComments.java"),
94              violationMessage, removeSuppressed(violationMessage, suppressed));
95      }
96  
97      @Test
98      public void testSuppressionCommentsInXmlFile() throws Exception {
99          final DefaultConfiguration filterCfg =
100             createModuleConfig(SuppressWithPlainTextCommentFilter.class);
101         filterCfg.addProperty("offCommentFormat", "CS-OFF");
102         filterCfg.addProperty("onCommentFormat", "CS-ON");
103 
104         final DefaultConfiguration checkCfg = createModuleConfig(FileTabCharacterCheck.class);
105         checkCfg.addProperty("eachLine", "true");
106 
107         final String[] suppressed = {
108             "7:1: " + getCheckMessage(FileTabCharacterCheck.class, MSG_CONTAINS_TAB),
109         };
110 
111         final String[] violationMessages = {
112             "7:1: " + getCheckMessage(FileTabCharacterCheck.class, MSG_CONTAINS_TAB),
113             "10:1: " + getCheckMessage(FileTabCharacterCheck.class, MSG_CONTAINS_TAB),
114         };
115 
116         verifySuppressed(
117             "InputSuppressWithPlainTextCommentFilter.xml",
118             removeSuppressed(violationMessages, suppressed),
119             filterCfg, checkCfg
120         );
121     }
122 
123     @Test
124     public void testSuppressionCommentsInPropertiesFile() throws Exception {
125         final DefaultConfiguration filterCfg =
126             createModuleConfig(SuppressWithPlainTextCommentFilter.class);
127         filterCfg.addProperty("offCommentFormat", "# CHECKSTYLE:OFF");
128         filterCfg.addProperty("onCommentFormat", "# CHECKSTYLE:ON");
129 
130         final DefaultConfiguration checkCfg = createModuleConfig(RegexpSinglelineCheck.class);
131         checkCfg.addProperty("format", "^key[0-9]=$");
132 
133         final String[] suppressed = {
134             "2: " + getCheckMessage(RegexpSinglelineCheck.class, MSG_REGEXP_EXCEEDED,
135                 "^key[0-9]=$"),
136         };
137 
138         final String[] violationMessages = {
139             "2: " + getCheckMessage(RegexpSinglelineCheck.class, MSG_REGEXP_EXCEEDED,
140                 "^key[0-9]=$"),
141             "4: " + getCheckMessage(RegexpSinglelineCheck.class, MSG_REGEXP_EXCEEDED,
142                 "^key[0-9]=$"),
143         };
144 
145         verifySuppressed(
146             "InputSuppressWithPlainTextCommentFilter.properties",
147             removeSuppressed(violationMessages, suppressed),
148             filterCfg, checkCfg
149         );
150     }
151 
152     @Test
153     public void testSuppressionCommentsInSqlFile() throws Exception {
154         final DefaultConfiguration filterCfg =
155             createModuleConfig(SuppressWithPlainTextCommentFilter.class);
156         filterCfg.addProperty("offCommentFormat", "-- CHECKSTYLE OFF");
157         filterCfg.addProperty("onCommentFormat", "-- CHECKSTYLE ON");
158 
159         final DefaultConfiguration checkCfg = createModuleConfig(FileTabCharacterCheck.class);
160         checkCfg.addProperty("eachLine", "true");
161 
162         final String[] suppressed = {
163             "2:1: " + getCheckMessage(FileTabCharacterCheck.class, MSG_CONTAINS_TAB),
164         };
165 
166         final String[] violationMessages = {
167             "2:1: " + getCheckMessage(FileTabCharacterCheck.class, MSG_CONTAINS_TAB),
168             "5:1: " + getCheckMessage(FileTabCharacterCheck.class, MSG_CONTAINS_TAB),
169         };
170 
171         verifySuppressed(
172             "InputSuppressWithPlainTextCommentFilter.sql",
173             removeSuppressed(violationMessages, suppressed),
174             filterCfg, checkCfg
175         );
176     }
177 
178     @Test
179     public void testSuppressionCommentsInJavaScriptFile() throws Exception {
180         final String[] suppressed = {
181             "22: " + getCheckMessage(RegexpSinglelineCheck.class,
182                     MSG_REGEXP_EXCEEDED, ".*\\s===.*"),
183         };
184 
185         final String[] violationMessages = {
186             "22: " + getCheckMessage(RegexpSinglelineCheck.class,
187                     MSG_REGEXP_EXCEEDED, ".*\\s===.*"),
188             "25: " + getCheckMessage(RegexpSinglelineCheck.class,
189                     MSG_REGEXP_EXCEEDED, ".*\\s===.*"),
190         };
191 
192         verifyFilterWithInlineConfigParser(
193             getPath("InputSuppressWithPlainTextCommentFilter.js"),
194             violationMessages,
195             removeSuppressed(violationMessages, suppressed)
196         );
197     }
198 
199     @Test
200     public void testInvalidCheckFormat() throws Exception {
201         final DefaultConfiguration filterCfg =
202             createModuleConfig(SuppressWithPlainTextCommentFilter.class);
203         filterCfg.addProperty("checkFormat", "e[l");
204         filterCfg.addProperty("onCommentFormat", "// cs-on");
205         filterCfg.addProperty("offCommentFormat", "// cs-off");
206 
207         final DefaultConfiguration checkCfg = createModuleConfig(FileTabCharacterCheck.class);
208         checkCfg.addProperty("eachLine", "true");
209 
210         final String[] suppressed = CommonUtil.EMPTY_STRING_ARRAY;
211 
212         final String[] violationMessages = {
213             "5:7: " + getCheckMessage(FileTabCharacterCheck.class, MSG_FILE_CONTAINS_TAB),
214             "8:7: " + getCheckMessage(FileTabCharacterCheck.class, MSG_CONTAINS_TAB),
215             "10:1: " + getCheckMessage(FileTabCharacterCheck.class, MSG_CONTAINS_TAB),
216         };
217 
218         try {
219             verifySuppressed(
220                 "InputSuppressWithPlainTextCommentFilterWithCustomOnAndOffComments.java",
221                 removeSuppressed(violationMessages, suppressed),
222                 filterCfg, checkCfg
223             );
224             assertWithMessage("CheckstyleException is expected").fail();
225         }
226         catch (CheckstyleException ex) {
227             final IllegalArgumentException cause = (IllegalArgumentException) ex.getCause();
228             assertWithMessage("Invalid exception message")
229                 .that(cause)
230                 .hasMessageThat()
231                 .isEqualTo("unable to parse expanded comment e[l");
232         }
233     }
234 
235     @Test
236     public void testInvalidIdFormat() throws Exception {
237         final DefaultConfiguration filterCfg =
238             createModuleConfig(SuppressWithPlainTextCommentFilter.class);
239         filterCfg.addProperty("idFormat", "e[l");
240         filterCfg.addProperty("onCommentFormat", "// cs-on");
241         filterCfg.addProperty("offCommentFormat", "// cs-off");
242 
243         final DefaultConfiguration checkCfg = createModuleConfig(FileTabCharacterCheck.class);
244         checkCfg.addProperty("eachLine", "true");
245 
246         try {
247             verifySuppressed(
248                 "InputSuppressWithPlainTextCommentFilterWithCustomOnAndOffComments.java",
249                 CommonUtil.EMPTY_STRING_ARRAY, filterCfg, checkCfg
250             );
251             assertWithMessage("CheckstyleException is expected").fail();
252         }
253         catch (CheckstyleException ex) {
254             final IllegalArgumentException cause = (IllegalArgumentException) ex.getCause();
255             assertWithMessage("Invalid exception message")
256                 .that(cause)
257                 .hasMessageThat()
258                 .isEqualTo("unable to parse expanded comment e[l");
259         }
260     }
261 
262     @Test
263     public void testInvalidMessageFormat() throws Exception {
264         final DefaultConfiguration filterCfg =
265             createModuleConfig(SuppressWithPlainTextCommentFilter.class);
266         filterCfg.addProperty("messageFormat", "e[l");
267         filterCfg.addProperty("onCommentFormat", "// cs-on");
268         filterCfg.addProperty("offCommentFormat", "// cs-off");
269 
270         final DefaultConfiguration checkCfg = createModuleConfig(FileTabCharacterCheck.class);
271         checkCfg.addProperty("eachLine", "true");
272 
273         final String[] suppressed = CommonUtil.EMPTY_STRING_ARRAY;
274 
275         final String[] violationMessages = {
276             "5:7: " + getCheckMessage(FileTabCharacterCheck.class, MSG_FILE_CONTAINS_TAB),
277             "8:7: " + getCheckMessage(FileTabCharacterCheck.class, MSG_CONTAINS_TAB),
278             "10:1: " + getCheckMessage(FileTabCharacterCheck.class, MSG_CONTAINS_TAB),
279         };
280 
281         try {
282             verifySuppressed(
283                 "InputSuppressWithPlainTextCommentFilterWithCustomOnAndOffComments.java",
284                 removeSuppressed(violationMessages, suppressed),
285                 filterCfg, checkCfg
286             );
287             assertWithMessage("CheckstyleException is expected").fail();
288         }
289         catch (CheckstyleException ex) {
290             final IllegalArgumentException cause = (IllegalArgumentException) ex.getCause();
291             assertWithMessage("Invalid exception message")
292                 .that(cause)
293                 .hasMessageThat()
294                 .isEqualTo("unable to parse expanded comment e[l");
295         }
296     }
297 
298     @Test
299     public void testInvalidMessageFormatInSqlFile() throws Exception {
300         final DefaultConfiguration filterCfg =
301             createModuleConfig(SuppressWithPlainTextCommentFilter.class);
302         filterCfg.addProperty("onCommentFormat", "CSON (\\w+)");
303         filterCfg.addProperty("messageFormat", "e[l");
304 
305         final DefaultConfiguration checkCfg = createModuleConfig(RegexpSinglelineCheck.class);
306         checkCfg.addProperty("format", "^.*COUNT\\(\\*\\).*$");
307 
308         final String[] suppressed = CommonUtil.EMPTY_STRING_ARRAY;
309 
310         final String[] violationMessages = {
311             "2: " + getCheckMessage(RegexpSinglelineCheck.class, MSG_REGEXP_EXCEEDED,
312                     "^.*COUNT\\(\\*\\).*$"),
313         };
314 
315         try {
316             verifySuppressed(
317                 "InputSuppressWithPlainTextCommentFilterWithCustomOnComment.sql",
318                 removeSuppressed(violationMessages, suppressed),
319                 filterCfg, checkCfg
320             );
321             assertWithMessage("CheckstyleException is expected").fail();
322         }
323         catch (CheckstyleException ex) {
324             final IllegalArgumentException cause = (IllegalArgumentException) ex.getCause();
325             assertWithMessage("Invalid exception message")
326                 .that(cause)
327                 .hasMessageThat()
328                 .isEqualTo("unable to parse expanded comment e[l");
329         }
330     }
331 
332     @Test
333     public void testAcceptNullViolation() {
334         final SuppressWithPlainTextCommentFilter filter = new SuppressWithPlainTextCommentFilter();
335         final AuditEvent auditEvent = new AuditEvent(this);
336         assertWithMessage("Filter should accept audit event")
337                 .that(filter.accept(auditEvent))
338                 .isTrue();
339         assertWithMessage("File name should not be null")
340             .that(auditEvent.getFileName())
341             .isNull();
342     }
343 
344     /**
345      * Our goal is 100% test coverage, for this we use white-box testing.
346      * So we need access to the implementation details. For this reason, it is necessary
347      * to use reflection to gain access to the inner type {@code Suppression} here.
348      */
349     @Test
350     public void testEqualsAndHashCodeOfSuppressionClass() throws ClassNotFoundException {
351         final Class<?> suppressionClass = TestUtil.getInnerClassType(
352                 SuppressWithPlainTextCommentFilter.class, "Suppression");
353         final EqualsVerifierReport ev = EqualsVerifier
354                 .forClass(suppressionClass).usingGetClass()
355                 .report();
356         assertWithMessage("Error: " + ev.getMessage())
357                 .that(ev.isSuccessful())
358                 .isTrue();
359     }
360 
361     @Test
362     public void testSuppressByCheck() throws Exception {
363         final String[] suppressedViolationMessages = {
364             "36:1: " + getCheckMessage(FileTabCharacterCheck.class, MSG_CONTAINS_TAB),
365         };
366 
367         final String[] expectedViolationMessages = {
368             "33: " + getCheckMessage(RegexpSinglelineCheck.class, MSG_REGEXP_EXCEEDED,
369                 ".*[a-zA-Z][0-9].*"),
370             "36: " + getCheckMessage(RegexpSinglelineCheck.class, MSG_REGEXP_EXCEEDED,
371                 ".*[a-zA-Z][0-9].*"),
372             "36:1: " + getCheckMessage(FileTabCharacterCheck.class, MSG_CONTAINS_TAB),
373             "38: " + getCheckMessage(RegexpSinglelineCheck.class, MSG_REGEXP_EXCEEDED,
374                 ".*[a-zA-Z][0-9].*"),
375             "41: " + getCheckMessage(RegexpSinglelineCheck.class, MSG_REGEXP_EXCEEDED,
376                 ".*[a-zA-Z][0-9].*"),
377         };
378 
379         verifyFilterWithInlineConfigParser(
380                 getPath("InputSuppressWithPlainTextCommentFilterSuppressById.java"),
381                 expectedViolationMessages,
382                 removeSuppressed(expectedViolationMessages, suppressedViolationMessages)
383         );
384     }
385 
386     @Test
387     public void testSuppressByModuleId() throws Exception {
388         final String[] suppressedViolationMessages = {
389             "33: " + getCheckMessage(RegexpSinglelineCheck.class, MSG_REGEXP_EXCEEDED,
390                 ".*[a-zA-Z][0-9].*"),
391             "36: " + getCheckMessage(RegexpSinglelineCheck.class, MSG_REGEXP_EXCEEDED,
392                 ".*[a-zA-Z][0-9].*"),
393             "38: " + getCheckMessage(RegexpSinglelineCheck.class, MSG_REGEXP_EXCEEDED,
394                 ".*[a-zA-Z][0-9].*"),
395         };
396 
397         final String[] expectedViolationMessages = {
398             "30: " + getCheckMessage(RegexpSinglelineCheck.class, MSG_REGEXP_EXCEEDED,
399                 ".*[a-zA-Z][0-9].*"),
400             "33: " + getCheckMessage(RegexpSinglelineCheck.class, MSG_REGEXP_EXCEEDED,
401                 ".*[a-zA-Z][0-9].*"),
402             "36:1: " + getCheckMessage(FileTabCharacterCheck.class, MSG_CONTAINS_TAB),
403             "36: " + getCheckMessage(RegexpSinglelineCheck.class, MSG_REGEXP_EXCEEDED,
404                 ".*[a-zA-Z][0-9].*"),
405             "38: " + getCheckMessage(RegexpSinglelineCheck.class, MSG_REGEXP_EXCEEDED,
406                 ".*[a-zA-Z][0-9].*"),
407             "41: " + getCheckMessage(RegexpSinglelineCheck.class, MSG_REGEXP_EXCEEDED,
408                 ".*[a-zA-Z][0-9].*"),
409         };
410 
411         verifyFilterWithInlineConfigParser(
412             getPath("InputSuppressWithPlainTextCommentFilterSuppressById2.java"),
413             expectedViolationMessages,
414             removeSuppressed(expectedViolationMessages, suppressedViolationMessages)
415         );
416     }
417 
418     @Test
419     public void testSuppressByCheckAndModuleId() throws Exception {
420         final String[] suppressedViolationMessages = {
421             "36:1: " + getCheckMessage(FileTabCharacterCheck.class, MSG_CONTAINS_TAB),
422         };
423 
424         final String[] expectedViolationMessages = {
425             "30: " + getCheckMessage(RegexpSinglelineCheck.class, MSG_REGEXP_EXCEEDED,
426                 ".*[a-zA-Z][0-9].*"),
427             "33: " + getCheckMessage(RegexpSinglelineCheck.class, MSG_REGEXP_EXCEEDED,
428                 ".*[a-zA-Z][0-9].*"),
429             "36:1: " + getCheckMessage(FileTabCharacterCheck.class, MSG_CONTAINS_TAB),
430             "36: " + getCheckMessage(RegexpSinglelineCheck.class, MSG_REGEXP_EXCEEDED,
431                 ".*[a-zA-Z][0-9].*"),
432             "38: " + getCheckMessage(RegexpSinglelineCheck.class, MSG_REGEXP_EXCEEDED,
433                 ".*[a-zA-Z][0-9].*"),
434             "41: " + getCheckMessage(RegexpSinglelineCheck.class, MSG_REGEXP_EXCEEDED,
435                 ".*[a-zA-Z][0-9].*"),
436         };
437 
438         verifyFilterWithInlineConfigParser(
439             getPath("InputSuppressWithPlainTextCommentFilterSuppressById3.java"),
440             expectedViolationMessages,
441             removeSuppressed(expectedViolationMessages, suppressedViolationMessages)
442         );
443     }
444 
445     @Test
446     public void testSuppressByCheckAndNonMatchingModuleId() throws Exception {
447         final String[] suppressedViolationMessages = CommonUtil.EMPTY_STRING_ARRAY;
448 
449         final String[] expectedViolationMessages = {
450             "30: " + getCheckMessage(RegexpSinglelineCheck.class, MSG_REGEXP_EXCEEDED,
451                 ".*[a-zA-Z][0-9].*"),
452             "33: " + getCheckMessage(RegexpSinglelineCheck.class, MSG_REGEXP_EXCEEDED,
453                 ".*[a-zA-Z][0-9].*"),
454             "36:1: " + getCheckMessage(FileTabCharacterCheck.class, MSG_CONTAINS_TAB),
455             "36: " + getCheckMessage(RegexpSinglelineCheck.class, MSG_REGEXP_EXCEEDED,
456                 ".*[a-zA-Z][0-9].*"),
457             "38: " + getCheckMessage(RegexpSinglelineCheck.class, MSG_REGEXP_EXCEEDED,
458                 ".*[a-zA-Z][0-9].*"),
459             "41: " + getCheckMessage(RegexpSinglelineCheck.class, MSG_REGEXP_EXCEEDED,
460                 ".*[a-zA-Z][0-9].*"),
461         };
462 
463         verifyFilterWithInlineConfigParser(
464             getPath("InputSuppressWithPlainTextCommentFilterSuppressById4.java"),
465             expectedViolationMessages,
466             removeSuppressed(expectedViolationMessages, suppressedViolationMessages)
467         );
468     }
469 
470     @Test
471     public void testSuppressByModuleIdWithNullModuleId() throws Exception {
472         final String[] suppressedViolationMessages = {
473             "33: " + getCheckMessage(RegexpSinglelineCheck.class, MSG_REGEXP_EXCEEDED,
474                 ".*[a-zA-Z][0-9].*"),
475             "36: " + getCheckMessage(RegexpSinglelineCheck.class, MSG_REGEXP_EXCEEDED,
476                 ".*[a-zA-Z][0-9].*"),
477             "38: " + getCheckMessage(RegexpSinglelineCheck.class, MSG_REGEXP_EXCEEDED,
478                 ".*[a-zA-Z][0-9].*"),
479         };
480 
481         final String[] expectedViolationMessages = {
482             "30: " + getCheckMessage(RegexpSinglelineCheck.class, MSG_REGEXP_EXCEEDED,
483                 ".*[a-zA-Z][0-9].*"),
484             "33: " + getCheckMessage(RegexpSinglelineCheck.class, MSG_REGEXP_EXCEEDED,
485                 ".*[a-zA-Z][0-9].*"),
486             "36:1: " + getCheckMessage(FileTabCharacterCheck.class, MSG_CONTAINS_TAB),
487             "36: " + getCheckMessage(RegexpSinglelineCheck.class, MSG_REGEXP_EXCEEDED,
488                 ".*[a-zA-Z][0-9].*"),
489             "38: " + getCheckMessage(RegexpSinglelineCheck.class, MSG_REGEXP_EXCEEDED,
490                 ".*[a-zA-Z][0-9].*"),
491             "41: " + getCheckMessage(RegexpSinglelineCheck.class, MSG_REGEXP_EXCEEDED,
492                 ".*[a-zA-Z][0-9].*"),
493         };
494 
495         verifyFilterWithInlineConfigParser(
496             getPath("InputSuppressWithPlainTextCommentFilterSuppressById5.java"),
497             expectedViolationMessages,
498             removeSuppressed(expectedViolationMessages, suppressedViolationMessages)
499         );
500     }
501 
502     @Test
503     public void testSuppressedByIdJavadocCheck() throws Exception {
504         final String[] suppressedViolationMessages = {
505             "28: " + getCheckMessage(JavadocMethodCheck.class, MSG_RETURN_EXPECTED),
506             "32:9: " + getCheckMessage(JavadocMethodCheck.class,
507                                        MSG_UNUSED_TAG, "@param", "unused"),
508             "39:22: " + getCheckMessage(JavadocMethodCheck.class,
509                                         MSG_EXPECTED_TAG, "@param", "a"),
510         };
511 
512         final String[] expectedViolationMessages = {
513             "28: " + getCheckMessage(JavadocMethodCheck.class, MSG_RETURN_EXPECTED),
514             "32:9: " + getCheckMessage(JavadocMethodCheck.class,
515                                        MSG_UNUSED_TAG, "@param", "unused"),
516             "39:22: " + getCheckMessage(JavadocMethodCheck.class,
517                                         MSG_EXPECTED_TAG, "@param", "a"),
518         };
519 
520         verifyFilterWithInlineConfigParser(
521             getPath("InputSuppressWithPlainTextCommentFilterSuppressByIdJavadocCheck.java"),
522             expectedViolationMessages,
523             removeSuppressed(expectedViolationMessages, suppressedViolationMessages)
524         );
525     }
526 
527     @Test
528     public void testAcceptThrowsIllegalStateExceptionAsFileNotFound() {
529         final Violation message = new Violation(1, 1, 1, TokenTypes.CLASS_DEF,
530             "messages.properties", "key", null, SeverityLevel.ERROR, null, getClass(), null);
531         final String fileName = "nonexisting_file";
532         final AuditEvent auditEvent = new AuditEvent(this, fileName, message);
533 
534         final SuppressWithPlainTextCommentFilter filter = new SuppressWithPlainTextCommentFilter();
535 
536         try {
537             filter.accept(auditEvent);
538             assertWithMessage(IllegalStateException.class.getSimpleName() + " is expected").fail();
539         }
540         catch (IllegalStateException ex) {
541             assertWithMessage("Invalid exception message")
542                 .that(ex.getMessage())
543                 .isEqualTo("Cannot read source file: " + fileName);
544 
545             final Throwable cause = ex.getCause();
546             assertWithMessage("Exception cause has invalid type")
547                     .that(cause)
548                     .isInstanceOf(FileNotFoundException.class);
549             assertWithMessage("Invalid exception message")
550                 .that(cause)
551                 .hasMessageThat()
552                 .isEqualTo(fileName + " (No such file or directory)");
553         }
554     }
555 
556     @Test
557     public void testFilterWithCustomMessageFormat() throws Exception {
558         final String[] suppressed = {
559             "34:1: " + getCheckMessage(FileTabCharacterCheck.class, MSG_CONTAINS_TAB),
560         };
561 
562         final String[] violationMessages = {
563             "32: " + getCheckMessage(RegexpSinglelineCheck.class, MSG_REGEXP_EXCEEDED,
564                 ".*[a-zA-Z][0-9].*"),
565             "34:1: " + getCheckMessage(FileTabCharacterCheck.class, MSG_CONTAINS_TAB),
566             "34: " + getCheckMessage(RegexpSinglelineCheck.class, MSG_REGEXP_EXCEEDED,
567                 ".*[a-zA-Z][0-9].*"),
568             "36: " + getCheckMessage(RegexpSinglelineCheck.class, MSG_REGEXP_EXCEEDED,
569                 ".*[a-zA-Z][0-9].*"),
570             "39: " + getCheckMessage(RegexpSinglelineCheck.class, MSG_REGEXP_EXCEEDED,
571                 ".*[a-zA-Z][0-9].*"),
572         };
573 
574         verifyFilterWithInlineConfigParser(
575             getPath("InputSuppressWithPlainTextCommentFilterCustomMessageFormat.java"),
576             violationMessages, removeSuppressed(violationMessages, suppressed)
577         );
578     }
579 
580     @Test
581     public void testFilterWithIdAndCustomMessageFormat() throws Exception {
582         final DefaultConfiguration filterCfg =
583             createModuleConfig(SuppressWithPlainTextCommentFilter.class);
584         filterCfg.addProperty("offCommentFormat", "CHECKSTYLE stop (\\w+) (\\w+)");
585         filterCfg.addProperty("onCommentFormat", "CHECKSTYLE resume (\\w+) (\\w+)");
586         filterCfg.addProperty("idFormat", "$1");
587         filterCfg.addProperty("messageFormat", "$2");
588 
589         final DefaultConfiguration regexpCheckCfg = createModuleConfig(RegexpSinglelineCheck.class);
590         regexpCheckCfg.addProperty("id", "warning");
591         regexpCheckCfg.addProperty("format", "^.*COUNT\\(\\*\\).*$");
592 
593         final String[] suppressedViolationMessages = {
594             "2: " + getCheckMessage(RegexpSinglelineCheck.class, MSG_REGEXP_EXCEEDED,
595                 "^.*COUNT\\(\\*\\).*$"),
596         };
597 
598         final String[] expectedViolationMessages = {
599             "2: " + getCheckMessage(RegexpSinglelineCheck.class, MSG_REGEXP_EXCEEDED,
600                 "^.*COUNT\\(\\*\\).*$"),
601             "5: " + getCheckMessage(RegexpSinglelineCheck.class, MSG_REGEXP_EXCEEDED,
602                 "^.*COUNT\\(\\*\\).*$"),
603             "8: " + getCheckMessage(RegexpSinglelineCheck.class, MSG_REGEXP_EXCEEDED,
604                 "^.*COUNT\\(\\*\\).*$"),
605         };
606 
607         verifySuppressed(
608             "InputSuppressWithPlainTextCommentFilterCustomMessageFormat.sql",
609             removeSuppressed(expectedViolationMessages, suppressedViolationMessages),
610             filterCfg, regexpCheckCfg
611         );
612     }
613 
614     @Test
615     public void testFilterWithCheckAndCustomMessageFormat() throws Exception {
616         final DefaultConfiguration filterCfg =
617             createModuleConfig(SuppressWithPlainTextCommentFilter.class);
618         filterCfg.addProperty("offCommentFormat", "CHECKSTYLE stop (\\w+) (\\w+)");
619         filterCfg.addProperty("onCommentFormat", "CHECKSTYLE resume (\\w+) (\\w+)");
620         filterCfg.addProperty("checkFormat", "RegexpSinglelineCheck");
621         filterCfg.addProperty("messageFormat", "$2");
622 
623         final DefaultConfiguration regexpCheckCfg = createModuleConfig(RegexpSinglelineCheck.class);
624         regexpCheckCfg.addProperty("id", "warning");
625         regexpCheckCfg.addProperty("format", "^.*COUNT\\(\\*\\).*$");
626 
627         final String[] suppressedViolationMessages = {
628             "2: " + getCheckMessage(RegexpSinglelineCheck.class, MSG_REGEXP_EXCEEDED,
629                 "^.*COUNT\\(\\*\\).*$"),
630         };
631 
632         final String[] expectedViolationMessages = {
633             "2: " + getCheckMessage(RegexpSinglelineCheck.class, MSG_REGEXP_EXCEEDED,
634                 "^.*COUNT\\(\\*\\).*$"),
635             "5: " + getCheckMessage(RegexpSinglelineCheck.class, MSG_REGEXP_EXCEEDED,
636                 "^.*COUNT\\(\\*\\).*$"),
637             "8: " + getCheckMessage(RegexpSinglelineCheck.class, MSG_REGEXP_EXCEEDED,
638                 "^.*COUNT\\(\\*\\).*$"),
639         };
640 
641         verifySuppressed(
642             "InputSuppressWithPlainTextCommentFilterCustomMessageFormat.sql",
643             removeSuppressed(expectedViolationMessages, suppressedViolationMessages),
644             filterCfg, regexpCheckCfg
645         );
646     }
647 
648     @Test
649     public void testFilterWithDirectory() throws IOException {
650         final SuppressWithPlainTextCommentFilter filter = new SuppressWithPlainTextCommentFilter();
651         final AuditEvent event = new AuditEvent(this, getPath(""), new Violation(1, 1,
652                 "bundle", "key", null, SeverityLevel.ERROR, "moduleId", getClass(),
653                 "customMessage"));
654 
655         assertWithMessage("filter should accept directory")
656                 .that(filter.accept(event))
657                 .isTrue();
658     }
659 
660     private void verifySuppressed(String fileNameWithExtension, String[] violationMessages,
661                                   Configuration... childConfigs) throws Exception {
662         final DefaultConfiguration checkerConfig = createRootConfig(null);
663 
664         Arrays.stream(childConfigs).forEach(checkerConfig::addChild);
665 
666         final String fileExtension = CommonUtil.getFileExtension(fileNameWithExtension);
667         checkerConfig.addProperty("fileExtensions", fileExtension);
668 
669         verify(checkerConfig, getPath(fileNameWithExtension), violationMessages);
670     }
671 
672 }