summaryrefslogtreecommitdiff
path: root/test_util/src/temp_dir.rs
diff options
context:
space:
mode:
Diffstat (limited to 'test_util/src/temp_dir.rs')
-rw-r--r--test_util/src/temp_dir.rs87
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()
+ }
+}