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/reporter/reporter_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/reporter/reporter_test.go')
| -rw-r--r-- | internal/reporter/reporter_test.go | 114 |
1 files changed, 114 insertions, 0 deletions
diff --git a/internal/reporter/reporter_test.go b/internal/reporter/reporter_test.go new file mode 100644 index 0000000..1ddce23 --- /dev/null +++ b/internal/reporter/reporter_test.go @@ -0,0 +1,114 @@ +package reporter + +import ( + "bytes" + "encoding/json" + "strings" + "testing" + "time" + + "github.com/claudomator/claudomator/internal/storage" +) + +func sampleExecutions() []*storage.Execution { + now := time.Date(2026, 2, 8, 10, 0, 0, 0, time.UTC) + return []*storage.Execution{ + { + ID: "exec-1", TaskID: "task-1", Status: "COMPLETED", + StartTime: now, EndTime: now.Add(2 * time.Minute), + ExitCode: 0, CostUSD: 0.25, + }, + { + ID: "exec-2", TaskID: "task-2", Status: "FAILED", + StartTime: now, EndTime: now.Add(30 * time.Second), + ExitCode: 1, CostUSD: 0.10, ErrorMsg: "something broke", + }, + } +} + +func TestConsoleReporter_WithExecutions(t *testing.T) { + r := &ConsoleReporter{} + var buf bytes.Buffer + err := r.Generate(&buf, sampleExecutions()) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + output := buf.String() + if !strings.Contains(output, "COMPLETED") { + t.Error("missing COMPLETED status") + } + if !strings.Contains(output, "FAILED") { + t.Error("missing FAILED status") + } + if !strings.Contains(output, "1 completed, 1 failed") { + t.Errorf("missing summary in output: %s", output) + } + if !strings.Contains(output, "$0.3500") { + t.Errorf("missing total cost in output: %s", output) + } +} + +func TestConsoleReporter_Empty(t *testing.T) { + r := &ConsoleReporter{} + var buf bytes.Buffer + r.Generate(&buf, []*storage.Execution{}) + if !strings.Contains(buf.String(), "No executions") { + t.Error("expected 'No executions' message") + } +} + +func TestJSONReporter(t *testing.T) { + r := &JSONReporter{Pretty: false} + var buf bytes.Buffer + err := r.Generate(&buf, sampleExecutions()) + if err != nil { + t.Fatal(err) + } + + var result []storage.Execution + if err := json.Unmarshal(buf.Bytes(), &result); err != nil { + t.Fatalf("invalid JSON: %v", err) + } + if len(result) != 2 { + t.Errorf("want 2 results, got %d", len(result)) + } + if result[0].Status != "COMPLETED" { + t.Errorf("want COMPLETED, got %q", result[0].Status) + } +} + +func TestJSONReporter_Pretty(t *testing.T) { + r := &JSONReporter{Pretty: true} + var buf bytes.Buffer + r.Generate(&buf, sampleExecutions()) + if !strings.Contains(buf.String(), " ") { + t.Error("expected indented JSON") + } +} + +func TestHTMLReporter(t *testing.T) { + r := &HTMLReporter{} + var buf bytes.Buffer + err := r.Generate(&buf, sampleExecutions()) + if err != nil { + t.Fatal(err) + } + + html := buf.String() + if !strings.Contains(html, "<!DOCTYPE html>") { + t.Error("missing DOCTYPE") + } + if !strings.Contains(html, "Claudomator Report") { + t.Error("missing title") + } + if !strings.Contains(html, "COMPLETED") { + t.Error("missing COMPLETED status") + } + if !strings.Contains(html, "FAILED") { + t.Error("missing FAILED status") + } + if !strings.Contains(html, "$0.3500") { + t.Error("missing total cost") + } +} |
