cfait 1.0.2

Powerful, fast and elegant task / TODO manager. (GUI & TUI, CalDAV & local)
Documentation
// SPDX-License-Identifier: GPL-3.0-or-later
//! Tests for import functionality.
use cfait::context::TestContext;
use cfait::model::Task;
use cfait::storage::LocalStorage;
use serial_test::serial;
use std::fs;

fn create_simple_ics() -> String {
    r#"BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Test//Test//EN
BEGIN:VTODO
UID:test-task-1
SUMMARY:Test Task 1
STATUS:NEEDS-ACTION
PRIORITY:5
END:VTODO
END:VCALENDAR"#
        .to_string()
}

fn create_multi_task_ics() -> String {
    r#"BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Test//Test//EN
BEGIN:VTODO
UID:test-task-1
SUMMARY:First Task
STATUS:NEEDS-ACTION
PRIORITY:1
END:VTODO
BEGIN:VTODO
UID:test-task-2
SUMMARY:Second Task
STATUS:NEEDS-ACTION
PRIORITY:5
DUE:20260215T140000Z
END:VTODO
BEGIN:VTODO
UID:test-task-3
SUMMARY:Third Task
STATUS:COMPLETED
COMPLETED:20260101T120000Z
END:VTODO
END:VCALENDAR"#
        .to_string()
}

fn create_ics_with_alarms() -> String {
    r#"BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//cfait//cfait//EN
BEGIN:VTODO
UID:alarm-task-1
SUMMARY:Task with Alarm
DUE:20260215T140000Z
STATUS:NEEDS-ACTION
BEGIN:VALARM
ACTION:DISPLAY
TRIGGER:-PT15M
DESCRIPTION:Reminder
END:VALARM
END:VTODO
END:VCALENDAR"#
        .to_string()
}

fn create_ics_with_recurrence() -> String {
    r#"BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//cfait//cfait//EN
BEGIN:VTODO
UID:recurring-task-1
SUMMARY:Weekly Meeting
STATUS:NEEDS-ACTION
DTSTART:20260101T100000Z
RRULE:FREQ=WEEKLY;BYDAY=MO
END:VTODO
END:VCALENDAR"#
        .to_string()
}

fn create_ics_without_vcalendar_wrapper() -> String {
    r#"BEGIN:VTODO
UID:unwrapped-task-1
SUMMARY:Unwrapped Task
STATUS:NEEDS-ACTION
END:VTODO"#
        .to_string()
}

#[test]
#[serial]
fn test_import_single_task() {
    let ctx = TestContext::new();
    let href = "local://test-calendar-1";
    let ics_content = create_simple_ics();

    let result = LocalStorage::import_from_ics(&ctx, href, &ics_content);
    assert!(result.is_ok());
    assert_eq!(result.unwrap(), 1);

    let tasks = LocalStorage::load_for_href(&ctx, href).unwrap();
    assert_eq!(tasks.len(), 1);
    assert_eq!(tasks[0].summary, "Test Task 1");
    assert_eq!(tasks[0].priority, 5);
}

#[test]
#[serial]
fn test_import_multiple_tasks() {
    let ctx = TestContext::new();
    let href = "local://test-calendar-2";
    let ics_content = create_multi_task_ics();

    let result = LocalStorage::import_from_ics(&ctx, href, &ics_content);
    assert!(result.is_ok());
    assert_eq!(result.unwrap(), 3);

    let tasks = LocalStorage::load_for_href(&ctx, href).unwrap();
    assert_eq!(tasks.len(), 3);
    assert_eq!(tasks[0].summary, "First Task");
    assert_eq!(tasks[0].priority, 1);
}

