diff --git a/backend/modules/chess/src/time_control.rs b/backend/modules/chess/src/time_control.rs index 0b5feff4..5099547d 100644 --- a/backend/modules/chess/src/time_control.rs +++ b/backend/modules/chess/src/time_control.rs @@ -68,6 +68,41 @@ impl PlayerClock { } pub fn time_out(&self) -> bool { - self.remaining_time.is_zero() + self.get_real_time_remaining().is_zero() + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn stopped_clock_reports_timeout_when_remaining_is_zero() { + let mut clock = PlayerClock::new(Duration::from_secs(0)); + assert!(clock.time_out()); + + clock.set_remaining_time(Duration::from_secs(10)); + assert!(!clock.time_out()); + } + + #[test] + fn running_clock_flags_when_it_runs_past_zero_on_the_mover() { + // Player on the move with almost no time left, clock running. + let mut clock = PlayerClock::new(Duration::from_millis(1)); + clock.start(); + // The mover sits on the running clock past zero without moving. + std::thread::sleep(Duration::from_millis(5)); + + // remaining_time is untouched until stop(), so the raw field is still + // non-zero; flag-fall must be detected via the real remaining time. + assert!(!clock.remaining_time.is_zero()); + assert!(clock.time_out()); + } + + #[test] + fn running_clock_with_time_left_is_not_flagged() { + let mut clock = PlayerClock::new(Duration::from_secs(60)); + clock.start(); + assert!(!clock.time_out()); } }