From e8b7d95559f89ece18ef225c47c1f63b7e749c4e Mon Sep 17 00:00:00 2001 From: Lilleman auf Larv Date: Sat, 10 Oct 2026 13:16:59 +0200 Subject: [PATCH] Test that each shipped module renders beside the modules it reads, that the test's module list matches data.Modules(), and that a data path's manifest and an indexed one each name what they read --- data.go | 15 ++---- imports_test.go | 2 +- internal/datafiles/datafiles_test.go | 15 ++---- node.go | 13 ----- shipped_test.go | 78 ++++++++++++++++++++-------- 5 files changed, 66 insertions(+), 57 deletions(-) diff --git a/data.go b/data.go index 7c8b582..68dbc53 100644 --- a/data.go +++ b/data.go @@ -8,7 +8,7 @@ import ( // loadSources merges sources in order, the last winning a clash. A source whose manifest // carries an index leaves its categories unloaded; every other source loads here, with -// the unloaded categories it needs: docs/decisions.md#a-source-whose-manifest-carries-an-index-loads-each-category-on-first-reach-any-other-loads-in-new-with-what-it-reads +// the unloaded categories it needs. func loadSources(sources []datafiles.Source) (folder, error) { root := folder{children: map[string]node{}} for _, src := range sources { @@ -25,16 +25,13 @@ func addSource(root *folder, src datafiles.Source) error { return err } if m.Index != nil { - placeIndex(root, src, m) + placeIndex(root, src, m.Index) return nil } g := &folder{children: map[string]node{}} if err := src.Walk(compileInto(func(dir []string) *folder { return madeFolder(g, dir) })); err != nil { return err } - for _, s := range categorySites(g) { - s.in.setReads(s.name, m.Reads) - } mergeFolder(root, g) return nil } @@ -73,7 +70,6 @@ func mergeFolder(dst, src *folder) { } } dst.put(k, v) - dst.setReads(k, src.reads[k]) } } @@ -84,9 +80,8 @@ type nodeSet func(fn func(label string, n node) error) error // categorySite is a loaded category, where it sits and its own dot path. type categorySite struct { categoryAt - n node - path string - reads []string + n node + path string } // categorySites lists every category under root, folders and names in sorted order. @@ -107,7 +102,7 @@ func categorySites(root *folder) []categorySite { } func siteIn(dir []string, in *folder, name string) categorySite { - return categorySite{categoryAt: categoryAt{dir: dir, in: in, name: name}, n: in.children[name], path: categoryPath(dir, name), reads: in.reads[name]} + return categorySite{categoryAt: categoryAt{dir: dir, in: in, name: name}, n: in.children[name], path: categoryPath(dir, name)} } func categoryPath(dir []string, name string) string { return join(strings.Join(dir, "."), name) } diff --git a/imports_test.go b/imports_test.go index 766a17b..1842f26 100644 --- a/imports_test.go +++ b/imports_test.go @@ -48,7 +48,7 @@ func TestPackageImports(t *testing.T) { "internal/rows": {"internal/drawstate", "internal/grammar", "internal/invariant"}, } testsAlso := map[string][]string{ - ".": {"data", "data/sv_SE"}, + ".": {"data", "data/en_US", "data/geo/SE", "data/geo/US", "data/misc", "data/sv_SE"}, "cmd/fejkdata": {"internal/grammar"}, "data/en_US": {"."}, "data/geo/SE": {"."}, diff --git a/internal/datafiles/datafiles_test.go b/internal/datafiles/datafiles_test.go index 0adb691..e47f141 100644 --- a/internal/datafiles/datafiles_test.go +++ b/internal/datafiles/datafiles_test.go @@ -49,13 +49,6 @@ func TestWalkHandsEachCategoryInOrder(t *testing.T) { } } -func TestWalkStartsAtTheBaseDir(t *testing.T) { - got, err := walk(t, Source{fsys: fstest.MapFS{"data/a.json": {Data: []byte(`"x"`)}, "b.json": {Data: []byte(`"y"`)}}, base: "data"}) - if err != nil || len(got) != 1 || got[0].name != "a" || got[0].dir != nil { - t.Errorf("Walk = %#v, %v, want a alone at the base", got, err) - } -} - func TestReadRowsReadsOnlyAFileBesideTheCategory(t *testing.T) { src := Source{fsys: fstest.MapFS{ "t.json": {Data: []byte(`{"rows":"t.tsv"}`)}, @@ -138,10 +131,10 @@ func TestWalkRefusesADiskPathThatIsNoDirectory(t *testing.T) { func TestLoadHandsOneCategoryAndItsRows(t *testing.T) { src := Source{fsys: fstest.MapFS{ - "data/sub/t.json": {Data: []byte(`{"rows":"t.tsv"}`)}, - "data/sub/t.tsv": {Data: []byte("key\nA\n")}, - "data/sub/u.json": {Data: []byte(`{`)}, - }, base: "data"} + "sub/t.json": {Data: []byte(`{"rows":"t.tsv"}`)}, + "sub/t.tsv": {Data: []byte("key\nA\n")}, + "sub/u.json": {Data: []byte(`{`)}, + }} var got handed var rows string err := src.Load([]string{"sub"}, "t", func(c Category) error { diff --git a/node.go b/node.go index 48ab7ce..fe19297 100644 --- a/node.go +++ b/node.go @@ -24,8 +24,6 @@ type node interface{ isNode() } type folder struct { children map[string]node unloaded map[string]*indexed - // reads is, for each category, the modules its source's manifest names it reading by default. - reads map[string][]string } func (*folder) isNode() {} @@ -35,17 +33,6 @@ func (g *folder) put(name string, n node) { delete(g.unloaded, name) } -func (g *folder) setReads(name string, reads []string) { - if len(reads) == 0 { - delete(g.reads, name) - return - } - if g.reads == nil { - g.reads = map[string][]string{} - } - g.reads[name] = reads -} - func (g *folder) putUnloaded(name string, x *indexed) { delete(g.children, name) if g.unloaded == nil { diff --git a/shipped_test.go b/shipped_test.go index 653d625..2ffdb38 100644 --- a/shipped_test.go +++ b/shipped_test.go @@ -8,7 +8,6 @@ import ( "io/fs" "maps" "os" - "path" "path/filepath" "reflect" "slices" @@ -19,6 +18,10 @@ import ( "testing/fstest" "github.com/larvit/fejkdata/data" + "github.com/larvit/fejkdata/data/en_US" + "github.com/larvit/fejkdata/data/geo/SE" + "github.com/larvit/fejkdata/data/geo/US" + "github.com/larvit/fejkdata/data/misc" "github.com/larvit/fejkdata/data/sv_SE" "github.com/larvit/fejkdata/internal/datafiles" ) @@ -47,25 +50,16 @@ func (m shippedModule) holds(path string) bool { return strings.HasPrefix(path, strings.ReplaceAll(m.dir, "/", ".")+".") } -// shippedModules is every module data.Modules lists, each folder found by descending its -// tree while a folder holds one folder and nothing else. +// shippedModules is every module data.Modules lists, each beside its folder under data/. func shippedModules(t testing.TB) []shippedModule { t.Helper() - var out []shippedModule - for _, fsys := range data.Modules() { - dir := "." - for { - entries, err := fs.ReadDir(fsys, dir) - if err != nil { - t.Fatal(err) - } - entries = slices.DeleteFunc(entries, func(e fs.DirEntry) bool { return strings.HasPrefix(e.Name(), ".") }) - if len(entries) != 1 || !entries[0].IsDir() { - break - } - dir = path.Join(dir, entries[0].Name()) - } - out = append(out, shippedModule{fsys: fsys, dir: dir}) + out := []shippedModule{{en_US.FS, "en_US"}, {SE.FS, "geo/SE"}, {US.FS, "geo/US"}, {misc.FS, "misc"}, {sv_SE.FS, "sv_SE"}} + var listed []fs.FS + for _, m := range out { + listed = append(listed, m.fsys) + } + if !slices.Equal(listed, data.Modules()) { + t.Fatal("data.Modules() lists other modules than shippedModules does") } return out } @@ -180,7 +174,7 @@ func shippedIndex(t *testing.T) map[string]datafiles.IndexEntry { t.Helper() index := map[string]datafiles.IndexEntry{} for _, m := range shippedModules(t) { - manifest, err := datafiles.FS(m.fsys, "").Manifest() + manifest, err := datafiles.FS(m.fsys).Manifest() if err != nil { t.Fatal(err) } @@ -191,7 +185,7 @@ func shippedIndex(t *testing.T) map[string]datafiles.IndexEntry { func TestEachShippedModuleNamesWhatItReads(t *testing.T) { for _, m := range shippedModules(t) { - manifest, err := datafiles.FS(m.fsys, "").Manifest() + manifest, err := datafiles.FS(m.fsys).Manifest() if err != nil { t.Fatal(err) } @@ -204,6 +198,33 @@ func TestEachShippedModuleNamesWhatItReads(t *testing.T) { } } +func TestEachShippedModuleRendersBesideTheModulesItReads(t *testing.T) { + modules := shippedModules(t) + for _, m := range modules { + manifest, err := datafiles.FS(m.fsys).Manifest() + if err != nil { + t.Fatal(err) + } + set := []fs.FS{m.fsys} + for _, read := range manifest.Reads { + i := slices.IndexFunc(modules, func(r shippedModule) bool { return r.importPath() == read }) + if i < 0 { + t.Fatalf("%s reads %s, which no shipped module is", m.dir, read) + } + set = append(set, modules[i].fsys) + } + f, err := New(WithDataFS(set...)) + if err != nil { + t.Fatalf("New(%s with what it reads) = %v", m.dir, err) + } + for _, p := range sortedNames(manifest.Index) { + if _, err := f.Fake(p); err != nil { + t.Errorf("%s with what it reads: Fake(%q) = %v", m.dir, p, err) + } + } + } +} + func TestAReadNoModuleProvidesNamesTheReadersModules(t *testing.T) { f, err := New(WithDataFS(sv_SE.FS)) if err != nil { @@ -236,6 +257,19 @@ func TestADataPathManifestNamesWhatItReads(t *testing.T) { } } +func TestAnIndexedModuleNamesWhatItReads(t *testing.T) { + f, err := New(WithDataFS(fstest.MapFS{ + ".fejkdata.json": {Data: []byte(`{"index": {"x": {"paths": [""]}}, "reads": ["example.com/places"]}`)}, + "x.json": {Data: []byte(`"{/place}"`)}, + })) + if err != nil { + t.Fatalf("New = %v", err) + } + if _, err := f.Fake("x"); err == nil || !strings.Contains(err.Error(), "the module holding x reads by default example.com/places") { + t.Errorf(`Fake("x") = %v, want the module x reads named`, err) + } +} + func TestNewLoadsNoShippedCategory(t *testing.T) { f, err := New(withShipped()) if err != nil { @@ -405,8 +439,8 @@ func TestABrokenManifestFailsNewNamingEveryMistake(t *testing.T) { `{"index": {"a": {"paths": ["", "x", "x"]}}}`: {`paths item 3 repeats "x"`}, `{"index": {"a": {"paths": [""], "parent": "b"}}}`: {`parent "b" names no entry`}, `{"index": {"a": {"paths": [""], "reads": ["b"]}}}`: {`unknown key "reads"`}, - `{"reads": "b"}`: {"reads must be a list, not a string"}, - `{"reads": ["", 3]}`: {"reads item 1 is empty", "reads item 2 must be a string, not a number"}, + `{"index": {}, "reads": "b"}`: {"reads must be a list, not a string"}, + `{"index": {}, "reads": ["", 3]}`: {"reads item 1 is empty", "reads item 2 must be a string, not a number"}, } { _, err := New(WithDataFS(fstest.MapFS{".fejkdata.json": {Data: []byte(manifest)}})) for _, w := range want {