#![expect(clippy::unwrap_used)]
use super::{parse_date_only, parse_iso8601_or_date};
const FLAG: &str = "--created-since";
#[test]
fn accepts_bare_date_and_canonicalizes() {
let canon = parse_iso8601_or_date("2026-04-01", FLAG).unwrap();
assert_eq!(canon, "2026-04-01T00:00:00Z");
}
#[test]
fn accepts_naive_datetime_unchanged() {
let canon = parse_iso8601_or_date("2026-04-01T12:30:45", FLAG).unwrap();
assert_eq!(canon, "2026-04-01T12:30:45");
}
#[test]
fn accepts_zulu_datetime_unchanged() {
let canon = parse_iso8601_or_date("2026-04-01T12:30:45Z", FLAG).unwrap();
assert_eq!(canon, "2026-04-01T12:30:45Z");
}
#[test]
fn accepts_positive_offset_unchanged() {
let canon = parse_iso8601_or_date("2026-04-01T12:30:45+05:30", FLAG).unwrap();
assert_eq!(canon, "2026-04-01T12:30:45+05:30");
}
#[test]
fn accepts_negative_offset_unchanged() {
let canon = parse_iso8601_or_date("2026-04-01T12:30:45-08:00", FLAG).unwrap();
assert_eq!(canon, "2026-04-01T12:30:45-08:00");
}
#[test]
fn accepts_leap_second() {
let canon = parse_iso8601_or_date("2016-12-31T23:59:60Z", FLAG).unwrap();
assert_eq!(canon, "2016-12-31T23:59:60Z");
}
#[test]
fn rejects_empty_string() {
let err = parse_iso8601_or_date("", FLAG).unwrap_err();
assert!(err.to_string().contains(FLAG));
}
#[test]
fn rejects_garbage_word() {
let err = parse_iso8601_or_date("tomorrow", FLAG).unwrap_err();
assert!(err.to_string().contains("tomorrow"));
assert!(err.to_string().contains(FLAG));
}
#[test]
fn rejects_year_only() {
assert!(parse_iso8601_or_date("2026", FLAG).is_err());
}
#[test]
fn rejects_year_month() {
assert!(parse_iso8601_or_date("2026-04", FLAG).is_err());
}
#[test]
fn rejects_slash_separators() {
assert!(parse_iso8601_or_date("2026/04/01", FLAG).is_err());
}
#[test]
fn rejects_space_separator_between_date_and_time() {
assert!(parse_iso8601_or_date("2026-04-01 12:30:45", FLAG).is_err());
}
#[test]
fn rejects_fractional_seconds() {
assert!(parse_iso8601_or_date("2026-04-01T12:30:45.123Z", FLAG).is_err());
}
#[test]
fn rejects_week_date() {
assert!(parse_iso8601_or_date("2026-W18-3", FLAG).is_err());
}
#[test]
fn rejects_ordinal_date() {
assert!(parse_iso8601_or_date("2026-128", FLAG).is_err());
}
#[test]
fn rejects_zero_month() {
assert!(parse_iso8601_or_date("2026-00-15", FLAG).is_err());
}
#[test]
fn rejects_month_above_twelve() {
assert!(parse_iso8601_or_date("2026-13-01", FLAG).is_err());
}
#[test]
fn rejects_zero_day() {
assert!(parse_iso8601_or_date("2026-04-00", FLAG).is_err());
}
#[test]
fn rejects_day_above_thirty_one() {
assert!(parse_iso8601_or_date("2026-04-32", FLAG).is_err());
}
#[test]
fn rejects_day_past_month_length() {
assert!(parse_iso8601_or_date("2026-04-31", FLAG).is_err());
assert!(parse_iso8601_or_date("2026-02-30", FLAG).is_err());
}
#[test]
fn rejects_february_twenty_ninth_on_non_leap_year() {
assert!(parse_iso8601_or_date("2025-02-29", FLAG).is_err());
}
#[test]
fn accepts_february_twenty_ninth_on_leap_year() {
let canon = parse_iso8601_or_date("2024-02-29", FLAG).unwrap();
assert_eq!(canon, "2024-02-29T00:00:00Z");
}
#[test]
fn rejects_february_twenty_ninth_on_century_non_leap_year() {
assert!(parse_iso8601_or_date("1900-02-29", FLAG).is_err());
}
#[test]
fn accepts_february_twenty_ninth_on_quadricentennial_leap_year() {
let canon = parse_iso8601_or_date("2000-02-29", FLAG).unwrap();
assert_eq!(canon, "2000-02-29T00:00:00Z");
}
#[test]
fn accepts_year_zero() {
let canon = parse_iso8601_or_date("0000-01-01", FLAG).unwrap();
assert_eq!(canon, "0000-01-01T00:00:00Z");
}
#[test]
fn rejects_hour_above_twenty_three() {
assert!(parse_iso8601_or_date("2026-04-01T25:00:00Z", FLAG).is_err());
}
#[test]
fn rejects_minute_above_fifty_nine() {
assert!(parse_iso8601_or_date("2026-04-01T12:60:00Z", FLAG).is_err());
}
#[test]
fn rejects_second_above_sixty() {
assert!(parse_iso8601_or_date("2026-04-01T12:30:61Z", FLAG).is_err());
}
#[test]
fn rejects_offset_without_colon() {
assert!(parse_iso8601_or_date("2026-04-01T12:30:45+0530", FLAG).is_err());
}
#[test]
fn rejects_offset_with_invalid_sign() {
assert!(parse_iso8601_or_date("2026-04-01T12:30:45 05:30", FLAG).is_err());
}
#[test]
fn rejects_offset_hours_above_fourteen() {
assert!(parse_iso8601_or_date("2026-04-01T12:30:45+15:00", FLAG).is_err());
}
#[test]
fn rejects_offset_minutes_when_hour_is_fourteen() {
assert!(parse_iso8601_or_date("2026-04-01T12:30:45+14:01", FLAG).is_err());
}
#[test]
fn rejects_offset_minutes_above_fifty_nine() {
assert!(parse_iso8601_or_date("2026-04-01T12:30:45+05:60", FLAG).is_err());
}
#[test]
fn rejects_non_ascii_input() {
assert!(parse_iso8601_or_date("2026-04-0\u{00E9}", FLAG).is_err());
}
#[test]
fn error_message_includes_expected_forms() {
let err = parse_iso8601_or_date("nope", FLAG).unwrap_err();
let msg = err.to_string();
assert!(msg.contains("YYYY-MM-DD"));
assert!(msg.contains("YYYY-MM-DDTHH:MM:SS"));
assert!(msg.contains("YYYY-MM-DDTHH:MM:SSZ"));
assert!(msg.contains("YYYY-MM-DDTHH:MM:SS±HH:MM"));
}
#[test]
fn date_only_accepts_bare_date_verbatim() {
assert_eq!(
parse_date_only("2026-12-31", "--deadline").unwrap(),
"2026-12-31"
);
}
#[test]
fn date_only_rejects_datetime() {
assert!(parse_date_only("2026-12-31T00:00:00Z", "--deadline").is_err());
}
#[test]
fn date_only_rejects_garbage_and_names_flag() {
let err = parse_date_only("garbage", "--deadline").unwrap_err();
assert_eq!(err.exit_code(), 7);
assert!(err.to_string().contains("--deadline"));
}
#[test]
fn date_only_rejects_century_non_leap_feb_29() {
assert!(parse_date_only("1900-02-29", "--deadline").is_err());
}