use crate::Clock;
use chrono::{DateTime, Utc};
use std::sync::{Arc, Mutex};
#[derive(Debug, Clone)]
pub struct MockClock {
current: Arc<Mutex<DateTime<Utc>>>,
}
impl MockClock {
pub fn at(time: DateTime<Utc>) -> Self {
Self {
current: Arc::new(Mutex::new(time)),
}
}
pub fn now() -> Self {
Self::at(Utc::now())
}
pub fn advance_secs(&self, secs: i64) {
let mut guard = self.current.lock().unwrap();
*guard += chrono::Duration::seconds(secs);
}
pub fn advance(&self, duration: chrono::Duration) {
let mut guard = self.current.lock().unwrap();
*guard += duration;
}
pub fn set(&self, time: DateTime<Utc>) {
*self.current.lock().unwrap() = time;
}
}
impl Clock for MockClock {
fn now(&self) -> DateTime<Utc> {
*self.current.lock().unwrap()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn at_pins_initial_time() {
let t = DateTime::from_timestamp(1_700_000_000, 0).unwrap();
let clock = MockClock::at(t);
assert_eq!(clock.now(), t);
}
#[test]
fn advance_secs_moves_forward() {
let t0 = DateTime::from_timestamp(1_700_000_000, 0).unwrap();
let clock = MockClock::at(t0);
clock.advance_secs(7);
assert_eq!(
clock.now(),
t0 + chrono::Duration::seconds(7),
"advance_secs must add forward (kills `+= → -=` and body-`()`)"
);
}
#[test]
fn advance_duration_moves_forward() {
let t0 = DateTime::from_timestamp(1_700_000_000, 0).unwrap();
let clock = MockClock::at(t0);
clock.advance(chrono::Duration::hours(2));
assert_eq!(
clock.now(),
t0 + chrono::Duration::hours(2),
"advance must add forward (kills `+= -> -=` and body-`()`)"
);
}
#[test]
fn set_replaces_current_time() {
let t0 = DateTime::from_timestamp(1_700_000_000, 0).unwrap();
let t1 = DateTime::from_timestamp(1_800_000_000, 0).unwrap();
let clock = MockClock::at(t0);
clock.set(t1);
assert_eq!(
clock.now(),
t1,
"set must replace the current value (kills body-`()` mutation)"
);
}
}