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.utils;
21
22 import static com.google.common.truth.Truth.assertThat;
23 import static com.google.common.truth.Truth.assertWithMessage;
24 import static com.puppycrawl.tools.checkstyle.internal.utils.TestUtil.getExpectedThrowable;
25 import static com.puppycrawl.tools.checkstyle.internal.utils.TestUtil.isUtilsClassHasPrivateConstructor;
26 import static org.mockito.Mockito.CALLS_REAL_METHODS;
27 import static org.mockito.Mockito.mock;
28 import static org.mockito.Mockito.mockStatic;
29 import static org.mockito.Mockito.when;
30
31 import java.io.Closeable;
32 import java.io.File;
33 import java.io.IOException;
34 import java.lang.reflect.Constructor;
35 import java.net.URI;
36 import java.net.URISyntaxException;
37 import java.net.URL;
38 import java.nio.charset.StandardCharsets;
39 import java.util.Dictionary;
40 import java.util.Properties;
41 import java.util.regex.Pattern;
42
43 import org.apache.commons.io.IOUtils;
44 import org.junit.jupiter.api.Test;
45 import org.mockito.MockedStatic;
46
47 import com.puppycrawl.tools.checkstyle.AbstractPathTestSupport;
48 import com.puppycrawl.tools.checkstyle.ConfigurationLoader;
49 import com.puppycrawl.tools.checkstyle.PropertiesExpander;
50 import com.puppycrawl.tools.checkstyle.api.CheckstyleException;
51 import com.puppycrawl.tools.checkstyle.api.Configuration;
52
53 public class CommonUtilTest extends AbstractPathTestSupport {
54
55
56 private static final String PATH_DENORMALIZER = "/levelDown/.././";
57
58 @Override
59 public String getPackageLocation() {
60 return "com/puppycrawl/tools/checkstyle/utils/commonutil";
61 }
62
63 @Test
64 public void testIsProperUtilsClass() throws ReflectiveOperationException {
65 assertWithMessage("Constructor is not private")
66 .that(isUtilsClassHasPrivateConstructor(CommonUtil.class))
67 .isTrue();
68 }
69
70
71
72
73 @Test
74 public void testLengthExpandedTabs() {
75 final String s1 = "\t";
76 assertWithMessage("Invalid expanded tabs length")
77 .that(CommonUtil.lengthExpandedTabs(s1, s1.length(), 8))
78 .isEqualTo(8);
79
80 final String s2 = " \t";
81 assertWithMessage("Invalid expanded tabs length")
82 .that(CommonUtil.lengthExpandedTabs(s2, s2.length(), 8))
83 .isEqualTo(8);
84
85 final String s3 = "\t\t";
86 assertWithMessage("Invalid expanded tabs length")
87 .that(CommonUtil.lengthExpandedTabs(s3, s3.length(), 8))
88 .isEqualTo(16);
89
90 final String s4 = " \t ";
91 assertWithMessage("Invalid expanded tabs length")
92 .that(CommonUtil.lengthExpandedTabs(s4, s4.length(), 8))
93 .isEqualTo(9);
94
95 assertWithMessage("Invalid expanded tabs length")
96 .that(CommonUtil.lengthMinusTrailingWhitespace(""))
97 .isEqualTo(0);
98 assertWithMessage("Invalid expanded tabs length")
99 .that(CommonUtil.lengthMinusTrailingWhitespace(" \t "))
100 .isEqualTo(0);
101 assertWithMessage("Invalid expanded tabs length")
102 .that(CommonUtil.lengthMinusTrailingWhitespace(" 23"))
103 .isEqualTo(3);
104 assertWithMessage("Invalid expanded tabs length")
105 .that(CommonUtil.lengthMinusTrailingWhitespace(" 23 \t "))
106 .isEqualTo(3);
107 }
108
109 @Test
110 public void testCreatePattern() {
111 assertWithMessage("invalid pattern")
112 .that(CommonUtil.createPattern("Test").pattern())
113 .isEqualTo("Test");
114 assertWithMessage("invalid pattern")
115 .that(CommonUtil.createPattern(".*Pattern.*")
116 .pattern())
117 .isEqualTo(".*Pattern.*");
118 }
119
120 @Test
121 public void testBadRegex() {
122 final IllegalArgumentException ex =
123 getExpectedThrowable(IllegalArgumentException.class, () -> {
124 CommonUtil.createPattern("[");
125 });
126 assertWithMessage("Invalid exception message")
127 .that(ex)
128 .hasMessageThat()
129 .isEqualTo("Failed to initialise regular expression [");
130 }
131
132 @Test
133 public void testBadRegex2() {
134 final IllegalArgumentException ex =
135 getExpectedThrowable(IllegalArgumentException.class, () -> {
136 CommonUtil.createPattern("[", Pattern.MULTILINE);
137 });
138 assertWithMessage("Invalid exception message")
139 .that(ex)
140 .hasMessageThat()
141 .isEqualTo("Failed to initialise regular expression [");
142 }
143
144 @Test
145 public void testFileExtensions() {
146 final String[] fileExtensions = {"java"};
147 final File pdfFile = new File("file.pdf");
148 assertWithMessage("Invalid file extension")
149 .that(CommonUtil.matchesFileExtension(pdfFile, fileExtensions))
150 .isFalse();
151 assertWithMessage("Invalid file extension")
152 .that(CommonUtil.matchesFileExtension(pdfFile))
153 .isTrue();
154 assertWithMessage("Invalid file extension")
155 .that(CommonUtil.matchesFileExtension(pdfFile, (String[]) null))
156 .isTrue();
157 final File javaFile = new File("file.java");
158 assertWithMessage("Invalid file extension")
159 .that(CommonUtil.matchesFileExtension(javaFile, fileExtensions))
160 .isTrue();
161 final File invalidJavaFile = new File("file,java");
162 assertWithMessage("Invalid file extension")
163 .that(CommonUtil.matchesFileExtension(invalidJavaFile, fileExtensions))
164 .isFalse();
165 final File emptyExtensionFile = new File("file.");
166 assertWithMessage("Invalid file extension")
167 .that(CommonUtil.matchesFileExtension(emptyExtensionFile, ""))
168 .isTrue();
169 assertWithMessage("Invalid file extension")
170 .that(CommonUtil.matchesFileExtension(pdfFile, ".noMatch"))
171 .isFalse();
172 assertWithMessage("Invalid file extension")
173 .that(CommonUtil.matchesFileExtension(pdfFile, ".pdf"))
174 .isTrue();
175 }
176
177 @Test
178 public void testHasWhitespaceBefore() {
179 assertWithMessage("Invalid result")
180 .that(CommonUtil.hasWhitespaceBefore(0, "a"))
181 .isTrue();
182 assertWithMessage("Invalid result")
183 .that(CommonUtil.hasWhitespaceBefore(4, " a"))
184 .isTrue();
185 assertWithMessage("Invalid result")
186 .that(CommonUtil.hasWhitespaceBefore(5, " a"))
187 .isFalse();
188 }
189
190 @Test
191 public void testBaseClassNameForCanonicalName() {
192 assertWithMessage("Invalid base class name")
193 .that(CommonUtil.baseClassName("java.util.List"))
194 .isEqualTo("List");
195 }
196
197 @Test
198 public void testBaseClassNameForSimpleName() {
199 assertWithMessage("Invalid base class name")
200 .that(CommonUtil.baseClassName("Set"))
201 .isEqualTo("Set");
202 }
203
204 @Test
205 public void testRelativeNormalizedPath() {
206 final String relativePath = CommonUtil.relativizePath("/home", "/home/test");
207
208 assertWithMessage("Invalid relative path")
209 .that(relativePath)
210 .isEqualTo("test");
211 }
212
213 @Test
214 public void testRelativeNormalizedPathWithNullBaseDirectory() {
215 final String relativePath = CommonUtil.relativizePath(null, "/tmp");
216
217 assertWithMessage("Invalid relative path")
218 .that(relativePath)
219 .isEqualTo("/tmp");
220 }
221
222 @Test
223 public void testRelativeNormalizedPathWithDenormalizedBaseDirectory() throws IOException {
224 final String sampleAbsolutePath = new File("src/main/java").getCanonicalPath();
225 final String absoluteFilePath = sampleAbsolutePath + "/SampleFile.java";
226 final String basePath = sampleAbsolutePath + PATH_DENORMALIZER;
227
228 final String relativePath = CommonUtil.relativizePath(basePath,
229 absoluteFilePath);
230
231 assertWithMessage("Invalid relative path")
232 .that(relativePath)
233 .isEqualTo("SampleFile.java");
234 }
235
236 @Test
237 public void testPattern() {
238 final boolean result = CommonUtil.isPatternValid("someValidPattern");
239 assertWithMessage("Should return true when pattern is valid")
240 .that(result)
241 .isTrue();
242 }
243
244 @Test
245 public void testInvalidPattern() {
246 final boolean result = CommonUtil.isPatternValid("some[invalidPattern");
247 assertWithMessage("Should return false when pattern is invalid")
248 .that(result)
249 .isFalse();
250 }
251
252 @Test
253 public void testGetExistingConstructor() throws NoSuchMethodException {
254 final Constructor<?> constructor = CommonUtil.getConstructor(String.class, String.class);
255
256 assertWithMessage("Invalid constructor")
257 .that(constructor)
258 .isEqualTo(String.class.getConstructor(String.class));
259 }
260
261 @Test
262 public void testGetNonExistentConstructor() {
263 final IllegalStateException ex = getExpectedThrowable(IllegalStateException.class, () -> {
264 CommonUtil.getConstructor(Math.class);
265 });
266 assertWithMessage("Invalid exception cause")
267 .that(ex)
268 .hasCauseThat()
269 .isInstanceOf(NoSuchMethodException.class);
270 }
271
272 @Test
273 public void testInvokeConstructor() throws NoSuchMethodException {
274 final Constructor<String> constructor = String.class.getConstructor(String.class);
275
276 final String constructedString = CommonUtil.invokeConstructor(constructor, "string");
277
278 assertWithMessage("Invalid construction result")
279 .that(constructedString)
280 .isEqualTo("string");
281 }
282
283 @SuppressWarnings("rawtypes")
284 @Test
285 public void testInvokeConstructorThatFails() throws NoSuchMethodException {
286 final Constructor<Dictionary> constructor = Dictionary.class.getConstructor();
287 final IllegalStateException ex = getExpectedThrowable(IllegalStateException.class, () -> {
288 CommonUtil.invokeConstructor(constructor);
289 });
290 assertWithMessage("Invalid exception cause")
291 .that(ex)
292 .hasCauseThat()
293 .isInstanceOf(InstantiationException.class);
294 }
295
296 @Test
297 public void testClose() {
298 final TestCloseable closeable = new TestCloseable();
299
300 CommonUtil.close(null);
301 CommonUtil.close(closeable);
302
303 assertWithMessage("Should be closed")
304 .that(closeable.closed)
305 .isTrue();
306 }
307
308 @Test
309 public void testCloseWithException() {
310 final IllegalStateException ex = getExpectedThrowable(IllegalStateException.class, () -> {
311 CommonUtil.close(() -> {
312 throw new IOException("Test IOException");
313 });
314 });
315 assertWithMessage("Invalid exception message")
316 .that(ex)
317 .hasMessageThat()
318 .isEqualTo("Cannot close the stream");
319 }
320
321 @Test
322 public void testFillTemplateWithStringsByRegexp() {
323 assertWithMessage("invalid result")
324 .that(CommonUtil.fillTemplateWithStringsByRegexp("template",
325 "lineToPlaceInTemplate", Pattern.compile("NO MATCH")))
326 .isEqualTo("template");
327 assertWithMessage("invalid result")
328 .that(CommonUtil.fillTemplateWithStringsByRegexp("before $0 after", "word",
329 Pattern.compile("\\w+")))
330 .isEqualTo("before word after");
331 assertWithMessage("invalid result")
332 .that(CommonUtil.fillTemplateWithStringsByRegexp("before $0 after1 $1 after2 $2 after3",
333 "word 123", Pattern.compile("(\\w+) (\\d+)")))
334 .isEqualTo("before word 123 after1 word after2 123 after3");
335 assertWithMessage("dollar sign in match must be treated literally")
336 .that(CommonUtil.fillTemplateWithStringsByRegexp("before $0 after",
337 "a$b", Pattern.compile(".+")))
338 .isEqualTo("before a$b after");
339 assertWithMessage("backslash in match must be treated literally")
340 .that(CommonUtil.fillTemplateWithStringsByRegexp("before $0 after",
341 "a\\b", Pattern.compile(".+")))
342 .isEqualTo("before a\\b after");
343 assertWithMessage("non-matching optional group must be left untouched")
344 .that(CommonUtil.fillTemplateWithStringsByRegexp("x $1 y $2 z",
345 "a", Pattern.compile("(a)(b)?")))
346 .isEqualTo("x a y $2 z");
347 }
348
349 @Test
350 public void testGetFileNameWithoutExtension() {
351 assertWithMessage("invalid result")
352 .that(CommonUtil.getFileNameWithoutExtension("filename"))
353 .isEqualTo("filename");
354 assertWithMessage("invalid result")
355 .that(CommonUtil.getFileNameWithoutExtension("filename.extension"))
356 .isEqualTo("filename");
357 assertWithMessage("invalid result")
358 .that(CommonUtil.getFileNameWithoutExtension("filename.subext.extension"))
359 .isEqualTo("filename.subext");
360 }
361
362 @Test
363 public void testGetFileExtension() {
364 assertWithMessage("Invalid extension")
365 .that(CommonUtil.getFileExtension("filename"))
366 .isEqualTo("");
367 assertWithMessage("Invalid extension")
368 .that(CommonUtil.getFileExtension("filename.extension"))
369 .isEqualTo("extension");
370 assertWithMessage("Invalid extension")
371 .that(CommonUtil.getFileExtension("filename.subext.extension"))
372 .isEqualTo("extension");
373 }
374
375 @Test
376 public void testIsIdentifier() {
377 assertWithMessage("Should return true when valid identifier is passed")
378 .that(CommonUtil.isIdentifier("aValidIdentifier"))
379 .isTrue();
380 }
381
382 @Test
383 public void testIsIdentifierEmptyString() {
384 assertWithMessage("Should return false when empty string is passed")
385 .that(CommonUtil.isIdentifier(""))
386 .isFalse();
387 }
388
389 @Test
390 public void testIsIdentifierInvalidFirstSymbol() {
391 assertWithMessage("Should return false when invalid identifier is passed")
392 .that(CommonUtil.isIdentifier("1InvalidIdentifier"))
393 .isFalse();
394 }
395
396 @Test
397 public void testIsIdentifierInvalidSymbols() {
398 assertWithMessage("Should return false when invalid identifier is passed")
399 .that(CommonUtil.isIdentifier("invalid#Identifier"))
400 .isFalse();
401 }
402
403 @Test
404 public void testIsName() {
405 assertWithMessage("Should return true when valid name is passed")
406 .that(CommonUtil.isName("a.valid.Nam3"))
407 .isTrue();
408 }
409
410 @Test
411 public void testIsNameEmptyString() {
412 assertWithMessage("Should return false when empty string is passed")
413 .that(CommonUtil.isName(""))
414 .isFalse();
415 }
416
417 @Test
418 public void testIsNameInvalidFirstSymbol() {
419 assertWithMessage("Should return false when invalid name is passed")
420 .that(CommonUtil.isName("1.invalid.name"))
421 .isFalse();
422 }
423
424 @Test
425 public void testIsNameEmptyPart() {
426 assertWithMessage("Should return false when name has empty part")
427 .that(CommonUtil.isName("invalid..name"))
428 .isFalse();
429 }
430
431 @Test
432 public void testIsNameEmptyLastPart() {
433 assertWithMessage("Should return false when name has empty part")
434 .that(CommonUtil.isName("invalid.name."))
435 .isFalse();
436 }
437
438 @Test
439 public void testIsNameInvalidSymbol() {
440 assertWithMessage("Should return false when invalid name is passed")
441 .that(CommonUtil.isName("invalid.name#42"))
442 .isFalse();
443 }
444
445 @Test
446 public void testIsBlank() {
447 assertWithMessage("Should return false when string is not empty")
448 .that(CommonUtil.isBlank("string"))
449 .isFalse();
450 }
451
452 @Test
453 public void testIsBlankAheadWhitespace() {
454 assertWithMessage("Should return false when string is not empty")
455 .that(CommonUtil.isBlank(" string"))
456 .isFalse();
457 }
458
459 @Test
460 public void testIsBlankBehindWhitespace() {
461 assertWithMessage("Should return false when string is not empty")
462 .that(CommonUtil.isBlank("string "))
463 .isFalse();
464 }
465
466 @Test
467 public void testIsBlankWithWhitespacesAround() {
468 assertWithMessage("Should return false when string is not empty")
469 .that(CommonUtil.isBlank(" string "))
470 .isFalse();
471 }
472
473 @Test
474 public void testIsBlankWhitespaceInside() {
475 assertWithMessage("Should return false when string is not empty")
476 .that(CommonUtil.isBlank("str ing"))
477 .isFalse();
478 }
479
480 @Test
481 public void testIsBlankNullString() {
482 assertWithMessage("Should return true when string is null")
483 .that(CommonUtil.isBlank(null))
484 .isTrue();
485 }
486
487 @Test
488 public void testIsBlankWithEmptyString() {
489 assertWithMessage("Should return true when string is empty")
490 .that(CommonUtil.isBlank(""))
491 .isTrue();
492 }
493
494 @Test
495 public void testIsBlankWithWhitespacesOnly() {
496 assertWithMessage("Should return true when string contains only spaces")
497 .that(CommonUtil.isBlank(" "))
498 .isTrue();
499 }
500
501 @Test
502 public void testGetUriByFilenameFindsAbsoluteResourceOnClasspath() throws Exception {
503 final String filename =
504 "/" + getPackageLocation() + "/InputCommonUtilTest_empty_checks.xml";
505 final URI uri = CommonUtil.getUriByFilename(filename);
506
507 final Properties properties = System.getProperties();
508 final Configuration config = ConfigurationLoader.loadConfiguration(uri.toASCIIString(),
509 new PropertiesExpander(properties));
510 assertWithMessage("Unexpected config name!")
511 .that(config.getName())
512 .isEqualTo("Checker");
513 }
514
515 @Test
516 public void testGetUriByFilenameFindsRelativeResourceOnClasspath() throws Exception {
517 final String filename =
518 getPackageLocation() + "/InputCommonUtilTest_empty_checks.xml";
519 final URI uri = CommonUtil.getUriByFilename(filename);
520
521 final Properties properties = System.getProperties();
522 final Configuration config = ConfigurationLoader.loadConfiguration(uri.toASCIIString(),
523 new PropertiesExpander(properties));
524 assertWithMessage("Unexpected config name!")
525 .that(config.getName())
526 .isEqualTo("Checker");
527 }
528
529
530
531
532
533
534
535
536 @Test
537 public void testGetUriByFilenameFindsResourceRelativeToRootClasspath() throws Exception {
538 final String filename =
539 getPackageLocation() + "/InputCommonUtilTest_resource.txt";
540 final URI uri = CommonUtil.getUriByFilename(filename);
541 assertWithMessage("URI is null for: %s", filename)
542 .that(uri)
543 .isNotNull();
544 final String uriRelativeToPackage =
545 "com/puppycrawl/tools/checkstyle/utils/"
546 + getPackageLocation() + "/InputCommonUtilTest_resource.txt";
547 assertWithMessage("URI is relative to package %s", uriRelativeToPackage)
548 .that(uri.toASCIIString())
549 .doesNotContain(uriRelativeToPackage);
550 final String content = IOUtils.toString(uri.toURL(), StandardCharsets.UTF_8);
551 assertWithMessage("Content mismatches for: %s", uri.toASCIIString())
552 .that(content)
553 .startsWith("good");
554 }
555
556 @Test
557 public void testGetUriByFilenameClasspathPrefixLoadConfig() throws Exception {
558 final String filename = CommonUtil.CLASSPATH_URL_PROTOCOL
559 + getPackageLocation() + "/InputCommonUtilTestWithChecks.xml";
560 final URI uri = CommonUtil.getUriByFilename(filename);
561
562 final Properties properties = System.getProperties();
563 final Configuration config = ConfigurationLoader.loadConfiguration(uri.toASCIIString(),
564 new PropertiesExpander(properties));
565 assertWithMessage("Unexpected config name!")
566 .that(config.getName())
567 .isEqualTo("Checker");
568 }
569
570 @Test
571 public void testGetUriByFilenameFindsRelativeResourceOnClasspathPrefix() throws Exception {
572 final String filename = CommonUtil.CLASSPATH_URL_PROTOCOL
573 + getPackageLocation() + "/InputCommonUtilTest_empty_checks.xml";
574 final URI uri = CommonUtil.getUriByFilename(filename);
575
576 final Properties properties = System.getProperties();
577 final Configuration config = ConfigurationLoader.loadConfiguration(uri.toASCIIString(),
578 new PropertiesExpander(properties));
579 assertWithMessage("Unexpected config name!")
580 .that(config.getName())
581 .isEqualTo("Checker");
582 }
583
584 @Test
585 public void testIsCodePointWhitespace() {
586 final int[] codePoints = " 123".codePoints().toArray();
587 assertThat(CommonUtil.isCodePointWhitespace(codePoints, 0))
588 .isTrue();
589 assertThat(CommonUtil.isCodePointWhitespace(codePoints, 1))
590 .isFalse();
591 }
592
593 @Test
594 public void testLoadSuppressionsUriSyntaxException() throws Exception {
595 final URL configUrl = mock();
596 when(configUrl.toURI()).thenThrow(URISyntaxException.class);
597 try (MockedStatic<CommonUtil> utilities =
598 mockStatic(CommonUtil.class, CALLS_REAL_METHODS)) {
599 final String fileName = "/suppressions_none.xml";
600 utilities.when(() -> CommonUtil.getCheckstyleResource(fileName))
601 .thenReturn(configUrl);
602
603 final CheckstyleException ex = getExpectedThrowable(CheckstyleException.class, () -> {
604 CommonUtil.getUriByFilename(fileName);
605 });
606 assertWithMessage("Invalid exception cause")
607 .that(ex)
608 .hasCauseThat()
609 .isInstanceOf(URISyntaxException.class);
610 assertWithMessage("Invalid exception message")
611 .that(ex)
612 .hasMessageThat()
613 .isEqualTo("Unable to find: " + fileName);
614 }
615 }
616
617 private static final class TestCloseable implements Closeable {
618
619 private boolean closed;
620
621 @Override
622 public void close() {
623 closed = true;
624 }
625
626 }
627
628 }