1use std::sync::{Arc, Mutex};
2
3use chrono::{DateTime, Duration, Utc};
4
5use crate::Clock;
6
7#[derive(Clone)]
11pub struct SystemClock;
12
13impl SystemClock {
14 #[allow(clippy::new_ret_no_self)]
16 pub fn new() -> Arc<dyn Clock> {
17 Arc::new(Self)
18 }
19}
20
21impl Default for SystemClock {
22 fn default() -> Self {
23 Self
24 }
25}
26
27impl Clock for SystemClock {
28 fn now(&self) -> DateTime<Utc> {
29 Utc::now()
30 }
31}
32
33#[derive(Clone)]
35pub struct TestClock {
36 pub(crate) time: Arc<Mutex<DateTime<Utc>>>,
37}
38
39impl TestClock {
40 #[allow(clippy::new_ret_no_self)]
42 pub fn new() -> Arc<dyn Clock> {
43 Arc::new(Self {
44 time: Arc::new(Mutex::new(Utc::now())),
45 })
46 }
47
48 pub fn new_at(time: DateTime<Utc>) -> Arc<dyn Clock> {
50 Arc::new(Self {
51 time: Arc::new(Mutex::new(time)),
52 })
53 }
54
55 pub fn build_for_testing() -> Self {
57 Self {
58 time: Arc::new(Mutex::new(Utc::now())),
59 }
60 }
61
62 pub fn build_for_testing_at(time: DateTime<Utc>) -> Self {
64 Self {
65 time: Arc::new(Mutex::new(time)),
66 }
67 }
68
69 pub fn advance(&self, duration: Duration) {
71 let mut time = self.time.lock().unwrap();
72 *time += duration;
73 }
74
75 pub fn set(&self, new_time: DateTime<Utc>) {
77 let mut time = self.time.lock().unwrap();
78 *time = new_time;
79 }
80}
81
82impl Default for TestClock {
83 fn default() -> Self {
84 Self {
85 time: Arc::new(Mutex::new(Utc::now())),
86 }
87 }
88}
89
90impl Clock for TestClock {
91 fn now(&self) -> DateTime<Utc> {
92 *self.time.lock().unwrap()
93 }
94}
95
96#[cfg(test)]
97mod tests {
98 use std::{
99 sync::{Arc, Mutex},
100 thread,
101 };
102
103 use chrono::TimeZone;
104
105 use super::*;
106
107 #[test]
108 fn test_system_clock_new() {
109 let clock = SystemClock::new();
110 let _ = clock.now(); }
112
113 #[test]
114 fn test_system_clock_returns_real_time() {
115 let clock = SystemClock::new();
116 let before = Utc::now();
117 let clock_time = clock.now();
118 let after = Utc::now();
119
120 assert!(clock_time >= before - Duration::seconds(1));
122 assert!(clock_time <= after + Duration::seconds(1));
123 }
124
125 #[test]
126 fn test_system_clock_is_send_sync() {
127 fn assert_send<T: Send>() {}
128 fn assert_sync<T: Sync>() {}
129 assert_send::<SystemClock>();
130 assert_sync::<SystemClock>();
131 }
132
133 #[test]
134 fn test_test_clock_new() {
135 let clock = TestClock::new();
136 let _ = clock.now(); }
138
139 #[test]
140 fn test_test_clock_new_at() {
141 let time = Utc.with_ymd_and_hms(2025, 1, 1, 0, 0, 0).unwrap();
142 let clock = TestClock::new_at(time);
143 assert_eq!(clock.now(), time);
144 }
145
146 #[test]
147 fn test_test_clock_advance() {
148 let start_time = Utc.with_ymd_and_hms(2025, 1, 1, 0, 0, 0).unwrap();
149
150 let test_clock = TestClock {
152 time: Arc::new(Mutex::new(start_time)),
153 };
154
155 test_clock.advance(Duration::hours(5));
156 let expected = start_time + Duration::hours(5);
157 assert_eq!(test_clock.now(), expected);
158 }
159
160 #[test]
161 fn test_test_clock_advance_is_additive() {
162 let start_time = Utc.with_ymd_and_hms(2025, 1, 1, 0, 0, 0).unwrap();
163 let test_clock = TestClock {
164 time: Arc::new(Mutex::new(start_time)),
165 };
166
167 test_clock.advance(Duration::hours(2));
168 test_clock.advance(Duration::hours(3));
169
170 let expected = start_time + Duration::hours(5);
171 assert_eq!(test_clock.now(), expected);
172 }
173
174 #[test]
175 fn test_test_clock_set() {
176 let start_time = Utc.with_ymd_and_hms(2025, 1, 1, 0, 0, 0).unwrap();
177 let test_clock = TestClock {
178 time: Arc::new(Mutex::new(start_time)),
179 };
180
181 let new_time = Utc.with_ymd_and_hms(2025, 6, 15, 12, 30, 0).unwrap();
182 test_clock.set(new_time);
183
184 assert_eq!(test_clock.now(), new_time);
185 }
186
187 #[test]
188 fn test_test_clock_is_clone() {
189 let start_time = Utc.with_ymd_and_hms(2025, 1, 1, 0, 0, 0).unwrap();
190 let test_clock = TestClock {
191 time: Arc::new(Mutex::new(start_time)),
192 };
193
194 let clock2 = test_clock.clone();
195
196 test_clock.advance(Duration::hours(1));
198 assert_eq!(clock2.now(), start_time + Duration::hours(1));
199 }
200
201 #[test]
202 fn test_test_clock_concurrent_access() {
203 let start_time = Utc.with_ymd_and_hms(2025, 1, 1, 0, 0, 0).unwrap();
204 let test_clock = TestClock {
205 time: Arc::new(Mutex::new(start_time)),
206 };
207
208 let clock1 = test_clock.clone();
209 let clock2 = test_clock.clone();
210
211 let handle1 = thread::spawn(move || {
212 clock1.advance(Duration::hours(1));
213 });
214
215 let handle2 = thread::spawn(move || {
216 clock2.advance(Duration::hours(2));
217 });
218
219 handle1.join().unwrap();
220 handle2.join().unwrap();
221
222 assert_eq!(test_clock.now(), start_time + Duration::hours(3));
224 }
225
226 #[test]
227 fn test_arc_dyn_clock_pattern() {
228 let clock: Arc<dyn Clock> = SystemClock::new();
230 let _ = clock.now();
231
232 let test_clock: Arc<dyn Clock> = TestClock::new();
233 let _ = test_clock.now();
234 }
235}