1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.commons.io.file;
19
20 import static org.junit.jupiter.api.Assertions.assertArrayEquals;
21 import static org.junit.jupiter.api.Assertions.assertEquals;
22 import static org.junit.jupiter.api.Assertions.assertFalse;
23 import static org.junit.jupiter.api.Assertions.assertNotEquals;
24 import static org.junit.jupiter.api.Assertions.assertNotNull;
25 import static org.junit.jupiter.api.Assertions.assertNull;
26 import static org.junit.jupiter.api.Assertions.assertThrows;
27 import static org.junit.jupiter.api.Assertions.assertTrue;
28 import static org.junit.jupiter.api.Assumptions.assumeFalse;
29
30 import java.io.File;
31 import java.io.IOException;
32 import java.io.OutputStream;
33 import java.net.URI;
34 import java.net.URISyntaxException;
35 import java.net.URL;
36 import java.nio.charset.StandardCharsets;
37 import java.nio.file.DirectoryStream;
38 import java.nio.file.FileSystem;
39 import java.nio.file.FileSystems;
40 import java.nio.file.Files;
41 import java.nio.file.LinkOption;
42 import java.nio.file.Path;
43 import java.nio.file.Paths;
44 import java.nio.file.attribute.DosFileAttributeView;
45 import java.nio.file.attribute.FileTime;
46 import java.nio.file.attribute.PosixFileAttributes;
47 import java.util.GregorianCalendar;
48 import java.util.HashMap;
49 import java.util.Iterator;
50 import java.util.Map;
51
52 import org.apache.commons.io.FileUtils;
53 import org.apache.commons.io.FilenameUtils;
54 import org.apache.commons.io.filefilter.NameFileFilter;
55 import org.apache.commons.io.test.TestUtils;
56 import org.apache.commons.lang3.ArrayUtils;
57 import org.apache.commons.lang3.StringUtils;
58 import org.apache.commons.lang3.SystemUtils;
59 import org.junit.jupiter.api.Test;
60
61
62
63
64 public class PathUtilsTest extends AbstractTempDirTest {
65
66 private static final String STRING_FIXTURE = "Hello World";
67
68 private static final byte[] BYTE_ARRAY_FIXTURE = STRING_FIXTURE.getBytes(StandardCharsets.UTF_8);
69
70 private static final String TEST_JAR_NAME = "test.jar";
71
72 private static final String TEST_JAR_PATH = "src/test/resources/org/apache/commons/io/test.jar";
73
74 private static final String PATH_FIXTURE = "NOTICE.txt";
75
76 private Path current() {
77 return PathUtils.current();
78 }
79
80 private Long getLastModifiedMillis(final Path file) throws IOException {
81 return Files.getLastModifiedTime(file).toMillis();
82 }
83
84 private Path getNonExistentPath() {
85 return Paths.get("/does not exist/for/certain");
86 }
87
88 private FileSystem openArchive(final Path p, final boolean createNew) throws IOException {
89 if (createNew) {
90 final Map<String, String> env = new HashMap<>();
91 env.put("create", "true");
92 final URI fileUri = p.toAbsolutePath().toUri();
93 final URI uri = URI.create("jar:" + fileUri.toASCIIString());
94 return FileSystems.newFileSystem(uri, env, null);
95 }
96 return FileSystems.newFileSystem(p, (ClassLoader) null);
97 }
98
99 private void setLastModifiedMillis(final Path file, final long millis) throws IOException {
100 Files.setLastModifiedTime(file, FileTime.fromMillis(millis));
101 }
102
103 @Test
104 public void testCopyDirectoryForDifferentFilesystemsWithAbsolutePath() throws IOException {
105 final Path archivePath = Paths.get(TEST_JAR_PATH);
106 try (FileSystem archive = openArchive(archivePath, false)) {
107
108 Path sourceDir = archive.getPath("dir1");
109 PathUtils.copyDirectory(sourceDir, tempDirPath);
110 assertTrue(Files.exists(tempDirPath.resolve("f1")));
111
112
113 sourceDir = archive.getPath("/next");
114 PathUtils.copyDirectory(sourceDir, tempDirPath);
115 assertTrue(Files.exists(tempDirPath.resolve("dir")));
116 }
117 }
118
119 @Test
120 public void testCopyDirectoryForDifferentFilesystemsWithAbsolutePathReverse() throws IOException {
121 try (FileSystem archive = openArchive(tempDirPath.resolve(TEST_JAR_NAME), true)) {
122
123 Path targetDir = archive.getPath("target");
124 Files.createDirectory(targetDir);
125 final Path sourceDir = Paths.get("src/test/resources/org/apache/commons/io/dirs-2-file-size-2").toAbsolutePath();
126 PathUtils.copyDirectory(sourceDir, targetDir);
127 assertTrue(Files.exists(targetDir.resolve("dirs-a-file-size-1")));
128
129
130 targetDir = archive.getPath("/");
131 PathUtils.copyDirectory(sourceDir, targetDir);
132 assertTrue(Files.exists(targetDir.resolve("dirs-a-file-size-1")));
133 }
134 }
135
136 @Test
137 public void testCopyDirectoryForDifferentFilesystemsWithRelativePath() throws IOException {
138 final Path archivePath = Paths.get(TEST_JAR_PATH);
139 try (FileSystem archive = openArchive(archivePath, false);
140 final FileSystem targetArchive = openArchive(tempDirPath.resolve(TEST_JAR_NAME), true)) {
141 final Path targetDir = targetArchive.getPath("targetDir");
142 Files.createDirectory(targetDir);
143
144 Path sourceDir = archive.getPath("next");
145 PathUtils.copyDirectory(sourceDir, targetDir);
146 assertTrue(Files.exists(targetDir.resolve("dir")));
147
148
149 sourceDir = archive.getPath("/dir1");
150 PathUtils.copyDirectory(sourceDir, targetDir);
151 assertTrue(Files.exists(targetDir.resolve("f1")));
152 }
153 }
154
155 @Test
156 public void testCopyDirectoryForDifferentFilesystemsWithRelativePathReverse() throws IOException {
157 try (FileSystem archive = openArchive(tempDirPath.resolve(TEST_JAR_NAME), true)) {
158
159 Path targetDir = archive.getPath("target");
160 Files.createDirectory(targetDir);
161 final Path sourceDir = Paths.get("src/test/resources/org/apache/commons/io/dirs-2-file-size-2");
162 PathUtils.copyDirectory(sourceDir, targetDir);
163 assertTrue(Files.exists(targetDir.resolve("dirs-a-file-size-1")));
164
165
166 targetDir = archive.getPath("/");
167 PathUtils.copyDirectory(sourceDir, targetDir);
168 assertTrue(Files.exists(targetDir.resolve("dirs-a-file-size-1")));
169 }
170 }
171
172 @Test
173 public void testCopyFile() throws IOException {
174 final Path sourceFile = Paths.get("src/test/resources/org/apache/commons/io/dirs-1-file-size-1/file-size-1.bin");
175 final Path targetFile = PathUtils.copyFileToDirectory(sourceFile, tempDirPath);
176 assertTrue(Files.exists(targetFile));
177 assertEquals(Files.size(sourceFile), Files.size(targetFile));
178 }
179
180 @Test
181 public void testCopyURL() throws IOException {
182 final Path sourceFile = Paths.get("src/test/resources/org/apache/commons/io/dirs-1-file-size-1/file-size-1.bin");
183 final URL url = new URL("file:///" + FilenameUtils.getPath(sourceFile.toAbsolutePath().toString()) + sourceFile.getFileName());
184 final Path targetFile = PathUtils.copyFileToDirectory(url, tempDirPath);
185 assertTrue(Files.exists(targetFile));
186 assertEquals(Files.size(sourceFile), Files.size(targetFile));
187 }
188
189 @Test
190 public void testCreateDirectoriesAlreadyExists() throws IOException {
191 assertEquals(tempDirPath.getParent(), PathUtils.createParentDirectories(tempDirPath));
192 }
193
194 @SuppressWarnings("resource")
195 @Test
196 public void testCreateDirectoriesForRoots() throws IOException {
197 for (final Path path : FileSystems.getDefault().getRootDirectories()) {
198 final Path parent = path.getParent();
199 assertNull(parent);
200 assertEquals(parent, PathUtils.createParentDirectories(path));
201 }
202 }
203
204 @Test
205 public void testCreateDirectoriesForRootsLinkOptionNull() throws IOException {
206 for (final File f : File.listRoots()) {
207 final Path path = f.toPath();
208 assertEquals(path.getParent(), PathUtils.createParentDirectories(path, (LinkOption) null));
209 }
210 }
211
212 @Test
213 public void testCreateDirectoriesNew() throws IOException {
214 assertEquals(tempDirPath, PathUtils.createParentDirectories(tempDirPath.resolve("child")));
215 }
216
217 @Test
218 public void testCreateDirectoriesSymlink() throws IOException {
219 final Path symlinkedDir = createTempSymlinkedRelativeDir(tempDirPath);
220 final String leafDirName = "child";
221 final Path newDirFollowed = PathUtils.createParentDirectories(symlinkedDir.resolve(leafDirName), PathUtils.NULL_LINK_OPTION);
222 assertEquals(Files.readSymbolicLink(symlinkedDir), newDirFollowed);
223 }
224
225 @Test
226 public void testCreateDirectoriesSymlinkClashing() throws IOException {
227 final Path symlinkedDir = createTempSymlinkedRelativeDir(tempDirPath);
228 assertEquals(symlinkedDir, PathUtils.createParentDirectories(symlinkedDir.resolve("child")));
229 }
230
231 @Test
232 public void testGetBaseNamePathBaseCases() {
233 assertEquals("bar", PathUtils.getBaseName(Paths.get("a/b/c/bar.foo")));
234 assertEquals("foo", PathUtils.getBaseName(Paths.get("foo")));
235 assertEquals("", PathUtils.getBaseName(Paths.get("")));
236 assertEquals("", PathUtils.getBaseName(Paths.get(".")));
237 for (final File f : File.listRoots()) {
238 assertNull(PathUtils.getBaseName(f.toPath()));
239 }
240 if (SystemUtils.IS_OS_WINDOWS) {
241 assertNull(PathUtils.getBaseName(Paths.get("C:\\")));
242 }
243 }
244
245 @Test
246 public void testGetBaseNamePathCornerCases() {
247 assertNull(PathUtils.getBaseName((Path) null));
248 assertEquals("foo", PathUtils.getBaseName(Paths.get("foo.")));
249 assertEquals("", PathUtils.getBaseName(Paths.get("bar/.foo")));
250 }
251
252 @Test
253 public void testGetExtension() {
254 assertNull(PathUtils.getExtension(null));
255 assertEquals("ext", PathUtils.getExtension(Paths.get("file.ext")));
256 assertEquals("", PathUtils.getExtension(Paths.get("README")));
257 assertEquals("com", PathUtils.getExtension(Paths.get("domain.dot.com")));
258 assertEquals("jpeg", PathUtils.getExtension(Paths.get("image.jpeg")));
259 assertEquals("", PathUtils.getExtension(Paths.get("a.b/c")));
260 assertEquals("txt", PathUtils.getExtension(Paths.get("a.b/c.txt")));
261 assertEquals("", PathUtils.getExtension(Paths.get("a/b/c")));
262 assertEquals("", PathUtils.getExtension(Paths.get("a.b\\c")));
263 assertEquals("txt", PathUtils.getExtension(Paths.get("a.b\\c.txt")));
264 assertEquals("", PathUtils.getExtension(Paths.get("a\\b\\c")));
265 assertEquals("", PathUtils.getExtension(Paths.get("C:\\temp\\foo.bar\\README")));
266 assertEquals("ext", PathUtils.getExtension(Paths.get("../filename.ext")));
267
268 if (File.separatorChar != '\\') {
269
270 assertEquals("txt", PathUtils.getExtension(Paths.get("foo.exe:bar.txt")));
271 }
272 }
273
274 @Test
275 public void testGetFileName() {
276 assertNull(PathUtils.getFileName(null, null));
277 assertNull(PathUtils.getFileName(null, Path::toString));
278 assertNull(PathUtils.getFileName(Paths.get("/"), Path::toString));
279 assertNull(PathUtils.getFileName(Paths.get("/"), Path::toString));
280 assertEquals("", PathUtils.getFileName(Paths.get(""), Path::toString));
281 assertEquals("a", PathUtils.getFileName(Paths.get("a"), Path::toString));
282 assertEquals("a", PathUtils.getFileName(Paths.get("p", "a"), Path::toString));
283 }
284
285 @Test
286 public void testGetFileNameString() {
287 assertNull(PathUtils.getFileNameString(Paths.get("/")));
288 assertEquals("", PathUtils.getFileNameString(Paths.get("")));
289 assertEquals("a", PathUtils.getFileNameString(Paths.get("a")));
290 assertEquals("a", PathUtils.getFileNameString(Paths.get("p", "a")));
291 }
292
293 @Test
294 public void testGetLastModifiedFileTime_File_Present() throws IOException {
295 assertNotNull(PathUtils.getLastModifiedFileTime(current().toFile()));
296 }
297
298 @Test
299 public void testGetLastModifiedFileTime_Path_Absent() throws IOException {
300 assertNull(PathUtils.getLastModifiedFileTime(getNonExistentPath()));
301 }
302
303 @Test
304 public void testGetLastModifiedFileTime_Path_FileTime_Absent() throws IOException {
305 final FileTime fromMillis = FileTime.fromMillis(0);
306 assertEquals(fromMillis, PathUtils.getLastModifiedFileTime(getNonExistentPath(), fromMillis));
307 }
308
309 @Test
310 public void testGetLastModifiedFileTime_Path_Present() throws IOException {
311 assertNotNull(PathUtils.getLastModifiedFileTime(current()));
312 }
313
314 @Test
315 public void testGetLastModifiedFileTime_URI_Present() throws IOException {
316 assertNotNull(PathUtils.getLastModifiedFileTime(current().toUri()));
317 }
318
319 @Test
320 public void testGetLastModifiedFileTime_URL_Present() throws IOException, URISyntaxException {
321 assertNotNull(PathUtils.getLastModifiedFileTime(current().toUri().toURL()));
322 }
323
324 @Test
325 public void testGetTempDirectory() {
326 final Path tempDirectory = Paths.get(System.getProperty("java.io.tmpdir"));
327 assertEquals(tempDirectory, PathUtils.getTempDirectory());
328 }
329
330 @Test
331 public void testIsDirectory() throws IOException {
332 assertFalse(PathUtils.isDirectory(null));
333
334 assertTrue(PathUtils.isDirectory(tempDirPath));
335 try (TempFile testFile1 = TempFile.create(tempDirPath, "prefix", null)) {
336 assertFalse(PathUtils.isDirectory(testFile1.get()));
337
338 Path ref = null;
339 try (TempDirectory tempDir = TempDirectory.create(getClass().getCanonicalName())) {
340 ref = tempDir.get();
341 assertTrue(PathUtils.isDirectory(tempDir.get()));
342 }
343 assertFalse(PathUtils.isDirectory(ref));
344 }
345 }
346
347 @Test
348 public void testIsPosix() throws IOException {
349 boolean isPosix;
350 try {
351 Files.getPosixFilePermissions(current());
352 isPosix = true;
353 } catch (final UnsupportedOperationException e) {
354 isPosix = false;
355 }
356 assertEquals(isPosix, PathUtils.isPosix(current()));
357 }
358
359 @Test
360 public void testIsRegularFile() throws IOException {
361 assertFalse(PathUtils.isRegularFile(null));
362
363 assertFalse(PathUtils.isRegularFile(tempDirPath));
364 try (TempFile testFile1 = TempFile.create(tempDirPath, "prefix", null)) {
365 assertTrue(PathUtils.isRegularFile(testFile1.get()));
366
367 Files.delete(testFile1.get());
368 assertFalse(PathUtils.isRegularFile(testFile1.get()));
369 }
370 }
371
372 @Test
373 public void testNewDirectoryStream() throws Exception {
374 final PathFilter pathFilter = new NameFileFilter(PATH_FIXTURE);
375 try (DirectoryStream<Path> stream = PathUtils.newDirectoryStream(current(), pathFilter)) {
376 final Iterator<Path> iterator = stream.iterator();
377 final Path path = iterator.next();
378 assertEquals(PATH_FIXTURE, PathUtils.getFileNameString(path));
379 assertFalse(iterator.hasNext());
380 }
381 }
382
383 @Test
384 public void testNewOutputStreamExistingFileAppendFalse() throws IOException {
385 testNewOutputStreamNewFile(false);
386 testNewOutputStreamNewFile(false);
387 }
388
389 @Test
390 public void testNewOutputStreamExistingFileAppendTrue() throws IOException {
391 testNewOutputStreamNewFile(true);
392 final Path file = writeToNewOutputStream(true);
393 assertArrayEquals(ArrayUtils.addAll(BYTE_ARRAY_FIXTURE, BYTE_ARRAY_FIXTURE), Files.readAllBytes(file));
394 }
395
396 public void testNewOutputStreamNewFile(final boolean append) throws IOException {
397 final Path file = writeToNewOutputStream(append);
398 assertArrayEquals(BYTE_ARRAY_FIXTURE, Files.readAllBytes(file));
399 }
400
401 @Test
402 public void testNewOutputStreamNewFileAppendFalse() throws IOException {
403 testNewOutputStreamNewFile(false);
404 }
405
406 @Test
407 public void testNewOutputStreamNewFileAppendTrue() throws IOException {
408 testNewOutputStreamNewFile(true);
409 }
410
411 @Test
412 public void testNewOutputStreamNewFileInsideExistingSymlinkedDir() throws IOException {
413 final Path symlinkDir = createTempSymlinkedRelativeDir(tempDirPath);
414 final Path file = symlinkDir.resolve("test.txt");
415 try (OutputStream outputStream = PathUtils.newOutputStream(file, new LinkOption[] {})) {
416
417 }
418 try (OutputStream outputStream = PathUtils.newOutputStream(file, null)) {
419
420 }
421 try (OutputStream outputStream = PathUtils.newOutputStream(file, true)) {
422
423 }
424 try (OutputStream outputStream = PathUtils.newOutputStream(file, false)) {
425
426 }
427 }
428
429 @Test
430 public void testReadAttributesPosix() throws IOException {
431 boolean isPosix;
432 try {
433 Files.getPosixFilePermissions(current());
434 isPosix = true;
435 } catch (final UnsupportedOperationException e) {
436 isPosix = false;
437 }
438 assertEquals(isPosix, PathUtils.readAttributes(current(), PosixFileAttributes.class) != null);
439 }
440
441 @Test
442 public void testReadStringEmptyFile() throws IOException {
443 final Path path = Paths.get("src/test/resources/org/apache/commons/io/test-file-empty.bin");
444 assertEquals(StringUtils.EMPTY, PathUtils.readString(path, StandardCharsets.UTF_8));
445 assertEquals(StringUtils.EMPTY, PathUtils.readString(path, null));
446 }
447
448 @Test
449 public void testReadStringSimpleUtf8() throws IOException {
450 final Path path = Paths.get("src/test/resources/org/apache/commons/io/test-file-simple-utf8.bin");
451 final String expected = "ABC\r\n";
452 assertEquals(expected, PathUtils.readString(path, StandardCharsets.UTF_8));
453 assertEquals(expected, PathUtils.readString(path, null));
454 }
455
456 @Test
457 public void testSetReadOnlyFile() throws IOException {
458 final Path resolved = tempDirPath.resolve("testSetReadOnlyFile.txt");
459
460 final boolean isPosix = PathUtils.isPosix(tempDirPath);
461
462
463 assumeFalse(SystemUtils.IS_OS_LINUX);
464
465 PathUtils.writeString(resolved, "test", StandardCharsets.UTF_8);
466 final boolean readable = Files.isReadable(resolved);
467 final boolean writable = Files.isWritable(resolved);
468 final boolean regularFile = Files.isRegularFile(resolved);
469 final boolean executable = Files.isExecutable(resolved);
470 final boolean hidden = Files.isHidden(resolved);
471 final boolean directory = Files.isDirectory(resolved);
472 final boolean symbolicLink = Files.isSymbolicLink(resolved);
473
474 assertTrue(readable);
475 assertTrue(writable);
476
477 PathUtils.setReadOnly(resolved, false);
478 assertTrue(Files.isReadable(resolved), "isReadable");
479 assertTrue(Files.isWritable(resolved), "isWritable");
480
481 PathUtils.setReadOnly(resolved, false);
482 assertTrue(Files.isReadable(resolved), "isReadable");
483 assertTrue(Files.isWritable(resolved), "isWritable");
484
485 assertEquals(regularFile, Files.isReadable(resolved));
486 assertEquals(executable, Files.isExecutable(resolved));
487 assertEquals(hidden, Files.isHidden(resolved));
488 assertEquals(directory, Files.isDirectory(resolved));
489 assertEquals(symbolicLink, Files.isSymbolicLink(resolved));
490
491 PathUtils.setReadOnly(resolved, true);
492 if (isPosix) {
493
494 assertFalse(Files.isReadable(resolved), "isReadable");
495 } else {
496 assertTrue(Files.isReadable(resolved), "isReadable");
497 }
498 assertFalse(Files.isWritable(resolved), "isWritable");
499 final DosFileAttributeView dosFileAttributeView = PathUtils.getDosFileAttributeView(resolved);
500 if (dosFileAttributeView != null) {
501 assertTrue(dosFileAttributeView.readAttributes().isReadOnly());
502 }
503 if (isPosix) {
504 assertFalse(Files.isReadable(resolved));
505 } else {
506 assertEquals(regularFile, Files.isReadable(resolved));
507 }
508 assertEquals(executable, Files.isExecutable(resolved));
509 assertEquals(hidden, Files.isHidden(resolved));
510 assertEquals(directory, Files.isDirectory(resolved));
511 assertEquals(symbolicLink, Files.isSymbolicLink(resolved));
512
513 PathUtils.setReadOnly(resolved, false);
514 PathUtils.deleteFile(resolved);
515 }
516
517 @Test
518 public void testTouch() throws IOException {
519 assertThrows(NullPointerException.class, () -> FileUtils.touch(null));
520
521 final Path file = managedTempDirPath.resolve("touch.txt");
522 Files.deleteIfExists(file);
523 assertFalse(Files.exists(file), "Bad test: test file still exists");
524 PathUtils.touch(file);
525 assertTrue(Files.exists(file), "touch() created file");
526 try (OutputStream out = Files.newOutputStream(file)) {
527 assertEquals(0, Files.size(file), "Created empty file.");
528 out.write(0);
529 }
530 assertEquals(1, Files.size(file), "Wrote one byte to file");
531 final long y2k = new GregorianCalendar(2000, 0, 1).getTime().getTime();
532 setLastModifiedMillis(file, y2k);
533 assertEquals(y2k, getLastModifiedMillis(file), "Bad test: set lastModified set incorrect value");
534 final long nowMillis = System.currentTimeMillis();
535 PathUtils.touch(file);
536 assertEquals(1, Files.size(file), "FileUtils.touch() didn't empty the file.");
537 assertNotEquals(y2k, getLastModifiedMillis(file), "FileUtils.touch() changed lastModified");
538 final int delta = 3000;
539 assertTrue(getLastModifiedMillis(file) >= nowMillis - delta, "FileUtils.touch() changed lastModified to more than now-3s");
540 assertTrue(getLastModifiedMillis(file) <= nowMillis + delta, "FileUtils.touch() changed lastModified to less than now+3s");
541 }
542
543 @Test
544 public void testWriteStringToFile1() throws Exception {
545 final Path file = tempDirPath.resolve("write.txt");
546 PathUtils.writeString(file, "Hello /u1234", StandardCharsets.UTF_8);
547 final byte[] text = "Hello /u1234".getBytes(StandardCharsets.UTF_8);
548 TestUtils.assertEqualContent(text, file);
549 }
550
551
552
553
554 private Path writeToNewOutputStream(final boolean append) throws IOException {
555 final Path file = tempDirPath.resolve("test1.txt");
556 try (OutputStream os = PathUtils.newOutputStream(file, append)) {
557 os.write(BYTE_ARRAY_FIXTURE);
558 }
559 return file;
560 }
561
562 }