package svg
import (
"strings"
"testing"
"gno.land/p/nt/uassert/v0"
)
func TestBaseAttrsEmpty(t *testing.T) {
uassert.Equal(t, "", BaseAttrs{}.String())
}
func TestBaseAttrsAllFields(t *testing.T) {
b := BaseAttrs{
ID: "i",
Class: "c",
Style: "fill:red",
Stroke: "black",
StrokeWidth: "2",
Opacity: "0.5",
Transform: "rotate(90)",
Visibility: "hidden",
}
uassert.Equal(t,
`id="i" class="c" style="fill:red" stroke="black" stroke-width="2" opacity="0.5" transform="rotate(90)" visibility="hidden"`,
b.String())
}
func TestBaseAttrsSkipsEmptyFields(t *testing.T) {
uassert.Equal(t, `id="i" opacity="0.5"`, BaseAttrs{ID: "i", Opacity: "0.5"}.String())
}
func TestCircle(t *testing.T) {
c := NewCircle(1, 2, 3, "red")
uassert.Equal(t, ``, c.String())
uassert.True(t, c.WithClass("dot") == c, "WithClass should be chainable: same pointer back")
uassert.Equal(t, ``, c.String())
}
func TestEllipse(t *testing.T) {
e := NewEllipse(4, 5, "blue")
// NewEllipse takes no radii, so RX/RY stay zero until set directly.
uassert.Equal(t, ``, e.String())
e.RX, e.RY = 10, 20
e.WithClass("blob")
uassert.Equal(t, ``, e.String())
}
func TestRectangle(t *testing.T) {
r := NewRectangle(1, 2, 30, 40, "green")
uassert.Equal(t, ``, r.String())
r.RX, r.RY = 5, 6
r.WithClass("box")
uassert.Equal(t, ``, r.String())
}
func TestPath(t *testing.T) {
p := NewPath("M0 0 L10 10", "none")
uassert.Equal(t, ``, p.String())
p.WithClass("stroke")
uassert.Equal(t, ``, p.String())
}
func TestPolygon(t *testing.T) {
p := NewPolygon("0,0 10,0 5,8", "yellow")
uassert.Equal(t, ``, p.String())
p.WithClass("tri")
uassert.Equal(t, ``, p.String())
}
func TestPolyline(t *testing.T) {
p := NewPolyline("0,0 10,10", "none")
uassert.Equal(t, ``, p.String())
p.WithClass("line")
uassert.Equal(t, ``, p.String())
}
func TestText(t *testing.T) {
tx := NewText(7, 8, "hello", "black")
uassert.Equal(t, `hello`, tx.String())
tx.DX, tx.DY, tx.Rotate = 1, 2, "45"
tx.WithClass("label")
uassert.Equal(t, `hello`, tx.String())
}
func TestGroup(t *testing.T) {
g := NewGroup("purple")
uassert.Equal(t, ``, g.String())
g.Append(NewCircle(0, 0, 1, "red"), NewPath("M0 0", "none"))
g.WithClass("layer")
uassert.Equal(t,
``,
g.String())
}
func TestGroupNesting(t *testing.T) {
inner := NewGroup("a")
inner.Append(NewCircle(1, 1, 1, "red"))
outer := NewGroup("b")
outer.Append(inner)
uassert.Equal(t,
``,
outer.String())
}
func TestCanvasEmpty(t *testing.T) {
c := NewCanvas(100, 50)
uassert.Equal(t,
``,
c.String())
}
func TestCanvasWithViewBox(t *testing.T) {
c := NewCanvas(100, 50)
uassert.True(t, c.WithViewBox(0, 0, 200, 100) == c, "WithViewBox should be chainable")
uassert.True(t, strings.Contains(c.String(), `viewBox="0 0 200 100"`), "viewBox should be set")
}
func TestCanvasAppend(t *testing.T) {
c := NewCanvas(10, 10)
c.Append(NewCircle(1, 1, 1, "red"), NewCircle(2, 2, 2, "blue"))
out := c.String()
uassert.True(t, strings.Contains(out, ``),
"elements should render in insertion order")
}
// TestCanvasStyleIsKeyOrdered is the determinism check that matters on-chain:
// the style block must not depend on insertion order, or two nodes could
// disagree on the rendered output.
func TestCanvasStyleIsKeyOrdered(t *testing.T) {
a := NewCanvas(10, 10)
a.AddStyle("z-last", "fill:blue").AddStyle("a-first", "fill:red")
b := NewCanvas(10, 10)
b.AddStyle("a-first", "fill:red").AddStyle("z-last", "fill:blue")
uassert.Equal(t, a.String(), b.String())
uassert.True(t, strings.Contains(a.String(), ``),
"styles should be emitted in key order")
}
func TestCanvasNoStyleBlockWhenUnset(t *testing.T) {
uassert.False(t, strings.Contains(NewCanvas(1, 1).String(), "