// This file holds the REPL-integration and headless-flag tests for /status // (US-005, #295) that drive the package-main REPL harness (runREPL/newTestDeps) // or inspect CLI flags. The direct-call rendering tests live in // internal/cli/status alongside RunStatus. package repl import ( "bytes" "strings" "testing" flag "github.com/spf13/pflag" ) func TestStatusGuard(t *testing.T) { // The guard logic is in the REPL loop: matches "/status" or "/status " // but not "/statusfoo" or "/statusbar" testCases := []struct { line string want bool }{ {"/status", true}, {"/status ", true}, {"/status foo", true}, {"/statusbar", false}, {"/statusfoo", false}, {"/status123", false}, {"/stat", false}, {"/session", false}, } for _, tc := range testCases { got := (tc.line == "/status" || strings.HasPrefix(tc.line, "/status ")) if got != tc.want { t.Errorf("line %q: got %v, want %v", tc.line, got, tc.want) } } } func TestRunStatusViaREPL(t *testing.T) { // Verify that /status is intercepted in the REPL loop and doesn't invoke the model p := &replProvider{reply: "should not be called"} deps, _ := newTestDeps(t, p) var out bytes.Buffer in := strings.NewReader("/status\n/exit\n") if err := runREPL(in, &out, deps); err != nil { t.Fatalf("runREPL: %v", err) } if p.calls != 0 { t.Errorf("expected 0 model calls for /status, got %d", p.calls) } output := out.String() if !strings.Contains(output, "runtime config:") { t.Error("expected REPL /status output to contain 'runtime config:'") } if !strings.Contains(output, "context:") { t.Error("expected REPL /status output to contain 'context:'") } } func TestStatusFooNotIntercepted(t *testing.T) { // Verify that "/statusfoo" is NOT intercepted as "/status" p := &replProvider{reply: "model called"} deps, _ := newTestDeps(t, p) var out bytes.Buffer in := strings.NewReader("/statusfoo\n/exit\n") if err := runREPL(in, &out, deps); err != nil { t.Fatalf("runREPL: %v", err) } if p.calls != 0 { t.Errorf("expected 0 model calls for /statusfoo, got %d", p.calls) } output := out.String() if strings.Contains(output, "runtime config:") { t.Error("expected /statusfoo to NOT run the status command") } } // TestStatusNotInHeadless verifies /status is REPL-only: there is no --status // CLI flag. (The /status intercept lives in runREPL only; headless print mode // never runs the REPL loop, so "/status" there is treated as an ordinary // prompt, not a command.) func TestStatusNotInHeadless(t *testing.T) { if f := flag.Lookup("status"); f != nil { t.Errorf("--status flag should not exist (headless must not expose /status), got %v", f) } } // TestStatusE2EViaREPL drives /status through the REPL loop intercept and // asserts every section is present and the model is never invoked. func TestStatusE2EViaREPL(t *testing.T) { p := &replProvider{reply: "should not be called"} deps, _ := newTestDeps(t, p) deps.cwd = "/tmp/e2e-repl" deps.live.Model = "e2e-model" deps.live.ProviderName = "e2e-prov" deps.live.ContextWindow = 128000 var out bytes.Buffer in := strings.NewReader("/status\n/exit\n") if err := runREPL(in, &out, deps); err != nil { t.Fatalf("runREPL: %v", err) } if p.calls != 0 { t.Errorf("expected 0 model calls for /status, got %d", p.calls) } got := out.String() for _, want := range []string{ "runtime config:", "model: e2e-model", "context:", "project & environment:", "credentials & connectivity:", "telemetry:", "no telemetry yet", } { if !strings.Contains(got, want) { t.Errorf("REPL /status: expected output to contain %q", want) } } }