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.assertFalse;
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.Assert;
33 import org.junit.Test;
34 import org.powermock.reflect.Whitebox;
35
36 import com.puppycrawl.tools.checkstyle.AbstractModuleTestSupport;
37 import com.puppycrawl.tools.checkstyle.DefaultConfiguration;
38 import com.puppycrawl.tools.checkstyle.TreeWalker;
39 import com.puppycrawl.tools.checkstyle.TreeWalkerAuditEvent;
40 import com.puppycrawl.tools.checkstyle.api.CheckstyleException;
41 import com.puppycrawl.tools.checkstyle.api.Configuration;
42 import com.puppycrawl.tools.checkstyle.api.FileContents;
43 import com.puppycrawl.tools.checkstyle.api.LocalizedMessage;
44 import com.puppycrawl.tools.checkstyle.checks.coding.IllegalCatchCheck;
45 import com.puppycrawl.tools.checkstyle.checks.naming.AbstractNameCheck;
46 import com.puppycrawl.tools.checkstyle.checks.naming.ConstantNameCheck;
47 import com.puppycrawl.tools.checkstyle.checks.naming.MemberNameCheck;
48 import com.puppycrawl.tools.checkstyle.utils.CommonUtil;
49 import nl.jqno.equalsverifier.EqualsVerifier;
50 import nl.jqno.equalsverifier.EqualsVerifierReport;
51
52 public class SuppressionCommentFilterTest
53 extends AbstractModuleTestSupport {
54
55 private static final String[] ALL_MESSAGES = {
56 "13:17: "
57 + getCheckMessage(AbstractNameCheck.class,
58 MSG_INVALID_PATTERN, "I", "^[a-z][a-zA-Z0-9]*$"),
59 "16:17: "
60 + getCheckMessage(AbstractNameCheck.class,
61 MSG_INVALID_PATTERN, "J", "^[a-z][a-zA-Z0-9]*$"),
62 "19:17: "
63 + getCheckMessage(AbstractNameCheck.class,
64 MSG_INVALID_PATTERN, "K", "^[a-z][a-zA-Z0-9]*$"),
65 "22:17: "
66 + getCheckMessage(AbstractNameCheck.class,
67 MSG_INVALID_PATTERN, "L", "^[a-z][a-zA-Z0-9]*$"),
68 "23:30: "
69 + getCheckMessage(AbstractNameCheck.class,
70 MSG_INVALID_PATTERN, "m", "^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$"),
71 "27:17: "
72 + getCheckMessage(AbstractNameCheck.class,
73 MSG_INVALID_PATTERN, "M2", "^[a-z][a-zA-Z0-9]*$"),
74 "28:30: "
75 + getCheckMessage(AbstractNameCheck.class,
76 MSG_INVALID_PATTERN, "n", "^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$"),
77 "32:17: "
78 + getCheckMessage(AbstractNameCheck.class,
79 MSG_INVALID_PATTERN, "P", "^[a-z][a-zA-Z0-9]*$"),
80 "35:17: "
81 + getCheckMessage(AbstractNameCheck.class,
82 MSG_INVALID_PATTERN, "Q", "^[a-z][a-zA-Z0-9]*$"),
83 "38:17: "
84 + getCheckMessage(AbstractNameCheck.class,
85 MSG_INVALID_PATTERN, "R", "^[a-z][a-zA-Z0-9]*$"),
86 "39:30: "
87 + getCheckMessage(AbstractNameCheck.class,
88 MSG_INVALID_PATTERN, "s", "^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$"),
89 "43:17: "
90 + getCheckMessage(AbstractNameCheck.class,
91 MSG_INVALID_PATTERN, "T", "^[a-z][a-zA-Z0-9]*$"),
92 "64:23: "
93 + getCheckMessage(IllegalCatchCheck.class, IllegalCatchCheck.MSG_KEY, "Exception"),
94 "71:11: "
95 + getCheckMessage(IllegalCatchCheck.class, IllegalCatchCheck.MSG_KEY, "Exception"),
96 "77:11: "
97 + getCheckMessage(IllegalCatchCheck.class,
98 IllegalCatchCheck.MSG_KEY, "RuntimeException"),
99 "78:11: "
100 + getCheckMessage(IllegalCatchCheck.class, IllegalCatchCheck.MSG_KEY, "Exception"),
101 "86:31: "
102 + getCheckMessage(IllegalCatchCheck.class, IllegalCatchCheck.MSG_KEY, "Exception"),
103 };
104
105 @Override
106 protected String getPackageLocation() {
107 return "com/puppycrawl/tools/checkstyle/filters/suppressioncommentfilter";
108 }
109
110 @Test
111 public void testNone() throws Exception {
112 final DefaultConfiguration filterConfig = null;
113 final String[] suppressed = CommonUtil.EMPTY_STRING_ARRAY;
114 verifySuppressed(filterConfig, suppressed);
115 }
116
117
118 @Test
119 public void testDefault() throws Exception {
120 final DefaultConfiguration filterConfig =
121 createModuleConfig(SuppressionCommentFilter.class);
122 final String[] suppressed = {
123 "16:17: "
124 + getCheckMessage(AbstractNameCheck.class,
125 MSG_INVALID_PATTERN, "J", "^[a-z][a-zA-Z0-9]*$"),
126 "43:17: "
127 + getCheckMessage(AbstractNameCheck.class,
128 MSG_INVALID_PATTERN, "T", "^[a-z][a-zA-Z0-9]*$"),
129 "64:23: "
130 + getCheckMessage(IllegalCatchCheck.class, IllegalCatchCheck.MSG_KEY, "Exception"),
131 "71:11: "
132 + getCheckMessage(IllegalCatchCheck.class, IllegalCatchCheck.MSG_KEY, "Exception"),
133 "86:31: "
134 + getCheckMessage(IllegalCatchCheck.class, IllegalCatchCheck.MSG_KEY, "Exception"),
135 };
136 verifySuppressed(filterConfig, suppressed);
137 }
138
139 @Test
140 public void testCheckC() throws Exception {
141 final DefaultConfiguration filterConfig =
142 createModuleConfig(SuppressionCommentFilter.class);
143 filterConfig.addAttribute("checkC", "false");
144 final String[] suppressed = {
145 "43:17: "
146 + getCheckMessage(AbstractNameCheck.class,
147 MSG_INVALID_PATTERN, "T", "^[a-z][a-zA-Z0-9]*$"),
148 "64:23: "
149 + getCheckMessage(IllegalCatchCheck.class, IllegalCatchCheck.MSG_KEY, "Exception"),
150 "71:11: "
151 + getCheckMessage(IllegalCatchCheck.class, IllegalCatchCheck.MSG_KEY, "Exception"),
152 };
153 verifySuppressed(filterConfig, suppressed);
154 }
155
156 @Test
157 public void testCheckCpp() throws Exception {
158 final DefaultConfiguration filterConfig =
159 createModuleConfig(SuppressionCommentFilter.class);
160 filterConfig.addAttribute("checkCPP", "false");
161 final String[] suppressed = {
162 "16:17: "
163 + getCheckMessage(AbstractNameCheck.class,
164 MSG_INVALID_PATTERN, "J", "^[a-z][a-zA-Z0-9]*$"),
165 "86:31: "
166 + getCheckMessage(IllegalCatchCheck.class, IllegalCatchCheck.MSG_KEY, "Exception"),
167 };
168 verifySuppressed(filterConfig, suppressed);
169 }
170
171
172 @Test
173 public void testOffFormat() throws Exception {
174 final DefaultConfiguration filterConfig =
175 createModuleConfig(SuppressionCommentFilter.class);
176 filterConfig.addAttribute("offCommentFormat", "CS_OFF");
177 filterConfig.addAttribute("onCommentFormat", "CS_ON");
178 final String[] suppressed = {
179 "32:17: "
180 + getCheckMessage(AbstractNameCheck.class,
181 MSG_INVALID_PATTERN, "P", "^[a-z][a-zA-Z0-9]*$"),
182 "38:17: "
183 + getCheckMessage(AbstractNameCheck.class,
184 MSG_INVALID_PATTERN, "R", "^[a-z][a-zA-Z0-9]*$"),
185 "39:30: "
186 + getCheckMessage(AbstractNameCheck.class,
187 MSG_INVALID_PATTERN, "s", "^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$"),
188 "42:17: "
189 + getCheckMessage(AbstractNameCheck.class,
190 MSG_INVALID_PATTERN, "T", "^[a-z][a-zA-Z0-9]*$"),
191 };
192 verifySuppressed(filterConfig, suppressed);
193 }
194
195
196
197 @Test
198 public void testOffFormatCheck() throws Exception {
199 final DefaultConfiguration filterConfig =
200 createModuleConfig(SuppressionCommentFilter.class);
201 filterConfig.addAttribute("offCommentFormat", "CS_OFF");
202 filterConfig.addAttribute("onCommentFormat", "CS_ON");
203 filterConfig.addAttribute("checkFormat", "ConstantNameCheck");
204 final String[] suppressed = {
205 "39:30: "
206 + getCheckMessage(AbstractNameCheck.class,
207 MSG_INVALID_PATTERN, "s", "^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$"),
208 };
209 verifySuppressed(filterConfig, suppressed);
210 }
211
212 @Test
213 public void testArgumentSuppression() throws Exception {
214 final DefaultConfiguration filterConfig =
215 createModuleConfig(SuppressionCommentFilter.class);
216 filterConfig.addAttribute("offCommentFormat", "IllegalCatchCheck OFF\\: (\\w+)");
217 filterConfig.addAttribute("onCommentFormat", "IllegalCatchCheck ON\\: (\\w+)");
218 filterConfig.addAttribute("checkFormat", "IllegalCatchCheck");
219
220 filterConfig.addAttribute("messageFormat",
221 "^" + getCheckMessage(IllegalCatchCheck.class, IllegalCatchCheck.MSG_KEY, "$1")
222 + "*$");
223 final String[] suppressed = {
224 "78:11: "
225 + getCheckMessage(IllegalCatchCheck.class, IllegalCatchCheck.MSG_KEY, "Exception"),
226 };
227 verifySuppressed(filterConfig, suppressed);
228 }
229
230 @Test
231 public void testExpansion() throws Exception {
232 final DefaultConfiguration filterConfig =
233 createModuleConfig(SuppressionCommentFilter.class);
234 filterConfig.addAttribute("offCommentFormat", "CSOFF\\: ([\\w\\|]+)");
235 filterConfig.addAttribute("onCommentFormat", "CSON\\: ([\\w\\|]+)");
236 filterConfig.addAttribute("checkFormat", "$1");
237 final String[] suppressed = {
238 "22:17: "
239 + getCheckMessage(AbstractNameCheck.class,
240 MSG_INVALID_PATTERN, "L", "^[a-z][a-zA-Z0-9]*$"),
241 "23:30: "
242 + getCheckMessage(AbstractNameCheck.class,
243 MSG_INVALID_PATTERN, "m", "^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$"),
244 "28:30: "
245 + getCheckMessage(AbstractNameCheck.class,
246 MSG_INVALID_PATTERN, "n", "^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$"),
247 };
248 verifySuppressed(filterConfig, suppressed);
249 }
250
251 @Test
252 public void testMessage() throws Exception {
253 final DefaultConfiguration filterConfig =
254 createModuleConfig(SuppressionCommentFilter.class);
255 filterConfig.addAttribute("onCommentFormat", "UNUSED ON\\: (\\w+)");
256 filterConfig.addAttribute("offCommentFormat", "UNUSED OFF\\: (\\w+)");
257 filterConfig.addAttribute("checkFormat", "Unused");
258 filterConfig.addAttribute("messageFormat", "^Unused \\w+ '$1'.$");
259 final String[] suppressed = CommonUtil.EMPTY_STRING_ARRAY;
260 verifySuppressed(filterConfig, suppressed);
261 }
262
263 private void verifySuppressed(Configuration moduleConfig,
264 String... aSuppressed)
265 throws Exception {
266 verifySuppressed(moduleConfig, getPath("InputSuppressionCommentFilter.java"),
267 ALL_MESSAGES, aSuppressed);
268 }
269
270 private void verifySuppressed(Configuration moduleConfig, String fileName,
271 String[] expectedViolations, String... suppressedViolations) throws Exception {
272 final DefaultConfiguration memberNameCheckConfig =
273 createModuleConfig(MemberNameCheck.class);
274 memberNameCheckConfig.addAttribute("id", "ignore");
275
276 final DefaultConfiguration constantNameCheckConfig =
277 createModuleConfig(ConstantNameCheck.class);
278 constantNameCheckConfig.addAttribute("id", null);
279
280 final DefaultConfiguration treewalkerConfig = createModuleConfig(TreeWalker.class);
281 treewalkerConfig.addChild(memberNameCheckConfig);
282 treewalkerConfig.addChild(constantNameCheckConfig);
283 treewalkerConfig.addChild(createModuleConfig(IllegalCatchCheck.class));
284
285 if (moduleConfig != null) {
286 treewalkerConfig.addChild(moduleConfig);
287 }
288
289 final DefaultConfiguration checkerConfig = createRootConfig(treewalkerConfig);
290
291 verify(checkerConfig, fileName,
292 removeSuppressed(expectedViolations, suppressedViolations));
293 }
294
295 private static String[] removeSuppressed(String[] from, String... remove) {
296 final Collection<String> coll = Arrays.stream(from).collect(Collectors.toList());
297 coll.removeAll(Arrays.asList(remove));
298 return coll.toArray(CommonUtil.EMPTY_STRING_ARRAY);
299 }
300
301 @Test
302 public void testEqualsAndHashCodeOfTagClass() {
303 final EqualsVerifierReport ev = EqualsVerifier.forClass(SuppressionCommentFilter.Tag.class)
304 .usingGetClass().report();
305 assertEquals("Error: " + ev.getMessage(), EqualsVerifierReport.SUCCESS, ev);
306 }
307
308 @Test
309 public void testToStringOfTagClass() {
310 final SuppressionCommentFilter.Tag tag = new SuppressionCommentFilter.Tag(
311 0, 1, "text",
312 SuppressionCommentFilter.TagType.OFF, new SuppressionCommentFilter()
313 );
314
315 assertEquals("Invalid toString result",
316 "Tag[text='text', line=0, column=1, type=OFF,"
317 + " tagCheckRegexp=.*, tagMessageRegexp=null]", tag.toString());
318 }
319
320 @Test
321 public void testInvalidCheckFormat() throws Exception {
322 final DefaultConfiguration filterConfig =
323 createModuleConfig(SuppressionCommentFilter.class);
324 filterConfig.addAttribute("checkFormat", "e[l");
325
326 try {
327 final String[] suppressed = CommonUtil.EMPTY_STRING_ARRAY;
328 verifySuppressed(filterConfig, suppressed);
329 fail("Exception is expected");
330 }
331 catch (CheckstyleException ex) {
332 final IllegalArgumentException cause = (IllegalArgumentException) ex.getCause();
333 assertEquals("Invalid exception message",
334 "unable to parse expanded comment e[l", cause.getMessage());
335 }
336 }
337
338 @Test
339 public void testInvalidMessageFormat() throws Exception {
340 final DefaultConfiguration filterConfig =
341 createModuleConfig(SuppressionCommentFilter.class);
342 filterConfig.addAttribute("messageFormat", "e[l");
343
344 try {
345 final String[] suppressed = CommonUtil.EMPTY_STRING_ARRAY;
346 verifySuppressed(filterConfig, suppressed);
347 fail("Exception is expected");
348 }
349 catch (CheckstyleException ex) {
350 final IllegalArgumentException cause = (IllegalArgumentException) ex.getCause();
351 assertEquals("Invalid exception message",
352 "unable to parse expanded comment e[l", cause.getMessage());
353 }
354 }
355
356 @Test
357 public void testAcceptNullLocalizedMessage() {
358 final SuppressionCommentFilter filter = new SuppressionCommentFilter();
359 final TreeWalkerAuditEvent auditEvent = new TreeWalkerAuditEvent(null, null, null, null);
360 Assert.assertTrue("Filter should accept audit event", filter.accept(auditEvent));
361 Assert.assertNull("File name should not be null", auditEvent.getFileName());
362 }
363
364 @Test
365 public void testSuppressById() throws Exception {
366 final DefaultConfiguration filterConfig =
367 createModuleConfig(SuppressionCommentFilter.class);
368 filterConfig.addAttribute("offCommentFormat", "CSOFF (\\w+) \\(\\w+\\)");
369 filterConfig.addAttribute("onCommentFormat", "CSON (\\w+)");
370 filterConfig.addAttribute("checkFormat", "$1");
371 final String[] suppressedViolationMessages = {
372 "6:17: "
373 + getCheckMessage(AbstractNameCheck.class,
374 MSG_INVALID_PATTERN, "A1", "^[a-z][a-zA-Z0-9]*$"),
375 "12:9: "
376 + getCheckMessage(AbstractNameCheck.class,
377 MSG_INVALID_PATTERN, "line_length", "^[a-z][a-zA-Z0-9]*$"),
378 };
379 final String[] expectedViolationMessages = {
380 "6:17: "
381 + getCheckMessage(AbstractNameCheck.class,
382 MSG_INVALID_PATTERN, "A1", "^[a-z][a-zA-Z0-9]*$"),
383 "9:30: "
384 + getCheckMessage(AbstractNameCheck.class,
385 MSG_INVALID_PATTERN, "abc", "^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$"),
386 "12:9: "
387 + getCheckMessage(AbstractNameCheck.class,
388 MSG_INVALID_PATTERN, "line_length", "^[a-z][a-zA-Z0-9]*$"),
389 "15:18: "
390 + getCheckMessage(AbstractNameCheck.class,
391 MSG_INVALID_PATTERN, "ID", "^[a-z][a-zA-Z0-9]*$"),
392 };
393
394 verifySuppressed(filterConfig, getPath("InputSuppressionCommentFilterSuppressById.java"),
395 expectedViolationMessages, suppressedViolationMessages);
396 }
397
398 @Test
399 public void testFindNearestMatchDontAllowSameColumn() {
400 final SuppressionCommentFilter suppressionCommentFilter = new SuppressionCommentFilter();
401 final FileContents contents =
402 new FileContents("filename", "//CHECKSTYLE:OFF: ConstantNameCheck", "line2");
403 contents.reportSingleLineComment(1, 0);
404 final TreeWalkerAuditEvent dummyEvent = new TreeWalkerAuditEvent(contents, "filename",
405 new LocalizedMessage(1, null, null, null, null, Object.class, null), null);
406 final boolean result = suppressionCommentFilter.accept(dummyEvent);
407 assertFalse("Filter should not accept event", result);
408 }
409
410 @Test
411 public void testTagsAreClearedEachRun() {
412 final SuppressionCommentFilter suppressionCommentFilter = new SuppressionCommentFilter();
413 final FileContents contents =
414 new FileContents("filename", "//CHECKSTYLE:OFF", "line2");
415 contents.reportSingleLineComment(1, 0);
416 final TreeWalkerAuditEvent dummyEvent = new TreeWalkerAuditEvent(contents, "filename",
417 new LocalizedMessage(1, null, null, null, null, Object.class, null), null);
418 suppressionCommentFilter.accept(dummyEvent);
419 final FileContents contents2 =
420 new FileContents("filename2", "some line", "//CHECKSTYLE:OFF");
421 contents2.reportSingleLineComment(2, 0);
422 final TreeWalkerAuditEvent dummyEvent2 = new TreeWalkerAuditEvent(contents2, "filename",
423 new LocalizedMessage(1, null, null, null, null, Object.class, null), null);
424 suppressionCommentFilter.accept(dummyEvent2);
425 final List<SuppressionCommentFilter.Tag> tags =
426 Whitebox.getInternalState(suppressionCommentFilter, "tags");
427 assertEquals("Invalid tags size", 1, tags.size());
428 }
429
430 }