Skip to main content

utils/
temp_dir.rs

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}