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.google.common.truth.Truth.assertWithMessage;
23 import static com.puppycrawl.tools.checkstyle.checks.naming.AbstractNameCheck.MSG_INVALID_PATTERN;
24 import static com.puppycrawl.tools.checkstyle.checks.sizes.LineLengthCheck.MSG_KEY;
25 import static com.puppycrawl.tools.checkstyle.internal.utils.TestUtil.getExpectedThrowable;
26
27 import java.io.File;
28 import java.io.FileNotFoundException;
29 import java.io.IOException;
30 import java.nio.file.Files;
31 import java.nio.file.StandardCopyOption;
32 import java.util.List;
33
34 import org.junit.jupiter.api.Test;
35 import org.junit.jupiter.api.io.TempDir;
36
37 import com.puppycrawl.tools.checkstyle.AbstractModuleTestSupport;
38 import com.puppycrawl.tools.checkstyle.api.AuditEvent;
39 import com.puppycrawl.tools.checkstyle.api.CheckstyleException;
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.coding.MagicNumberCheck;
44 import com.puppycrawl.tools.checkstyle.checks.naming.ConstantNameCheck;
45 import com.puppycrawl.tools.checkstyle.checks.regexp.RegexpSinglelineCheck;
46 import com.puppycrawl.tools.checkstyle.checks.sizes.LineLengthCheck;
47 import com.puppycrawl.tools.checkstyle.internal.utils.TestUtil;
48
49 public class SuppressWithNearbyTextFilterTest extends AbstractModuleTestSupport {
50
51 private static final String REGEXP_SINGLELINE_CHECK_FORMAT = "this should not appear";
52
53 @TempDir
54 public File temporaryFolder;
55
56 @Override
57 public String getPackageLocation() {
58 return "com/puppycrawl/tools/checkstyle/filters/suppresswithnearbytextfilter";
59 }
60
61 @Test
62 public void testDefaultConfig() throws Exception {
63 final int expectedLineLength = 90;
64 final String pattern = "^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$";
65
66 final String[] violationMessages = {
67 "29: " + getLineLengthCheckMessage(expectedLineLength, 94),
68 "31: " + getLineLengthCheckMessage(expectedLineLength, 97),
69 "41: " + getLineLengthCheckMessage(expectedLineLength, 94),
70 "44:22: " + getCheckMessage(ConstantNameCheck.class,
71 MSG_INVALID_PATTERN, "badConstant", pattern),
72 "47:22: " + getCheckMessage(ConstantNameCheck.class,
73 MSG_INVALID_PATTERN, "badConstant1", pattern),
74 };
75
76 final String[] suppressedMessages = {
77 "31: " + getLineLengthCheckMessage(expectedLineLength, 97),
78 "41: " + getLineLengthCheckMessage(expectedLineLength, 94),
79 "47:22: " + getCheckMessage(ConstantNameCheck.class,
80 MSG_INVALID_PATTERN, "badConstant1", pattern),
81 };
82
83 verifyFilterWithInlineConfigParser(
84 getPath("InputSuppressWithNearbyTextFilterDefaultConfig.java"),
85 violationMessages, removeSuppressed(violationMessages, suppressedMessages)
86 );
87 }
88
89 @Test
90 public void testNearbyTextPattern() throws Exception {
91 final int expectedLineLength = 90;
92
93 final String[] violationMessages = {
94 "15: " + getRegexpSinglelineCheckMessage(),
95 "28: " + getLineLengthCheckMessage(expectedLineLength, 94),
96 "33: " + getLineLengthCheckMessage(expectedLineLength, 93),
97 "33: " + getRegexpSinglelineCheckMessage(),
98 "39: " + getLineLengthCheckMessage(expectedLineLength, 93),
99 "44: " + getRegexpSinglelineCheckMessage(),
100 "49: " + getLineLengthCheckMessage(expectedLineLength, 95),
101 "54: " + getRegexpSinglelineCheckMessage(),
102 "58: " + getLineLengthCheckMessage(expectedLineLength, 97),
103 };
104
105 final String[] suppressedMessages = {
106 "33: " + getLineLengthCheckMessage(expectedLineLength, 93),
107 "33: " + getRegexpSinglelineCheckMessage(),
108 "39: " + getLineLengthCheckMessage(expectedLineLength, 93),
109 "49: " + getLineLengthCheckMessage(expectedLineLength, 95),
110 "54: " + getRegexpSinglelineCheckMessage(),
111 "58: " + getLineLengthCheckMessage(expectedLineLength, 97),
112 };
113
114 verifyFilterWithInlineConfigParser(
115 getPath("InputSuppressWithNearbyTextFilterNearbyTextPattern.css.txt"),
116 violationMessages, removeSuppressed(violationMessages, suppressedMessages)
117 );
118 }
119
120 @Test
121 public void testCheckPattern() throws Exception {
122 final int expectedLineLength = 80;
123
124 final String[] violationMessages = {
125 "15: " + getRegexpSinglelineCheckMessage(),
126 "28: " + getLineLengthCheckMessage(expectedLineLength, 89),
127 "29: " + getRegexpSinglelineCheckMessage(),
128 "35: " + getLineLengthCheckMessage(expectedLineLength, 87),
129 };
130
131 final String[] suppressedMessages = {
132 "28: " + getLineLengthCheckMessage(expectedLineLength, 89),
133 "35: " + getLineLengthCheckMessage(expectedLineLength, 87),
134 };
135
136 verifyFilterWithInlineConfigParser(
137 getPath("InputSuppressWithNearbyTextFilterCheckPattern.bash.txt"),
138 violationMessages, removeSuppressed(violationMessages, suppressedMessages)
139 );
140 }
141
142 @Test
143 public void testMessagePattern() throws Exception {
144 final int expectedLineLength = 90;
145
146 final String[] violationMessages = {
147 "15: " + getRegexpSinglelineCheckMessage(),
148 "33: " + getRegexpSinglelineCheckMessage(),
149 "38: " + getLineLengthCheckMessage(expectedLineLength, 98),
150 "42: " + getLineLengthCheckMessage(expectedLineLength, 96),
151 };
152
153 final String[] suppressedMessages = {
154 "38: " + getLineLengthCheckMessage(expectedLineLength, 98),
155 "42: " + getLineLengthCheckMessage(expectedLineLength, 96),
156 };
157
158 verifyFilterWithInlineConfigParser(
159 getPath("InputSuppressWithNearbyTextFilterMessagePattern.xml.txt"),
160 violationMessages, removeSuppressed(violationMessages, suppressedMessages)
161 );
162 }
163
164 @Test
165 public void testIdPattern() throws Exception {
166 final int expectedLineLength = 80;
167
168 final String[] violationMessages = {
169 "16: " + getRegexpSinglelineCheckMessage(),
170 "29: " + getRegexpSinglelineCheckMessage(),
171 "34: " + getLineLengthCheckMessage(expectedLineLength, 83),
172 "38: " + getLineLengthCheckMessage(expectedLineLength, 84),
173 };
174
175 final String[] suppressedMessages = {
176 "34: " + getLineLengthCheckMessage(expectedLineLength, 83),
177 "38: " + getLineLengthCheckMessage(expectedLineLength, 84),
178 };
179
180 verifyFilterWithInlineConfigParser(
181 getPath("InputSuppressWithNearbyTextFilterIdPattern.html.txt"),
182 violationMessages, removeSuppressed(violationMessages, suppressedMessages)
183 );
184 }
185
186 @Test
187 public void testLineRangePositive3() throws Exception {
188 final int expectedLineLength = 92;
189
190 final String[] violationMessages = {
191 "15: " + getRegexpSinglelineCheckMessage(),
192 "27: " + getLineLengthCheckMessage(expectedLineLength, 98),
193 "28: " + getLineLengthCheckMessage(expectedLineLength, 98),
194 "29: " + getLineLengthCheckMessage(expectedLineLength, 98),
195 "30: " + getLineLengthCheckMessage(expectedLineLength, 93),
196 "33: " + getRegexpSinglelineCheckMessage(),
197 "34: " + getRegexpSinglelineCheckMessage(),
198 "35: " + getRegexpSinglelineCheckMessage(),
199 "36: " + getRegexpSinglelineCheckMessage(),
200 };
201
202 final String[] suppressedMessages = {
203 "27: " + getLineLengthCheckMessage(expectedLineLength, 98),
204 "28: " + getLineLengthCheckMessage(expectedLineLength, 98),
205 "29: " + getLineLengthCheckMessage(expectedLineLength, 98),
206 "33: " + getRegexpSinglelineCheckMessage(),
207 "34: " + getRegexpSinglelineCheckMessage(),
208 "35: " + getRegexpSinglelineCheckMessage(),
209 "36: " + getRegexpSinglelineCheckMessage(),
210 };
211
212 verifyFilterWithInlineConfigParser(
213 getPath("InputSuppressWithNearbyTextFilterLineRangePositive3.sql.txt"),
214 violationMessages, removeSuppressed(violationMessages, suppressedMessages)
215 );
216 }
217
218 @Test
219 public void testLineRangeNegative2() throws Exception {
220 final int expectedLineLength = 91;
221
222 final String[] violationMessages = {
223 "15: " + getRegexpSinglelineCheckMessage(),
224 "27: " + getLineLengthCheckMessage(expectedLineLength, 96),
225 "28: " + getLineLengthCheckMessage(expectedLineLength, 94),
226 "29: " + getLineLengthCheckMessage(expectedLineLength, 94),
227 "30: " + getLineLengthCheckMessage(expectedLineLength, 98),
228 "33: " + getRegexpSinglelineCheckMessage(),
229 "34: " + getRegexpSinglelineCheckMessage(),
230 "35: " + getRegexpSinglelineCheckMessage(),
231 "36: " + getRegexpSinglelineCheckMessage(),
232 };
233
234 final String[] suppressedMessages = {
235 "28: " + getLineLengthCheckMessage(expectedLineLength, 94),
236 "29: " + getLineLengthCheckMessage(expectedLineLength, 94),
237 "30: " + getLineLengthCheckMessage(expectedLineLength, 98),
238 "34: " + getRegexpSinglelineCheckMessage(),
239 "35: " + getRegexpSinglelineCheckMessage(),
240 "36: " + getRegexpSinglelineCheckMessage(),
241 };
242
243 verifyFilterWithInlineConfigParser(
244 getPath("InputSuppressWithNearbyTextFilterLineRangeNegative2.txt"),
245 violationMessages, removeSuppressed(violationMessages, suppressedMessages)
246 );
247 }
248
249 @Test
250 public void testVariableCheckPatternAndLineRange() throws Exception {
251 final int expectedLineLength = 85;
252
253 final String[] violationMessages = {
254 "19: " + getLineLengthCheckMessage(expectedLineLength, 89),
255 "20: " + getLineLengthCheckMessage(expectedLineLength, 89),
256 "21: " + getLineLengthCheckMessage(expectedLineLength, 89),
257 "22: " + getLineLengthCheckMessage(expectedLineLength, 87),
258 "24: " + getLineLengthCheckMessage(expectedLineLength, 87),
259 "25: " + getLineLengthCheckMessage(expectedLineLength, 89),
260 "26: " + getLineLengthCheckMessage(expectedLineLength, 89),
261 };
262
263 final String[] suppressedMessages = {
264 "19: " + getLineLengthCheckMessage(expectedLineLength, 89),
265 "20: " + getLineLengthCheckMessage(expectedLineLength, 89),
266 "21: " + getLineLengthCheckMessage(expectedLineLength, 89),
267 "25: " + getLineLengthCheckMessage(expectedLineLength, 89),
268 "26: " + getLineLengthCheckMessage(expectedLineLength, 89),
269 };
270
271 verifyFilterWithInlineConfigParser(
272 getPath("InputSuppressWithNearbyTextFilter"
273 + "VariableNearbyTextPatternAndLineRange.xml.txt"),
274 violationMessages, removeSuppressed(violationMessages, suppressedMessages)
275 );
276 }
277
278 @Test
279 public void testNearbyTextPatternAny() throws Exception {
280 final int expectedLineLength = 76;
281
282 final String[] violationMessages = {
283 "18: " + getLineLengthCheckMessage(expectedLineLength, 80),
284 };
285
286 final String[] suppressedMessages = {
287 "18: " + getLineLengthCheckMessage(expectedLineLength, 80),
288 };
289
290 verifyFilterWithInlineConfigParser(
291 getPath("InputSuppressWithNearbyTextFilterNearbyTextPatternAny.txt"),
292 violationMessages, removeSuppressed(violationMessages, suppressedMessages)
293 );
294 }
295
296 @Test
297 public void testNearbyTextPatternCompactVariableCheckPattern() throws Exception {
298 final String[] violationMessages = {
299 "26:13: " + getCheckMessage(MagicNumberCheck.class, MagicNumberCheck.MSG_KEY, "42"),
300 "27:13: " + getCheckMessage(MagicNumberCheck.class, MagicNumberCheck.MSG_KEY, "43"),
301 };
302
303 final String[] suppressedMessages = {
304 "26:13: " + getCheckMessage(MagicNumberCheck.class, MagicNumberCheck.MSG_KEY, "42"),
305 };
306
307 verifyFilterWithInlineConfigParser(
308 getPath("InputSuppressWithNearbyTextFilterNearbyTextPattern"
309 + "CompactVariableCheckPattern.java"),
310 violationMessages, removeSuppressed(violationMessages, suppressedMessages)
311 );
312 }
313
314 @Test
315 public void testNearbyTextPatternUrlLineLengthSuppression() throws Exception {
316 final int expectedLineLength = 90;
317
318 final String[] violationMessages = {
319 "32: " + getLineLengthCheckMessage(expectedLineLength, 98),
320 "39: " + getLineLengthCheckMessage(expectedLineLength, 97),
321 };
322
323 final String[] suppressedMessages = {
324 "32: " + getLineLengthCheckMessage(expectedLineLength, 98),
325 "39: " + getLineLengthCheckMessage(expectedLineLength, 97),
326 };
327
328 verifyFilterWithInlineConfigParser(
329 getPath("InputSuppressWithNearbyTextFilterNearbyTextPatternUrlLineLengthSuppression"
330 + ".java"),
331 violationMessages, removeSuppressed(violationMessages, suppressedMessages)
332 );
333 }
334
335 @Test
336 public void testInvalidCheckPattern() {
337 final String[] violationAndSuppressedMessages = {
338 "18: " + getLineLengthCheckMessage(80, 93),
339 };
340
341 final CheckstyleException exc = getExpectedThrowable(
342 CheckstyleException.class,
343 () -> {
344 verifyFilterWithInlineConfigParser(
345 getPath("InputSuppressWithNearbyTextFilterInvalidCheckPattern.txt"),
346 violationAndSuppressedMessages
347 );
348 });
349 final IllegalArgumentException cause = (IllegalArgumentException) exc.getCause();
350 assertWithMessage("Invalid exception message")
351 .that(cause)
352 .hasMessageThat()
353 .isEqualTo("unable to parse expanded comment a![b");
354 }
355
356 @Test
357 public void testInvalidIdPattern() {
358 final String[] violationAndSuppressedMessages = {
359 "18: " + getLineLengthCheckMessage(80, 93),
360 };
361
362 final CheckstyleException exc = getExpectedThrowable(
363 CheckstyleException.class,
364 () -> {
365 verifyFilterWithInlineConfigParser(
366 getPath("InputSuppressWithNearbyTextFilterInvalidIdPattern.txt"),
367 violationAndSuppressedMessages
368 );
369 });
370 final IllegalArgumentException cause = (IllegalArgumentException) exc.getCause();
371 assertWithMessage("Invalid exception message")
372 .that(cause)
373 .hasMessageThat()
374 .isEqualTo("unable to parse expanded comment a![b");
375 }
376
377 @Test
378 public void testInvalidMessagePattern() {
379 final String[] violationAndSuppressedMessages = {
380 "18: " + getLineLengthCheckMessage(80, 93),
381 };
382
383 final CheckstyleException exc = getExpectedThrowable(
384 CheckstyleException.class,
385 () -> {
386 verifyFilterWithInlineConfigParser(
387 getPath("InputSuppressWithNearbyTextFilterInvalidMessagePattern.txt"),
388 violationAndSuppressedMessages
389 );
390 });
391 final IllegalArgumentException cause = (IllegalArgumentException) exc.getCause();
392 assertWithMessage("Invalid exception message")
393 .that(cause)
394 .hasMessageThat()
395 .isEqualTo("unable to parse expanded comment a![b");
396 }
397
398 @Test
399 public void testInvalidLineRange() {
400 final String[] violationAndSuppressedMessages = {
401 "18: " + getLineLengthCheckMessage(80, 93),
402 };
403
404 final CheckstyleException exc = getExpectedThrowable(
405 CheckstyleException.class,
406 () -> {
407 verifyFilterWithInlineConfigParser(
408 getPath("InputSuppressWithNearbyTextFilterInvalidLineRange.txt"),
409 violationAndSuppressedMessages
410 );
411 });
412 assertWithMessage("Invalid exception message")
413 .that(exc)
414 .hasCauseThat()
415 .hasMessageThat()
416 .isEqualTo("unable to parse line range"
417 + " from 'SUPPRESS CHECKSTYLE LineLengthCheck' using a!b");
418 }
419
420
421
422
423
424
425
426
427 @Test
428 public void testCachingExecution() throws Exception {
429 final SuppressWithNearbyTextFilter suppressFilter = new SuppressWithNearbyTextFilter();
430 final String inputPath =
431 getPath("InputSuppressWithNearbyTextFilterDefaultConfig.java");
432 final File tempFile = new File(temporaryFolder,
433 "InputSuppressWithNearbyTextFilterDefaultConfig.java");
434 Files.copy(new File(inputPath).toPath(), tempFile.toPath(),
435 StandardCopyOption.REPLACE_EXISTING);
436
437 final AuditEvent auditEvent1 = new AuditEvent(
438 tempFile.getPath(), tempFile.getPath(),
439 new Violation(1, null, null, null, null,
440 Object.class, null)
441 );
442 suppressFilter.accept(auditEvent1);
443 final boolean deleted = tempFile.delete();
444 assertWithMessage("Temporary file should be deleted.")
445 .that(deleted).isTrue();
446 final AuditEvent auditEvent2 = new AuditEvent(
447 tempFile.getPath(), tempFile.getPath(),
448 new Violation(2, null, null, null, null,
449 Object.class, null)
450 );
451 suppressFilter.accept(auditEvent2);
452
453 assertWithMessage("Cache should handle missing file.")
454 .that(tempFile.exists()).isFalse();
455 }
456
457
458
459
460
461
462 @Test
463 public void testAcceptNullViolation() {
464 final SuppressWithNearbyTextFilter filter = new SuppressWithNearbyTextFilter();
465 final AuditEvent auditEvent = new AuditEvent(this);
466 assertWithMessage("Filter should accept audit event")
467 .that(filter.accept(auditEvent))
468 .isTrue();
469 assertWithMessage("File name should not be null")
470 .that(auditEvent.getFileName())
471 .isNull();
472 }
473
474
475
476
477
478
479
480 @Test
481 public void testThrowsIllegalStateExceptionWhenFileNotFound() {
482 final Violation message = new Violation(1, 1, 1, TokenTypes.CLASS_DEF,
483 "messages.properties", "key", null, SeverityLevel.ERROR, null, getClass(), null);
484 final String fileName = "nonexisting_file";
485 final AuditEvent auditEvent = new AuditEvent(this, fileName, message);
486 final SuppressWithNearbyTextFilter filter = new SuppressWithNearbyTextFilter();
487
488 final IllegalStateException exc = getExpectedThrowable(
489 IllegalStateException.class,
490 () -> {
491 filter.accept(auditEvent);
492 });
493 assertWithMessage("Invalid exception message")
494 .that(exc.getMessage())
495 .isEqualTo("Cannot read source file: " + fileName);
496
497 final Throwable cause = exc.getCause();
498 assertWithMessage("Exception cause has invalid type")
499 .that(cause)
500 .isInstanceOf(FileNotFoundException.class);
501 assertWithMessage("Invalid exception message")
502 .that(cause)
503 .hasMessageThat()
504 .isEqualTo(fileName + " (No such file or directory)");
505 }
506
507
508
509
510
511
512
513
514
515
516 @Test
517 public void testFilterWithDirectory() throws IOException {
518 final SuppressWithNearbyTextFilter filter = new SuppressWithNearbyTextFilter();
519 final AuditEvent event = new AuditEvent(this, getPath(""), new Violation(1, 1,
520 "bundle", "key", null, SeverityLevel.ERROR, "moduleId", getClass(),
521 "customMessage"));
522
523 assertWithMessage("filter should accept directory")
524 .that(filter.accept(event))
525 .isTrue();
526 }
527
528
529
530
531
532
533
534
535
536 @Test
537 public void testSuppressionsAreClearedEachRun() throws IOException {
538 final SuppressWithNearbyTextFilter filter = new SuppressWithNearbyTextFilter();
539
540 final List<?> suppressions1 = getSuppressionsAfterExecution(filter,
541 getPath("InputSuppressWithNearbyTextFilterDefaultConfig.java"));
542 assertWithMessage("Invalid suppressions size")
543 .that(suppressions1)
544 .hasSize(3);
545
546 final List<?> suppressions2 = getSuppressionsAfterExecution(filter,
547 getPath("InputSuppressWithNearbyTextFilterOneLineText.txt"));
548 assertWithMessage("Invalid suppressions size")
549 .that(suppressions2)
550 .isEmpty();
551 }
552
553
554
555
556
557
558
559
560
561 @Test
562 public void testCachedFileAbsolutePathHasChangedEachRun() throws IOException {
563 final SuppressWithNearbyTextFilter filter = new SuppressWithNearbyTextFilter();
564
565 final String cachedFileAbsolutePath1 = getCachedFileAbsolutePathAfterExecution(filter,
566 getPath("InputSuppressWithNearbyTextFilterDefaultConfig.java"));
567 final String cachedFileAbsolutePath2 = getCachedFileAbsolutePathAfterExecution(filter,
568 getPath("InputSuppressWithNearbyTextFilterOneLineText.txt"));
569
570 assertWithMessage("cachedFileAbsolutePath has not changed")
571 .that(cachedFileAbsolutePath1)
572 .isNotEqualTo(cachedFileAbsolutePath2);
573 }
574
575
576
577
578
579
580 private static List<?> getSuppressionsAfterExecution(SuppressWithNearbyTextFilter filter,
581 String filename) {
582 final AuditEvent dummyEvent = buildDummyAuditEvent(filename);
583 filter.accept(dummyEvent);
584 return TestUtil.getInternalState(filter, "suppressions", List.class);
585 }
586
587
588
589
590
591
592
593 private static String getCachedFileAbsolutePathAfterExecution(SuppressWithNearbyTextFilter
594 filter,
595 String filename) {
596 final AuditEvent dummyEvent = buildDummyAuditEvent(filename);
597 filter.accept(dummyEvent);
598 return TestUtil.getInternalState(filter, "cachedFileAbsolutePath", String.class);
599 }
600
601
602
603
604
605
606
607 private static AuditEvent buildDummyAuditEvent(String filename) {
608 final Violation violation = new Violation(1, null, null,
609 null, null, Object.class, null);
610 return new AuditEvent("", filename, violation);
611 }
612
613 private static String getLineLengthCheckMessage(int expectedLength, int actualLength) {
614 return getCheckMessage(LineLengthCheck.class, MSG_KEY, expectedLength, actualLength);
615 }
616
617 private static String getRegexpSinglelineCheckMessage() {
618 final String msgRegexExceeded = "regexp.exceeded";
619 return getCheckMessage(RegexpSinglelineCheck.class,
620 msgRegexExceeded, REGEXP_SINGLELINE_CHECK_FORMAT);
621 }
622 }