#[test]
#[serial]
fn test_import_with_existing_tasks() {
    let ctx = TestContext::new();
    let href = "local://test-calendar-3";

    let existing_task = Task::new("Existing Task", &Default::default(), None);
    LocalStorage::save_for_href(&ctx, href, &[existing_task]).unwrap();

    let ics_content = create_multi_task_ics();
    let result = LocalStorage::import_from_ics(&ctx, href, &ics_content);
    assert!(result.is_ok());
    assert_eq!(result.unwrap(), 3);

    let tasks = LocalStorage::load_for_href(&ctx, href).unwrap();
    assert_eq!(tasks.len(), 4);
}

#[test]
#[serial]
fn test_import_preserves_alarms() {
    let ctx = TestContext::new();
    let href = "local://test-calendar-4";
    let ics_content = create_ics_with_alarms();

    let result = LocalStorage::import_from_ics(&ctx, href, &ics_content);
    assert!(result.is_ok());

    let tasks = LocalStorage::load_for_href(&ctx, href).unwrap();
    assert_eq!(tasks.len(), 1);
    assert!(!tasks[0].alarms.is_empty());
}

#[test]
#[serial]
fn test_import_preserves_recurrence() {
    let ctx = TestContext::new();
    let href = "local://test-calendar-5";
    let ics_content = create_ics_with_recurrence();

    let result = LocalStorage::import_from_ics(&ctx, href, &ics_content);
    assert!(result.is_ok());

    let tasks = LocalStorage::load_for_href(&ctx, href).unwrap();
    assert_eq!(tasks.len(), 1);
    assert!(tasks[0].rrule.is_some());
}

#[test]
#[serial]
fn test_import_unwrapped_vtodo() {
    let ctx = TestContext::new();
    let href = "local://test-calendar-6";
    let ics_content = create_ics_without_vcalendar_wrapper();

    let result = LocalStorage::import_from_ics(&ctx, href, &ics_content);
    assert!(result.is_ok());
    assert_eq!(result.unwrap(), 1);

    let tasks = LocalStorage::load_for_href(&ctx, href).unwrap();
    assert_eq!(tasks.len(), 1);
    assert_eq!(tasks[0].summary, "Unwrapped Task");
}

#[test]
#[serial]
fn test_import_empty_ics() {
    let ctx = TestContext::new();
    let href = "local://test-calendar-7";
    let ics_content = "BEGIN:VCALENDAR\nVERSION:2.0\nEND:VCALENDAR".to_string();

    let result = LocalStorage::import_from_ics(&ctx, href, &ics_content);
    assert!(result.is_err());
}

#[test]
#[serial]
fn test_import_invalid_ics() {
    let ctx = TestContext::new();
    let href = "local://test-calendar-8";
    let ics_content = "This is not valid ICS content".to_string();

    let result = LocalStorage::import_from_ics(&ctx, href, &ics_content);
    assert!(result.is_err());
}

#[test]
#[serial]
fn test_import_assigns_new_calendar_href() {
    let ctx = TestContext::new();
    let target_href = "local://target-calendar";
    let ics_content = create_simple_ics();

    let result = LocalStorage::import_from_ics(&ctx, target_href, &ics_content);
    assert!(result.is_ok());

    let tasks = LocalStorage::load_for_href(&ctx, target_href).unwrap();
    assert_eq!(tasks.len(), 1);
    assert_eq!(tasks[0].calendar_href, target_href);
}

#[test]
#[serial]
fn test_cli_import_from_file() {
    let ctx = TestContext::new();
    let temp_dir = std::env::temp_dir();
    let test_file = temp_dir.join("test_cli_import.ics");
    let ics_content = create_multi_task_ics();
    fs::write(&test_file, &ics_content).unwrap();

    let default_href = "local://default";
    let result = LocalStorage::import_from_ics(&ctx, default_href, &ics_content);
    assert!(result.is_ok());
    assert_eq!(result.unwrap(), 3);

    let tasks = LocalStorage::load_for_href(&ctx, default_href).unwrap();
    assert_eq!(tasks.len(), 3);

    fs::remove_file(&test_file).ok();
}