Files
audita/internal/cli/run_test.go

200 lines
5.6 KiB
Go

package cli
import (
"bytes"
"errors"
"strings"
"testing"
)
func TestRunRootHelp(t *testing.T) {
var stdout bytes.Buffer
var stderr bytes.Buffer
exitCode := Run([]string{"--help"}, &stdout, &stderr)
if exitCode != 0 {
t.Fatalf("expected exit code 0, got %d", exitCode)
}
if !strings.Contains(stdout.String(), "audita <command> [options]") {
t.Fatalf("expected root usage in stdout, got %q", stdout.String())
}
if !strings.Contains(stdout.String(), "process") {
t.Fatalf("expected process command in root help, got %q", stdout.String())
}
if stderr.Len() != 0 {
t.Fatalf("expected empty stderr, got %q", stderr.String())
}
}
func TestRunProcessHelpListsExpectedFlags(t *testing.T) {
var stdout bytes.Buffer
var stderr bytes.Buffer
exitCode := Run([]string{"process", "--help"}, &stdout, &stderr)
if exitCode != 0 {
t.Fatalf("expected exit code 0, got %d", exitCode)
}
for _, expectedFlag := range []string{
"--glossary",
"--output",
"--report-json",
"--modules",
"--llm-api-key",
"--validation-llm-api-key",
"--model",
"--validation-model",
"--base-url",
"--validation-base-url",
"--llm-timeout-seconds",
"--validation-llm-timeout-seconds",
"--validation-max-prompt-tokens",
"--target-sections",
"--max-retries",
"--validation-max-retries",
"--validation-llm-concurrency",
"--max-section-tokens",
"--min-section-tokens",
"--glossary-confidence-threshold",
"--grammar-confidence-threshold",
"--homophones-confidence-threshold",
"--spoken-word-confidence-threshold",
"--normalize-max-segment-gap",
"--normalize-ellipsis-gap",
"--normalize-max-segment-duration",
"--normalize-max-segment-tokens",
"--work-dir",
"--work-dir-retention",
} {
if !strings.Contains(stdout.String(), expectedFlag) {
t.Fatalf("expected process help to include %q, got %q", expectedFlag, stdout.String())
}
}
if stderr.Len() != 0 {
t.Fatalf("expected empty stderr, got %q", stderr.String())
}
}
func TestRunUnknownCommand(t *testing.T) {
var stdout bytes.Buffer
var stderr bytes.Buffer
exitCode := Run([]string{"unknown"}, &stdout, &stderr)
if exitCode != 2 {
t.Fatalf("expected exit code 2, got %d", exitCode)
}
if stdout.Len() != 0 {
t.Fatalf("expected empty stdout, got %q", stdout.String())
}
if !strings.Contains(stderr.String(), "unknown command") {
t.Fatalf("expected unknown command error in stderr, got %q", stderr.String())
}
}
func TestRunProcessMissingTranscriptPath(t *testing.T) {
var stdout bytes.Buffer
var stderr bytes.Buffer
exitCode := Run([]string{"process", "--glossary", "glossary.yaml"}, &stdout, &stderr)
if exitCode == 0 {
t.Fatalf("expected nonzero exit code")
}
if stdout.Len() != 0 {
t.Fatalf("expected empty stdout, got %q", stdout.String())
}
if !strings.Contains(stderr.String(), "expected exactly 1 transcript JSON path argument") {
t.Fatalf("expected missing transcript error, got %q", stderr.String())
}
}
func TestRunProcessMissingGlossary(t *testing.T) {
var stdout bytes.Buffer
var stderr bytes.Buffer
exitCode := Run([]string{"process", "transcript.json"}, &stdout, &stderr)
if exitCode == 0 {
t.Fatalf("expected nonzero exit code")
}
if stdout.Len() != 0 {
t.Fatalf("expected empty stdout, got %q", stdout.String())
}
if !strings.Contains(stderr.String(), "--glossary is required") {
t.Fatalf("expected missing glossary error, got %q", stderr.String())
}
}
func TestRunProcessInvalidCLIConfig(t *testing.T) {
var stdout bytes.Buffer
var stderr bytes.Buffer
exitCode := Run([]string{"process", "transcript.json", "--glossary", "glossary.yaml", "--work-dir-retention", "invalid"}, &stdout, &stderr)
if exitCode != 2 {
t.Fatalf("expected exit code 2, got %d", exitCode)
}
if stdout.Len() != 0 {
t.Fatalf("expected empty stdout, got %q", stdout.String())
}
if !strings.Contains(stderr.String(), "invalid CLI configuration") {
t.Fatalf("expected invalid config error, got %q", stderr.String())
}
}
func TestRunProcessNotImplemented(t *testing.T) {
var stdout bytes.Buffer
var stderr bytes.Buffer
exitCode := Run([]string{"process", "transcript.json", "--glossary", "glossary.yaml"}, &stdout, &stderr)
if exitCode != 1 {
t.Fatalf("expected exit code 1 for not-implemented process, got %d", exitCode)
}
if stdout.Len() != 0 {
t.Fatalf("expected empty stdout, got %q", stdout.String())
}
if !strings.Contains(stderr.String(), processNotImplementedMessage) {
t.Fatalf("expected not-implemented message in stderr, got %q", stderr.String())
}
}
func TestRunProcessCLIOverridesEnvironment(t *testing.T) {
var stdout bytes.Buffer
var stderr bytes.Buffer
t.Setenv("AUDITA_MODEL", "env-model")
t.Setenv("AUDITA_VALIDATION_LLM_CONCURRENCY", "2")
var captured processInvocation
originalRunner := processRunner
processRunner = func(inv processInvocation) error {
captured = inv
return errors.New(processNotImplementedMessage)
}
t.Cleanup(func() {
processRunner = originalRunner
})
exitCode := Run([]string{
"process",
"transcript.json",
"--glossary",
"glossary.yaml",
"--model",
"cli-model",
"--validation-llm-concurrency",
"5",
}, &stdout, &stderr)
if exitCode != 1 {
t.Fatalf("expected exit code 1 for not implemented, got %d", exitCode)
}
if captured.Config.PrimaryLLM.Model != "cli-model" {
t.Fatalf("expected CLI model override, got %q", captured.Config.PrimaryLLM.Model)
}
if captured.Config.ValidationLLM.Concurrency == nil || *captured.Config.ValidationLLM.Concurrency != 5 {
t.Fatalf("expected CLI validation concurrency override, got %#v", captured.Config.ValidationLLM.Concurrency)
}
if captured.GlossaryPath != "glossary.yaml" {
t.Fatalf("unexpected glossary path: %q", captured.GlossaryPath)
}
}