Skip to main content

doido_core/
test_time.rs

1//! Test time control (Rails `travel_to` / `travel`).
2//!
3//! Rust has no global mutable clock, so tests thread a [`TestClock`] through the
4//! code under test (read time via `clock.now()`), then move it with `travel`/
5//! `travel_to`.
6
7use chrono::{DateTime, Duration, Utc};
8use std::sync::Mutex;
9
10/// A clock whose "now" can be set and advanced.
11pub struct TestClock {
12    now: Mutex<DateTime<Utc>>,
13}
14
15impl TestClock {
16    /// A clock frozen at `at`.
17    pub fn new(at: DateTime<Utc>) -> Self {
18        Self {
19            now: Mutex::new(at),
20        }
21    }
22
23    /// The current (frozen) time.
24    pub fn now(&self) -> DateTime<Utc> {
25        *self.now.lock().unwrap()
26    }
27
28    /// Jump to an absolute time (Rails `travel_to`).
29    pub fn travel_to(&self, at: DateTime<Utc>) {
30        *self.now.lock().unwrap() = at;
31    }
32
33    /// Advance by a duration (Rails `travel`).
34    pub fn travel(&self, by: Duration) {
35        let mut now = self.now.lock().unwrap();
36        *now += by;
37    }
38}