Skip to main content

hegel/generators/
time.rs

1use super::{BasicGenerator, Generator};
2use crate::cbor_utils::cbor_map;
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}
13
14impl DurationGenerator {
15    /// Set the minimum duration (inclusive).
16    pub fn min_value(mut self, min: Duration) -> Self {
17        self.min_nanos = duration_to_nanos(min);
18        self
19    }
20
21    /// Set the maximum duration (inclusive).
22    pub fn max_value(mut self, max: Duration) -> Self {
23        self.max_nanos = duration_to_nanos(max);
24        self
25    }
26
27    fn build_schema(&self) -> ciborium::Value {
28        assert!(
29            self.min_nanos <= self.max_nanos,
30            "Cannot have max_value < min_value"
31        );
32        cbor_map! {
33            "type" => "integer",
34            "min_value" => self.min_nanos,
35            "max_value" => self.max_nanos
36        }
37    }
38}
39
40impl Generator<Duration> for DurationGenerator {
41    fn as_basic(&self) -> Option<BasicGenerator<'_, Duration>> {
42        Some(BasicGenerator::new(self.build_schema(), |raw| {
43            let nanos: u64 = super::deserialize_value(raw);
44            Duration::from_nanos(nanos)
45        }))
46    }
47}
48
49/// Generate [`Duration`] values.
50/// By default, generates durations from zero up to `u64::MAX` nanoseconds
51/// (approximately 584 years). Use builder methods `min_value` and `max_value`
52/// to constrain the range. See [`DurationGenerator`] for more details.
53///
54/// # Example
55///
56/// ```no_run
57/// use std::time::Duration;
58///
59/// #[hegel::test]
60/// fn my_test(tc: hegel::TestCase) {
61///     let d = tc.draw(hegel::generators::durations()
62///         .max_value(Duration::from_secs(60)));
63///     assert!(d <= Duration::from_secs(60));
64/// }
65/// ```
66pub fn durations() -> DurationGenerator {
67    DurationGenerator {
68        min_nanos: 0,
69        max_nanos: u64::MAX,
70    }
71}
72
73fn duration_to_nanos(d: Duration) -> u64 {
74    d.as_nanos().try_into().unwrap_or(u64::MAX)
75}