diff --git a/internal/adapter/cli/run_test.go b/internal/adapter/cli/run_test.go index 7b06d8c..ef0e61f 100644 --- a/internal/adapter/cli/run_test.go +++ b/internal/adapter/cli/run_test.go @@ -662,42 +662,29 @@ func TestRunCommandVarsOptional(t *testing.T) { } func TestRunCommandSucceedsWithPromptAndProfileDirsFromConfig(t *testing.T) { - tmp := t.TempDir() - promptDir := filepath.Join(tmp, "prompts") - profileDir := filepath.Join(tmp, "profiles") - if err := os.MkdirAll(promptDir, 0o755); err != nil { - t.Fatal(err) - } - if err := os.MkdirAll(profileDir, 0o755); err != nil { - t.Fatal(err) - } - inputPath := filepath.Join(tmp, "transcript.md") - if err := os.WriteFile(inputPath, []byte("hello"), 0o644); err != nil { - t.Fatal(err) - } + lib := newCLITestLibrary(t) + inputPath := lib.writeInputFile(t, "transcript.md", "hello") ts := newTestLLMServer("from-config-dirs", nil) defer ts.Close() - writePromptFile(t, promptDir, "prompt.default", "local-default") - writeProfileFile(t, profileDir, "local-default", ts.URL+"/v1", "profile-model") + writePromptFile(t, lib.promptDir, "prompt.default", "local-default") + writeProfileFile(t, lib.profileDir, "local-default", ts.URL+"/v1", "profile-model") configPath := writeAppConfigFile(t, fmt.Sprintf(` prompt_dir: %s profile_dir: %s -`, promptDir, profileDir)) +`, lib.promptDir, lib.profileDir)) - var stdout bytes.Buffer - var stderr bytes.Buffer - code := runCommand([]string{ + code, stdout, stderr := runCLICommand(t, runCommand, []string{ "--config", configPath, "--prompt", "prompt.default", "--input", "transcript=" + inputPath, - }, &stdout, &stderr) + }) if code != ExitOK { - t.Fatalf("expected ExitOK, got %d stderr=%q", code, stderr.String()) + t.Fatalf("expected ExitOK, got %d stderr=%q", code, stderr) } - if stdout.String() != "from-config-dirs" { - t.Fatalf("unexpected stdout output: %q", stdout.String()) + if stdout != "from-config-dirs" { + t.Fatalf("unexpected stdout output: %q", stdout) } } @@ -706,28 +693,15 @@ func TestRenderCommandDefaultFormatTextIncludesPreparedDetailsAndNoSecrets(t *te const secret = "super-secret-render-key" t.Setenv(envName, secret) - tmp := t.TempDir() - promptDir := filepath.Join(tmp, "prompts") - profileDir := filepath.Join(tmp, "profiles") - if err := os.MkdirAll(promptDir, 0o755); err != nil { - t.Fatal(err) - } - if err := os.MkdirAll(profileDir, 0o755); err != nil { - t.Fatal(err) - } - inputPath := filepath.Join(tmp, "transcript.md") - if err := os.WriteFile(inputPath, []byte("hello transcript"), 0o644); err != nil { - t.Fatal(err) - } + lib := newCLITestLibrary(t) + inputPath := lib.writeInputFile(t, "transcript.md", "hello transcript") - writePromptFileWithTemplate(t, promptDir, "prompt.render", "local-default", "Date {{.session_date}} - Summarize: {{input \"transcript\"}}") - writeProfileFile(t, profileDir, "local-default", "http://127.0.0.1:1/v1", "profile-model") + writePromptFileWithTemplate(t, lib.promptDir, "prompt.render", "local-default", "Date {{.session_date}} - Summarize: {{input \"transcript\"}}") + writeProfileFile(t, lib.profileDir, "local-default", "http://127.0.0.1:1/v1", "profile-model") - var stdout bytes.Buffer - var stderr bytes.Buffer - code := renderCommand([]string{ - "--prompt-dir", promptDir, - "--profile-dir", profileDir, + code, stdout, stderr := runCLICommand(t, renderCommand, []string{ + "--prompt-dir", lib.promptDir, + "--profile-dir", lib.profileDir, "--prompt", "prompt.render", "--profile", "local-default", "--input", "transcript=" + inputPath, @@ -739,15 +713,15 @@ func TestRenderCommandDefaultFormatTextIncludesPreparedDetailsAndNoSecrets(t *te "--top-p", "0.2", "--timeout", "20s", "--api-key-env", envName, - }, &stdout, &stderr) + }) if code != ExitOK { - t.Fatalf("expected ExitOK, got %d stderr=%q", code, stderr.String()) + t.Fatalf("expected ExitOK, got %d stderr=%q", code, stderr) } - if stderr.Len() != 0 { - t.Fatalf("expected empty stderr on success, got %q", stderr.String()) + if stderr != "" { + t.Fatalf("expected empty stderr on success, got %q", stderr) } - out := stdout.String() + out := stdout for _, want := range []string{ "prompt: prompt.render", "selected_profile_id: local-default", @@ -774,111 +748,72 @@ func TestRenderCommandDefaultFormatTextIncludesPreparedDetailsAndNoSecrets(t *te } func TestRenderCommandSucceedsWithPromptAndProfileDirsFromConfig(t *testing.T) { - tmp := t.TempDir() - promptDir := filepath.Join(tmp, "prompts") - profileDir := filepath.Join(tmp, "profiles") - if err := os.MkdirAll(promptDir, 0o755); err != nil { - t.Fatal(err) - } - if err := os.MkdirAll(profileDir, 0o755); err != nil { - t.Fatal(err) - } - inputPath := filepath.Join(tmp, "transcript.md") - if err := os.WriteFile(inputPath, []byte("hello transcript"), 0o644); err != nil { - t.Fatal(err) - } + lib := newCLITestLibrary(t) + inputPath := lib.writeInputFile(t, "transcript.md", "hello transcript") - writePromptFile(t, promptDir, "prompt.render", "local-default") - writeProfileFile(t, profileDir, "local-default", "http://127.0.0.1:1/v1", "profile-model") + writePromptFile(t, lib.promptDir, "prompt.render", "local-default") + writeProfileFile(t, lib.profileDir, "local-default", "http://127.0.0.1:1/v1", "profile-model") configPath := writeAppConfigFile(t, fmt.Sprintf(` prompt_dir: %s profile_dir: %s -`, promptDir, profileDir)) +`, lib.promptDir, lib.profileDir)) - var stdout bytes.Buffer - var stderr bytes.Buffer - code := renderCommand([]string{ + code, stdout, stderr := runCLICommand(t, renderCommand, []string{ "--config", configPath, "--prompt", "prompt.render", "--input", "transcript=" + inputPath, - }, &stdout, &stderr) + }) if code != ExitOK { - t.Fatalf("expected ExitOK, got %d stderr=%q", code, stderr.String()) + t.Fatalf("expected ExitOK, got %d stderr=%q", code, stderr) } - if !strings.Contains(stdout.String(), "prompt: prompt.render") { - t.Fatalf("expected rendered output, got %q", stdout.String()) + if !strings.Contains(stdout, "prompt: prompt.render") { + t.Fatalf("expected rendered output, got %q", stdout) } } func TestRenderCommandExplicitTextFormatWorks(t *testing.T) { - tmp := t.TempDir() - promptDir := filepath.Join(tmp, "prompts") - profileDir := filepath.Join(tmp, "profiles") - if err := os.MkdirAll(promptDir, 0o755); err != nil { - t.Fatal(err) - } - if err := os.MkdirAll(profileDir, 0o755); err != nil { - t.Fatal(err) - } - inputPath := filepath.Join(tmp, "transcript.md") - if err := os.WriteFile(inputPath, []byte("hello transcript"), 0o644); err != nil { - t.Fatal(err) - } + lib := newCLITestLibrary(t) + inputPath := lib.writeInputFile(t, "transcript.md", "hello transcript") - writePromptFile(t, promptDir, "prompt.render", "local-default") - writeProfileFile(t, profileDir, "local-default", "http://127.0.0.1:1/v1", "profile-model") + writePromptFile(t, lib.promptDir, "prompt.render", "local-default") + writeProfileFile(t, lib.profileDir, "local-default", "http://127.0.0.1:1/v1", "profile-model") - var stdout bytes.Buffer - var stderr bytes.Buffer - code := renderCommand([]string{ - "--prompt-dir", promptDir, - "--profile-dir", profileDir, + code, stdout, stderr := runCLICommand(t, renderCommand, []string{ + "--prompt-dir", lib.promptDir, + "--profile-dir", lib.profileDir, "--prompt", "prompt.render", "--input", "transcript=" + inputPath, "--format", "text", - }, &stdout, &stderr) + }) if code != ExitOK { - t.Fatalf("expected ExitOK, got %d stderr=%q", code, stderr.String()) + t.Fatalf("expected ExitOK, got %d stderr=%q", code, stderr) } - if !strings.Contains(stdout.String(), "prompt: prompt.render") { - t.Fatalf("expected text output for explicit --format text, got %q", stdout.String()) + if !strings.Contains(stdout, "prompt: prompt.render") { + t.Fatalf("expected text output for explicit --format text, got %q", stdout) } } func TestRenderCommandExplicitJSONFormatOutputsValidJSON(t *testing.T) { - tmp := t.TempDir() - promptDir := filepath.Join(tmp, "prompts") - profileDir := filepath.Join(tmp, "profiles") - if err := os.MkdirAll(promptDir, 0o755); err != nil { - t.Fatal(err) - } - if err := os.MkdirAll(profileDir, 0o755); err != nil { - t.Fatal(err) - } - inputPath := filepath.Join(tmp, "transcript.md") - if err := os.WriteFile(inputPath, []byte("hello transcript"), 0o644); err != nil { - t.Fatal(err) - } + lib := newCLITestLibrary(t) + inputPath := lib.writeInputFile(t, "transcript.md", "hello transcript") - writePromptFile(t, promptDir, "prompt.render", "local-default") - writeProfileFile(t, profileDir, "local-default", "http://127.0.0.1:1/v1", "profile-model") + writePromptFile(t, lib.promptDir, "prompt.render", "local-default") + writeProfileFile(t, lib.profileDir, "local-default", "http://127.0.0.1:1/v1", "profile-model") - var stdout bytes.Buffer - var stderr bytes.Buffer - code := renderCommand([]string{ - "--prompt-dir", promptDir, - "--profile-dir", profileDir, + code, stdout, stderr := runCLICommand(t, renderCommand, []string{ + "--prompt-dir", lib.promptDir, + "--profile-dir", lib.profileDir, "--prompt", "prompt.render", "--input", "transcript=" + inputPath, "--format", "json", - }, &stdout, &stderr) + }) if code != ExitOK { - t.Fatalf("expected ExitOK, got %d stderr=%q", code, stderr.String()) + t.Fatalf("expected ExitOK, got %d stderr=%q", code, stderr) } var payload map[string]any - if err := json.Unmarshal(stdout.Bytes(), &payload); err != nil { - t.Fatalf("expected valid json output, got %v\nbody=%s", err, stdout.String()) + if err := json.Unmarshal([]byte(stdout), &payload); err != nil { + t.Fatalf("expected valid json output, got %v\nbody=%s", err, stdout) } if payload["prompt_id"] != "prompt.render" { t.Fatalf("expected prompt_id, got %#v", payload["prompt_id"]) @@ -910,38 +845,25 @@ func TestRenderCommandUnknownFormatFailsClearly(t *testing.T) { } func TestRenderCommandOutWritesToFile(t *testing.T) { - tmp := t.TempDir() - promptDir := filepath.Join(tmp, "prompts") - profileDir := filepath.Join(tmp, "profiles") - if err := os.MkdirAll(promptDir, 0o755); err != nil { - t.Fatal(err) - } - if err := os.MkdirAll(profileDir, 0o755); err != nil { - t.Fatal(err) - } - inputPath := filepath.Join(tmp, "transcript.md") - if err := os.WriteFile(inputPath, []byte("hello transcript"), 0o644); err != nil { - t.Fatal(err) - } - outPath := filepath.Join(tmp, "render.txt") + lib := newCLITestLibrary(t) + inputPath := lib.writeInputFile(t, "transcript.md", "hello transcript") + outPath := filepath.Join(lib.rootDir, "render.txt") - writePromptFile(t, promptDir, "prompt.render", "local-default") - writeProfileFile(t, profileDir, "local-default", "http://127.0.0.1:1/v1", "profile-model") + writePromptFile(t, lib.promptDir, "prompt.render", "local-default") + writeProfileFile(t, lib.profileDir, "local-default", "http://127.0.0.1:1/v1", "profile-model") - var stdout bytes.Buffer - var stderr bytes.Buffer - code := renderCommand([]string{ - "--prompt-dir", promptDir, - "--profile-dir", profileDir, + code, stdout, stderr := runCLICommand(t, renderCommand, []string{ + "--prompt-dir", lib.promptDir, + "--profile-dir", lib.profileDir, "--prompt", "prompt.render", "--input", "transcript=" + inputPath, "--out", outPath, - }, &stdout, &stderr) + }) if code != ExitOK { - t.Fatalf("expected ExitOK, got %d stderr=%q", code, stderr.String()) + t.Fatalf("expected ExitOK, got %d stderr=%q", code, stderr) } - if stdout.Len() != 0 { - t.Fatalf("expected empty stdout when --out is set, got %q", stdout.String()) + if stdout != "" { + t.Fatalf("expected empty stdout when --out is set, got %q", stdout) } out, err := os.ReadFile(outPath) if err != nil { @@ -953,36 +875,23 @@ func TestRenderCommandOutWritesToFile(t *testing.T) { } func TestRenderCommandPromptDefaultProfileWorksThroughCLIPath(t *testing.T) { - tmp := t.TempDir() - promptDir := filepath.Join(tmp, "prompts") - profileDir := filepath.Join(tmp, "profiles") - if err := os.MkdirAll(promptDir, 0o755); err != nil { - t.Fatal(err) - } - if err := os.MkdirAll(profileDir, 0o755); err != nil { - t.Fatal(err) - } - inputPath := filepath.Join(tmp, "transcript.md") - if err := os.WriteFile(inputPath, []byte("hello"), 0o644); err != nil { - t.Fatal(err) - } + lib := newCLITestLibrary(t) + inputPath := lib.writeInputFile(t, "transcript.md", "hello") - writePromptFile(t, promptDir, "prompt.default", "local-default") - writeProfileFile(t, profileDir, "local-default", "http://127.0.0.1:1/v1", "default-model") + writePromptFile(t, lib.promptDir, "prompt.default", "local-default") + writeProfileFile(t, lib.profileDir, "local-default", "http://127.0.0.1:1/v1", "default-model") - var stdout bytes.Buffer - var stderr bytes.Buffer - code := renderCommand([]string{ - "--prompt-dir", promptDir, - "--profile-dir", profileDir, + code, stdout, stderr := runCLICommand(t, renderCommand, []string{ + "--prompt-dir", lib.promptDir, + "--profile-dir", lib.profileDir, "--prompt", "prompt.default", "--input", "transcript=" + inputPath, - }, &stdout, &stderr) + }) if code != ExitOK { - t.Fatalf("expected ExitOK, got %d stderr=%q", code, stderr.String()) + t.Fatalf("expected ExitOK, got %d stderr=%q", code, stderr) } - out := stdout.String() + out := stdout if !strings.Contains(out, "selected_profile_id: local-default") { t.Fatalf("expected prompt default profile in output, got %q", out) } @@ -992,38 +901,25 @@ func TestRenderCommandPromptDefaultProfileWorksThroughCLIPath(t *testing.T) { } func TestRenderCommandExplicitProfileOverridesPromptDefault(t *testing.T) { - tmp := t.TempDir() - promptDir := filepath.Join(tmp, "prompts") - profileDir := filepath.Join(tmp, "profiles") - if err := os.MkdirAll(promptDir, 0o755); err != nil { - t.Fatal(err) - } - if err := os.MkdirAll(profileDir, 0o755); err != nil { - t.Fatal(err) - } - inputPath := filepath.Join(tmp, "transcript.md") - if err := os.WriteFile(inputPath, []byte("hello"), 0o644); err != nil { - t.Fatal(err) - } + lib := newCLITestLibrary(t) + inputPath := lib.writeInputFile(t, "transcript.md", "hello") - writePromptFile(t, promptDir, "prompt.default", "local-default") - writeProfileFile(t, profileDir, "local-default", "http://127.0.0.1:1/v1", "default-model") - writeProfileFile(t, profileDir, "quality", "http://127.0.0.1:1/v1", "quality-model") + writePromptFile(t, lib.promptDir, "prompt.default", "local-default") + writeProfileFile(t, lib.profileDir, "local-default", "http://127.0.0.1:1/v1", "default-model") + writeProfileFile(t, lib.profileDir, "quality", "http://127.0.0.1:1/v1", "quality-model") - var stdout bytes.Buffer - var stderr bytes.Buffer - code := renderCommand([]string{ - "--prompt-dir", promptDir, - "--profile-dir", profileDir, + code, stdout, stderr := runCLICommand(t, renderCommand, []string{ + "--prompt-dir", lib.promptDir, + "--profile-dir", lib.profileDir, "--prompt", "prompt.default", "--profile", "quality", "--input", "transcript=" + inputPath, - }, &stdout, &stderr) + }) if code != ExitOK { - t.Fatalf("expected ExitOK, got %d stderr=%q", code, stderr.String()) + t.Fatalf("expected ExitOK, got %d stderr=%q", code, stderr) } - out := stdout.String() + out := stdout if !strings.Contains(out, "selected_profile_id: quality") { t.Fatalf("expected explicit profile in output, got %q", out) } @@ -1033,104 +929,67 @@ func TestRenderCommandExplicitProfileOverridesPromptDefault(t *testing.T) { } func TestRunCommandPromptDefaultProfileWorksThroughCLIPath(t *testing.T) { - tmp := t.TempDir() - promptDir := filepath.Join(tmp, "prompts") - profileDir := filepath.Join(tmp, "profiles") - if err := os.MkdirAll(promptDir, 0o755); err != nil { - t.Fatal(err) - } - if err := os.MkdirAll(profileDir, 0o755); err != nil { - t.Fatal(err) - } - inputPath := filepath.Join(tmp, "transcript.md") - if err := os.WriteFile(inputPath, []byte("hello"), 0o644); err != nil { - t.Fatal(err) - } + lib := newCLITestLibrary(t) + inputPath := lib.writeInputFile(t, "transcript.md", "hello") ts := newTestLLMServer("default-output", nil) defer ts.Close() - writePromptFile(t, promptDir, "prompt.default", "local-default") - writeProfileFile(t, profileDir, "local-default", ts.URL+"/v1", "profile-model") + writePromptFile(t, lib.promptDir, "prompt.default", "local-default") + writeProfileFile(t, lib.profileDir, "local-default", ts.URL+"/v1", "profile-model") - var stdout bytes.Buffer - var stderr bytes.Buffer - code := runCommand([]string{ - "--prompt-dir", promptDir, - "--profile-dir", profileDir, + code, stdout, stderr := runCLICommand(t, runCommand, []string{ + "--prompt-dir", lib.promptDir, + "--profile-dir", lib.profileDir, "--prompt", "prompt.default", "--input", "transcript=" + inputPath, - }, &stdout, &stderr) + }) if code != ExitOK { - t.Fatalf("expected ExitOK, got %d stderr=%q", code, stderr.String()) + t.Fatalf("expected ExitOK, got %d stderr=%q", code, stderr) } - if stdout.String() != "default-output" { - t.Fatalf("unexpected stdout output: %q", stdout.String()) + if stdout != "default-output" { + t.Fatalf("unexpected stdout output: %q", stdout) } - if !strings.Contains(stderr.String(), "selected_profile=local-default") { - t.Fatalf("expected selected profile in summary, got %q", stderr.String()) + if !strings.Contains(stderr, "selected_profile=local-default") { + t.Fatalf("expected selected profile in summary, got %q", stderr) } } func TestRunCommandExplicitProfileOverridesPromptDefault(t *testing.T) { - tmp := t.TempDir() - promptDir := filepath.Join(tmp, "prompts") - profileDir := filepath.Join(tmp, "profiles") - if err := os.MkdirAll(promptDir, 0o755); err != nil { - t.Fatal(err) - } - if err := os.MkdirAll(profileDir, 0o755); err != nil { - t.Fatal(err) - } - inputPath := filepath.Join(tmp, "transcript.md") - if err := os.WriteFile(inputPath, []byte("hello"), 0o644); err != nil { - t.Fatal(err) - } + lib := newCLITestLibrary(t) + inputPath := lib.writeInputFile(t, "transcript.md", "hello") defaultServer := newTestLLMServer("from-default", nil) defer defaultServer.Close() overrideServer := newTestLLMServer("from-override", nil) defer overrideServer.Close() - writePromptFile(t, promptDir, "prompt.default", "local-default") - writeProfileFile(t, profileDir, "local-default", defaultServer.URL+"/v1", "default-model") - writeProfileFile(t, profileDir, "quality", overrideServer.URL+"/v1", "quality-model") + writePromptFile(t, lib.promptDir, "prompt.default", "local-default") + writeProfileFile(t, lib.profileDir, "local-default", defaultServer.URL+"/v1", "default-model") + writeProfileFile(t, lib.profileDir, "quality", overrideServer.URL+"/v1", "quality-model") - var stdout bytes.Buffer - var stderr bytes.Buffer - code := runCommand([]string{ - "--prompt-dir", promptDir, - "--profile-dir", profileDir, + code, stdout, stderr := runCLICommand(t, runCommand, []string{ + "--prompt-dir", lib.promptDir, + "--profile-dir", lib.profileDir, "--prompt", "prompt.default", "--profile", "quality", "--input", "transcript=" + inputPath, - }, &stdout, &stderr) + }) if code != ExitOK { - t.Fatalf("expected ExitOK, got %d stderr=%q", code, stderr.String()) + t.Fatalf("expected ExitOK, got %d stderr=%q", code, stderr) } - if stdout.String() != "from-override" { - t.Fatalf("expected explicit profile output, got %q", stdout.String()) + if stdout != "from-override" { + t.Fatalf("expected explicit profile output, got %q", stdout) } - if !strings.Contains(stderr.String(), "selected_profile=quality") { - t.Fatalf("expected selected profile quality, got %q", stderr.String()) + if !strings.Contains(stderr, "selected_profile=quality") { + t.Fatalf("expected selected profile quality, got %q", stderr) } } func TestRunCommandRuntimeFlagsOverrideSelectedProfileValues(t *testing.T) { - tmp := t.TempDir() - promptDir := filepath.Join(tmp, "prompts") - profileDir := filepath.Join(tmp, "profiles") - if err := os.MkdirAll(promptDir, 0o755); err != nil { - t.Fatal(err) - } - if err := os.MkdirAll(profileDir, 0o755); err != nil { - t.Fatal(err) - } - inputPath := filepath.Join(tmp, "transcript.md") - if err := os.WriteFile(inputPath, []byte("hello"), 0o644); err != nil { - t.Fatal(err) - } + lib := newCLITestLibrary(t) + inputPath := lib.writeInputFile(t, "transcript.md", "hello") var baseHits int32 baseServer := newTestLLMServer("base", &baseHits) @@ -1147,14 +1006,12 @@ func TestRunCommandRuntimeFlagsOverrideSelectedProfileValues(t *testing.T) { })) defer overrideServer.Close() - writePromptFile(t, promptDir, "prompt.default", "local-default") - writeProfileFile(t, profileDir, "local-default", baseServer.URL+"/v1", "profile-model") + writePromptFile(t, lib.promptDir, "prompt.default", "local-default") + writeProfileFile(t, lib.profileDir, "local-default", baseServer.URL+"/v1", "profile-model") - var stdout bytes.Buffer - var stderr bytes.Buffer - code := runCommand([]string{ - "--prompt-dir", promptDir, - "--profile-dir", profileDir, + code, stdout, stderr := runCLICommand(t, runCommand, []string{ + "--prompt-dir", lib.promptDir, + "--profile-dir", lib.profileDir, "--prompt", "prompt.default", "--input", "transcript=" + inputPath, "--llm-base-url", overrideServer.URL + "/v1", @@ -1163,9 +1020,9 @@ func TestRunCommandRuntimeFlagsOverrideSelectedProfileValues(t *testing.T) { "--max-tokens", "55", "--top-p", "0.2", "--timeout", "20s", - }, &stdout, &stderr) + }) if code != ExitOK { - t.Fatalf("expected ExitOK, got %d stderr=%q", code, stderr.String()) + t.Fatalf("expected ExitOK, got %d stderr=%q", code, stderr) } if atomic.LoadInt32(&baseHits) != 0 { t.Fatalf("expected base profile endpoint not to be hit, got %d", baseHits) @@ -1173,8 +1030,8 @@ func TestRunCommandRuntimeFlagsOverrideSelectedProfileValues(t *testing.T) { if atomic.LoadInt32(&overrideHits) != 1 { t.Fatalf("expected override endpoint to be hit once, got %d", overrideHits) } - if stdout.String() != "override" { - t.Fatalf("unexpected stdout output: %q", stdout.String()) + if stdout != "override" { + t.Fatalf("unexpected stdout output: %q", stdout) } if !strings.Contains(observedBody, `"model":"override-model"`) { t.Fatalf("expected override model in request body, got %s", observedBody) @@ -1209,6 +1066,49 @@ func TestWriteOutputAndSummaryUseSeparateWriters(t *testing.T) { } } +type cliTestLibrary struct { + rootDir string + promptDir string + profileDir string +} + +func newCLITestLibrary(t *testing.T) *cliTestLibrary { + t.Helper() + root := t.TempDir() + lib := &cliTestLibrary{ + rootDir: root, + promptDir: filepath.Join(root, "prompts"), + profileDir: filepath.Join(root, "profiles"), + } + if err := os.MkdirAll(lib.promptDir, 0o755); err != nil { + t.Fatalf("failed to create prompt fixture directory: %v", err) + } + if err := os.MkdirAll(lib.profileDir, 0o755); err != nil { + t.Fatalf("failed to create profile fixture directory: %v", err) + } + return lib +} + +func (l *cliTestLibrary) writeInputFile(t *testing.T, name, body string) string { + t.Helper() + path := filepath.Join(l.rootDir, name) + if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil { + t.Fatalf("failed to create input fixture directory: %v", err) + } + if err := os.WriteFile(path, []byte(body), 0o644); err != nil { + t.Fatalf("failed to write input fixture: %v", err) + } + return path +} + +func runCLICommand(t *testing.T, command func([]string, io.Writer, io.Writer) int, args []string) (int, string, string) { + t.Helper() + var stdout bytes.Buffer + var stderr bytes.Buffer + code := command(args, &stdout, &stderr) + return code, stdout.String(), stderr.String() +} + func writePromptFile(t *testing.T, dir, id, defaultProfile string) { t.Helper() writePromptFileWithTemplate(t, dir, id, defaultProfile, "Summarize: {{input \"transcript\"}}")