1package main23import (4 "encoding/json"5 "strings"6 "testing"78 "github.com/FelineStateMachine/atlas/internal/bundle"9 "github.com/FelineStateMachine/atlas/internal/semconv"10)1112// The wire emission mirrors the model: point collections first with their13// features packed under their collection's index, shape collections after14// with their features inline, prose deferred to the text payload either way.15func TestBuildPayloadEmitsCollections(t *testing.T) {16 collections, err := normalizeWorld(declaredFixture())17 if err != nil {18 t.Fatal(err)19 }20 detail, packed, text := buildPayload(catalogWorld{Collections: collections})21 if len(detail.Collections) != 3 {22 t.Fatalf("wire lists %d collections, want 3", len(detail.Collections))23 }24 districts, creeks, implicit := detail.Collections[0], detail.Collections[1], detail.Collections[2]25 if districts.Kind != kindArea || len(districts.Features) != 1 || districts.Features[0].Title != "R-5" {26 t.Fatalf("districts emit as %+v", districts)27 }28 if districts.Attrs[semconv.KeyLabelPolicy] != "quiet" {29 t.Fatalf("districts lost their declared attrs on the wire: %v", districts.Attrs)30 }31 if creeks.Kind != kindPath || creeks.Attrs[semconv.KeyStrokeWidthPx] != "10" {32 t.Fatalf("creeks emit as %+v", creeks)33 }34 if implicit.Kind != kindArea || implicit.Features[0].Title != "Old Town" {35 t.Fatalf("implicit collection emits as %+v", implicit)36 }37 seen := map[int64]bool{districts.ID: true, creeks.ID: true, implicit.ID: true}38 if len(seen) != 3 || seen[0] {39 t.Fatalf("collection ids are not distinct and nonzero: %d %d %d",40 districts.ID, creeks.ID, implicit.ID)41 }42 locations, err := bundle.UnpackLocations(packed)43 if err != nil {44 t.Fatal(err)45 }46 if len(locations) != 0 || len(text) != 0 {47 t.Fatalf("a shapes-only world packed %d locations and %d texts", len(locations), len(text))48 }49}5051// A world with both kinds packs its points under the collection indexes the52// wire lists, and defers every kind's prose behind the hasText marker.53func TestBuildPayloadPacksOwnersAndDefersProse(t *testing.T) {54 world := catalogWorld{Collections: []worldCollection{55 {ID: 41, Kind: kindArea, Key: "districts", Title: "Districts", Visible: true,56 Features: []feature{{ID: 9001, Title: "Old Town", Description: "The old quarter."}}},57 {ID: 10, Kind: kindPoint, Title: "Shops", Visible: true,58 Features: []feature{{ID: 100, Title: "Bakery", Description: "Fresh bread."}}},59 {ID: 11, Kind: kindPoint, Title: "Signs", Visible: true,60 Features: []feature{{ID: 101, Title: "Welcome"}}},61 }}62 detail, packed, text := buildPayload(world)63 // Points lead the wire whatever order the model held them in.64 if detail.Collections[0].ID != 10 || detail.Collections[1].ID != 11 || detail.Collections[2].ID != 41 {65 t.Fatalf("wire order = %d %d %d, want points then shapes",66 detail.Collections[0].ID, detail.Collections[1].ID, detail.Collections[2].ID)67 }68 locations, err := bundle.UnpackLocations(packed)69 if err != nil {70 t.Fatal(err)71 }72 if len(locations) != 2 || locations[0].Owner != 0 || locations[1].Owner != 1 {73 t.Fatalf("locations own %+v, want collection indexes 0 and 1", locations)74 }75 if entry, told := text["100"]; !told || entry.Description != "Fresh bread." {76 t.Fatalf("pin text = %+v, %v", entry, told)77 }78 if entry, told := text["9001"]; !told || entry.Description != "The old quarter." {79 t.Fatalf("zone text = %+v, %v", entry, told)80 }81 if !detail.Collections[2].Features[0].HasText {82 t.Fatal("the zone's deferred prose left no hasText marker")83 }84 raw, err := json.Marshal(detail)85 if err != nil {86 t.Fatal(err)87 }88 if strings.Contains(string(raw), "quarter") || strings.Contains(string(raw), "bread") {89 t.Fatal("prose rode the detail payload")90 }91}