package task import ( "os" "path/filepath" "testing" "time" ) func TestParse_SingleTask(t *testing.T) { yaml := ` name: "Test Task" description: "A simple test" claude: model: "sonnet" instructions: "Do something" working_dir: "/tmp" timeout: "10m" tags: - "test" ` tasks, err := Parse([]byte(yaml)) if err != nil { t.Fatalf("unexpected error: %v", err) } if len(tasks) != 1 { t.Fatalf("expected 1 task, got %d", len(tasks)) } task := tasks[0] if task.Name != "Test Task" { t.Errorf("expected name 'Test Task', got %q", task.Name) } if task.Claude.Model != "sonnet" { t.Errorf("expected model 'sonnet', got %q", task.Claude.Model) } if task.Timeout.Duration != 10*time.Minute { t.Errorf("expected timeout 10m, got %v", task.Timeout.Duration) } if task.State != StatePending { t.Errorf("expected state PENDING, got %v", task.State) } if task.ID == "" { t.Error("expected auto-generated ID") } if task.Priority != PriorityNormal { t.Errorf("expected default priority 'normal', got %q", task.Priority) } } func TestParse_BatchTasks(t *testing.T) { yaml := ` tasks: - name: "Task A" claude: instructions: "Do A" working_dir: "/tmp" tags: ["alpha"] - name: "Task B" claude: instructions: "Do B" working_dir: "/tmp" tags: ["beta"] ` tasks, err := Parse([]byte(yaml)) if err != nil { t.Fatalf("unexpected error: %v", err) } if len(tasks) != 2 { t.Fatalf("expected 2 tasks, got %d", len(tasks)) } if tasks[0].Name != "Task A" { t.Errorf("expected 'Task A', got %q", tasks[0].Name) } if tasks[1].Name != "Task B" { t.Errorf("expected 'Task B', got %q", tasks[1].Name) } } func TestParse_MissingName_ReturnsError(t *testing.T) { yaml := ` description: "no name" claude: instructions: "something" ` _, err := Parse([]byte(yaml)) if err == nil { t.Fatal("expected error for missing name") } } func TestParse_DefaultRetryConfig(t *testing.T) { yaml := ` name: "Defaults" claude: instructions: "test" ` tasks, err := Parse([]byte(yaml)) if err != nil { t.Fatalf("unexpected error: %v", err) } if tasks[0].Retry.MaxAttempts != 1 { t.Errorf("expected default max_attempts=1, got %d", tasks[0].Retry.MaxAttempts) } if tasks[0].Retry.Backoff != "exponential" { t.Errorf("expected default backoff 'exponential', got %q", tasks[0].Retry.Backoff) } } func TestParse_WithPriority(t *testing.T) { yaml := ` name: "High Priority" priority: "high" claude: instructions: "urgent" ` tasks, err := Parse([]byte(yaml)) if err != nil { t.Fatalf("unexpected error: %v", err) } if tasks[0].Priority != PriorityHigh { t.Errorf("expected priority 'high', got %q", tasks[0].Priority) } } func TestParseFile(t *testing.T) { dir := t.TempDir() path := filepath.Join(dir, "task.yaml") content := ` name: "File Task" claude: instructions: "from file" working_dir: "/tmp" ` if err := os.WriteFile(path, []byte(content), 0644); err != nil { t.Fatal(err) } tasks, err := ParseFile(path) if err != nil { t.Fatalf("unexpected error: %v", err) } if len(tasks) != 1 || tasks[0].Name != "File Task" { t.Errorf("unexpected tasks: %+v", tasks) } } func TestParseFile_NotFound(t *testing.T) { _, err := ParseFile("/nonexistent/task.yaml") if err == nil { t.Fatal("expected error for nonexistent file") } }