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.checks;
21
22 import static org.junit.Assert.assertArrayEquals;
23 import static org.junit.Assert.assertEquals;
24 import static org.junit.Assert.assertFalse;
25 import static org.junit.Assert.assertTrue;
26 import static org.junit.Assert.fail;
27
28 import java.io.File;
29 import java.lang.reflect.Constructor;
30 import java.lang.reflect.InvocationTargetException;
31 import java.lang.reflect.Method;
32 import java.util.List;
33 import java.util.Map;
34 import java.util.Optional;
35
36 import org.junit.After;
37 import org.junit.Test;
38 import org.powermock.reflect.Whitebox;
39
40 import com.puppycrawl.tools.checkstyle.AbstractModuleTestSupport;
41 import com.puppycrawl.tools.checkstyle.Checker;
42 import com.puppycrawl.tools.checkstyle.DefaultConfiguration;
43 import com.puppycrawl.tools.checkstyle.JavaParser;
44 import com.puppycrawl.tools.checkstyle.TreeWalker;
45 import com.puppycrawl.tools.checkstyle.api.AuditEvent;
46 import com.puppycrawl.tools.checkstyle.api.Configuration;
47 import com.puppycrawl.tools.checkstyle.api.DetailAST;
48 import com.puppycrawl.tools.checkstyle.api.LocalizedMessage;
49 import com.puppycrawl.tools.checkstyle.api.TokenTypes;
50 import com.puppycrawl.tools.checkstyle.checks.naming.MemberNameCheck;
51 import com.puppycrawl.tools.checkstyle.checks.whitespace.AbstractParenPadCheck;
52 import com.puppycrawl.tools.checkstyle.checks.whitespace.TypecastParenPadCheck;
53 import com.puppycrawl.tools.checkstyle.filters.SuppressWarningsFilter;
54 import com.puppycrawl.tools.checkstyle.internal.utils.TestUtil;
55 import com.puppycrawl.tools.checkstyle.utils.CommonUtil;
56
57 public class SuppressWarningsHolderTest extends AbstractModuleTestSupport {
58
59 @Override
60 protected String getPackageLocation() {
61 return "com/puppycrawl/tools/checkstyle/checks/suppresswarningsholder";
62 }
63
64 @After
65 public void cleanUp() {
66
67
68 new SuppressWarningsHolder().beginTree(null);
69
70 final Map<String, String> map = Whitebox.getInternalState(SuppressWarningsHolder.class,
71 "CHECK_ALIAS_MAP");
72 map.clear();
73 }
74
75 @Test
76 public void testGet() {
77 final SuppressWarningsHolder checkObj = new SuppressWarningsHolder();
78 final int[] expected = {TokenTypes.ANNOTATION};
79 assertArrayEquals("Required token array differs from expected",
80 expected, checkObj.getRequiredTokens());
81 assertArrayEquals("Required token array differs from expected",
82 expected, checkObj.getAcceptableTokens());
83 }
84
85 @Test
86 public void testOnComplexAnnotations() throws Exception {
87 final Configuration checkConfig = createModuleConfig(SuppressWarningsHolder.class);
88
89 final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
90
91 verify(checkConfig, getPath("InputSuppressWarningsHolder.java"), expected);
92 }
93
94 @Test
95 public void testOnComplexAnnotationsNonConstant() throws Exception {
96 final Configuration checkConfig = createModuleConfig(SuppressWarningsHolder.class);
97
98 final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
99
100 verify(checkConfig,
101 getNonCompilablePath("InputSuppressWarningsHolderNonConstant.java"), expected);
102 }
103
104 @Test
105 public void testCustomAnnotation() throws Exception {
106 final Configuration checkConfig = createModuleConfig(SuppressWarningsHolder.class);
107
108 final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
109
110 verify(checkConfig, getPath("InputSuppressWarningsHolder5.java"), expected);
111 }
112
113 @Test
114 public void testAll() throws Exception {
115 final Configuration checkConfig = createModuleConfig(SuppressWarningsHolder.class);
116 final DefaultConfiguration treeWalker = createModuleConfig(TreeWalker.class);
117 final Configuration filter = createModuleConfig(SuppressWarningsFilter.class);
118 final DefaultConfiguration violationCheck = createModuleConfig(TypecastParenPadCheck.class);
119 violationCheck.addAttribute("option", "space");
120
121 treeWalker.addChild(checkConfig);
122 treeWalker.addChild(violationCheck);
123
124 final DefaultConfiguration root = createRootConfig(treeWalker);
125 root.addChild(filter);
126
127 final String[] expected = {
128 "8:72: "
129 + getCheckMessage(TypecastParenPadCheck.class,
130 AbstractParenPadCheck.MSG_WS_NOT_PRECEDED, ")"),
131 };
132
133 verify(root, getPath("InputSuppressWarningsHolder6.java"), expected);
134 }
135
136 @Test
137 public void testGetDefaultAlias() {
138 assertEquals("Default alias differs from expected",
139 "somename", SuppressWarningsHolder.getDefaultAlias("SomeName"));
140 assertEquals("Default alias differs from expected",
141 "somename", SuppressWarningsHolder.getDefaultAlias("SomeNameCheck"));
142 }
143
144 @Test
145 public void testSetAliasListEmpty() {
146 final SuppressWarningsHolder holder = new SuppressWarningsHolder();
147 holder.setAliasList("");
148 assertEquals("Empty alias list should not be set", "",
149 SuppressWarningsHolder.getAlias(""));
150 }
151
152 @Test
153 public void testSetAliasListCorrect() {
154 final SuppressWarningsHolder holder = new SuppressWarningsHolder();
155 holder.setAliasList("alias=value");
156 assertEquals("Alias differs from expected",
157 "value", SuppressWarningsHolder.getAlias("alias"));
158 }
159
160 @Test
161 public void testSetAliasListWrong() {
162 final SuppressWarningsHolder holder = new SuppressWarningsHolder();
163
164 try {
165 holder.setAliasList("=SomeAlias");
166 fail("Exception expected");
167 }
168 catch (IllegalArgumentException ex) {
169 assertEquals("Error message is unexpected",
170 "'=' expected in alias list item: =SomeAlias", ex.getMessage());
171 }
172 }
173
174 @Test
175 public void testIsSuppressed() throws Exception {
176 populateHolder("MockEntry", 100, 100, 350, 350);
177 final AuditEvent event = createAuditEvent("check", 100, 10);
178
179 assertFalse("Event is not suppressed", SuppressWarningsHolder.isSuppressed(event));
180 }
181
182 @Test
183 public void testIsSuppressedByName() throws Exception {
184 populateHolder("check", 100, 100, 350, 350);
185 final SuppressWarningsHolder holder = new SuppressWarningsHolder();
186 final AuditEvent event = createAuditEvent("id", 110, 10);
187 holder.setAliasList(MemberNameCheck.class.getName() + "=check");
188
189 assertTrue("Event is not suppressed", SuppressWarningsHolder.isSuppressed(event));
190 }
191
192 @Test
193 public void testIsSuppressedByModuleId() throws Exception {
194 populateHolder("check", 100, 100, 350, 350);
195 final AuditEvent event = createAuditEvent("check", 350, 350);
196
197 assertTrue("Event is not suppressed", SuppressWarningsHolder.isSuppressed(event));
198 }
199
200 @Test
201 public void testIsSuppressedAfterEventEnd() throws Exception {
202 populateHolder("check", 100, 100, 350, 350);
203 final AuditEvent event = createAuditEvent("check", 350, 352);
204
205 assertFalse("Event is not suppressed", SuppressWarningsHolder.isSuppressed(event));
206 }
207
208 @Test
209 public void testIsSuppressedAfterEventEnd2() throws Exception {
210 populateHolder("check", 100, 100, 350, 350);
211 final AuditEvent event = createAuditEvent("check", 400, 10);
212
213 assertFalse("Event is not suppressed", SuppressWarningsHolder.isSuppressed(event));
214 }
215
216 @Test
217 public void testIsSuppressedAfterEventStart() throws Exception {
218 populateHolder("check", 100, 100, 350, 350);
219 final AuditEvent event = createAuditEvent("check", 100, 100);
220
221 assertTrue("Event is not suppressed", SuppressWarningsHolder.isSuppressed(event));
222 }
223
224 @Test
225 public void testIsSuppressedWithAllArgument() throws Exception {
226 populateHolder("all", 100, 100, 350, 350);
227
228 final Checker source = new Checker();
229 final LocalizedMessage firstMessageForTest =
230 new LocalizedMessage(100, 10, null, null, null, "id", MemberNameCheck.class, "msg");
231 final AuditEvent firstEventForTest =
232 new AuditEvent(source, "fileName", firstMessageForTest);
233 assertFalse("Event is suppressed",
234 SuppressWarningsHolder.isSuppressed(firstEventForTest));
235
236 final LocalizedMessage secondMessageForTest =
237 new LocalizedMessage(100, 150, null, null, null, "id", MemberNameCheck.class, "msg");
238 final AuditEvent secondEventForTest =
239 new AuditEvent(source, "fileName", secondMessageForTest);
240 assertTrue("Event is not suppressed",
241 SuppressWarningsHolder.isSuppressed(secondEventForTest));
242
243 final LocalizedMessage thirdMessageForTest =
244 new LocalizedMessage(200, 1, null, null, null, "id", MemberNameCheck.class, "msg");
245 final AuditEvent thirdEventForTest =
246 new AuditEvent(source, "fileName", thirdMessageForTest);
247 assertTrue("Event is not suppressed",
248 SuppressWarningsHolder.isSuppressed(thirdEventForTest));
249 }
250
251 @Test
252 public void testAnnotationInTry() throws Exception {
253 final Configuration checkConfig = createModuleConfig(SuppressWarningsHolder.class);
254
255 final String[] expected = {
256 "11: " + getCheckMessage(SuppressWarningsHolder.MSG_KEY),
257 };
258
259 verify(checkConfig, getPath("InputSuppressWarningsHolder2.java"), expected);
260 }
261
262 @Test
263 public void testEmptyAnnotation() throws Exception {
264 final Configuration checkConfig = createModuleConfig(SuppressWarningsHolder.class);
265
266 final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
267
268 verify(checkConfig, getPath("InputSuppressWarningsHolder3.java"), expected);
269 }
270
271 @Test
272 public void testGetAllAnnotationValuesWrongArg() throws ReflectiveOperationException {
273 final SuppressWarningsHolder holder = new SuppressWarningsHolder();
274 final Method getAllAnnotationValues = holder.getClass()
275 .getDeclaredMethod("getAllAnnotationValues", DetailAST.class);
276 getAllAnnotationValues.setAccessible(true);
277
278 final DetailAST methodDef = new DetailAST();
279 methodDef.setType(TokenTypes.METHOD_DEF);
280 methodDef.setText("Method Def");
281 methodDef.setLineNo(0);
282 methodDef.setColumnNo(0);
283
284 final DetailAST lparen = new DetailAST();
285 lparen.setType(TokenTypes.LPAREN);
286
287 final DetailAST parent = new DetailAST();
288 parent.addChild(lparen);
289 parent.addChild(methodDef);
290
291 try {
292 getAllAnnotationValues.invoke(holder, parent);
293 fail("Exception expected");
294 }
295 catch (InvocationTargetException ex) {
296 assertTrue("Error type is unexpected",
297 ex.getCause() instanceof IllegalArgumentException);
298 assertEquals("Error message is unexpected",
299 "Unexpected AST: Method Def[0x0]", ex.getCause().getMessage());
300 }
301 }
302
303 @Test
304 public void testGetAnnotationValuesWrongArg() throws ReflectiveOperationException {
305 final SuppressWarningsHolder holder = new SuppressWarningsHolder();
306 final Method getAllAnnotationValues = holder.getClass()
307 .getDeclaredMethod("getAnnotationValues", DetailAST.class);
308 getAllAnnotationValues.setAccessible(true);
309
310 final DetailAST methodDef = new DetailAST();
311 methodDef.setType(TokenTypes.METHOD_DEF);
312 methodDef.setText("Method Def");
313 methodDef.setLineNo(0);
314 methodDef.setColumnNo(0);
315
316 try {
317 getAllAnnotationValues.invoke(holder, methodDef);
318 fail("Exception expected");
319 }
320 catch (InvocationTargetException ex) {
321 assertTrue("Error type is unexpected",
322 ex.getCause() instanceof IllegalArgumentException);
323 assertEquals("Error message is unexpected",
324 "Expression or annotation array"
325 + " initializer AST expected: Method Def[0x0]", ex.getCause().getMessage());
326 }
327 }
328
329 @Test
330 public void testGetAnnotationTargetWrongArg() throws ReflectiveOperationException {
331 final SuppressWarningsHolder holder = new SuppressWarningsHolder();
332 final Method getAnnotationTarget = holder.getClass()
333 .getDeclaredMethod("getAnnotationTarget", DetailAST.class);
334 getAnnotationTarget.setAccessible(true);
335
336 final DetailAST methodDef = new DetailAST();
337 methodDef.setType(TokenTypes.METHOD_DEF);
338 methodDef.setText("Method Def");
339
340 final DetailAST parent = new DetailAST();
341 parent.setType(TokenTypes.ASSIGN);
342 parent.setText("Parent ast");
343 parent.addChild(methodDef);
344 parent.setLineNo(0);
345 parent.setColumnNo(0);
346
347 try {
348 getAnnotationTarget.invoke(holder, methodDef);
349 fail("Exception expected");
350 }
351 catch (InvocationTargetException ex) {
352 assertTrue("Error type is unexpected",
353 ex.getCause() instanceof IllegalArgumentException);
354 assertEquals("Error message is unexpected",
355 "Unexpected container AST: Parent ast[0x0]", ex.getCause().getMessage());
356 }
357 }
358
359 @Test
360 public void testAstWithoutChildren() {
361 final SuppressWarningsHolder holder = new SuppressWarningsHolder();
362 final DetailAST methodDef = new DetailAST();
363 methodDef.setType(TokenTypes.METHOD_DEF);
364
365 try {
366 holder.visitToken(methodDef);
367 fail("Exception expected");
368 }
369 catch (IllegalArgumentException ex) {
370 assertEquals("Error message is unexpected",
371 "Identifier AST expected, but get null.", ex.getMessage());
372 }
373 }
374
375 @Test
376 public void testAnnotationWithFullName() throws Exception {
377 final Configuration checkConfig = createModuleConfig(SuppressWarningsHolder.class);
378
379 final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
380
381 verify(checkConfig, getPath("InputSuppressWarningsHolder4.java"), expected);
382 }
383
384 @Test
385 @SuppressWarnings("unchecked")
386 public void testClearState() throws Exception {
387 final SuppressWarningsHolder check = new SuppressWarningsHolder();
388
389 final Optional<DetailAST> annotationDef = TestUtil.findTokenInAstByPredicate(
390 JavaParser.parseFile(
391 new File(getPath("InputSuppressWarningsHolder.java")),
392 JavaParser.Options.WITHOUT_COMMENTS),
393 ast -> ast.getType() == TokenTypes.ANNOTATION);
394
395 assertTrue("Ast should contain ANNOTATION", annotationDef.isPresent());
396 assertTrue("State is not cleared on beginTree",
397 TestUtil.isStatefulFieldClearedDuringBeginTree(check, annotationDef.get(),
398 "ENTRIES",
399 entries -> ((ThreadLocal<List<Object>>) entries).get().isEmpty()));
400 }
401
402 private static void populateHolder(String checkName, int firstLine,
403 int firstColumn, int lastLine,
404 int lastColumn) throws Exception {
405 final Class<?> entry = Class
406 .forName("com.puppycrawl.tools.checkstyle.checks.SuppressWarningsHolder$Entry");
407 final Constructor<?> entryConstr = entry.getDeclaredConstructor(String.class, int.class,
408 int.class, int.class, int.class);
409 entryConstr.setAccessible(true);
410
411 final Object entryInstance = entryConstr.newInstance(checkName, firstLine,
412 firstColumn, lastLine, lastColumn);
413
414 final ThreadLocal<List<Object>> entries = Whitebox
415 .getInternalState(SuppressWarningsHolder.class, "ENTRIES");
416 entries.get().add(entryInstance);
417 }
418
419 private static AuditEvent createAuditEvent(String moduleId, int line, int column) {
420 final Checker source = new Checker();
421 final LocalizedMessage message = new LocalizedMessage(line, column, null, null, null,
422 moduleId, MemberNameCheck.class, "message");
423 return new AuditEvent(source, "filename", message);
424 }
425
426 }