diff options
| author | Peter Stone <thepeterstone@gmail.com> | 2026-02-08 21:35:45 -1000 |
|---|---|---|
| committer | Peter Stone <thepeterstone@gmail.com> | 2026-02-08 21:35:45 -1000 |
| commit | 2e2b2187b957e9af78797a67ec5c6874615fae02 (patch) | |
| tree | 1181dbb7e43f5d30cb025fa4d50fd4e7a2c893b3 /internal/task/validator_test.go | |
Initial project: task model, executor, API server, CLI, storage, reporter
Claudomator automation toolkit for Claude Code with:
- Task model with YAML parsing, validation, state machine (49 tests, 0 races)
- SQLite storage for tasks and executions
- Executor pool with bounded concurrency, timeout, cancellation
- REST API + WebSocket for mobile PWA integration
- Webhook/multi-notifier system
- CLI: init, run, serve, list, status commands
- Console, JSON, HTML reporters with cost tracking
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Diffstat (limited to 'internal/task/validator_test.go')
| -rw-r--r-- | internal/task/validator_test.go | 115 |
1 files changed, 115 insertions, 0 deletions
diff --git a/internal/task/validator_test.go b/internal/task/validator_test.go new file mode 100644 index 0000000..967eed3 --- /dev/null +++ b/internal/task/validator_test.go @@ -0,0 +1,115 @@ +package task + +import ( + "strings" + "testing" +) + +func validTask() *Task { + return &Task{ + ID: "test-id", + Name: "Valid Task", + Claude: ClaudeConfig{ + Instructions: "do something", + WorkingDir: "/tmp", + }, + Priority: PriorityNormal, + Retry: RetryConfig{MaxAttempts: 1, Backoff: "exponential"}, + } +} + +func TestValidate_ValidTask_NoError(t *testing.T) { + task := validTask() + if err := Validate(task); err != nil { + t.Errorf("expected no error, got: %v", err) + } +} + +func TestValidate_MissingName_ReturnsError(t *testing.T) { + task := validTask() + task.Name = "" + err := Validate(task) + if err == nil { + t.Fatal("expected error") + } + if !strings.Contains(err.Error(), "name is required") { + t.Errorf("expected 'name is required' in error, got: %v", err) + } +} + +func TestValidate_MissingInstructions_ReturnsError(t *testing.T) { + task := validTask() + task.Claude.Instructions = "" + err := Validate(task) + if err == nil { + t.Fatal("expected error") + } + if !strings.Contains(err.Error(), "instructions is required") { + t.Errorf("expected 'instructions is required' in error, got: %v", err) + } +} + +func TestValidate_NegativeBudget_ReturnsError(t *testing.T) { + task := validTask() + task.Claude.MaxBudgetUSD = -1.0 + err := Validate(task) + if err == nil { + t.Fatal("expected error") + } + if !strings.Contains(err.Error(), "max_budget_usd") { + t.Errorf("expected budget error, got: %v", err) + } +} + +func TestValidate_InvalidBackoff_ReturnsError(t *testing.T) { + task := validTask() + task.Retry.Backoff = "random" + err := Validate(task) + if err == nil { + t.Fatal("expected error") + } + if !strings.Contains(err.Error(), "backoff") { + t.Errorf("expected backoff error, got: %v", err) + } +} + +func TestValidate_InvalidPriority_ReturnsError(t *testing.T) { + task := validTask() + task.Priority = "urgent" + err := Validate(task) + if err == nil { + t.Fatal("expected error") + } + if !strings.Contains(err.Error(), "invalid priority") { + t.Errorf("expected priority error, got: %v", err) + } +} + +func TestValidate_InvalidPermissionMode_ReturnsError(t *testing.T) { + task := validTask() + task.Claude.PermissionMode = "yolo" + err := Validate(task) + if err == nil { + t.Fatal("expected error") + } + if !strings.Contains(err.Error(), "permission_mode") { + t.Errorf("expected permission_mode error, got: %v", err) + } +} + +func TestValidate_MultipleErrors(t *testing.T) { + task := &Task{ + Retry: RetryConfig{MaxAttempts: 0, Backoff: "bad"}, + } + err := Validate(task) + if err == nil { + t.Fatal("expected error") + } + ve, ok := err.(*ValidationError) + if !ok { + t.Fatalf("expected *ValidationError, got %T", err) + } + if len(ve.Errors) < 3 { + t.Errorf("expected at least 3 errors, got %d: %v", len(ve.Errors), ve.Errors) + } +} |
