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