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.imports;
21
22 import static com.google.common.truth.Truth.assertWithMessage;
23 import static com.puppycrawl.tools.checkstyle.checks.imports.UnusedImportsCheck.MSG_KEY;
24 import static com.puppycrawl.tools.checkstyle.checks.javadoc.AbstractJavadocCheck.MSG_KEY_UNCLOSED_HTML_TAG;
25
26 import java.io.File;
27 import java.util.Arrays;
28 import java.util.List;
29
30 import org.junit.jupiter.api.Test;
31
32 import com.google.common.collect.ImmutableMap;
33 import com.puppycrawl.tools.checkstyle.AbstractModuleTestSupport;
34 import com.puppycrawl.tools.checkstyle.DefaultConfiguration;
35 import com.puppycrawl.tools.checkstyle.DetailAstImpl;
36 import com.puppycrawl.tools.checkstyle.api.JavadocCommentsTokenTypes;
37 import com.puppycrawl.tools.checkstyle.api.TokenTypes;
38 import com.puppycrawl.tools.checkstyle.checks.javadoc.JavadocNodeImpl;
39 import com.puppycrawl.tools.checkstyle.utils.CommonUtil;
40
41 public class UnusedImportsCheckTest extends AbstractModuleTestSupport {
42
43 @Override
44 public String getPackageLocation() {
45 return "com/puppycrawl/tools/checkstyle/checks/imports/unusedimports";
46 }
47
48 @Test
49 public void testReferencedStateIsCleared() throws Exception {
50 final DefaultConfiguration checkConfig = createModuleConfig(UnusedImportsCheck.class);
51 final String inputWithoutWarnings = getPath("InputUnusedImportsWithoutWarnings.java");
52 final String inputWithWarnings = getPath("InputUnusedImportsCheckClearState.java");
53 final List<String> expectedFirstInput = Arrays.asList(CommonUtil.EMPTY_STRING_ARRAY);
54 final List<String> expectedSecondInput = Arrays.asList(
55 "10:8: " + getCheckMessage(MSG_KEY, "java.util.Arrays"),
56 "11:8: " + getCheckMessage(MSG_KEY, "java.util.List"),
57 "12:8: " + getCheckMessage(MSG_KEY, "java.util.Set")
58 );
59 final File[] inputsWithWarningsFirst =
60 {new File(inputWithWarnings), new File(inputWithoutWarnings)};
61 final File[] inputsWithoutWarningFirst =
62 {new File(inputWithoutWarnings), new File(inputWithWarnings)};
63
64 verify(createChecker(checkConfig), inputsWithWarningsFirst, ImmutableMap.of(
65 inputWithoutWarnings, expectedFirstInput,
66 inputWithWarnings, expectedSecondInput));
67 verify(createChecker(checkConfig), inputsWithoutWarningFirst, ImmutableMap.of(
68 inputWithoutWarnings, expectedFirstInput,
69 inputWithWarnings, expectedSecondInput));
70 }
71
72 @Test
73 public void testWithoutProcessJavadoc() throws Exception {
74 final String[] expected = {
75 "11:8: " + getCheckMessage(MSG_KEY,
76 "com.google.errorprone.annotations."
77 + "concurrent.GuardedBy"),
78 "15:8: " + getCheckMessage(MSG_KEY, "java.lang.String"),
79 "17:8: " + getCheckMessage(MSG_KEY, "java.util.List"),
80 "18:8: " + getCheckMessage(MSG_KEY, "java.util.List"),
81 "21:8: " + getCheckMessage(MSG_KEY, "java.util.Enumeration"),
82 "24:8: " + getCheckMessage(MSG_KEY, "javax.swing.JToggleButton"),
83 "26:8: " + getCheckMessage(MSG_KEY, "javax.swing.BorderFactory"),
84 "31:15: " + getCheckMessage(MSG_KEY, "java.io.File.createTempFile"),
85
86 "34:8: " + getCheckMessage(MSG_KEY, "java.awt.Graphics2D"),
87 "35:8: " + getCheckMessage(MSG_KEY, "java.awt.HeadlessException"),
88 "36:8: " + getCheckMessage(MSG_KEY, "java.awt.Label"),
89 "37:8: " + getCheckMessage(MSG_KEY, "java.util.Date"),
90 "38:8: " + getCheckMessage(MSG_KEY, "java.util.Calendar"),
91 "39:8: " + getCheckMessage(MSG_KEY, "java.util.BitSet"),
92 "41:8: " + getCheckMessage(MSG_KEY, "com.google.errorprone."
93 + "annotations.CheckReturnValue"),
94 "42:8: " + getCheckMessage(MSG_KEY, "com.google.errorprone."
95 + "annotations.CanIgnoreReturnValue"),
96 "43:8: " + getCheckMessage(MSG_KEY, "com.google.errorprone."
97 + "annotations.CompatibleWith"),
98 "44:8: " + getCheckMessage(MSG_KEY,
99 "com.google.errorprone.annotations.concurrent."
100 + "LazyInit"),
101 "45:8: " + getCheckMessage(MSG_KEY,
102 "com.google.errorprone.annotations.DoNotCall"),
103 "46:8: " + getCheckMessage(MSG_KEY,
104 "com.google.errorprone.annotations.CompileTimeConstant"),
105 "47:8: " + getCheckMessage(MSG_KEY,
106 "com.google.errorprone.annotations.FormatMethod"),
107 "48:8: " + getCheckMessage(MSG_KEY, "com.google.errorprone.annotations.FormatString"),
108 };
109 verifyWithInlineConfigParser(
110 getPath("InputUnusedImports2.java"), expected);
111 }
112
113 @Test
114 public void testProcessJavadoc() throws Exception {
115 final String[] expected = {
116 "11:8: " + getCheckMessage(MSG_KEY,
117 "com.google.errorprone.annotations."
118 + "concurrent.GuardedBy"),
119 "15:8: " + getCheckMessage(MSG_KEY, "java.lang.String"),
120 "17:8: " + getCheckMessage(MSG_KEY, "java.util.List"),
121 "18:8: " + getCheckMessage(MSG_KEY, "java.util.List"),
122 "21:8: " + getCheckMessage(MSG_KEY, "java.util.Enumeration"),
123 "24:8: " + getCheckMessage(MSG_KEY, "javax.swing.JToggleButton"),
124 "26:8: " + getCheckMessage(MSG_KEY, "javax.swing.BorderFactory"),
125 "31:15: " + getCheckMessage(MSG_KEY, "java.io.File.createTempFile"),
126
127 "36:8: " + getCheckMessage(MSG_KEY, "java.awt.Label"),
128 "48:8: " + getCheckMessage(MSG_KEY, "com.google.errorprone.annotations.ForOverride"),
129 };
130 verifyWithInlineConfigParser(
131 getPath("InputUnusedImports.java"), expected);
132 }
133
134 @Test
135 public void testProcessJavadocWithLinkTag() throws Exception {
136 final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
137 verifyWithInlineConfigParser(
138 getPath("InputUnusedImportsWithValueTag.java"), expected);
139 }
140
141 @Test
142 public void testProcessJavadocWithBlockTagContainingMethodParameters() throws Exception {
143 final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
144 verifyWithInlineConfigParser(
145 getPath("InputUnusedImportsWithBlockMethodParameters.java"), expected);
146 }
147
148 @Test
149 public void testProcessJavadocWithLinkAndGenericMethodParameters() throws Exception {
150 final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
151 verifyWithInlineConfigParser(
152 getPath("InputUnusedImportsWithLinkAndGenericMethodParameters.java"), expected);
153 }
154
155 @Test
156 public void testProcessJavadocWithLinkAndGenericMethodParametersWithInnerTypes()
157 throws Exception {
158 final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
159 verifyWithInlineConfigParser(
160 getPath("InputUnusedImportsWithLinkAndGenericMethodParameters2.java"), expected);
161 }
162
163 @Test
164 public void testProcessJavadocWithLinkAndGenericMethodParametersWithInnerTypesOnly()
165 throws Exception {
166 final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
167 verifyWithInlineConfigParser(
168 getPath("InputUnusedImportsWithLinkAndGenericMethodParameters3.java"), expected);
169 }
170
171 @Test
172 public void testProcessJavadocWithLinkAndGenericMethodParametersMultipleArgs()
173 throws Exception {
174 final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
175 verifyWithInlineConfigParser(
176 getPath("InputUnusedImportsWithLinkAndGenericMethodParameters4.java"), expected);
177 }
178
179 @Test
180 public void testSeeTagWithParameterNames() throws Exception {
181 final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
182 verifyWithInlineConfigParser(
183 getPath("InputUnusedImportsWithSeeTagAndParameterNames.java"), expected);
184 }
185
186 @Test
187 public void testAnnotations() throws Exception {
188 final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
189 verifyWithInlineConfigParser(
190 getNonCompilablePath("InputUnusedImportsAnnotations.java"), expected);
191 }
192
193 @Test
194 public void testArrayRef() throws Exception {
195 final String[] expected = {
196 "13:8: " + getCheckMessage(MSG_KEY, "java.util.ArrayList"),
197 };
198 verifyWithInlineConfigParser(
199 getPath("InputUnusedImportsArrayRef.java"), expected);
200 }
201
202 @Test
203 public void testBug() throws Exception {
204 final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
205 verifyWithInlineConfigParser(
206 getPath("InputUnusedImportsBug.java"), expected);
207 }
208
209 @Test
210 public void testNewlinesInsideTags() throws Exception {
211 final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
212 verifyWithInlineConfigParser(
213 getPath("InputUnusedImportsWithNewlinesInsideTags.java"), expected);
214 }
215
216 @Test
217 public void testGetRequiredTokens() {
218 final UnusedImportsCheck testCheckObject =
219 new UnusedImportsCheck();
220 final int[] actual = testCheckObject.getRequiredTokens();
221 final int[] expected = {
222 TokenTypes.IDENT,
223 TokenTypes.IMPORT,
224 TokenTypes.STATIC_IMPORT,
225 TokenTypes.OBJBLOCK,
226 TokenTypes.SLIST,
227 TokenTypes.BLOCK_COMMENT_BEGIN,
228 };
229
230 assertWithMessage("Default required tokens are invalid")
231 .that(actual)
232 .isEqualTo(expected);
233 }
234
235 @Test
236 public void testGetAcceptableTokens() {
237 final UnusedImportsCheck testCheckObject =
238 new UnusedImportsCheck();
239 final int[] actual = testCheckObject.getAcceptableTokens();
240 final int[] expected = {
241 TokenTypes.IDENT,
242 TokenTypes.IMPORT,
243 TokenTypes.STATIC_IMPORT,
244 TokenTypes.OBJBLOCK,
245 TokenTypes.SLIST,
246 TokenTypes.BLOCK_COMMENT_BEGIN,
247 };
248
249 assertWithMessage("Default acceptable tokens are invalid")
250 .that(actual)
251 .isEqualTo(expected);
252 }
253
254 @Test
255 public void testFileInUnnamedPackage() throws Exception {
256 final String[] expected = {
257 "12:8: " + getCheckMessage(MSG_KEY, "java.util.Arrays"),
258 "13:8: " + getCheckMessage(MSG_KEY, "java.lang.String"),
259 };
260 verifyWithInlineConfigParser(
261 getNonCompilablePath("InputUnusedImportsFileInUnnamedPackage.java"),
262 expected);
263 }
264
265 @Test
266 public void testImportsFromJavaLang() throws Exception {
267 final String[] expected = {
268 "10:8: " + getCheckMessage(MSG_KEY, "java.lang.String"),
269 "11:8: " + getCheckMessage(MSG_KEY, "java.lang.Math"),
270 "12:8: " + getCheckMessage(MSG_KEY, "java.lang.Class"),
271 "13:8: " + getCheckMessage(MSG_KEY, "java.lang.Exception"),
272 "14:8: " + getCheckMessage(MSG_KEY, "java.lang.Runnable"),
273 "15:8: " + getCheckMessage(MSG_KEY, "java.lang.RuntimeException"),
274 "16:8: " + getCheckMessage(MSG_KEY, "java.lang.ProcessBuilder"),
275 "17:8: " + getCheckMessage(MSG_KEY, "java.lang.Double"),
276 "18:8: " + getCheckMessage(MSG_KEY, "java.lang.Integer"),
277 "19:8: " + getCheckMessage(MSG_KEY, "java.lang.Float"),
278 "20:8: " + getCheckMessage(MSG_KEY, "java.lang.Short"),
279 };
280 verifyWithInlineConfigParser(
281 getPath("InputUnusedImportsFromJavaLang.java"), expected);
282 }
283
284 @Test
285 public void testImportsJavadocQualifiedName() throws Exception {
286 final String[] expected = {
287 "11:8: " + getCheckMessage(MSG_KEY, "java.util.List"),
288 };
289 verifyWithInlineConfigParser(
290 getPath("InputUnusedImportsJavadocQualifiedName.java"), expected);
291 }
292
293 @Test
294 public void testSingleWordPackage() throws Exception {
295 final String[] expected = {
296 "10:8: " + getCheckMessage(MSG_KEY, "module"),
297 "11:15: " + getCheckMessage(MSG_KEY, "module2"),
298 };
299 verifyWithInlineConfigParser(
300 getNonCompilablePath("InputUnusedImportsSingleWordPackage.java"),
301 expected);
302 }
303
304 @Test
305 public void testRecordsAndCompactCtors() throws Exception {
306 final String[] expected = {
307 "19:8: " + getCheckMessage(MSG_KEY, "javax.swing.JToolBar"),
308 "20:8: " + getCheckMessage(MSG_KEY, "javax.swing.JToggleButton"),
309 };
310 verifyWithInlineConfigParser(
311 getPath("InputUnusedImportsRecordsAndCompactCtors.java"),
312 expected);
313 }
314
315 @Test
316 public void testShadowedImports() throws Exception {
317 final String[] expected = {
318 "12:8: " + getCheckMessage(MSG_KEY, "java.util.Map"),
319 "13:8: " + getCheckMessage(MSG_KEY, "java.util.Set"),
320 "16:8: " + getCheckMessage(MSG_KEY, "com.puppycrawl.tools.checkstyle.checks.imports."
321 + "unusedimports.InputUnusedImportsShadowed"),
322 };
323 verifyWithInlineConfigParser(
324 getPath("InputUnusedImportsShadowed.java"), expected);
325 }
326
327 @Test
328 public void testUnusedImports3() throws Exception {
329 final String[] expected = {
330 "11:8: " + getCheckMessage(MSG_KEY, "java.awt.Rectangle"),
331 "13:8: " + getCheckMessage(MSG_KEY, "java.awt.event.KeyEvent"),
332 };
333 verifyWithInlineConfigParser(
334 getPath("InputUnusedImports3.java"), expected);
335 }
336
337 @Test
338 public void testStateIsClearedOnBeginTreeCollect() throws Exception {
339 final String file1 = getPath(
340 "InputUnusedImportsRecordsAndCompactCtors.java");
341 final String file2 = getNonCompilablePath(
342 "InputUnusedImportsSingleWordPackage.java");
343 final List<String> expectedFirstInput = List.of(
344 "19:8: " + getCheckMessage(MSG_KEY, "javax.swing.JToolBar"),
345 "20:8: " + getCheckMessage(MSG_KEY, "javax.swing.JToggleButton")
346 );
347 final List<String> expectedSecondInput = List.of(
348 "10:8: " + getCheckMessage(MSG_KEY, "module"),
349 "11:15: " + getCheckMessage(MSG_KEY, "module2")
350 );
351 verifyWithInlineConfigParser(file1, file2, expectedFirstInput, expectedSecondInput);
352 }
353
354 @Test
355 public void testStaticMethodRefImports() throws Exception {
356 final String[] expected = {
357 "26:15: " + getCheckMessage(MSG_KEY, "java.lang.String.format"),
358 "27:15: " + getCheckMessage(MSG_KEY, "java.util.Arrays.sort"),
359 "28:15: " + getCheckMessage(MSG_KEY, "java.util.List.of"),
360 "29:15: " + getCheckMessage(MSG_KEY, "java.util.Collections.emptyMap"),
361 };
362 verifyWithInlineConfigParser(
363 getPath("InputUnusedImportsFromStaticMethodRef.java"), expected);
364 }
365
366 @Test
367 public void testStaticMethodRefImportsExtended() throws Exception {
368 final String[] expected = {
369 "17:8: " + getCheckMessage(MSG_KEY, "java.util.Objects"),
370 "18:15: " + getCheckMessage(MSG_KEY, "java.util.Arrays.toString"),
371 "19:15: " + getCheckMessage(MSG_KEY, "java.util.Arrays.asList"),
372 "20:15: " + getCheckMessage(MSG_KEY, "java.lang.Integer.parseInt"),
373 "21:15: " + getCheckMessage(MSG_KEY, "java.util.Collections.emptyList"),
374 };
375 verifyWithInlineConfigParser(
376 getPath("InputUnusedImportsFromStaticMethodRefExtended.java"), expected);
377 }
378
379 @Test
380 public void testStaticMethodRefImportsWithJavadocDisabled() throws Exception {
381 final String[] expected = {
382 "24:8: " + getCheckMessage(MSG_KEY, "java.util.Arrays"),
383 "25:15: " + getCheckMessage(MSG_KEY, "java.lang.Integer.parseInt"),
384 "26:15: " + getCheckMessage(MSG_KEY, "java.lang.String.format"),
385 "27:15: " + getCheckMessage(MSG_KEY, "java.util.List.of"),
386 "28:15: " + getCheckMessage(MSG_KEY, "java.util.Collections.emptyMap"),
387 };
388 verifyWithInlineConfigParser(
389 getPath("InputUnusedImportsFromStaticMethodRefJavadocDisabled.java"), expected);
390 }
391
392 @Test
393 public void testStaticMethodRefImportsWithJavadocErrorAndJavadocDisabled() throws Exception {
394 final String[] expected = {
395 "10:8: " + getCheckMessage(MSG_KEY, "java.util.Arrays"),
396 "11:15: " + getCheckMessage(MSG_KEY, "java.lang.Integer.parseInt"),
397 };
398 verifyWithInlineConfigParser(
399 getJavadocWithErrorPath(
400 "InputUnusedImportsFromStaticMethodRefJavadocDisabled.java"),
401 expected);
402 }
403
404 @Test
405 public void testUnusedImportsJavadocAboveComments() throws Exception {
406 final String[] expected = {
407 "11:8: " + getCheckMessage(MSG_KEY, "java.util.List"),
408 };
409 verifyWithInlineConfigParser(
410 getPath("InputUnusedImportsJavadocAboveComments.java"), expected);
411 }
412
413 @Test
414 public void testImportJavaLinkTag() throws Exception {
415 final String[] expected = {
416 "10:8: " + getCheckMessage(MSG_KEY, "java.util.List"),
417 "12:8: " + getCheckMessage(MSG_KEY, "java.util.TreeSet"),
418
419 };
420 verifyWithInlineConfigParser(
421 getPath("InputUnusedImportsWithLinkTag.java"), expected);
422
423 }
424
425 @Test
426 public void testImportJavaLinkTagWithMethod() throws Exception {
427 final String[] expected = {
428 "15:8: " + getCheckMessage(MSG_KEY, "java.util.Set"),
429 "23:8: " + getCheckMessage(MSG_KEY, "java.util.concurrent.TimeUnit"),
430 };
431 verifyWithInlineConfigParser(
432 getPath("InputUnusedImportsWithLinkAndMethodTag.java"), expected);
433
434 }
435
436 @Test
437 public void testJavadocSetters() throws Exception {
438 final String[] expected = {
439 "14: " + getCheckMessage(MSG_KEY_UNCLOSED_HTML_TAG, "p"),
440 };
441 verifyWithInlineConfigParser(
442 getPath("InputUnusedImportsJavadocSetters.java"), expected);
443
444 }
445
446 @Test
447 public void testCache() throws Exception {
448 final String[] expected = {
449 "10:8: " + getCheckMessage(MSG_KEY, "java.util.TreeSet"),
450 };
451 verifyWithInlineConfigParser(getPath("InputUnusedImportsCache1.java"),
452 getPath("InputUnusedImportsCache2.java"), expected);
453 }
454
455
456
457
458
459
460
461
462 @Test
463 public void testImproperToken() {
464 final UnusedImportsCheck check = new UnusedImportsCheck();
465
466 final DetailAstImpl lambdaAst = new DetailAstImpl();
467 lambdaAst.setType(TokenTypes.LAMBDA);
468 lambdaAst.setText("LAMBDA");
469
470 try {
471 check.visitToken(lambdaAst);
472 assertWithMessage("IllegalArgumentException is expected").fail();
473 }
474 catch (IllegalArgumentException exc) {
475 assertWithMessage("Message must include token name")
476 .that(exc.getMessage())
477 .contains("LAMBDA");
478 }
479 }
480
481
482
483
484
485
486
487 @Test
488 public void testImproperJavadocToken() {
489 final UnusedImportsCheck check = new UnusedImportsCheck();
490
491 final JavadocNodeImpl ast = new JavadocNodeImpl();
492 ast.setType(JavadocCommentsTokenTypes.EQUALS);
493 ast.setText("EQUALS");
494
495 try {
496 check.visitJavadocToken(ast);
497 assertWithMessage("IllegalArgumentException is expected").fail();
498 }
499 catch (IllegalArgumentException exc) {
500 assertWithMessage("Message must include token name")
501 .that(exc.getMessage())
502 .contains("EQUALS");
503 }
504 }
505
506 }