use std::ffi::OsStr;
#[cfg(any(test, feature = "test-support"))]
pub fn run_with_conversation_scope(test_name: &str, enabled: bool) -> bool {
run_in_own_process(
test_name,
&[(
"LEAN_CTX_CONVERSATION_SCOPE",
if enabled { "1" } else { "0" },
)],
)
}
pub fn run_in_own_process(test_name: &str, env: &[(&str, &str)]) -> bool {
run_in_own_process_at(test_name, env, None)
}
pub fn run_in_own_process_at(
test_name: &str,
env: &[(&str, &str)],
directory: Option<&std::path::Path>,
) -> bool {
const CHILD: &str = "LEAN_CTX_TEST_ISOLATED_CASE";
if std::env::var(CHILD).as_deref() == Ok(test_name) {
return false;
}
let _environment = crate::core::data_dir::test_env_lock();
let mut child = std::process::Command::new(std::env::current_exe().expect("test executable"));
child
.args(["--exact", test_name, "--nocapture"])
.env(CHILD, test_name)
.envs(env.iter().copied());
if let Some(directory) = directory {
child.current_dir(directory);
}
let output = child.output().expect("isolated test process");
let stdout = String::from_utf8_lossy(&output.stdout);
assert!(
output.status.success() && stdout.contains("test result: ok. 1 passed"),
"isolated test {test_name} failed or did not run: {}\n{stdout}\n{}",
output.status,
String::from_utf8_lossy(&output.stderr),
);
true
}
pub use lean_ctx_fs::env_lock::{remove_var, set_var};
pub struct VarGuard {
key: std::ffi::OsString,
previous: Option<std::ffi::OsString>,
}
impl VarGuard {
pub fn set<K: AsRef<OsStr>, V: AsRef<OsStr>>(key: K, value: V) -> Self {
let previous = std::env::var_os(&key);
set_var(&key, value);
Self {
key: key.as_ref().to_owned(),
previous,
}
}
}
impl Drop for VarGuard {
fn drop(&mut self) {
match self.previous.take() {
Some(previous) => set_var(&self.key, previous),
None => remove_var(&self.key),
}
}
}
pub struct EnvVarGuard {
key: &'static str,
previous: Option<std::ffi::OsString>,
_lock: crate::core::data_dir::TestEnvGuard,
}
impl EnvVarGuard {
pub fn set(key: &'static str, value: &str) -> Self {
let lock = crate::core::data_dir::test_env_lock();
let previous = std::env::var_os(key);
set_var(key, value);
Self {
key,
previous,
_lock: lock,
}
}
}
impl Drop for EnvVarGuard {
fn drop(&mut self) {
if let Some(previous) = &self.previous {
set_var(self.key, previous);
} else {
remove_var(self.key);
}
}
}
pub struct CurrentDirGuard {
previous: std::path::PathBuf,
_lock: crate::core::data_dir::TestEnvGuard,
}
impl CurrentDirGuard {
pub fn enter(directory: &std::path::Path) -> Self {
let lock = crate::core::data_dir::test_env_lock();
let previous = std::env::current_dir().expect("read the current directory");
std::env::set_current_dir(directory).expect("enter the test directory");
Self {
previous,
_lock: lock,
}
}
}
impl Drop for CurrentDirGuard {
fn drop(&mut self) {
let _ = std::env::set_current_dir(&self.previous);
}
}