recurring_event 0.1.3

Calculate dates for recurring events (daily, weekly, monthly and yearly).
Documentation
use recurring_event::{DailyEvent, MonthlyEvent, MonthlyWeekdayOrdinal, Ordinal, Recurrent, WeeklyEvent, YearlyEvent, time::{Month, Weekday, macros::datetime}};

/*
Daily
*/

#[test]
fn daily_next_date_from() {
    let expected = datetime!(2022-12-31 00:00 UTC);
    let date = datetime!(2022-12-25 00:00 UTC);
    let mut event = DailyEvent::new(date);
    let from_date = datetime!(2022-12-31 00:00 UTC);
    let actual = event.next_date_from(&from_date).unwrap();
    assert_eq!(expected, actual, "actual: {}", actual);
}

#[test]
fn daily_next_date_from_time_is_kept() {
    let date = datetime!(2022-12-25 00:00 UTC);
    let mut event = DailyEvent::new(date);

    let actual = event.next_date_from(&datetime!(2022-12-31 00:00 UTC)).unwrap();

    assert_eq!(datetime!(2022-12-31 00:00 UTC), actual);
    assert_eq!(datetime!(2022-12-31 00:00 UTC), *event.current_date());

    let actual = event.next_date_from(&datetime!(2022-12-31 12:12 UTC)).unwrap();

    assert_eq!(datetime!(2023-01-01 00:00 UTC), actual);
    assert_eq!(datetime!(2023-01-01 00:00 UTC), *event.current_date());
}

/*
Weekly
*/

#[test]
fn weekly_next_date_from() {
    let expected = datetime!(2023-01-12 00:00 UTC);
    let date = datetime!(2022-12-25 00:00 UTC);
    let mut event = WeeklyEvent::new(date);
    event.insert_weekday(Weekday::Monday);
    event.insert_weekday(Weekday::Thursday);
    let from_date = datetime!(2023-01-10 00:00 UTC);
    let actual = event.next_date_from(&from_date).unwrap();
    assert_eq!(expected, actual, "actual: {}", actual);
}

#[test]
fn weekly_next_date_from_frequenced() {
    let expected = datetime!(2023-04-17 00:00 UTC);
    let date = datetime!(2022-12-25 00:00 UTC);
    let mut event = WeeklyEvent::new(date);
    event.update_frequency(4);
    event.insert_weekday(Weekday::Monday);
    event.insert_weekday(Weekday::Thursday);
    let from_date = datetime!(2023-03-25 00:00 UTC);
    let actual = event.next_date_from(&from_date).unwrap();
    assert_eq!(expected, actual, "actual: {}", actual);
}

#[test]
fn weekly_next_date_from_time_is_kept() {
    let expected = datetime!(2023-01-12 00:00 UTC);
    let date = datetime!(2022-12-25 00:00 UTC);
    let mut event = WeeklyEvent::new(date);
    event.insert_weekday(Weekday::Monday);
    event.insert_weekday(Weekday::Thursday);
    let from_date = datetime!(2023-01-10 12:12 UTC);
    let actual = event.next_date_from(&from_date).unwrap();
    assert_eq!(expected, actual, "actual: {}", actual);
}

/*
Monthly
*/

#[test]
fn monthly_next_date_from() {
    let expected = datetime!(2023-01-02 00:00 UTC);
    let date = datetime!(2022-12-25 00:00 UTC);
    let mut event = MonthlyEvent::new(date);
    event.insert_weekday(Weekday::Monday);
    event.insert_weekday(Weekday::Thursday);
    event.insert_monthly_day_ordinal(7);
    event.insert_monthly_day_ordinal(25);
    event.insert_monthly_weekday_ordinal(MonthlyWeekdayOrdinal::new(Ordinal::Second, Weekday::Tuesday));
    event.insert_monthly_weekday_ordinal(MonthlyWeekdayOrdinal::new(Ordinal::Fourth, Weekday::Sunday));
    let from_date = datetime!(2022-12-30 00:00 UTC);
    let actual = event.next_date_from(&from_date).unwrap();
    assert_eq!(expected, actual, "actual: {}", actual.date());
}

