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