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)2223// Root answers the corpus bundles directory, relative to some caller-known24// repository root.25func Root(repo string) string {26 return filepath.Join(repo, "testdata", "corpus", "bundles")27}2829// Slugs lists the extracted volumes, which is the corpus contract: public30// provenance only, so the list is short and worth reading.31func Slugs(root string) ([]string, error) {32 entries, err := os.ReadDir(root)33 if err != nil {34 return nil, err35 }36 var slugs []string37 for _, entry := range entries {38 if entry.IsDir() {39 slugs = append(slugs, entry.Name())40 }41 }42 return slugs, nil43}4445// Pack writes one extraction out as a real .atlas file in dir and answers46// with its path.47func Pack(fixture, dir string) (string, error) {48 var manifest bundle.Manifest49 if err := readJSON(filepath.Join(fixture, "manifest.json"), &manifest); err != nil {50 return "", err51 }5253 path := filepath.Join(dir, bundle.VersionedFileName(manifest))54 file, err := os.Create(path)55 if err != nil {56 return "", err57 }58 defer file.Close()59 writer, err := bundle.NewWriter(file, manifest)60 if err != nil {61 return "", err62 }63 for _, entry := range manifest.Worlds {64 payload, err := os.ReadFile(filepath.Join(fixture, "worlds", entry.Slug+".payload.json"))65 if err != nil {66 return "", err67 }68 text, err := os.ReadFile(filepath.Join(fixture, "worlds", entry.Slug+".text.json"))69 if err != nil {70 return "", err71 }72 if err := writer.AddDeflated(bundle.WorldEntryName(entry.Slug, bundle.WorldSuffix), payload); err != nil {73 return "", err74 }75 if err := writer.AddDeflated(bundle.WorldEntryName(entry.Slug, bundle.TextSuffix), text); err != nil {76 return "", err77 }78 locations, err := readLocations(filepath.Join(fixture, "worlds", entry.Slug+".locations.json"))79 if err != nil {80 return "", err81 }82 packed := bundle.PackLocations(locations)83 if err := writer.AddStored(bundle.WorldEntryName(entry.Slug, bundle.PackedSuffix), bytes.NewReader(packed)); err != nil {84 return "", err85 }86 }87 if err := writer.Close(); err != nil {88 return "", err89 }90 return path, nil91}9293func readLocations(path string) ([]bundle.Location, error) {94 var held struct {95 Locations []struct {96 ID int64 `json:"id"`97 Owner uint16 `json:"owner"`98 Lat float64 `json:"lat"`99 Lng float64 `json:"lng"`100 Member int64 `json:"member"`101 Shard int64 `json:"shard"`102 Title string `json:"title"`103 } `json:"locations"`104 }105 if err := readJSON(path, &held); err != nil {106 return nil, err107 }108 out := make([]bundle.Location, 0, len(held.Locations))109 for _, location := range held.Locations {110 out = append(out, bundle.Location{111 ID: location.ID, Owner: location.Owner, Lat: location.Lat, Lng: location.Lng,112 Member: location.Member, Shard: location.Shard, Title: location.Title,113 })114 }115 return out, nil116}117118func readJSON(path string, into any) error {119 data, err := os.ReadFile(path)120 if err != nil {121 return err122 }123 if err := json.Unmarshal(data, into); err != nil {124 return fmt.Errorf("%s: %w", path, err)125 }126 return nil127}