1 | #![deny (rust_2018_idioms)] |
2 | |
3 | use std::env; |
4 | use std::ffi::{OsStr, OsString}; |
5 | use std::fs::File; |
6 | use std::io::{Read, Seek, SeekFrom, Write}; |
7 | use std::path::{Path, PathBuf}; |
8 | use tempfile::{tempdir, Builder, NamedTempFile, TempPath}; |
9 | |
10 | fn exists<P: AsRef<Path>>(path: P) -> bool { |
11 | std::fs::metadata(path.as_ref()).is_ok() |
12 | } |
13 | |
14 | #[test] |
15 | fn test_prefix() { |
16 | let tmpfile = NamedTempFile::with_prefix("prefix" ).unwrap(); |
17 | let name = tmpfile.path().file_name().unwrap().to_str().unwrap(); |
18 | assert!(name.starts_with("prefix" )); |
19 | } |
20 | |
21 | #[test] |
22 | fn test_basic() { |
23 | let mut tmpfile = NamedTempFile::new().unwrap(); |
24 | write!(tmpfile, "abcde" ).unwrap(); |
25 | tmpfile.seek(SeekFrom::Start(0)).unwrap(); |
26 | let mut buf = String::new(); |
27 | tmpfile.read_to_string(&mut buf).unwrap(); |
28 | assert_eq!("abcde" , buf); |
29 | } |
30 | |
31 | #[test] |
32 | fn test_deleted() { |
33 | let tmpfile = NamedTempFile::new().unwrap(); |
34 | let path = tmpfile.path().to_path_buf(); |
35 | assert!(exists(&path)); |
36 | drop(tmpfile); |
37 | assert!(!exists(&path)); |
38 | } |
39 | |
40 | #[test] |
41 | fn test_persist() { |
42 | let mut tmpfile = NamedTempFile::new().unwrap(); |
43 | let old_path = tmpfile.path().to_path_buf(); |
44 | let persist_path = env::temp_dir().join("persisted_temporary_file" ); |
45 | write!(tmpfile, "abcde" ).unwrap(); |
46 | { |
47 | assert!(exists(&old_path)); |
48 | let mut f = tmpfile.persist(&persist_path).unwrap(); |
49 | assert!(!exists(&old_path)); |
50 | |
51 | // Check original file |
52 | f.seek(SeekFrom::Start(0)).unwrap(); |
53 | let mut buf = String::new(); |
54 | f.read_to_string(&mut buf).unwrap(); |
55 | assert_eq!("abcde" , buf); |
56 | } |
57 | |
58 | { |
59 | // Try opening it at the new path. |
60 | let mut f = File::open(&persist_path).unwrap(); |
61 | f.seek(SeekFrom::Start(0)).unwrap(); |
62 | let mut buf = String::new(); |
63 | f.read_to_string(&mut buf).unwrap(); |
64 | assert_eq!("abcde" , buf); |
65 | } |
66 | std::fs::remove_file(&persist_path).unwrap(); |
67 | } |
68 | |
69 | #[test] |
70 | fn test_persist_noclobber() { |
71 | let mut tmpfile = NamedTempFile::new().unwrap(); |
72 | let old_path = tmpfile.path().to_path_buf(); |
73 | let persist_target = NamedTempFile::new().unwrap(); |
74 | let persist_path = persist_target.path().to_path_buf(); |
75 | write!(tmpfile, "abcde" ).unwrap(); |
76 | assert!(exists(&old_path)); |
77 | { |
78 | tmpfile = tmpfile.persist_noclobber(&persist_path).unwrap_err().into(); |
79 | assert!(exists(&old_path)); |
80 | std::fs::remove_file(&persist_path).unwrap(); |
81 | drop(persist_target); |
82 | } |
83 | tmpfile.persist_noclobber(&persist_path).unwrap(); |
84 | // Try opening it at the new path. |
85 | let mut f = File::open(&persist_path).unwrap(); |
86 | f.seek(SeekFrom::Start(0)).unwrap(); |
87 | let mut buf = String::new(); |
88 | f.read_to_string(&mut buf).unwrap(); |
89 | assert_eq!("abcde" , buf); |
90 | std::fs::remove_file(&persist_path).unwrap(); |
91 | } |
92 | |
93 | #[test] |
94 | fn test_customnamed() { |
95 | let tmpfile = Builder::new() |
96 | .prefix("tmp" ) |
97 | .suffix(&".rs" ) |
98 | .rand_bytes(12) |
99 | .tempfile() |
100 | .unwrap(); |
101 | let name = tmpfile.path().file_name().unwrap().to_str().unwrap(); |
102 | assert!(name.starts_with("tmp" )); |
103 | assert!(name.ends_with(".rs" )); |
104 | assert_eq!(name.len(), 18); |
105 | } |
106 | |
107 | #[test] |
108 | fn test_append() { |
109 | let mut tmpfile = Builder::new().append(true).tempfile().unwrap(); |
110 | tmpfile.write_all(b"a" ).unwrap(); |
111 | tmpfile.seek(SeekFrom::Start(0)).unwrap(); |
112 | tmpfile.write_all(b"b" ).unwrap(); |
113 | |
114 | tmpfile.seek(SeekFrom::Start(0)).unwrap(); |
115 | let mut buf = vec![0u8; 1]; |
116 | tmpfile.read_exact(&mut buf).unwrap(); |
117 | assert_eq!(buf, b"a" ); |
118 | } |
119 | |
120 | #[test] |
121 | fn test_reopen() { |
122 | let source = NamedTempFile::new().unwrap(); |
123 | let mut first = source.reopen().unwrap(); |
124 | let mut second = source.reopen().unwrap(); |
125 | drop(source); |
126 | |
127 | write!(first, "abcde" ).expect("write failed" ); |
128 | let mut buf = String::new(); |
129 | second.read_to_string(&mut buf).unwrap(); |
130 | assert_eq!("abcde" , buf); |
131 | } |
132 | |
133 | #[test] |
134 | fn test_into_file() { |
135 | let mut file = NamedTempFile::new().unwrap(); |
136 | let path = file.path().to_owned(); |
137 | write!(file, "abcde" ).expect("write failed" ); |
138 | |
139 | assert!(path.exists()); |
140 | let mut file = file.into_file(); |
141 | assert!(!path.exists()); |
142 | |
143 | file.seek(SeekFrom::Start(0)).unwrap(); |
144 | let mut buf = String::new(); |
145 | file.read_to_string(&mut buf).unwrap(); |
146 | assert_eq!("abcde" , buf); |
147 | } |
148 | |
149 | #[test] |
150 | fn test_immut() { |
151 | let tmpfile = NamedTempFile::new().unwrap(); |
152 | (&tmpfile).write_all(b"abcde" ).unwrap(); |
153 | (&tmpfile).seek(SeekFrom::Start(0)).unwrap(); |
154 | let mut buf = String::new(); |
155 | (&tmpfile).read_to_string(&mut buf).unwrap(); |
156 | assert_eq!("abcde" , buf); |
157 | } |
158 | |
159 | #[test] |
160 | fn test_temppath() { |
161 | let mut tmpfile = NamedTempFile::new().unwrap(); |
162 | write!(tmpfile, "abcde" ).unwrap(); |
163 | |
164 | let path = tmpfile.into_temp_path(); |
165 | assert!(path.is_file()); |
166 | } |
167 | |
168 | #[test] |
169 | fn test_temppath_persist() { |
170 | let mut tmpfile = NamedTempFile::new().unwrap(); |
171 | write!(tmpfile, "abcde" ).unwrap(); |
172 | |
173 | let tmppath = tmpfile.into_temp_path(); |
174 | |
175 | let old_path = tmppath.to_path_buf(); |
176 | let persist_path = env::temp_dir().join("persisted_temppath_file" ); |
177 | |
178 | { |
179 | assert!(exists(&old_path)); |
180 | tmppath.persist(&persist_path).unwrap(); |
181 | assert!(!exists(&old_path)); |
182 | } |
183 | |
184 | { |
185 | // Try opening it at the new path. |
186 | let mut f = File::open(&persist_path).unwrap(); |
187 | f.seek(SeekFrom::Start(0)).unwrap(); |
188 | let mut buf = String::new(); |
189 | f.read_to_string(&mut buf).unwrap(); |
190 | assert_eq!("abcde" , buf); |
191 | } |
192 | |
193 | std::fs::remove_file(&persist_path).unwrap(); |
194 | } |
195 | |
196 | #[test] |
197 | fn test_temppath_persist_noclobber() { |
198 | let mut tmpfile = NamedTempFile::new().unwrap(); |
199 | write!(tmpfile, "abcde" ).unwrap(); |
200 | |
201 | let mut tmppath = tmpfile.into_temp_path(); |
202 | |
203 | let old_path = tmppath.to_path_buf(); |
204 | let persist_target = NamedTempFile::new().unwrap(); |
205 | let persist_path = persist_target.path().to_path_buf(); |
206 | |
207 | assert!(exists(&old_path)); |
208 | |
209 | { |
210 | tmppath = tmppath.persist_noclobber(&persist_path).unwrap_err().into(); |
211 | assert!(exists(&old_path)); |
212 | std::fs::remove_file(&persist_path).unwrap(); |
213 | drop(persist_target); |
214 | } |
215 | |
216 | tmppath.persist_noclobber(&persist_path).unwrap(); |
217 | |
218 | // Try opening it at the new path. |
219 | let mut f = File::open(&persist_path).unwrap(); |
220 | f.seek(SeekFrom::Start(0)).unwrap(); |
221 | let mut buf = String::new(); |
222 | f.read_to_string(&mut buf).unwrap(); |
223 | assert_eq!("abcde" , buf); |
224 | std::fs::remove_file(&persist_path).unwrap(); |
225 | } |
226 | |
227 | #[test] |
228 | fn temp_path_from_existing() { |
229 | let tmp_dir = tempdir().unwrap(); |
230 | let tmp_file_path_1 = tmp_dir.path().join("testfile1" ); |
231 | let tmp_file_path_2 = tmp_dir.path().join("testfile2" ); |
232 | |
233 | File::create(&tmp_file_path_1).unwrap(); |
234 | assert!(tmp_file_path_1.exists(), "Test file 1 hasn't been created" ); |
235 | |
236 | File::create(&tmp_file_path_2).unwrap(); |
237 | assert!(tmp_file_path_2.exists(), "Test file 2 hasn't been created" ); |
238 | |
239 | let tmp_path = TempPath::from_path(&tmp_file_path_1); |
240 | assert!( |
241 | tmp_file_path_1.exists(), |
242 | "Test file has been deleted before dropping TempPath" |
243 | ); |
244 | |
245 | drop(tmp_path); |
246 | assert!( |
247 | !tmp_file_path_1.exists(), |
248 | "Test file exists after dropping TempPath" |
249 | ); |
250 | assert!( |
251 | tmp_file_path_2.exists(), |
252 | "Test file 2 has been deleted before dropping TempDir" |
253 | ); |
254 | } |
255 | |
256 | #[test] |
257 | #[allow (unreachable_code)] |
258 | fn temp_path_from_argument_types() { |
259 | // This just has to compile |
260 | return; |
261 | |
262 | TempPath::from_path("" ); |
263 | TempPath::from_path(String::new()); |
264 | TempPath::from_path(OsStr::new("" )); |
265 | TempPath::from_path(OsString::new()); |
266 | TempPath::from_path(Path::new("" )); |
267 | TempPath::from_path(PathBuf::new()); |
268 | TempPath::from_path(PathBuf::new().into_boxed_path()); |
269 | } |
270 | |
271 | #[test] |
272 | fn test_write_after_close() { |
273 | let path = NamedTempFile::new().unwrap().into_temp_path(); |
274 | File::create(path).unwrap().write_all(b"test" ).unwrap(); |
275 | } |
276 | |
277 | #[test] |
278 | fn test_change_dir() { |
279 | env::set_current_dir(env::temp_dir()).unwrap(); |
280 | let tmpfile = NamedTempFile::new_in("." ).unwrap(); |
281 | let path = env::current_dir().unwrap().join(tmpfile.path()); |
282 | env::set_current_dir("/" ).unwrap(); |
283 | drop(tmpfile); |
284 | assert!(!exists(path)) |
285 | } |
286 | |
287 | #[test] |
288 | fn test_into_parts() { |
289 | let mut file = NamedTempFile::new().unwrap(); |
290 | write!(file, "abcd" ).expect("write failed" ); |
291 | |
292 | let (mut file, temp_path) = file.into_parts(); |
293 | |
294 | let path = temp_path.to_path_buf(); |
295 | |
296 | assert!(path.exists()); |
297 | drop(temp_path); |
298 | assert!(!path.exists()); |
299 | |
300 | write!(file, "efgh" ).expect("write failed" ); |
301 | |
302 | file.seek(SeekFrom::Start(0)).unwrap(); |
303 | let mut buf = String::new(); |
304 | file.read_to_string(&mut buf).unwrap(); |
305 | assert_eq!("abcdefgh" , buf); |
306 | } |
307 | |
308 | #[test] |
309 | fn test_from_parts() { |
310 | let mut file = NamedTempFile::new().unwrap(); |
311 | write!(file, "abcd" ).expect("write failed" ); |
312 | |
313 | let (file, temp_path) = file.into_parts(); |
314 | |
315 | let file = NamedTempFile::from_parts(file, temp_path); |
316 | |
317 | assert!(file.path().exists()); |
318 | } |
319 | |
320 | #[test] |
321 | fn test_keep() { |
322 | let mut tmpfile = NamedTempFile::new().unwrap(); |
323 | write!(tmpfile, "abcde" ).unwrap(); |
324 | let (mut f, temp_path) = tmpfile.into_parts(); |
325 | let path; |
326 | { |
327 | assert!(exists(&temp_path)); |
328 | path = temp_path.keep().unwrap(); |
329 | assert!(exists(&path)); |
330 | |
331 | // Check original file |
332 | f.seek(SeekFrom::Start(0)).unwrap(); |
333 | let mut buf = String::new(); |
334 | f.read_to_string(&mut buf).unwrap(); |
335 | assert_eq!("abcde" , buf); |
336 | } |
337 | |
338 | { |
339 | // Try opening it again. |
340 | let mut f = File::open(&path).unwrap(); |
341 | f.seek(SeekFrom::Start(0)).unwrap(); |
342 | let mut buf = String::new(); |
343 | f.read_to_string(&mut buf).unwrap(); |
344 | assert_eq!("abcde" , buf); |
345 | } |
346 | std::fs::remove_file(&path).unwrap(); |
347 | } |
348 | |
349 | #[test] |
350 | fn test_make() { |
351 | let tmpfile = Builder::new().make(|path| File::create(path)).unwrap(); |
352 | |
353 | assert!(tmpfile.path().is_file()); |
354 | } |
355 | |
356 | #[test] |
357 | fn test_make_in() { |
358 | let tmp_dir = tempdir().unwrap(); |
359 | |
360 | let tmpfile = Builder::new() |
361 | .make_in(tmp_dir.path(), |path| File::create(path)) |
362 | .unwrap(); |
363 | |
364 | assert!(tmpfile.path().is_file()); |
365 | assert_eq!(tmpfile.path().parent(), Some(tmp_dir.path())); |
366 | } |
367 | |
368 | #[test] |
369 | fn test_make_fnmut() { |
370 | let mut count = 0; |
371 | |
372 | // Show that an FnMut can be used. |
373 | let tmpfile = Builder::new() |
374 | .make(|path| { |
375 | count += 1; |
376 | File::create(path) |
377 | }) |
378 | .unwrap(); |
379 | |
380 | assert!(tmpfile.path().is_file()); |
381 | } |
382 | |
383 | #[cfg (unix)] |
384 | #[test] |
385 | fn test_make_uds() { |
386 | use std::os::unix::net::UnixListener; |
387 | |
388 | let temp_sock = Builder::new() |
389 | .prefix("tmp" ) |
390 | .suffix(".sock" ) |
391 | .rand_bytes(12) |
392 | .make(|path| UnixListener::bind(path)) |
393 | .unwrap(); |
394 | |
395 | assert!(temp_sock.path().exists()); |
396 | } |
397 | |
398 | #[cfg (unix)] |
399 | #[test] |
400 | fn test_make_uds_conflict() { |
401 | use std::os::unix::net::UnixListener; |
402 | use std::sync::atomic::{AtomicUsize, Ordering}; |
403 | use std::sync::Arc; |
404 | |
405 | // Check that retries happen correctly by racing N different threads. |
406 | |
407 | const NTHREADS: usize = 20; |
408 | |
409 | // The number of times our callback was called. |
410 | let tries = Arc::new(AtomicUsize::new(0)); |
411 | |
412 | let mut threads = Vec::with_capacity(NTHREADS); |
413 | |
414 | for _ in 0..NTHREADS { |
415 | let tries = tries.clone(); |
416 | threads.push(std::thread::spawn(move || { |
417 | // Ensure that every thread uses the same seed so we are guaranteed |
418 | // to retry. Note that fastrand seeds are thread-local. |
419 | fastrand::seed(42); |
420 | |
421 | Builder::new() |
422 | .prefix("tmp" ) |
423 | .suffix(".sock" ) |
424 | .rand_bytes(12) |
425 | .make(|path| { |
426 | tries.fetch_add(1, Ordering::Relaxed); |
427 | UnixListener::bind(path) |
428 | }) |
429 | })); |
430 | } |
431 | |
432 | // Join all threads, but don't drop the temp file yet. Otherwise, we won't |
433 | // get a deterministic number of `tries`. |
434 | let sockets: Vec<_> = threads |
435 | .into_iter() |
436 | .map(|thread| thread.join().unwrap().unwrap()) |
437 | .collect(); |
438 | |
439 | // Number of tries is exactly equal to (n*(n+1))/2. |
440 | assert_eq!( |
441 | tries.load(Ordering::Relaxed), |
442 | (NTHREADS * (NTHREADS + 1)) / 2 |
443 | ); |
444 | |
445 | for socket in sockets { |
446 | assert!(socket.path().exists()); |
447 | } |
448 | } |
449 | |
450 | // Issue #224. |
451 | #[test] |
452 | fn test_overly_generic_bounds() { |
453 | pub struct Foo<T>(T); |
454 | |
455 | impl<T> Foo<T> |
456 | where |
457 | T: Sync + Send + 'static, |
458 | for<'a> &'a T: Write + Read, |
459 | { |
460 | pub fn new(foo: T) -> Self { |
461 | Self(foo) |
462 | } |
463 | } |
464 | |
465 | // Don't really need to run this. Only care if it compiles. |
466 | if let Ok(file) = File::open("i_do_not_exist" ) { |
467 | let mut f; |
468 | let _x = { |
469 | f = Foo::new(file); |
470 | &mut f |
471 | }; |
472 | } |
473 | } |
474 | |