svg_test.gno
5.66 Kb · 177 lines
1package svg
2
3import (
4 "strings"
5 "testing"
6
7 "gno.land/p/nt/uassert/v0"
8)
9
10func TestBaseAttrsEmpty(t *testing.T) {
11 uassert.Equal(t, "", BaseAttrs{}.String())
12}
13
14func TestBaseAttrsAllFields(t *testing.T) {
15 b := BaseAttrs{
16 ID: "i",
17 Class: "c",
18 Style: "fill:red",
19 Stroke: "black",
20 StrokeWidth: "2",
21 Opacity: "0.5",
22 Transform: "rotate(90)",
23 Visibility: "hidden",
24 }
25 uassert.Equal(t,
26 `id="i" class="c" style="fill:red" stroke="black" stroke-width="2" opacity="0.5" transform="rotate(90)" visibility="hidden"`,
27 b.String())
28}
29
30func TestBaseAttrsSkipsEmptyFields(t *testing.T) {
31 uassert.Equal(t, `id="i" opacity="0.5"`, BaseAttrs{ID: "i", Opacity: "0.5"}.String())
32}
33
34func TestCircle(t *testing.T) {
35 c := NewCircle(1, 2, 3, "red")
36 uassert.Equal(t, `<circle cx="1" cy="2" r="3" fill="red" />`, c.String())
37
38 uassert.True(t, c.WithClass("dot") == c, "WithClass should be chainable: same pointer back")
39 uassert.Equal(t, `<circle cx="1" cy="2" r="3" fill="red" class="dot"/>`, c.String())
40}
41
42func TestEllipse(t *testing.T) {
43 e := NewEllipse(4, 5, "blue")
44 // NewEllipse takes no radii, so RX/RY stay zero until set directly.
45 uassert.Equal(t, `<ellipse cx="4" cy="5" rx="0" ry="0" fill="blue" />`, e.String())
46
47 e.RX, e.RY = 10, 20
48 e.WithClass("blob")
49 uassert.Equal(t, `<ellipse cx="4" cy="5" rx="10" ry="20" fill="blue" class="blob"/>`, e.String())
50}
51
52func TestRectangle(t *testing.T) {
53 r := NewRectangle(1, 2, 30, 40, "green")
54 uassert.Equal(t, `<rect x="1" y="2" width="30" height="40" rx="0" ry="0" fill="green" />`, r.String())
55
56 r.RX, r.RY = 5, 6
57 r.WithClass("box")
58 uassert.Equal(t, `<rect x="1" y="2" width="30" height="40" rx="5" ry="6" fill="green" class="box"/>`, r.String())
59}
60
61func TestPath(t *testing.T) {
62 p := NewPath("M0 0 L10 10", "none")
63 uassert.Equal(t, `<path d="M0 0 L10 10" fill="none" />`, p.String())
64
65 p.WithClass("stroke")
66 uassert.Equal(t, `<path d="M0 0 L10 10" fill="none" class="stroke"/>`, p.String())
67}
68
69func TestPolygon(t *testing.T) {
70 p := NewPolygon("0,0 10,0 5,8", "yellow")
71 uassert.Equal(t, `<polygon points="0,0 10,0 5,8" fill="yellow" />`, p.String())
72
73 p.WithClass("tri")
74 uassert.Equal(t, `<polygon points="0,0 10,0 5,8" fill="yellow" class="tri"/>`, p.String())
75}
76
77func TestPolyline(t *testing.T) {
78 p := NewPolyline("0,0 10,10", "none")
79 uassert.Equal(t, `<polyline points="0,0 10,10" fill="none" />`, p.String())
80
81 p.WithClass("line")
82 uassert.Equal(t, `<polyline points="0,0 10,10" fill="none" class="line"/>`, p.String())
83}
84
85func TestText(t *testing.T) {
86 tx := NewText(7, 8, "hello", "black")
87 uassert.Equal(t, `<text x="7" y="8" dx="0" dy="0" rotate="" fill="black" >hello</text>`, tx.String())
88
89 tx.DX, tx.DY, tx.Rotate = 1, 2, "45"
90 tx.WithClass("label")
91 uassert.Equal(t, `<text x="7" y="8" dx="1" dy="2" rotate="45" fill="black" class="label">hello</text>`, tx.String())
92}
93
94func TestGroup(t *testing.T) {
95 g := NewGroup("purple")
96 uassert.Equal(t, `<g fill="purple" ></g>`, g.String())
97
98 g.Append(NewCircle(0, 0, 1, "red"), NewPath("M0 0", "none"))
99 g.WithClass("layer")
100 uassert.Equal(t,
101 `<g fill="purple" class="layer"><circle cx="0" cy="0" r="1" fill="red" /><path d="M0 0" fill="none" /></g>`,
102 g.String())
103}
104
105func TestGroupNesting(t *testing.T) {
106 inner := NewGroup("a")
107 inner.Append(NewCircle(1, 1, 1, "red"))
108 outer := NewGroup("b")
109 outer.Append(inner)
110
111 uassert.Equal(t,
112 `<g fill="b" ><g fill="a" ><circle cx="1" cy="1" r="1" fill="red" /></g></g>`,
113 outer.String())
114}
115
116func TestCanvasEmpty(t *testing.T) {
117 c := NewCanvas(100, 50)
118 uassert.Equal(t,
119 `<svg xmlns="http://www.w3.org/2000/svg" width="100" height="50" viewBox=""></svg>`,
120 c.String())
121}
122
123func TestCanvasWithViewBox(t *testing.T) {
124 c := NewCanvas(100, 50)
125 uassert.True(t, c.WithViewBox(0, 0, 200, 100) == c, "WithViewBox should be chainable")
126 uassert.True(t, strings.Contains(c.String(), `viewBox="0 0 200 100"`), "viewBox should be set")
127}
128
129func TestCanvasAppend(t *testing.T) {
130 c := NewCanvas(10, 10)
131 c.Append(NewCircle(1, 1, 1, "red"), NewCircle(2, 2, 2, "blue"))
132
133 out := c.String()
134 uassert.True(t, strings.Contains(out, `<circle cx="1" cy="1" r="1" fill="red" /><circle cx="2" cy="2" r="2" fill="blue" />`),
135 "elements should render in insertion order")
136}
137
138// TestCanvasStyleIsKeyOrdered is the determinism check that matters on-chain:
139// the style block must not depend on insertion order, or two nodes could
140// disagree on the rendered output.
141func TestCanvasStyleIsKeyOrdered(t *testing.T) {
142 a := NewCanvas(10, 10)
143 a.AddStyle("z-last", "fill:blue").AddStyle("a-first", "fill:red")
144
145 b := NewCanvas(10, 10)
146 b.AddStyle("a-first", "fill:red").AddStyle("z-last", "fill:blue")
147
148 uassert.Equal(t, a.String(), b.String())
149 uassert.True(t, strings.Contains(a.String(), `<style>a-first{fill:red}z-last{fill:blue}</style>`),
150 "styles should be emitted in key order")
151}
152
153func TestCanvasNoStyleBlockWhenUnset(t *testing.T) {
154 uassert.False(t, strings.Contains(NewCanvas(1, 1).String(), "<style>"),
155 "a canvas with no styles should not emit an empty <style> block")
156}
157
158func TestCanvasAddStyleChainable(t *testing.T) {
159 c := NewCanvas(1, 1)
160 uassert.True(t, c.AddStyle("a", "b") == c, "AddStyle should be chainable")
161}
162
163func TestCanvasBase64RoundTrip(t *testing.T) {
164 c := NewCanvas(10, 10)
165 c.Append(NewCircle(1, 1, 1, "red"))
166
167 // Base64 must encode exactly what String() produced.
168 uassert.Equal(t, "PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMCIgaGVpZ2h0PSIxMCIgdmlld0JveD0iIj48Y2lyY2xlIGN4PSIxIiBjeT0iMSIgcj0iMSIgZmlsbD0icmVkIiAvPjwvc3ZnPg==",
169 c.Base64())
170}
171
172func TestCanvasRenderWrapsBase64(t *testing.T) {
173 c := NewCanvas(10, 10)
174 c.Append(NewCircle(1, 1, 1, "red"))
175
176 uassert.Equal(t, "+")", c.Render("a picture"))
177}