Skip to main content

omni_dev/voice/
clock.rs

1//! Pluggable wall clock for deterministic timestamps in tests.
2//!
3//! Mirrors the [`UlidRng`](super::det::UlidRng) pattern: production code
4//! uses [`SystemClock`], tests inject [`FixedClock`] so snapshot output is
5//! byte-stable.
6
7use chrono::{DateTime, Utc};
8
9/// Source of wall-clock time.
10pub trait Clock: Send + Sync {
11    /// Returns the current UTC time.
12    fn now(&self) -> DateTime<Utc>;
13}
14
15/// Production clock: defers to `Utc::now()`.
16#[derive(Debug, Default)]
17pub struct SystemClock;
18
19impl Clock for SystemClock {
20    fn now(&self) -> DateTime<Utc> {
21        Utc::now()
22    }
23}
24
25/// Test clock: always returns the same instant.
26#[derive(Debug, Clone)]
27pub struct FixedClock(pub DateTime<Utc>);
28
29impl FixedClock {
30    /// Parses an RFC3339 timestamp into a fixed clock. Panics if `s` is
31    /// not a valid RFC3339 string — intended for test-only use, where a
32    /// hard-coded constant string is the input.
33    #[must_use]
34    #[allow(clippy::expect_used, clippy::missing_panics_doc)]
35    pub fn from_rfc3339(s: &str) -> Self {
36        let dt = DateTime::parse_from_rfc3339(s)
37            .expect("FixedClock::from_rfc3339: invalid RFC3339 timestamp")
38            .with_timezone(&Utc);
39        Self(dt)
40    }
41}
42
43impl Clock for FixedClock {
44    fn now(&self) -> DateTime<Utc> {
45        self.0
46    }
47}
48
49#[cfg(test)]
50mod tests {
51    use super::*;
52
53    #[test]
54    fn fixed_clock_returns_same_instant_repeatedly() {
55        let clock = FixedClock::from_rfc3339("2026-01-01T00:00:00Z");
56        let a = clock.now();
57        let b = clock.now();
58        assert_eq!(a, b);
59    }
60
61    #[test]
62    fn fixed_clock_from_rfc3339_parses_utc() {
63        let clock = FixedClock::from_rfc3339("2026-01-01T00:00:00Z");
64        assert_eq!(clock.0.to_rfc3339(), "2026-01-01T00:00:00+00:00");
65    }
66
67    #[test]
68    fn system_clock_returns_recent_time() {
69        let clock = SystemClock;
70        let now = clock.now();
71        let real_now = Utc::now();
72        let delta = (real_now - now).num_seconds().abs();
73        assert!(delta < 2, "SystemClock should be close to Utc::now()");
74    }
75}