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