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 / internal / enrich / enrichers / stdicons / stdicons_test.go
stdicons_test.go 4.4K
1package stdicons23import (4 "slices"5 "strings"6 "testing"78 "github.com/FelineStateMachine/atlas/format/semconv"9 "github.com/FelineStateMachine/atlas/internal/enrich"10)1112func volume(collections ...enrich.Collection) *enrich.Volume {13 return &enrich.Volume{14 Slug: "bend-or",15 Worlds: []enrich.World{{Slug: "today", Collections: collections}},16 }17}1819func declaring(id int64, ref string) enrich.Collection {20 return enrich.Collection{21 ID: id, Title: "Historic Resources", Kind: enrich.KindPoint,22 Attrs: map[string]string{semconv.KeyIconStd: ref},23 }24}2526func TestResolutionLandsWhereThereIsNoArtwork(t *testing.T) {27 own := declaring(2, "maki/mountain")28 own.Icon = "the-source-shipped-this"29 composed := declaring(3, "maki/park")30 composed.IconAsset = "already-resolved.svg"31 shape := declaring(4, "maki/water")32 shape.Kind = enrich.KindArea3334 cases := []struct {35 what string36 collection enrich.Collection37 resolves bool38 }{39 {"a declaration with nothing in the slot", declaring(1, "maki/monument"), true},40 {"a collection whose source shipped artwork", own, false},41 {"a collection whose artwork is already resolved", composed, false},42 {"a shape collection, which wears no marker", shape, false},43 {"a collection that declares nothing",44 enrich.Collection{ID: 5, Kind: enrich.KindPoint}, false},45 }46 for _, c := range cases {47 t.Run(c.what, func(t *testing.T) {48 contribution, err := New().Enrich(volume(c.collection), enrich.Context{})49 if err != nil {50 t.Fatal(err)51 }52 if contribution.Empty() == c.resolves {53 t.Fatalf("resolved=%t, want %t", !contribution.Empty(), c.resolves)54 }55 })56 }57}5859func TestOneAssetTravelsOnceHoweverManyCollectionsNameIt(t *testing.T) {60 contribution, err := New().Enrich(volume(61 declaring(1, "maki/monument"),62 declaring(2, "maki/monument"),63 declaring(3, "maki/mountain"),64 ), enrich.Context{})65 if err != nil {66 t.Fatal(err)67 }68 assets, resolutions := 0, 069 for _, op := range contribution.Ops {70 switch op.Kind {71 case enrich.OpAddAsset:72 assets++73 case enrich.OpSetIcon:74 resolutions++75 }76 }77 if assets != 2 || resolutions != 3 {78 t.Errorf("%d assets for %d collections, want 2 for 3", assets, resolutions)79 }80}8182func TestADeclarationTheLibraryCannotAnswerFailsTheBuild(t *testing.T) {83 // The one place in this lane where refusal beats silence: the promise was84 // made by a translator author, in this repository, and an unanswerable one85 // is a typo that should be heard about.86 _, err := New().Enrich(volume(declaring(1, "maki/skyscraper")), enrich.Context{})87 if err == nil {88 t.Fatal("a declaration nobody vendored was quietly dropped")89 }90 if !strings.Contains(err.Error(), "not vendored") {91 t.Errorf("refused with %v", err)92 }93}9495func TestStandardNamesItsProvenance(t *testing.T) {96 cases := []struct {97 ref string98 asset string99 refuse bool100 }{101 {ref: "maki/monument", asset: "std--maki-monument.svg"},102 {ref: "maki/mountain", asset: "std--maki-mountain.svg"},103 {ref: "maki/skyscraper", refuse: true},104 {ref: "lucide/mountain", refuse: true},105 {ref: "mountain", refuse: true},106 {ref: "", refuse: true},107 {ref: "maki/../../etc/passwd", refuse: true},108 }109 for _, c := range cases {110 t.Run(c.ref, func(t *testing.T) {111 data, asset, err := Standard(c.ref)112 if c.refuse {113 if err == nil {114 t.Fatalf("%q resolved to %s", c.ref, asset)115 }116 return117 }118 if err != nil {119 t.Fatal(err)120 }121 if asset != c.asset {122 t.Errorf("asset %q, want %q", asset, c.asset)123 }124 if !strings.Contains(string(data), "<svg") {125 t.Error("the resolved bytes are not an svg")126 }127 })128 }129}130131func TestTheVendoredSetIsTheVocabulary(t *testing.T) {132 vocabulary := Vocabulary()133 if len(vocabulary) < 10 {134 t.Fatalf("the vendored set holds %d names", len(vocabulary))135 }136 if !slices.IsSorted(vocabulary) {137 t.Error("the vocabulary is not in a stable order")138 }139 for _, ref := range vocabulary {140 if _, _, err := Standard(ref); err != nil {141 t.Errorf("%q is vendored but does not resolve: %v", ref, err)142 }143 }144 if slices.Contains(vocabulary, "maki/LICENSE") {145 t.Error("the licence is listed as a glyph")146 }147}148149func TestTheEnricherDeclaresNoAttributes(t *testing.T) {150 // Artwork is not a claim about the world, and the kind of artwork a151 // collection carries is declared by composition, which is the step that152 // knows whether the asset actually travelled.153 if declares := New().Declares(); len(declares) != 0 {154 t.Errorf("stdicons declares %v", declares)155 }156}