hegel/generators/time.rs
1use super::{Generator, TestCase, integers};
2use crate::test_case::invalid_argument;
3use std::time::Duration;
4
5/// Generator for [`Duration`] values. Created by [`durations()`].
6///
7/// Internally generates nanoseconds as a `u64`, so the maximum representable
8/// duration is approximately 584 years (`u64::MAX` nanoseconds).
9pub struct DurationGenerator {
10 min_nanos: u64,
11 max_nanos: u64,
12 /// Set when `min_value` was given a duration above `u64::MAX`
13 /// nanoseconds: no generatable value could satisfy it, so the draw
14 /// reports a usage error instead of silently generating below the
15 /// requested minimum.
16 min_unrepresentable: bool,
17}
18
19impl DurationGenerator {
20 /// Set the minimum duration (inclusive).
21 pub fn min_value(mut self, min: Duration) -> Self {
22 match u64::try_from(min.as_nanos()) {
23 Ok(nanos) => {
24 self.min_nanos = nanos;
25 self.min_unrepresentable = false;
26 }
27 Err(_) => self.min_unrepresentable = true,
28 }
29 self
30 }
31
32 /// Set the maximum duration (inclusive). Saturates at `u64::MAX`
33 /// nanoseconds, the largest generatable duration.
34 pub fn max_value(mut self, max: Duration) -> Self {
35 self.max_nanos = duration_to_nanos(max);
36 self
37 }
38}
39
40impl Generator<Duration> for DurationGenerator {
41 fn do_draw(&self, tc: &TestCase) -> Duration {
42 if self.min_unrepresentable {
43 invalid_argument!(
44 "min_value exceeds the largest generatable Duration \
45 (u64::MAX nanoseconds, about 584 years)"
46 );
47 }
48 if self.min_nanos > self.max_nanos {
49 invalid_argument!("Cannot have max_value < min_value");
50 }
51 let nanos = integers::<u64>()
52 .min_value(self.min_nanos)
53 .max_value(self.max_nanos)
54 .do_draw(tc);
55 Duration::from_nanos(nanos)
56 }
57}
58
59/// Generate [`Duration`] values.
60/// By default, generates durations from zero up to `u64::MAX` nanoseconds
61/// (approximately 584 years). Use builder methods `min_value` and `max_value`
62/// to constrain the range. See [`DurationGenerator`] for more details.
63///
64/// # Example
65///
66/// ```no_run
67/// use std::time::Duration;
68///
69/// #[hegel::test]
70/// fn my_test(tc: hegel::TestCase) {
71/// let d = tc.draw(hegel::generators::durations()
72/// .max_value(Duration::from_secs(60)));
73/// assert!(d <= Duration::from_secs(60));
74/// }
75/// ```
76pub fn durations() -> DurationGenerator {
77 DurationGenerator {
78 min_nanos: 0,
79 max_nanos: u64::MAX,
80 min_unrepresentable: false,
81 }
82}
83
84fn duration_to_nanos(d: Duration) -> u64 {
85 d.as_nanos().try_into().unwrap_or(u64::MAX)
86}