clone

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

feat/atlas-next-horizon
atlas / tests / corpus / corpus.go
corpus.go 4.9K
1// Package corpus packs the committed corpus extractions back into real2// .atlas files.3//4// testdata/corpus/bundles/<slug>/ holds a JSON extraction of one build: the5// manifest, and one payload trio per world. Packing an extraction through6// format/bundle's real writer is what lets a test — or the e2e registry —7// serve real volumes without a single opaque byte in the repository. No8// rasters are committed, so a packed bundle carries every payload and no9// tiles; a page over one draws its chrome, its features and its island, and10// the map answers 404 for imagery, which the renderer is built to survive.11package corpus1213import (14 "bytes"15 "encoding/json"16 "fmt"17 "os"18 "path/filepath"1920 "github.com/FelineStateMachine/atlas/format/bundle"21 "github.com/FelineStateMachine/atlas/format/vnext"22)2324// Root answers the corpus bundles directory, relative to some caller-known25// repository root.26func Root(repo string) string {27 return filepath.Join(repo, "testdata", "corpus", "bundles")28}2930// Slugs lists the extracted volumes, which is the corpus contract: public31// provenance only, so the list is short and worth reading.32func Slugs(root string) ([]string, error) {33 entries, err := os.ReadDir(root)34 if err != nil {35 return nil, err36 }37 var slugs []string38 for _, entry := range entries {39 if entry.IsDir() {40 slugs = append(slugs, entry.Name())41 }42 }43 return slugs, nil44}4546// Pack writes one extraction out as a real .atlas file in dir and answers47// with its path.48func Pack(fixture, dir string) (string, error) {49 var manifest bundle.Manifest50 if err := readJSON(filepath.Join(fixture, "manifest.json"), &manifest); err != nil {51 return "", err52 }5354 legacy, err := os.CreateTemp(dir, ".corpus-v3-*")55 if err != nil {56 return "", err57 }58 legacyPath := legacy.Name()59 defer os.Remove(legacyPath)60 writer, err := bundle.NewWriter(legacy, manifest)61 if err != nil {62 return "", err63 }64 for _, entry := range manifest.Worlds {65 payload, err := os.ReadFile(filepath.Join(fixture, "worlds", entry.Slug+".payload.json"))66 if err != nil {67 return "", err68 }69 text, err := os.ReadFile(filepath.Join(fixture, "worlds", entry.Slug+".text.json"))70 if err != nil {71 return "", err72 }73 if err := writer.AddDeflated(bundle.WorldEntryName(entry.Slug, bundle.WorldSuffix), payload); err != nil {74 return "", err75 }76 if err := writer.AddDeflated(bundle.WorldEntryName(entry.Slug, bundle.TextSuffix), text); err != nil {77 return "", err78 }79 locations, err := readLocations(filepath.Join(fixture, "worlds", entry.Slug+".locations.json"))80 if err != nil {81 return "", err82 }83 packed := bundle.PackLocations(locations)84 if err := writer.AddStored(bundle.WorldEntryName(entry.Slug, bundle.PackedSuffix), bytes.NewReader(packed)); err != nil {85 return "", err86 }87 }88 if err := writer.Close(); err != nil {89 return "", err90 }91 if err := legacy.Close(); err != nil {92 return "", err93 }94 opened, err := bundle.Open(legacyPath)95 if err != nil {96 return "", err97 }98 semantic, err := vnext.ImportV3Volume(manifest, opened.ReadEntry)99 opened.Close()100 if err != nil {101 return "", err102 }103 packed, err := vnext.Compile(semantic)104 if err != nil {105 return "", err106 }107 packed.Release.CreatedAt = manifest.Version.CreatedAt108 packed.Release.Revision = manifest.Version.Revision109 native, err := os.CreateTemp(dir, ".corpus-native-*")110 if err != nil {111 return "", err112 }113 nativePath := native.Name()114 defer os.Remove(nativePath)115 if err := vnext.Write(native, packed); err != nil {116 native.Close()117 return "", err118 }119 if err := native.Close(); err != nil {120 return "", err121 }122 descriptor, err := vnext.Describe(nativePath, vnext.StandardSchema())123 if err != nil {124 return "", err125 }126 release := vnext.Release{Title: descriptor.Title, CreatedAt: descriptor.CreatedAt, Revision: descriptor.Revision, Stamp: descriptor.Stamp, Worlds: descriptor.Worlds}127 path := filepath.Join(dir, vnext.VersionedFileName(descriptor.Slug, release))128 if err := os.Rename(nativePath, path); err != nil {129 return "", err130 }131 return path, nil132}133134func readLocations(path string) ([]bundle.Location, error) {135 var held struct {136 Locations []struct {137 ID int64 `json:"id"`138 Owner uint16 `json:"owner"`139 Lat float64 `json:"lat"`140 Lng float64 `json:"lng"`141 Member int64 `json:"member"`142 Shard int64 `json:"shard"`143 Title string `json:"title"`144 } `json:"locations"`145 }146 if err := readJSON(path, &held); err != nil {147 return nil, err148 }149 out := make([]bundle.Location, 0, len(held.Locations))150 for _, location := range held.Locations {151 out = append(out, bundle.Location{152 ID: location.ID, Owner: location.Owner, Lat: location.Lat, Lng: location.Lng,153 Member: location.Member, Shard: location.Shard, Title: location.Title,154 })155 }156 return out, nil157}158159func readJSON(path string, into any) error {160 data, err := os.ReadFile(path)161 if err != nil {162 return err163 }164 if err := json.Unmarshal(data, into); err != nil {165 return fmt.Errorf("%s: %w", path, err)166 }167 return nil168}