package cli import ( "bytes" "errors" "strings" "testing" "time" "gitea.maximumdirect.net/eric/scriptorium/internal/domain" ) func TestParseMappingsSingleAndRepeated(t *testing.T) { got, err := parseMappings([]string{"transcript=./t.md", "glossary=./g.yml"}, false) if err != nil { t.Fatalf("unexpected error: %v", err) } if got["transcript"] != "./t.md" || got["glossary"] != "./g.yml" { t.Fatalf("unexpected mappings: %#v", got) } } func TestParseMappingsCommaSeparated(t *testing.T) { got, err := parseMappings([]string{"transcript=./t.md,glossary=./g.yml"}, false) if err != nil { t.Fatalf("unexpected error: %v", err) } if got["transcript"] != "./t.md" || got["glossary"] != "./g.yml" { t.Fatalf("unexpected mappings: %#v", got) } } func TestParseMappingsVarWithEqualsInValue(t *testing.T) { got, err := parseMappings([]string{"session_note=a=b=c"}, false) if err != nil { t.Fatalf("unexpected error: %v", err) } if got["session_note"] != "a=b=c" { t.Fatalf("unexpected variable value: %#v", got) } } func TestParseMappingsMalformed(t *testing.T) { tests := []string{"", "novalue", "=emptyname", "name="} for _, tc := range tests { _, err := parseMappings([]string{tc}, false) if err == nil { t.Fatalf("expected error for %q", tc) } } } func TestParseRunArgsRequiredFlags(t *testing.T) { _, err := parseRunArgs([]string{"--profile-id", "p", "--input", "a=b", "--llm-base-url", "http://x/v1", "--model", "m"}) if err == nil { t.Fatal("expected missing --profile-dir error") } _, err = parseRunArgs([]string{"--profile-dir", "./profiles", "--input", "a=b", "--llm-base-url", "http://x/v1", "--model", "m"}) if err == nil { t.Fatal("expected missing --profile-id error") } _, err = parseRunArgs([]string{"--profile-dir", "./profiles", "--profile-id", "p", "--llm-base-url", "http://x/v1", "--model", "m"}) if err == nil { t.Fatal("expected missing --input error") } _, err = parseRunArgs([]string{"--profile-dir", "./profiles", "--profile-id", "p", "--input", "a=b", "--model", "m"}) if err == nil { t.Fatal("expected missing --llm-base-url error") } _, err = parseRunArgs([]string{"--profile-dir", "./profiles", "--profile-id", "p", "--input", "a=b", "--llm-base-url", "http://x/v1"}) if err == nil { t.Fatal("expected missing --model error") } } func TestParseServeArgsRequiredFlags(t *testing.T) { _, err := parseServeArgs([]string{"--llm-base-url", "http://x/v1"}) if err == nil { t.Fatal("expected missing --profile-dir error") } _, err = parseServeArgs([]string{"--profile-dir", "./profiles"}) if err == nil { t.Fatal("expected missing --llm-base-url error") } cfg, err := parseServeArgs([]string{"--profile-dir", "./profiles", "--llm-base-url", "http://x/v1"}) if err != nil { t.Fatalf("expected valid serve args, got %v", err) } if cfg.addr != ":8080" { t.Fatalf("expected default addr :8080, got %q", cfg.addr) } if cfg.timeout != 10*time.Minute { t.Fatalf("expected default timeout 10m, got %s", cfg.timeout) } } func TestParseRunArgsTimeout(t *testing.T) { cfg, err := parseRunArgs([]string{ "--profile-dir", "./profiles", "--profile-id", "p", "--input", "a=b", "--llm-base-url", "http://x/v1", "--model", "m", }) if err != nil { t.Fatalf("expected valid run args, got %v", err) } if cfg.timeout != 10*time.Minute { t.Fatalf("expected default timeout 10m, got %s", cfg.timeout) } cfg, err = parseRunArgs([]string{ "--profile-dir", "./profiles", "--profile-id", "p", "--input", "a=b", "--llm-base-url", "http://x/v1", "--model", "m", "--timeout", "2m30s", }) if err != nil { t.Fatalf("expected valid run args with timeout override, got %v", err) } if cfg.timeout != 2*time.Minute+30*time.Second { t.Fatalf("expected timeout override 2m30s, got %s", cfg.timeout) } } func TestDetermineExitCode(t *testing.T) { if got := determineExitCode(errors.New("boom"), nil); got != ExitRuntimeError { t.Fatalf("expected runtime exit code, got %d", got) } if got := determineExitCode(nil, &domain.RunResult{Validation: domain.ValidationResult{Status: domain.ValidationFailed}}); got != ExitValidationFailed { t.Fatalf("expected validation exit code, got %d", got) } if got := determineExitCode(nil, &domain.RunResult{Validation: domain.ValidationResult{Status: domain.ValidationPassed}}); got != ExitOK { t.Fatalf("expected success exit code for passed validation, got %d", got) } if got := determineExitCode(nil, &domain.RunResult{Validation: domain.ValidationResult{Status: domain.ValidationSkipped}}); got != ExitOK { t.Fatalf("expected success exit code for skipped validation, got %d", got) } } func TestRunCommandVarsOptional(t *testing.T) { var stdout bytes.Buffer var stderr bytes.Buffer code := runCommand([]string{ "--profile-dir", "./profiles", "--profile-id", "p", "--input", "transcript=./t.md", "--llm-base-url", "://bad-url", "--model", "m", }, &stdout, &stderr) if code != ExitRuntimeError { t.Fatalf("expected runtime error exit code, got %d", code) } if strings.Contains(stderr.String(), "var parse error") { t.Fatalf("expected --var to be optional, got stderr=%q", stderr.String()) } if !strings.Contains(stderr.String(), "llm client error") { t.Fatalf("expected llm client error after parsing succeeds, got stderr=%q", stderr.String()) } }