package engine import ( "os" "testing" "time" "github.com/google/uuid" ) func TestMain(m *testing.M) { // Setup test database with explicit directory overrides testDir := "/tmp/opal-test" // Set directory overrides to use test directory SetConfigDirOverride(testDir) SetDataDirOverride(testDir) // Ensure test directory exists if err := os.MkdirAll(testDir, 0755); err != nil { panic(err) } if err := InitDB(); err != nil { panic(err) } defer CloseDB() // Run tests code := m.Run() // Cleanup os.RemoveAll(testDir) os.Exit(code) } func TestCreateTask(t *testing.T) { task, err := CreateTask("Test task") if err != nil { t.Fatalf("Failed to create task: %v", err) } if task.UUID == uuid.Nil { t.Error("Task UUID should not be nil") } if task.Description != "Test task" { t.Errorf("Expected description 'Test task', got '%s'", task.Description) } if task.Status != StatusPending { t.Errorf("Expected status Pending, got %v", task.Status) } if task.Priority != PriorityDefault { t.Errorf("Expected priority Default, got %v", task.Priority) } } func TestGetTask(t *testing.T) { // Create a task created, err := CreateTask("Test get task") if err != nil { t.Fatalf("Failed to create task: %v", err) } // Retrieve it retrieved, err := GetTask(created.UUID) if err != nil { t.Fatalf("Failed to get task: %v", err) } if retrieved.UUID != created.UUID { t.Error("UUIDs don't match") } if retrieved.Description != created.Description { t.Error("Descriptions don't match") } } func TestTaskSave(t *testing.T) { task, err := CreateTask("Test save") if err != nil { t.Fatalf("Failed to create task: %v", err) } // Modify task task.Description = "Modified description" task.Priority = PriorityHigh project := "test-project" task.Project = &project if err := task.Save(); err != nil { t.Fatalf("Failed to save task: %v", err) } // Retrieve and verify retrieved, err := GetTask(task.UUID) if err != nil { t.Fatalf("Failed to get task: %v", err) } if retrieved.Description != "Modified description" { t.Error("Description not updated") } if retrieved.Priority != PriorityHigh { t.Error("Priority not updated") } if retrieved.Project == nil || *retrieved.Project != "test-project" { t.Error("Project not updated") } } func TestTaskTags(t *testing.T) { task, err := CreateTask("Test tags") if err != nil { t.Fatalf("Failed to create task: %v", err) } // Add tags if err := task.AddTag("urgent"); err != nil { t.Fatalf("Failed to add tag: %v", err) } if err := task.AddTag("work"); err != nil { t.Fatalf("Failed to add tag: %v", err) } // Retrieve and verify tags retrieved, err := GetTask(task.UUID) if err != nil { t.Fatalf("Failed to get task: %v", err) } if len(retrieved.Tags) != 2 { t.Errorf("Expected 2 tags, got %d", len(retrieved.Tags)) } // Remove a tag if err := retrieved.RemoveTag("urgent"); err != nil { t.Fatalf("Failed to remove tag: %v", err) } // Verify removal retrieved2, err := GetTask(task.UUID) if err != nil { t.Fatalf("Failed to get task: %v", err) } if len(retrieved2.Tags) != 1 { t.Errorf("Expected 1 tag after removal, got %d", len(retrieved2.Tags)) } if retrieved2.Tags[0] != "work" { t.Errorf("Expected remaining tag 'work', got '%s'", retrieved2.Tags[0]) } } func TestTaskComplete(t *testing.T) { task, err := CreateTask("Test complete") if err != nil { t.Fatalf("Failed to create task: %v", err) } if err := task.Complete(); err != nil { t.Fatalf("Failed to complete task: %v", err) } if task.Status != StatusCompleted { t.Error("Status should be Completed") } if task.End == nil { t.Error("End time should be set") } // Verify in database retrieved, err := GetTask(task.UUID) if err != nil { t.Fatalf("Failed to get task: %v", err) } if retrieved.Status != StatusCompleted { t.Error("Retrieved task should be completed") } } func TestTaskDelete(t *testing.T) { // Test soft delete task1, err := CreateTask("Test soft delete") if err != nil { t.Fatalf("Failed to create task: %v", err) } if err := task1.Delete(false); err != nil { t.Fatalf("Failed to soft delete: %v", err) } retrieved, err := GetTask(task1.UUID) if err != nil { t.Fatalf("Failed to get deleted task: %v", err) } if retrieved.Status != StatusDeleted { t.Error("Task should be marked as deleted") } // Test hard delete task2, err := CreateTask("Test hard delete") if err != nil { t.Fatalf("Failed to create task: %v", err) } if err := task2.Delete(true); err != nil { t.Fatalf("Failed to hard delete: %v", err) } _, err = GetTask(task2.UUID) if err == nil { t.Error("Should not be able to retrieve hard-deleted task") } } func TestTaskStartStop(t *testing.T) { task, err := CreateTask("Test start/stop") if err != nil { t.Fatalf("Failed to create task: %v", err) } // Start task if err := task.StartTask(); err != nil { t.Fatalf("Failed to start task: %v", err) } if task.Start == nil { t.Error("Start time should be set") } // Stop task if err := task.StopTask(); err != nil { t.Fatalf("Failed to stop task: %v", err) } if task.Start != nil { t.Error("Start time should be nil after stop") } } func TestGetTasks(t *testing.T) { // Create multiple tasks CreateTask("Task 1") CreateTask("Task 2") CreateTask("Task 3") tasks, err := GetTasks(nil) if err != nil { t.Fatalf("Failed to get tasks: %v", err) } if len(tasks) < 3 { t.Errorf("Expected at least 3 tasks, got %d", len(tasks)) } } func TestTaskWithDueDate(t *testing.T) { task, err := CreateTask("Task with due date") if err != nil { t.Fatalf("Failed to create task: %v", err) } dueDate := time.Now().Add(24 * time.Hour) task.Due = &dueDate if err := task.Save(); err != nil { t.Fatalf("Failed to save task with due date: %v", err) } retrieved, err := GetTask(task.UUID) if err != nil { t.Fatalf("Failed to get task: %v", err) } if retrieved.Due == nil { t.Error("Due date should be set") } if retrieved.Due.Unix() != dueDate.Unix() { t.Error("Due dates don't match") } }