use thiserror::Error;
#[derive(Debug, Clone, PartialEq, Eq, Error)]
pub enum Error {
#[error("{0}")]
Easter(#[from] EasterError),
#[error("{0}")]
Weekday(#[from] WeekdayError),
#[error("{0}")]
RelativeDelta(#[from] RelativeDeltaError),
#[error("{0}")]
Parse(#[from] ParseError),
#[error("{0}")]
RRule(#[from] RRuleError),
#[error("{0}")]
Tz(#[from] TzError),
}
#[derive(Debug, Clone, PartialEq, Eq, Error)]
pub enum EasterError {
#[error("invalid method: {0}")]
InvalidMethod(i32),
#[error("invalid year: {0}")]
InvalidYear(i32),
#[error("date out of range: {year}-{month}-{day}")]
DateOutOfRange { year: i32, month: u32, day: u32 },
}
#[derive(Debug, Clone, PartialEq, Eq, Error)]
pub enum WeekdayError {
#[error("invalid weekday: {0} (must be 0..=6)")]
InvalidWeekday(u8),
#[error("N must not be 0")]
InvalidN,
}
#[derive(Debug, Clone, PartialEq, Eq, Error)]
pub enum RelativeDeltaError {
#[error("invalid year day: {0}")]
InvalidYearDay(i32),
}
#[derive(Debug, Clone, PartialEq, Eq, Error)]
pub enum ParseError {
#[error("unknown string format: {0}")]
UnknownFormat(Box<str>),
#[error("string does not contain a date: {0}")]
NoDate(Box<str>),
#[error("{0}")]
ValueError(Box<str>),
}
#[derive(Debug, Clone, PartialEq, Eq, Error)]
pub enum RRuleError {
#[error("invalid bysetpos: must be between -366 and 366, excluding 0")]
InvalidBySetPos,
#[error("invalid frequency: {0}")]
InvalidFrequency(Box<str>),
#[error("FREQ is required")]
MissingFrequency,
#[error("invalid rrule byxxx generates an empty set")]
EmptyBySet,
#[error("invalid wkst: {0} (must be 0..=6)")]
InvalidWkst(u8),
#[error("invalid interval: must be >= 1")]
InvalidInterval,
#[error("{0}")]
ValueError(Box<str>),
}
#[derive(Debug, Clone, PartialEq, Eq, Error)]
pub enum TzError {
#[error("I/O error: {0}")]
Io(Box<str>),
#[error("invalid TZif magic: expected 'TZif'")]
InvalidMagic,
#[error("invalid TZif data: {0}")]
InvalidData(Box<str>),
#[error("invalid POSIX TZ string: {0}")]
InvalidPosixTz(Box<str>),
#[error("timezone not found: {0}")]
NotFound(Box<str>),
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_easter_error_display_all_variants() {
assert_eq!(EasterError::InvalidMethod(0).to_string(), "invalid method: 0");
assert_eq!(EasterError::InvalidYear(0).to_string(), "invalid year: 0");
assert_eq!(
EasterError::DateOutOfRange { year: 2024, month: 2, day: 30 }.to_string(),
"date out of range: 2024-2-30"
);
}
#[test]
fn test_weekday_error_display() {
assert_eq!(WeekdayError::InvalidWeekday(7).to_string(), "invalid weekday: 7 (must be 0..=6)");
assert_eq!(WeekdayError::InvalidWeekday(255).to_string(), "invalid weekday: 255 (must be 0..=6)");
}
#[test]
fn test_relativedelta_error_display() {
assert_eq!(RelativeDeltaError::InvalidYearDay(367).to_string(), "invalid year day: 367");
}
#[test]
fn test_parse_error_display() {
assert_eq!(ParseError::UnknownFormat("xyz".into()).to_string(), "unknown string format: xyz");
assert_eq!(ParseError::NoDate("".into()).to_string(), "string does not contain a date: ");
assert_eq!(ParseError::ValueError("bad value".into()).to_string(), "bad value");
}
#[test]
fn test_top_level_error_from_easter() {
let e: Error = EasterError::InvalidYear(0).into();
assert_eq!(e.to_string(), "invalid year: 0");
}
#[test]
fn test_top_level_error_from_weekday() {
let e: Error = WeekdayError::InvalidWeekday(7).into();
assert_eq!(e.to_string(), "invalid weekday: 7 (must be 0..=6)");
}
#[test]
fn test_top_level_error_from_relativedelta() {
let e: Error = RelativeDeltaError::InvalidYearDay(400).into();
assert_eq!(e.to_string(), "invalid year day: 400");
}
#[test]
fn test_top_level_error_from_parse() {
let e: Error = ParseError::NoDate("test".into()).into();
assert_eq!(e.to_string(), "string does not contain a date: test");
}
#[test]
fn test_error_clone_and_eq() {
let e1 = EasterError::InvalidYear(5);
let e2 = e1.clone();
assert_eq!(e1, e2);
let w1 = WeekdayError::InvalidWeekday(7);
let w2 = w1.clone();
assert_eq!(w1, w2);
let p1 = ParseError::NoDate("x".into());
let p2 = p1.clone();
assert_eq!(p1, p2);
}
#[test]
fn test_error_debug_format() {
let e = EasterError::InvalidMethod(99);
let debug = format!("{:?}", e);
assert!(debug.contains("InvalidMethod"));
assert!(debug.contains("99"));
}
}