1use std::{
2 env::temp_dir,
3 fs::{create_dir_all, remove_dir_all},
4 io::{self, Write},
5 path::{Path, PathBuf},
6};
7use tempfile::Builder;
8use uuid::Uuid;
9
10#[derive(Debug)]
11pub struct TempDir(PathBuf);
12
13impl TempDir {
14 pub fn new() -> Self {
15 Self(temp_dir().join(format!("aether-{}", Uuid::new_v4())))
16 }
17
18 pub fn path(&self) -> &Path {
19 &self.0
20 }
21
22 pub fn save(&self, label: &str, text: &str) -> io::Result<PathBuf> {
23 create_dir_all(&self.0)?;
24 let label = label.replace(|c: char| !c.is_ascii_alphanumeric() && c != '-' && c != '_', "_");
25 let mut file = Builder::new().prefix(&format!("{label}-")).suffix(".txt").tempfile_in(&self.0)?;
26 file.write_all(text.as_bytes())?;
27 Ok(file.keep()?.1)
28 }
29}
30
31impl Default for TempDir {
32 fn default() -> Self {
33 Self::new()
34 }
35}
36
37impl Drop for TempDir {
38 fn drop(&mut self) {
39 let _ = remove_dir_all(&self.0);
40 }
41}
42
43#[cfg(test)]
44mod tests {
45 use std::fs::{create_dir_all, read_to_string, write};
46
47 use super::*;
48
49 #[test]
50 fn each_dir_is_unique() {
51 assert_ne!(TempDir::new().path(), TempDir::new().path());
52 }
53
54 #[test]
55 fn dropping_the_dir_deletes_what_was_written_into_it() {
56 let dir = TempDir::new();
57 create_dir_all(dir.path()).unwrap();
58 write(dir.path().join("saved.txt"), "output").unwrap();
59 let path = dir.path().to_path_buf();
60
61 drop(dir);
62 assert!(!path.exists());
63 }
64
65 #[test]
66 fn save_creates_the_dir_and_keeps_labels_with_path_separators_inside_it() {
67 let dir = TempDir::new();
68
69 let saved = dir.save("../my/server__tool", "output").unwrap();
70
71 assert_eq!(saved.parent(), Some(dir.path()));
72 assert_eq!(read_to_string(saved).unwrap(), "output");
73 }
74}