#![cfg(test)]
use std::path::{Path, PathBuf};
use std::sync::{Mutex, MutexGuard, OnceLock};
static STATE_LOCK: OnceLock<Mutex<()>> = OnceLock::new();
fn state_lock() -> MutexGuard<'static, ()> {
STATE_LOCK
.get_or_init(|| Mutex::new(()))
.lock()
.unwrap_or_else(|poisoned| poisoned.into_inner())
}
pub(crate) struct CwdGuard {
_lock: MutexGuard<'static, ()>,
saved: PathBuf,
}
impl CwdGuard {
pub(crate) fn enter(dir: &Path) -> Self {
let guard = Self::hold();
std::env::set_current_dir(dir).expect("set current dir");
guard
}
pub(crate) fn hold() -> Self {
let lock = state_lock();
let saved = std::env::current_dir().expect("read current dir");
Self { _lock: lock, saved }
}
pub(crate) fn switch_to(&self, dir: &Path) {
std::env::set_current_dir(dir).expect("set current dir");
}
}
impl Drop for CwdGuard {
fn drop(&mut self) {
let _ = std::env::set_current_dir(&self.saved);
}
}
pub(crate) struct BudgetGuard {
_lock: MutexGuard<'static, ()>,
}
impl BudgetGuard {
pub(crate) fn hold() -> Self {
let lock = state_lock();
crate::tools::codemap::update_budget(0, 1_000_000, 0);
Self { _lock: lock }
}
}
impl Drop for BudgetGuard {
fn drop(&mut self) {
crate::tools::codemap::update_budget(0, 1_000_000, 0);
}
}
pub(crate) struct ExecGuard {
_lock: MutexGuard<'static, ()>,
saved: PathBuf,
}
impl ExecGuard {
pub(crate) fn hold() -> Self {
let lock = state_lock();
let saved = std::env::current_dir().expect("read current dir");
crate::tools::codemap::update_budget(0, 1_000_000, 0);
crate::reset_shutdown_for_test();
Self { _lock: lock, saved }
}
}
impl Drop for ExecGuard {
fn drop(&mut self) {
crate::tools::codemap::update_budget(0, 1_000_000, 0);
crate::reset_shutdown_for_test();
let _ = std::env::set_current_dir(&self.saved);
}
}
pub(crate) struct EnvGuard {
_lock: MutexGuard<'static, ()>,
saved: Vec<(&'static str, Option<std::ffi::OsString>)>,
}
impl EnvGuard {
pub(crate) fn capture(keys: &[&'static str]) -> Self {
let lock = state_lock();
let saved = keys.iter().map(|k| (*k, std::env::var_os(k))).collect();
Self { _lock: lock, saved }
}
pub(crate) fn set(&self, key: &str, value: impl AsRef<std::ffi::OsStr>) {
std::env::set_var(key, value);
}
}
impl Drop for EnvGuard {
fn drop(&mut self) {
for (key, value) in self.saved.drain(..) {
match value {
Some(v) => std::env::set_var(key, v),
None => std::env::remove_var(key),
}
}
}
}