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}