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
19 changed files with 91 additions and 87 deletions
Showing only changes of commit 3ae8b9f1b1 - Show all commits
+1 -1
View File
@@ -310,7 +310,7 @@ func TestCalcRefusesABadOperand(t *testing.T) {
}
func TestATypedColumnRefusesACalcOverNoDigits(t *testing.T) {
_, err := New(WithDataPath(writeData(t, map[string]string{
_, err := New(WithSeed(1), WithDataPath(writeData(t, map[string]string{
"row": `{"format":"","x":{"format":"{calc(d + 1)}","d":"{digits(0)}","datatype":"integer"}}`,
})))
if err == nil || !strings.Contains(err.Error(), "{digits(0)} prints nothing, which is no number") {
+7
View File
@@ -127,6 +127,13 @@ func TestRunDotPath(t *testing.T) {
}
}
func TestRunWithoutASeedSeedsFromTheSystem(t *testing.T) {
_, a, errb := runOut("{uuid()}")
if code, b, _ := runOut("{uuid()}"); code != 0 || a == "" || a == b {
t.Fatalf("two runs without --seed = %q and %q, exit %d, stderr=%q; want each its own draw", a, b, code, errb)
}
}
func TestRunSeedSpellings(t *testing.T) {
_, want, _ := runOut("{/address}", "--seed", "42", "--data-path", svSE)
for _, args := range [][]string{
+1 -1
View File
@@ -12,7 +12,7 @@ func TestFSLoadsByItsManifest(t *testing.T) {
if _, err := fs.Stat(enus.FS, ".fejkdata.json"); err != nil {
t.Fatalf("FS holds no manifest: %v", err)
}
f, err := fejkdata.New(fejkdata.WithDataFS(enus.Modules()...))
f, err := fejkdata.New(fejkdata.WithDataFS(enus.Modules()...), fejkdata.WithSeed(1))
if err != nil {
t.Fatalf("New(WithDataFS(Modules()...)) = %v", err)
}
+1 -1
View File
@@ -12,7 +12,7 @@ func TestFSLoadsByItsManifest(t *testing.T) {
if _, err := fs.Stat(geose.FS, ".fejkdata.json"); err != nil {
t.Fatalf("FS holds no manifest: %v", err)
}
f, err := fejkdata.New(fejkdata.WithDataFS(geose.Modules()...))
f, err := fejkdata.New(fejkdata.WithDataFS(geose.Modules()...), fejkdata.WithSeed(1))
if err != nil {
t.Fatalf("New(WithDataFS(Modules()...)) = %v", err)
}
+1 -1
View File
@@ -12,7 +12,7 @@ func TestFSLoadsByItsManifest(t *testing.T) {
if _, err := fs.Stat(geous.FS, ".fejkdata.json"); err != nil {
t.Fatalf("FS holds no manifest: %v", err)
}
f, err := fejkdata.New(fejkdata.WithDataFS(geous.Modules()...))
f, err := fejkdata.New(fejkdata.WithDataFS(geous.Modules()...), fejkdata.WithSeed(1))
if err != nil {
t.Fatalf("New(WithDataFS(Modules()...)) = %v", err)
}
+1 -1
View File
@@ -12,7 +12,7 @@ func TestFSLoadsByItsManifest(t *testing.T) {
if _, err := fs.Stat(misc.FS, ".fejkdata.json"); err != nil {
t.Fatalf("FS holds no manifest: %v", err)
}
f, err := fejkdata.New(fejkdata.WithDataFS(misc.Modules()...))
f, err := fejkdata.New(fejkdata.WithDataFS(misc.Modules()...), fejkdata.WithSeed(1))
if err != nil {
t.Fatalf("New(WithDataFS(Modules()...)) = %v", err)
}
+1 -1
View File
@@ -12,7 +12,7 @@ func TestFSLoadsByItsManifest(t *testing.T) {
if _, err := fs.Stat(svse.FS, ".fejkdata.json"); err != nil {
t.Fatalf("FS holds no manifest: %v", err)
}
f, err := fejkdata.New(fejkdata.WithDataFS(svse.Modules()...))
f, err := fejkdata.New(fejkdata.WithDataFS(svse.Modules()...), fejkdata.WithSeed(1))
if err != nil {
t.Fatalf("New(WithDataFS(Modules()...)) = %v", err)
}
+3 -3
View File
@@ -88,7 +88,7 @@ func TestDatatypeRejectsAValueItsTypeRejects(t *testing.T) {
for name, body := range tree {
files[name] = body
}
_, err := New(WithDataPath(writeData(t, files)))
_, err := New(WithSeed(1), WithDataPath(writeData(t, files)))
if err == nil || !strings.Contains(err.Error(), c.want) {
t.Errorf("%s: New = %v, want an error containing %q", c.name, err, c.want)
}
@@ -102,14 +102,14 @@ func TestDatatypeRejectsAValueItsTypeRejects(t *testing.T) {
`[{"format":"1","datatype":"integer"},{"format":"1.5","datatype":"number"}]`: "its items hold integer and number; a column holds one datatype",
} {
row := `{"format":"","col":` + column + `}`
if _, err := New(WithDataPath(writeData(t, map[string]string{"row": row}))); err == nil || !strings.HasSuffix(err.Error(), want) {
if _, err := New(WithSeed(1), WithDataPath(writeData(t, map[string]string{"row": row}))); err == nil || !strings.HasSuffix(err.Error(), want) {
t.Errorf("items of two declared datatypes %s: New = %v, want an error ending %q", column, err, want)
}
if _, err := newGenerator(t, writeData(t, tree)).NewTemplate(row); err == nil || !strings.HasSuffix(err.Error(), want) {
t.Errorf("items of two declared datatypes %s: NewTemplate = %v, want an error ending %q", column, err, want)
}
}
_, err := New(WithDataPath(writeData(t, map[string]string{
_, err := New(WithSeed(1), WithDataPath(writeData(t, map[string]string{
"a": `{"format":"","c":["{/b.x}",{"format":"1","datatype":"integer"}]}`,
"b": `{"format":"","x":["2",{"format":"1","datatype":"integer"}]}`,
})))
+9 -12
View File
@@ -7,7 +7,6 @@ import (
"path/filepath"
"strings"
"testing"
"testing/fstest"
"github.com/larvit/fejkdata/data"
"github.com/larvit/fejkdata/internal/drawstate"
@@ -30,7 +29,7 @@ func newGeneratorN(t *testing.T, dirs []string, opts ...Option) *Generator {
for _, dir := range dirs {
all = append(all, WithDataPath(dir))
}
f, err := New(append(all, opts...)...)
f, err := New(append(append(all, WithSeed(1)), opts...)...)
if err != nil {
t.Fatalf("New(%q): %v", dirs, err)
}
@@ -41,7 +40,7 @@ func newGeneratorN(t *testing.T, dirs []string, opts ...Option) *Generator {
// categories sit at the root, failing on error.
func newBareModule(t *testing.T, module string, opts ...Option) *Generator {
t.Helper()
f, err := New(append([]Option{WithDataFS(withoutManifest{os.DirFS(filepath.Join("data", module))})}, opts...)...)
f, err := New(append([]Option{WithDataFS(withoutManifest{os.DirFS(filepath.Join("data", module))}), WithSeed(1)}, opts...)...)
if err != nil {
t.Fatalf("New(%s without its manifest): %v", module, err)
}
@@ -59,26 +58,24 @@ func fake(t *testing.T, f *Generator, path string) string {
}
func TestNewMissingDirectory(t *testing.T) {
_, err := New(WithDataPath("data/de_DE"))
_, err := New(WithSeed(1), WithDataPath("data/de_DE"))
if err == nil || !strings.Contains(err.Error(), "de_DE") || !errors.Is(err, fs.ErrNotExist) {
t.Fatalf("New(missing) error = %v, want the real error, naming the path", err)
}
}
func TestNewRejectsAnEmptyDataPath(t *testing.T) {
_, err := New(WithDataPath(""))
_, err := New(WithSeed(1), WithDataPath(""))
if err == nil || !strings.Contains(err.Error(), "empty") {
t.Fatalf("New(WithDataPath(\"\")) = %v, want the empty path named", err)
}
}
func TestNewReportsAnEntropyFailure(t *testing.T) {
saved := randomBytes
randomBytes = func([]byte) (int, error) { return 0, errors.New("no entropy") }
defer func() { randomBytes = saved }()
_, err := New(WithDataFS(fstest.MapFS{"w.json": {Data: []byte(`"x"`)}}))
if err == nil || !strings.Contains(err.Error(), "no entropy") {
t.Fatalf("New() without entropy = %v, want the failure reported", err)
func TestNewWithoutASeedFailsNamingWithSeed(t *testing.T) {
for name, opts := range map[string][]Option{"no option": nil, "only data": {WithDataFS()}} {
if _, err := New(opts...); err == nil || !strings.Contains(err.Error(), "WithSeed(") {
t.Errorf("New(%s) = %v, want it refused, naming WithSeed", name, err)
}
}
}
+6 -6
View File
@@ -187,12 +187,12 @@ func TestRepeatProductAlongAPathIsCapped(t *testing.T) {
"b": `{"format":"x","repeat":2048}`,
},
} {
_, err := New(WithDataPath(writeData(t, files)))
_, err := New(WithSeed(1), WithDataPath(writeData(t, files)))
if err == nil || !strings.Contains(err.Error(), "repeat") || !strings.Contains(err.Error(), "1048576") {
t.Errorf("%s: New = %v, want the repeat product rejected naming the maximum", name, err)
}
}
if _, err := New(WithDataPath(writeData(t, map[string]string{
if _, err := New(WithSeed(1), WithDataPath(writeData(t, map[string]string{
"cat": `{"format":"{a}{c}","repeat":1024,"a":{"format":"{b}","repeat":1024,"b":"x"},"c":{"format":"y","repeat":1024}}`,
}))); err != nil {
t.Errorf("New = %v, want 1024 x 1024 along one path accepted", err)
@@ -205,11 +205,11 @@ func TestNewErrors(t *testing.T) {
if err := os.WriteFile(file, []byte("{}"), 0o644); err != nil {
t.Fatal(err)
}
if _, err := New(WithDataPath(file)); err == nil || !strings.Contains(err.Error(), "xx_XX: not a directory") {
if _, err := New(WithSeed(1), WithDataPath(file)); err == nil || !strings.Contains(err.Error(), "xx_XX: not a directory") {
t.Errorf("New(file) = %v, want not-a-directory error", err)
}
// Invalid JSON in a category file fails.
if _, err := New(WithDataPath(writeData(t, map[string]string{"broken": `{ not json`}))); err == nil {
if _, err := New(WithSeed(1), WithDataPath(writeData(t, map[string]string{"broken": `{ not json`}))); err == nil {
t.Error("New(invalid JSON) = nil error")
}
// An option that cannot take effect, and a category or folder no dot path can
@@ -300,7 +300,7 @@ func TestNewErrors(t *testing.T) {
},
}
for name, c := range rejected {
_, err := New(WithDataPath(writeData(t, c.files)))
_, err := New(WithSeed(1), WithDataPath(writeData(t, c.files)))
if err == nil {
t.Errorf("%s: New = nil error, want it rejected at load", name)
continue
@@ -328,7 +328,7 @@ func TestNewErrors(t *testing.T) {
"repeated reference arm": {map[string]string{"a": `"x"`, "b": `"{/a|/a}"`}, "b", "x"},
}
for name, c := range accepted {
f, err := New(WithDataPath(writeData(t, c.files)))
f, err := New(WithSeed(1), WithDataPath(writeData(t, c.files)))
if err != nil {
t.Errorf("%s: New = %v, want it accepted", name, err)
continue
+2 -2
View File
@@ -253,7 +253,7 @@ func TestNameErrors(t *testing.T) {
}
files[name] = body
}
_, err := New(WithDataPath(writeFiles(t, files)))
_, err := New(WithSeed(1), WithDataPath(writeFiles(t, files)))
if c.want == "" {
if err != nil {
t.Fatalf("New() = %v, want it to load", err)
@@ -463,7 +463,7 @@ func TestARowThroughANameHintsAPathThatLoads(t *testing.T) {
files := nameTables()
files["card.json"] = `{"format":"{x as r}{r[01]}","x":"{/region}"}`
want := `a path through name "r" may not select a row; bind the row to a name of its own`
if _, err := New(WithDataPath(writeFiles(t, files))); err == nil || !strings.Contains(err.Error(), want) {
if _, err := New(WithSeed(1), WithDataPath(writeFiles(t, files))); err == nil || !strings.Contains(err.Error(), want) {
t.Errorf("New(a field-bound name selecting a row) = %v, want %s", err, want)
}
}
+1 -1
View File
@@ -17,7 +17,7 @@ func TestAnOptionOfTheWrongKindIsNamedByItsJSONKind(t *testing.T) {
t.Errorf("compile(%s) = %v, want %q", src, err, want)
}
}
_, err := New(WithDataPath(writeFiles(t, map[string]string{"t.json": `{"format":"{a}","rows":"t.tsv","key":5}`, "t.tsv": "a\nx\n"})))
_, err := New(WithSeed(1), WithDataPath(writeFiles(t, map[string]string{"t.json": `{"format":"{a}","rows":"t.tsv","key":5}`, "t.tsv": "a\nx\n"})))
if err == nil || !strings.Contains(err.Error(), "key must be a string, not a number") {
t.Errorf("key 5 = %v, want the kind named", err)
}
+1 -1
View File
@@ -130,7 +130,7 @@ func TestPathKeyIsUnambiguous(t *testing.T) {
dir := writeData(t, map[string]string{
"cat": `[{"format":"{a.b}","a.b":"1"},{"format":"{a}","a":{"format":"{b}","b":"2"}}]`,
})
_, err := New(WithDataPath(dir))
_, err := New(WithSeed(1), WithDataPath(dir))
if err == nil || !strings.Contains(err.Error(), `field "a.b" contains "."`) {
t.Fatalf("New = %v, want the dotted field name rejected", err)
}
+6 -6
View File
@@ -44,7 +44,7 @@ func TestNoRenderAllocRegression(t *testing.T) {
{"format":"y","a":"A","b":"B","c":"C","d":"D","e":"E","f":"F","g":"G","h":"H","i":"I","j":"J"}]}`, 3},
}
for _, s := range shapes {
f, err := New(WithDataFS(fstest.MapFS{"x.json": {Data: []byte(s.json)}}))
f, err := New(WithSeed(1), WithDataFS(fstest.MapFS{"x.json": {Data: []byte(s.json)}}))
if err != nil {
t.Fatalf("New(%s): %v", s.name, err)
}
@@ -66,7 +66,7 @@ func TestNoReferenceAllocRegression(t *testing.T) {
{"a repeat of a name", `{"format":"{r}","r":{"format":"{/word as n}{n.w}{n.w}","repeat":20,"separator":", "}}`, 162, 1.10},
{"a read two levels under a pick", `{"format":"{place.geo as g}{g} {g.town.zip}","place":{"format":"{geo}","geo":{"format":"{town.zip}","town":{"format":"{zip}","zip":"1"}}}}`, 12, 1},
} {
f, err := New(WithDataFS(fstest.MapFS{
f, err := New(WithSeed(1), WithDataFS(fstest.MapFS{
"word.json": {Data: []byte(word)},
"x.json": {Data: []byte(s.json)},
}))
@@ -81,7 +81,7 @@ func TestNoReferenceAllocRegression(t *testing.T) {
// A table read pins a row inline and reads its cells in place.
func TestNoTableAllocRegression(t *testing.T) {
f, err := New(WithDataFS(fstest.MapFS{
f, err := New(WithSeed(1), WithDataFS(fstest.MapFS{
"region.json": {Data: []byte(`{"format":"{name}","rows":"region.tsv","key":"code","weight":"population"}`)},
"region.tsv": {Data: []byte("code\tname\tpopulation\n01\tStockholms län\t2400000\n12\tSkåne län\t1400000\n14\tVästra Götalands län\t1750000\n")},
"x.json": {Data: []byte(`"{/region.name}, {/region.code}"`)},
@@ -113,7 +113,7 @@ func TestNoTableAllocRegression(t *testing.T) {
}
deep[name+".json"], deep[name+".tsv"] = &fstest.MapFile{Data: []byte(category)}, &fstest.MapFile{Data: []byte(rows)}
}
f, err = New(WithDataFS(deep))
f, err = New(WithSeed(1), WithDataFS(deep))
if err != nil {
t.Fatal(err)
}
@@ -129,7 +129,7 @@ func TestNoRecordAllocRegression(t *testing.T) {
{"record 3 columns", `{"format":"","a":"x","b":"y","c":"z"}`},
{"record 50 columns", wideTokenJSON(50)},
} {
f, err := New(WithDataFS(fstest.MapFS{"x.json": {Data: []byte(s.json)}}))
f, err := New(WithSeed(1), WithDataFS(fstest.MapFS{"x.json": {Data: []byte(s.json)}}))
if err != nil {
t.Fatalf("New(%s): %v", s.name, err)
}
@@ -148,7 +148,7 @@ func TestNoRecordAllocRegression(t *testing.T) {
}
func TestNoStructAllocRegression(t *testing.T) {
f, err := New(WithDataFS(fstest.MapFS{"x.json": {Data: []byte(`{"format":"","a":"x","b":"y","c":"z"}`)}}))
f, err := New(WithSeed(1), WithDataFS(fstest.MapFS{"x.json": {Data: []byte(`{"format":"","a":"x","b":"y","c":"z"}`)}}))
if err != nil {
t.Fatal(err)
}
+9 -9
View File
@@ -152,7 +152,7 @@ func TestANameReadOnceIsWhatItBinds(t *testing.T) {
func TestCycleReachedOnlyByAPathTokenIsRejected(t *testing.T) {
// A path token renders what it lands on, not the level it started from, so the
// cycle walk has to follow it there.
_, err := New(WithDataPath(writeData(t, map[string]string{
_, err := New(WithSeed(1), WithDataPath(writeData(t, map[string]string{
"a": `{"format":"{p.x}","p":{"format":"static","x":"{/b}"}}`,
"b": `"{/a}"`,
})))
@@ -162,7 +162,7 @@ func TestCycleReachedOnlyByAPathTokenIsRejected(t *testing.T) {
}
func TestACycleInALaterVariantIsRejected(t *testing.T) {
_, err := New(WithDataPath(writeData(t, map[string]string{
_, err := New(WithSeed(1), WithDataPath(writeData(t, map[string]string{
"cat": `{"format":"{p.x}","p":[{"format":"h","x":"safe"},{"format":"h","x":"{/hop}"}]}`,
"hop": `"{/cat}"`,
})))
@@ -172,7 +172,7 @@ func TestACycleInALaterVariantIsRejected(t *testing.T) {
}
func TestCycleThroughAPathTokenIsRejected(t *testing.T) {
_, err := New(WithDataPath(writeData(t, map[string]string{
_, err := New(WithSeed(1), WithDataPath(writeData(t, map[string]string{
"a": `{"format":"{p.x}","p":{"format":"{x}","x":"{/b}"}}`,
"b": `"{/a}"`,
})))
@@ -190,7 +190,7 @@ func TestADeepDiamondChainLoads(t *testing.T) {
`{"format":"{a}{b}","a":"{/l%d}","b":"{/l%d}"}`, i-1, i-1)
}
files["thing"] = `{"format":"{p.first} {/l30}","p":{"format":"x","first":["A","B"]}}`
if _, err := New(WithDataPath(writeData(t, files))); err != nil {
if _, err := New(WithSeed(1), WithDataPath(writeData(t, files))); err != nil {
t.Fatalf("New = %v, want a deep diamond chain to load", err)
}
}
@@ -208,7 +208,7 @@ func TestNestedChoiceDrawsOneVariant(t *testing.T) {
}
func TestRepeatingLevelIsNamedInTheError(t *testing.T) {
_, err := New(WithDataPath(writeData(t, map[string]string{
_, err := New(WithSeed(1), WithDataPath(writeData(t, map[string]string{
"cat": `{"format":"[{p.a.b}]","p":{"format":"{a}","a":{"format":"{b}","repeat":3,"separator":",","b":"z"}}}`,
})))
if err == nil || !strings.Contains(err.Error(), `"p.a"`) {
@@ -223,7 +223,7 @@ func TestPathIntoARepeatingLevelIsRejected(t *testing.T) {
`{"format":"[{p.a}]","p":{"format":"{a}","repeat":3,"separator":",","a":"z"}}`,
`{"format":"[{p.a}]","p":[{"format":"{a}","repeat":3,"separator":",","a":"x"},{"format":"{a}","a":"y"}]}`,
} {
_, err := New(WithDataPath(writeData(t, map[string]string{"cat": cat})))
_, err := New(WithSeed(1), WithDataPath(writeData(t, map[string]string{"cat": cat})))
if err == nil || !strings.Contains(err.Error(), "repeat") {
t.Errorf("New(%s) = %v, want a path into a repeating level rejected", cat, err)
}
@@ -231,7 +231,7 @@ func TestPathIntoARepeatingLevelIsRejected(t *testing.T) {
}
func TestPathIntoAPlainTemplateNamesTheMissingField(t *testing.T) {
_, err := New(WithDataPath(writeData(t, map[string]string{
_, err := New(WithSeed(1), WithDataPath(writeData(t, map[string]string{
"cat": `{"format":"{a.nope}","a":{"format":"x","b":"1"}}`,
})))
if err == nil || !strings.Contains(err.Error(), `no field "nope"`) {
@@ -273,7 +273,7 @@ func TestDottedTokenErrors(t *testing.T) {
},
}
for name, c := range rejected {
_, err := New(WithDataPath(writeData(t, map[string]string{"cat": c.file})))
_, err := New(WithSeed(1), WithDataPath(writeData(t, map[string]string{"cat": c.file})))
if err == nil || !strings.Contains(err.Error(), c.want) {
t.Errorf("%s: New = %v, want it to mention %q", name, err, c.want)
}
@@ -285,7 +285,7 @@ func TestEmptyPathSegmentIsRejected(t *testing.T) {
"trailing dot": `{"format":"[{a.}]","a":"x"}`,
"triple dot": `{"format":"[{a...b}]","a":"x"}`,
} {
_, err := New(WithDataPath(writeData(t, map[string]string{"cat": file})))
_, err := New(WithSeed(1), WithDataPath(writeData(t, map[string]string{"cat": file})))
if err == nil || !strings.Contains(err.Error(), "empty segment") {
t.Errorf("%s: New = %v, want it to name the empty segment", name, err)
}
+9 -9
View File
@@ -107,7 +107,7 @@ func TestReferenceErrors(t *testing.T) {
"field key using the reference prefix": {"cat": `{"format":"hi","..x":"{/nope}"}`},
}
for name, files := range cases {
if _, err := New(WithDataPath(writeData(t, files))); err == nil {
if _, err := New(WithSeed(1), WithDataPath(writeData(t, files))); err == nil {
t.Errorf("%s: New = nil error, want a reference error", name)
}
}
@@ -142,13 +142,13 @@ func TestAReferenceIntoItsOwnCategoryIsAFreshDraw(t *testing.T) {
"the category in its format": `{"format":"{/cat}"}`,
"a field reading itself": `{"format":"{x}","x":"{/cat.x}"}`,
} {
_, err := New(WithDataPath(writeData(t, map[string]string{"cat": file})))
_, err := New(WithSeed(1), WithDataPath(writeData(t, map[string]string{"cat": file})))
if err == nil || !strings.Contains(err.Error(), "cycle") {
t.Errorf("%s: New = %v, want the cycle refused", name, err)
}
}
// Reading a sibling as a path is the spelling that stays.
if _, err := New(WithDataPath(writeData(t, map[string]string{
if _, err := New(WithSeed(1), WithDataPath(writeData(t, map[string]string{
"cat": `{"format":"{y.v}","y":{"format":"{v}","v":["1","2"]}}`,
}))); err != nil {
t.Errorf("New = %v, want the sibling path accepted", err)
@@ -173,7 +173,7 @@ func TestNewErrorIsDeterministic(t *testing.T) {
dir := writeData(t, files)
var first string
for i := 0; i < 50; i++ {
_, err := New(WithDataPath(dir))
_, err := New(WithSeed(1), WithDataPath(dir))
if err == nil {
t.Fatalf("%s: New = nil error, want a load error", name)
}
@@ -210,7 +210,7 @@ func TestNewErrorPathIsCanonical(t *testing.T) {
},
}
for _, c := range cases {
_, err := New(WithDataPath(writeData(t, c.files)))
_, err := New(WithSeed(1), WithDataPath(writeData(t, c.files)))
if err == nil {
t.Errorf("%s: New = nil error", c.name)
continue
@@ -222,7 +222,7 @@ func TestNewErrorPathIsCanonical(t *testing.T) {
}
func TestReferenceThroughChoiceNeedsEveryVariant(t *testing.T) {
_, err := New(WithDataPath(writeData(t, map[string]string{
_, err := New(WithSeed(1), WithDataPath(writeData(t, map[string]string{
"who": `[{"format":"{f}{h}","f":"1","h":"x"},{"format":"{g}{h}","g":"2","h":"y"}]`,
"card": `"{/who.f}"`,
})))
@@ -325,7 +325,7 @@ func TestReferenceSigilErrors(t *testing.T) {
"missing sibling": {"sv_SE/a": `"{.nope}"`},
"slash in a field name": {"a": `{"format":"{x}","x":"1","a/b":"2"}`},
} {
if _, err := New(WithDataPath(writeData(t, files))); err == nil {
if _, err := New(WithSeed(1), WithDataPath(writeData(t, files))); err == nil {
t.Errorf("%s: New = nil error, want a reference error", name)
}
}
@@ -336,7 +336,7 @@ func TestSlashAfterAReferenceSigilIsRejected(t *testing.T) {
"after ..": {"sv_SE/person": `"Ada"`, "sv_SE/deep/a": `"{../person}"`},
"after .": {"sv_SE/person": `"Ada"`, "sv_SE/a": `"{./person}"`},
} {
_, err := New(WithDataPath(writeData(t, files)))
_, err := New(WithSeed(1), WithDataPath(writeData(t, files)))
if err == nil || !strings.Contains(err.Error(), "person}") || !strings.Contains(err.Error(), "write {") {
t.Errorf("%s: New = %v, want the slash rejected naming the spelling", name, err)
}
@@ -344,7 +344,7 @@ func TestSlashAfterAReferenceSigilIsRejected(t *testing.T) {
}
func TestACycleThroughASelectedRowIsRefused(t *testing.T) {
_, err := New(WithDataPath(writeFiles(t, map[string]string{
_, err := New(WithSeed(1), WithDataPath(writeFiles(t, map[string]string{
"x.json": `{"format":"{v} {/y}","rows":"x.tsv","key":"code"}`,
"x.tsv": "code\tv\n1\ta\n2\tb\n",
"y.json": `"{/x[1]}"`,
+4 -4
View File
@@ -95,7 +95,7 @@ func TestAGeneratorWithNoDataRendersWhatReadsNone(t *testing.T) {
"no module": {WithDataFS()},
"empty folder": {WithDataPath(t.TempDir())},
} {
f, err := New(opts...)
f, err := New(append(opts, WithSeed(1))...)
if err != nil {
t.Fatalf("%s: New = %v, want a generator holding no data", name, err)
}
@@ -146,7 +146,7 @@ func TestWithDataFS(t *testing.T) {
t.Errorf("nested.x.y = %q, want z", got)
}
bad := fstest.MapFS{"broken.json": {Data: []byte(`{ not json`)}}
if _, err := New(WithDataFS(bad)); err == nil || !strings.Contains(err.Error(), "broken.json") {
if _, err := New(WithSeed(1), WithDataFS(bad)); err == nil || !strings.Contains(err.Error(), "broken.json") {
t.Errorf("New(bad fs) = %v, want an error naming the file", err)
}
}
@@ -154,7 +154,7 @@ func TestWithDataFS(t *testing.T) {
func TestWithDataFSLayersEachModuleOverTheOneBefore(t *testing.T) {
a := fstest.MapFS{"x.json": {Data: []byte(`"a"`)}, "y.json": {Data: []byte(`"a"`)}}
b := fstest.MapFS{"x.json": {Data: []byte(`"b"`)}}
f, err := New(WithDataFS(a, b))
f, err := New(WithSeed(1), WithDataFS(a, b))
if err != nil {
t.Fatalf("New(WithDataFS(a, b)) = %v", err)
}
@@ -165,7 +165,7 @@ func TestWithDataFSLayersEachModuleOverTheOneBefore(t *testing.T) {
func TestWithDataFSRefusesANilModule(t *testing.T) {
var unset fs.FS
if _, err := New(WithDataFS(fstest.MapFS{}, unset)); err == nil || !strings.Contains(err.Error(), "WithDataFS module 2 is nil") {
if _, err := New(WithSeed(1), WithDataFS(fstest.MapFS{}, unset)); err == nil || !strings.Contains(err.Error(), "WithDataFS module 2 is nil") {
t.Errorf("New(WithDataFS(fsys, nil)) = %v, want module 2 named nil", err)
}
}
+19 -19
View File
@@ -97,7 +97,7 @@ func newShippedWhole(t testing.TB, opts ...Option) *Generator {
for _, m := range shippedModules(t) {
modules = append(modules, m.whole(t))
}
f, err := New(append([]Option{WithDataFS(modules...)}, opts...)...)
f, err := New(append([]Option{WithDataFS(modules...), WithSeed(1)}, opts...)...)
if err != nil {
t.Fatalf("New() = %v", err)
}
@@ -223,7 +223,7 @@ func TestEachShippedPackagesModulesHoldWhatItReadsAndRender(t *testing.T) {
if err != nil {
t.Fatal(err)
}
f, err := New(WithDataFS(set...))
f, err := New(WithSeed(1), WithDataFS(set...))
if err != nil {
t.Fatalf("New(%s's Modules) = %v", m.namespace, err)
}
@@ -236,7 +236,7 @@ func TestEachShippedPackagesModulesHoldWhatItReadsAndRender(t *testing.T) {
}
func TestALocaleAloneFailsAtItsAddressNamingTheMissingGeo(t *testing.T) {
f, err := New(WithDataFS(svse.FS))
f, err := New(WithSeed(1), WithDataFS(svse.FS))
if err != nil {
t.Fatalf("New(WithDataFS(svse.FS)) = %v", err)
}
@@ -249,7 +249,7 @@ func TestALocaleAloneFailsAtItsAddressNamingTheMissingGeo(t *testing.T) {
}
func TestAMountedModuleNamesItsRootFolderByItsNamespace(t *testing.T) {
_, err := New(WithDataFS(fstest.MapFS{
_, err := New(WithSeed(1), WithDataFS(fstest.MapFS{
".fejkdata.json": {Data: []byte(`{"namespace": "my.data"}`)},
"t.json": {Data: []byte(`{"format":"{name}","rows":"t.tsv","key":"name"}`)},
}))
@@ -259,7 +259,7 @@ func TestAMountedModuleNamesItsRootFolderByItsNamespace(t *testing.T) {
}
func TestAMountedModuleNamesItsFilesByItsNamespace(t *testing.T) {
_, err := New(WithDataFS(fstest.MapFS{
_, err := New(WithSeed(1), WithDataFS(fstest.MapFS{
".fejkdata.json": {Data: []byte(`{"namespace": "my.data"}`)},
"word.json": {Data: []byte(`{`)},
}))
@@ -281,7 +281,7 @@ func TestANamespaceMountsAModuleUnderIt(t *testing.T) {
"sub/word.json": {Data: []byte(`"hej"`)},
}),
} {
f, err := New(opt)
f, err := New(opt, WithSeed(1))
if err != nil {
t.Fatalf("New(%s) = %v", name, err)
}
@@ -294,7 +294,7 @@ func TestANamespaceMountsAModuleUnderIt(t *testing.T) {
}
func TestNewLoadsNoShippedCategory(t *testing.T) {
f, err := New(withShipped())
f, err := New(withShipped(), WithSeed(1))
if err != nil {
t.Fatalf("New() = %v", err)
}
@@ -338,7 +338,7 @@ func TestReachingACategoryLoadsWhatItReads(t *testing.T) {
absent: []string{"sv_SE.person"},
},
} {
f, err := New(withShipped())
f, err := New(withShipped(), WithSeed(1))
if err != nil {
t.Fatalf("New() = %v", err)
}
@@ -360,7 +360,7 @@ func TestReachingACategoryLoadsWhatItReads(t *testing.T) {
}
func TestADataPathLoadsWhatItReads(t *testing.T) {
f, err := New(withShipped(), WithDataPath(writeData(t, map[string]string{"greeting": `"Hej {/sv_SE.person}!"`})))
f, err := New(withShipped(), WithSeed(1), WithDataPath(writeData(t, map[string]string{"greeting": `"Hej {/sv_SE.person}!"`})))
if err != nil {
t.Fatalf("New() = %v", err)
}
@@ -385,7 +385,7 @@ func TestAReplacementBreakingAShippedReaderFailsItsFirstReach(t *testing.T) {
"sv_SE/last-name.json": {Data: []byte(`"x"`)},
}),
} {
f, err := New(withShipped(), opt)
f, err := New(withShipped(), WithSeed(1), opt)
if err != nil {
t.Fatalf("New(%s) = %v", name, err)
}
@@ -424,7 +424,7 @@ func TestAnIndexedSourceLoadsOnFirstReachLikeTheShippedOne(t *testing.T) {
}
func TestAnIndexedCategoryFailsAtFirstReachAndEveryReachAfter(t *testing.T) {
f, err := New(WithDataFS(fstest.MapFS{
f, err := New(WithSeed(1), WithDataFS(fstest.MapFS{
".fejkdata.json": {Data: []byte(`{"index": {"bad": {"paths": [""]}, "good": {"paths": [""]}}}`)},
"bad.json": {Data: []byte(`"{/nope}"`)},
"good.json": {Data: []byte(`"fine"`)},
@@ -467,7 +467,7 @@ func TestABrokenManifestFailsNewNamingEveryMistake(t *testing.T) {
`{"namespace": "a..b"}`: {`namespace "a..b"`},
`{"index": {"b.x": {"paths": [""]}}, "namespace": "a"}`: {`index entry "b.x" lies outside the namespace "a"`},
} {
_, err := New(WithDataFS(fstest.MapFS{".fejkdata.json": {Data: []byte(manifest)}}))
_, err := New(WithSeed(1), WithDataFS(fstest.MapFS{".fejkdata.json": {Data: []byte(manifest)}}))
for _, w := range want {
if err == nil || !strings.Contains(err.Error(), w) {
t.Errorf("New(manifest %s) = %v, want an error naming %s", manifest, err, w)
@@ -485,7 +485,7 @@ func TestNewMatchesErrLoadOnDataThatFailsToLoad(t *testing.T) {
"a broken category": WithDataPath(writeData(t, map[string]string{"x": `{ not json`})),
"a broken manifest": WithDataFS(fstest.MapFS{".fejkdata.json": {Data: []byte(`{`)}}),
} {
if _, err := New(withShipped(), opt); !errors.Is(err, ErrLoad) {
if _, err := New(withShipped(), WithSeed(1), opt); !errors.Is(err, ErrLoad) {
t.Errorf("New(%s) = %v, want it to match ErrLoad", name, err)
}
}
@@ -494,7 +494,7 @@ func TestNewMatchesErrLoadOnDataThatFailsToLoad(t *testing.T) {
func TestOnDemandRendersAsTheWholeLoad(t *testing.T) {
whole := newShippedWhole(t)
paths := whole.List()
lazy, err := New(withShipped())
lazy, err := New(withShipped(), WithSeed(1))
if err != nil {
t.Fatalf("New() = %v", err)
}
@@ -519,7 +519,7 @@ func TestOnDemandRendersAsTheWholeLoad(t *testing.T) {
func TestEveryShippedCategoryLoadsAlone(t *testing.T) {
for _, p := range sortedNames(shippedIndex(t)) {
f, err := New(withShipped())
f, err := New(withShipped(), WithSeed(1))
if err != nil {
t.Fatalf("New() = %v", err)
}
@@ -530,7 +530,7 @@ func TestEveryShippedCategoryLoadsAlone(t *testing.T) {
}
func TestListRunsBesideAnOnDemandLoad(t *testing.T) {
f, err := New(withShipped())
f, err := New(withShipped(), WithSeed(1))
if err != nil {
t.Fatalf("New() = %v", err)
}
@@ -552,7 +552,7 @@ func TestListRunsBesideAnOnDemandLoad(t *testing.T) {
}
func TestATableWhoseEntryOmitsItsParentFailsAtFirstReach(t *testing.T) {
f, err := New(WithDataFS(fstest.MapFS{
f, err := New(WithSeed(1), WithDataFS(fstest.MapFS{
".fejkdata.json": {Data: []byte(`{"index": {"city": {"paths": ["", "country", "name"]}, "country": {"paths": ["", "code", "name"]}}}`)},
"country.json": {Data: []byte(`{"format":"{name}","rows":"country.tsv","key":"code"}`)},
"country.tsv": {Data: []byte("code\tname\nSE\tSweden\n")},
@@ -598,7 +598,7 @@ func indexEntry(s categorySite) datafiles.IndexEntry {
}
func TestAMountedIndexedCategoryWithNoFileNamesTheManifestBesideItsFiles(t *testing.T) {
f, err := New(WithDataFS(fstest.MapFS{
f, err := New(WithSeed(1), WithDataFS(fstest.MapFS{
".fejkdata.json": {Data: []byte(`{"index": {"my.gone": {"paths": [""]}}, "namespace": "my"}`)},
}))
if err != nil {
@@ -610,7 +610,7 @@ func TestAMountedIndexedCategoryWithNoFileNamesTheManifestBesideItsFiles(t *test
}
func TestAnIndexedCategoryWithNoFileNamesTheManifest(t *testing.T) {
f, err := New(WithDataFS(fstest.MapFS{
f, err := New(WithSeed(1), WithDataFS(fstest.MapFS{
".fejkdata.json": {Data: []byte(`{"index": {"gone": {"paths": [""]}}}`)},
}))
if err != nil {
+9 -9
View File
@@ -165,7 +165,7 @@ func TestTableCellsAreStringNodes(t *testing.T) {
"place.json": `{"format":"{name}","rows":"place.tsv"}`,
"place.tsv": "name\tzip\nA\t{name}\nB\t2\n",
})
if _, err := New(WithDataPath(bad)); err == nil || !strings.Contains(err.Error(), "place.tsv") || !strings.Contains(err.Error(), `no field "name"`) {
if _, err := New(WithSeed(1), WithDataPath(bad)); err == nil || !strings.Contains(err.Error(), "place.tsv") || !strings.Contains(err.Error(), `no field "name"`) {
t.Fatalf("New = %v, want a cell reading a column refused, naming the file", err)
}
}
@@ -327,7 +327,7 @@ func TestTableStepUpRefusals(t *testing.T) {
if _, err := f.Fake(path); err == nil || !strings.Contains(err.Error(), want) {
t.Errorf("Fake(%q) = %v, want an error mentioning %s", path, err, want)
}
_, err := New(WithDataPath(writeFiles(t, with(geo(), map[string]string{
_, err := New(WithSeed(1), WithDataPath(writeFiles(t, with(geo(), map[string]string{
"x.json": `{"format":"{y}","y":"a"}`,
"t.json": strconv.Quote("{/" + path + "}"),
}))))
@@ -335,7 +335,7 @@ func TestTableStepUpRefusals(t *testing.T) {
t.Errorf("{/%s}: New = %v, want an error mentioning %s", path, err, want)
}
}
if _, err := New(WithDataPath(writeFiles(t, map[string]string{"s.json": `{"format":"{a..b}","a":{"format":"{b}","b":"x"}}`}))); err == nil || !strings.Contains(err.Error(), "only from a table's row") {
if _, err := New(WithSeed(1), WithDataPath(writeFiles(t, map[string]string{"s.json": `{"format":"{a..b}","a":{"format":"{b}","b":"x"}}`}))); err == nil || !strings.Contains(err.Error(), "only from a table's row") {
t.Errorf("{a..b} on a field: New = %v, want an error mentioning only from a table's row", err)
}
}
@@ -464,7 +464,7 @@ func TestTableSelectorInAReference(t *testing.T) {
"selector on template": {`"{/x[1].a}"`, "not a table"},
"selector on repeating template": {`"{/rep[1]}"`, "not a table"},
} {
_, err := New(WithDataPath(writeFiles(t, with(files, map[string]string{"bad.json": c.json, "rep.json": `{"format":"x","repeat":2}`}))))
_, err := New(WithSeed(1), WithDataPath(writeFiles(t, with(files, map[string]string{"bad.json": c.json, "rep.json": `{"format":"x","repeat":2}`}))))
if err == nil || !strings.Contains(err.Error(), c.want) {
t.Errorf("%s: New = %v, want an error mentioning %q", name, err, c.want)
}
@@ -595,7 +595,7 @@ func TestTableFences(t *testing.T) {
"a category referencing itself": {map[string]string{"t.json": `{"format":"{a}","rows":"t.tsv"}`, "t.tsv": "a\n{/t.a}\ny\n"}, "cycle"},
}
for name, c := range rejected {
_, err := New(WithDataPath(writeFiles(t, c.files)))
_, err := New(WithSeed(1), WithDataPath(writeFiles(t, c.files)))
if err == nil {
t.Errorf("%s: New = nil error, want it rejected at load", name)
continue
@@ -627,7 +627,7 @@ func TestTableFences(t *testing.T) {
}
}
}
if _, err := New(WithDataFS(os.DirFS(writeFiles(t, base)))); err != nil {
if _, err := New(WithSeed(1), WithDataFS(os.DirFS(writeFiles(t, base)))); err != nil {
t.Fatalf("New(WithDataFS) = %v, want a table loaded from any fs.FS", err)
}
inline := newGenerator(t, writeFiles(t, base))
@@ -1136,7 +1136,7 @@ func TestDatatypeRefusesARowRead(t *testing.T) {
for _, format := range []string{"{/region}", "{/region[01]}"} {
files := with(geo(), map[string]string{"row.json": `{"format":"","col":{"format":"` + format + `","datatype":"integer"}}`})
want := `"{name}" renders a row of region, which is composed text`
if _, err := New(WithDataPath(writeFiles(t, files))); err == nil || !strings.Contains(err.Error(), want) {
if _, err := New(WithSeed(1), WithDataPath(writeFiles(t, files))); err == nil || !strings.Contains(err.Error(), want) {
t.Errorf("%s: New = %v, want an error containing %q", format, err, want)
}
}
@@ -1148,12 +1148,12 @@ func TestATableErrorNamesItsPathAndACellItsLine(t *testing.T) {
"g/t.tsv": "a\tb\nx\t-\ny\t{/nope}\n",
}
want := "g.t.b, line 3: reference {/nope}"
if _, err := New(WithDataPath(writeFiles(t, files))); err == nil || !strings.Contains(err.Error(), want) {
if _, err := New(WithSeed(1), WithDataPath(writeFiles(t, files))); err == nil || !strings.Contains(err.Error(), want) {
t.Errorf("a cell's bad reference: New = %v, want it to contain %q", err, want)
}
files["g/t.json"], files["g/t.tsv"] = `{"format":"{a} {/nope}","rows":"t.tsv","key":"a"}`, "a\tb\nx\t-\ny\t-\n"
want = "g.t: reference {/nope}"
if _, err := New(WithDataPath(writeFiles(t, files))); err == nil || !strings.Contains(err.Error(), want) {
if _, err := New(WithSeed(1), WithDataPath(writeFiles(t, files))); err == nil || !strings.Contains(err.Error(), want) {
t.Errorf("a format's bad reference: New = %v, want it to contain %q", err, want)
}
f := newGenerator(t, writeFiles(t, geo()), WithSeed(1))