1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44 package org.eclipse.jgit.util;
45
46 import static org.junit.Assert.assertEquals;
47 import static org.junit.Assert.assertFalse;
48 import static org.junit.Assert.assertTrue;
49 import static org.junit.Assert.fail;
50
51 import java.io.File;
52 import java.io.IOException;
53 import java.io.UnsupportedEncodingException;
54 import java.nio.file.Files;
55 import java.nio.file.StandardCopyOption;
56 import java.rmi.RemoteException;
57 import java.util.regex.Matcher;
58
59 import javax.management.remote.JMXProviderException;
60
61 import org.eclipse.jgit.junit.JGitTestUtil;
62 import org.junit.After;
63 import org.junit.Assume;
64 import org.junit.Before;
65 import org.junit.Test;
66
67 public class FileUtilsTest {
68 private static final String MSG = "Stale file handle";
69
70 private static final String SOME_ERROR_MSG = "some error message";
71
72 private static final IOException IO_EXCEPTION = new UnsupportedEncodingException(
73 MSG);
74
75 private static final IOException IO_EXCEPTION_WITH_CAUSE = new RemoteException(
76 SOME_ERROR_MSG,
77 new JMXProviderException(SOME_ERROR_MSG, IO_EXCEPTION));
78
79 private File trash;
80
81 @Before
82 public void setUp() throws Exception {
83 trash = File.createTempFile("tmp_", "");
84 trash.delete();
85 assertTrue("mkdir " + trash, trash.mkdir());
86 }
87
88 @After
89 public void tearDown() throws Exception {
90 FileUtils.delete(trash, FileUtils.RECURSIVE | FileUtils.RETRY);
91 }
92
93 @Test
94 public void testDeleteFile() throws IOException {
95 File f = new File(trash, "test");
96 FileUtils.createNewFile(f);
97 FileUtils.delete(f);
98 assertFalse(f.exists());
99
100 try {
101 FileUtils.delete(f);
102 fail("deletion of non-existing file must fail");
103 } catch (IOException e) {
104
105 }
106
107 try {
108 FileUtils.delete(f, FileUtils.SKIP_MISSING);
109 } catch (IOException e) {
110 fail("deletion of non-existing file must not fail with option SKIP_MISSING");
111 }
112 }
113
114 @Test
115 public void testDeleteRecursive() throws IOException {
116 File f1 = new File(trash, "test/test/a");
117 FileUtils.mkdirs(f1.getParentFile());
118 FileUtils.createNewFile(f1);
119 File f2 = new File(trash, "test/test/b");
120 FileUtils.createNewFile(f2);
121 File d = new File(trash, "test");
122 FileUtils.delete(d, FileUtils.RECURSIVE);
123 assertFalse(d.exists());
124
125 try {
126 FileUtils.delete(d, FileUtils.RECURSIVE);
127 fail("recursive deletion of non-existing directory must fail");
128 } catch (IOException e) {
129
130 }
131
132 try {
133 FileUtils.delete(d, FileUtils.RECURSIVE | FileUtils.SKIP_MISSING);
134 } catch (IOException e) {
135 fail("recursive deletion of non-existing directory must not fail with option SKIP_MISSING");
136 }
137 }
138
139 @Test
140
141 public void testDeleteRecursiveEmpty() throws IOException {
142 File f1 = new File(trash, "test/test/a");
143 File f2 = new File(trash, "test/a");
144 File d1 = new File(trash, "test");
145 File d2 = new File(trash, "test/test");
146 File d3 = new File(trash, "test/b");
147 FileUtils.mkdirs(f1.getParentFile());
148 FileUtils.createNewFile(f2);
149 FileUtils.createNewFile(f1);
150 FileUtils.mkdirs(d3);
151
152
153 try {
154 FileUtils.delete(d1, FileUtils.EMPTY_DIRECTORIES_ONLY);
155 fail("delete should fail");
156 } catch (IOException e1) {
157 try {
158 FileUtils.delete(d1, FileUtils.EMPTY_DIRECTORIES_ONLY|FileUtils.RECURSIVE);
159 fail("delete should fail");
160 } catch (IOException e2) {
161
162 assertTrue(f1.exists());
163 assertTrue(f2.exists());
164 assertTrue(d1.exists());
165 assertTrue(d2.exists());
166 assertTrue(d3.exists());
167 }
168 }
169
170
171 assertTrue(f1.delete());
172 assertTrue(f2.delete());
173
174
175 try {
176 FileUtils.delete(d1, FileUtils.EMPTY_DIRECTORIES_ONLY);
177 fail("delete should fail");
178 } catch (IOException e2) {
179
180 assertTrue(d1.exists());
181 assertTrue(d2.exists());
182 assertTrue(d3.exists());
183 }
184
185
186 FileUtils.delete(d2, FileUtils.EMPTY_DIRECTORIES_ONLY
187 | FileUtils.RECURSIVE);
188 assertFalse(d2.exists());
189
190
191 try {
192 FileUtils.delete(d2, FileUtils.EMPTY_DIRECTORIES_ONLY);
193 fail("Cannot delete non-existent entity");
194 } catch (IOException e) {
195
196 }
197
198
199 FileUtils.delete(d2, FileUtils.EMPTY_DIRECTORIES_ONLY
200 | FileUtils.SKIP_MISSING);
201 FileUtils.delete(d2, FileUtils.EMPTY_DIRECTORIES_ONLY
202 | FileUtils.RECURSIVE | FileUtils.SKIP_MISSING);
203
204
205 FileUtils.delete(d2, FileUtils.EMPTY_DIRECTORIES_ONLY
206 | FileUtils.IGNORE_ERRORS);
207 FileUtils.delete(d2, FileUtils.EMPTY_DIRECTORIES_ONLY
208 | FileUtils.RECURSIVE | FileUtils.IGNORE_ERRORS);
209 }
210
211 @Test
212 public void testDeleteRecursiveEmptyNeedsToCheckFilesFirst()
213 throws IOException {
214 File d1 = new File(trash, "test");
215 File d2 = new File(trash, "test/a");
216 File d3 = new File(trash, "test/b");
217 File f1 = new File(trash, "test/c");
218 File d4 = new File(trash, "test/d");
219 FileUtils.mkdirs(d1);
220 FileUtils.mkdirs(d2);
221 FileUtils.mkdirs(d3);
222 FileUtils.mkdirs(d4);
223 FileUtils.createNewFile(f1);
224
225
226 try {
227 FileUtils.delete(d1, FileUtils.EMPTY_DIRECTORIES_ONLY
228 | FileUtils.RECURSIVE);
229 fail("delete should fail");
230 } catch (IOException e) {
231
232 assertTrue(f1.exists());
233 assertTrue(d1.exists());
234 assertTrue(d2.exists());
235 assertTrue(d3.exists());
236 assertTrue(d4.exists());
237 }
238 }
239
240 @Test
241 public void testDeleteRecursiveEmptyDirectoriesOnlyButIsFile()
242 throws IOException {
243 File f1 = new File(trash, "test/test/a");
244 FileUtils.mkdirs(f1.getParentFile());
245 FileUtils.createNewFile(f1);
246 try {
247 FileUtils.delete(f1, FileUtils.EMPTY_DIRECTORIES_ONLY);
248 fail("delete should fail");
249 } catch (IOException e) {
250 assertTrue(f1.exists());
251 }
252 }
253
254 @Test
255 public void testMkdir() throws IOException {
256 File d = new File(trash, "test");
257 FileUtils.mkdir(d);
258 assertTrue(d.exists() && d.isDirectory());
259
260 try {
261 FileUtils.mkdir(d);
262 fail("creation of existing directory must fail");
263 } catch (IOException e) {
264
265 }
266
267 FileUtils.mkdir(d, true);
268 assertTrue(d.exists() && d.isDirectory());
269
270 assertTrue(d.delete());
271 File f = new File(trash, "test");
272 FileUtils.createNewFile(f);
273 try {
274 FileUtils.mkdir(d);
275 fail("creation of directory having same path as existing file must"
276 + " fail");
277 } catch (IOException e) {
278
279 }
280 assertTrue(f.delete());
281 }
282
283 @Test
284 public void testMkdirs() throws IOException {
285 File root = new File(trash, "test");
286 assertTrue(root.mkdir());
287
288 File d = new File(root, "test/test");
289 FileUtils.mkdirs(d);
290 assertTrue(d.exists() && d.isDirectory());
291
292 try {
293 FileUtils.mkdirs(d);
294 fail("creation of existing directory hierarchy must fail");
295 } catch (IOException e) {
296
297 }
298
299 FileUtils.mkdirs(d, true);
300 assertTrue(d.exists() && d.isDirectory());
301
302 FileUtils.delete(root, FileUtils.RECURSIVE);
303 File f = new File(trash, "test");
304 FileUtils.createNewFile(f);
305 try {
306 FileUtils.mkdirs(d);
307 fail("creation of directory having path conflicting with existing"
308 + " file must fail");
309 } catch (IOException e) {
310
311 }
312 assertTrue(f.delete());
313 }
314
315 @Test
316 public void testCreateNewFile() throws IOException {
317 File f = new File(trash, "x");
318 FileUtils.createNewFile(f);
319 assertTrue(f.exists());
320
321 try {
322 FileUtils.createNewFile(f);
323 fail("creation of already existing file must fail");
324 } catch (IOException e) {
325
326 }
327
328 FileUtils.delete(f);
329 }
330
331 @Test
332 public void testDeleteEmptyTreeOk() throws IOException {
333 File t = new File(trash, "t");
334 FileUtils.mkdir(t);
335 FileUtils.mkdir(new File(t, "d"));
336 FileUtils.mkdir(new File(new File(t, "d"), "e"));
337 FileUtils.delete(t, FileUtils.EMPTY_DIRECTORIES_ONLY | FileUtils.RECURSIVE);
338 assertFalse(t.exists());
339 }
340
341 @Test
342 public void testDeleteNotEmptyTreeNotOk() throws IOException {
343 File t = new File(trash, "t");
344 FileUtils.mkdir(t);
345 FileUtils.mkdir(new File(t, "d"));
346 File f = new File(new File(t, "d"), "f");
347 FileUtils.createNewFile(f);
348 FileUtils.mkdir(new File(new File(t, "d"), "e"));
349 try {
350 FileUtils.delete(t, FileUtils.EMPTY_DIRECTORIES_ONLY | FileUtils.RECURSIVE);
351 fail("expected failure to delete f");
352 } catch (IOException e) {
353 assertTrue(e.getMessage().endsWith(f.getAbsolutePath()));
354 }
355 assertTrue(t.exists());
356 }
357
358 @Test
359 public void testDeleteNotEmptyTreeNotOkButIgnoreFail() throws IOException {
360 File t = new File(trash, "t");
361 FileUtils.mkdir(t);
362 FileUtils.mkdir(new File(t, "d"));
363 File f = new File(new File(t, "d"), "f");
364 FileUtils.createNewFile(f);
365 File e = new File(new File(t, "d"), "e");
366 FileUtils.mkdir(e);
367 FileUtils.delete(t, FileUtils.EMPTY_DIRECTORIES_ONLY | FileUtils.RECURSIVE
368 | FileUtils.IGNORE_ERRORS);
369
370 assertTrue(t.exists());
371 assertTrue(f.exists());
372 assertFalse(e.exists());
373 }
374
375 @Test
376 public void testRenameOverNonExistingFile() throws IOException {
377 File d = new File(trash, "d");
378 FileUtils.mkdirs(d);
379 File f1 = new File(trash, "d/f");
380 File f2 = new File(trash, "d/g");
381 JGitTestUtil.write(f1, "f1");
382
383 FileUtils.rename(f1, f2);
384 assertFalse(f1.exists());
385 assertTrue(f2.exists());
386 assertEquals("f1", JGitTestUtil.read(f2));
387 }
388
389 @Test
390 public void testRenameOverExistingFile() throws IOException {
391 File d = new File(trash, "d");
392 FileUtils.mkdirs(d);
393 File f1 = new File(trash, "d/f");
394 File f2 = new File(trash, "d/g");
395 JGitTestUtil.write(f1, "f1");
396 JGitTestUtil.write(f2, "f2");
397
398 FileUtils.rename(f1, f2);
399 assertFalse(f1.exists());
400 assertTrue(f2.exists());
401 assertEquals("f1", JGitTestUtil.read(f2));
402 }
403
404 @Test
405 public void testRenameOverExistingNonEmptyDirectory() throws IOException {
406 File d = new File(trash, "d");
407 FileUtils.mkdirs(d);
408 File f1 = new File(trash, "d/f");
409 File f2 = new File(trash, "d/g");
410 File d1 = new File(trash, "d/g/h/i");
411 File f3 = new File(trash, "d/g/h/f");
412 FileUtils.mkdirs(d1);
413 JGitTestUtil.write(f1, "f1");
414 JGitTestUtil.write(f3, "f3");
415
416 try {
417 FileUtils.rename(f1, f2);
418 fail("rename to non-empty directory should fail");
419 } catch (IOException e) {
420 assertEquals("f1", JGitTestUtil.read(f1));
421 assertEquals("f3", JGitTestUtil.read(f3));
422
423 }
424 }
425
426 @Test
427 public void testRenameOverExistingEmptyDirectory() throws IOException {
428 File d = new File(trash, "d");
429 FileUtils.mkdirs(d);
430 File f1 = new File(trash, "d/f");
431 File f2 = new File(trash, "d/g");
432 File d1 = new File(trash, "d/g/h/i");
433 FileUtils.mkdirs(d1);
434 JGitTestUtil.write(f1, "f1");
435
436 FileUtils.rename(f1, f2);
437 assertFalse(f1.exists());
438 assertTrue(f2.exists());
439 assertEquals("f1", JGitTestUtil.read(f2));
440 }
441
442 @Test
443 public void testCreateSymlink() throws IOException {
444 FS fs = FS.DETECTED;
445
446 Assume.assumeTrue(fs.supportsSymlinks());
447 fs.createSymLink(new File(trash, "x"), "y");
448 String target = fs.readSymLink(new File(trash, "x"));
449 assertEquals("y", target);
450 }
451
452 @Test
453 public void testCreateSymlinkOverrideExisting() throws IOException {
454 FS fs = FS.DETECTED;
455
456 Assume.assumeTrue(fs.supportsSymlinks());
457 File file = new File(trash, "x");
458 fs.createSymLink(file, "y");
459 String target = fs.readSymLink(file);
460 assertEquals("y", target);
461 fs.createSymLink(file, "z");
462 target = fs.readSymLink(file);
463 assertEquals("z", target);
464 }
465
466 @Test
467 public void testRelativize_doc() {
468
469 String base = toOSPathString("c:\\Users\\jdoe\\eclipse\\git\\project");
470 String other = toOSPathString("c:\\Users\\jdoe\\eclipse\\git\\another_project\\pom.xml");
471 String expected = toOSPathString("..\\another_project\\pom.xml");
472
473 String actual = FileUtils.relativizeNativePath(base, other);
474 assertEquals(expected, actual);
475 }
476
477 @Test
478 public void testRelativize_mixedCase() {
479 SystemReader systemReader = SystemReader.getInstance();
480 String base = toOSPathString("C:\\git\\jgit");
481 String other = toOSPathString("C:\\Git\\test\\d\\f.txt");
482 String expectedCaseInsensitive = toOSPathString("..\\test\\d\\f.txt");
483 String expectedCaseSensitive = toOSPathString("..\\..\\Git\\test\\d\\f.txt");
484
485 if (systemReader.isWindows()) {
486 String actual = FileUtils.relativizeNativePath(base, other);
487 assertEquals(expectedCaseInsensitive, actual);
488 } else if (systemReader.isMacOS()) {
489 String actual = FileUtils.relativizeNativePath(base, other);
490 assertEquals(expectedCaseInsensitive, actual);
491 } else {
492 String actual = FileUtils.relativizeNativePath(base, other);
493 assertEquals(expectedCaseSensitive, actual);
494 }
495 }
496
497 @Test
498 public void testRelativize_scheme() {
499 String base = toOSPathString("file:/home/eclipse/runtime-New_configuration/project_1/file.java");
500 String other = toOSPathString("file:/home/eclipse/runtime-New_configuration/project");
501
502 String expected = toOSPathString("../../project");
503
504 String actual = FileUtils.relativizeNativePath(base, other);
505 assertEquals(expected, actual);
506 }
507
508 @Test
509 public void testRelativize_equalPaths() {
510 String base = toOSPathString("file:/home/eclipse/runtime-New_configuration/project_1");
511 String other = toOSPathString("file:/home/eclipse/runtime-New_configuration/project_1");
512 String expected = "";
513
514 String actual = FileUtils.relativizeNativePath(base, other);
515 assertEquals(expected, actual);
516 }
517
518 @Test
519 public void testRelativize_whitespaces() {
520 String base = toOSPathString("/home/eclipse 3.4/runtime New_configuration/project_1");
521 String other = toOSPathString("/home/eclipse 3.4/runtime New_configuration/project_1/file");
522 String expected = "file";
523
524 String actual = FileUtils.relativizeNativePath(base, other);
525 assertEquals(expected, actual);
526 }
527
528 @Test
529 public void testDeleteSymlinkToDirectoryDoesNotDeleteTarget()
530 throws IOException {
531 org.junit.Assume.assumeTrue(FS.DETECTED.supportsSymlinks());
532 FS fs = FS.DETECTED;
533 File dir = new File(trash, "dir");
534 File file = new File(dir, "file");
535 File link = new File(trash, "link");
536 FileUtils.mkdirs(dir);
537 FileUtils.createNewFile(file);
538 fs.createSymLink(link, "dir");
539 FileUtils.delete(link, FileUtils.RECURSIVE);
540 assertFalse(link.exists());
541 assertTrue(dir.exists());
542 assertTrue(file.exists());
543 }
544
545 @Test
546 public void testAtomicMove() throws IOException {
547 File src = new File(trash, "src");
548 Files.createFile(src.toPath());
549 File dst = new File(trash, "dst");
550 FileUtils.rename(src, dst, StandardCopyOption.ATOMIC_MOVE);
551 assertFalse(Files.exists(src.toPath()));
552 assertTrue(Files.exists(dst.toPath()));
553 }
554
555 private String toOSPathString(String path) {
556 return path.replaceAll("/|\\\\",
557 Matcher.quoteReplacement(File.separator));
558 }
559
560 @Test
561 public void testIsStaleFileHandleWithDirectCause() throws Exception {
562 assertTrue(FileUtils.isStaleFileHandle(IO_EXCEPTION));
563 }
564
565 @Test
566 public void testIsStaleFileHandleWithIndirectCause() throws Exception {
567 assertFalse(
568 FileUtils.isStaleFileHandle(IO_EXCEPTION_WITH_CAUSE));
569 }
570
571 @Test
572 public void testIsStaleFileHandleInCausalChainWithDirectCause()
573 throws Exception {
574 assertTrue(
575 FileUtils.isStaleFileHandleInCausalChain(IO_EXCEPTION));
576 }
577
578 @Test
579 public void testIsStaleFileHandleInCausalChainWithIndirectCause()
580 throws Exception {
581 assertTrue(FileUtils
582 .isStaleFileHandleInCausalChain(IO_EXCEPTION_WITH_CAUSE));
583 }
584 }