Skip to main content

ephemeral_dir/
lib.rs

1use std::fs;
2use std::path::{Path, PathBuf};
3
4pub fn ephemeral_dir(path: impl AsRef<Path>) -> eyre::Result<EphemeralDir> {
5    EphemeralDir::new(path)
6}
7
8pub fn ephemeral_dir_forced(path: impl AsRef<Path>) -> eyre::Result<EphemeralDir> {
9    EphemeralDir::new_forced(path)
10}
11
12#[derive(Debug)]
13pub struct EphemeralDir {
14    // TODO: should we use a Box<Path> here instead of PathBuf?
15    path: PathBuf,
16}
17
18impl EphemeralDir {
19    pub fn new(path: impl AsRef<Path>) -> eyre::Result<Self> {
20        let path = path.as_ref();
21        assert!(!path.exists());
22
23        fs::create_dir_all(path)?;
24
25        Ok(Self {
26            path: PathBuf::from(path),
27        })
28    }
29
30    pub fn new_forced(path: impl AsRef<Path>) -> eyre::Result<Self> {
31        let path = path.as_ref();
32        if path.exists() {
33            fs::remove_dir_all(path)?;
34        }
35
36        Self::new(path)
37    }
38
39    pub fn path(&self) -> &Path {
40        self.path.as_ref()
41    }
42}
43
44impl Drop for EphemeralDir {
45    fn drop(&mut self) {
46        let _ = fs::remove_dir_all(self.path());
47    }
48}
49
50impl AsRef<Path> for EphemeralDir {
51    fn as_ref(&self) -> &Path {
52        self.path()
53    }
54}
55
56#[test]
57fn test_dir_exists_after_creation() {
58    let path = "/tmp/ephemeral_dir_test";
59    let res_dir = EphemeralDir::new_forced(path);
60    assert!(res_dir.is_ok());
61    let Ok(dir) = res_dir else { unreachable!() };
62    assert!(dir.path().exists());
63    let dir_path_str = format!("{}", dir.path().display());
64    assert_eq!(dir_path_str, path);
65}
66
67#[test]
68fn test_dir_does_not_exist_after_going_out_of_scope() {
69    let path = "/tmp/ephemeral_dir_test";
70    let res_dir = EphemeralDir::new_forced(path);
71    assert!(res_dir.is_ok());
72    {
73        let Ok(dir) = res_dir else { unreachable!() };
74        assert!(dir.path().exists());
75        let dir_path_str = format!("{}", dir.path().display());
76        assert_eq!(dir_path_str, path);
77        let dir_path = Path::new(&dir_path_str);
78        assert!(dir_path.exists());
79    }
80    let path_path = Path::new(path);
81    assert!(!path_path.exists());
82}
83
84#[test]
85fn test_wrapper_functions() {
86    // ephemeral_dir::ephemeral_dir()
87    let path = "/tmp/ephemeral_dir_test";
88    let res_dir = ephemeral_dir(path);
89    assert!(res_dir.is_ok());
90    let Ok(dir) = res_dir else { unreachable!() };
91    assert!(dir.path().exists());
92    let dir_path_str = format!("{}", dir.path().display());
93    assert_eq!(dir_path_str, path);
94
95    // ephemeral_dir::ephemeral_dir_forced()
96    let path = "/tmp/ephemeral_dir_test";
97    let res_dir = ephemeral_dir_forced(path);
98    assert!(res_dir.is_ok());
99    {
100        let Ok(dir) = res_dir else { unreachable!() };
101        assert!(dir.path().exists());
102        let dir_path_str = format!("{}", dir.path().display());
103        assert_eq!(dir_path_str, path);
104        let dir_path = Path::new(&dir_path_str);
105        assert!(dir_path.exists());
106    }
107    let path_path = Path::new(path);
108    assert!(!path_path.exists());
109}
110
111#[test]
112fn test_asref_path() {
113    let path = "/tmp/ephemeral_test_dir";
114    let res_dir = ephemeral_dir(path).unwrap();
115
116    fn foo(p: impl AsRef<Path>) -> bool {
117        let p = p.as_ref();
118        p.exists()
119    }
120
121    assert!(foo(&res_dir));
122}