package task import ( "os" "strings" "testing" "time" "my-brain-importer/internal/agents" ) func newTestAgent(t *testing.T) (*Agent, func()) { t.Helper() f, err := os.CreateTemp("", "tasks_agent_*.json") if err != nil { t.Fatalf("temp-Datei: %v", err) } name := f.Name() f.Close() os.Remove(name) // Datei entfernen → loadLocked gibt leeres Slice zurück a := &Agent{store: &Store{path: name}} return a, func() { os.Remove(name) } } // ── parseAddArgs ───────────────────────────────────────────────────────────── func TestParseAddArgs_TextOnly(t *testing.T) { text, prio, due := parseAddArgs([]string{"Arzttermin", "buchen"}) if text != "Arzttermin buchen" { t.Errorf("text: %q", text) } if prio != "" { t.Errorf("prio sollte leer sein: %q", prio) } if due != nil { t.Error("due sollte nil sein") } } func TestParseAddArgs_AllFlags(t *testing.T) { text, prio, due := parseAddArgs([]string{"Zahnarzt", "--due", "2026-12-01", "--priority", "hoch"}) if text != "Zahnarzt" { t.Errorf("text: %q", text) } if prio != "hoch" { t.Errorf("prio: %q", prio) } if due == nil { t.Fatal("due sollte gesetzt sein") } if due.Format("2006-01-02") != "2026-12-01" { t.Errorf("due: %v", due) } } func TestParseAddArgs_ShortFlags(t *testing.T) { text, prio, due := parseAddArgs([]string{"Meeting", "-p", "mittel", "-d", "2026-06-15"}) if text != "Meeting" { t.Errorf("text: %q", text) } if prio != "mittel" { t.Errorf("prio: %q", prio) } if due == nil || due.Format("2006-01-02") != "2026-06-15" { t.Errorf("due: %v", due) } } func TestParseAddArgs_InvalidDate(t *testing.T) { _, _, due := parseAddArgs([]string{"Task", "--due", "kein-datum"}) if due != nil { t.Error("ungültiges Datum sollte nil ergeben") } } // ── Agent.Handle ───────────────────────────────────────────────────────────── func TestAgent_Add(t *testing.T) { a, cleanup := newTestAgent(t) defer cleanup() resp := a.Handle(agents.Request{Action: agents.ActionAdd, Args: []string{"Mein Task"}}) if resp.Error != nil { t.Fatalf("Add: %v", resp.Error) } if !strings.Contains(resp.Text, "Mein Task") { t.Errorf("Antwort enthält keinen Task-Text: %q", resp.Text) } } func TestAgent_Add_WithDueAndPriority(t *testing.T) { a, cleanup := newTestAgent(t) defer cleanup() resp := a.Handle(agents.Request{ Action: agents.ActionAdd, Args: []string{"Frist", "--due", "2026-12-31", "--priority", "hoch"}, }) if resp.Error != nil { t.Fatalf("Add: %v", resp.Error) } if !strings.Contains(resp.Text, "Frist") { t.Errorf("Task-Text fehlt: %q", resp.Text) } if !strings.Contains(resp.Text, "hoch") { t.Errorf("Priorität fehlt: %q", resp.Text) } if !strings.Contains(resp.Text, "31.12.2026") { t.Errorf("Datum fehlt: %q", resp.Text) } } func TestAgent_Add_NoArgs(t *testing.T) { a, cleanup := newTestAgent(t) defer cleanup() resp := a.Handle(agents.Request{Action: agents.ActionAdd, Args: []string{}}) if !strings.Contains(resp.Text, "❌") { t.Errorf("erwartet Fehlermeldung, got: %q", resp.Text) } } func TestAgent_List_Empty(t *testing.T) { a, cleanup := newTestAgent(t) defer cleanup() resp := a.Handle(agents.Request{Action: agents.ActionList}) if !strings.Contains(resp.Text, "Keine Tasks") { t.Errorf("erwartet 'Keine Tasks': %q", resp.Text) } } func TestAgent_List_ShowsDueDate(t *testing.T) { a, cleanup := newTestAgent(t) defer cleanup() due := time.Now().Add(48 * time.Hour) // übermorgen a.store.Add("Übermorgen", "", &due) resp := a.Handle(agents.Request{Action: agents.ActionList}) if !strings.Contains(resp.Text, "📅") { t.Errorf("Datum-Icon fehlt in Liste: %q", resp.Text) } } func TestAgent_List_ShowsOverdue(t *testing.T) { a, cleanup := newTestAgent(t) defer cleanup() past := time.Now().Add(-48 * time.Hour) // vorgestern a.store.Add("Überfällig", "", &past) resp := a.Handle(agents.Request{Action: agents.ActionList}) if !strings.Contains(resp.Text, "ÜBERFÄLLIG") { t.Errorf("ÜBERFÄLLIG fehlt: %q", resp.Text) } } func TestAgent_Done(t *testing.T) { a, cleanup := newTestAgent(t) defer cleanup() addResp := a.Handle(agents.Request{Action: agents.ActionAdd, Args: []string{"Erledigen"}}) // Short-ID aus Antwort extrahieren tasks, _ := a.store.Load() if len(tasks) == 0 { t.Fatal("kein Task angelegt") } id := tasks[0].ID shortID := id[len(id)-6:] _ = addResp resp := a.Handle(agents.Request{Action: agents.ActionDone, Args: []string{shortID}}) if resp.Error != nil { t.Fatalf("Done: %v", resp.Error) } if !strings.Contains(resp.Text, "✅") { t.Errorf("erwartet ✅: %q", resp.Text) } } func TestAgent_Delete(t *testing.T) { a, cleanup := newTestAgent(t) defer cleanup() a.Handle(agents.Request{Action: agents.ActionAdd, Args: []string{"Löschen"}}) tasks, _ := a.store.Load() id := tasks[0].ID shortID := id[len(id)-6:] resp := a.Handle(agents.Request{Action: agents.ActionDelete, Args: []string{shortID}}) if resp.Error != nil { t.Fatalf("Delete: %v", resp.Error) } if !strings.Contains(resp.Text, "🗑️") { t.Errorf("erwartet 🗑️: %q", resp.Text) } tasks, _ = a.store.Load() if len(tasks) != 0 { t.Errorf("Task sollte gelöscht sein, noch %d vorhanden", len(tasks)) } } func TestAgent_UnknownAction(t *testing.T) { a, cleanup := newTestAgent(t) defer cleanup() resp := a.Handle(agents.Request{Action: "unknown"}) if !strings.Contains(resp.Text, "❌") { t.Errorf("erwartet Fehlermeldung: %q", resp.Text) } } // ── resolveID ──────────────────────────────────────────────────────────────── func TestResolveID_FullMatch(t *testing.T) { tasks := []Task{{ID: "123456789"}} if got := resolveID(tasks, "123456789"); got != "123456789" { t.Errorf("got %q", got) } } func TestResolveID_ShortMatch(t *testing.T) { tasks := []Task{{ID: "123456789"}} if got := resolveID(tasks, "456789"); got != "123456789" { t.Errorf("got %q", got) } } func TestResolveID_NotFound(t *testing.T) { tasks := []Task{{ID: "123456789"}} if got := resolveID(tasks, "000000"); got != "" { t.Errorf("erwartet leer, got %q", got) } }