Skip to main content

atomic_time/
proptest.rs

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}