mirror of
https://github.com/tiennm99/ghglance.git
synced 2026-10-11 12:18:55 +00:00
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:
1 parent
27c8014270
commit
992846855d
2 files changed
+70
-5
No files matched your search
@@ -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",
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user