fix(core): cfg-gate test override + restore TEST_OVERRIDE on panic

TEST_OVERRIDE and test_get_override are now #[cfg(test)]-gated and
the read in probe_power_state is wrapped in a #[cfg(test)] block,
so test scaffolding doesn't compile into production builds.

with_override now uses a drop-guard pattern so a panic inside body
still resets TEST_OVERRIDE, preventing stale state from leaking
into subsequent tests.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
jars
2026-05-09 11:30:33 +01:00
parent 0c761c0be6
commit 3d978e3978

View File

@@ -64,6 +64,7 @@ fn read_trimmed(path: &Path) -> Option<String> {
fs::read_to_string(path).ok().map(|s| s.trim().to_owned())
}
#[cfg(test)]
use std::sync::Mutex;
/// Top-level power-state probe.
@@ -80,6 +81,7 @@ use std::sync::Mutex;
///
/// (TTL cache is added in Task 1.4.)
pub fn probe_power_state() -> PowerState {
#[cfg(test)]
if let Some(state) = test_get_override() {
return state;
}
@@ -111,14 +113,29 @@ fn platform_probe() -> PowerState {
// In-process override slot. Tests must use `with_override` (below) to
// set it; production code never writes to this. Read on every probe.
#[cfg(test)]
static TEST_OVERRIDE: Mutex<Option<PowerState>> = Mutex::new(None);
#[cfg(test)]
fn test_get_override() -> Option<PowerState> {
*TEST_OVERRIDE.lock().expect("power test override mutex poisoned")
}
/// Drop-guard that resets `TEST_OVERRIDE` to `None` on drop (including on unwind).
/// This prevents a panicking test body from leaking stale override state into
/// subsequent tests.
#[cfg(test)]
struct OverrideGuard;
#[cfg(test)]
impl Drop for OverrideGuard {
fn drop(&mut self) {
*TEST_OVERRIDE.lock().expect("power test override mutex poisoned") = None;
}
}
/// Run `body` with the in-process override set to `state`. Restores
/// the previous override (always `None` in practice) on return.
/// `TEST_OVERRIDE` to `None` on return, even if `body` panics.
///
/// Holds a dedicated `TEST_LOCK` mutex for the duration of the body,
/// so override-using unit tests run serially with respect to each
@@ -128,9 +145,8 @@ pub(crate) fn with_override<R>(state: Option<PowerState>, body: impl FnOnce() ->
static TEST_LOCK: Mutex<()> = Mutex::new(());
let _lock = TEST_LOCK.lock().expect("power TEST_LOCK poisoned");
*TEST_OVERRIDE.lock().expect("power test override mutex poisoned") = state;
let result = body();
*TEST_OVERRIDE.lock().expect("power test override mutex poisoned") = None;
result
let _guard = OverrideGuard;
body()
}
#[cfg(test)]