package command import ( "strings" "testing" ) func TestTaskLoopCommandMapsDryRunFilterRetryAndTerminalExit(t *testing.T) { cases := []struct { name string args []string response TaskLoopResponse wantErr bool assert func(t *testing.T, request TaskLoopRequest) }{ { name: "dry run filter", args: []string{"task-loop", "--dry-run", "--task-group", "m-m1", "--repo-config", "/r", "--local-config", "/l"}, response: TaskLoopResponse{DryRun: true}, assert: func(t *testing.T, request TaskLoopRequest) { if !request.DryRun || request.TaskGroup != "m-m1" || request.RetryBlocked { t.Fatalf("request = %#v", request) } }, }, { name: "retry blocked", args: []string{"task-loop", "--retry-blocked", "--task-group", "m-m1", "--repo-config", "/r", "--local-config", "/l", "--provider-catalog", "/c"}, response: TaskLoopResponse{}, assert: func(t *testing.T, request TaskLoopRequest) { if request.DryRun || !request.RetryBlocked || request.Config.ProviderCatalog != "/c" { t.Fatalf("request = %#v", request) } }, }, { name: "drained blocker terminal", args: []string{"task-loop", "--repo-config", "/r", "--local-config", "/l"}, response: TaskLoopResponse{ExitCode: 2}, wantErr: true, assert: func(t *testing.T, request TaskLoopRequest) {}, }, } for _, tt := range cases { t.Run(tt.name, func(t *testing.T) { svc := newTestService() svc.taskLoopResp = tt.response root := NewRoot(svc, newTextBuf(), newTextBuf()) stdout, _, err := cmdRunner(t, root, tt.args) if (err != nil) != tt.wantErr { t.Fatalf("error = %v, want error=%t", err, tt.wantErr) } if !strings.Contains(stdout, "task-loop") { t.Fatalf("stdout = %q", stdout) } tt.assert(t, svc.lastTaskLoopReq) }) } } func TestTaskLoopParityRequiresDisposalManifest(t *testing.T) { svc := newTestService() root := NewRoot(svc, newTextBuf(), newTextBuf()) if _, _, err := cmdRunner(t, root, []string{"task-loop", "parity"}); err == nil { t.Fatal("expected missing disposal manifest error") } stdout, _, err := cmdRunner(t, root, []string{"task-loop", "parity", "--disposal-manifest"}) if err != nil || stdout != "parity: ok\n" { t.Fatalf("stdout=%q err=%v", stdout, err) } } func TestTaskLoopValidatePlanMapsRequestAndPropagatesError(t *testing.T) { svc := newTestService() root := NewRoot(svc, newTextBuf(), newTextBuf()) stdout, _, err := cmdRunner(t, root, []string{"task-loop", "validate-plan", "--workspace", "/workspace", "/tmp/plan.md"}) if err != nil || stdout != "" { t.Fatalf("stdout=%q err=%v", stdout, err) } if svc.lastPlanValidationReq != (PlanValidationRequest{Workspace: "/workspace", PlanPath: "/tmp/plan.md"}) { t.Fatalf("request = %#v", svc.lastPlanValidationReq) } svc.planValidationErr = assertError{} _, _, err = cmdRunner(t, root, []string{"task-loop", "validate-plan", "--workspace", "/workspace", "/tmp/plan.md"}) if err == nil || !strings.Contains(err.Error(), "validate-plan") { t.Fatalf("error = %v", err) } } type assertError struct{} func (assertError) Error() string { return "rejected" }