diff --git a/src/lib.rs b/src/lib.rs index ebc0860..4e2e190 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -14,4 +14,6 @@ pub mod engines; pub mod instance; pub mod rolling; pub mod state; +#[cfg(test)] +pub(crate) mod test; pub mod util; diff --git a/src/test.rs b/src/test.rs new file mode 100644 index 0000000..3ac0473 --- /dev/null +++ b/src/test.rs @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2026 Nutanix, Inc. +// +// Author: Leonardo Forchini +// +//! Shared infrastructure for crate unit tests. + +use std::{cell::RefCell, path::PathBuf}; + +use rstest::fixture; + +thread_local! { + pub static ROOT_OVERRIDE: RefCell> = const { RefCell::new(None) }; +} + +/// Scoped root override for tests that access absolute paths through +/// `util::Path`. +pub(crate) struct RootOverride { + previous: Option, +} + +impl Drop for RootOverride { + fn drop(&mut self) { + ROOT_OVERRIDE.with(|root| { + root.replace(self.previous.take()); + }); + } +} + +/// Override the root used by `util::Path` on the current test thread. +pub(crate) fn override_root(root: impl Into) -> RootOverride { + let previous = ROOT_OVERRIDE.with(|slot| slot.replace(Some(root.into()))); + RootOverride { previous } +} + +/// Temporary mock root installed as the current test thread's `util::Path` +/// prefix. +pub(crate) struct MockDir { + _dir: tempfile::TempDir, + _root_override: RootOverride, + // path: PathBuf, +} + +impl MockDir { + pub(crate) fn new() -> Self { + let dir = tempfile::tempdir().unwrap(); + + Self { + _root_override: override_root(dir.path()), + // path: dir.path().into(), + _dir: dir, + } + } + + // pub(crate) fn join(&self, path: impl AsRef) -> PathBuf { + // self.path.join(path.as_ref()) + // } +} + +#[fixture] +pub(crate) fn mock_dir() -> MockDir { + MockDir::new() +} diff --git a/src/util.rs b/src/util.rs index 60c7719..d4536e1 100644 --- a/src/util.rs +++ b/src/util.rs @@ -69,12 +69,21 @@ impl fmt::Display for Path { } } -static IO_THREAD_CONTROLLER_ROOT_PATH: LazyLock = LazyLock::new(|| { +static ROOT_PATH: LazyLock = LazyLock::new(|| { std::path::PathBuf::from( env::var("IO_THREAD_CONTROLLER_ROOT_PATH").unwrap_or(String::from("/")), ) }); +fn effective_root() -> std::path::PathBuf { + #[cfg(test)] + if let Some(root) = crate::test::ROOT_OVERRIDE.with(|slot| slot.borrow().clone()) { + return root; + } + + ROOT_PATH.clone() +} + impl Path { pub fn new(s: &S) -> Self where @@ -82,7 +91,7 @@ impl Path { { let mut pb = std::path::PathBuf::from(s); if pb.is_absolute() { - pb = IO_THREAD_CONTROLLER_ROOT_PATH.join(pb.strip_prefix("/").expect("absolute path")) + pb = effective_root().join(pb.strip_prefix("/").expect("absolute path")) } Self { path: pb } }