aboutsummaryrefslogtreecommitdiff
path: root/internal/imgw/imgw_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/imgw/imgw_test.go')
-rw-r--r--internal/imgw/imgw_test.go190
1 files changed, 190 insertions, 0 deletions
diff --git a/internal/imgw/imgw_test.go b/internal/imgw/imgw_test.go
new file mode 100644
index 0000000..ffc678e
--- /dev/null
+++ b/internal/imgw/imgw_test.go
@@ -0,0 +1,190 @@
+package imgw
+
+import (
+ "net/http"
+ "net/http/httptest"
+ "os"
+ "path/filepath"
+ "strings"
+ "testing"
+ "time"
+)
+
+func serve(t *testing.T, fixture string, gotQuery *string) *httptest.Server {
+ t.Helper()
+ body, err := os.ReadFile(filepath.Join("testdata", fixture))
+ if err != nil {
+ t.Fatal(err)
+ }
+ srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ if gotQuery != nil {
+ *gotQuery = r.URL.RawQuery
+ }
+ w.Write(body)
+ }))
+ t.Cleanup(srv.Close)
+ return srv
+}
+
+func serveText(t *testing.T, body string) *httptest.Server {
+ t.Helper()
+ srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ w.Write([]byte(body))
+ }))
+ t.Cleanup(srv.Close)
+ return srv
+}
+
+func pinClock(t *testing.T, at time.Time) {
+ t.Helper()
+ old := now
+ now = func() time.Time { return at }
+ t.Cleanup(func() { now = old })
+}
+
+// A point inside Poland resolves to the first four digits of its TERYT code.
+func TestPowiatTruncatesTerytToFourDigits(t *testing.T) {
+ srv := serve(t, "gugik_krakow.json", nil)
+ gugikURL = srv.URL
+ code, status, err := Powiat(50.0617, 19.9373)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if status != StatusOK {
+ t.Fatalf("status = %v, want StatusOK", status)
+ }
+ if code != "1815" {
+ t.Fatalf("code = %q, want 1815 (first four digits of 126101)", code)
+ }
+}
+
+// GUGiK answers a foreign point with HTTP 200 and no results. That is a real
+// answer -- "not in Poland" -- and must never be confused with a failure, which
+// is the difference between "no warnings apply" and "I do not know".
+func TestPowiatOutsidePolandIsAnAnswerNotAnError(t *testing.T) {
+ srv := serve(t, "gugik_abroad.json", nil)
+ gugikURL = srv.URL
+ code, status, err := Powiat(52.52, 13.40)
+ if err != nil {
+ t.Fatalf("a valid 'no results' response must not be an error: %v", err)
+ }
+ if status != StatusOutside {
+ t.Fatalf("status = %v, want StatusOutside", status)
+ }
+ if code != "" {
+ t.Fatalf("code = %q, want empty", code)
+ }
+}
+
+func TestPowiatUnreachableIsStatusError(t *testing.T) {
+ srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ http.Error(w, "boom", http.StatusBadGateway)
+ }))
+ srv.Close() // closed: the request cannot connect at all
+ gugikURL = srv.URL
+ _, status, err := Powiat(50, 21)
+ if status != StatusError {
+ t.Fatalf("status = %v, want StatusError", status)
+ }
+ if err == nil {
+ t.Fatal("expected an error describing the failure")
+ }
+}
+
+// The default 100 m radius finds nothing in the mountains, which is
+// indistinguishable from being abroad and would suppress real warnings.
+func TestPowiatAsksForAWideRadius(t *testing.T) {
+ var query string
+ srv := serve(t, "gugik_krakow.json", &query)
+ gugikURL = srv.URL
+ if _, _, err := Powiat(50, 21); err != nil {
+ t.Fatal(err)
+ }
+ if !strings.Contains(query, "radius=10000") {
+ t.Fatalf("query %q must ask for a wide radius", query)
+ }
+}
+
+func TestWarningsKeepOnlyThisPowiat(t *testing.T) {
+ pinClock(t, time.Date(2000, 1, 1, 0, 0, 0, 0, time.Local)) // nothing expired
+ body := `[
+ {"nazwa_zdarzenia":"Upal","stopien":"1","obowiazuje_do":"2030-01-01 00:00:00","teryt":["1815","1234"]},
+ {"nazwa_zdarzenia":"Burze","stopien":"2","obowiazuje_do":"2030-01-01 00:00:00","teryt":["2207"]}
+ ]`
+ srv := serveText(t, body)
+ warningsURL = srv.URL
+
+ live, err := Warnings("1815")
+ if err != nil {
+ t.Fatal(err)
+ }
+ if len(live) != 1 || live[0].Event != "Upal" {
+ t.Fatalf("got %+v, want only the warning covering 1815", live)
+ }
+}
+
+func TestWarningsDropExpiredButKeepUnparseableDates(t *testing.T) {
+ pinClock(t, time.Date(2026, 8, 10, 12, 0, 0, 0, time.Local))
+ body := `[
+ {"nazwa_zdarzenia":"Wczorajsze","stopien":"1","obowiazuje_do":"2026-08-09 23:00:00","teryt":["1815"]},
+ {"nazwa_zdarzenia":"Trwajace","stopien":"1","obowiazuje_do":"2026-08-10 20:00:00","teryt":["1815"]},
+ {"nazwa_zdarzenia":"Bezdaty","stopien":"1","obowiazuje_do":"","teryt":["1815"]}
+ ]`
+ srv := serveText(t, body)
+ warningsURL = srv.URL
+
+ live, err := Warnings("1815")
+ if err != nil {
+ t.Fatal(err)
+ }
+ var names []string
+ for _, w := range live {
+ names = append(names, w.Event)
+ }
+ got := strings.Join(names, ",")
+ // Unparseable is kept: showing a stale warning beats hiding a live one.
+ if got != "Trwajace,Bezdaty" {
+ t.Fatalf("got %q, want \"Trwajace,Bezdaty\"", got)
+ }
+}
+
+// IMGW has been seen to encode TERYT codes as numbers as well as strings.
+func TestWarningsMatchNumericTerytCodes(t *testing.T) {
+ pinClock(t, time.Date(2000, 1, 1, 0, 0, 0, 0, time.Local))
+ srv := serveText(t, `[{"nazwa_zdarzenia":"X","obowiazuje_do":"2030-01-01 00:00:00","teryt":[1815]}]`)
+ warningsURL = srv.URL
+ live, err := Warnings("1815")
+ if err != nil {
+ t.Fatal(err)
+ }
+ if len(live) != 1 {
+ t.Fatalf("a numeric teryt entry must still match, got %d warnings", len(live))
+ }
+}
+
+func TestWarningsUnreachableIsAnError(t *testing.T) {
+ srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}))
+ srv.Close()
+ warningsURL = srv.URL
+ if _, err := Warnings("1815"); err == nil {
+ t.Fatal("expected an error: the caller must be able to say 'could not check'")
+ }
+}
+
+// The recorded national feed must parse, and must not match a made-up powiat.
+func TestWarningsParseTheRecordedFeed(t *testing.T) {
+ pinClock(t, time.Date(2000, 1, 1, 0, 0, 0, 0, time.Local))
+ srv := serve(t, "warnings.json", nil)
+ warningsURL = srv.URL
+
+ if _, err := Warnings("1815"); err != nil {
+ t.Fatalf("the recorded feed must parse: %v", err)
+ }
+ none, err := Warnings("9999")
+ if err != nil {
+ t.Fatal(err)
+ }
+ if len(none) != 0 {
+ t.Fatalf("powiat 9999 does not exist but matched %d warnings", len(none))
+ }
+}