travelagent 1.11.1

Agent-first TUI code review tool
//! Test-only helpers shared by unit tests across the TUI crate.
//!
//! The process-global current-working-directory is a shared resource that several
//! tests must mutate (to point App::new at a fresh temp repo). Each test module
//! used to declare its own `Mutex`, which meant tests in different modules could
//! race against each other even though they individually serialised. This
//! module exposes a single crate-wide lock so every test participates in the
//! same serialisation — and it returns a poison-tolerant guard so a single
//! panicking test does not cascade into every subsequent test.

#![cfg(test)]

use std::sync::{Mutex, MutexGuard, OnceLock, PoisonError};

use tokio::runtime::{Handle, Runtime};

static CWD_LOCK: Mutex<()> = Mutex::new(());

/// Acquire the shared CWD lock, returning the inner guard even when the mutex
/// has been poisoned by a prior panic. Test isolation is still preserved
/// because the guard still serialises access to the directory.
pub fn cwd_lock() -> MutexGuard<'static, ()> {
    CWD_LOCK.lock().unwrap_or_else(PoisonError::into_inner)
}

/// Return a `tokio::runtime::Handle` backed by a process-wide test runtime.
///
/// Production code in the TUI takes a `Handle` everywhere an async forge call
/// fires. Tests need a handle just to satisfy `App::build`'s signature —
/// they don't actually exercise forge async paths. Lazily spinning up a
/// single shared multi-thread runtime keeps the test footprint small while
/// letting every `#[test]` get a real handle without per-test runtime
/// churn.
///
/// The runtime is stored in a `OnceLock` so it's never dropped for the
/// lifetime of the test process; tokio's multi-thread runtime refuses to
/// drop while it still has spawned work, and leaking it matches how the
/// production runtime in `main.rs` lives for the duration of `trv`.
pub fn runtime_handle() -> Handle {
    static RUNTIME: OnceLock<Runtime> = OnceLock::new();
    RUNTIME
        .get_or_init(|| {
            tokio::runtime::Builder::new_multi_thread()
                .worker_threads(1)
                .enable_all()
                .build()
                .expect("test runtime builds")
        })
        .handle()
        .clone()
}