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 testAnnotations() throws Exception {
150 final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
151 verifyWithInlineConfigParser(
152 getNonCompilablePath("InputUnusedImportsAnnotations.java"), expected);
153 }
154
155 @Test
156 public void testArrayRef() throws Exception {
157 final String[] expected = {
158 "13:8: " + getCheckMessage(MSG_KEY, "java.util.ArrayList"),
159 };
160 verifyWithInlineConfigParser(
161 getPath("InputUnusedImportsArrayRef.java"), expected);
162 }
163
164 @Test
165 public void testBug() throws Exception {
166 final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
167 verifyWithInlineConfigParser(
168 getPath("InputUnusedImportsBug.java"), expected);
169 }
170
171 @Test
172 public void testNewlinesInsideTags() throws Exception {
173 final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
174 verifyWithInlineConfigParser(
175 getPath("InputUnusedImportsWithNewlinesInsideTags.java"), expected);
176 }
177
178 @Test
179 public void testGetRequiredTokens() {
180 final UnusedImportsCheck testCheckObject =
181 new UnusedImportsCheck();
182 final int[] actual = testCheckObject.getRequiredTokens();
183 final int[] expected = {
184 TokenTypes.IDENT,
185 TokenTypes.IMPORT,
186 TokenTypes.STATIC_IMPORT,
187 TokenTypes.OBJBLOCK,
188 TokenTypes.SLIST,
189 TokenTypes.BLOCK_COMMENT_BEGIN,
190 };
191
192 assertWithMessage("Default required tokens are invalid")
193 .that(actual)
194 .isEqualTo(expected);
195 }
196
197 @Test
198 public void testGetAcceptableTokens() {
199 final UnusedImportsCheck testCheckObject =
200 new UnusedImportsCheck();
201 final int[] actual = testCheckObject.getAcceptableTokens();
202 final int[] expected = {
203 TokenTypes.IDENT,
204 TokenTypes.IMPORT,
205 TokenTypes.STATIC_IMPORT,
206 TokenTypes.OBJBLOCK,
207 TokenTypes.SLIST,
208 TokenTypes.BLOCK_COMMENT_BEGIN,
209 };
210
211 assertWithMessage("Default acceptable tokens are invalid")
212 .that(actual)
213 .isEqualTo(expected);
214 }
215
216 @Test
217 public void testFileInUnnamedPackage() throws Exception {
218 final String[] expected = {
219 "12:8: " + getCheckMessage(MSG_KEY, "java.util.Arrays"),
220 "13:8: " + getCheckMessage(MSG_KEY, "java.lang.String"),
221 };
222 verifyWithInlineConfigParser(
223 getNonCompilablePath("InputUnusedImportsFileInUnnamedPackage.java"),
224 expected);
225 }
226
227 @Test
228 public void testImportsFromJavaLang() throws Exception {
229 final String[] expected = {
230 "10:8: " + getCheckMessage(MSG_KEY, "java.lang.String"),
231 "11:8: " + getCheckMessage(MSG_KEY, "java.lang.Math"),
232 "12:8: " + getCheckMessage(MSG_KEY, "java.lang.Class"),
233 "13:8: " + getCheckMessage(MSG_KEY, "java.lang.Exception"),
234 "14:8: " + getCheckMessage(MSG_KEY, "java.lang.Runnable"),
235 "15:8: " + getCheckMessage(MSG_KEY, "java.lang.RuntimeException"),
236 "16:8: " + getCheckMessage(MSG_KEY, "java.lang.ProcessBuilder"),
237 "17:8: " + getCheckMessage(MSG_KEY, "java.lang.Double"),
238 "18:8: " + getCheckMessage(MSG_KEY, "java.lang.Integer"),
239 "19:8: " + getCheckMessage(MSG_KEY, "java.lang.Float"),
240 "20:8: " + getCheckMessage(MSG_KEY, "java.lang.Short"),
241 };
242 verifyWithInlineConfigParser(
243 getPath("InputUnusedImportsFromJavaLang.java"), expected);
244 }
245
246 @Test
247 public void testImportsJavadocQualifiedName() throws Exception {
248 final String[] expected = {
249 "11:8: " + getCheckMessage(MSG_KEY, "java.util.List"),
250 };
251 verifyWithInlineConfigParser(
252 getPath("InputUnusedImportsJavadocQualifiedName.java"), expected);
253 }
254
255 @Test
256 public void testSingleWordPackage() throws Exception {
257 final String[] expected = {
258 "10:8: " + getCheckMessage(MSG_KEY, "module"),
259 "11:15: " + getCheckMessage(MSG_KEY, "module2"),
260 };
261 verifyWithInlineConfigParser(
262 getNonCompilablePath("InputUnusedImportsSingleWordPackage.java"),
263 expected);
264 }
265
266 @Test
267 public void testRecordsAndCompactCtors() throws Exception {
268 final String[] expected = {
269 "19:8: " + getCheckMessage(MSG_KEY, "javax.swing.JToolBar"),
270 "20:8: " + getCheckMessage(MSG_KEY, "javax.swing.JToggleButton"),
271 };
272 verifyWithInlineConfigParser(
273 getPath("InputUnusedImportsRecordsAndCompactCtors.java"),
274 expected);
275 }
276
277 @Test
278 public void testShadowedImports() throws Exception {
279 final String[] expected = {
280 "12:8: " + getCheckMessage(MSG_KEY, "java.util.Map"),
281 "13:8: " + getCheckMessage(MSG_KEY, "java.util.Set"),
282 "16:8: " + getCheckMessage(MSG_KEY, "com.puppycrawl.tools.checkstyle.checks.imports."
283 + "unusedimports.InputUnusedImportsShadowed"),
284 };
285 verifyWithInlineConfigParser(
286 getPath("InputUnusedImportsShadowed.java"), expected);
287 }
288
289 @Test
290 public void testUnusedImports3() throws Exception {
291 final String[] expected = {
292 "11:8: " + getCheckMessage(MSG_KEY, "java.awt.Rectangle"),
293 "13:8: " + getCheckMessage(MSG_KEY, "java.awt.event.KeyEvent"),
294 };
295 verifyWithInlineConfigParser(
296 getPath("InputUnusedImports3.java"), expected);
297 }
298
299 @Test
300 public void testStateIsClearedOnBeginTreeCollect() throws Exception {
301 final String file1 = getPath(
302 "InputUnusedImportsRecordsAndCompactCtors.java");
303 final String file2 = getNonCompilablePath(
304 "InputUnusedImportsSingleWordPackage.java");
305 final List<String> expectedFirstInput = List.of(
306 "19:8: " + getCheckMessage(MSG_KEY, "javax.swing.JToolBar"),
307 "20:8: " + getCheckMessage(MSG_KEY, "javax.swing.JToggleButton")
308 );
309 final List<String> expectedSecondInput = List.of(
310 "10:8: " + getCheckMessage(MSG_KEY, "module"),
311 "11:15: " + getCheckMessage(MSG_KEY, "module2")
312 );
313 verifyWithInlineConfigParser(file1, file2, expectedFirstInput, expectedSecondInput);
314 }
315
316 @Test
317 public void testStaticMethodRefImports() throws Exception {
318 final String[] expected = {
319 "26:15: " + getCheckMessage(MSG_KEY, "java.lang.String.format"),
320 "27:15: " + getCheckMessage(MSG_KEY, "java.util.Arrays.sort"),
321 "28:15: " + getCheckMessage(MSG_KEY, "java.util.List.of"),
322 "29:15: " + getCheckMessage(MSG_KEY, "java.util.Collections.emptyMap"),
323 };
324 verifyWithInlineConfigParser(
325 getPath("InputUnusedImportsFromStaticMethodRef.java"), expected);
326 }
327
328 @Test
329 public void testStaticMethodRefImportsExtended() throws Exception {
330 final String[] expected = {
331 "17:8: " + getCheckMessage(MSG_KEY, "java.util.Objects"),
332 "18:15: " + getCheckMessage(MSG_KEY, "java.util.Arrays.toString"),
333 "19:15: " + getCheckMessage(MSG_KEY, "java.util.Arrays.asList"),
334 "20:15: " + getCheckMessage(MSG_KEY, "java.lang.Integer.parseInt"),
335 "21:15: " + getCheckMessage(MSG_KEY, "java.util.Collections.emptyList"),
336 };
337 verifyWithInlineConfigParser(
338 getPath("InputUnusedImportsFromStaticMethodRefExtended.java"), expected);
339 }
340
341 @Test
342 public void testStaticMethodRefImportsWithJavadocDisabled() throws Exception {
343 final String[] expected = {
344 "24:8: " + getCheckMessage(MSG_KEY, "java.util.Arrays"),
345 "25:15: " + getCheckMessage(MSG_KEY, "java.lang.Integer.parseInt"),
346 "26:15: " + getCheckMessage(MSG_KEY, "java.lang.String.format"),
347 "27:15: " + getCheckMessage(MSG_KEY, "java.util.List.of"),
348 "28:15: " + getCheckMessage(MSG_KEY, "java.util.Collections.emptyMap"),
349 };
350 verifyWithInlineConfigParser(
351 getPath("InputUnusedImportsFromStaticMethodRefJavadocDisabled.java"), expected);
352 }
353
354 @Test
355 public void testUnusedImportsJavadocAboveComments() throws Exception {
356 final String[] expected = {
357 "11:8: " + getCheckMessage(MSG_KEY, "java.util.List"),
358 };
359 verifyWithInlineConfigParser(
360 getPath("InputUnusedImportsJavadocAboveComments.java"), expected);
361 }
362
363 @Test
364 public void testImportJavaLinkTag() throws Exception {
365 final String[] expected = {
366 "10:8: " + getCheckMessage(MSG_KEY, "java.util.List"),
367 "12:8: " + getCheckMessage(MSG_KEY, "java.util.TreeSet"),
368
369 };
370 verifyWithInlineConfigParser(
371 getPath("InputUnusedImportsWithLinkTag.java"), expected);
372
373 }
374
375 @Test
376 public void testImportJavaLinkTagWithMethod() throws Exception {
377 final String[] expected = {
378 "15:8: " + getCheckMessage(MSG_KEY, "java.util.Set"),
379 "23:8: " + getCheckMessage(MSG_KEY, "java.util.concurrent.TimeUnit"),
380 };
381 verifyWithInlineConfigParser(
382 getPath("InputUnusedImportsWithLinkAndMethodTag.java"), expected);
383
384 }
385
386 @Test
387 public void testJavadocSetters() throws Exception {
388 final String[] expected = {
389 "14: " + getCheckMessage(MSG_KEY_UNCLOSED_HTML_TAG, "p"),
390 };
391 verifyWithInlineConfigParser(
392 getPath("InputUnusedImportsJavadocSetters.java"), expected);
393
394 }
395
396 @Test
397 public void testCache() throws Exception {
398 final String[] expected = {
399 "10:8: " + getCheckMessage(MSG_KEY, "java.util.TreeSet"),
400 };
401 verifyWithInlineConfigParser(getPath("InputUnusedImportsCache1.java"),
402 getPath("InputUnusedImportsCache2.java"), expected);
403 }
404
405
406
407
408
409
410
411
412 @Test
413 public void testImproperToken() {
414 final UnusedImportsCheck check = new UnusedImportsCheck();
415
416 final DetailAstImpl lambdaAst = new DetailAstImpl();
417 lambdaAst.setType(TokenTypes.LAMBDA);
418 lambdaAst.setText("LAMBDA");
419
420 try {
421 check.visitToken(lambdaAst);
422 assertWithMessage("IllegalArgumentException is expected").fail();
423 }
424 catch (IllegalArgumentException exc) {
425 assertWithMessage("Message must include token name")
426 .that(exc.getMessage())
427 .contains("LAMBDA");
428 }
429 }
430
431
432
433
434
435
436
437 @Test
438 public void testImproperJavadocToken() {
439 final UnusedImportsCheck check = new UnusedImportsCheck();
440
441 final JavadocNodeImpl ast = new JavadocNodeImpl();
442 ast.setType(JavadocCommentsTokenTypes.EQUALS);
443 ast.setText("EQUALS");
444
445 try {
446 check.visitJavadocToken(ast);
447 assertWithMessage("IllegalArgumentException is expected").fail();
448 }
449 catch (IllegalArgumentException exc) {
450 assertWithMessage("Message must include token name")
451 .that(exc.getMessage())
452 .contains("EQUALS");
453 }
454 }
455
456 }