package main import ( "strings" "testing" "github.com/open-code-review/open-code-review/internal/model" ) func TestBuildBadge(t *testing.T) { tests := []struct { name string comment model.LlmComment want string }{ {"both fields", model.LlmComment{Category: "security", Severity: "high"}, "[security · high]"}, {"category only", model.LlmComment{Category: "bug"}, "[bug]"}, {"severity only", model.LlmComment{Severity: "low"}, "[low]"}, {"neither", model.LlmComment{}, ""}, {"strips control chars", model.LlmComment{Category: "bug\x1b[0m", Severity: "high"}, "[bug[0m · high]"}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := buildBadge(tt.comment); got != tt.want { t.Errorf("buildBadge() = %q, want %q", got, tt.want) } }) } } func TestSeverityColor(t *testing.T) { // Each known severity must map to a distinct color; unknown falls back to dim. seen := map[string]string{} for _, sev := range []string{"critical", "high", "medium", "low"} { c := severityColor(sev) if c == "" { t.Errorf("severityColor(%q) is empty", sev) } if prev, ok := seen[c]; ok { t.Errorf("severityColor(%q) shares color with %q", sev, prev) } seen[c] = sev } if got := severityColor("bogus"); got != "\033[2m" { t.Errorf("severityColor(unknown) = %q, want dim", got) } if got := severityColor(""); got != "\033[2m" { t.Errorf("severityColor(empty) = %q, want dim", got) } } // TestRenderComment_BadgeInline verifies the badge is colorized and rendered inline // with the first line of the comment content. func TestRenderComment_BadgeInline(t *testing.T) { out := captureStdout(t, func() { renderComment(model.LlmComment{ Path: "internal/mcp/client.go", StartLine: 27, EndLine: 27, Content: "Potential environment variable leak.", Category: "security", Severity: "high", }) }) if !strings.Contains(out, "[security · high]") { t.Errorf("expected badge in output, got:\n%s", out) } // severity high → bright red; the badge must be wrapped in the color + reset. if !strings.Contains(out, "\033[91m[security · high]\033[0m") { t.Errorf("expected colorized badge, got:\n%q", out) } if !strings.Contains(out, "Potential environment variable leak.") { t.Errorf("expected content in output, got:\n%s", out) } } func TestSanitizeTerminal(t *testing.T) { tests := []struct { name string in string want string }{ {"plain text unchanged", "hello world", "hello world"}, {"preserves tab", "col1\tcol2", "col1\tcol2"}, {"preserves newline", "line1\nline2", "line1\nline2"}, {"strips ESC", "before\x1b[2Jafter", "before[2Jafter"}, {"strips OSC 52", "\x1b]52;c;dGVzdA==\x07", "]52;c;dGVzdA=="}, {"strips BEL alone", "beep\x07done", "beepdone"}, {"strips null byte", "a\x00b", "ab"}, {"strips DEL", "a\x7fb", "ab"}, {"strips carriage return", "fake\rreal", "fakereal"}, {"empty string", "", ""}, {"only control chars", "\x1b\x07\x00\x7f", ""}, {"unicode preserved", "代码审查 レビュー 🔍", "代码审查 レビュー 🔍"}, {"mixed safe and unsafe", "path\x1b[0m/file.go", "path[0m/file.go"}, {"strips C1 CSI (U+009B)", "before\u009bafter", "beforeafter"}, {"strips C1 OSC (U+009D)", "before\u009dafter", "beforeafter"}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got := sanitizeTerminal(tt.in) if got != tt.want { t.Errorf("sanitizeTerminal(%q) = %q, want %q", tt.in, got, tt.want) } }) } }