1use std::sync::{Arc, Mutex};
4use std::time::Duration;
5
6#[derive(Debug, Clone)]
31pub struct FakeClock {
32 inner: Arc<Mutex<FakeClockInner>>,
33}
34
35#[derive(Debug, Clone)]
36struct FakeClockInner {
37 millis: u64,
38}
39
40impl Default for FakeClock {
41 fn default() -> Self {
42 Self::new()
43 }
44}
45
46impl FakeClock {
47 pub fn new() -> Self {
49 Self {
50 inner: Arc::new(Mutex::new(FakeClockInner { millis: 0 })),
51 }
52 }
53
54 pub fn at_millis(millis: u64) -> Self {
56 Self {
57 inner: Arc::new(Mutex::new(FakeClockInner { millis })),
58 }
59 }
60
61 pub fn at(duration: Duration) -> Self {
63 Self::at_millis(duration.as_millis() as u64)
64 }
65
66 pub fn with_millis(self, millis: u64) -> Self {
68 self.inner.lock().expect("lock").millis = millis;
69 self
70 }
71
72 pub fn with_duration(self, duration: Duration) -> Self {
74 self.with_millis(duration.as_millis() as u64)
75 }
76
77 pub fn now_millis(&self) -> u64 {
79 self.inner.lock().expect("lock").millis
80 }
81
82 pub fn now(&self) -> Duration {
84 Duration::from_millis(self.now_millis())
85 }
86
87 pub fn advance(&self, duration: Duration) {
89 self.advance_millis(duration.as_millis() as u64);
90 }
91
92 pub fn advance_millis(&self, millis: u64) {
94 let mut inner = self.inner.lock().expect("lock");
95 inner.millis = inner.millis.saturating_add(millis);
96 }
97
98 pub fn reset(&self) {
100 self.inner.lock().expect("lock").millis = 0;
101 }
102}
103
104#[cfg(test)]
105mod tests {
106 use super::*;
107
108 #[test]
109 fn new_clock_starts_at_zero() {
110 let clock = FakeClock::new();
111 assert_eq!(clock.now_millis(), 0);
112 }
113
114 #[test]
115 fn at_millis_sets_initial_time() {
116 let clock = FakeClock::at_millis(5000);
117 assert_eq!(clock.now_millis(), 5000);
118 }
119
120 #[test]
121 fn at_duration_sets_initial_time() {
122 let clock = FakeClock::at(Duration::from_secs(10));
123 assert_eq!(clock.now_millis(), 10000);
124 }
125
126 #[test]
127 fn with_millis_configures_time() {
128 let clock = FakeClock::new().with_millis(1234);
129 assert_eq!(clock.now_millis(), 1234);
130 }
131
132 #[test]
133 fn with_duration_configures_time() {
134 let clock = FakeClock::new().with_duration(Duration::from_secs(30));
135 assert_eq!(clock.now_millis(), 30000);
136 }
137
138 #[test]
139 fn advance_increments_time() {
140 let clock = FakeClock::new().with_millis(100);
141 clock.advance(Duration::from_millis(50));
142
143 assert_eq!(clock.now_millis(), 150);
144 }
145
146 #[test]
147 fn advance_millis_increments_time() {
148 let clock = FakeClock::new().with_millis(100);
149 clock.advance_millis(200);
150
151 assert_eq!(clock.now_millis(), 300);
152 }
153
154 #[test]
155 fn reset_returns_to_zero() {
156 let clock = FakeClock::new().with_millis(9999);
157 clock.reset();
158
159 assert_eq!(clock.now_millis(), 0);
160 }
161
162 #[test]
163 fn saturating_addition_on_overflow() {
164 let clock = FakeClock::new().with_millis(u64::MAX);
165 clock.advance_millis(1);
166
167 assert_eq!(clock.now_millis(), u64::MAX);
168 }
169
170 #[test]
171 fn thread_safe_sharing() {
172 use std::sync::Arc;
173 use std::thread;
174
175 let clock = Arc::new(FakeClock::new());
176
177 let handles: Vec<_> = (0..4)
178 .map(|_i| {
179 let c = clock.clone();
180 thread::spawn(move || {
181 c.advance_millis(100);
182 c.now_millis()
183 })
184 })
185 .collect();
186
187 let _results: Vec<_> = handles.into_iter().map(|h| h.join().unwrap()).collect();
188
189 assert_eq!(clock.now_millis(), 400);
190 }
191}