Files

88 lines
2.4 KiB
Go
Raw Permalink Normal View History

package svg
import (
"encoding/xml"
"io"
"strconv"
"strings"
"testing"
)
// svgElement 是一个已解析的 SVG 起始标签及其属性。
type svgElement struct {
tag string
attrs map[string]string
}
func parseSVGElements(t *testing.T, value string) []svgElement {
t.Helper()
decoder := xml.NewDecoder(strings.NewReader(value))
elements := make([]svgElement, 0)
for {
token, err := decoder.Token()
if err == io.EOF {
return elements
}
if err != nil {
t.Fatalf("chart is not valid XML: %v", err)
}
start, ok := token.(xml.StartElement)
if !ok {
continue
}
attrs := make(map[string]string, len(start.Attr))
for _, attr := range start.Attr {
attrs[attr.Name.Local] = attr.Value
}
elements = append(elements, svgElement{tag: start.Name.Local, attrs: attrs})
}
}
func svgAttributeFloat(attrs map[string]string, name string) (float64, bool) {
value, ok := attrs[name]
if !ok {
return 0, false
}
parsed, err := strconv.ParseFloat(value, 64)
if err != nil {
return 0, false
}
return parsed, true
}
// assertSVGElementsInCanvas 断言全部文本与矩形都落在画布内:版面一旦按硬编码坐标排版,
// 尺寸不足时元素会静默跑到画布外而不是报错。
func assertSVGElementsInCanvas(t *testing.T, value string, width, height int) {
t.Helper()
texts, rects := 0, 0
for _, element := range parseSVGElements(t, value) {
switch element.tag {
case "text":
texts++
x, hasX := svgAttributeFloat(element.attrs, "x")
y, hasY := svgAttributeFloat(element.attrs, "y")
if hasX && (x < 0 || x > float64(width)) {
t.Fatalf("text x=%.3f outside the %d-wide canvas: %v", x, width, element.attrs)
}
if hasY && (y < 0 || y > float64(height)) {
t.Fatalf("text y=%.3f outside the %d-high canvas: %v", y, height, element.attrs)
}
case "rect":
x, hasX := svgAttributeFloat(element.attrs, "x")
y, hasY := svgAttributeFloat(element.attrs, "y")
w, hasW := svgAttributeFloat(element.attrs, "width")
h, hasH := svgAttributeFloat(element.attrs, "height")
if !hasX || !hasY || !hasW || !hasH {
continue
}
rects++
if x < -0.01 || y < -0.01 || x+w > float64(width)+0.01 || y+h > float64(height)+0.01 {
t.Fatalf("rect (%.3f,%.3f,%.3f,%.3f) outside the %dx%d canvas", x, y, w, h, width, height)
}
}
}
if texts == 0 || rects == 0 {
t.Fatalf("chart carries %d texts and %d rects, want a full page", texts, rects)
}
}