#[test]
fn monthly_next_date_from_frequenced() {
    let expected = datetime!(2023-08-03 00:00 UTC);
    let date = datetime!(2022-12-25 00:00 UTC);
    let mut event = MonthlyEvent::new(date);
    event.update_frequency(4);
    event.insert_weekday(Weekday::Monday);
    event.insert_weekday(Weekday::Thursday);
    event.insert_monthly_day_ordinal(7);
    event.insert_monthly_day_ordinal(25);
    event.insert_monthly_weekday_ordinal(MonthlyWeekdayOrdinal::new(Ordinal::Second, Weekday::Tuesday));
    event.insert_monthly_weekday_ordinal(MonthlyWeekdayOrdinal::new(Ordinal::Fourth, Weekday::Sunday));
    let from_date = datetime!(2023-04-29 00:00 UTC);
    let actual = event.next_date_from(&from_date).unwrap();
    assert_eq!(expected, actual, "actual: {}", actual.date());
}

#[test]
fn monthly_next_date_from_time_is_kept() {
    let expected = datetime!(2023-01-02 00:00 UTC);
    let date = datetime!(2022-12-25 00:00 UTC);
    let mut event = MonthlyEvent::new(date);
    event.insert_weekday(Weekday::Monday);
    event.insert_weekday(Weekday::Thursday);
    event.insert_monthly_day_ordinal(7);
    event.insert_monthly_day_ordinal(25);
    event.insert_monthly_weekday_ordinal(MonthlyWeekdayOrdinal::new(Ordinal::Second, Weekday::Tuesday));
    event.insert_monthly_weekday_ordinal(MonthlyWeekdayOrdinal::new(Ordinal::Fourth, Weekday::Sunday));
    let from_date = datetime!(2022-12-30 12:012 UTC);
    let actual = event.next_date_from(&from_date).unwrap();
    assert_eq!(expected, actual, "actual: {}", actual.date());
}

/*
Yearly
*/

#[test]
fn yearly_next_date_from() {
    let expected = datetime!(2023-02-02 00:00 UTC);
    let date = datetime!(2022-02-14 00:00 UTC);
    let mut event = YearlyEvent::new(date);

    event.insert_weekday(Weekday::Monday, Month::February);
    event.insert_weekday(Weekday::Thursday, Month::February);
    event.insert_monthly_day_ordinal(7, Month::February);
    event.insert_monthly_day_ordinal(25, Month::February);
    event.insert_monthly_weekday_ordinal(MonthlyWeekdayOrdinal::new(Ordinal::Second, Weekday::Tuesday), Month::February);
    event.insert_monthly_weekday_ordinal(MonthlyWeekdayOrdinal::new(Ordinal::Fourth, Weekday::Sunday), Month::February);

    event.insert_weekday(Weekday::Tuesday, Month::August);
    event.insert_weekday(Weekday::Saturday, Month::August);
    event.insert_monthly_day_ordinal(13, Month::August);
    event.insert_monthly_day_ordinal(29, Month::August);
    event.insert_monthly_weekday_ordinal(MonthlyWeekdayOrdinal::new(Ordinal::First, Weekday::Wednesday), Month::August);
    event.insert_monthly_weekday_ordinal(MonthlyWeekdayOrdinal::new(Ordinal::Third, Weekday::Friday), Month::August);

    let from_date = datetime!(2022-08-31 00:00 UTC);
    let actual = event.next_date_from(&from_date).unwrap();
    assert_eq!(expected, actual, "actual: {}", actual.date());
}

