]> git.proxmox.com Git - rustc.git/blame - library/std/src/fs/tests.rs
New upstream version 1.53.0+dfsg1
[rustc.git] / library / std / src / fs / tests.rs
CommitLineData
1b1a35ee
XL
1use crate::io::prelude::*;
2
3use crate::fs::{self, File, OpenOptions};
4use crate::io::{ErrorKind, SeekFrom};
5use crate::path::Path;
6use crate::str;
7use crate::sys_common::io::test::{tmpdir, TempDir};
8use crate::thread;
9
10use rand::{rngs::StdRng, RngCore, SeedableRng};
11
12#[cfg(unix)]
13use crate::os::unix::fs::symlink as symlink_dir;
14#[cfg(unix)]
15use crate::os::unix::fs::symlink as symlink_file;
16#[cfg(unix)]
17use crate::os::unix::fs::symlink as symlink_junction;
18#[cfg(windows)]
19use crate::os::windows::fs::{symlink_dir, symlink_file};
20#[cfg(windows)]
21use crate::sys::fs::symlink_junction;
22
23macro_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)]
33macro_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)]
46macro_rules! error {
47 ($e:expr, $s:expr) => {
48 error_contains!($e, $s)
49 };
50}
51
52macro_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.
69pub 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) {
1b1a35ee
XL
76 // ERROR_PRIVILEGE_NOT_HELD = 1314
77 Err(ref err) if err.raw_os_error() == Some(1314) => false,
29967ef6 78 Ok(_) | Err(_) => true,
1b1a35ee
XL
79 }
80}
81
82#[test]
83fn 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]
104fn 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]
118fn 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]
133fn 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]
159fn 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]
186fn 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]
210fn 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]
242fn 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)]
257fn 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)]
313fn 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)]
335fn 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]
388fn 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]
408fn 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]
420fn 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]
429fn 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]
439fn 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]
451fn 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]
480fn 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]
489fn 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]
498fn 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]
506fn 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]
520fn 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]
541fn recursive_mkdir_slash() {
542 check!(fs::create_dir_all(Path::new("/")));
543}
544
545#[test]
546fn recursive_mkdir_dot() {
547 check!(fs::create_dir_all(Path::new(".")));
548}
549
550#[test]
551fn recursive_mkdir_empty() {
552 check!(fs::create_dir_all(Path::new("")));
553}
554
555#[test]
556fn 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]
575fn 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)]
593fn 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]
610fn 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]
629fn 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]
642fn 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]
656fn 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]
669fn 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]
684fn 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]
696fn 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]
711fn 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]
723fn 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)]
740fn 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]
751fn 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]
763fn 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]
785fn 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]
804fn 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]
818fn 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]
846fn 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]
855fn 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]
881fn 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]
904fn 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]
922fn 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]
935fn 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]
969fn 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]
1093fn _assert_send_sync() {
1094 fn _assert_send_sync<T: Send + Sync>() {}
1095 _assert_send_sync::<OpenOptions>();
1096}
1097
1098#[test]
1099fn 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]
1112fn 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]
1135fn 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))]
1155fn 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]
1166fn 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]
1173fn 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]
1182fn 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]
1209fn 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]
1240fn 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]
1263fn 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]
1274fn 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]
1280fn 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]
1309fn 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))
cdc7bbd5
XL
1332 if e1.kind() == ErrorKind::Other && e2.kind() == ErrorKind::Other
1333 || e1.kind() == ErrorKind::Unsupported
1334 && e2.kind() == ErrorKind::Unsupported => {}
1b1a35ee
XL
1335 (a, b) => {
1336 panic!("creation time must be always supported or not supported: {:?} {:?}", a, b,)
1337 }
1338 }
1339 }
1340}
29967ef6
XL
1341
1342/// Test creating hard links to symlinks.
1343#[test]
1344fn symlink_hard_link() {
1345 let tmpdir = tmpdir();
fc512014
XL
1346 if !got_symlink_permission(&tmpdir) {
1347 return;
1348 };
29967ef6
XL
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}