package engine import ( "testing" "time" ) func TestParseModifier(t *testing.T) { tests := []struct { name string args []string checkFn func(*testing.T, *Modifier) }{ { name: "add tags", args: []string{"+urgent", "+work"}, checkFn: func(t *testing.T, m *Modifier) { if len(m.AddTags) != 2 { t.Errorf("Expected 2 add tags, got %d", len(m.AddTags)) } if m.AddTags[0] != "urgent" || m.AddTags[1] != "work" { t.Error("Tags not parsed correctly") } }, }, { name: "remove tags", args: []string{"-someday", "-later"}, checkFn: func(t *testing.T, m *Modifier) { if len(m.RemoveTags) != 2 { t.Errorf("Expected 2 remove tags, got %d", len(m.RemoveTags)) } }, }, { name: "set attributes", args: []string{"priority:H", "project:backend", "due:tomorrow"}, checkFn: func(t *testing.T, m *Modifier) { if len(m.SetAttributes) != 3 { t.Errorf("Expected 3 attributes, got %d", len(m.SetAttributes)) } if m.SetAttributes["priority"] == nil || *m.SetAttributes["priority"] != "H" { t.Error("Priority not set correctly") } if m.SetAttributes["project"] == nil || *m.SetAttributes["project"] != "backend" { t.Error("Project not set correctly") } }, }, { name: "clear attribute", args: []string{"priority:"}, checkFn: func(t *testing.T, m *Modifier) { if m.SetAttributes["priority"] != nil { t.Error("Expected priority to be nil (cleared)") } }, }, { name: "compound modifier", args: []string{"+urgent", "-someday", "priority:H", "due:tomorrow"}, checkFn: func(t *testing.T, m *Modifier) { if len(m.AddTags) != 1 || m.AddTags[0] != "urgent" { t.Error("Add tag not parsed") } if len(m.RemoveTags) != 1 || m.RemoveTags[0] != "someday" { t.Error("Remove tag not parsed") } if len(m.SetAttributes) != 2 { t.Errorf("Expected 2 attributes, got %d", len(m.SetAttributes)) } }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { result, err := ParseModifier(tt.args) if err != nil { t.Fatalf("ParseModifier returned error: %v", err) } tt.checkFn(t, result) }) } } func TestModifierApply(t *testing.T) { // Create a task task, err := CreateTask("Test task") if err != nil { t.Fatalf("Failed to create task: %v", err) } // Create modifier mod, _ := ParseModifier([]string{"priority:H", "project:backend", "+urgent"}) // Apply modifier if err := mod.Apply(task); err != nil { t.Fatalf("Failed to apply modifier: %v", err) } // Verify changes if task.Priority != PriorityHigh { t.Error("Priority not updated") } if task.Project == nil || *task.Project != "backend" { t.Error("Project not updated") } // Reload to verify tags were saved reloaded, _ := GetTask(task.UUID) found := false for _, tag := range reloaded.Tags { if tag == "urgent" { found = true } } if !found { t.Error("Tag not added") } } func TestCreateTaskWithModifier(t *testing.T) { mod, _ := ParseModifier([]string{"priority:H", "project:test", "+work", "+urgent"}) task, err := CreateTaskWithModifier("Task with modifiers", mod) if err != nil { t.Fatalf("Failed to create task with modifier: %v", err) } if task.Priority != PriorityHigh { t.Error("Priority not set during creation") } if task.Project == nil || *task.Project != "test" { t.Error("Project not set during creation") } if len(task.Tags) != 2 { t.Errorf("Expected 2 tags, got %d", len(task.Tags)) } } func TestParseDateISO(t *testing.T) { date, err := ParseDate("2026-01-15") if err != nil { t.Fatalf("Failed to parse ISO date: %v", err) } if date.Year() != 2026 || date.Month() != 1 || date.Day() != 15 { t.Errorf("Date not parsed correctly: %v", date) } } func TestParseDateRelative(t *testing.T) { now := time.Now() // Test today today, err := ParseDate("today") if err != nil { t.Fatalf("Failed to parse 'today': %v", err) } if today.Day() != now.Day() { t.Error("'today' not parsed correctly") } // Test tomorrow tomorrow, err := ParseDate("tomorrow") if err != nil { t.Fatalf("Failed to parse 'tomorrow': %v", err) } expected := now.AddDate(0, 0, 1) if tomorrow.Day() != expected.Day() { t.Error("'tomorrow' not parsed correctly") } } func TestParseDateWeekday(t *testing.T) { // Test Sunday sunday, err := ParseDate("sunday") if err != nil { t.Fatalf("Failed to parse 'sunday': %v", err) } if sunday.Weekday() != time.Sunday { t.Error("'sunday' not parsed correctly") } // Test abbreviated form mon, err := ParseDate("mon") if err != nil { t.Fatalf("Failed to parse 'mon': %v", err) } if mon.Weekday() != time.Monday { t.Error("'mon' not parsed correctly") } } func TestNextWeekday(t *testing.T) { // Test case: Thursday -> next Sunday should be this Sunday thursday := time.Date(2026, 1, 1, 0, 0, 0, 0, time.UTC) // Jan 1, 2026 is a Thursday parser := NewDateParser(thursday, time.Monday) nextSun := parser.nextWeekday(time.Sunday) if nextSun.Weekday() != time.Sunday { t.Error("Should return Sunday") } // Should be 3 days later (this Sunday) expectedDays := 3 actualDays := int(nextSun.Sub(thursday).Hours() / 24) if actualDays != expectedDays { t.Errorf("Expected %d days until Sunday, got %d", expectedDays, actualDays) } // Test case: Sunday -> next Sunday should be 7 days later sunday := time.Date(2026, 1, 4, 0, 0, 0, 0, time.UTC) // Jan 4, 2026 is a Sunday parser2 := NewDateParser(sunday, time.Monday) nextSun2 := parser2.nextWeekday(time.Sunday) expectedDays = 7 actualDays = int(nextSun2.Sub(sunday).Hours() / 24) if actualDays != expectedDays { t.Errorf("Sunday to Sunday: expected %d days, got %d", expectedDays, actualDays) } } func TestModifierWithDates(t *testing.T) { task, _ := CreateTask("Test date modifiers") // Apply due date mod, _ := ParseModifier([]string{"due:tomorrow"}) if err := mod.Apply(task); err != nil { t.Fatalf("Failed to apply date modifier: %v", err) } if task.Due == nil { t.Error("Due date should be set") } tomorrow := time.Now().AddDate(0, 0, 1) if task.Due.Day() != tomorrow.Day() { t.Error("Due date not set to tomorrow") } // Clear due date mod2, _ := ParseModifier([]string{"due:"}) if err := mod2.Apply(task); err != nil { t.Fatalf("Failed to clear due date: %v", err) } if task.Due != nil { t.Error("Due date should be cleared") } } func TestModifierWithRecurrence(t *testing.T) { task, _ := CreateTask("Test recurrence modifier") mod, _ := ParseModifier([]string{"recur:1w"}) if err := mod.Apply(task); err != nil { t.Fatalf("Failed to apply recurrence: %v", err) } if task.RecurrenceDuration == nil { t.Error("Recurrence should be set") } expected := 7 * 24 * time.Hour if *task.RecurrenceDuration != expected { t.Errorf("Expected recurrence %v, got %v", expected, *task.RecurrenceDuration) } }