118 lines
4.3 KiB
Go
118 lines
4.3 KiB
Go
|
|
package svg
|
|||
|
|
|
|||
|
|
import (
|
|||
|
|
"errors"
|
|||
|
|
"strconv"
|
|||
|
|
"testing"
|
|||
|
|
"time"
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
// 本文件钉住全球掩带图的画布下限与"所有文本都在画布内":480x360、600x400 曾因图例压页脚、经纬刻度出框而被放行。
|
|||
|
|
|
|||
|
|
func TestOccultationMapRejectsCanvasBelowMinimum(t *testing.T) {
|
|||
|
|
tests := []struct {
|
|||
|
|
name string
|
|||
|
|
width, height int
|
|||
|
|
}{
|
|||
|
|
{name: "reference too small", width: 480, height: 360},
|
|||
|
|
{name: "legend footer collision", width: 600, height: 400},
|
|||
|
|
{name: "width just below", width: 639, height: 480},
|
|||
|
|
{name: "height just below", width: 640, height: 479},
|
|||
|
|
}
|
|||
|
|
starPath := occultationTestStarPath(t)
|
|||
|
|
planetPath := occultationTestSaturnPath(t)
|
|||
|
|
for _, test := range tests {
|
|||
|
|
t.Run(test.name, func(t *testing.T) {
|
|||
|
|
options := StarOccultationSVGOptions{Width: test.width, Height: test.height}
|
|||
|
|
if _, err := StarOccultationPathSVG(starPath, options); !errors.Is(err, ErrInvalidStarOccultationSVGOptions) {
|
|||
|
|
t.Fatalf("stellar %dx%d error = %v, want ErrInvalidStarOccultationSVGOptions", test.width, test.height, err)
|
|||
|
|
}
|
|||
|
|
if _, err := PlanetOccultationPathSVG(planetPath, options); !errors.Is(err, ErrInvalidPlanetOccultationSVGOptions) {
|
|||
|
|
t.Fatalf("planetary %dx%d error = %v, want ErrInvalidPlanetOccultationSVGOptions", test.width, test.height, err)
|
|||
|
|
}
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func TestOccultationMapKeepsEveryTextInsideCanvas(t *testing.T) {
|
|||
|
|
sizes := [][2]int{{640, 480}, {800, 600}, {1200, 800}, {1000, 1414}}
|
|||
|
|
projections := []MapProjection{MapProjectionAuto, MapProjectionNorthPolar, MapProjectionOrthographic}
|
|||
|
|
starPath := occultationTestStarPath(t)
|
|||
|
|
planetPath := occultationTestSaturnPath(t)
|
|||
|
|
for _, size := range sizes {
|
|||
|
|
for _, projection := range projections {
|
|||
|
|
name := strconv.Itoa(size[0]) + "x" + strconv.Itoa(size[1]) + "-" + string(projection)
|
|||
|
|
t.Run(name, func(t *testing.T) {
|
|||
|
|
options := StarOccultationSVGOptions{
|
|||
|
|
Width: size[0], Height: size[1], Location: time.UTC, Projection: projection,
|
|||
|
|
}
|
|||
|
|
diagrams := map[string]string{}
|
|||
|
|
star, err := StarOccultationPathSVG(starPath, options)
|
|||
|
|
if err != nil {
|
|||
|
|
t.Fatalf("stellar render: %v", err)
|
|||
|
|
}
|
|||
|
|
diagrams["stellar"] = star
|
|||
|
|
planet, err := PlanetOccultationPathSVG(planetPath, options)
|
|||
|
|
if err != nil {
|
|||
|
|
t.Fatalf("planetary render: %v", err)
|
|||
|
|
}
|
|||
|
|
diagrams["planetary"] = planet
|
|||
|
|
for label, diagram := range diagrams {
|
|||
|
|
texts := occultationSVGTexts(t, diagram)
|
|||
|
|
if len(texts) == 0 {
|
|||
|
|
t.Fatalf("%s SVG has no text", label)
|
|||
|
|
}
|
|||
|
|
if outside := occultationSVGTextsOutsideCanvas(texts, float64(size[0]), float64(size[1])); len(outside) > 0 {
|
|||
|
|
t.Fatalf("%s SVG has %d texts outside %s: %v", label, len(outside), name, outside)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func TestOccultationMapLegendDoesNotOverlapFooter(t *testing.T) {
|
|||
|
|
sizes := [][2]int{{640, 480}, {800, 600}, {1200, 800}}
|
|||
|
|
starPath := occultationTestStarPath(t)
|
|||
|
|
planetPath := occultationTestSaturnPath(t)
|
|||
|
|
for _, size := range sizes {
|
|||
|
|
t.Run(strconv.Itoa(size[0])+"x"+strconv.Itoa(size[1]), func(t *testing.T) {
|
|||
|
|
options := StarOccultationSVGOptions{Width: size[0], Height: size[1], Location: time.UTC}
|
|||
|
|
for _, item := range []struct {
|
|||
|
|
label string
|
|||
|
|
path func() (string, error)
|
|||
|
|
}{
|
|||
|
|
{label: "stellar", path: func() (string, error) { return StarOccultationPathSVG(starPath, options) }},
|
|||
|
|
{label: "planetary", path: func() (string, error) { return PlanetOccultationPathSVG(planetPath, options) }},
|
|||
|
|
} {
|
|||
|
|
diagram, err := item.path()
|
|||
|
|
if err != nil {
|
|||
|
|
t.Fatalf("%s render: %v", item.label, err)
|
|||
|
|
}
|
|||
|
|
texts := occultationSVGTexts(t, diagram)
|
|||
|
|
legend := []occultationSVGText{}
|
|||
|
|
footer := []occultationSVGText{}
|
|||
|
|
for _, text := range texts {
|
|||
|
|
if text.class == "occultation-legend-text" {
|
|||
|
|
legend = append(legend, text)
|
|||
|
|
}
|
|||
|
|
if text.parent == "svg" && text.class == "" && text.fontSize == 11 && text.x == 40 {
|
|||
|
|
footer = append(footer, text)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
if len(legend) < 3 || len(footer) == 0 {
|
|||
|
|
t.Fatalf("%s SVG legend=%d footer=%d, want both present", item.label, len(legend), len(footer))
|
|||
|
|
}
|
|||
|
|
for _, legendText := range legend {
|
|||
|
|
for _, footerText := range footer {
|
|||
|
|
if occultationSVGTextBox(legendText)[3] > occultationSVGTextBox(footerText)[1] {
|
|||
|
|
t.Fatalf("%s legend %q overlaps footer %q at %dx%d",
|
|||
|
|
item.label, legendText.value, footerText.value, size[0], size[1])
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
}
|