Skip to main content

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}