Files
review-bot/review/formatter_test.go
T
Rodin 2287a8238c
CI / test (pull_request) Successful in 14s
CI / review (gpt-4.1, gpt, GPT_REVIEW_TOKEN) (pull_request) Successful in 19s
CI / review (gpt-5, security, SECURITY_REVIEW.md, SONNET_REVIEW_TOKEN) (pull_request) Successful in 1m27s
CI / review (gpt-5, sonnet, SONNET_REVIEW_TOKEN) (pull_request) Successful in 1m42s
feat: add role title as H1 header for visual differentiation
When reviewer-name is set, prepend "# Security Review" / "# Sonnet Review"
etc. as a top-level header. Makes it immediately obvious which role each
review represents in the Gitea UI, especially when multiple reviews come
from the same bot account.
2026-05-01 21:36:32 -07:00

162 lines
4.5 KiB
Go

package review
import (
"strings"
"testing"
)
func TestFormatMarkdown_EmptyFindings(t *testing.T) {
result := &ReviewResult{
Verdict: "APPROVE",
Summary: "All good, no issues.",
Findings: []Finding{},
Recommendation: "Merge this PR.",
}
got := FormatMarkdown(result, "Sonnet")
if !strings.Contains(got, "## Summary") {
t.Error("expected Summary header")
}
if !strings.Contains(got, "All good, no issues.") {
t.Error("expected summary text")
}
if strings.Contains(got, "## Findings") {
t.Error("should not contain Findings header when empty")
}
if !strings.Contains(got, "**APPROVE**") {
t.Error("expected verdict in recommendation")
}
if !strings.Contains(got, "Review by Sonnet") {
t.Error("expected reviewer name")
}
}
func TestFormatMarkdown_MultipleFindings(t *testing.T) {
result := &ReviewResult{
Verdict: "REQUEST_CHANGES",
Summary: "Several issues found.",
Findings: []Finding{
{Severity: "MAJOR", File: "main.go", Line: 42, Finding: "Nil pointer dereference"},
{Severity: "MINOR", File: "util.go", Line: 7, Finding: "Unused variable"},
{Severity: "NIT", File: "doc.go", Line: 1, Finding: "Typo in comment"},
},
Recommendation: "Fix the nil pointer issue before merging.",
}
got := FormatMarkdown(result, "GPT")
if !strings.Contains(got, "## Findings") {
t.Error("expected Findings header")
}
if !strings.Contains(got, "| 1 | [MAJOR] | `main.go` | 42 | Nil pointer dereference |") {
t.Error("expected first finding row")
}
if !strings.Contains(got, "| 2 | [MINOR] | `util.go` | 7 | Unused variable |") {
t.Error("expected second finding row")
}
if !strings.Contains(got, "| 3 | [NIT] | `doc.go` | 1 | Typo in comment |") {
t.Error("expected third finding row")
}
if !strings.Contains(got, "**REQUEST_CHANGES**") {
t.Error("expected verdict in recommendation")
}
}
func TestFormatMarkdown_NoReviewerName(t *testing.T) {
result := &ReviewResult{
Verdict: "APPROVE",
Summary: "Fine.",
Findings: []Finding{},
Recommendation: "Go ahead.",
}
got := FormatMarkdown(result, "")
if strings.Contains(got, "Review by") {
t.Error("should not contain reviewer line when name is empty")
}
}
func TestFormatMarkdown_SpecialChars(t *testing.T) {
result := &ReviewResult{
Verdict: "REQUEST_CHANGES",
Summary: "Issues with `fmt.Sprintf` usage.",
Findings: []Finding{
{Severity: "MAJOR", File: "render.go", Line: 15, Finding: "Use `%v` instead of `%s` for interface{}"},
},
Recommendation: "Fix the format verb.",
}
got := FormatMarkdown(result, "Test")
// Should contain the backtick content without breaking the table
if !strings.Contains(got, "`render.go`") {
t.Error("expected file in backticks")
}
if !strings.Contains(got, "Use `%v` instead of `%s` for interface{}") {
t.Error("expected finding text with backticks preserved")
}
}
func TestGiteaEvent(t *testing.T) {
tests := []struct {
verdict string
expected string
}{
{"APPROVE", "APPROVED"},
{"REQUEST_CHANGES", "REQUEST_CHANGES"},
{"UNKNOWN", "COMMENT"},
{"", "COMMENT"},
}
for _, tc := range tests {
got := GiteaEvent(tc.verdict)
if got != tc.expected {
t.Errorf("GiteaEvent(%q) = %q, want %q", tc.verdict, got, tc.expected)
}
}
}
func TestFormatMarkdown_Sentinel(t *testing.T) {
result := &ReviewResult{
Verdict: "APPROVE",
Summary: "All good.",
Recommendation: "Merge it.",
}
output := FormatMarkdown(result, "security")
if !strings.Contains(output, "<!-- review-bot:security -->") {
t.Error("expected sentinel comment in output")
}
// Empty reviewer name should NOT have sentinel
output2 := FormatMarkdown(result, "")
if strings.Contains(output2, "<!-- review-bot") {
t.Error("should not contain sentinel when reviewer name is empty")
}
}
func TestFormatMarkdown_RoleTitle(t *testing.T) {
result := &ReviewResult{
Verdict: "APPROVE",
Summary: "All good.",
Recommendation: "Merge it.",
}
// With reviewer name: should have title header
output := FormatMarkdown(result, "security")
if !strings.Contains(output, "# Security Review\n") {
t.Error("expected '# Security Review' header when reviewer name is set")
}
output2 := FormatMarkdown(result, "gpt")
if !strings.Contains(output2, "# Gpt Review\n") {
t.Error("expected '# Gpt Review' header")
}
// Without reviewer name: no title header
output3 := FormatMarkdown(result, "")
if strings.Contains(output3, "# ") && strings.Contains(output3, " Review\n") {
t.Error("should not contain role title header when reviewer name is empty")
}
}