From 3d978e3978824734352d5c8507fcb291b1a3789b Mon Sep 17 00:00:00 2001 From: jars Date: Sat, 9 May 2026 11:30:33 +0100 Subject: [PATCH] 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 --- crates/core/src/power.rs | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/crates/core/src/power.rs b/crates/core/src/power.rs index e032d14..8f83ede 100644 --- a/crates/core/src/power.rs +++ b/crates/core/src/power.rs @@ -64,6 +64,7 @@ fn read_trimmed(path: &Path) -> Option { 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> = Mutex::new(None); +#[cfg(test)] fn test_get_override() -> Option { *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(state: Option, 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)]