package showcase import ( "strings" "testing" ) // makeTestSummaries builds a small slice of ProjectSummary with rank history // suitable for unit-testing the SVG generator without touching the filesystem. func makeTestSummaries() []ProjectSummary { return []ProjectSummary{ { Name: "alpha", RankHistory: []RepoRankHistory{ {Spot: 1, Anchor: "now", SnapshotDate: "2026-05-27"}, {Spot: 2, Anchor: "1w", SnapshotDate: "2026-05-20"}, {Spot: 2, Anchor: "2w", SnapshotDate: "2026-05-13"}, {Spot: 3, Anchor: "3w", SnapshotDate: "2026-05-06"}, {Spot: 0, Anchor: "4w"}, // missing snapshot week }, }, { Name: "beta", RankHistory: []RepoRankHistory{ {Spot: 2, Anchor: "now", SnapshotDate: "2026-05-27"}, {Spot: 1, Anchor: "1w", SnapshotDate: "2026-05-20"}, {Spot: 1, Anchor: "2w", SnapshotDate: "2026-05-13"}, {Spot: 0, Anchor: "3w"}, {Spot: 0, Anchor: "4w"}, }, }, { // Project with no rank data at all should be skipped. Name: "ghost", RankHistory: []RepoRankHistory{{Spot: 0}, {Spot: 0}, {Spot: 0}, {Spot: 0}, {Spot: 0}}, }, } } func TestGenerateRankHistorySVG_IsValidSVG(t *testing.T) { t.Parallel() svg := GenerateRankHistorySVG(makeTestSummaries()) if !strings.HasPrefix(svg, "") { t.Fatalf("expected SVG to end with '', got suffix: %.40s", svg[len(svg)-40:]) } } func TestGenerateRankHistorySVG_ContainsProjectNames(t *testing.T) { t.Parallel() svg := GenerateRankHistorySVG(makeTestSummaries()) if !strings.Contains(svg, `"name":"alpha"`) { t.Error("SVG JSON data missing project 'alpha'") } if !strings.Contains(svg, `"name":"beta"`) { t.Error("SVG JSON data missing project 'beta'") } // 'ghost' has no valid data points and must be excluded. if strings.Contains(svg, `"name":"ghost"`) { t.Error("SVG JSON data should not contain 'ghost' (no rank data)") } } func TestGenerateRankHistorySVG_ContainsInteractiveJS(t *testing.T) { t.Parallel() svg := GenerateRankHistorySVG(makeTestSummaries()) // Key JS functions must be present for interactivity. for _, fn := range []string{"onEnter", "onLeave", "moveTT"} { if !strings.Contains(svg, fn) { t.Errorf("SVG JavaScript missing function %q", fn) } } // Tooltip anchor elements must exist. for _, id := range []string{"tt", "ttbg", "tttl", "ttbd"} { if !strings.Contains(svg, `id="`+id+`"`) { t.Errorf("SVG missing element id=%q", id) } } } func TestGenerateRankHistorySVG_EmptySummaries(t *testing.T) { t.Parallel() svg := GenerateRankHistorySVG([]ProjectSummary{}) // Should still produce a valid (empty-data) SVG with the subtitle showing 0 projects. if !strings.Contains(svg, " tc.wantMax { t.Errorf("gridStep(%d) = %d, want ≤ %d", tc.maxRank, got, tc.wantMax) } if got <= 0 { t.Errorf("gridStep(%d) = %d, want > 0", tc.maxRank, got) } } }