]> git.lizzy.rs Git - rust.git/blob - tests/run-pass/fs.rs
a6ce8627cde7c24003b3d0f62e935b90f7e43f6a
[rust.git] / tests / run-pass / fs.rs
1 // ignore-windows: File handling is not implemented yet
2 // compile-flags: -Zmiri-disable-isolation
3
4 use std::fs::{File, remove_file, rename};
5 use std::io::{Read, Write, ErrorKind, Result, Seek, SeekFrom};
6 use std::path::{PathBuf, Path};
7
8 fn main() {
9     test_file();
10     test_file_clone();
11     test_seek();
12     test_metadata();
13     test_symlink();
14     test_errors();
15     test_rename();
16 }
17
18 /// Prepare: compute filename and make sure the file does not exist.
19 fn prepare(filename: &str) -> PathBuf {
20     let tmp = std::env::temp_dir();
21     let path = tmp.join(filename);
22     // Clean the paths for robustness.
23     remove_file(&path).ok();
24     path
25 }
26
27 /// Prepare like above, and also write some initial content to the file.
28 fn prepare_with_content(filename: &str, content: &[u8]) -> PathBuf {
29     let path = prepare(filename);
30     let mut file = File::create(&path).unwrap();
31     file.write(content).unwrap();
32     path
33 }
34
35 fn test_file() {
36     let bytes = b"Hello, World!\n";
37     let path = prepare("miri_test_fs_file.txt");
38
39     // Test creating, writing and closing a file (closing is tested when `file` is dropped).
40     let mut file = File::create(&path).unwrap();
41     // Writing 0 bytes should not change the file contents.
42     file.write(&mut []).unwrap();
43     assert_eq!(file.metadata().unwrap().len(), 0);
44
45     file.write(bytes).unwrap();
46     assert_eq!(file.metadata().unwrap().len(), bytes.len() as u64);
47     // Test opening, reading and closing a file.
48     let mut file = File::open(&path).unwrap();
49     let mut contents = Vec::new();
50     // Reading 0 bytes should not move the file pointer.
51     file.read(&mut []).unwrap();
52     // Reading until EOF should get the whole text.
53     file.read_to_end(&mut contents).unwrap();
54     assert_eq!(bytes, contents.as_slice());
55
56     // Removing file should succeed.
57     remove_file(&path).unwrap();
58 }
59
60 fn test_file_clone() {
61     let bytes = b"Hello, World!\n";
62     let path = prepare_with_content("miri_test_fs_file_clone.txt", bytes);
63
64     // Cloning a file should be successful.
65     let file = File::open(&path).unwrap();
66     let mut cloned = file.try_clone().unwrap();
67     // Reading from a cloned file should get the same text.
68     let mut contents = Vec::new();
69     cloned.read_to_end(&mut contents).unwrap();
70     assert_eq!(bytes, contents.as_slice());
71
72     // Removing file should succeed.
73     remove_file(&path).unwrap();
74 }
75
76 fn test_seek() {
77     let bytes = b"Hello, entire World!\n";
78     let path = prepare_with_content("miri_test_fs_seek.txt", bytes);
79
80     let mut file = File::open(&path).unwrap();
81     let mut contents = Vec::new();
82     file.read_to_end(&mut contents).unwrap();
83     assert_eq!(bytes, contents.as_slice());
84     // Test that seeking to the beginning and reading until EOF gets the text again.
85     file.seek(SeekFrom::Start(0)).unwrap();
86     let mut contents = Vec::new();
87     file.read_to_end(&mut contents).unwrap();
88     assert_eq!(bytes, contents.as_slice());
89     // Test seeking relative to the end of the file.
90     file.seek(SeekFrom::End(-1)).unwrap();
91     let mut contents = Vec::new();
92     file.read_to_end(&mut contents).unwrap();
93     assert_eq!(&bytes[bytes.len() - 1..], contents.as_slice());
94     // Test seeking relative to the current position.
95     file.seek(SeekFrom::Start(5)).unwrap();
96     file.seek(SeekFrom::Current(-3)).unwrap();
97     let mut contents = Vec::new();
98     file.read_to_end(&mut contents).unwrap();
99     assert_eq!(&bytes[2..], contents.as_slice());
100
101     // Removing file should succeed.
102     remove_file(&path).unwrap();
103 }
104
105 fn check_metadata(bytes: &[u8], path: &Path) -> Result<()> {
106     // Test that the file metadata is correct.
107     let metadata = path.metadata()?;
108     // `path` should point to a file.
109     assert!(metadata.is_file());
110     // The size of the file must be equal to the number of written bytes.
111     assert_eq!(bytes.len() as u64, metadata.len());
112     Ok(())
113 }
114
115 fn test_metadata() {
116     let bytes = b"Hello, meta-World!\n";
117     let path = prepare_with_content("miri_test_fs_metadata.txt", bytes);
118
119     // Test that metadata of an absolute path is correct.
120     check_metadata(bytes, &path).unwrap();
121     // Test that metadata of a relative path is correct.
122     std::env::set_current_dir(path.parent().unwrap()).unwrap();
123     check_metadata(bytes, Path::new(path.file_name().unwrap())).unwrap();
124
125     // Removing file should succeed.
126     remove_file(&path).unwrap();
127 }
128
129 fn test_symlink() {
130     let bytes = b"Hello, World!\n";
131     let path = prepare_with_content("miri_test_fs_link_target.txt", bytes);
132     let symlink_path = prepare("miri_test_fs_symlink.txt");
133
134     // Creating a symbolic link should succeed.
135     std::os::unix::fs::symlink(&path, &symlink_path).unwrap();
136     // Test that the symbolic link has the same contents as the file.
137     let mut symlink_file = File::open(&symlink_path).unwrap();
138     let mut contents = Vec::new();
139     symlink_file.read_to_end(&mut contents).unwrap();
140     assert_eq!(bytes, contents.as_slice());
141     // Test that metadata of a symbolic link is correct.
142     check_metadata(bytes, &symlink_path).unwrap();
143     // Test that the metadata of a symbolic link is correct when not following it.
144     assert!(symlink_path.symlink_metadata().unwrap().file_type().is_symlink());
145     // Removing symbolic link should succeed.
146     remove_file(&symlink_path).unwrap();
147
148     // Removing file should succeed.
149     remove_file(&path).unwrap();
150 }
151
152 fn test_errors() {
153     let bytes = b"Hello, World!\n";
154     let path = prepare("miri_test_fs_errors.txt");
155
156     // The following tests also check that the `__errno_location()` shim is working properly.
157     // Opening a non-existing file should fail with a "not found" error.
158     assert_eq!(ErrorKind::NotFound, File::open(&path).unwrap_err().kind());
159     // Removing a non-existing file should fail with a "not found" error.
160     assert_eq!(ErrorKind::NotFound, remove_file(&path).unwrap_err().kind());
161     // Reading the metadata of a non-existing file should fail with a "not found" error.
162     assert_eq!(ErrorKind::NotFound, check_metadata(bytes, &path).unwrap_err().kind());
163 }
164
165 fn test_rename() {
166     // Renaming a file should succeed.
167     let path1 = prepare("miri_test_fs_rename_source.txt");
168     let path2 = prepare("miri_test_fs_rename_destination.txt");
169
170     let file = File::create(&path1).unwrap();
171     drop(file);
172
173     // Renaming should succeed
174     rename(&path1, &path2).unwrap();
175     // Check that the old file path isn't present
176     assert_eq!(ErrorKind::NotFound, path1.metadata().unwrap_err().kind());
177     // Check that the file has moved successfully
178     assert!(path2.metadata().unwrap().is_file());
179
180     // Renaming a nonexistent file should fail
181     assert_eq!(ErrorKind::NotFound, rename(&path1, &path2).unwrap_err().kind());
182
183     remove_file(&path2).unwrap();
184 }