715 lines
20 KiB
Go
715 lines
20 KiB
Go
package workflow
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestWriteTriageTable(t *testing.T) {
|
|
report := TriageReport{
|
|
Repository: "owner/repo",
|
|
Results: []TriageResult{
|
|
{
|
|
Issue: IssueRef{Number: 7, Title: "bug"},
|
|
DetectedType: IssueTypeBug,
|
|
Priority: PriorityP1,
|
|
Confidence: 85,
|
|
RecommendedAction: ActionScheduleFix,
|
|
MissingInformation: []string{"steps to reproduce"},
|
|
},
|
|
},
|
|
}
|
|
var buf bytes.Buffer
|
|
if err := writeTriageTable(&buf, report); err != nil {
|
|
t.Fatalf("writeTriageTable error: %v", err)
|
|
}
|
|
out := buf.String()
|
|
if !strings.Contains(out, "NUMBER") {
|
|
t.Fatalf("missing header: %s", out)
|
|
}
|
|
if !strings.Contains(out, "7") {
|
|
t.Fatalf("missing issue number: %s", out)
|
|
}
|
|
if !strings.Contains(out, "steps to reproduce") {
|
|
t.Fatalf("missing missing info: %s", out)
|
|
}
|
|
}
|
|
|
|
func TestWriteTriageTableNoMissing(t *testing.T) {
|
|
report := TriageReport{
|
|
Repository: "owner/repo",
|
|
Results: []TriageResult{
|
|
{
|
|
Issue: IssueRef{Number: 1, Title: "feat"},
|
|
DetectedType: IssueTypeFeature,
|
|
Priority: PriorityP2,
|
|
Confidence: 60,
|
|
RecommendedAction: ActionScheduleFix,
|
|
MissingInformation: nil,
|
|
},
|
|
},
|
|
}
|
|
var buf bytes.Buffer
|
|
if err := writeTriageTable(&buf, report); err != nil {
|
|
t.Fatalf("writeTriageTable error: %v", err)
|
|
}
|
|
if !strings.Contains(buf.String(), "-") {
|
|
t.Fatalf("expected - for no missing info: %s", buf.String())
|
|
}
|
|
}
|
|
|
|
func TestWriteTriageMarkdown(t *testing.T) {
|
|
report := TriageReport{
|
|
Repository: "owner/repo",
|
|
Results: []TriageResult{
|
|
{
|
|
Issue: IssueRef{Number: 7, Title: "security bug"},
|
|
DetectedType: IssueTypeSecurity,
|
|
Priority: PriorityP0,
|
|
Confidence: 95,
|
|
RecommendedAction: ActionReviewSecurity,
|
|
MissingInformation: []string{"impact"},
|
|
},
|
|
},
|
|
}
|
|
var buf bytes.Buffer
|
|
if err := writeTriageMarkdown(&buf, report); err != nil {
|
|
t.Fatalf("writeTriageMarkdown error: %v", err)
|
|
}
|
|
out := buf.String()
|
|
if !strings.Contains(out, "owner/repo") {
|
|
t.Fatalf("missing repo: %s", out)
|
|
}
|
|
if !strings.Contains(out, "#7") {
|
|
t.Fatalf("missing issue ref: %s", out)
|
|
}
|
|
if !strings.Contains(out, "security") {
|
|
t.Fatalf("missing type: %s", out)
|
|
}
|
|
}
|
|
|
|
func TestWriteTriageMarkdownEmpty(t *testing.T) {
|
|
report := TriageReport{Repository: "owner/repo"}
|
|
var buf bytes.Buffer
|
|
if err := writeTriageMarkdown(&buf, report); err != nil {
|
|
t.Fatalf("writeTriageMarkdown error: %v", err)
|
|
}
|
|
if !strings.Contains(buf.String(), "owner/repo") {
|
|
t.Fatalf("missing repo in empty report: %s", buf.String())
|
|
}
|
|
}
|
|
|
|
func TestWriteHealthTable(t *testing.T) {
|
|
result := HealthResult{
|
|
Repository: "owner/repo",
|
|
HealthScore: 85,
|
|
RiskLevel: "low",
|
|
Metrics: []HealthMetric{
|
|
{Name: "issues", Status: "good", Score: 20, MaxScore: 20, Reason: "few open issues"},
|
|
{Name: "activity", Status: "warning", Score: 10, MaxScore: 20, Reason: "last activity 7 days ago"},
|
|
},
|
|
}
|
|
var buf bytes.Buffer
|
|
if err := writeHealthTable(&buf, result); err != nil {
|
|
t.Fatalf("writeHealthTable error: %v", err)
|
|
}
|
|
out := buf.String()
|
|
if !strings.Contains(out, "owner/repo") {
|
|
t.Fatalf("missing repo: %s", out)
|
|
}
|
|
if !strings.Contains(out, "85") {
|
|
t.Fatalf("missing score: %s", out)
|
|
}
|
|
if !strings.Contains(out, "issues") {
|
|
t.Fatalf("missing metric: %s", out)
|
|
}
|
|
if !strings.Contains(out, "few open issues") {
|
|
t.Fatalf("missing reason: %s", out)
|
|
}
|
|
}
|
|
|
|
func TestRenderTriageReportTable(t *testing.T) {
|
|
report := TriageReport{
|
|
Repository: "owner/repo",
|
|
Results: []TriageResult{
|
|
{
|
|
Issue: IssueRef{Number: 1, Title: "test"},
|
|
DetectedType: IssueTypeBug,
|
|
Priority: PriorityP1,
|
|
Confidence: 80,
|
|
RecommendedAction: ActionScheduleFix,
|
|
},
|
|
},
|
|
}
|
|
var buf bytes.Buffer
|
|
if err := renderTriageReport(&buf, report, "table"); err != nil {
|
|
t.Fatalf("renderTriageReport table error: %v", err)
|
|
}
|
|
if !strings.Contains(buf.String(), "NUMBER") {
|
|
t.Fatalf("missing table header: %s", buf.String())
|
|
}
|
|
}
|
|
|
|
func TestRenderTriageReportMarkdown(t *testing.T) {
|
|
report := TriageReport{
|
|
Repository: "owner/repo",
|
|
Results: []TriageResult{},
|
|
}
|
|
var buf bytes.Buffer
|
|
if err := renderTriageReport(&buf, report, "markdown"); err != nil {
|
|
t.Fatalf("renderTriageReport markdown error: %v", err)
|
|
}
|
|
if !strings.Contains(buf.String(), "owner/repo") {
|
|
t.Fatalf("missing repo: %s", buf.String())
|
|
}
|
|
}
|
|
|
|
func TestRenderTriageReportJSON(t *testing.T) {
|
|
report := TriageReport{
|
|
Repository: "owner/repo",
|
|
Results: []TriageResult{},
|
|
}
|
|
var buf bytes.Buffer
|
|
if err := renderTriageReport(&buf, report, "json"); err != nil {
|
|
t.Fatalf("renderTriageReport json error: %v", err)
|
|
}
|
|
var parsed TriageReport
|
|
if err := json.Unmarshal(buf.Bytes(), &parsed); err != nil {
|
|
t.Fatalf("unmarshal error: %v", err)
|
|
}
|
|
if parsed.Repository != "owner/repo" {
|
|
t.Fatalf("Repository = %q", parsed.Repository)
|
|
}
|
|
}
|
|
|
|
func TestRenderTriageReportBadFormat(t *testing.T) {
|
|
report := TriageReport{Repository: "owner/repo"}
|
|
var buf bytes.Buffer
|
|
err := renderTriageReport(&buf, report, "xml")
|
|
if err == nil {
|
|
t.Fatal("expected error for bad format")
|
|
}
|
|
}
|
|
|
|
func TestRenderHealthResultTable(t *testing.T) {
|
|
result := ScoreHealth(HealthInput{
|
|
Repository: "owner/repo",
|
|
RecentActivityKnown: true,
|
|
RecentActivityDays: 3,
|
|
ReleaseKnown: true,
|
|
HasRecentRelease: true,
|
|
HasReadme: true,
|
|
HasLicense: true,
|
|
HasContributing: true,
|
|
AgentReadinessKnown: true,
|
|
AgentReadinessScore: 9,
|
|
}, "en")
|
|
|
|
var buf bytes.Buffer
|
|
if err := renderHealthResult(&buf, result, "table"); err != nil {
|
|
t.Fatalf("renderHealthResult table error: %v", err)
|
|
}
|
|
if !strings.Contains(buf.String(), "REPOSITORY") {
|
|
t.Fatalf("missing table header: %s", buf.String())
|
|
}
|
|
}
|
|
|
|
func TestRenderHealthResultBadFormat(t *testing.T) {
|
|
var buf bytes.Buffer
|
|
err := renderHealthResult(&buf, HealthResult{}, "xml")
|
|
if err == nil {
|
|
t.Fatal("expected error for bad format")
|
|
}
|
|
}
|
|
|
|
func TestNormalizeFormat(t *testing.T) {
|
|
tests := []struct {
|
|
input, want string
|
|
}{
|
|
{"", "json"},
|
|
{" ", "json"},
|
|
{"JSON", "json"},
|
|
{"yaml", "yaml"},
|
|
{" TABLE ", "table"},
|
|
}
|
|
for _, tt := range tests {
|
|
got := normalizeFormat(tt.input)
|
|
if got != tt.want {
|
|
t.Errorf("normalizeFormat(%q) = %q, want %q", tt.input, got, tt.want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestTruncateTableText(t *testing.T) {
|
|
tests := []struct {
|
|
value string
|
|
max int
|
|
want string
|
|
}{
|
|
{"", 10, ""},
|
|
{"short", 10, "short"},
|
|
{"hello world", 5, "he..."},
|
|
{"hello world", 3, "hel"},
|
|
{"hello world", 0, "hello world"},
|
|
{"hello world", -1, "hello world"},
|
|
{"hello world", 20, "hello world"},
|
|
{"a very long string that needs truncation", 15, "a very long ..."},
|
|
}
|
|
for _, tt := range tests {
|
|
got := truncateTableText(tt.value, tt.max)
|
|
if got != tt.want {
|
|
t.Errorf("truncateTableText(%q, %d) = %q, want %q", tt.value, tt.max, got, tt.want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestWriteHealthMarkdownWithRecommendations(t *testing.T) {
|
|
result := HealthResult{
|
|
Repository: "owner/repo",
|
|
HealthScore: 90,
|
|
RiskLevel: "low",
|
|
Metrics: []HealthMetric{
|
|
{Name: "issues", Status: "good", Score: 20, MaxScore: 20, Reason: "few issues"},
|
|
},
|
|
Recommendations: []string{"Fix bugs", "Add docs"},
|
|
}
|
|
var buf bytes.Buffer
|
|
if err := writeHealthMarkdown(&buf, result); err != nil {
|
|
t.Fatalf("writeHealthMarkdown error: %v", err)
|
|
}
|
|
out := buf.String()
|
|
if !strings.Contains(out, "Recommendations") {
|
|
t.Fatalf("missing recommendations: %s", out)
|
|
}
|
|
if !strings.Contains(out, "Fix bugs") {
|
|
t.Fatalf("missing first recommendation: %s", out)
|
|
}
|
|
}
|
|
|
|
func TestWriteRepoReportMarkdownNoHealth(t *testing.T) {
|
|
result := RepoReportResult{
|
|
Repository: "owner/repo",
|
|
Source: "local-json",
|
|
}
|
|
var buf bytes.Buffer
|
|
if err := writeRepoReportMarkdown(&buf, result, "en"); err != nil {
|
|
t.Fatalf("writeRepoReportMarkdown error: %v", err)
|
|
}
|
|
out := buf.String()
|
|
if !strings.Contains(out, "owner/repo") {
|
|
t.Fatalf("missing repository: %s", out)
|
|
}
|
|
}
|
|
|
|
func TestWriteRepoReportTableNoHealth(t *testing.T) {
|
|
result := RepoReportResult{
|
|
Repository: "owner/repo",
|
|
ReportScore: 50,
|
|
RiskLevel: "medium",
|
|
IssueSummary: RepoIssueSummary{
|
|
Total: 3,
|
|
HighRisk: 1,
|
|
},
|
|
PRSummary: RepoPRSummary{
|
|
Total: 2,
|
|
HighRisk: 0,
|
|
},
|
|
Source: "local-json",
|
|
}
|
|
var buf bytes.Buffer
|
|
if err := writeRepoReportTable(&buf, result, "en"); err != nil {
|
|
t.Fatalf("writeRepoReportTable error: %v", err)
|
|
}
|
|
if !strings.Contains(buf.String(), "owner/repo") {
|
|
t.Fatalf("missing repository: %s", buf.String())
|
|
}
|
|
}
|
|
|
|
func TestWriteRepoReportTableWithTopRecommendation(t *testing.T) {
|
|
result := RepoReportResult{
|
|
Repository: "owner/repo",
|
|
ReportScore: 80,
|
|
RiskLevel: "low",
|
|
Health: &HealthResult{HealthScore: 90, RiskLevel: "low", Metrics: nil},
|
|
IssueSummary: RepoIssueSummary{
|
|
Total: 5,
|
|
HighRisk: 2,
|
|
ByType: map[string]int{"bug": 3},
|
|
ByPriority: map[string]int{"P0": 1, "P1": 2},
|
|
},
|
|
PRSummary: RepoPRSummary{
|
|
Total: 3,
|
|
HighRisk: 1,
|
|
},
|
|
Recommendations: []string{"Address security issues immediately"},
|
|
Source: "local-json",
|
|
}
|
|
var buf bytes.Buffer
|
|
if err := writeRepoReportTable(&buf, result, "en"); err != nil {
|
|
t.Fatalf("writeRepoReportTable error: %v", err)
|
|
}
|
|
if !strings.Contains(buf.String(), "Address") {
|
|
t.Fatalf("missing recommendation: %s", buf.String())
|
|
}
|
|
}
|
|
|
|
func TestWriteCountMapMarkdownEmpty(t *testing.T) {
|
|
var buf bytes.Buffer
|
|
if err := writeCountMapMarkdown(&buf, "Test", nil); err != nil {
|
|
t.Fatalf("writeCountMapMarkdown error: %v", err)
|
|
}
|
|
if buf.Len() != 0 {
|
|
t.Fatalf("expected empty output for nil map, got: %s", buf.String())
|
|
}
|
|
}
|
|
|
|
func TestWriteRepoReportMarkdownListEmpty(t *testing.T) {
|
|
var buf bytes.Buffer
|
|
if err := writeRepoReportMarkdownList(&buf, "Empty", nil, "none"); err != nil {
|
|
t.Fatalf("writeRepoReportMarkdownList error: %v", err)
|
|
}
|
|
if !strings.Contains(buf.String(), "none") {
|
|
t.Fatalf("missing fallback: %s", buf.String())
|
|
}
|
|
}
|
|
|
|
func TestWritePRSummaryMarkdownListEmpty(t *testing.T) {
|
|
var buf bytes.Buffer
|
|
if err := writePRSummaryMarkdownList(&buf, "Empty", nil, "fallback text"); err != nil {
|
|
t.Fatalf("writePRSummaryMarkdownList error: %v", err)
|
|
}
|
|
if !strings.Contains(buf.String(), "fallback text") {
|
|
t.Fatalf("missing fallback: %s", buf.String())
|
|
}
|
|
}
|
|
|
|
func TestWriteRepoReportMarkdownChinese(t *testing.T) {
|
|
result := AnalyzeRepoReport(sampleRepoReportInput(), "zh-CN")
|
|
var buf bytes.Buffer
|
|
if err := writeRepoReportMarkdown(&buf, result, "zh-CN"); err != nil {
|
|
t.Fatalf("writeRepoReportMarkdown zh-CN error: %v", err)
|
|
}
|
|
out := buf.String()
|
|
if !strings.Contains(out, "仓库工作流报告") {
|
|
t.Fatalf("missing Chinese title: %s", out)
|
|
}
|
|
}
|
|
|
|
func TestWritePRSummaryMarkdownChinese(t *testing.T) {
|
|
result := samplePRSummaryResult()
|
|
var buf bytes.Buffer
|
|
if err := writePRSummaryMarkdown(&buf, result, "zh-CN"); err != nil {
|
|
t.Fatalf("writePRSummaryMarkdown zh-CN error: %v", err)
|
|
}
|
|
out := buf.String()
|
|
if !strings.Contains(out, "PR 审阅摘要") {
|
|
t.Fatalf("missing Chinese title: %s", out)
|
|
}
|
|
}
|
|
|
|
func TestWritePRSummaryTableChinese(t *testing.T) {
|
|
result := samplePRSummaryResult()
|
|
var buf bytes.Buffer
|
|
// table format ignores language
|
|
if err := writePRSummaryTable(&buf, result); err != nil {
|
|
t.Fatalf("writePRSummaryTable error: %v", err)
|
|
}
|
|
if !strings.Contains(buf.String(), "#42") {
|
|
t.Fatalf("missing PR number: %s", buf.String())
|
|
}
|
|
}
|
|
|
|
func TestWriteTriageMarkdownMultipleIssues(t *testing.T) {
|
|
report := TriageReport{
|
|
Repository: "owner/repo",
|
|
Results: []TriageResult{
|
|
{
|
|
Issue: IssueRef{Number: 1, Title: "bug"},
|
|
DetectedType: IssueTypeBug,
|
|
Priority: PriorityP1,
|
|
Confidence: 80,
|
|
RecommendedAction: ActionScheduleFix,
|
|
MissingInformation: []string{"steps", "version"},
|
|
},
|
|
{
|
|
Issue: IssueRef{Number: 2, Title: "feat"},
|
|
DetectedType: IssueTypeFeature,
|
|
Priority: PriorityP2,
|
|
Confidence: 60,
|
|
RecommendedAction: ActionScheduleFix,
|
|
},
|
|
},
|
|
}
|
|
var buf bytes.Buffer
|
|
if err := writeTriageMarkdown(&buf, report); err != nil {
|
|
t.Fatalf("writeTriageMarkdown error: %v", err)
|
|
}
|
|
out := buf.String()
|
|
if !strings.Contains(out, "#1") || !strings.Contains(out, "#2") {
|
|
t.Fatalf("missing issue refs: %s", out)
|
|
}
|
|
if !strings.Contains(out, "steps, version") {
|
|
t.Fatalf("missing multiple missing info: %s", out)
|
|
}
|
|
}
|
|
|
|
func TestWriteRepoReportMarkdownFull(t *testing.T) {
|
|
result := AnalyzeRepoReport(sampleRepoReportInput(), "en")
|
|
var buf bytes.Buffer
|
|
if err := writeRepoReportMarkdown(&buf, result, "en"); err != nil {
|
|
t.Fatalf("writeRepoReportMarkdown error: %v", err)
|
|
}
|
|
out := buf.String()
|
|
for _, want := range []string{"Repository Workflow Report", "Overview", "Health Summary", "Issue Triage Summary", "PR Review Summary", "Recommendations", "Reasoning"} {
|
|
if !strings.Contains(out, want) {
|
|
t.Fatalf("missing section %q: %s", want, out)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestWriteRepoReportMarkdownNoPRReviewFocus(t *testing.T) {
|
|
result := AnalyzeRepoReport(sampleRepoReportInput(), "en")
|
|
result.PRSummary.ReviewFocus = nil
|
|
var buf bytes.Buffer
|
|
if err := writeRepoReportMarkdown(&buf, result, "en"); err != nil {
|
|
t.Fatalf("writeRepoReportMarkdown error: %v", err)
|
|
}
|
|
if !strings.Contains(buf.String(), "owner/repo") {
|
|
t.Fatalf("missing repo: %s", buf.String())
|
|
}
|
|
}
|
|
|
|
func TestWriteJSON(t *testing.T) {
|
|
var buf bytes.Buffer
|
|
if err := writeJSON(&buf, map[string]string{"key": "val"}); err != nil {
|
|
t.Fatalf("writeJSON error: %v", err)
|
|
}
|
|
if !strings.Contains(buf.String(), `"key"`) {
|
|
t.Fatalf("missing key: %s", buf.String())
|
|
}
|
|
}
|
|
|
|
func TestRenderPRSummaryJSON(t *testing.T) {
|
|
rendered, err := RenderPRSummary(samplePRSummaryResult(), "json", "en")
|
|
if err != nil {
|
|
t.Fatalf("RenderPRSummary returned error: %v", err)
|
|
}
|
|
var result PRSummaryResult
|
|
if err := json.Unmarshal([]byte(rendered), &result); err != nil {
|
|
t.Fatalf("json.Unmarshal returned error: %v\noutput=%s", err, rendered)
|
|
}
|
|
if result.Number != 42 {
|
|
t.Fatalf("Number = %d, want 42", result.Number)
|
|
}
|
|
}
|
|
|
|
func TestRenderPRSummaryMarkdown(t *testing.T) {
|
|
result := samplePRSummaryResult()
|
|
rendered, err := RenderPRSummary(result, "markdown", "en")
|
|
if err != nil {
|
|
t.Fatalf("RenderPRSummary returned error: %v", err)
|
|
}
|
|
for _, want := range []string{result.Title, "Risk level", "Review Focus"} {
|
|
if !strings.Contains(rendered, want) {
|
|
t.Fatalf("markdown output missing %q:\n%s", want, rendered)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestRenderPRSummaryTable(t *testing.T) {
|
|
rendered, err := RenderPRSummary(samplePRSummaryResult(), "table", "en")
|
|
if err != nil {
|
|
t.Fatalf("RenderPRSummary returned error: %v", err)
|
|
}
|
|
if !strings.Contains(rendered, "#42") || !strings.Contains(rendered, "medium") {
|
|
t.Fatalf("table output = %q, want PR number and risk", rendered)
|
|
}
|
|
}
|
|
|
|
func TestRenderPRSummaryUnknownFormat(t *testing.T) {
|
|
_, err := RenderPRSummary(samplePRSummaryResult(), "xml", "en")
|
|
if err == nil {
|
|
t.Fatal("RenderPRSummary returned nil error for unknown format")
|
|
}
|
|
}
|
|
|
|
func TestRenderPRSummaryChineseMarkdown(t *testing.T) {
|
|
rendered, err := RenderPRSummary(samplePRSummaryResult(), "markdown", "zh-CN")
|
|
if err != nil {
|
|
t.Fatalf("RenderPRSummary returned error: %v", err)
|
|
}
|
|
if !strings.Contains(rendered, "PR 审阅摘要") {
|
|
t.Fatalf("zh-CN markdown output missing Chinese title:\n%s", rendered)
|
|
}
|
|
}
|
|
|
|
func TestRenderPRSummaryChineseTable(t *testing.T) {
|
|
rendered, err := RenderPRSummary(samplePRSummaryResult(), "table", "zh-CN")
|
|
if err != nil {
|
|
t.Fatalf("RenderPRSummary error: %v", err)
|
|
}
|
|
if !strings.Contains(rendered, "#42") {
|
|
t.Fatalf("table output missing PR number: %s", rendered)
|
|
}
|
|
}
|
|
|
|
func TestRenderPRSummaryEmptyReviewFocus(t *testing.T) {
|
|
result := samplePRSummaryResult()
|
|
result.ReviewFocus = nil
|
|
result.TestSuggestions = nil
|
|
result.MergeChecklist = nil
|
|
result.Reasoning = nil
|
|
rendered, err := RenderPRSummary(result, "markdown", "en")
|
|
if err != nil {
|
|
t.Fatalf("RenderPRSummary error: %v", err)
|
|
}
|
|
if !strings.Contains(rendered, "no focus areas") && !strings.Contains(rendered, "No review") {
|
|
// Falls back to fallback text - should not be empty
|
|
if !strings.Contains(rendered, result.Title) {
|
|
t.Fatalf("markdown output missing title: %s", rendered)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestRenderHealthResultChineseMarkdown(t *testing.T) {
|
|
result := ScoreHealth(HealthInput{
|
|
Repository: "owner/repo",
|
|
RecentActivityKnown: true,
|
|
RecentActivityDays: 3,
|
|
HasReadme: true,
|
|
}, "zh-CN")
|
|
|
|
var buf bytes.Buffer
|
|
if err := renderHealthResult(&buf, result, "markdown"); err != nil {
|
|
t.Fatalf("renderHealthResult error: %v", err)
|
|
}
|
|
if !strings.Contains(buf.String(), "Issue 积压处于可控状态") {
|
|
t.Fatalf("missing Chinese metric text: %s", buf.String())
|
|
}
|
|
}
|
|
|
|
func TestRenderHealthResultJSON(t *testing.T) {
|
|
result := ScoreHealth(HealthInput{
|
|
Repository: "owner/repo",
|
|
RecentActivityKnown: true,
|
|
RecentActivityDays: 2,
|
|
}, "en")
|
|
|
|
var buf bytes.Buffer
|
|
if err := renderHealthResult(&buf, result, "json"); err != nil {
|
|
t.Fatalf("renderHealthResult error: %v", err)
|
|
}
|
|
var parsed HealthResult
|
|
if err := json.Unmarshal(buf.Bytes(), &parsed); err != nil {
|
|
t.Fatalf("unmarshal error: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestRenderStaleReportMarkdown(t *testing.T) {
|
|
report := StaleReport{
|
|
Repository: "owner/repo",
|
|
Source: "local-json",
|
|
State: "open",
|
|
StaleDays: 30,
|
|
ScannedTotal: 3,
|
|
FlaggedTotal: 1,
|
|
ShownTotal: 1,
|
|
ByBucket: map[string]int{
|
|
staleBucketFresh: 2,
|
|
staleBucketWatch: 1,
|
|
staleBucketStale: 0,
|
|
staleBucketZombie: 0,
|
|
},
|
|
Items: []StaleItem{{
|
|
Kind: staleKindIssue,
|
|
Number: 3,
|
|
Title: "stale issue",
|
|
Bucket: staleBucketWatch,
|
|
AgeDays: 45,
|
|
LastActivityAt: time.Date(2026, 5, 1, 0, 0, 0, 0, time.UTC),
|
|
SuggestedAction: "Follow up",
|
|
}},
|
|
Recommendations: []string{"Follow up"},
|
|
}
|
|
|
|
var buf bytes.Buffer
|
|
if err := renderStaleReport(&buf, report, "markdown", "en"); err != nil {
|
|
t.Fatalf("renderStaleReport markdown error: %v", err)
|
|
}
|
|
out := buf.String()
|
|
if !strings.Contains(out, "Stale Queue Report") || !strings.Contains(out, "#3") {
|
|
t.Fatalf("unexpected markdown output: %s", out)
|
|
}
|
|
}
|
|
|
|
func TestRenderStaleReportTable(t *testing.T) {
|
|
report := StaleReport{
|
|
Items: []StaleItem{{
|
|
Kind: staleKindPR,
|
|
Number: 9,
|
|
Title: "old pr",
|
|
Bucket: staleBucketZombie,
|
|
AgeDays: 120,
|
|
LastActivityAt: time.Date(2026, 3, 1, 0, 0, 0, 0, time.UTC),
|
|
SuggestedAction: "Close or refresh",
|
|
}},
|
|
}
|
|
|
|
var buf bytes.Buffer
|
|
if err := renderStaleReport(&buf, report, "table", "en"); err != nil {
|
|
t.Fatalf("renderStaleReport table error: %v", err)
|
|
}
|
|
if !strings.Contains(buf.String(), "TYPE") || !strings.Contains(buf.String(), "#9") {
|
|
t.Fatalf("unexpected table output: %s", buf.String())
|
|
}
|
|
}
|
|
|
|
func TestRenderStaleReportJSON(t *testing.T) {
|
|
report := StaleReport{
|
|
Repository: "owner/repo",
|
|
Items: []StaleItem{{
|
|
Kind: staleKindIssue,
|
|
Number: 1,
|
|
Title: "issue",
|
|
}},
|
|
}
|
|
|
|
var buf bytes.Buffer
|
|
if err := renderStaleReport(&buf, report, "json", "en"); err != nil {
|
|
t.Fatalf("renderStaleReport json error: %v", err)
|
|
}
|
|
var parsed StaleReport
|
|
if err := json.Unmarshal(buf.Bytes(), &parsed); err != nil {
|
|
t.Fatalf("json.Unmarshal error: %v", err)
|
|
}
|
|
if parsed.Repository != "owner/repo" || len(parsed.Items) != 1 {
|
|
t.Fatalf("parsed = %+v", parsed)
|
|
}
|
|
}
|
|
|
|
func samplePRSummaryResult() PRSummaryResult {
|
|
return PRSummaryResult{
|
|
Repository: "owner/repo",
|
|
Number: 42,
|
|
Title: "feat: add workflow PR summary",
|
|
Author: "alice",
|
|
State: "open",
|
|
BaseBranch: "master",
|
|
HeadBranch: "feature/pr-summary",
|
|
ChangedFilesCount: 2,
|
|
Additions: 100,
|
|
Deletions: 4,
|
|
CommitCount: 2,
|
|
ChangeType: PRChangeTypeFeature,
|
|
RiskLevel: PRRiskMedium,
|
|
ReviewFocus: []string{"Check shortcut command compatibility and flag behavior."},
|
|
TestSuggestions: []string{"Run `go test ./shortcuts/workflow`."},
|
|
MergeChecklist: []string{"Tests pass."},
|
|
Reasoning: []string{"change type: feature", "risk level: medium"},
|
|
Source: "local-json",
|
|
}
|
|
}
|