clone

an offline map explorer where each world, from a game map to a city's open data, ships as one .atlas file

archive/golden-reference
atlas / internal / semconv / semconv_test.go
semconv_test.go 6.1K
1package semconv23import (4 "math"5 "os"6 "regexp"7 "strings"8 "testing"9)1011func TestValidateHoldsTheVocabulary(t *testing.T) {12 good := []struct {13 entity Entity14 attrs map[string]string15 }{16 {EntityCollection, map[string]string{KeyRenderAs: "pin"}},17 {EntityCollection, map[string]string{KeyRenderAs: "text", KeyIconStd: "maki/mountain"}},18 {EntityCollection, map[string]string{KeyIconKind: "glyph", KeyCollectionKey: "ripperdoc"}},19 {EntityCollection, map[string]string{KeyGeometryKind: "point"}},20 {EntityCollection, map[string]string{KeyGeometryKind: "path", KeyStrokeWidthPx: "12"}},21 {EntityCollection, map[string]string{KeyGeometryKind: "area", KeyLabelPolicy: "quiet"}},22 {EntityWorld, map[string]string{23 KeyGeometrySurface: "sphere",24 KeyGeometryProjection: "equirect",25 KeyGeometryEquirectPx: "0,0,8192,4096",26 KeyGeometryEquirectDeg: "-180,90,180,-90",27 KeyGeometryBody: "mars",28 KeyGeometryRadiusKM: "3389.5",29 }},30 {EntityWorld, map[string]string{KeyIconOutset: "dark"}},31 {EntityFeature, map[string]string{KeyGeoLat: "-42.4301", KeyGeoLon: "70.5025"}},32 {EntityFeature, map[string]string{KeyHydroHUC12: "170703010101"}},33 // Empty is always fine: conventions are declared, never demanded.34 {EntityCollection, nil},35 }36 for _, test := range good {37 if err := Validate(test.entity, test.attrs); err != nil {38 t.Errorf("%s %v refused: %v", test.entity, test.attrs, err)39 }40 }4142 bad := []struct {43 entity Entity44 attrs map[string]string45 mention string46 }{47 {EntityCollection, map[string]string{"atlas.render.like": "pin"}, "not registered"},48 {EntityCollection, map[string]string{KeyRenderAs: "zone"}, "not one of"},49 {EntityWorld, map[string]string{KeyRenderAs: "pin"}, "attaches to"},50 {EntityCollection, map[string]string{KeyIconStd: "mountain"}, "set/name"},51 {EntityCollection, map[string]string{KeyIconStd: "Maki/Mountain"}, "slug"},52 {EntityCollection, map[string]string{KeyGeometryKind: "polygon"}, "not one of"},53 {EntityCollection, map[string]string{KeyLabelPolicy: "loud"}, "not one of"},54 {EntityFeature, map[string]string{KeyGeometryKind: "area"}, "attaches to"},55 {EntityFeature, map[string]string{KeyStrokeWidthPx: "12"}, "attaches to"},56 {EntityWorld, map[string]string{KeyGeometryEquirectPx: "0,0,8192"}, "4"},57 {EntityWorld, map[string]string{KeyGeometryRadiusKM: "big"}, "number"},58 {EntityFeature, map[string]string{KeyGeoLat: "north"}, "number"},59 {EntityCollection, map[string]string{KeyHydroHUC12: "170703010101"}, "attaches to"},60 // The policy name never rides a payload.61 {EntityFeature, map[string]string{KeyNoteText: "words"}, "not registered"},62 }63 for _, test := range bad {64 err := Validate(test.entity, test.attrs)65 if err == nil || !strings.Contains(err.Error(), test.mention) {66 t.Errorf("%s %v: %v, wanted mention of %q", test.entity, test.attrs, err, test.mention)67 }68 }69}7071func TestRenderAsPrefersAttributesOverLegacy(t *testing.T) {72 cases := []struct {73 attrs map[string]string74 legacy string75 want string76 }{77 {map[string]string{KeyRenderAs: "text"}, "markers", "text"},78 {map[string]string{KeyRenderAs: "pin"}, "text", "pin"},79 {nil, "text", "text"},80 {nil, "markers", "pin"},81 {nil, "", "pin"},82 }83 for _, test := range cases {84 if got := RenderAs(test.attrs, test.legacy); got != test.want {85 t.Errorf("RenderAs(%v, %q) = %q, want %q", test.attrs, test.legacy, got, test.want)86 }87 }88}8990// TestEquirectRoundTrip drives the Mars mapping both ways: the declared91// window is the top half of the 8192-pixel world, and every corner and92// famous place must survive there and back within floating-point noise.93func TestEquirectRoundTrip(t *testing.T) {94 mapping, err := ParseEquirect("0,0,8192,4096", "-180,90,180,-90")95 if err != nil {96 t.Fatal(err)97 }98 places := [][2]float64{99 {90, -180}, {90, 180}, {-90, -180}, {-90, 180}, {0, 0},100 {18.6528, -133.8025}, // Olympus Mons101 {-42.4301, 70.5025}, // Hellas Planitia102 {-14.0059, -58.5877}, // Valles Marineris103 }104 for _, place := range places {105 x, y := mapping.Apply(place[0], place[1])106 lat, lon := mapping.Invert(x, y)107 if math.Abs(lat-place[0]) > 1e-9 || math.Abs(lon-place[1]) > 1e-9 {108 t.Errorf("%v round-trips to %v,%v via %v,%v", place, lat, lon, x, y)109 }110 }111 // And the anchor the whole design stands on: Olympus Mons lands on the112 // same pixel the trekmap translator computes.113 x, y := mapping.Apply(18.6528, -133.8025)114 wantX := (-133.8025 + 180) / 360 * 8192115 wantY := (90 - 18.6528) / 180 * 4096116 if math.Abs(x-wantX) > 1e-9 || math.Abs(y-wantY) > 1e-9 {117 t.Errorf("Olympus Mons at %v,%v, want %v,%v", x, y, wantX, wantY)118 }119}120121func TestParseEquirectRefusesEmptyWindows(t *testing.T) {122 cases := [][2]string{123 {"0,0,0,4096", "-180,90,180,-90"},124 {"0,0,8192,4096", "-180,90,-180,-90"},125 {"0,0,8192", "-180,90,180,-90"},126 }127 for _, test := range cases {128 if _, err := ParseEquirect(test[0], test[1]); err == nil {129 t.Errorf("ParseEquirect(%q, %q) accepted", test[0], test[1])130 }131 }132}133134// TestRegistryAgreesWithItsDocument holds semconv.go and REGISTRY.md to the135// same vocabulary: every registered key appears in the document's attribute136// table with the same entity and stability, and the document names no137// attribute the registry does not know.138func TestRegistryAgreesWithItsDocument(t *testing.T) {139 doc, err := os.ReadFile("REGISTRY.md")140 if err != nil {141 t.Fatal(err)142 }143 row := regexp.MustCompile("(?m)^\\| `(atlas\\.[a-z0-9_.]+)` \\| (bundle|world|collection|feature) \\|.*\\| (stable|experimental) \\|")144 documented := make(map[string][2]string)145 for _, match := range row.FindAllStringSubmatch(string(doc), -1) {146 documented[match[1]] = [2]string{match[2], match[3]}147 }148 for _, key := range Keys() {149 entry, found := documented[key]150 if !found {151 t.Errorf("%s is registered but not documented", key)152 continue153 }154 entity, _ := EntityOf(key)155 stability, _ := StabilityOf(key)156 if entry[0] != string(entity) || entry[1] != string(stability) {157 t.Errorf("%s documented as %s/%s, registered as %s/%s",158 key, entry[0], entry[1], entity, stability)159 }160 delete(documented, key)161 }162 for key := range documented {163 t.Errorf("%s is documented but not registered", key)164 }165}