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