// tests/common/iso.rs --- isolated bootstrap roots for integration tests.

//! The integration suite's side of `pmacs::bootstrap`.
//!
//! An integration test links `pmacs` as an ordinary dependency, so it is
//! compiled **without** `cfg(test)` and the `#[cfg(not(test))]` guard in
//! `EditorState::new` is live for it: a raw `EditorState::new()` reads
//! the developer's real `~/.config/pmacs/init.lua` and writes bundled
//! packages into the developer's real `~/.local/share/pmacs`. It cannot
//! fix that by setting an environment variable --- `std::env::set_var`
//! is `unsafe` and `pmacs` is `#![forbid(unsafe_code)]`. So it passes
//! [`roots`] to `EditorState::new_with_roots` instead.
//!
//! See `docs/test-ambient-config-isolation-framing.md`.
//!
//! Included per-file rather than through `mod common;` so a suite that
//! needs no daemon or PTY fixture does not compile them:
//!
//! ```ignore
//! #[path = "common/iso.rs"]
//! mod iso;
//! ```
//!
//! [`roots`] is a **pure function of the build environment** --- no
//! counter, no `OnceLock`. Two copies of this module in one test binary
//! (one via `mod common;`, one via `#[path]`) therefore return the same
//! value rather than racing over a shared counter.

#![allow(dead_code)] // not every including suite uses every helper

use std::path::PathBuf;

use pmacs::bootstrap::BootstrapRoots;

/// The shared isolated base, under Cargo's per-package integration-test
/// temp directory.
///
/// `CARGO_TARGET_TMPDIR` (`target/<profile>/tmp`) rather than `/tmp`:
/// nothing here is ever unlinked --- there is no libtest teardown hook
/// to unlink it from --- so the tree has to live somewhere `cargo clean`
/// owns instead of leaking into the system temp dir once per run.
///
/// Deliberately shared across tests and across test binaries.
/// `materialize_all` is content-gated and idempotent, so after the first
/// construction every later one is a no-op read; a per-test directory
/// would repeat the whole materialization ~330 times per run for no
/// isolation gain (the tree is byte-identical for every caller).
#[must_use]
pub fn base() -> PathBuf {
    PathBuf::from(env!("CARGO_TARGET_TMPDIR")).join("ambient-isolation")
}

/// Isolated bootstrap roots for an in-process editor.
///
/// Pass to `EditorState::new_with_roots` / `open_with_roots`.
#[must_use]
pub fn roots() -> BootstrapRoots {
    let base = base();
    let roots = BootstrapRoots::isolated_under(&base);
    // Create the config dir eagerly. `load_user_config_at` registers it
    // on Lua's `package.path` whether or not `init.lua` exists, and a
    // suite that later writes a config chunk into it should not have to
    // know the layout.
    if let Some(dir) = roots.config_dir() {
        std::fs::create_dir_all(&dir).expect("create isolated config dir");
    }
    roots
}
