summaryrefslogtreecommitdiffstats
path: root/third_party/rust/time/src/quickcheck.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/time/src/quickcheck.rs')
-rw-r--r--third_party/rust/time/src/quickcheck.rs220
1 files changed, 220 insertions, 0 deletions
diff --git a/third_party/rust/time/src/quickcheck.rs b/third_party/rust/time/src/quickcheck.rs
new file mode 100644
index 0000000000..707f3e0a97
--- /dev/null
+++ b/third_party/rust/time/src/quickcheck.rs
@@ -0,0 +1,220 @@
+//! Implementations of the [`quickcheck::Arbitrary`](quickcheck::Arbitrary) trait.
+//!
+//! This enables users to write tests such as this, and have test values provided automatically:
+//!
+//! ```
+//! # #![allow(dead_code)]
+//! use quickcheck::quickcheck;
+//! use time::Date;
+//!
+//! struct DateRange {
+//! from: Date,
+//! to: Date,
+//! }
+//!
+//! impl DateRange {
+//! fn new(from: Date, to: Date) -> Result<Self, ()> {
+//! Ok(DateRange { from, to })
+//! }
+//! }
+//!
+//! quickcheck! {
+//! fn date_range_is_well_defined(from: Date, to: Date) -> bool {
+//! let r = DateRange::new(from, to);
+//! if from <= to {
+//! r.is_ok()
+//! } else {
+//! r.is_err()
+//! }
+//! }
+//! }
+//! ```
+//!
+//! An implementation for `Instant` is intentionally omitted since its values are only meaningful in
+//! relation to a [`Duration`], and obtaining an `Instant` from a [`Duration`] is very simple
+//! anyway.
+
+use alloc::boxed::Box;
+
+use quickcheck::{empty_shrinker, single_shrinker, Arbitrary, Gen};
+
+use crate::{Date, Duration, Month, OffsetDateTime, PrimitiveDateTime, Time, UtcOffset, Weekday};
+
+/// Obtain an arbitrary value between the minimum and maximum inclusive.
+macro_rules! arbitrary_between {
+ ($type:ty; $gen:expr, $min:expr, $max:expr) => {{
+ let min = $min;
+ let max = $max;
+ let range = max - min;
+ <$type>::arbitrary($gen).rem_euclid(range + 1) + min
+ }};
+}
+
+impl Arbitrary for Date {
+ fn arbitrary(g: &mut Gen) -> Self {
+ Self::from_julian_day_unchecked(arbitrary_between!(
+ i32;
+ g,
+ Self::MIN.to_julian_day(),
+ Self::MAX.to_julian_day()
+ ))
+ }
+
+ fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
+ Box::new(
+ self.to_ordinal_date()
+ .shrink()
+ .flat_map(|(year, ordinal)| Self::from_ordinal_date(year, ordinal)),
+ )
+ }
+}
+
+impl Arbitrary for Duration {
+ fn arbitrary(g: &mut Gen) -> Self {
+ Self::nanoseconds_i128(arbitrary_between!(
+ i128;
+ g,
+ Self::MIN.whole_nanoseconds(),
+ Self::MAX.whole_nanoseconds()
+ ))
+ }
+
+ fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
+ Box::new(
+ (self.subsec_nanoseconds(), self.whole_seconds())
+ .shrink()
+ .map(|(mut nanoseconds, seconds)| {
+ // Coerce the sign if necessary.
+ if (seconds > 0 && nanoseconds < 0) || (seconds < 0 && nanoseconds > 0) {
+ nanoseconds *= -1;
+ }
+
+ Self::new_unchecked(seconds, nanoseconds)
+ }),
+ )
+ }
+}
+
+impl Arbitrary for Time {
+ fn arbitrary(g: &mut Gen) -> Self {
+ Self::__from_hms_nanos_unchecked(
+ arbitrary_between!(u8; g, 0, 23),
+ arbitrary_between!(u8; g, 0, 59),
+ arbitrary_between!(u8; g, 0, 59),
+ arbitrary_between!(u32; g, 0, 999_999_999),
+ )
+ }
+
+ fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
+ Box::new(
+ self.as_hms_nano()
+ .shrink()
+ .map(|(hour, minute, second, nanosecond)| {
+ Self::__from_hms_nanos_unchecked(hour, minute, second, nanosecond)
+ }),
+ )
+ }
+}
+
+impl Arbitrary for PrimitiveDateTime {
+ fn arbitrary(g: &mut Gen) -> Self {
+ Self::new(<_>::arbitrary(g), <_>::arbitrary(g))
+ }
+
+ fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
+ Box::new(
+ (self.date, self.time)
+ .shrink()
+ .map(|(date, time)| Self { date, time }),
+ )
+ }
+}
+
+impl Arbitrary for UtcOffset {
+ fn arbitrary(g: &mut Gen) -> Self {
+ let seconds = arbitrary_between!(i32; g, -86_399, 86_399);
+ Self::__from_hms_unchecked(
+ (seconds / 3600) as _,
+ ((seconds % 3600) / 60) as _,
+ (seconds % 60) as _,
+ )
+ }
+
+ fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
+ Box::new(
+ self.as_hms().shrink().map(|(hours, minutes, seconds)| {
+ Self::__from_hms_unchecked(hours, minutes, seconds)
+ }),
+ )
+ }
+}
+
+impl Arbitrary for OffsetDateTime {
+ fn arbitrary(g: &mut Gen) -> Self {
+ let datetime = PrimitiveDateTime::arbitrary(g);
+ datetime.assume_offset(<_>::arbitrary(g))
+ }
+
+ fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
+ Box::new(
+ (self.local_datetime, self.offset)
+ .shrink()
+ .map(|(local_datetime, offset)| local_datetime.assume_offset(offset)),
+ )
+ }
+}
+
+impl Arbitrary for Weekday {
+ fn arbitrary(g: &mut Gen) -> Self {
+ use Weekday::*;
+ match arbitrary_between!(u8; g, 0, 6) {
+ 0 => Monday,
+ 1 => Tuesday,
+ 2 => Wednesday,
+ 3 => Thursday,
+ 4 => Friday,
+ 5 => Saturday,
+ val => {
+ debug_assert!(val == 6);
+ Sunday
+ }
+ }
+ }
+
+ fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
+ match self {
+ Self::Monday => empty_shrinker(),
+ _ => single_shrinker(self.previous()),
+ }
+ }
+}
+
+impl Arbitrary for Month {
+ fn arbitrary(g: &mut Gen) -> Self {
+ use Month::*;
+ match arbitrary_between!(u8; g, 1, 12) {
+ 1 => January,
+ 2 => February,
+ 3 => March,
+ 4 => April,
+ 5 => May,
+ 6 => June,
+ 7 => July,
+ 8 => August,
+ 9 => September,
+ 10 => October,
+ 11 => November,
+ val => {
+ debug_assert!(val == 12);
+ December
+ }
+ }
+ }
+
+ fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
+ match self {
+ Self::January => empty_shrinker(),
+ _ => single_shrinker(self.previous()),
+ }
+ }
+}