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.naming.AbstractNameCheck.MSG_INVALID_PATTERN;
23 import static org.junit.Assert.assertEquals;
24 import static org.junit.Assert.assertTrue;
25 import static org.junit.Assert.fail;
26
27 import java.util.Arrays;
28 import java.util.Collection;
29 import java.util.List;
30 import java.util.stream.Collectors;
31
32 import org.junit.Test;
33 import org.powermock.reflect.Whitebox;
34
35 import com.puppycrawl.tools.checkstyle.AbstractModuleTestSupport;
36 import com.puppycrawl.tools.checkstyle.DefaultConfiguration;
37 import com.puppycrawl.tools.checkstyle.TreeWalker;
38 import com.puppycrawl.tools.checkstyle.TreeWalkerAuditEvent;
39 import com.puppycrawl.tools.checkstyle.api.CheckstyleException;
40 import com.puppycrawl.tools.checkstyle.api.Configuration;
41 import com.puppycrawl.tools.checkstyle.api.FileContents;
42 import com.puppycrawl.tools.checkstyle.api.LocalizedMessage;
43 import com.puppycrawl.tools.checkstyle.checks.coding.IllegalCatchCheck;
44 import com.puppycrawl.tools.checkstyle.checks.naming.AbstractNameCheck;
45 import com.puppycrawl.tools.checkstyle.checks.naming.ConstantNameCheck;
46 import com.puppycrawl.tools.checkstyle.checks.naming.MemberNameCheck;
47 import com.puppycrawl.tools.checkstyle.utils.CommonUtil;
48 import nl.jqno.equalsverifier.EqualsVerifier;
49 import nl.jqno.equalsverifier.EqualsVerifierReport;
50
51 public class SuppressWithNearbyCommentFilterTest
52 extends AbstractModuleTestSupport {
53
54 private static final String[] ALL_MESSAGES = {
55 "14:17: "
56 + getCheckMessage(AbstractNameCheck.class,
57 MSG_INVALID_PATTERN, "A1", "^[a-z][a-zA-Z0-9]*$"),
58 "15:17: "
59 + getCheckMessage(AbstractNameCheck.class,
60 MSG_INVALID_PATTERN, "A2", "^[a-z][a-zA-Z0-9]*$"),
61 "16:59: "
62 + getCheckMessage(AbstractNameCheck.class,
63 MSG_INVALID_PATTERN, "A3", "^[a-z][a-zA-Z0-9]*$"),
64 "18:17: "
65 + getCheckMessage(AbstractNameCheck.class,
66 MSG_INVALID_PATTERN, "B1", "^[a-z][a-zA-Z0-9]*$"),
67 "19:17: "
68 + getCheckMessage(AbstractNameCheck.class,
69 MSG_INVALID_PATTERN, "B2", "^[a-z][a-zA-Z0-9]*$"),
70 "20:59: "
71 + getCheckMessage(AbstractNameCheck.class,
72 MSG_INVALID_PATTERN, "B3", "^[a-z][a-zA-Z0-9]*$"),
73 "22:17: "
74 + getCheckMessage(AbstractNameCheck.class,
75 MSG_INVALID_PATTERN, "C1", "^[a-z][a-zA-Z0-9]*$"),
76 "24:17: "
77 + getCheckMessage(AbstractNameCheck.class,
78 MSG_INVALID_PATTERN, "C2", "^[a-z][a-zA-Z0-9]*$"),
79 "25:17: "
80 + getCheckMessage(AbstractNameCheck.class,
81 MSG_INVALID_PATTERN, "C3", "^[a-z][a-zA-Z0-9]*$"),
82 "27:17: "
83 + getCheckMessage(AbstractNameCheck.class,
84 MSG_INVALID_PATTERN, "D1", "^[a-z][a-zA-Z0-9]*$"),
85 "28:17: "
86 + getCheckMessage(AbstractNameCheck.class,
87 MSG_INVALID_PATTERN, "D2", "^[a-z][a-zA-Z0-9]*$"),
88 "30:17: "
89 + getCheckMessage(AbstractNameCheck.class,
90 MSG_INVALID_PATTERN, "D3", "^[a-z][a-zA-Z0-9]*$"),
91 "32:30: "
92 + getCheckMessage(AbstractNameCheck.class,
93 MSG_INVALID_PATTERN, "e1", "^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$"),
94 "33:17: "
95 + getCheckMessage(AbstractNameCheck.class,
96 MSG_INVALID_PATTERN, "E2", "^[a-z][a-zA-Z0-9]*$"),
97 "34:17: "
98 + getCheckMessage(AbstractNameCheck.class,
99 MSG_INVALID_PATTERN, "E3", "^[a-z][a-zA-Z0-9]*$"),
100 "35:30: "
101 + getCheckMessage(AbstractNameCheck.class,
102 MSG_INVALID_PATTERN, "e4", "^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$"),
103 "36:17: "
104 + getCheckMessage(AbstractNameCheck.class,
105 MSG_INVALID_PATTERN, "E5", "^[a-z][a-zA-Z0-9]*$"),
106 "37:30: "
107 + getCheckMessage(AbstractNameCheck.class,
108 MSG_INVALID_PATTERN, "e6", "^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$"),
109 "38:17: "
110 + getCheckMessage(AbstractNameCheck.class,
111 MSG_INVALID_PATTERN, "E7", "^[a-z][a-zA-Z0-9]*$"),
112 "39:17: "
113 + getCheckMessage(AbstractNameCheck.class,
114 MSG_INVALID_PATTERN, "E8", "^[a-z][a-zA-Z0-9]*$"),
115 "40:30: "
116 + getCheckMessage(AbstractNameCheck.class,
117 MSG_INVALID_PATTERN, "e9", "^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$"),
118 "64:23: "
119 + getCheckMessage(IllegalCatchCheck.class, IllegalCatchCheck.MSG_KEY, "Exception"),
120 "66:23: "
121 + getCheckMessage(IllegalCatchCheck.class, IllegalCatchCheck.MSG_KEY, "Throwable"),
122 "73:11: "
123 + getCheckMessage(IllegalCatchCheck.class, IllegalCatchCheck.MSG_KEY, "Exception"),
124 "80:59: "
125 + getCheckMessage(AbstractNameCheck.class,
126 MSG_INVALID_PATTERN, "A2", "^[a-z][a-zA-Z0-9]*$"),
127 "81:17: "
128 + getCheckMessage(AbstractNameCheck.class,
129 MSG_INVALID_PATTERN, "A1", "^[a-z][a-zA-Z0-9]*$"),
130 };
131
132 @Override
133 protected String getPackageLocation() {
134 return "com/puppycrawl/tools/checkstyle/filters/suppresswithnearbycommentfilter";
135 }
136
137 @Test
138 public void testNone() throws Exception {
139 final DefaultConfiguration filterConfig = null;
140 final String[] suppressed = CommonUtil.EMPTY_STRING_ARRAY;
141 verifySuppressed(filterConfig, suppressed);
142 }
143
144 @Test
145 public void testDefault() throws Exception {
146 final DefaultConfiguration filterConfig =
147 createModuleConfig(SuppressWithNearbyCommentFilter.class);
148 final String[] suppressed = {
149 "14:17: "
150 + getCheckMessage(AbstractNameCheck.class,
151 MSG_INVALID_PATTERN, "A1", "^[a-z][a-zA-Z0-9]*$"),
152 "15:17: "
153 + getCheckMessage(AbstractNameCheck.class,
154 MSG_INVALID_PATTERN, "A2", "^[a-z][a-zA-Z0-9]*$"),
155 "16:59: "
156 + getCheckMessage(AbstractNameCheck.class,
157 MSG_INVALID_PATTERN, "A3", "^[a-z][a-zA-Z0-9]*$"),
158 "18:17: "
159 + getCheckMessage(AbstractNameCheck.class,
160 MSG_INVALID_PATTERN, "B1", "^[a-z][a-zA-Z0-9]*$"),
161 "19:17: "
162 + getCheckMessage(AbstractNameCheck.class,
163 MSG_INVALID_PATTERN, "B2", "^[a-z][a-zA-Z0-9]*$"),
164 "20:59: "
165 + getCheckMessage(AbstractNameCheck.class,
166 MSG_INVALID_PATTERN, "B3", "^[a-z][a-zA-Z0-9]*$"),
167 "80:59: "
168 + getCheckMessage(AbstractNameCheck.class,
169 MSG_INVALID_PATTERN, "A2", "^[a-z][a-zA-Z0-9]*$"),
170 };
171 verifySuppressed(filterConfig, suppressed);
172 }
173
174 @Test
175 public void testCheckC() throws Exception {
176 final DefaultConfiguration filterConfig =
177 createModuleConfig(SuppressWithNearbyCommentFilter.class);
178 filterConfig.addAttribute("checkC", "false");
179 final String[] suppressed = {
180 "14:17: "
181 + getCheckMessage(AbstractNameCheck.class,
182 MSG_INVALID_PATTERN, "A1", "^[a-z][a-zA-Z0-9]*$"),
183 "18:17: "
184 + getCheckMessage(AbstractNameCheck.class,
185 MSG_INVALID_PATTERN, "B1", "^[a-z][a-zA-Z0-9]*$"),
186 };
187 verifySuppressed(filterConfig, suppressed);
188 }
189
190 @Test
191 public void testCheckCpp() throws Exception {
192 final DefaultConfiguration filterConfig =
193 createModuleConfig(SuppressWithNearbyCommentFilter.class);
194 filterConfig.addAttribute("checkCPP", "false");
195 final String[] suppressed = {
196 "15:17: "
197 + getCheckMessage(AbstractNameCheck.class,
198 MSG_INVALID_PATTERN, "A2", "^[a-z][a-zA-Z0-9]*$"),
199 "16:59: "
200 + getCheckMessage(AbstractNameCheck.class,
201 MSG_INVALID_PATTERN, "A3", "^[a-z][a-zA-Z0-9]*$"),
202 "19:17: "
203 + getCheckMessage(AbstractNameCheck.class,
204 MSG_INVALID_PATTERN, "B2", "^[a-z][a-zA-Z0-9]*$"),
205 "20:59: "
206 + getCheckMessage(AbstractNameCheck.class,
207 MSG_INVALID_PATTERN, "B3", "^[a-z][a-zA-Z0-9]*$"),
208 "80:59: "
209 + getCheckMessage(AbstractNameCheck.class,
210 MSG_INVALID_PATTERN, "A2", "^[a-z][a-zA-Z0-9]*$"),
211 };
212 verifySuppressed(filterConfig, suppressed);
213 }
214
215 @Test
216 public void testUsingVariableMessage() throws Exception {
217 final DefaultConfiguration filterConfig =
218 createModuleConfig(SuppressWithNearbyCommentFilter.class);
219 filterConfig.addAttribute("commentFormat", "ALLOW CATCH (\\w+) BECAUSE");
220 filterConfig.addAttribute("checkFormat", "IllegalCatchCheck");
221 filterConfig.addAttribute("messageFormat", "$1");
222 filterConfig.addAttribute("influenceFormat", "-1");
223 final String[] suppressed = {
224 "66:23: "
225 + getCheckMessage(IllegalCatchCheck.class,
226 IllegalCatchCheck.MSG_KEY, "Throwable"),
227 "73:11: "
228 + getCheckMessage(IllegalCatchCheck.class,
229 IllegalCatchCheck.MSG_KEY, "Exception"),
230 };
231 verifySuppressed(filterConfig, suppressed);
232 }
233
234 @Test
235 public void testUsingVariableCheckOnNextLine() throws Exception {
236 final DefaultConfiguration filterConfig =
237 createModuleConfig(SuppressWithNearbyCommentFilter.class);
238 filterConfig.addAttribute("commentFormat", "ALLOW (\\w+) ON NEXT LINE");
239 filterConfig.addAttribute("checkFormat", "$1");
240 filterConfig.addAttribute("influenceFormat", "1");
241 final String[] suppressed = {
242 "24:17: "
243 + getCheckMessage(AbstractNameCheck.class,
244 MSG_INVALID_PATTERN, "C2", "^[a-z][a-zA-Z0-9]*$"),
245 };
246 verifySuppressed(filterConfig, suppressed);
247 }
248
249 @Test
250 public void testUsingVariableCheckOnPreviousLine() throws Exception {
251 final DefaultConfiguration filterConfig =
252 createModuleConfig(SuppressWithNearbyCommentFilter.class);
253 filterConfig.addAttribute("commentFormat", "ALLOW (\\w+) ON PREVIOUS LINE");
254 filterConfig.addAttribute("checkFormat", "$1");
255 filterConfig.addAttribute("influenceFormat", "-1");
256 final String[] suppressed = {
257 "28:17: "
258 + getCheckMessage(AbstractNameCheck.class,
259 MSG_INVALID_PATTERN, "D2", "^[a-z][a-zA-Z0-9]*$"),
260 };
261 verifySuppressed(filterConfig, suppressed);
262 }
263
264 @Test
265 public void testVariableCheckOnVariableNumberOfLines() throws Exception {
266 final DefaultConfiguration filterConfig =
267 createModuleConfig(SuppressWithNearbyCommentFilter.class);
268 filterConfig.addAttribute("commentFormat", "ALLOW (\\w+) UNTIL THIS LINE([+-]\\d+)");
269 filterConfig.addAttribute("checkFormat", "$1");
270 filterConfig.addAttribute("influenceFormat", "$2");
271 final String[] suppressed = {
272 "35:30: "
273 + getCheckMessage(AbstractNameCheck.class,
274 MSG_INVALID_PATTERN, "e4", "^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$"),
275 "36:17: "
276 + getCheckMessage(AbstractNameCheck.class,
277 MSG_INVALID_PATTERN, "E5", "^[a-z][a-zA-Z0-9]*$"),
278 "38:17: "
279 + getCheckMessage(AbstractNameCheck.class,
280 MSG_INVALID_PATTERN, "E7", "^[a-z][a-zA-Z0-9]*$"),
281 "39:17: "
282 + getCheckMessage(AbstractNameCheck.class,
283 MSG_INVALID_PATTERN, "E8", "^[a-z][a-zA-Z0-9]*$"),
284 };
285 verifySuppressed(filterConfig, suppressed);
286 }
287
288 @Test
289 public void testEqualsAndHashCodeOfTagClass() {
290 final EqualsVerifierReport ev = EqualsVerifier
291 .forClass(SuppressWithNearbyCommentFilter.Tag.class).usingGetClass().report();
292 assertEquals("Error: " + ev.getMessage(), EqualsVerifierReport.SUCCESS, ev);
293 }
294
295 private void verifySuppressed(Configuration moduleConfig,
296 String... aSuppressed)
297 throws Exception {
298 verifySuppressed(moduleConfig, getPath("InputSuppressWithNearbyCommentFilter.java"),
299 ALL_MESSAGES, aSuppressed);
300 }
301
302 private void verifySuppressed(Configuration moduleConfig, String fileName,
303 String[] expectedViolations, String... suppressedViolations) throws Exception {
304 final DefaultConfiguration memberNameCheckConfig =
305 createModuleConfig(MemberNameCheck.class);
306 memberNameCheckConfig.addAttribute("id", "ignore");
307
308 final DefaultConfiguration constantNameCheckConfig =
309 createModuleConfig(ConstantNameCheck.class);
310 constantNameCheckConfig.addAttribute("id", null);
311
312 final DefaultConfiguration treewalkerConfig = createModuleConfig(TreeWalker.class);
313 treewalkerConfig.addChild(memberNameCheckConfig);
314 treewalkerConfig.addChild(constantNameCheckConfig);
315 treewalkerConfig.addChild(createModuleConfig(IllegalCatchCheck.class));
316
317 if (moduleConfig != null) {
318 treewalkerConfig.addChild(moduleConfig);
319 }
320
321 final DefaultConfiguration checkerConfig = createRootConfig(treewalkerConfig);
322
323 verify(checkerConfig,
324 fileName,
325 removeSuppressed(expectedViolations, suppressedViolations));
326 }
327
328 private static String[] removeSuppressed(String[] from, String... remove) {
329 final Collection<String> coll = Arrays.stream(from).collect(Collectors.toList());
330 coll.removeAll(Arrays.asList(remove));
331 return coll.toArray(CommonUtil.EMPTY_STRING_ARRAY);
332 }
333
334 @Test
335 public void testInvalidInfluenceFormat() throws Exception {
336 final DefaultConfiguration filterConfig =
337 createModuleConfig(SuppressWithNearbyCommentFilter.class);
338 filterConfig.addAttribute("influenceFormat", "a");
339
340 try {
341 final String[] suppressed = CommonUtil.EMPTY_STRING_ARRAY;
342 verifySuppressed(filterConfig, suppressed);
343 fail("Exception is expected");
344 }
345 catch (CheckstyleException ex) {
346 final IllegalArgumentException cause = (IllegalArgumentException) ex.getCause();
347 assertEquals("Invalid exception message", "unable to parse influence"
348 + " from 'SUPPRESS CHECKSTYLE MemberNameCheck' using a", cause.getMessage());
349 }
350 }
351
352 @Test
353 public void testInfluenceFormat() throws Exception {
354 final DefaultConfiguration filterConfig =
355 createModuleConfig(SuppressWithNearbyCommentFilter.class);
356 filterConfig.addAttribute("influenceFormat", "1");
357
358 final String[] suppressed = {
359 "14:17: "
360 + getCheckMessage(AbstractNameCheck.class,
361 MSG_INVALID_PATTERN, "A1", "^[a-z][a-zA-Z0-9]*$"),
362 "15:17: "
363 + getCheckMessage(AbstractNameCheck.class,
364 MSG_INVALID_PATTERN, "A2", "^[a-z][a-zA-Z0-9]*$"),
365 "16:59: "
366 + getCheckMessage(AbstractNameCheck.class,
367 MSG_INVALID_PATTERN, "A3", "^[a-z][a-zA-Z0-9]*$"),
368 "18:17: "
369 + getCheckMessage(AbstractNameCheck.class,
370 MSG_INVALID_PATTERN, "B1", "^[a-z][a-zA-Z0-9]*$"),
371 "19:17: "
372 + getCheckMessage(AbstractNameCheck.class,
373 MSG_INVALID_PATTERN, "B2", "^[a-z][a-zA-Z0-9]*$"),
374 "20:59: "
375 + getCheckMessage(AbstractNameCheck.class,
376 MSG_INVALID_PATTERN, "B3", "^[a-z][a-zA-Z0-9]*$"),
377 "80:59: "
378 + getCheckMessage(AbstractNameCheck.class,
379 MSG_INVALID_PATTERN, "A2", "^[a-z][a-zA-Z0-9]*$"),
380 "81:17: "
381 + getCheckMessage(AbstractNameCheck.class,
382 MSG_INVALID_PATTERN, "A1", "^[a-z][a-zA-Z0-9]*$"),
383 };
384 verifySuppressed(filterConfig, suppressed);
385 }
386
387 @Test
388 public void testInvalidCheckFormat() throws Exception {
389 final DefaultConfiguration filterConfig =
390 createModuleConfig(SuppressWithNearbyCommentFilter.class);
391 filterConfig.addAttribute("checkFormat", "a[l");
392
393 try {
394 final String[] suppressed = CommonUtil.EMPTY_STRING_ARRAY;
395 verifySuppressed(filterConfig, suppressed);
396 fail("Exception is expected");
397 }
398 catch (CheckstyleException ex) {
399 final IllegalArgumentException cause = (IllegalArgumentException) ex.getCause();
400 assertEquals("Invalid exception message",
401 "unable to parse expanded comment a[l", cause.getMessage());
402 }
403 }
404
405 @Test
406 public void testAcceptNullLocalizedMessage() {
407 final SuppressWithNearbyCommentFilter filter = new SuppressWithNearbyCommentFilter();
408 final TreeWalkerAuditEvent auditEvent = new TreeWalkerAuditEvent(null, null, null, null);
409 assertTrue("Filter should accept null localized message", filter.accept(auditEvent));
410 }
411
412 @Test
413 public void testToStringOfTagClass() {
414 final SuppressWithNearbyCommentFilter.Tag tag = new SuppressWithNearbyCommentFilter.Tag(
415 "text", 7, new SuppressWithNearbyCommentFilter()
416 );
417 assertEquals("Invalid toString result",
418 "Tag[text='text', firstLine=7, lastLine=7, "
419 + "tagCheckRegexp=.*, tagMessageRegexp=null]", tag.toString());
420 }
421
422 @Test
423 public void testUsingTagMessageRegexp() throws Exception {
424 final DefaultConfiguration filterConfig =
425 createModuleConfig(SuppressWithNearbyCommentFilter.class);
426 filterConfig.addAttribute("commentFormat", "SUPPRESS CHECKSTYLE (\\w+)");
427 filterConfig.addAttribute("checkFormat", "IllegalCatchCheck");
428 filterConfig.addAttribute("messageFormat", "^$1 ololo*$");
429 final String[] suppressed = CommonUtil.EMPTY_STRING_ARRAY;
430 verifySuppressed(filterConfig, suppressed);
431 }
432
433 @Test
434 public void testSuppressById() throws Exception {
435 final DefaultConfiguration filterConfig =
436 createModuleConfig(SuppressWithNearbyCommentFilter.class);
437 filterConfig.addAttribute("commentFormat", "@cs-: (\\w+) \\(\\w+\\)");
438 filterConfig.addAttribute("checkFormat", "$1");
439 filterConfig.addAttribute("influenceFormat", "0");
440 final String[] suppressedViolationMessages = {
441 "5:17: "
442 + getCheckMessage(AbstractNameCheck.class,
443 MSG_INVALID_PATTERN, "A1", "^[a-z][a-zA-Z0-9]*$"),
444 "9:9: "
445 + getCheckMessage(AbstractNameCheck.class,
446 MSG_INVALID_PATTERN, "line_length", "^[a-z][a-zA-Z0-9]*$"),
447 };
448 final String[] expectedViolationMessages = {
449 "5:17: "
450 + getCheckMessage(AbstractNameCheck.class,
451 MSG_INVALID_PATTERN, "A1", "^[a-z][a-zA-Z0-9]*$"),
452 "7:30: "
453 + getCheckMessage(AbstractNameCheck.class,
454 MSG_INVALID_PATTERN, "abc", "^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$"),
455 "9:9: "
456 + getCheckMessage(AbstractNameCheck.class,
457 MSG_INVALID_PATTERN, "line_length", "^[a-z][a-zA-Z0-9]*$"),
458 "11:18: "
459 + getCheckMessage(AbstractNameCheck.class,
460 MSG_INVALID_PATTERN, "ID", "^[a-z][a-zA-Z0-9]*$"),
461 };
462
463 verifySuppressed(filterConfig,
464 getPath("InputSuppressWithNearbyCommentFilterById.java"),
465 expectedViolationMessages, suppressedViolationMessages);
466 }
467
468 @Test
469 public void testTagsAreClearedEachRun() {
470 final SuppressWithNearbyCommentFilter suppressionCommentFilter =
471 new SuppressWithNearbyCommentFilter();
472 final FileContents contents =
473 new FileContents("filename", "//SUPPRESS CHECKSTYLE ignore", "line2");
474 contents.reportSingleLineComment(1, 0);
475 final TreeWalkerAuditEvent dummyEvent = new TreeWalkerAuditEvent(contents, "filename",
476 new LocalizedMessage(1, null, null, null, null, Object.class, null), null);
477 suppressionCommentFilter.accept(dummyEvent);
478 final FileContents contents2 =
479 new FileContents("filename2", "some line", "//SUPPRESS CHECKSTYLE ignore");
480 contents2.reportSingleLineComment(2, 0);
481 final TreeWalkerAuditEvent dummyEvent2 = new TreeWalkerAuditEvent(contents2, "filename",
482 new LocalizedMessage(1, null, null, null, null, Object.class, null), null);
483 suppressionCommentFilter.accept(dummyEvent2);
484 final List<SuppressionCommentFilter.Tag> tags =
485 Whitebox.getInternalState(suppressionCommentFilter, "tags");
486 assertEquals("Invalid tags size", 1, tags.size());
487 }
488
489 }