]> git.lizzy.rs Git - rust.git/blob - library/std/src/fs/tests.rs
cc856b4cd45c53f4433791294178056cd5186dac
[rust.git] / library / std / src / fs / tests.rs
1 use crate::io::prelude::*;
2
3 use crate::fs::{self, File, OpenOptions};
4 use crate::io::{ErrorKind, SeekFrom};
5 use crate::path::Path;
6 use crate::str;
7 use crate::sys_common::io::test::{tmpdir, TempDir};
8 use crate::thread;
9
10 use rand::{rngs::StdRng, RngCore, SeedableRng};
11
12 #[cfg(unix)]
13 use crate::os::unix::fs::symlink as symlink_dir;
14 #[cfg(unix)]
15 use crate::os::unix::fs::symlink as symlink_file;
16 #[cfg(unix)]
17 use crate::os::unix::fs::symlink as symlink_junction;
18 #[cfg(windows)]
19 use crate::os::windows::fs::{symlink_dir, symlink_file};
20 #[cfg(windows)]
21 use crate::sys::fs::symlink_junction;
22
23 macro_rules! check {
24     ($e:expr) => {
25         match $e {
26             Ok(t) => t,
27             Err(e) => panic!("{} failed with: {}", stringify!($e), e),
28         }
29     };
30 }
31
32 #[cfg(windows)]
33 macro_rules! error {
34     ($e:expr, $s:expr) => {
35         match $e {
36             Ok(_) => panic!("Unexpected success. Should've been: {:?}", $s),
37             Err(ref err) => assert!(
38                 err.raw_os_error() == Some($s),
39                 format!("`{}` did not have a code of `{}`", err, $s)
40             ),
41         }
42     };
43 }
44
45 #[cfg(unix)]
46 macro_rules! error {
47     ($e:expr, $s:expr) => {
48         error_contains!($e, $s)
49     };
50 }
51
52 macro_rules! error_contains {
53     ($e:expr, $s:expr) => {
54         match $e {
55             Ok(_) => panic!("Unexpected success. Should've been: {:?}", $s),
56             Err(ref err) => {
57                 assert!(err.to_string().contains($s), format!("`{}` did not contain `{}`", err, $s))
58             }
59         }
60     };
61 }
62
63 // Several test fail on windows if the user does not have permission to
64 // create symlinks (the `SeCreateSymbolicLinkPrivilege`). Instead of
65 // disabling these test on Windows, use this function to test whether we
66 // have permission, and return otherwise. This way, we still don't run these
67 // tests most of the time, but at least we do if the user has the right
68 // permissions.
69 pub fn got_symlink_permission(tmpdir: &TempDir) -> bool {
70     if cfg!(unix) {
71         return true;
72     }
73     let link = tmpdir.join("some_hopefully_unique_link_name");
74
75     match symlink_file(r"nonexisting_target", link) {
76         // ERROR_PRIVILEGE_NOT_HELD = 1314
77         Err(ref err) if err.raw_os_error() == Some(1314) => false,
78         Ok(_) | Err(_) => true,
79     }
80 }
81
82 #[test]
83 fn file_test_io_smoke_test() {
84     let message = "it's alright. have a good time";
85     let tmpdir = tmpdir();
86     let filename = &tmpdir.join("file_rt_io_file_test.txt");
87     {
88         let mut write_stream = check!(File::create(filename));
89         check!(write_stream.write(message.as_bytes()));
90     }
91     {
92         let mut read_stream = check!(File::open(filename));
93         let mut read_buf = [0; 1028];
94         let read_str = match check!(read_stream.read(&mut read_buf)) {
95             0 => panic!("shouldn't happen"),
96             n => str::from_utf8(&read_buf[..n]).unwrap().to_string(),
97         };
98         assert_eq!(read_str, message);
99     }
100     check!(fs::remove_file(filename));
101 }
102
103 #[test]
104 fn invalid_path_raises() {
105     let tmpdir = tmpdir();
106     let filename = &tmpdir.join("file_that_does_not_exist.txt");
107     let result = File::open(filename);
108
109     #[cfg(all(unix, not(target_os = "vxworks")))]
110     error!(result, "No such file or directory");
111     #[cfg(target_os = "vxworks")]
112     error!(result, "no such file or directory");
113     #[cfg(windows)]
114     error!(result, 2); // ERROR_FILE_NOT_FOUND
115 }
116
117 #[test]
118 fn file_test_iounlinking_invalid_path_should_raise_condition() {
119     let tmpdir = tmpdir();
120     let filename = &tmpdir.join("file_another_file_that_does_not_exist.txt");
121
122     let result = fs::remove_file(filename);
123
124     #[cfg(all(unix, not(target_os = "vxworks")))]
125     error!(result, "No such file or directory");
126     #[cfg(target_os = "vxworks")]
127     error!(result, "no such file or directory");
128     #[cfg(windows)]
129     error!(result, 2); // ERROR_FILE_NOT_FOUND
130 }
131
132 #[test]
133 fn file_test_io_non_positional_read() {
134     let message: &str = "ten-four";
135     let mut read_mem = [0; 8];
136     let tmpdir = tmpdir();
137     let filename = &tmpdir.join("file_rt_io_file_test_positional.txt");
138     {
139         let mut rw_stream = check!(File::create(filename));
140         check!(rw_stream.write(message.as_bytes()));
141     }
142     {
143         let mut read_stream = check!(File::open(filename));
144         {
145             let read_buf = &mut read_mem[0..4];
146             check!(read_stream.read(read_buf));
147         }
148         {
149             let read_buf = &mut read_mem[4..8];
150             check!(read_stream.read(read_buf));
151         }
152     }
153     check!(fs::remove_file(filename));
154     let read_str = str::from_utf8(&read_mem).unwrap();
155     assert_eq!(read_str, message);
156 }
157
158 #[test]
159 fn file_test_io_seek_and_tell_smoke_test() {
160     let message = "ten-four";
161     let mut read_mem = [0; 4];
162     let set_cursor = 4 as u64;
163     let tell_pos_pre_read;
164     let tell_pos_post_read;
165     let tmpdir = tmpdir();
166     let filename = &tmpdir.join("file_rt_io_file_test_seeking.txt");
167     {
168         let mut rw_stream = check!(File::create(filename));
169         check!(rw_stream.write(message.as_bytes()));
170     }
171     {
172         let mut read_stream = check!(File::open(filename));
173         check!(read_stream.seek(SeekFrom::Start(set_cursor)));
174         tell_pos_pre_read = check!(read_stream.seek(SeekFrom::Current(0)));
175         check!(read_stream.read(&mut read_mem));
176         tell_pos_post_read = check!(read_stream.seek(SeekFrom::Current(0)));
177     }
178     check!(fs::remove_file(filename));
179     let read_str = str::from_utf8(&read_mem).unwrap();
180     assert_eq!(read_str, &message[4..8]);
181     assert_eq!(tell_pos_pre_read, set_cursor);
182     assert_eq!(tell_pos_post_read, message.len() as u64);
183 }
184
185 #[test]
186 fn file_test_io_seek_and_write() {
187     let initial_msg = "food-is-yummy";
188     let overwrite_msg = "-the-bar!!";
189     let final_msg = "foo-the-bar!!";
190     let seek_idx = 3;
191     let mut read_mem = [0; 13];
192     let tmpdir = tmpdir();
193     let filename = &tmpdir.join("file_rt_io_file_test_seek_and_write.txt");
194     {
195         let mut rw_stream = check!(File::create(filename));
196         check!(rw_stream.write(initial_msg.as_bytes()));
197         check!(rw_stream.seek(SeekFrom::Start(seek_idx)));
198         check!(rw_stream.write(overwrite_msg.as_bytes()));
199     }
200     {
201         let mut read_stream = check!(File::open(filename));
202         check!(read_stream.read(&mut read_mem));
203     }
204     check!(fs::remove_file(filename));
205     let read_str = str::from_utf8(&read_mem).unwrap();
206     assert!(read_str == final_msg);
207 }
208
209 #[test]
210 fn file_test_io_seek_shakedown() {
211     //                   01234567890123
212     let initial_msg = "qwer-asdf-zxcv";
213     let chunk_one: &str = "qwer";
214     let chunk_two: &str = "asdf";
215     let chunk_three: &str = "zxcv";
216     let mut read_mem = [0; 4];
217     let tmpdir = tmpdir();
218     let filename = &tmpdir.join("file_rt_io_file_test_seek_shakedown.txt");
219     {
220         let mut rw_stream = check!(File::create(filename));
221         check!(rw_stream.write(initial_msg.as_bytes()));
222     }
223     {
224         let mut read_stream = check!(File::open(filename));
225
226         check!(read_stream.seek(SeekFrom::End(-4)));
227         check!(read_stream.read(&mut read_mem));
228         assert_eq!(str::from_utf8(&read_mem).unwrap(), chunk_three);
229
230         check!(read_stream.seek(SeekFrom::Current(-9)));
231         check!(read_stream.read(&mut read_mem));
232         assert_eq!(str::from_utf8(&read_mem).unwrap(), chunk_two);
233
234         check!(read_stream.seek(SeekFrom::Start(0)));
235         check!(read_stream.read(&mut read_mem));
236         assert_eq!(str::from_utf8(&read_mem).unwrap(), chunk_one);
237     }
238     check!(fs::remove_file(filename));
239 }
240
241 #[test]
242 fn file_test_io_eof() {
243     let tmpdir = tmpdir();
244     let filename = tmpdir.join("file_rt_io_file_test_eof.txt");
245     let mut buf = [0; 256];
246     {
247         let oo = OpenOptions::new().create_new(true).write(true).read(true).clone();
248         let mut rw = check!(oo.open(&filename));
249         assert_eq!(check!(rw.read(&mut buf)), 0);
250         assert_eq!(check!(rw.read(&mut buf)), 0);
251     }
252     check!(fs::remove_file(&filename));
253 }
254
255 #[test]
256 #[cfg(unix)]
257 fn file_test_io_read_write_at() {
258     use crate::os::unix::fs::FileExt;
259
260     let tmpdir = tmpdir();
261     let filename = tmpdir.join("file_rt_io_file_test_read_write_at.txt");
262     let mut buf = [0; 256];
263     let write1 = "asdf";
264     let write2 = "qwer-";
265     let write3 = "-zxcv";
266     let content = "qwer-asdf-zxcv";
267     {
268         let oo = OpenOptions::new().create_new(true).write(true).read(true).clone();
269         let mut rw = check!(oo.open(&filename));
270         assert_eq!(check!(rw.write_at(write1.as_bytes(), 5)), write1.len());
271         assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 0);
272         assert_eq!(check!(rw.read_at(&mut buf, 5)), write1.len());
273         assert_eq!(str::from_utf8(&buf[..write1.len()]), Ok(write1));
274         assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 0);
275         assert_eq!(check!(rw.read_at(&mut buf[..write2.len()], 0)), write2.len());
276         assert_eq!(str::from_utf8(&buf[..write2.len()]), Ok("\0\0\0\0\0"));
277         assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 0);
278         assert_eq!(check!(rw.write(write2.as_bytes())), write2.len());
279         assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 5);
280         assert_eq!(check!(rw.read(&mut buf)), write1.len());
281         assert_eq!(str::from_utf8(&buf[..write1.len()]), Ok(write1));
282         assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 9);
283         assert_eq!(check!(rw.read_at(&mut buf[..write2.len()], 0)), write2.len());
284         assert_eq!(str::from_utf8(&buf[..write2.len()]), Ok(write2));
285         assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 9);
286         assert_eq!(check!(rw.write_at(write3.as_bytes(), 9)), write3.len());
287         assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 9);
288     }
289     {
290         let mut read = check!(File::open(&filename));
291         assert_eq!(check!(read.read_at(&mut buf, 0)), content.len());
292         assert_eq!(str::from_utf8(&buf[..content.len()]), Ok(content));
293         assert_eq!(check!(read.seek(SeekFrom::Current(0))), 0);
294         assert_eq!(check!(read.seek(SeekFrom::End(-5))), 9);
295         assert_eq!(check!(read.read_at(&mut buf, 0)), content.len());
296         assert_eq!(str::from_utf8(&buf[..content.len()]), Ok(content));
297         assert_eq!(check!(read.seek(SeekFrom::Current(0))), 9);
298         assert_eq!(check!(read.read(&mut buf)), write3.len());
299         assert_eq!(str::from_utf8(&buf[..write3.len()]), Ok(write3));
300         assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14);
301         assert_eq!(check!(read.read_at(&mut buf, 0)), content.len());
302         assert_eq!(str::from_utf8(&buf[..content.len()]), Ok(content));
303         assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14);
304         assert_eq!(check!(read.read_at(&mut buf, 14)), 0);
305         assert_eq!(check!(read.read_at(&mut buf, 15)), 0);
306         assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14);
307     }
308     check!(fs::remove_file(&filename));
309 }
310
311 #[test]
312 #[cfg(unix)]
313 fn set_get_unix_permissions() {
314     use crate::os::unix::fs::PermissionsExt;
315
316     let tmpdir = tmpdir();
317     let filename = &tmpdir.join("set_get_unix_permissions");
318     check!(fs::create_dir(filename));
319     let mask = 0o7777;
320
321     check!(fs::set_permissions(filename, fs::Permissions::from_mode(0)));
322     let metadata0 = check!(fs::metadata(filename));
323     assert_eq!(mask & metadata0.permissions().mode(), 0);
324
325     check!(fs::set_permissions(filename, fs::Permissions::from_mode(0o1777)));
326     let metadata1 = check!(fs::metadata(filename));
327     #[cfg(all(unix, not(target_os = "vxworks")))]
328     assert_eq!(mask & metadata1.permissions().mode(), 0o1777);
329     #[cfg(target_os = "vxworks")]
330     assert_eq!(mask & metadata1.permissions().mode(), 0o0777);
331 }
332
333 #[test]
334 #[cfg(windows)]
335 fn file_test_io_seek_read_write() {
336     use crate::os::windows::fs::FileExt;
337
338     let tmpdir = tmpdir();
339     let filename = tmpdir.join("file_rt_io_file_test_seek_read_write.txt");
340     let mut buf = [0; 256];
341     let write1 = "asdf";
342     let write2 = "qwer-";
343     let write3 = "-zxcv";
344     let content = "qwer-asdf-zxcv";
345     {
346         let oo = OpenOptions::new().create_new(true).write(true).read(true).clone();
347         let mut rw = check!(oo.open(&filename));
348         assert_eq!(check!(rw.seek_write(write1.as_bytes(), 5)), write1.len());
349         assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 9);
350         assert_eq!(check!(rw.seek_read(&mut buf, 5)), write1.len());
351         assert_eq!(str::from_utf8(&buf[..write1.len()]), Ok(write1));
352         assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 9);
353         assert_eq!(check!(rw.seek(SeekFrom::Start(0))), 0);
354         assert_eq!(check!(rw.write(write2.as_bytes())), write2.len());
355         assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 5);
356         assert_eq!(check!(rw.read(&mut buf)), write1.len());
357         assert_eq!(str::from_utf8(&buf[..write1.len()]), Ok(write1));
358         assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 9);
359         assert_eq!(check!(rw.seek_read(&mut buf[..write2.len()], 0)), write2.len());
360         assert_eq!(str::from_utf8(&buf[..write2.len()]), Ok(write2));
361         assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 5);
362         assert_eq!(check!(rw.seek_write(write3.as_bytes(), 9)), write3.len());
363         assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 14);
364     }
365     {
366         let mut read = check!(File::open(&filename));
367         assert_eq!(check!(read.seek_read(&mut buf, 0)), content.len());
368         assert_eq!(str::from_utf8(&buf[..content.len()]), Ok(content));
369         assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14);
370         assert_eq!(check!(read.seek(SeekFrom::End(-5))), 9);
371         assert_eq!(check!(read.seek_read(&mut buf, 0)), content.len());
372         assert_eq!(str::from_utf8(&buf[..content.len()]), Ok(content));
373         assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14);
374         assert_eq!(check!(read.seek(SeekFrom::End(-5))), 9);
375         assert_eq!(check!(read.read(&mut buf)), write3.len());
376         assert_eq!(str::from_utf8(&buf[..write3.len()]), Ok(write3));
377         assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14);
378         assert_eq!(check!(read.seek_read(&mut buf, 0)), content.len());
379         assert_eq!(str::from_utf8(&buf[..content.len()]), Ok(content));
380         assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14);
381         assert_eq!(check!(read.seek_read(&mut buf, 14)), 0);
382         assert_eq!(check!(read.seek_read(&mut buf, 15)), 0);
383     }
384     check!(fs::remove_file(&filename));
385 }
386
387 #[test]
388 fn file_test_stat_is_correct_on_is_file() {
389     let tmpdir = tmpdir();
390     let filename = &tmpdir.join("file_stat_correct_on_is_file.txt");
391     {
392         let mut opts = OpenOptions::new();
393         let mut fs = check!(opts.read(true).write(true).create(true).open(filename));
394         let msg = "hw";
395         fs.write(msg.as_bytes()).unwrap();
396
397         let fstat_res = check!(fs.metadata());
398         assert!(fstat_res.is_file());
399     }
400     let stat_res_fn = check!(fs::metadata(filename));
401     assert!(stat_res_fn.is_file());
402     let stat_res_meth = check!(filename.metadata());
403     assert!(stat_res_meth.is_file());
404     check!(fs::remove_file(filename));
405 }
406
407 #[test]
408 fn file_test_stat_is_correct_on_is_dir() {
409     let tmpdir = tmpdir();
410     let filename = &tmpdir.join("file_stat_correct_on_is_dir");
411     check!(fs::create_dir(filename));
412     let stat_res_fn = check!(fs::metadata(filename));
413     assert!(stat_res_fn.is_dir());
414     let stat_res_meth = check!(filename.metadata());
415     assert!(stat_res_meth.is_dir());
416     check!(fs::remove_dir(filename));
417 }
418
419 #[test]
420 fn file_test_fileinfo_false_when_checking_is_file_on_a_directory() {
421     let tmpdir = tmpdir();
422     let dir = &tmpdir.join("fileinfo_false_on_dir");
423     check!(fs::create_dir(dir));
424     assert!(!dir.is_file());
425     check!(fs::remove_dir(dir));
426 }
427
428 #[test]
429 fn file_test_fileinfo_check_exists_before_and_after_file_creation() {
430     let tmpdir = tmpdir();
431     let file = &tmpdir.join("fileinfo_check_exists_b_and_a.txt");
432     check!(check!(File::create(file)).write(b"foo"));
433     assert!(file.exists());
434     check!(fs::remove_file(file));
435     assert!(!file.exists());
436 }
437
438 #[test]
439 fn file_test_directoryinfo_check_exists_before_and_after_mkdir() {
440     let tmpdir = tmpdir();
441     let dir = &tmpdir.join("before_and_after_dir");
442     assert!(!dir.exists());
443     check!(fs::create_dir(dir));
444     assert!(dir.exists());
445     assert!(dir.is_dir());
446     check!(fs::remove_dir(dir));
447     assert!(!dir.exists());
448 }
449
450 #[test]
451 fn file_test_directoryinfo_readdir() {
452     let tmpdir = tmpdir();
453     let dir = &tmpdir.join("di_readdir");
454     check!(fs::create_dir(dir));
455     let prefix = "foo";
456     for n in 0..3 {
457         let f = dir.join(&format!("{}.txt", n));
458         let mut w = check!(File::create(&f));
459         let msg_str = format!("{}{}", prefix, n.to_string());
460         let msg = msg_str.as_bytes();
461         check!(w.write(msg));
462     }
463     let files = check!(fs::read_dir(dir));
464     let mut mem = [0; 4];
465     for f in files {
466         let f = f.unwrap().path();
467         {
468             let n = f.file_stem().unwrap();
469             check!(check!(File::open(&f)).read(&mut mem));
470             let read_str = str::from_utf8(&mem).unwrap();
471             let expected = format!("{}{}", prefix, n.to_str().unwrap());
472             assert_eq!(expected, read_str);
473         }
474         check!(fs::remove_file(&f));
475     }
476     check!(fs::remove_dir(dir));
477 }
478
479 #[test]
480 fn file_create_new_already_exists_error() {
481     let tmpdir = tmpdir();
482     let file = &tmpdir.join("file_create_new_error_exists");
483     check!(fs::File::create(file));
484     let e = fs::OpenOptions::new().write(true).create_new(true).open(file).unwrap_err();
485     assert_eq!(e.kind(), ErrorKind::AlreadyExists);
486 }
487
488 #[test]
489 fn mkdir_path_already_exists_error() {
490     let tmpdir = tmpdir();
491     let dir = &tmpdir.join("mkdir_error_twice");
492     check!(fs::create_dir(dir));
493     let e = fs::create_dir(dir).unwrap_err();
494     assert_eq!(e.kind(), ErrorKind::AlreadyExists);
495 }
496
497 #[test]
498 fn recursive_mkdir() {
499     let tmpdir = tmpdir();
500     let dir = tmpdir.join("d1/d2");
501     check!(fs::create_dir_all(&dir));
502     assert!(dir.is_dir())
503 }
504
505 #[test]
506 fn recursive_mkdir_failure() {
507     let tmpdir = tmpdir();
508     let dir = tmpdir.join("d1");
509     let file = dir.join("f1");
510
511     check!(fs::create_dir_all(&dir));
512     check!(File::create(&file));
513
514     let result = fs::create_dir_all(&file);
515
516     assert!(result.is_err());
517 }
518
519 #[test]
520 fn concurrent_recursive_mkdir() {
521     for _ in 0..100 {
522         let dir = tmpdir();
523         let mut dir = dir.join("a");
524         for _ in 0..40 {
525             dir = dir.join("a");
526         }
527         let mut join = vec![];
528         for _ in 0..8 {
529             let dir = dir.clone();
530             join.push(thread::spawn(move || {
531                 check!(fs::create_dir_all(&dir));
532             }))
533         }
534
535         // No `Display` on result of `join()`
536         join.drain(..).map(|join| join.join().unwrap()).count();
537     }
538 }
539
540 #[test]
541 fn recursive_mkdir_slash() {
542     check!(fs::create_dir_all(Path::new("/")));
543 }
544
545 #[test]
546 fn recursive_mkdir_dot() {
547     check!(fs::create_dir_all(Path::new(".")));
548 }
549
550 #[test]
551 fn recursive_mkdir_empty() {
552     check!(fs::create_dir_all(Path::new("")));
553 }
554
555 #[test]
556 fn recursive_rmdir() {
557     let tmpdir = tmpdir();
558     let d1 = tmpdir.join("d1");
559     let dt = d1.join("t");
560     let dtt = dt.join("t");
561     let d2 = tmpdir.join("d2");
562     let canary = d2.join("do_not_delete");
563     check!(fs::create_dir_all(&dtt));
564     check!(fs::create_dir_all(&d2));
565     check!(check!(File::create(&canary)).write(b"foo"));
566     check!(symlink_junction(&d2, &dt.join("d2")));
567     let _ = symlink_file(&canary, &d1.join("canary"));
568     check!(fs::remove_dir_all(&d1));
569
570     assert!(!d1.is_dir());
571     assert!(canary.exists());
572 }
573
574 #[test]
575 fn recursive_rmdir_of_symlink() {
576     // test we do not recursively delete a symlink but only dirs.
577     let tmpdir = tmpdir();
578     let link = tmpdir.join("d1");
579     let dir = tmpdir.join("d2");
580     let canary = dir.join("do_not_delete");
581     check!(fs::create_dir_all(&dir));
582     check!(check!(File::create(&canary)).write(b"foo"));
583     check!(symlink_junction(&dir, &link));
584     check!(fs::remove_dir_all(&link));
585
586     assert!(!link.is_dir());
587     assert!(canary.exists());
588 }
589
590 #[test]
591 // only Windows makes a distinction between file and directory symlinks.
592 #[cfg(windows)]
593 fn recursive_rmdir_of_file_symlink() {
594     let tmpdir = tmpdir();
595     if !got_symlink_permission(&tmpdir) {
596         return;
597     };
598
599     let f1 = tmpdir.join("f1");
600     let f2 = tmpdir.join("f2");
601     check!(check!(File::create(&f1)).write(b"foo"));
602     check!(symlink_file(&f1, &f2));
603     match fs::remove_dir_all(&f2) {
604         Ok(..) => panic!("wanted a failure"),
605         Err(..) => {}
606     }
607 }
608
609 #[test]
610 fn unicode_path_is_dir() {
611     assert!(Path::new(".").is_dir());
612     assert!(!Path::new("test/stdtest/fs.rs").is_dir());
613
614     let tmpdir = tmpdir();
615
616     let mut dirpath = tmpdir.path().to_path_buf();
617     dirpath.push("test-가一ー你好");
618     check!(fs::create_dir(&dirpath));
619     assert!(dirpath.is_dir());
620
621     let mut filepath = dirpath;
622     filepath.push("unicode-file-\u{ac00}\u{4e00}\u{30fc}\u{4f60}\u{597d}.rs");
623     check!(File::create(&filepath)); // ignore return; touch only
624     assert!(!filepath.is_dir());
625     assert!(filepath.exists());
626 }
627
628 #[test]
629 fn unicode_path_exists() {
630     assert!(Path::new(".").exists());
631     assert!(!Path::new("test/nonexistent-bogus-path").exists());
632
633     let tmpdir = tmpdir();
634     let unicode = tmpdir.path();
635     let unicode = unicode.join("test-각丁ー再见");
636     check!(fs::create_dir(&unicode));
637     assert!(unicode.exists());
638     assert!(!Path::new("test/unicode-bogus-path-각丁ー再见").exists());
639 }
640
641 #[test]
642 fn copy_file_does_not_exist() {
643     let from = Path::new("test/nonexistent-bogus-path");
644     let to = Path::new("test/other-bogus-path");
645
646     match fs::copy(&from, &to) {
647         Ok(..) => panic!(),
648         Err(..) => {
649             assert!(!from.exists());
650             assert!(!to.exists());
651         }
652     }
653 }
654
655 #[test]
656 fn copy_src_does_not_exist() {
657     let tmpdir = tmpdir();
658     let from = Path::new("test/nonexistent-bogus-path");
659     let to = tmpdir.join("out.txt");
660     check!(check!(File::create(&to)).write(b"hello"));
661     assert!(fs::copy(&from, &to).is_err());
662     assert!(!from.exists());
663     let mut v = Vec::new();
664     check!(check!(File::open(&to)).read_to_end(&mut v));
665     assert_eq!(v, b"hello");
666 }
667
668 #[test]
669 fn copy_file_ok() {
670     let tmpdir = tmpdir();
671     let input = tmpdir.join("in.txt");
672     let out = tmpdir.join("out.txt");
673
674     check!(check!(File::create(&input)).write(b"hello"));
675     check!(fs::copy(&input, &out));
676     let mut v = Vec::new();
677     check!(check!(File::open(&out)).read_to_end(&mut v));
678     assert_eq!(v, b"hello");
679
680     assert_eq!(check!(input.metadata()).permissions(), check!(out.metadata()).permissions());
681 }
682
683 #[test]
684 fn copy_file_dst_dir() {
685     let tmpdir = tmpdir();
686     let out = tmpdir.join("out");
687
688     check!(File::create(&out));
689     match fs::copy(&*out, tmpdir.path()) {
690         Ok(..) => panic!(),
691         Err(..) => {}
692     }
693 }
694
695 #[test]
696 fn copy_file_dst_exists() {
697     let tmpdir = tmpdir();
698     let input = tmpdir.join("in");
699     let output = tmpdir.join("out");
700
701     check!(check!(File::create(&input)).write("foo".as_bytes()));
702     check!(check!(File::create(&output)).write("bar".as_bytes()));
703     check!(fs::copy(&input, &output));
704
705     let mut v = Vec::new();
706     check!(check!(File::open(&output)).read_to_end(&mut v));
707     assert_eq!(v, b"foo".to_vec());
708 }
709
710 #[test]
711 fn copy_file_src_dir() {
712     let tmpdir = tmpdir();
713     let out = tmpdir.join("out");
714
715     match fs::copy(tmpdir.path(), &out) {
716         Ok(..) => panic!(),
717         Err(..) => {}
718     }
719     assert!(!out.exists());
720 }
721
722 #[test]
723 fn copy_file_preserves_perm_bits() {
724     let tmpdir = tmpdir();
725     let input = tmpdir.join("in.txt");
726     let out = tmpdir.join("out.txt");
727
728     let attr = check!(check!(File::create(&input)).metadata());
729     let mut p = attr.permissions();
730     p.set_readonly(true);
731     check!(fs::set_permissions(&input, p));
732     check!(fs::copy(&input, &out));
733     assert!(check!(out.metadata()).permissions().readonly());
734     check!(fs::set_permissions(&input, attr.permissions()));
735     check!(fs::set_permissions(&out, attr.permissions()));
736 }
737
738 #[test]
739 #[cfg(windows)]
740 fn copy_file_preserves_streams() {
741     let tmp = tmpdir();
742     check!(check!(File::create(tmp.join("in.txt:bunny"))).write("carrot".as_bytes()));
743     assert_eq!(check!(fs::copy(tmp.join("in.txt"), tmp.join("out.txt"))), 0);
744     assert_eq!(check!(tmp.join("out.txt").metadata()).len(), 0);
745     let mut v = Vec::new();
746     check!(check!(File::open(tmp.join("out.txt:bunny"))).read_to_end(&mut v));
747     assert_eq!(v, b"carrot".to_vec());
748 }
749
750 #[test]
751 fn copy_file_returns_metadata_len() {
752     let tmp = tmpdir();
753     let in_path = tmp.join("in.txt");
754     let out_path = tmp.join("out.txt");
755     check!(check!(File::create(&in_path)).write(b"lettuce"));
756     #[cfg(windows)]
757     check!(check!(File::create(tmp.join("in.txt:bunny"))).write(b"carrot"));
758     let copied_len = check!(fs::copy(&in_path, &out_path));
759     assert_eq!(check!(out_path.metadata()).len(), copied_len);
760 }
761
762 #[test]
763 fn copy_file_follows_dst_symlink() {
764     let tmp = tmpdir();
765     if !got_symlink_permission(&tmp) {
766         return;
767     };
768
769     let in_path = tmp.join("in.txt");
770     let out_path = tmp.join("out.txt");
771     let out_path_symlink = tmp.join("out_symlink.txt");
772
773     check!(fs::write(&in_path, "foo"));
774     check!(fs::write(&out_path, "bar"));
775     check!(symlink_file(&out_path, &out_path_symlink));
776
777     check!(fs::copy(&in_path, &out_path_symlink));
778
779     assert!(check!(out_path_symlink.symlink_metadata()).file_type().is_symlink());
780     assert_eq!(check!(fs::read(&out_path_symlink)), b"foo".to_vec());
781     assert_eq!(check!(fs::read(&out_path)), b"foo".to_vec());
782 }
783
784 #[test]
785 fn symlinks_work() {
786     let tmpdir = tmpdir();
787     if !got_symlink_permission(&tmpdir) {
788         return;
789     };
790
791     let input = tmpdir.join("in.txt");
792     let out = tmpdir.join("out.txt");
793
794     check!(check!(File::create(&input)).write("foobar".as_bytes()));
795     check!(symlink_file(&input, &out));
796     assert!(check!(out.symlink_metadata()).file_type().is_symlink());
797     assert_eq!(check!(fs::metadata(&out)).len(), check!(fs::metadata(&input)).len());
798     let mut v = Vec::new();
799     check!(check!(File::open(&out)).read_to_end(&mut v));
800     assert_eq!(v, b"foobar".to_vec());
801 }
802
803 #[test]
804 fn symlink_noexist() {
805     // Symlinks can point to things that don't exist
806     let tmpdir = tmpdir();
807     if !got_symlink_permission(&tmpdir) {
808         return;
809     };
810
811     // Use a relative path for testing. Symlinks get normalized by Windows,
812     // so we may not get the same path back for absolute paths
813     check!(symlink_file(&"foo", &tmpdir.join("bar")));
814     assert_eq!(check!(fs::read_link(&tmpdir.join("bar"))).to_str().unwrap(), "foo");
815 }
816
817 #[test]
818 fn read_link() {
819     if cfg!(windows) {
820         // directory symlink
821         assert_eq!(
822             check!(fs::read_link(r"C:\Users\All Users")).to_str().unwrap(),
823             r"C:\ProgramData"
824         );
825         // junction
826         assert_eq!(
827             check!(fs::read_link(r"C:\Users\Default User")).to_str().unwrap(),
828             r"C:\Users\Default"
829         );
830         // junction with special permissions
831         assert_eq!(
832             check!(fs::read_link(r"C:\Documents and Settings\")).to_str().unwrap(),
833             r"C:\Users"
834         );
835     }
836     let tmpdir = tmpdir();
837     let link = tmpdir.join("link");
838     if !got_symlink_permission(&tmpdir) {
839         return;
840     };
841     check!(symlink_file(&"foo", &link));
842     assert_eq!(check!(fs::read_link(&link)).to_str().unwrap(), "foo");
843 }
844
845 #[test]
846 fn readlink_not_symlink() {
847     let tmpdir = tmpdir();
848     match fs::read_link(tmpdir.path()) {
849         Ok(..) => panic!("wanted a failure"),
850         Err(..) => {}
851     }
852 }
853
854 #[test]
855 fn links_work() {
856     let tmpdir = tmpdir();
857     let input = tmpdir.join("in.txt");
858     let out = tmpdir.join("out.txt");
859
860     check!(check!(File::create(&input)).write("foobar".as_bytes()));
861     check!(fs::hard_link(&input, &out));
862     assert_eq!(check!(fs::metadata(&out)).len(), check!(fs::metadata(&input)).len());
863     assert_eq!(check!(fs::metadata(&out)).len(), check!(input.metadata()).len());
864     let mut v = Vec::new();
865     check!(check!(File::open(&out)).read_to_end(&mut v));
866     assert_eq!(v, b"foobar".to_vec());
867
868     // can't link to yourself
869     match fs::hard_link(&input, &input) {
870         Ok(..) => panic!("wanted a failure"),
871         Err(..) => {}
872     }
873     // can't link to something that doesn't exist
874     match fs::hard_link(&tmpdir.join("foo"), &tmpdir.join("bar")) {
875         Ok(..) => panic!("wanted a failure"),
876         Err(..) => {}
877     }
878 }
879
880 #[test]
881 fn chmod_works() {
882     let tmpdir = tmpdir();
883     let file = tmpdir.join("in.txt");
884
885     check!(File::create(&file));
886     let attr = check!(fs::metadata(&file));
887     assert!(!attr.permissions().readonly());
888     let mut p = attr.permissions();
889     p.set_readonly(true);
890     check!(fs::set_permissions(&file, p.clone()));
891     let attr = check!(fs::metadata(&file));
892     assert!(attr.permissions().readonly());
893
894     match fs::set_permissions(&tmpdir.join("foo"), p.clone()) {
895         Ok(..) => panic!("wanted an error"),
896         Err(..) => {}
897     }
898
899     p.set_readonly(false);
900     check!(fs::set_permissions(&file, p));
901 }
902
903 #[test]
904 fn fchmod_works() {
905     let tmpdir = tmpdir();
906     let path = tmpdir.join("in.txt");
907
908     let file = check!(File::create(&path));
909     let attr = check!(fs::metadata(&path));
910     assert!(!attr.permissions().readonly());
911     let mut p = attr.permissions();
912     p.set_readonly(true);
913     check!(file.set_permissions(p.clone()));
914     let attr = check!(fs::metadata(&path));
915     assert!(attr.permissions().readonly());
916
917     p.set_readonly(false);
918     check!(file.set_permissions(p));
919 }
920
921 #[test]
922 fn sync_doesnt_kill_anything() {
923     let tmpdir = tmpdir();
924     let path = tmpdir.join("in.txt");
925
926     let mut file = check!(File::create(&path));
927     check!(file.sync_all());
928     check!(file.sync_data());
929     check!(file.write(b"foo"));
930     check!(file.sync_all());
931     check!(file.sync_data());
932 }
933
934 #[test]
935 fn truncate_works() {
936     let tmpdir = tmpdir();
937     let path = tmpdir.join("in.txt");
938
939     let mut file = check!(File::create(&path));
940     check!(file.write(b"foo"));
941     check!(file.sync_all());
942
943     // Do some simple things with truncation
944     assert_eq!(check!(file.metadata()).len(), 3);
945     check!(file.set_len(10));
946     assert_eq!(check!(file.metadata()).len(), 10);
947     check!(file.write(b"bar"));
948     check!(file.sync_all());
949     assert_eq!(check!(file.metadata()).len(), 10);
950
951     let mut v = Vec::new();
952     check!(check!(File::open(&path)).read_to_end(&mut v));
953     assert_eq!(v, b"foobar\0\0\0\0".to_vec());
954
955     // Truncate to a smaller length, don't seek, and then write something.
956     // Ensure that the intermediate zeroes are all filled in (we have `seek`ed
957     // past the end of the file).
958     check!(file.set_len(2));
959     assert_eq!(check!(file.metadata()).len(), 2);
960     check!(file.write(b"wut"));
961     check!(file.sync_all());
962     assert_eq!(check!(file.metadata()).len(), 9);
963     let mut v = Vec::new();
964     check!(check!(File::open(&path)).read_to_end(&mut v));
965     assert_eq!(v, b"fo\0\0\0\0wut".to_vec());
966 }
967
968 #[test]
969 fn open_flavors() {
970     use crate::fs::OpenOptions as OO;
971     fn c<T: Clone>(t: &T) -> T {
972         t.clone()
973     }
974
975     let tmpdir = tmpdir();
976
977     let mut r = OO::new();
978     r.read(true);
979     let mut w = OO::new();
980     w.write(true);
981     let mut rw = OO::new();
982     rw.read(true).write(true);
983     let mut a = OO::new();
984     a.append(true);
985     let mut ra = OO::new();
986     ra.read(true).append(true);
987
988     #[cfg(windows)]
989     let invalid_options = 87; // ERROR_INVALID_PARAMETER
990     #[cfg(all(unix, not(target_os = "vxworks")))]
991     let invalid_options = "Invalid argument";
992     #[cfg(target_os = "vxworks")]
993     let invalid_options = "invalid argument";
994
995     // Test various combinations of creation modes and access modes.
996     //
997     // Allowed:
998     // creation mode           | read  | write | read-write | append | read-append |
999     // :-----------------------|:-----:|:-----:|:----------:|:------:|:-----------:|
1000     // not set (open existing) |   X   |   X   |     X      |   X    |      X      |
1001     // create                  |       |   X   |     X      |   X    |      X      |
1002     // truncate                |       |   X   |     X      |        |             |
1003     // create and truncate     |       |   X   |     X      |        |             |
1004     // create_new              |       |   X   |     X      |   X    |      X      |
1005     //
1006     // tested in reverse order, so 'create_new' creates the file, and 'open existing' opens it.
1007
1008     // write-only
1009     check!(c(&w).create_new(true).open(&tmpdir.join("a")));
1010     check!(c(&w).create(true).truncate(true).open(&tmpdir.join("a")));
1011     check!(c(&w).truncate(true).open(&tmpdir.join("a")));
1012     check!(c(&w).create(true).open(&tmpdir.join("a")));
1013     check!(c(&w).open(&tmpdir.join("a")));
1014
1015     // read-only
1016     error!(c(&r).create_new(true).open(&tmpdir.join("b")), invalid_options);
1017     error!(c(&r).create(true).truncate(true).open(&tmpdir.join("b")), invalid_options);
1018     error!(c(&r).truncate(true).open(&tmpdir.join("b")), invalid_options);
1019     error!(c(&r).create(true).open(&tmpdir.join("b")), invalid_options);
1020     check!(c(&r).open(&tmpdir.join("a"))); // try opening the file created with write_only
1021
1022     // read-write
1023     check!(c(&rw).create_new(true).open(&tmpdir.join("c")));
1024     check!(c(&rw).create(true).truncate(true).open(&tmpdir.join("c")));
1025     check!(c(&rw).truncate(true).open(&tmpdir.join("c")));
1026     check!(c(&rw).create(true).open(&tmpdir.join("c")));
1027     check!(c(&rw).open(&tmpdir.join("c")));
1028
1029     // append
1030     check!(c(&a).create_new(true).open(&tmpdir.join("d")));
1031     error!(c(&a).create(true).truncate(true).open(&tmpdir.join("d")), invalid_options);
1032     error!(c(&a).truncate(true).open(&tmpdir.join("d")), invalid_options);
1033     check!(c(&a).create(true).open(&tmpdir.join("d")));
1034     check!(c(&a).open(&tmpdir.join("d")));
1035
1036     // read-append
1037     check!(c(&ra).create_new(true).open(&tmpdir.join("e")));
1038     error!(c(&ra).create(true).truncate(true).open(&tmpdir.join("e")), invalid_options);
1039     error!(c(&ra).truncate(true).open(&tmpdir.join("e")), invalid_options);
1040     check!(c(&ra).create(true).open(&tmpdir.join("e")));
1041     check!(c(&ra).open(&tmpdir.join("e")));
1042
1043     // Test opening a file without setting an access mode
1044     let mut blank = OO::new();
1045     error!(blank.create(true).open(&tmpdir.join("f")), invalid_options);
1046
1047     // Test write works
1048     check!(check!(File::create(&tmpdir.join("h"))).write("foobar".as_bytes()));
1049
1050     // Test write fails for read-only
1051     check!(r.open(&tmpdir.join("h")));
1052     {
1053         let mut f = check!(r.open(&tmpdir.join("h")));
1054         assert!(f.write("wut".as_bytes()).is_err());
1055     }
1056
1057     // Test write overwrites
1058     {
1059         let mut f = check!(c(&w).open(&tmpdir.join("h")));
1060         check!(f.write("baz".as_bytes()));
1061     }
1062     {
1063         let mut f = check!(c(&r).open(&tmpdir.join("h")));
1064         let mut b = vec![0; 6];
1065         check!(f.read(&mut b));
1066         assert_eq!(b, "bazbar".as_bytes());
1067     }
1068
1069     // Test truncate works
1070     {
1071         let mut f = check!(c(&w).truncate(true).open(&tmpdir.join("h")));
1072         check!(f.write("foo".as_bytes()));
1073     }
1074     assert_eq!(check!(fs::metadata(&tmpdir.join("h"))).len(), 3);
1075
1076     // Test append works
1077     assert_eq!(check!(fs::metadata(&tmpdir.join("h"))).len(), 3);
1078     {
1079         let mut f = check!(c(&a).open(&tmpdir.join("h")));
1080         check!(f.write("bar".as_bytes()));
1081     }
1082     assert_eq!(check!(fs::metadata(&tmpdir.join("h"))).len(), 6);
1083
1084     // Test .append(true) equals .write(true).append(true)
1085     {
1086         let mut f = check!(c(&w).append(true).open(&tmpdir.join("h")));
1087         check!(f.write("baz".as_bytes()));
1088     }
1089     assert_eq!(check!(fs::metadata(&tmpdir.join("h"))).len(), 9);
1090 }
1091
1092 #[test]
1093 fn _assert_send_sync() {
1094     fn _assert_send_sync<T: Send + Sync>() {}
1095     _assert_send_sync::<OpenOptions>();
1096 }
1097
1098 #[test]
1099 fn binary_file() {
1100     let mut bytes = [0; 1024];
1101     StdRng::from_entropy().fill_bytes(&mut bytes);
1102
1103     let tmpdir = tmpdir();
1104
1105     check!(check!(File::create(&tmpdir.join("test"))).write(&bytes));
1106     let mut v = Vec::new();
1107     check!(check!(File::open(&tmpdir.join("test"))).read_to_end(&mut v));
1108     assert!(v == &bytes[..]);
1109 }
1110
1111 #[test]
1112 fn write_then_read() {
1113     let mut bytes = [0; 1024];
1114     StdRng::from_entropy().fill_bytes(&mut bytes);
1115
1116     let tmpdir = tmpdir();
1117
1118     check!(fs::write(&tmpdir.join("test"), &bytes[..]));
1119     let v = check!(fs::read(&tmpdir.join("test")));
1120     assert!(v == &bytes[..]);
1121
1122     check!(fs::write(&tmpdir.join("not-utf8"), &[0xFF]));
1123     error_contains!(
1124         fs::read_to_string(&tmpdir.join("not-utf8")),
1125         "stream did not contain valid UTF-8"
1126     );
1127
1128     let s = "𐁁𐀓𐀠𐀴𐀍";
1129     check!(fs::write(&tmpdir.join("utf8"), s.as_bytes()));
1130     let string = check!(fs::read_to_string(&tmpdir.join("utf8")));
1131     assert_eq!(string, s);
1132 }
1133
1134 #[test]
1135 fn file_try_clone() {
1136     let tmpdir = tmpdir();
1137
1138     let mut f1 =
1139         check!(OpenOptions::new().read(true).write(true).create(true).open(&tmpdir.join("test")));
1140     let mut f2 = check!(f1.try_clone());
1141
1142     check!(f1.write_all(b"hello world"));
1143     check!(f1.seek(SeekFrom::Start(2)));
1144
1145     let mut buf = vec![];
1146     check!(f2.read_to_end(&mut buf));
1147     assert_eq!(buf, b"llo world");
1148     drop(f2);
1149
1150     check!(f1.write_all(b"!"));
1151 }
1152
1153 #[test]
1154 #[cfg(not(windows))]
1155 fn unlink_readonly() {
1156     let tmpdir = tmpdir();
1157     let path = tmpdir.join("file");
1158     check!(File::create(&path));
1159     let mut perm = check!(fs::metadata(&path)).permissions();
1160     perm.set_readonly(true);
1161     check!(fs::set_permissions(&path, perm));
1162     check!(fs::remove_file(&path));
1163 }
1164
1165 #[test]
1166 fn mkdir_trailing_slash() {
1167     let tmpdir = tmpdir();
1168     let path = tmpdir.join("file");
1169     check!(fs::create_dir_all(&path.join("a/")));
1170 }
1171
1172 #[test]
1173 fn canonicalize_works_simple() {
1174     let tmpdir = tmpdir();
1175     let tmpdir = fs::canonicalize(tmpdir.path()).unwrap();
1176     let file = tmpdir.join("test");
1177     File::create(&file).unwrap();
1178     assert_eq!(fs::canonicalize(&file).unwrap(), file);
1179 }
1180
1181 #[test]
1182 fn realpath_works() {
1183     let tmpdir = tmpdir();
1184     if !got_symlink_permission(&tmpdir) {
1185         return;
1186     };
1187
1188     let tmpdir = fs::canonicalize(tmpdir.path()).unwrap();
1189     let file = tmpdir.join("test");
1190     let dir = tmpdir.join("test2");
1191     let link = dir.join("link");
1192     let linkdir = tmpdir.join("test3");
1193
1194     File::create(&file).unwrap();
1195     fs::create_dir(&dir).unwrap();
1196     symlink_file(&file, &link).unwrap();
1197     symlink_dir(&dir, &linkdir).unwrap();
1198
1199     assert!(link.symlink_metadata().unwrap().file_type().is_symlink());
1200
1201     assert_eq!(fs::canonicalize(&tmpdir).unwrap(), tmpdir);
1202     assert_eq!(fs::canonicalize(&file).unwrap(), file);
1203     assert_eq!(fs::canonicalize(&link).unwrap(), file);
1204     assert_eq!(fs::canonicalize(&linkdir).unwrap(), dir);
1205     assert_eq!(fs::canonicalize(&linkdir.join("link")).unwrap(), file);
1206 }
1207
1208 #[test]
1209 fn realpath_works_tricky() {
1210     let tmpdir = tmpdir();
1211     if !got_symlink_permission(&tmpdir) {
1212         return;
1213     };
1214
1215     let tmpdir = fs::canonicalize(tmpdir.path()).unwrap();
1216     let a = tmpdir.join("a");
1217     let b = a.join("b");
1218     let c = b.join("c");
1219     let d = a.join("d");
1220     let e = d.join("e");
1221     let f = a.join("f");
1222
1223     fs::create_dir_all(&b).unwrap();
1224     fs::create_dir_all(&d).unwrap();
1225     File::create(&f).unwrap();
1226     if cfg!(not(windows)) {
1227         symlink_file("../d/e", &c).unwrap();
1228         symlink_file("../f", &e).unwrap();
1229     }
1230     if cfg!(windows) {
1231         symlink_file(r"..\d\e", &c).unwrap();
1232         symlink_file(r"..\f", &e).unwrap();
1233     }
1234
1235     assert_eq!(fs::canonicalize(&c).unwrap(), f);
1236     assert_eq!(fs::canonicalize(&e).unwrap(), f);
1237 }
1238
1239 #[test]
1240 fn dir_entry_methods() {
1241     let tmpdir = tmpdir();
1242
1243     fs::create_dir_all(&tmpdir.join("a")).unwrap();
1244     File::create(&tmpdir.join("b")).unwrap();
1245
1246     for file in tmpdir.path().read_dir().unwrap().map(|f| f.unwrap()) {
1247         let fname = file.file_name();
1248         match fname.to_str() {
1249             Some("a") => {
1250                 assert!(file.file_type().unwrap().is_dir());
1251                 assert!(file.metadata().unwrap().is_dir());
1252             }
1253             Some("b") => {
1254                 assert!(file.file_type().unwrap().is_file());
1255                 assert!(file.metadata().unwrap().is_file());
1256             }
1257             f => panic!("unknown file name: {:?}", f),
1258         }
1259     }
1260 }
1261
1262 #[test]
1263 fn dir_entry_debug() {
1264     let tmpdir = tmpdir();
1265     File::create(&tmpdir.join("b")).unwrap();
1266     let mut read_dir = tmpdir.path().read_dir().unwrap();
1267     let dir_entry = read_dir.next().unwrap().unwrap();
1268     let actual = format!("{:?}", dir_entry);
1269     let expected = format!("DirEntry({:?})", dir_entry.0.path());
1270     assert_eq!(actual, expected);
1271 }
1272
1273 #[test]
1274 fn read_dir_not_found() {
1275     let res = fs::read_dir("/path/that/does/not/exist");
1276     assert_eq!(res.err().unwrap().kind(), ErrorKind::NotFound);
1277 }
1278
1279 #[test]
1280 fn create_dir_all_with_junctions() {
1281     let tmpdir = tmpdir();
1282     let target = tmpdir.join("target");
1283
1284     let junction = tmpdir.join("junction");
1285     let b = junction.join("a/b");
1286
1287     let link = tmpdir.join("link");
1288     let d = link.join("c/d");
1289
1290     fs::create_dir(&target).unwrap();
1291
1292     check!(symlink_junction(&target, &junction));
1293     check!(fs::create_dir_all(&b));
1294     // the junction itself is not a directory, but `is_dir()` on a Path
1295     // follows links
1296     assert!(junction.is_dir());
1297     assert!(b.exists());
1298
1299     if !got_symlink_permission(&tmpdir) {
1300         return;
1301     };
1302     check!(symlink_dir(&target, &link));
1303     check!(fs::create_dir_all(&d));
1304     assert!(link.is_dir());
1305     assert!(d.exists());
1306 }
1307
1308 #[test]
1309 fn metadata_access_times() {
1310     let tmpdir = tmpdir();
1311
1312     let b = tmpdir.join("b");
1313     File::create(&b).unwrap();
1314
1315     let a = check!(fs::metadata(&tmpdir.path()));
1316     let b = check!(fs::metadata(&b));
1317
1318     assert_eq!(check!(a.accessed()), check!(a.accessed()));
1319     assert_eq!(check!(a.modified()), check!(a.modified()));
1320     assert_eq!(check!(b.accessed()), check!(b.modified()));
1321
1322     if cfg!(target_os = "macos") || cfg!(target_os = "windows") {
1323         check!(a.created());
1324         check!(b.created());
1325     }
1326
1327     if cfg!(target_os = "linux") {
1328         // Not always available
1329         match (a.created(), b.created()) {
1330             (Ok(t1), Ok(t2)) => assert!(t1 <= t2),
1331             (Err(e1), Err(e2))
1332                 if e1.kind() == ErrorKind::Unknown && e2.kind() == ErrorKind::Unknown
1333                     || e1.kind() == ErrorKind::Unsupported
1334                         && e2.kind() == ErrorKind::Unsupported => {}
1335             (a, b) => {
1336                 panic!("creation time must be always supported or not supported: {:?} {:?}", a, b,)
1337             }
1338         }
1339     }
1340 }
1341
1342 /// Test creating hard links to symlinks.
1343 #[test]
1344 fn symlink_hard_link() {
1345     let tmpdir = tmpdir();
1346     if !got_symlink_permission(&tmpdir) {
1347         return;
1348     };
1349
1350     // Create "file", a file.
1351     check!(fs::File::create(tmpdir.join("file")));
1352
1353     // Create "symlink", a symlink to "file".
1354     check!(symlink_file("file", tmpdir.join("symlink")));
1355
1356     // Create "hard_link", a hard link to "symlink".
1357     check!(fs::hard_link(tmpdir.join("symlink"), tmpdir.join("hard_link")));
1358
1359     // "hard_link" should appear as a symlink.
1360     assert!(check!(fs::symlink_metadata(tmpdir.join("hard_link"))).file_type().is_symlink());
1361
1362     // We sould be able to open "file" via any of the above names.
1363     let _ = check!(fs::File::open(tmpdir.join("file")));
1364     assert!(fs::File::open(tmpdir.join("file.renamed")).is_err());
1365     let _ = check!(fs::File::open(tmpdir.join("symlink")));
1366     let _ = check!(fs::File::open(tmpdir.join("hard_link")));
1367
1368     // Rename "file" to "file.renamed".
1369     check!(fs::rename(tmpdir.join("file"), tmpdir.join("file.renamed")));
1370
1371     // Now, the symlink and the hard link should be dangling.
1372     assert!(fs::File::open(tmpdir.join("file")).is_err());
1373     let _ = check!(fs::File::open(tmpdir.join("file.renamed")));
1374     assert!(fs::File::open(tmpdir.join("symlink")).is_err());
1375     assert!(fs::File::open(tmpdir.join("hard_link")).is_err());
1376
1377     // The symlink and the hard link should both still point to "file".
1378     assert!(fs::read_link(tmpdir.join("file")).is_err());
1379     assert!(fs::read_link(tmpdir.join("file.renamed")).is_err());
1380     assert_eq!(check!(fs::read_link(tmpdir.join("symlink"))), Path::new("file"));
1381     assert_eq!(check!(fs::read_link(tmpdir.join("hard_link"))), Path::new("file"));
1382
1383     // Remove "file.renamed".
1384     check!(fs::remove_file(tmpdir.join("file.renamed")));
1385
1386     // Now, we can't open the file by any name.
1387     assert!(fs::File::open(tmpdir.join("file")).is_err());
1388     assert!(fs::File::open(tmpdir.join("file.renamed")).is_err());
1389     assert!(fs::File::open(tmpdir.join("symlink")).is_err());
1390     assert!(fs::File::open(tmpdir.join("hard_link")).is_err());
1391
1392     // "hard_link" should still appear as a symlink.
1393     assert!(check!(fs::symlink_metadata(tmpdir.join("hard_link"))).file_type().is_symlink());
1394 }