diff --git a/src/lib.rs b/src/lib.rs index 7270364..79e1238 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -53,6 +53,7 @@ use std::path::PathBuf; use std::rc::Rc; use std::sync::atomic::{AtomicBool, AtomicIsize, AtomicUsize}; use std::sync::{Arc, Mutex}; +use std::time::SystemTime; /// Generate arbitrary structured values from raw, unstructured data. /// @@ -1272,6 +1273,34 @@ impl<'a> Arbitrary<'a> for SocketAddr { } } +impl<'a> Arbitrary<'a> for SystemTime { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + // Create a SystemTime by adding or subtracting a duration from epoch. + // The result is not guaranteed to fit. Keep trying until a good SystemTime if found. + loop { + let add: bool = u.arbitrary()?; + let duration: Duration = u.arbitrary()?; + if add { + if let Some(system_time) = SystemTime::UNIX_EPOCH.checked_add(duration) { + return Ok(system_time); + } + } else { + if let Some(system_time) = SystemTime::UNIX_EPOCH.checked_sub(duration) { + return Ok(system_time); + } + } + } + } + + fn size_hint(depth: usize) -> (usize, Option) { + size_hint::and_all(&[ + bool::size_hint(depth), + Duration::size_hint(depth), + (0, None), + ]) + } +} + #[cfg(test)] mod test { use super::*; @@ -1587,6 +1616,16 @@ mod test { ); assert_eq!((1, None), <(u8, Vec) as Arbitrary>::size_hint(0)); } + + #[test] + fn size_hint_for_system_time() { + let system_time = SystemTime::size_hint(0); + + // SystemTime::size_hint as minimum of bool + Duration + assert_eq!(system_time.0, size_hint::and(bool::size_hint(0), Duration::size_hint(0)).0); + // SystemTime::size_hint has no maximum + assert_eq!(system_time.1, None); + } } /// Multiple conflicting arbitrary attributes are used on the same field: