test: add comprehensive tests for new UX features and fix ISO date timezone bug

Add 33 new test functions covering annotations, undo system, history
formatting, relative date display, and weekday parsing pipeline. Fix ISO
date parsing to use ParseInLocation instead of Parse to respect the
parser's timezone context.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-19 16:42:49 +01:00
parent 07d1a78dfc
commit 04fa9222d8
6 changed files with 1117 additions and 1 deletions
+178
View File
@@ -0,0 +1,178 @@
package engine
import (
"testing"
"time"
)
func TestAnnotate(t *testing.T) {
task, err := CreateTask("Annotation test task")
if err != nil {
t.Fatalf("Failed to create task: %v", err)
}
defer func() { task.Delete(true) }()
// Initially no annotations
if len(task.Annotations) != 0 {
t.Fatalf("new task should have 0 annotations, got %d", len(task.Annotations))
}
// Add first annotation
if err := task.Annotate("First note"); err != nil {
t.Fatalf("Annotate failed: %v", err)
}
if len(task.Annotations) != 1 {
t.Fatalf("expected 1 annotation, got %d", len(task.Annotations))
}
if task.Annotations[0].Text != "First note" {
t.Errorf("annotation text = %q, want %q", task.Annotations[0].Text, "First note")
}
if task.Annotations[0].Timestamp == 0 {
t.Error("annotation timestamp should be non-zero")
}
// Add second annotation
if err := task.Annotate("Second note"); err != nil {
t.Fatalf("Annotate failed: %v", err)
}
if len(task.Annotations) != 2 {
t.Fatalf("expected 2 annotations, got %d", len(task.Annotations))
}
if task.Annotations[1].Text != "Second note" {
t.Errorf("second annotation text = %q, want %q", task.Annotations[1].Text, "Second note")
}
}
func TestAnnotate_Persistence(t *testing.T) {
task, err := CreateTask("Annotation persistence test")
if err != nil {
t.Fatalf("Failed to create task: %v", err)
}
defer func() { task.Delete(true) }()
if err := task.Annotate("Persisted note"); err != nil {
t.Fatalf("Annotate failed: %v", err)
}
// Reload from DB
loaded, err := GetTask(task.UUID)
if err != nil {
t.Fatalf("GetTask failed: %v", err)
}
if len(loaded.Annotations) != 1 {
t.Fatalf("loaded task: expected 1 annotation, got %d", len(loaded.Annotations))
}
if loaded.Annotations[0].Text != "Persisted note" {
t.Errorf("loaded annotation text = %q, want %q", loaded.Annotations[0].Text, "Persisted note")
}
}
func TestAnnotate_TimestampOrdering(t *testing.T) {
origTimeNow := timeNow
defer func() { timeNow = origTimeNow }()
task, err := CreateTask("Timestamp ordering test")
if err != nil {
t.Fatalf("Failed to create task: %v", err)
}
defer func() { timeNow = origTimeNow; task.Delete(true) }()
// Add annotations at different times
t1 := time.Date(2026, 1, 1, 10, 0, 0, 0, time.UTC)
t2 := time.Date(2026, 1, 1, 11, 0, 0, 0, time.UTC)
timeNow = func() time.Time { return t1 }
task.Annotate("First")
timeNow = func() time.Time { return t2 }
task.Annotate("Second")
if task.Annotations[0].Timestamp >= task.Annotations[1].Timestamp {
t.Error("annotations should be in chronological order")
}
}
func TestDenotate(t *testing.T) {
task, err := CreateTask("Denotate test task")
if err != nil {
t.Fatalf("Failed to create task: %v", err)
}
defer func() { task.Delete(true) }()
task.Annotate("First")
task.Annotate("Second")
task.Annotate("Third")
// Denotate removes the last
removed, err := task.Denotate()
if err != nil {
t.Fatalf("Denotate failed: %v", err)
}
if removed.Text != "Third" {
t.Errorf("removed text = %q, want %q", removed.Text, "Third")
}
if len(task.Annotations) != 2 {
t.Fatalf("expected 2 annotations after denotate, got %d", len(task.Annotations))
}
// Remove second
removed, err = task.Denotate()
if err != nil {
t.Fatalf("Denotate failed: %v", err)
}
if removed.Text != "Second" {
t.Errorf("removed text = %q, want %q", removed.Text, "Second")
}
// Remove first
removed, err = task.Denotate()
if err != nil {
t.Fatalf("Denotate failed: %v", err)
}
if removed.Text != "First" {
t.Errorf("removed text = %q, want %q", removed.Text, "First")
}
// Nothing left — should error
_, err = task.Denotate()
if err == nil {
t.Error("Denotate on empty annotations should return error")
}
}
func TestDenotate_Empty(t *testing.T) {
task, err := CreateTask("Denotate empty test")
if err != nil {
t.Fatalf("Failed to create task: %v", err)
}
defer func() { task.Delete(true) }()
_, err = task.Denotate()
if err == nil {
t.Error("Denotate on task with no annotations should return error")
}
}
func TestDenotate_Persistence(t *testing.T) {
task, err := CreateTask("Denotate persistence test")
if err != nil {
t.Fatalf("Failed to create task: %v", err)
}
defer func() { task.Delete(true) }()
task.Annotate("Keep this")
task.Annotate("Remove this")
task.Denotate()
// Reload and verify
loaded, err := GetTask(task.UUID)
if err != nil {
t.Fatalf("GetTask failed: %v", err)
}
if len(loaded.Annotations) != 1 {
t.Fatalf("loaded: expected 1 annotation, got %d", len(loaded.Annotations))
}
if loaded.Annotations[0].Text != "Keep this" {
t.Errorf("remaining annotation = %q, want %q", loaded.Annotations[0].Text, "Keep this")
}
}