diff options
Diffstat (limited to 'test_util/src/temp_dir.rs')
-rw-r--r-- | test_util/src/temp_dir.rs | 87 |
1 files changed, 87 insertions, 0 deletions
diff --git a/test_util/src/temp_dir.rs b/test_util/src/temp_dir.rs new file mode 100644 index 000000000..da2b2a06e --- /dev/null +++ b/test_util/src/temp_dir.rs @@ -0,0 +1,87 @@ +use std::path::Path; +use std::path::PathBuf; +use std::sync::atomic::AtomicU32; +use std::sync::atomic::Ordering; +use std::sync::Arc; +use std::time::SystemTime; + +use anyhow::Context; +use once_cell::sync::OnceCell; + +static TEMP_DIR_SESSION: OnceCell<TempDirSession> = OnceCell::new(); + +struct TempDirSession { + default_prefix: String, + counter: AtomicU32, +} + +/// For creating temporary directories in tests. +/// +/// This was done because `tempfiles::TempDir` was very slow on Windows. +/// +/// Note: Do not use this in actual code as this does not protect against +/// "insecure temporary file" security vulnerabilities. +#[derive(Clone)] +pub struct TempDir(Arc<TempDirInner>); + +struct TempDirInner(PathBuf); + +impl Drop for TempDirInner { + fn drop(&mut self) { + let _ = std::fs::remove_dir_all(&self.0); + } +} + +impl Default for TempDir { + fn default() -> Self { + Self::new() + } +} + +impl TempDir { + pub fn new() -> Self { + Self::new_inner(&std::env::temp_dir(), None) + } + + pub fn new_in(path: &Path) -> Self { + Self::new_inner(path, None) + } + + pub fn new_with_prefix(prefix: &str) -> Self { + Self::new_inner(&std::env::temp_dir(), Some(prefix)) + } + + fn new_inner(parent_dir: &Path, prefix: Option<&str>) -> Self { + let session = TEMP_DIR_SESSION.get_or_init(|| { + let default_prefix = format!( + "deno-cli-test-{}", + SystemTime::now() + .duration_since(SystemTime::UNIX_EPOCH) + .unwrap() + .as_millis() + ); + TempDirSession { + default_prefix, + counter: Default::default(), + } + }); + Self({ + let count = session.counter.fetch_add(1, Ordering::SeqCst); + let path = parent_dir.join(format!( + "{}{}-{}", + prefix.unwrap_or(""), + session.default_prefix, + count, + )); + std::fs::create_dir_all(&path) + .with_context(|| format!("Error creating temp dir: {}", path.display())) + .unwrap(); + Arc::new(TempDirInner(path)) + }) + } + + pub fn path(&self) -> &Path { + let inner = &self.0; + inner.0.as_path() + } +} |