use cfait::model::{DateType, Task, TaskStatus};
use chrono::{Duration, Utc};
use std::collections::HashMap;
fn create_weekly_task(uid: &str, offset_days: i64) -> Task {
let aliases = HashMap::new();
let mut t = Task::new("Rec Test Task", &aliases, None);
t.uid = uid.to_string();
let dt = (Utc::now() + Duration::days(offset_days)).date_naive();
t.dtstart = Some(DateType::AllDay(dt));
t.due = Some(DateType::AllDay(dt));
t.rrule = Some("FREQ=WEEKLY".to_string());
t.status = TaskStatus::NeedsAction;
t
}
#[test]
fn test_recurrence_recycling_preserves_uid() {
let t = create_weekly_task("recycle_uid_test", 0);
let original_uid = t.uid.clone();
let (history, secondary) = t.recycle(TaskStatus::Completed, false);
assert_eq!(history.status, TaskStatus::Completed);
let t = secondary.unwrap();
assert_eq!(
t.uid, original_uid,
"UID must be preserved for Tasks.org compatibility"
);
assert_eq!(
t.status,
TaskStatus::NeedsAction,
"Status should reset to NeedsAction"
);
assert_ne!(t.dtstart, None, "Dates should be updated");
let old_due = (Utc::now()).date_naive();
let new_due = t.due.as_ref().unwrap().to_date_naive();
let diff = new_due - old_due;
assert_eq!(diff.num_days(), 7, "Date should advance 1 week");
}
#[test]
fn test_scenario_1_cancel_then_done_sequence() {
let t = create_weekly_task("task1", -5);
let initial_due = t.due.as_ref().unwrap().to_date_naive();
let (history1, secondary1) = t.recycle(TaskStatus::Completed, false);
assert_eq!(history1.status, TaskStatus::Completed);
let t = secondary1.unwrap();
let due1 = t.due.as_ref().unwrap().to_date_naive();
assert_eq!(due1, initial_due + Duration::days(7));
assert_eq!(t.status, TaskStatus::NeedsAction);
let (history2, secondary2) = t.recycle(TaskStatus::Completed, false);
assert_eq!(history2.status, TaskStatus::Completed);
let t = secondary2.unwrap();
let due2 = t.due.as_ref().unwrap().to_date_naive();
assert_eq!(due2, initial_due + Duration::days(14));
let (history3, secondary3) = t.recycle(TaskStatus::Cancelled, false);
assert_eq!(history3.status, TaskStatus::Cancelled);
let t = secondary3.unwrap();
let due3 = t.due.as_ref().unwrap().to_date_naive();
assert_eq!(due3, initial_due + Duration::days(21));
assert!(
!t.exdates.is_empty(),
"Next instance should contain the EXDATE"
);
assert_eq!(t.exdates.len(), 1);
let (history4, secondary4) = t.recycle(TaskStatus::Cancelled, false);
assert_eq!(history4.status, TaskStatus::Cancelled);
let t = secondary4.unwrap();
let due4 = t.due.as_ref().unwrap().to_date_naive();
assert_eq!(due4, initial_due + Duration::days(28));
assert_eq!(t.exdates.len(), 2, "Should have accumulated another EXDATE");
}
#[test]
fn test_scenario_2_multiple_cancels() {
let t = create_weekly_task("task2", -5);
let initial_due = t.due.as_ref().unwrap().to_date_naive();
let (_, secondary1) = t.recycle(TaskStatus::Cancelled, false);
let t = secondary1.unwrap();
assert_eq!(
t.due.as_ref().unwrap().to_date_naive(),
initial_due + Duration::days(7)
);
let (_, secondary2) = t.recycle(TaskStatus::Cancelled, false);
let t = secondary2.unwrap();
assert_eq!(
t.due.as_ref().unwrap().to_date_naive(),
initial_due + Duration::days(14)
);
let (_, secondary3) = t.recycle(TaskStatus::Cancelled, false);
let t = secondary3.unwrap();
assert_eq!(
t.due.as_ref().unwrap().to_date_naive(),
initial_due + Duration::days(21)
);
assert_eq!(t.exdates.len(), 3);
}
#[test]
fn test_scenario_3_cancel_loop() {
let t = create_weekly_task("task3", -5);
let initial_due = t.due.as_ref().unwrap().to_date_naive();
let (_, secondary1) = t.recycle(TaskStatus::Completed, false);
let t = secondary1.unwrap();
assert_eq!(
t.due.as_ref().unwrap().to_date_naive(),
initial_due + Duration::days(7)
);
let (_, secondary2) = t.recycle(TaskStatus::Cancelled, false);
let t = secondary2.unwrap();
assert_eq!(
t.due.as_ref().unwrap().to_date_naive(),
initial_due + Duration::days(14)
);
let (_, secondary3) = t.recycle(TaskStatus::Completed, false);
let t = secondary3.unwrap();
assert_eq!(
t.due.as_ref().unwrap().to_date_naive(),
initial_due + Duration::days(21)
);
let (_, secondary4) = t.recycle(TaskStatus::Cancelled, false);
let t = secondary4.unwrap();
assert_eq!(
t.due.as_ref().unwrap().to_date_naive(),
initial_due + Duration::days(28)
);
}