1use core::time::Duration;
2use std::time::SystemTime;
3
4use ::proptest::{
5 arbitrary::{any, Arbitrary},
6 strategy::{BoxedStrategy, Just, Strategy},
7};
8
9use crate::{AtomicDuration, AtomicOptionDuration, AtomicOptionSystemTime, AtomicSystemTime};
10
11fn duration_strategy() -> BoxedStrategy<Duration> {
12 (any::<u64>(), 0..1_000_000_000u32)
13 .prop_map(|(seconds, nanoseconds)| Duration::new(seconds, nanoseconds))
14 .boxed()
15}
16
17fn option_duration_strategy() -> BoxedStrategy<Option<Duration>> {
18 ::proptest::prop_oneof![Just(None), duration_strategy().prop_map(Some),].boxed()
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 system_time_strategy() -> BoxedStrategy<SystemTime> {
28 (0..=i32::MAX as u64, 0..1_000_000_000u32)
29 .prop_map(|(seconds, nanoseconds)| {
30 system_time_from_duration(Duration::new(seconds, nanoseconds))
31 })
32 .boxed()
33}
34
35fn option_system_time_strategy() -> BoxedStrategy<Option<SystemTime>> {
36 ::proptest::prop_oneof![Just(None), system_time_strategy().prop_map(Some),].boxed()
37}
38
39impl Arbitrary for AtomicDuration {
40 type Parameters = ();
41 type Strategy = BoxedStrategy<Self>;
42
43 fn arbitrary_with(_: Self::Parameters) -> Self::Strategy {
44 duration_strategy().prop_map(Self::new).boxed()
45 }
46}
47
48impl Arbitrary for AtomicOptionDuration {
49 type Parameters = ();
50 type Strategy = BoxedStrategy<Self>;
51
52 fn arbitrary_with(_: Self::Parameters) -> Self::Strategy {
53 option_duration_strategy().prop_map(Self::new).boxed()
54 }
55}
56
57impl Arbitrary for AtomicSystemTime {
58 type Parameters = ();
59 type Strategy = BoxedStrategy<Self>;
60
61 fn arbitrary_with(_: Self::Parameters) -> Self::Strategy {
62 system_time_strategy().prop_map(Self::new).boxed()
63 }
64}
65
66impl Arbitrary for AtomicOptionSystemTime {
67 type Parameters = ();
68 type Strategy = BoxedStrategy<Self>;
69
70 fn arbitrary_with(_: Self::Parameters) -> Self::Strategy {
71 option_system_time_strategy().prop_map(Self::new).boxed()
72 }
73}
74
75#[cfg(test)]
76mod tests {
77 use super::*;
78 use core::sync::atomic::Ordering;
79 use std::cell::Cell;
80
81 use ::proptest::{strategy::ValueTree, test_runner::TestRunner};
82
83 #[test]
84 fn strategies_generate_readable_values() {
85 let mut runner = TestRunner::default();
86
87 let duration = <AtomicDuration as Arbitrary>::arbitrary()
88 .new_tree(&mut runner)
89 .unwrap()
90 .current();
91 let _ = duration.load(Ordering::SeqCst);
92
93 let option_duration = <AtomicOptionDuration as Arbitrary>::arbitrary()
94 .new_tree(&mut runner)
95 .unwrap()
96 .current();
97 let _ = option_duration.load(Ordering::SeqCst);
98
99 let system_time = <AtomicSystemTime as Arbitrary>::arbitrary()
100 .new_tree(&mut runner)
101 .unwrap()
102 .current();
103 assert!(system_time
104 .load(Ordering::SeqCst)
105 .duration_since(SystemTime::UNIX_EPOCH)
106 .is_ok());
107
108 let option_system_time = <AtomicOptionSystemTime as Arbitrary>::arbitrary()
109 .new_tree(&mut runner)
110 .unwrap()
111 .current();
112 assert!(option_system_time
113 .load(Ordering::SeqCst)
114 .is_none_or(|value| value.duration_since(SystemTime::UNIX_EPOCH).is_ok()));
115 }
116
117 #[test]
118 fn option_strategies_cover_none_and_some_without_panicking() {
119 let duration_none = Cell::new(false);
120 let duration_some = Cell::new(false);
121 let duration_strategy = <AtomicOptionDuration as Arbitrary>::arbitrary();
122 TestRunner::default()
123 .run(&duration_strategy, |value| {
124 match value.load(Ordering::SeqCst) {
125 None => duration_none.set(true),
126 Some(_) => duration_some.set(true),
127 }
128 Ok(())
129 })
130 .unwrap();
131 assert!(duration_none.get());
132 assert!(duration_some.get());
133
134 let system_time_none = Cell::new(false);
135 let system_time_some = Cell::new(false);
136 let system_time_strategy = <AtomicOptionSystemTime as Arbitrary>::arbitrary();
137 TestRunner::default()
138 .run(&system_time_strategy, |value| {
139 match value.load(Ordering::SeqCst) {
140 None => system_time_none.set(true),
141 Some(time) => {
142 system_time_some.set(true);
143 assert!(time.duration_since(SystemTime::UNIX_EPOCH).is_ok());
144 }
145 }
146 Ok(())
147 })
148 .unwrap();
149 assert!(system_time_none.get());
150 assert!(system_time_some.get());
151 }
152}