Files
gems/opal-task/internal/engine/modifier_test.go
T
joakim b37e2dfc39 Phase 1: Refactor DateParser structure
- Create DateParser struct with configurable base time and week start
- Add placeholder methods for new parsing features
- Implement time-of-day parsing foundation (splitDateTime, parseTimeOfDay)
- Maintain backward compatibility with existing ParseDate() function
- Update tests to use new DateParser API
- All 33 existing tests passing
2026-01-05 09:54:58 +01:00

274 lines
6.8 KiB
Go

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)
}
}