package svg import ( "errors" "math" "strings" "testing" "time" "b612.me/astro/moon" ) func TestFindLocalPlanetOccultationSVGsSaturnFiveContacts(t *testing.T) { location := time.FixedZone("UTC+8", 8*3600) diagrams, err := FindLocalPlanetOccultationSVGs( time.Date(2025, time.February, 1, 0, 0, 0, 0, location), time.Date(2025, time.February, 2, 0, 0, 0, 0, location), moon.OccultationSaturn, 104.52219613, 55.25401991, 0, moon.OccultationSearchOptions{}, LocalPlanetOccultationSVGOptions{Width: 920, Height: 700, Location: location}, ) if err != nil { t.Fatalf("FindLocalPlanetOccultationSVGs() error = %v", err) } if len(diagrams) != 1 { t.Fatalf("FindLocalPlanetOccultationSVGs() returned %d diagrams, want 1", len(diagrams)) } diagram := diagrams[0] for _, want := range []string{ ` 1e-12 { t.Fatalf("C2 display distance = %.12f, want %.12f", math.Hypot(x-100, y-100), float64(40-6)) } event.label = "C4" x, y = localPlanetOccultationSVGStageCenter(event, 100, 100, 40, 6, 0.04) if math.Abs(math.Hypot(x-100, y-100)-(40+6)) > 1e-12 { t.Fatalf("C4 display distance = %.12f, want %.12f", math.Hypot(x-100, y-100), float64(40+6)) } } func TestLocalPlanetOccultationSVGEnglishAndCustomText(t *testing.T) { info := localSaturnOccultation(t) diagram, err := LocalPlanetOccultationSVG(info, LocalPlanetOccultationSVGOptions{ Language: "en", Location: time.UTC, Title: "Custom local planet title", SummaryText: "Custom local planet summary", GreatestText: "Custom local planet greatest", OverviewTitle: "Custom local planet overview", PhasePanelsTitle: "Custom local planet stages", ContactsTitle: "Custom local planet contacts", DirectionText: "Custom local planet direction", FooterNote: "Custom local planet footer", }) if err != nil { t.Fatalf("LocalPlanetOccultationSVG() error = %v", err) } for _, want := range []string{ "Custom local planet title", "Custom local planet summary", "Custom local planet greatest", "Custom local planet overview", "Custom local planet stages", "Custom local planet contacts", "Custom local planet direction", "Custom local planet footer", "C1 external ingress", "C2 internal ingress", "Greatest", "C3 internal egress", "C4 external egress", } { if !strings.Contains(diagram, want) { t.Fatalf("English local planetary SVG missing %q", want) } } if err := validateXML(diagram); err != nil { t.Fatalf("English local planetary SVG is not valid XML: %v", err) } } func TestLocalPlanetOccultationSVGRejectsInvalidInput(t *testing.T) { info := localSaturnOccultation(t) _, err := LocalPlanetOccultationSVG(info, LocalPlanetOccultationSVGOptions{Width: 1}) if !errors.Is(err, ErrInvalidLocalPlanetOccultationSVGOptions) { t.Fatalf("invalid canvas error = %v, want ErrInvalidLocalPlanetOccultationSVGOptions", err) } info.ContactsComplete = false _, err = LocalPlanetOccultationSVG(info, LocalPlanetOccultationSVGOptions{}) if !errors.Is(err, ErrInvalidLocalPlanetOccultationInfo) { t.Fatalf("incomplete event error = %v, want ErrInvalidLocalPlanetOccultationInfo", err) } } func TestLocalPlanetOccultationSVGRejectsTargetGeometryMismatch(t *testing.T) { info := localSaturnOccultation(t) info.Planet = moon.OccultationVenus info.TargetID = "Venus" _, err := LocalPlanetOccultationSVG(info, LocalPlanetOccultationSVGOptions{}) if !errors.Is(err, ErrInvalidLocalPlanetOccultationInfo) { t.Fatalf("mismatched planet error = %v, want ErrInvalidLocalPlanetOccultationInfo", err) } } func TestLocalPlanetOccultationSVGPartialEventUsesThreeStages(t *testing.T) { events, err := moon.FindPlanetOccultations( time.Date(2024, time.August, 21, 1, 30, 0, 0, time.UTC), time.Date(2024, time.August, 21, 4, 0, 0, 0, time.UTC), moon.OccultationSaturn, -30.072, -6.5, 0, moon.OccultationSearchOptions{}, ) if err != nil || len(events) != 1 { t.Fatalf("FindPlanetOccultations() = %d events, %v; want one", len(events), err) } diagram, err := LocalPlanetOccultationSVG(events[0], LocalPlanetOccultationSVGOptions{Language: "en"}) if err != nil { t.Fatalf("LocalPlanetOccultationSVG() error = %v", err) } if got := strings.Count(diagram, `class="stage-planet-disk"`); got != 3 { t.Fatalf("partial event stage count = %d, want 3", got) } if strings.Contains(diagram, "C2 internal ingress") || strings.Contains(diagram, "C3 internal egress") { t.Fatal("partial event SVG contains internal contacts") } } func localSaturnOccultation(t *testing.T) moon.PlanetOccultationInfo { t.Helper() location := time.FixedZone("UTC+8", 8*3600) events, err := moon.FindPlanetOccultations( time.Date(2025, time.February, 1, 0, 0, 0, 0, location), time.Date(2025, time.February, 2, 0, 0, 0, 0, location), moon.OccultationSaturn, 104.52219613, 55.25401991, 0, moon.OccultationSearchOptions{}, ) if err != nil { t.Fatalf("FindPlanetOccultations() error = %v", err) } if len(events) != 1 { t.Fatalf("FindPlanetOccultations() returned %d events, want 1", len(events)) } return events[0] }