#[test]
fn yearly_next_date_from_no_occurrence_first_year() {
    let expected = datetime!(2023-08-01 00:00 UTC);
    let date = datetime!(2022-02-14 00:00 UTC);
    let mut event = YearlyEvent::new(date);

    event.insert_weekday(Weekday::Monday, Month::February);
    event.insert_weekday(Weekday::Thursday, Month::February);
    event.insert_monthly_day_ordinal(7, Month::February);
    event.insert_monthly_day_ordinal(25, Month::February);
    event.insert_monthly_weekday_ordinal(MonthlyWeekdayOrdinal::new(Ordinal::Second, Weekday::Tuesday), Month::February);
    event.insert_monthly_weekday_ordinal(MonthlyWeekdayOrdinal::new(Ordinal::Fourth, Weekday::Sunday), Month::February);

    event.insert_weekday(Weekday::Tuesday, Month::August);
    event.insert_weekday(Weekday::Saturday, Month::August);
    event.insert_monthly_day_ordinal(13, Month::August);
    event.insert_monthly_day_ordinal(29, Month::August);
    event.insert_monthly_weekday_ordinal(MonthlyWeekdayOrdinal::new(Ordinal::First, Weekday::Wednesday), Month::August);
    event.insert_monthly_weekday_ordinal(MonthlyWeekdayOrdinal::new(Ordinal::Third, Weekday::Friday), Month::August);

    let from_date = datetime!(2023-02-28 00:00 UTC);
    let actual = event.next_date_from(&from_date).unwrap();
    assert_eq!(expected, actual, "actual: {}", actual.date());
}

#[test]
fn yearly_next_date_from_no_occurrence_first_year_frequenced() {
    let expected = datetime!(2026-02-02 00:00 UTC);
    let date = datetime!(2022-02-14 00:00 UTC);
    let mut event = YearlyEvent::new(date);
    event.update_frequency(4);

    event.insert_weekday(Weekday::Monday, Month::February);
    event.insert_weekday(Weekday::Thursday, Month::February);
    event.insert_monthly_day_ordinal(7, Month::February);
    event.insert_monthly_day_ordinal(25, Month::February);
    event.insert_monthly_weekday_ordinal(MonthlyWeekdayOrdinal::new(Ordinal::Second, Weekday::Tuesday), Month::February);
    event.insert_monthly_weekday_ordinal(MonthlyWeekdayOrdinal::new(Ordinal::Fourth, Weekday::Sunday), Month::February);

    event.insert_weekday(Weekday::Tuesday, Month::August);
    event.insert_weekday(Weekday::Saturday, Month::August);
    event.insert_monthly_day_ordinal(13, Month::August);
    event.insert_monthly_day_ordinal(29, Month::August);
    event.insert_monthly_weekday_ordinal(MonthlyWeekdayOrdinal::new(Ordinal::First, Weekday::Wednesday), Month::August);
    event.insert_monthly_weekday_ordinal(MonthlyWeekdayOrdinal::new(Ordinal::Third, Weekday::Friday), Month::August);

    let from_date = datetime!(2022-12-31 00:00 UTC);
    let actual = event.next_date_from(&from_date).unwrap();
    assert_eq!(expected, actual, "actual: {}", actual.date());
}

#[test]
fn yearly_next_date_from_time_is_kept() {
    let expected = datetime!(2023-02-02 00:00 UTC);
    let date = datetime!(2022-02-14 00:00 UTC);
    let mut event = YearlyEvent::new(date);

    event.insert_weekday(Weekday::Monday, Month::February);
    event.insert_weekday(Weekday::Thursday, Month::February);
    event.insert_monthly_day_ordinal(7, Month::February);
    event.insert_monthly_day_ordinal(25, Month::February);
    event.insert_monthly_weekday_ordinal(MonthlyWeekdayOrdinal::new(Ordinal::Second, Weekday::Tuesday), Month::February);
    event.insert_monthly_weekday_ordinal(MonthlyWeekdayOrdinal::new(Ordinal::Fourth, Weekday::Sunday), Month::February);

    event.insert_weekday(Weekday::Tuesday, Month::August);
    event.insert_weekday(Weekday::Saturday, Month::August);
    event.insert_monthly_day_ordinal(13, Month::August);
    event.insert_monthly_day_ordinal(29, Month::August);
    event.insert_monthly_weekday_ordinal(MonthlyWeekdayOrdinal::new(Ordinal::First, Weekday::Wednesday), Month::August);
    event.insert_monthly_weekday_ordinal(MonthlyWeekdayOrdinal::new(Ordinal::Third, Weekday::Friday), Month::August);

    let from_date = datetime!(2022-08-31 12:12 UTC);
    let actual = event.next_date_from(&from_date).unwrap();
    assert_eq!(expected, actual, "actual: {}", actual.date());
}