#![allow(clippy::unwrap_used, clippy::expect_used)]
use daaki_message::DateTime;
use proptest::prelude::*;
fn arb_datetime() -> impl Strategy<Value = DateTime> {
(
2000u16..2030,
1u8..=12,
1u8..=28,
0u8..=23,
0u8..=59,
0u8..=59,
prop_oneof![Just(0i16), Just(330), Just(-480), Just(60), Just(-300)],
)
.prop_map(|(year, month, day, hour, minute, second, tz)| {
DateTime::new(year, month, day, hour, minute, second, tz)
})
}
const MONTHS: [&str; 12] = [
"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
];
fn format_tz(tz_offset_minutes: i16) -> (char, i16, i16) {
if tz_offset_minutes >= 0 {
('+', tz_offset_minutes / 60, tz_offset_minutes % 60)
} else {
('-', (-tz_offset_minutes) / 60, (-tz_offset_minutes) % 60)
}
}
proptest! {
#![proptest_config(ProptestConfig::with_cases(256))]
#[test]
fn standard_format_parses(dt in arb_datetime()) {
let s = dt.to_rfc5322_string();
let parsed = DateTime::parse_rfc5322(&s);
prop_assert!(parsed.is_some(), "standard date must parse: {:?}", s);
let p = parsed.unwrap();
prop_assert_eq!(p.year(), dt.year());
prop_assert_eq!(p.month(), dt.month());
prop_assert_eq!(p.day(), dt.day());
}
#[test]
fn date_without_dow_parses(dt in arb_datetime()) {
let m = MONTHS[(dt.month() - 1) as usize];
let (sign, h, min) = format_tz(dt.tz_offset_minutes());
let s = format!(
"{} {} {} {:02}:{:02}:{:02} {}{:02}{:02}",
dt.day(), m, dt.year(), dt.hour(), dt.minute(), dt.second(), sign, h, min
);
let parsed = DateTime::parse_rfc5322(&s);
prop_assert!(parsed.is_some(), "date without day-of-week must parse: {:?}", s);
}
#[test]
fn date_with_comma_after_month(dt in arb_datetime()) {
let m = MONTHS[(dt.month() - 1) as usize];
let (sign, h, min) = format_tz(dt.tz_offset_minutes());
let s = format!(
"{} {}, {} {:02}:{:02}:{:02} {}{:02}{:02}",
dt.day(), m, dt.year(), dt.hour(), dt.minute(), dt.second(), sign, h, min
);
let parsed = DateTime::parse_rfc5322(&s);
prop_assert!(parsed.is_some(), "date with comma after month must parse: {:?}", s);
let p = parsed.unwrap();
prop_assert_eq!(p.day(), dt.day(), "day mismatch for {:?}", s);
prop_assert_eq!(p.month(), dt.month(), "month mismatch for {:?}", s);
prop_assert_eq!(p.year(), dt.year(), "year mismatch for {:?}", s);
}
#[test]
fn date_with_extra_whitespace(dt in arb_datetime()) {
let m = MONTHS[(dt.month() - 1) as usize];
let (sign, h, min) = format_tz(dt.tz_offset_minutes());
let s = format!(
"{} {} {} {:02}:{:02}:{:02} {}{:02}{:02}",
dt.day(), m, dt.year(), dt.hour(), dt.minute(), dt.second(), sign, h, min
);
let parsed = DateTime::parse_rfc5322(&s);
prop_assert!(parsed.is_some(), "date with extra whitespace must parse: {:?}", s);
}
}