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