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 / tools / generate / main_test.go
main_test.go 8.3K
1package main23import (4 "encoding/binary"5 "os"6 "path/filepath"7 "testing"8)910func TestResolvedCategoryColor(t *testing.T) {11 tests := []struct {12 name string13 group rawGroup14 category rawCategory15 want string16 }{17 {18 name: "category overrides group",19 group: rawGroup{Color: "38344C"},20 category: rawCategory{Color: "aaacae"},21 want: "#AAACAE",22 },23 {24 name: "group fallback",25 group: rawGroup{Color: "38344C"},26 category: rawCategory{},27 want: "#38344C",28 },29 {30 name: "invalid color omitted",31 group: rawGroup{Color: "not-a-color"},32 category: rawCategory{},33 want: "",34 },35 }3637 for _, tt := range tests {38 t.Run(tt.name, func(t *testing.T) {39 if got := resolvedCategoryColor(tt.group, tt.category); got != tt.want {40 t.Fatalf("resolvedCategoryColor() = %q, want %q", got, tt.want)41 }42 })43 }44}4546func TestAttachGameIcons(t *testing.T) {47 source := t.TempDir()48 if err := os.MkdirAll(filepath.Join(source, "icons"), 0o755); err != nil {49 t.Fatal(err)50 }51 const svg = `<svg viewBox="0 0 24 24"><path fill="currentColor" d="M0 0h24v24H0z"/></svg>`52 if err := os.WriteFile(filepath.Join(source, "icons", "pokemon_center.svg"), []byte(svg), 0o644); err != nil {53 t.Fatal(err)54 }5556 game := catalogVolume{57 Slug: "pokemon-red-blue-yellow",58 Worlds: []catalogWorld{{59 Collections: []worldCollection{60 {Kind: kindPoint, Icon: "pokemon_center"},61 {Kind: kindPoint, Icon: "missing"},62 },63 }},64 }65 if err := attachVolumeIcons(source, &game); err != nil {66 t.Fatal(err)67 }6869 collections := game.Worlds[0].Collections70 if got, want := collections[0].IconAsset, "pokemon_center.svg"; got != want {71 t.Fatalf("icon asset = %q, want %q", got, want)72 }73 if collections[1].IconAsset != "" {74 t.Fatalf("missing icon asset = %q, want empty", collections[1].IconAsset)75 }76 if got := string(game.Icons["pokemon_center.svg"]); got != svg {77 t.Fatalf("carried SVG = %q, want %q", got, svg)78 }79}8081func TestBuildGameSkipsMapWithoutSnapshotIndex(t *testing.T) {82 archiveRoot := t.TempDir()83 gamePath := filepath.Join(archiveRoot, "games", "pokemon-red-blue-yellow-246")84 if err := os.MkdirAll(filepath.Join(gamePath, "maps", "red-blue-847"), 0o755); err != nil {85 t.Fatal(err)86 }8788 game, err := buildVolume(89 archiveRoot,90 nil,91 nil,92 archiveGame{93 Directory: "games/pokemon-red-blue-yellow-246",94 ID: 246,95 Title: "Pokémon Red/Blue/Yellow",96 },97 tileGrid{SourceZoom: 13, FirstTile: 4064, TileSize: 256, Size: 8192},98 )99 if err != nil {100 t.Fatal(err)101 }102 if len(game.Worlds) != 0 {103 t.Fatalf("maps = %d, want 0", len(game.Worlds))104 }105}106107func TestSortGameMapsPrefersPrimaryMap(t *testing.T) {108 maps := []catalogWorld{109 {Title: "Big MT", Slug: "big-mt"},110 {Title: "Zion Canyon", Slug: "zion-canyon"},111 {Title: "Mojave Wasteland", Slug: "mojave-wasteland"},112 {Title: "Sierra Madre", Slug: "sierra-madre"},113 }114115 sortVolumeWorlds("fallout-new-vegas", maps)116117 want := []string{"mojave-wasteland", "big-mt", "sierra-madre", "zion-canyon"}118 for index, slug := range want {119 if maps[index].Slug != slug {120 t.Fatalf("map %d = %q, want %q", index, maps[index].Slug, slug)121 }122 }123}124125// The packed payload is the only thing the frontend reads a location from, so126// a field left out of it is a field the map does not have. Shard went missing127// this way once, and every layer's pins drew over every other.128func TestBuildPayloadPacksEveryColumn(t *testing.T) {129 region := int64(77)130 m := catalogWorld{Collections: []worldCollection{131 {Kind: kindPoint, Features: []feature{132 {ID: 11, Title: "Sky Mine", Lat: 1.5, Lng: -2.5, Shard: 1783},133 }},134 {Kind: kindPoint, Features: []feature{135 {ID: 12, Title: "Deep Well", Lat: -3, Lng: 4, Member: &region, Shard: 1785},136 }},137 }}138139 _, packed, _ := buildPayload(m)140141 if magic := string(packed[:8]); magic != "ATLASLOC" {142 t.Fatalf("magic = %q, want %q", magic, "ATLASLOC")143 }144 if version := binary.LittleEndian.Uint16(packed[8:]); version != 3 {145 t.Fatalf("version = %d, want 3", version)146 }147 count := int(binary.LittleEndian.Uint32(packed[10:]))148 if count != 2 {149 t.Fatalf("count = %d, want 2", count)150 }151152 column := func(index int) []int32 {153 at := 16 + index*count*4154 values := make([]int32, count)155 for i := range values {156 values[i] = int32(binary.LittleEndian.Uint32(packed[at+i*4:]))157 }158 return values159 }160161 if ids := column(0); ids[0] != 11 || ids[1] != 12 {162 t.Fatalf("ids = %v, want [11 12]", ids)163 }164 if members := column(3); members[0] != 0 || members[1] != 77 {165 t.Fatalf("members = %v, want [0 77]", members)166 }167 if shards := column(4); shards[0] != 1783 || shards[1] != 1785 {168 t.Fatalf("shards = %v, want [1783 1785]", shards)169 }170171 titles := string(packed[len(packed)-len("Sky MineDeep Well"):])172 if titles != "Sky MineDeep Well" {173 t.Fatalf("titles = %q, want %q", titles, "Sky MineDeep Well")174 }175}176177// A piece is cropped from the sheet by growing its ground into the space around178// it and then easing it away from its neighbours. Easing may only give back179// what the growth added: it once cut into the ground itself, which took the180// bottom border off the Camp McCarran panel -- the crop stopped inside the181// frame the panel is drawn with.182func TestGrowIntoGapsKeepsEveryPieceAroundItsGround(t *testing.T) {183 // Two pieces set corner to corner, sharing a span on neither axis, so both184 // grow into the same diagonal space and have to be eased apart again.185 ground := [][4]float64{186 {0, 0, 100, 100},187 {110, 110, 210, 210},188 }189190 grown := growIntoGaps(ground, 8192)191192 for index, box := range ground {193 got := grown[index]194 if got[0] > box[0] || got[1] > box[1] || got[2] < box[2] || got[3] < box[3] {195 t.Errorf("piece %d cropped to %v, which cuts into its ground %v", index, got, box)196 }197 }198}199200// The window a raster is cut from is not the ground the map is about: a sheet201// drawn inside a printed border or a title panel spends most of its thirty-two202// named cells on nothing. What the grid divides is measured from the map's own203// contents instead, and a location drawn off the sheet entirely does not get to204// stretch that measurement back over everything it left out.205func TestMarkSurfacesMeasuresContentsNotTheWindow(t *testing.T) {206 grid := tileGrid{SourceZoom: 13, FirstTile: 4064, TileSize: 256, Size: 8192}207 at := func(x, y float64) feature {208 return feature{209 Lat: unprojectLatitude(y, grid),210 Lng: unprojectLongitude(x, grid),211 }212 }213 window := contentBounds{X: 2000, Y: 2000, Width: 3000, Height: 3000}214 m := catalogWorld{215 Lenses: []lens{{Bounds: &window}},216 Collections: []worldCollection{{217 Kind: kindPoint,218 Features: []feature{219 at(3000, 3000),220 at(4000, 4000),221 // Off the sheet, and so no part of what the map covers.222 at(6000, 6000),223 },224 }},225 }226227 markSurfaces(&m, grid)228229 surface := m.Lenses[0].Surface230 if surface == nil {231 t.Fatal("no surface measured")232 }233 near := func(got, want int) bool { return got >= want-2 && got <= want+2 }234 // The margin is the larger of 32 pixels and a fiftieth of the longer side.235 if !near(surface.X, 2968) || !near(surface.Y, 2968) ||236 !near(surface.Width, 1064) || !near(surface.Height, 1064) {237 t.Fatalf("surface = %+v, want about {2968 2968 1064 1064}", *surface)238 }239 if surface.X < window.X || surface.Y < window.Y ||240 surface.X+surface.Width > window.X+window.Width ||241 surface.Y+surface.Height > window.Y+window.Height {242 t.Errorf("surface %+v reaches outside the window %+v", *surface, window)243 }244}245246// A piece of a sheet already knows the ground its regions cover, and that247// ground is kept: the pieces are cropped to it, and their locations need not248// reach every corner of what the piece is drawn to show.249func TestMarkSurfacesKeepsGroundAlreadyMeasured(t *testing.T) {250 grid := tileGrid{SourceZoom: 13, FirstTile: 4064, TileSize: 256, Size: 8192}251 window := contentBounds{X: 2000, Y: 2000, Width: 3000, Height: 3000}252 ground := contentBounds{X: 2500, Y: 2500, Width: 2000, Height: 2000}253 m := catalogWorld{254 Lenses: []lens{{Bounds: &window, Surface: &ground}},255 Collections: []worldCollection{{256 Kind: kindPoint,257 Features: []feature{{258 Lat: unprojectLatitude(3000, grid),259 Lng: unprojectLongitude(3000, grid),260 }},261 }},262 }263264 markSurfaces(&m, grid)265266 surface := m.Lenses[0].Surface267 if surface.X > ground.X || surface.Y > ground.Y ||268 surface.X+surface.Width < ground.X+ground.Width ||269 surface.Y+surface.Height < ground.Y+ground.Height {270 t.Fatalf("surface = %+v, which drops part of the ground %+v", *surface, ground)271 }272}