atomic_time/
quickcheck.rs1use core::sync::atomic::Ordering;
2use std::{
3 boxed::Box,
4 time::{Duration, SystemTime},
5};
6
7use ::quickcheck::{Arbitrary, Gen};
8
9use crate::{AtomicDuration, AtomicOptionDuration, AtomicOptionSystemTime, AtomicSystemTime};
10
11fn system_time_from_parts((seconds, nanoseconds): (u32, u32)) -> SystemTime {
12 let duration = Duration::new(
13 u64::from(seconds.min(i32::MAX as u32)),
14 nanoseconds % 1_000_000_000,
15 );
16 SystemTime::UNIX_EPOCH
17 .checked_add(duration)
18 .unwrap_or(SystemTime::UNIX_EPOCH)
19}
20
21fn system_time_from_duration(duration: Duration) -> SystemTime {
22 SystemTime::UNIX_EPOCH
23 .checked_add(duration)
24 .unwrap_or(SystemTime::UNIX_EPOCH)
25}
26
27fn duration_since_epoch(system_time: SystemTime) -> Duration {
28 system_time
29 .duration_since(SystemTime::UNIX_EPOCH)
30 .unwrap_or(Duration::ZERO)
31}
32
33impl Clone for AtomicDuration {
34 #[inline(always)]
40 fn clone(&self) -> Self {
41 Self::new(self.load(Ordering::SeqCst))
42 }
43}
44
45impl Clone for AtomicOptionDuration {
46 #[inline(always)]
52 fn clone(&self) -> Self {
53 Self::new(self.load(Ordering::SeqCst))
54 }
55}
56
57impl Clone for AtomicSystemTime {
58 #[inline(always)]
64 fn clone(&self) -> Self {
65 Self::new(self.load(Ordering::SeqCst))
66 }
67}
68
69impl Clone for AtomicOptionSystemTime {
70 #[inline(always)]
76 fn clone(&self) -> Self {
77 Self::new(self.load(Ordering::SeqCst))
78 }
79}
80
81impl Arbitrary for AtomicDuration {
82 fn arbitrary(g: &mut Gen) -> Self {
83 Self::new(Duration::arbitrary(g))
84 }
85
86 fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
87 Box::new(self.load(Ordering::SeqCst).shrink().map(Self::new))
88 }
89}
90
91impl Arbitrary for AtomicOptionDuration {
92 fn arbitrary(g: &mut Gen) -> Self {
93 Self::new(Option::<Duration>::arbitrary(g))
94 }
95
96 fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
97 Box::new(self.load(Ordering::SeqCst).shrink().map(Self::new))
98 }
99}
100
101impl Arbitrary for AtomicSystemTime {
102 fn arbitrary(g: &mut Gen) -> Self {
103 Self::new(system_time_from_parts(<(u32, u32)>::arbitrary(g)))
104 }
105
106 fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
107 Box::new(
108 duration_since_epoch(self.load(Ordering::SeqCst))
109 .shrink()
110 .map(|duration| Self::new(system_time_from_duration(duration))),
111 )
112 }
113}
114
115impl Arbitrary for AtomicOptionSystemTime {
116 fn arbitrary(g: &mut Gen) -> Self {
117 Self::new(Option::<(u32, u32)>::arbitrary(g).map(system_time_from_parts))
118 }
119
120 fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
121 Box::new(
122 self
123 .load(Ordering::SeqCst)
124 .map(duration_since_epoch)
125 .shrink()
126 .map(|duration| Self::new(duration.map(system_time_from_duration))),
127 )
128 }
129}
130
131#[cfg(test)]
132mod tests {
133 use super::*;
134
135 #[test]
136 fn arbitrary_values_can_be_loaded() {
137 let mut generator = Gen::new(32);
138
139 let duration = AtomicDuration::arbitrary(&mut generator);
140 let _ = duration.load(Ordering::SeqCst);
141
142 let option_duration = AtomicOptionDuration::arbitrary(&mut generator);
143 let _ = option_duration.load(Ordering::SeqCst);
144
145 let system_time = AtomicSystemTime::arbitrary(&mut generator);
146 assert!(system_time
147 .load(Ordering::SeqCst)
148 .duration_since(SystemTime::UNIX_EPOCH)
149 .is_ok());
150
151 let option_system_time = AtomicOptionSystemTime::arbitrary(&mut generator);
152 assert!(option_system_time
153 .load(Ordering::SeqCst)
154 .is_none_or(|value| value.duration_since(SystemTime::UNIX_EPOCH).is_ok()));
155 }
156
157 #[test]
158 fn clone_takes_a_snapshot() {
159 let duration = AtomicDuration::new(Duration::from_secs(1));
160 let duration_clone = duration.clone();
161 duration.store(Duration::from_secs(2), Ordering::SeqCst);
162 assert_eq!(
163 duration_clone.load(Ordering::SeqCst),
164 Duration::from_secs(1)
165 );
166
167 let option_duration = AtomicOptionDuration::new(Some(Duration::from_secs(1)));
168 let option_duration_clone = option_duration.clone();
169 option_duration.store(None, Ordering::SeqCst);
170 assert_eq!(
171 option_duration_clone.load(Ordering::SeqCst),
172 Some(Duration::from_secs(1))
173 );
174
175 let system_time = AtomicSystemTime::new(SystemTime::UNIX_EPOCH);
176 let system_time_clone = system_time.clone();
177 system_time.store(
178 SystemTime::UNIX_EPOCH + Duration::from_secs(1),
179 Ordering::SeqCst,
180 );
181 assert_eq!(
182 system_time_clone.load(Ordering::SeqCst),
183 SystemTime::UNIX_EPOCH
184 );
185
186 let option_system_time = AtomicOptionSystemTime::new(Some(SystemTime::UNIX_EPOCH));
187 let option_system_time_clone = option_system_time.clone();
188 option_system_time.store(None, Ordering::SeqCst);
189 assert_eq!(
190 option_system_time_clone.load(Ordering::SeqCst),
191 Some(SystemTime::UNIX_EPOCH)
192 );
193 }
194
195 #[test]
196 fn shrunk_system_times_remain_valid() {
197 let system_time = AtomicSystemTime::new(SystemTime::UNIX_EPOCH + Duration::from_secs(10));
198 for value in system_time.shrink().take(64) {
199 assert!(value
200 .load(Ordering::SeqCst)
201 .duration_since(SystemTime::UNIX_EPOCH)
202 .is_ok());
203 }
204
205 let none = AtomicOptionSystemTime::none();
206 assert!(none.shrink().next().is_none());
207
208 let some = AtomicOptionSystemTime::new(Some(SystemTime::UNIX_EPOCH + Duration::from_secs(10)));
209 for value in some.shrink().take(64) {
210 assert!(value
211 .load(Ordering::SeqCst)
212 .is_none_or(|time| time.duration_since(SystemTime::UNIX_EPOCH).is_ok()));
213 }
214 }
215}