1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package com.puppycrawl.tools.checkstyle.filters;
21
22 import static com.puppycrawl.tools.checkstyle.checks.whitespace.FileTabCharacterCheck.MSG_CONTAINS_TAB;
23 import static com.puppycrawl.tools.checkstyle.checks.whitespace.FileTabCharacterCheck.MSG_FILE_CONTAINS_TAB;
24 import static org.junit.Assert.assertEquals;
25 import static org.junit.Assert.assertTrue;
26 import static org.junit.Assert.fail;
27
28 import java.io.FileNotFoundException;
29 import java.io.IOException;
30 import java.util.Arrays;
31 import java.util.Collection;
32 import java.util.stream.Collectors;
33
34 import org.junit.Assert;
35 import org.junit.Test;
36
37 import com.puppycrawl.tools.checkstyle.AbstractModuleTestSupport;
38 import com.puppycrawl.tools.checkstyle.DefaultConfiguration;
39 import com.puppycrawl.tools.checkstyle.api.AuditEvent;
40 import com.puppycrawl.tools.checkstyle.api.CheckstyleException;
41 import com.puppycrawl.tools.checkstyle.api.Configuration;
42 import com.puppycrawl.tools.checkstyle.api.LocalizedMessage;
43 import com.puppycrawl.tools.checkstyle.api.SeverityLevel;
44 import com.puppycrawl.tools.checkstyle.api.TokenTypes;
45 import com.puppycrawl.tools.checkstyle.checks.regexp.RegexpSinglelineCheck;
46 import com.puppycrawl.tools.checkstyle.checks.whitespace.FileTabCharacterCheck;
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 DefaultConfiguration filterCfg =
63 createModuleConfig(SuppressWithPlainTextCommentFilter.class);
64
65 final DefaultConfiguration checkCfg = createModuleConfig(FileTabCharacterCheck.class);
66 checkCfg.addAttribute("eachLine", "true");
67
68 final String[] suppressed = {
69 "5:7: " + getCheckMessage(FileTabCharacterCheck.class, MSG_FILE_CONTAINS_TAB),
70 "10:1: " + getCheckMessage(FileTabCharacterCheck.class, MSG_CONTAINS_TAB),
71 };
72
73 final String[] violationMessages = {
74 "5:7: " + getCheckMessage(FileTabCharacterCheck.class, MSG_FILE_CONTAINS_TAB),
75 "8:7: " + getCheckMessage(FileTabCharacterCheck.class, MSG_CONTAINS_TAB),
76 "10:1: " + getCheckMessage(FileTabCharacterCheck.class, MSG_CONTAINS_TAB),
77 };
78
79 verifySuppressed(
80 "InputSuppressWithPlainTextCommentFilterWithDefaultCfg.java",
81 removeSuppressed(violationMessages, suppressed),
82 filterCfg, checkCfg
83 );
84 }
85
86 @Test
87 public void testChangeOffAndOnFormat() throws Exception {
88 final DefaultConfiguration filterCfg =
89 createModuleConfig(SuppressWithPlainTextCommentFilter.class);
90 filterCfg.addAttribute("onCommentFormat", "cs-on");
91 filterCfg.addAttribute("offCommentFormat", "cs-off");
92
93 final DefaultConfiguration checkCfg = createModuleConfig(FileTabCharacterCheck.class);
94 checkCfg.addAttribute("eachLine", "true");
95
96 final String[] suppressed = {
97 "5:7: " + getCheckMessage(FileTabCharacterCheck.class, MSG_FILE_CONTAINS_TAB),
98 "10:1: " + getCheckMessage(FileTabCharacterCheck.class, MSG_CONTAINS_TAB),
99 "11:1: " + getCheckMessage(FileTabCharacterCheck.class, MSG_CONTAINS_TAB),
100 "13:1: " + getCheckMessage(FileTabCharacterCheck.class, MSG_CONTAINS_TAB),
101 };
102
103 final String[] violationMessage = {
104 "5:7: " + getCheckMessage(FileTabCharacterCheck.class, MSG_FILE_CONTAINS_TAB),
105 "8:7: " + getCheckMessage(FileTabCharacterCheck.class, MSG_CONTAINS_TAB),
106 "10:1: " + getCheckMessage(FileTabCharacterCheck.class, MSG_CONTAINS_TAB),
107 "11:1: " + getCheckMessage(FileTabCharacterCheck.class, MSG_CONTAINS_TAB),
108 };
109
110 verifySuppressed(
111 "InputSuppressWithPlainTextCommentFilterWithCustomOnAndOffComments.java",
112 removeSuppressed(violationMessage, suppressed),
113 filterCfg, checkCfg
114 );
115 }
116
117 @Test
118 public void testSuppressionCommentsInXmlFile() throws Exception {
119 final DefaultConfiguration filterCfg =
120 createModuleConfig(SuppressWithPlainTextCommentFilter.class);
121 filterCfg.addAttribute("offCommentFormat", "CS-OFF");
122 filterCfg.addAttribute("onCommentFormat", "CS-ON");
123
124 final DefaultConfiguration checkCfg = createModuleConfig(FileTabCharacterCheck.class);
125 checkCfg.addAttribute("eachLine", "true");
126
127 final String[] suppressed = {
128 "7:1: " + getCheckMessage(FileTabCharacterCheck.class, MSG_CONTAINS_TAB),
129 };
130
131 final String[] violationMessages = {
132 "7:1: " + getCheckMessage(FileTabCharacterCheck.class, MSG_CONTAINS_TAB),
133 "10:1: " + getCheckMessage(FileTabCharacterCheck.class, MSG_CONTAINS_TAB),
134 };
135
136 verifySuppressed(
137 "InputSuppressWithPlainTextCommentFilter.xml",
138 removeSuppressed(violationMessages, suppressed),
139 filterCfg, checkCfg
140 );
141 }
142
143 @Test
144 public void testSuppressionCommentsInPropertiesFile() throws Exception {
145 final DefaultConfiguration filterCfg =
146 createModuleConfig(SuppressWithPlainTextCommentFilter.class);
147 filterCfg.addAttribute("offCommentFormat", "# CHECKSTYLE:OFF");
148 filterCfg.addAttribute("onCommentFormat", "# CHECKSTYLE:ON");
149
150 final DefaultConfiguration checkCfg = createModuleConfig(RegexpSinglelineCheck.class);
151 checkCfg.addAttribute("format", "^key[0-9]=$");
152
153 final String[] suppressed = {
154 "2: " + getCheckMessage(RegexpSinglelineCheck.class, MSG_REGEXP_EXCEEDED,
155 "^key[0-9]=$"),
156 };
157
158 final String[] violationMessages = {
159 "2: " + getCheckMessage(RegexpSinglelineCheck.class, MSG_REGEXP_EXCEEDED,
160 "^key[0-9]=$"),
161 "4: " + getCheckMessage(RegexpSinglelineCheck.class, MSG_REGEXP_EXCEEDED,
162 "^key[0-9]=$"),
163 };
164
165 verifySuppressed(
166 "InputSuppressWithPlainTextCommentFilter.properties",
167 removeSuppressed(violationMessages, suppressed),
168 filterCfg, checkCfg
169 );
170 }
171
172 @Test
173 public void testSuppressionCommentsInSqlFile() throws Exception {
174 final DefaultConfiguration filterCfg =
175 createModuleConfig(SuppressWithPlainTextCommentFilter.class);
176 filterCfg.addAttribute("offCommentFormat", "-- CHECKSTYLE OFF");
177 filterCfg.addAttribute("onCommentFormat", "-- CHECKSTYLE ON");
178
179 final DefaultConfiguration checkCfg = createModuleConfig(FileTabCharacterCheck.class);
180 checkCfg.addAttribute("eachLine", "true");
181
182 final String[] suppressed = {
183 "2:1: " + getCheckMessage(FileTabCharacterCheck.class, MSG_CONTAINS_TAB),
184 };
185
186 final String[] violationMessages = {
187 "2:1: " + getCheckMessage(FileTabCharacterCheck.class, MSG_CONTAINS_TAB),
188 "5:1: " + getCheckMessage(FileTabCharacterCheck.class, MSG_CONTAINS_TAB),
189 };
190
191 verifySuppressed(
192 "InputSuppressWithPlainTextCommentFilter.sql",
193 removeSuppressed(violationMessages, suppressed),
194 filterCfg, checkCfg
195 );
196 }
197
198 @Test
199 public void testSuppressionCommentsInJavaScriptFile() throws Exception {
200 final DefaultConfiguration filterCfg =
201 createModuleConfig(SuppressWithPlainTextCommentFilter.class);
202 filterCfg.addAttribute("offCommentFormat", "// CS-OFF");
203 filterCfg.addAttribute("onCommentFormat", "// CS-ON");
204
205 final DefaultConfiguration checkCfg = createModuleConfig(RegexpSinglelineCheck.class);
206 checkCfg.addAttribute("format", ".*===.*");
207
208 final String[] suppressed = {
209 "2: " + getCheckMessage(RegexpSinglelineCheck.class, MSG_REGEXP_EXCEEDED, ".*===.*"),
210 };
211
212 final String[] violationMessages = {
213 "2: " + getCheckMessage(RegexpSinglelineCheck.class, MSG_REGEXP_EXCEEDED, ".*===.*"),
214 "5: " + getCheckMessage(RegexpSinglelineCheck.class, MSG_REGEXP_EXCEEDED, ".*===.*"),
215 };
216
217 verifySuppressed(
218 "InputSuppressWithPlainTextCommentFilter.js",
219 removeSuppressed(violationMessages, suppressed),
220 filterCfg, checkCfg
221 );
222 }
223
224 @Test
225 public void testInvalidCheckFormat() throws Exception {
226 final DefaultConfiguration filterCfg =
227 createModuleConfig(SuppressWithPlainTextCommentFilter.class);
228 filterCfg.addAttribute("checkFormat", "e[l");
229 filterCfg.addAttribute("onCommentFormat", "// cs-on");
230 filterCfg.addAttribute("offCommentFormat", "// cs-off");
231
232 final DefaultConfiguration checkCfg = createModuleConfig(FileTabCharacterCheck.class);
233 checkCfg.addAttribute("eachLine", "true");
234
235 final String[] suppressed = CommonUtil.EMPTY_STRING_ARRAY;
236
237 final String[] violationMessages = {
238 "5:7: " + getCheckMessage(FileTabCharacterCheck.class, MSG_FILE_CONTAINS_TAB),
239 "8:7: " + getCheckMessage(FileTabCharacterCheck.class, MSG_CONTAINS_TAB),
240 "10:1: " + getCheckMessage(FileTabCharacterCheck.class, MSG_CONTAINS_TAB),
241 };
242
243 try {
244 verifySuppressed(
245 "InputSuppressWithPlainTextCommentFilterWithCustomOnAndOffComments.java",
246 removeSuppressed(violationMessages, suppressed),
247 filterCfg, checkCfg
248 );
249 fail("CheckstyleException is expected");
250 }
251 catch (CheckstyleException ex) {
252 final IllegalArgumentException cause = (IllegalArgumentException) ex.getCause();
253 assertEquals("Invalid exception message",
254 "unable to parse expanded comment e[l", cause.getMessage());
255 }
256 }
257
258 @Test
259 public void testInvalidMessageFormat() throws Exception {
260 final DefaultConfiguration filterCfg =
261 createModuleConfig(SuppressWithPlainTextCommentFilter.class);
262 filterCfg.addAttribute("messageFormat", "e[l");
263 filterCfg.addAttribute("onCommentFormat", "// cs-on");
264 filterCfg.addAttribute("offCommentFormat", "// cs-off");
265
266 final DefaultConfiguration checkCfg = createModuleConfig(FileTabCharacterCheck.class);
267 checkCfg.addAttribute("eachLine", "true");
268
269 final String[] suppressed = CommonUtil.EMPTY_STRING_ARRAY;
270
271 final String[] violationMessages = {
272 "5:7: " + getCheckMessage(FileTabCharacterCheck.class, MSG_FILE_CONTAINS_TAB),
273 "8:7: " + getCheckMessage(FileTabCharacterCheck.class, MSG_CONTAINS_TAB),
274 "10:1: " + getCheckMessage(FileTabCharacterCheck.class, MSG_CONTAINS_TAB),
275 };
276
277 try {
278 verifySuppressed(
279 "InputSuppressWithPlainTextCommentFilterWithCustomOnAndOffComments.java",
280 removeSuppressed(violationMessages, suppressed),
281 filterCfg, checkCfg
282 );
283 fail("CheckstyleException is expected");
284 }
285 catch (CheckstyleException ex) {
286 final IllegalArgumentException cause = (IllegalArgumentException) ex.getCause();
287 assertEquals("Invalid exception message",
288 "unable to parse expanded comment e[l", cause.getMessage());
289 }
290 }
291
292 @Test
293 public void testAcceptNullLocalizedMessage() {
294 final SuppressWithPlainTextCommentFilter filter = new SuppressWithPlainTextCommentFilter();
295 final AuditEvent auditEvent = new AuditEvent(this);
296 assertTrue("Filter should accept audit event", filter.accept(auditEvent));
297 Assert.assertNull("File name should not be null", auditEvent.getFileName());
298 }
299
300 @Test
301 public void testEqualsAndHashCodeOfTagClass() {
302 final EqualsVerifierReport ev = EqualsVerifier
303 .forClass(SuppressWithPlainTextCommentFilter.Suppression.class).usingGetClass()
304 .report();
305 assertEquals("Error: " + ev.getMessage(), EqualsVerifierReport.SUCCESS, ev);
306 }
307
308 @Test
309 public void testSuppressByModuleId() throws Exception {
310 final DefaultConfiguration filterCfg =
311 createModuleConfig(SuppressWithPlainTextCommentFilter.class);
312 filterCfg.addAttribute("offCommentFormat", "CSOFF (\\w+) \\(\\w+\\)");
313 filterCfg.addAttribute("onCommentFormat", "CSON (\\w+)");
314 filterCfg.addAttribute("checkFormat", "$1");
315
316 final DefaultConfiguration regexpCheckCfg = createModuleConfig(RegexpSinglelineCheck.class);
317 regexpCheckCfg.addAttribute("id", "ignore");
318 regexpCheckCfg.addAttribute("format", ".*[a-zA-Z][0-9].*");
319
320 final DefaultConfiguration fileTabCheckCfg =
321 createModuleConfig(FileTabCharacterCheck.class);
322 fileTabCheckCfg.addAttribute("eachLine", "true");
323 fileTabCheckCfg.addAttribute("id", "foo");
324
325 final String[] suppressedViolationMessages = {
326 "6: " + getCheckMessage(RegexpSinglelineCheck.class, MSG_REGEXP_EXCEEDED,
327 ".*[a-zA-Z][0-9].*"),
328 "9: " + getCheckMessage(RegexpSinglelineCheck.class, MSG_REGEXP_EXCEEDED,
329 ".*[a-zA-Z][0-9].*"),
330 "11: " + getCheckMessage(RegexpSinglelineCheck.class, MSG_REGEXP_EXCEEDED,
331 ".*[a-zA-Z][0-9].*"),
332 };
333
334 final String[] expectedViolationMessages = {
335 "6: " + getCheckMessage(RegexpSinglelineCheck.class, MSG_REGEXP_EXCEEDED,
336 ".*[a-zA-Z][0-9].*"),
337 "9:1: " + getCheckMessage(FileTabCharacterCheck.class, MSG_CONTAINS_TAB),
338 "9: " + getCheckMessage(RegexpSinglelineCheck.class, MSG_REGEXP_EXCEEDED,
339 ".*[a-zA-Z][0-9].*"),
340 "11: " + getCheckMessage(RegexpSinglelineCheck.class, MSG_REGEXP_EXCEEDED,
341 ".*[a-zA-Z][0-9].*"),
342 "14: " + getCheckMessage(RegexpSinglelineCheck.class, MSG_REGEXP_EXCEEDED,
343 ".*[a-zA-Z][0-9].*"),
344 };
345
346 verifySuppressed(
347 "InputSuppressWithPlainTextCommentFilterSuppressById.java",
348 removeSuppressed(expectedViolationMessages, suppressedViolationMessages),
349 filterCfg, regexpCheckCfg, fileTabCheckCfg
350 );
351 }
352
353 @Test
354 public void testSuppressByModuleIdWithNullModuleId() throws Exception {
355 final DefaultConfiguration filterCfg =
356 createModuleConfig(SuppressWithPlainTextCommentFilter.class);
357 filterCfg.addAttribute("offCommentFormat", "CSOFF (\\w+) \\(\\w+\\)");
358 filterCfg.addAttribute("onCommentFormat", "CSON (\\w+)");
359 filterCfg.addAttribute("checkFormat", "$1");
360
361 final DefaultConfiguration regexpCheckCfg = createModuleConfig(RegexpSinglelineCheck.class);
362 regexpCheckCfg.addAttribute("id", "ignore");
363 regexpCheckCfg.addAttribute("format", ".*[a-zA-Z][0-9].*");
364
365 final DefaultConfiguration fileTabCheckCfg =
366 createModuleConfig(FileTabCharacterCheck.class);
367 fileTabCheckCfg.addAttribute("eachLine", "true");
368 fileTabCheckCfg.addAttribute("id", null);
369
370 final String[] suppressedViolationMessages = {
371 "6: " + getCheckMessage(RegexpSinglelineCheck.class, MSG_REGEXP_EXCEEDED,
372 ".*[a-zA-Z][0-9].*"),
373 "9: " + getCheckMessage(RegexpSinglelineCheck.class, MSG_REGEXP_EXCEEDED,
374 ".*[a-zA-Z][0-9].*"),
375 "11: " + getCheckMessage(RegexpSinglelineCheck.class, MSG_REGEXP_EXCEEDED,
376 ".*[a-zA-Z][0-9].*"),
377 };
378
379 final String[] expectedViolationMessages = {
380 "6: " + getCheckMessage(RegexpSinglelineCheck.class, MSG_REGEXP_EXCEEDED,
381 ".*[a-zA-Z][0-9].*"),
382 "9:1: " + getCheckMessage(FileTabCharacterCheck.class, MSG_CONTAINS_TAB),
383 "9: " + getCheckMessage(RegexpSinglelineCheck.class, MSG_REGEXP_EXCEEDED,
384 ".*[a-zA-Z][0-9].*"),
385 "11: " + getCheckMessage(RegexpSinglelineCheck.class, MSG_REGEXP_EXCEEDED,
386 ".*[a-zA-Z][0-9].*"),
387 "14: " + getCheckMessage(RegexpSinglelineCheck.class, MSG_REGEXP_EXCEEDED,
388 ".*[a-zA-Z][0-9].*"),
389 };
390
391 verifySuppressed(
392 "InputSuppressWithPlainTextCommentFilterSuppressById.java",
393 removeSuppressed(expectedViolationMessages, suppressedViolationMessages),
394 filterCfg, regexpCheckCfg, fileTabCheckCfg
395 );
396 }
397
398 @Test
399 public void testAcceptThrowsIllegalStateExceptionAsFileNotFound() {
400 final LocalizedMessage message = new LocalizedMessage(1, 1, 1, TokenTypes.CLASS_DEF,
401 "messages.properties", "key", null, SeverityLevel.ERROR, null, getClass(), null);
402 final String fileName = "nonexisting_file";
403 final AuditEvent auditEvent = new AuditEvent(this, fileName, message);
404
405 final SuppressWithPlainTextCommentFilter filter = new SuppressWithPlainTextCommentFilter();
406
407 try {
408 filter.accept(auditEvent);
409 fail(IllegalStateException.class.getSimpleName() + " is expected");
410 }
411 catch (IllegalStateException ex) {
412 assertEquals("Invalid exception message",
413 "Cannot read source file: " + fileName, ex.getMessage());
414
415 final Throwable cause = ex.getCause();
416 assertTrue("Exception cause has invalid type",
417 cause instanceof FileNotFoundException);
418 assertEquals("Invalid exception message",
419 fileName + " (No such file or directory)", cause.getMessage());
420 }
421 }
422
423 @Test
424 public void testFilterWithCustomMessageFormat() throws Exception {
425 final DefaultConfiguration filterCfg =
426 createModuleConfig(SuppressWithPlainTextCommentFilter.class);
427 final String messageFormat =
428 ".*" + getCheckMessage(FileTabCharacterCheck.class, MSG_CONTAINS_TAB) + ".*";
429
430 filterCfg.addAttribute("messageFormat", messageFormat);
431
432 final DefaultConfiguration fileTabCheckCfg =
433 createModuleConfig(FileTabCharacterCheck.class);
434 fileTabCheckCfg.addAttribute("eachLine", "true");
435
436 final DefaultConfiguration regexpCheckCfg = createModuleConfig(RegexpSinglelineCheck.class);
437 regexpCheckCfg.addAttribute("id", "ignore");
438 regexpCheckCfg.addAttribute("format", ".*[a-zA-Z][0-9].*");
439
440 final String[] suppressed = {
441 "8:1: " + getCheckMessage(FileTabCharacterCheck.class, MSG_CONTAINS_TAB),
442 };
443
444 final String[] violationMessages = {
445 "6: " + getCheckMessage(RegexpSinglelineCheck.class, MSG_REGEXP_EXCEEDED,
446 ".*[a-zA-Z][0-9].*"),
447 "8:1: " + getCheckMessage(FileTabCharacterCheck.class, MSG_CONTAINS_TAB),
448 "8: " + getCheckMessage(RegexpSinglelineCheck.class, MSG_REGEXP_EXCEEDED,
449 ".*[a-zA-Z][0-9].*"),
450 "10: " + getCheckMessage(RegexpSinglelineCheck.class, MSG_REGEXP_EXCEEDED,
451 ".*[a-zA-Z][0-9].*"),
452 "13: " + getCheckMessage(RegexpSinglelineCheck.class, MSG_REGEXP_EXCEEDED,
453 ".*[a-zA-Z][0-9].*"),
454 };
455
456 verifySuppressed(
457 "InputSuppressWithPlainTextCommentFilterCustomMessageFormat.java",
458 removeSuppressed(violationMessages, suppressed),
459 filterCfg, fileTabCheckCfg, regexpCheckCfg
460 );
461 }
462
463 @Test
464 public void testFilterWithDirectory() throws IOException {
465 final SuppressWithPlainTextCommentFilter filter = new SuppressWithPlainTextCommentFilter();
466 final AuditEvent event = new AuditEvent(this, getPath(""), new LocalizedMessage(1, 1,
467 "bundle", "key", null, SeverityLevel.ERROR, "moduleId", getClass(),
468 "customMessage"));
469
470 assertTrue("filter should accept directory", filter.accept(event));
471 }
472
473 private void verifySuppressed(String fileNameWithExtension, String[] violationMessages,
474 Configuration... childConfigs) throws Exception {
475 final DefaultConfiguration checkerConfig = createRootConfig(null);
476
477 Arrays.stream(childConfigs).forEach(checkerConfig::addChild);
478
479 final String fileExtension = CommonUtil.getFileExtension(fileNameWithExtension);
480 checkerConfig.addAttribute("fileExtensions", fileExtension);
481
482 verify(checkerConfig, getPath(fileNameWithExtension), violationMessages);
483 }
484
485 private static String[] removeSuppressed(String[] from, String... remove) {
486 final Collection<String> coll = Arrays.stream(from).collect(Collectors.toList());
487 coll.removeAll(Arrays.asList(remove));
488 return coll.toArray(CommonUtil.EMPTY_STRING_ARRAY);
489 }
490
491 }