Make great documentation goal 1.2, and plan the README's reorganisation and the nested-template gaps #33

Open
lilleman wants to merge 966 commits from worktree-todo-relative-dates-exact-counts into main
Showing only changes of commit 2cb124b8a7 - Show all commits
+50 -49
View File
@@ -7,6 +7,7 @@ import (
"io/fs" "io/fs"
"os" "os"
"path" "path"
"path/filepath"
"reflect" "reflect"
"slices" "slices"
"sort" "sort"
@@ -80,7 +81,7 @@ func shippedManifest(whole *Generator) ([]byte, error) {
var b bytes.Buffer var b bytes.Buffer
b.WriteString("{\n\t\"index\": {") b.WriteString("{\n\t\"index\": {")
for i, s := range categorySites(&whole.root) { for i, s := range categorySites(&whole.root) {
line, err := json.Marshal(indexEntry(&whole.root, s)) line, err := json.Marshal(indexEntry(s))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -187,31 +188,30 @@ func TestADataPathLoadsWhatItReads(t *testing.T) {
} }
} }
func TestADataPathLoadsTheShippedCategoriesReachingWhatItReplaces(t *testing.T) { func TestAReplacementBreakingAShippedReaderFailsItsFirstReach(t *testing.T) {
f, err := New(WithDataPath(writeFiles(t, map[string]string{ for name, opt := range map[string]Option{
"sv_SE/last-name.json": `{"format":"{name}","rows":"last-name.tsv","key":"name"}`, "a data path": WithDataPath(writeData(t, map[string]string{"sv_SE/last-name": `"x"`})),
"sv_SE/last-name.tsv": "name\nSvensson\n", "an indexed source": WithDataFS(fstest.MapFS{
}))) ".fejkdata.json": {Data: []byte(`{"index": {"sv_SE.last-name": {"paths": [""]}}}`)},
if err != nil { "sv_SE/last-name.json": {Data: []byte(`"x"`)},
t.Fatalf("New() = %v", err) }),
} } {
got := loadedCategories(f) f, err := New(opt)
for _, w := range []string{"sv_SE.last-name", "sv_SE.person"} { if err != nil {
if !slices.Contains(got, w) { t.Fatalf("New(%s) = %v", name, err)
t.Errorf("New loaded %v, want %s among them", got, w) }
if got := loadedCategories(f); slices.Contains(got, "sv_SE.person") {
t.Errorf("New(%s) loaded %v, want sv_SE.person left for its first reach", name, got)
}
if _, err := f.Fake("sv_SE.person"); !errors.Is(err, ErrLoad) || !strings.Contains(err.Error(), "sv_SE.person") {
t.Errorf(`%s: Fake("sv_SE.person") = %v, want ErrLoad naming sv_SE.person`, name, err)
} }
}
if slices.Contains(got, "misc.uuid") {
t.Errorf("New loaded %v, want misc.uuid left unloaded", got)
}
if _, err := New(WithDataPath(writeData(t, map[string]string{"sv_SE/last-name": `"x"`}))); err == nil || !strings.Contains(err.Error(), "sv_SE.person") {
t.Fatalf("New(a last-name the shipped person cannot read) = %v, want an error naming sv_SE.person", err)
} }
} }
func TestAnIndexedSourceStandsLikeTheShippedOne(t *testing.T) { func TestAnIndexedSourceStandsLikeTheShippedOne(t *testing.T) {
fsys := fstest.MapFS{ fsys := fstest.MapFS{
".fejkdata.json": {Data: []byte(`{"index": {"a": {"paths": [""], "reads": ["b"]}, "b": {"paths": [""]}, "sub.c": {"paths": ["", "d"]}}}`)}, ".fejkdata.json": {Data: []byte(`{"index": {"a": {"paths": [""]}, "b": {"paths": [""]}, "sub.c": {"paths": ["", "d"]}}}`)},
"a.json": {Data: []byte(`"{/b}!"`)}, "a.json": {Data: []byte(`"{/b}!"`)},
"b.json": {Data: []byte(`"x"`)}, "b.json": {Data: []byte(`"x"`)},
"sub/c.json": {Data: []byte(`{"format":"{d}","d":"y"}`)}, "sub/c.json": {Data: []byte(`{"format":"{d}","d":"y"}`)},
@@ -258,32 +258,41 @@ func TestAnIndexedCategoryFailsAtFirstReachAndEveryReachAfter(t *testing.T) {
} }
} }
func TestABrokenManifestFailsNew(t *testing.T) { func TestABrokenManifestFailsNewNamingEveryMistake(t *testing.T) {
for manifest, want := range map[string]string{ for manifest, want := range map[string][]string{
`{`: datafiles.ManifestFile, `{`: {datafiles.ManifestFile},
`{"indx": {}}`: "indx", `{"index": {}} {}`: {"after top-level value"},
`{"index": {"a..b": {"paths": [""]}}}`: "a..b", `{"indx": {}, "INDEX": {}}`: {`unknown key "INDEX"`, `unknown key "indx"`},
`{"index": {}} {}`: "after top-level value", `{"index": []}`: {"index must be an object, not an array"},
`{"INDEX": {}}`: `unknown key "INDEX"`, `{"index": {"a..b": 5}}`: {`"a..b"`, "must be an object, not a number"},
`{"index": {"a": {"Paths": [""]}}}`: `unknown key "Paths"`, `{"index": {"a": {"Paths": [""]}}}`: {`unknown key "Paths"`, "paths is missing"},
`{"index": {"a": {}, "b": {}}}`: `"b": paths is missing`, `{"index": {"a": {}, "b": {}}}`: {`"a": paths is missing`, `"b": paths is missing`},
`{"index": {"a": {"paths": [""], "parent": "b"}}}`: `parent "b" names no entry`, `{"index": {"a": {"paths": ["x..y", 3]}}}`: {`"x..y"`, "paths item 2 must be a string, not a number"},
`{"index": {"a": {"paths": [""], "reads": ["b..c"]}}}`: "b..c", `{"index": {"a": {"paths": [""], "parent": 5}}}`: {"parent must be a string, not a number"},
`{"index": {"a": {"paths": [""], "parent": "b"}}}`: {`parent "b" names no entry`},
`{"index": {"a": {"paths": [""], "reads": ["b"]}}}`: {`unknown key "reads"`},
} { } {
_, err := New(WithoutShippedData(), WithDataFS(fstest.MapFS{".fejkdata.json": {Data: []byte(manifest)}})) _, err := New(WithoutShippedData(), WithDataFS(fstest.MapFS{".fejkdata.json": {Data: []byte(manifest)}}))
if err == nil || !strings.Contains(err.Error(), want) { for _, w := range want {
t.Errorf("New(manifest %s) = %v, want an error naming %s", manifest, err, want) if err == nil || !strings.Contains(err.Error(), w) {
t.Errorf("New(manifest %s) = %v, want an error naming %s", manifest, err, w)
}
}
if err != nil && strings.Count(err.Error(), "\n") >= len(want) {
t.Errorf("New(manifest %s) = %v, want %d mistakes, each once", manifest, err, len(want))
} }
} }
} }
func TestAnIndexedSourceReplacingAShippedCategoryLoadsItsReadersInNew(t *testing.T) { func TestNewMatchesErrLoadOnDataThatFailsToLoad(t *testing.T) {
_, err := New(WithDataFS(fstest.MapFS{ for name, opt := range map[string]Option{
".fejkdata.json": {Data: []byte(`{"index": {"sv_SE.last-name": {"paths": [""]}}}`)}, "a missing data path": WithDataPath(filepath.Join(t.TempDir(), "nope")),
"sv_SE/last-name.json": {Data: []byte(`"x"`)}, "a broken category": WithDataPath(writeData(t, map[string]string{"x": `{ not json`})),
})) "a broken manifest": WithDataFS(fstest.MapFS{".fejkdata.json": {Data: []byte(`{`)}}),
if err == nil || !strings.Contains(err.Error(), "sv_SE.person") { } {
t.Fatalf("New() = %v, want an error naming sv_SE.person", err) if _, err := New(opt); !errors.Is(err, ErrLoad) {
t.Errorf("New(%s) = %v, want it to match ErrLoad", name, err)
}
} }
} }
@@ -387,16 +396,8 @@ func TestADataPathTableUnderAShippedTableLoads(t *testing.T) {
} }
// indexEntry is what an index says of the loaded category s. // indexEntry is what an index says of the loaded category s.
func indexEntry(root *folder, s categorySite) datafiles.IndexEntry { func indexEntry(s categorySite) datafiles.IndexEntry {
e := datafiles.IndexEntry{Parent: parentOf(s.n), Paths: paths(s.n, false)} e := datafiles.IndexEntry{Parent: parentOf(s.n), Paths: paths(s.n, false)}
sort.Strings(e.Paths) sort.Strings(e.Paths)
seen := map[string]bool{s.path: true}
for _, c := range referenced(root, s.dir, siteNodes([]categorySite{s})) {
if p := categoryPath(c.dir, c.name); !seen[p] {
seen[p] = true
e.Reads = append(e.Reads, p)
}
}
sort.Strings(e.Reads)
return e return e
} }