1#![deny(rust_2018_idioms)]
2
3use std::env;
4use std::ffi::{OsStr, OsString};
5use std::fs::File;
6use std::io::{Read, Seek, SeekFrom, Write};
7use std::path::{Path, PathBuf};
8use tempfile::{tempdir, Builder, NamedTempFile, TempPath};
9
10fn exists<P: AsRef<Path>>(path: P) -> bool {
11 std::fs::metadata(path.as_ref()).is_ok()
12}
13
14#[test]
15fn 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]
22fn 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]
32fn 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]
41fn 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]
70fn 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]
94fn 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]
108fn 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]
121fn 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]
134fn 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]
150fn 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]
160fn 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]
169fn 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]
197fn 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]
228fn 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)]
258fn 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]
272fn 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]
278fn 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]
288fn 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]
309fn 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]
321fn 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]
350fn test_make() {
351 let tmpfile = Builder::new().make(|path| File::create(path)).unwrap();
352
353 assert!(tmpfile.path().is_file());
354}
355
356#[test]
357fn 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]
369fn 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]
385fn 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]
400fn 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]
452fn 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