test: meaningful escape check, single-slice donut, utcOffsetLabel

- I4 — TestRenderAll now seeds Name/Company with XML-significant chars
  that actually hit the render pipeline via cardTitle(). Previous test
  checked Bio which is no longer rendered, so the assertion was vacuous.
- New TestDonutSingleSlice guards against the I1 empty-arc regression:
  asserts the single-slice path emits <circle> primitives and not the
  degenerate A-command path.
- New TestDonutEmpty covers the zero-stats fallback.
- New TestUTCOffsetLabel pins the UTC±N.NN format across UTC,
  Asia/Saigon, Asia/Kolkata (half-hour), Asia/Kathmandu (quarter-hour).
  Catches %+.2f regressions.
This commit is contained in:
tiennm99 committed 2026-04-18 22:44:25 +07:00
1 parent 27c8014270
commit 992846855d
2 files changed
+70 -5

No files matched your search

+39 -5
View File
@@ -11,10 +11,13 @@ import (
)
func TestRenderAll(t *testing.T) {
// Name is rendered in every card's title via cardTitle(). Putting
// XML-significant chars here exercises escapeXML through the real
// rendering pipeline, not just through the unit test below.
p := &github.Profile{
Login: "tiennm99",
Name: "Minh Tien",
Bio: "Test & <bio>",
Name: `Alice & <bob> "quoted"`,
Company: "VNG & <Corp>",
Followers: 12,
Following: 7,
PublicRepos: 42,
@@ -57,15 +60,46 @@ func TestRenderAll(t *testing.T) {
if err != nil {
t.Fatalf("read %s: %v", name, err)
}
if !strings.HasPrefix(string(data), "<svg") {
content := string(data)
if !strings.HasPrefix(content, "<svg") {
t.Errorf("%s: missing <svg prefix", name)
}
if strings.Contains(string(data), "Test & <bio>") {
t.Errorf("%s: raw XML special characters leaked through escape", name)
// The raw Name string contains `&`, `<`, `>`, `"`. None should
// appear unescaped in the final markup. Presence of the escaped
// forms also verifies the title actually got rendered.
for _, leak := range []string{`Alice & <bob>`, `VNG & <Corp>`, `"quoted"`} {
if strings.Contains(content, leak) {
t.Errorf("%s: raw XML special characters leaked through escape (%q)", name, leak)
}
}
}
}
// TestDonutSingleSlice verifies the donut renderer handles a single-slice
// case (100%) with visible geometry. Regression guard against the empty-arc
// bug where start == end degenerates the SVG A command.
func TestDonutSingleSlice(t *testing.T) {
th, _ := theme.Lookup("dracula")
stats := []github.LangStat{{Name: "Go", Color: "#00ADD8", Value: 100}}
svg := string(renderDonutCard("Test", stats, th))
if !strings.Contains(svg, "<circle") {
t.Errorf("single-slice donut should use <circle> primitives; got:\n%s", svg)
}
if strings.Contains(svg, `A70.00,70.00 0 1 1 380.00,50.00`) {
t.Error("single-slice donut still emits degenerate arc")
}
}
// TestDonutEmpty verifies the zero-stats fallback path.
func TestDonutEmpty(t *testing.T) {
th, _ := theme.Lookup("dracula")
svg := string(renderDonutCard("Test", nil, th))
if !strings.Contains(svg, "No data available") {
t.Errorf("empty donut should render the no-data fallback; got:\n%s", svg)
}
}
func TestFormatInt(t *testing.T) {
cases := map[int]string{
0: "0",
+31
View File
@@ -0,0 +1,31 @@
package main
import (
"strings"
"testing"
"time"
)
// TestUTCOffsetLabel checks that half-hour and quarter-hour zones render
// with a decimal, matching github-profile-summary-cards' "UTC+X.NN" style.
func TestUTCOffsetLabel(t *testing.T) {
cases := []struct {
zone string
want string // must appear in the label; exact value varies by DST
}{
{"UTC", "UTC+0.00"},
{"Asia/Saigon", "UTC+7.00"},
{"Asia/Kolkata", "UTC+5.50"}, // half-hour zone
{"Asia/Kathmandu", "UTC+5.75"}, // quarter-hour zone
}
for _, tc := range cases {
loc, err := time.LoadLocation(tc.zone)
if err != nil {
t.Skipf("%s unavailable: %v", tc.zone, err)
}
got := utcOffsetLabel(loc)
if !strings.Contains(got, tc.want) {
t.Errorf("utcOffsetLabel(%q) = %q, want prefix %q", tc.zone, got, tc.want)
}
}
}