From dd09d7ae8258e577c369b90a4387d12c2ef90daf Mon Sep 17 00:00:00 2001 From: Lilleman auf Larv Date: Thu, 8 Oct 2026 11:48:08 +0200 Subject: [PATCH] Test blank stdin rendering, a category reading itself as a fresh draw, a bare number or boolean refused in a record column, a one-item choice of weight 0 refused, and a hidden rows file read --- cmd/fejkdata/main_test.go | 8 +++----- internal/datafiles/datafiles_test.go | 12 ++++++++++++ record_test.go | 23 +++++++++++++---------- reference_test.go | 23 +++++++++++++---------- spellings_test.go | 21 ++++++++++++++++++++- table_test.go | 2 +- 6 files changed, 62 insertions(+), 27 deletions(-) diff --git a/cmd/fejkdata/main_test.go b/cmd/fejkdata/main_test.go index b26f33b..c3dbc0b 100644 --- a/cmd/fejkdata/main_test.go +++ b/cmd/fejkdata/main_test.go @@ -220,8 +220,6 @@ func TestRunMisuse(t *testing.T) { stdin string args []string }{ - {"", nil}, - {"", []string{"--data-path", svSE}}, {"{/person}", []string{"-d", svSE, "word"}}, {"", []string{"-d", svSE, "--list", "person"}}, {"{/sv_SE.person}", []string{"--no-shipped-data"}}, @@ -313,10 +311,10 @@ func TestRunRendersExactlyWhatIsSent(t *testing.T) { } } -func TestRunRefusesBlankStdin(t *testing.T) { +func TestRunRendersBlankStdin(t *testing.T) { for _, stdin := range []string{"", "\n", " \r\n\t"} { - if code, out, errb := runOut(stdin); code != 2 || out != "" || !strings.Contains(errb, "holds no template") { - t.Errorf("run(%q) = %d, %q, %q; want misuse naming the empty stdin", stdin, code, out, errb) + if code, out, errb := runOut(stdin); code != 0 || out != stdin { + t.Errorf("run(%q) = %d, %q, %q; want the blank template rendered as it is", stdin, code, out, errb) } } } diff --git a/internal/datafiles/datafiles_test.go b/internal/datafiles/datafiles_test.go index f93d99a..0adb691 100644 --- a/internal/datafiles/datafiles_test.go +++ b/internal/datafiles/datafiles_test.go @@ -86,6 +86,18 @@ func TestWalkIgnoresARowsFileNoCategoryNames(t *testing.T) { } } +func TestARowsFileMayBeHidden(t *testing.T) { + var rows string + err := Source{fsys: fstest.MapFS{"a.json": {Data: []byte(`"x"`)}, ".a.tsv": {Data: []byte("key\nA\n")}}}.Walk(func(c Category) error { + var err error + rows, err = c.ReadRows(".a.tsv") + return err + }) + if err != nil || rows != "key\nA\n" { + t.Errorf("Walk = %v, read %q, want the hidden rows file read", err, rows) + } +} + func TestWalkLabelsWhatACategoryFileGetsWrong(t *testing.T) { for _, c := range []struct { name string diff --git a/record_test.go b/record_test.go index dd9f0ac..3ecd3c5 100644 --- a/record_test.go +++ b/record_test.go @@ -218,17 +218,20 @@ func TestRecordColumnsReadingOneReferenceLoad(t *testing.T) { } } -func TestRecordRejectsAColumnReadingItsOwnRecord(t *testing.T) { - for _, c := range []struct{ name, column string }{ - {"a path into itself", `"full":"{/person.first} {/person.last}"`}, - {"the record read whole", `"whole":"{/person}"`}, - {"the record as an operand", `"up":"{uppercase(/person)}"`}, - } { - person := `{"format":"{first} {last}","first":["Ada","Bo"],"last":["Lovelace","Ek"],` + c.column + `}` - _, err := New(WithoutShippedData(), WithDataPath(writeData(t, map[string]string{"person": person}))) - if err == nil || !strings.Contains(err.Error(), "names the category it sits in") { - t.Errorf("%s: New = %v, want it refused at load; the column would contradict the columns beside it", c.name, err) +func TestRecordColumnReadingItsOwnRecordIsAFreshDraw(t *testing.T) { + person := `{"format":"{first} {last}","first":["Ada","Bo"],"last":["Lovelace","Ek"],"other":"{/person.first}"}` + f := newGenerator(t, writeData(t, map[string]string{"person": person}), WithSeed(1)) + apart := false + for i := 0; i < 50 && !apart; i++ { + r, err := f.FakeRecord("person") + if err != nil { + t.Fatal(err) } + c := r.Columns() + apart = c[0].Value != c[2].Value + } + if !apart { + t.Error("other matched first in 50 records, want a draw of its own") } } diff --git a/reference_test.go b/reference_test.go index 8643a79..866a8dc 100644 --- a/reference_test.go +++ b/reference_test.go @@ -129,19 +129,22 @@ func TestDotPrefixedDataEntriesAreSkipped(t *testing.T) { } } -// TestReferenceIntoItsOwnCategoryIsRejected pins the unit a category is: a reference -// back into it describes a draw other than the fields beside it, whether the format -// renders that field or not, so it is refused at load rather than left to disagree in -// the record view. -func TestReferenceIntoItsOwnCategoryIsRejected(t *testing.T) { +func TestAReferenceIntoItsOwnCategoryIsAFreshDraw(t *testing.T) { + f := newGenerator(t, writeData(t, map[string]string{"cat": `{"format":"{y} {x}","x":"{/cat.y}","y":["1","2"]}`}), WithSeed(1)) + seen := map[string]bool{} + for i := 0; i < 50; i++ { + seen[fake(t, f, "cat")] = true + } + if !seen["1 2"] && !seen["2 1"] { + t.Errorf("cat drew %v in 50 renders, want x a draw apart from y", seen) + } for name, file := range map[string]string{ - "the category whole": `{"format":"hi","x":"see {/cat}"}`, - "a field of its own": `{"format":"hi","x":"{/cat.y}","y":"1"}`, - "a path the format reads": `{"format":"{/cat.y}","y":"1"}`, + "the category in its format": `{"format":"{/cat}"}`, + "a field reading itself": `{"format":"{x}","x":"{/cat.x}"}`, } { _, err := New(WithoutShippedData(), WithDataPath(writeData(t, map[string]string{"cat": file}))) - if err == nil || !strings.Contains(err.Error(), "names the category it sits in") { - t.Errorf("%s: New = %v, want the reference into its own category refused", name, err) + 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. diff --git a/spellings_test.go b/spellings_test.go index b15b203..ddd3b6e 100644 --- a/spellings_test.go +++ b/spellings_test.go @@ -30,6 +30,9 @@ func TestOneItemChoiceIsItsItem(t *testing.T) { if r, isTemplate := compiled(t, `[{"format":"","d":"x"}]`).(*template); !isTemplate || !r.isRecord { t.Error("a one-item choice of a record is no record, want the record it holds") } + if _, err := resolved(t, `[{"format":"a","weight":0}]`); err == nil || !strings.Contains(err.Error(), "every weight is 0") { + t.Errorf("a one-item choice of weight 0 = %v, want it refused as having nothing to draw", err) + } } func TestAPartWithNoEffectRendersAsWithoutIt(t *testing.T) { @@ -70,9 +73,25 @@ func TestAPartWithNoEffectRendersAsWithoutIt(t *testing.T) { } } +func TestAJSONNumberOrBooleanInARecordColumnIsRefused(t *testing.T) { + for src, want := range map[string][]string{ + `{"format":"","n":5}`: {`"5"`, `{"format":"5","datatype":"integer"}`}, + `{"format":"","n":1.50}`: {`"1.50"`, `{"format":"1.50","datatype":"number"}`}, + `{"format":"","b":true}`: {`"true"`, `{"format":"true","datatype":"boolean"}`}, + `{"format":"","n":[5,"x"]}`: {`"5"`, `{"format":"5","datatype":"integer"}`}, + } { + _, err := resolved(t, src) + for _, w := range want { + if err == nil || !strings.Contains(err.Error(), w) { + t.Errorf("compile(%s) = %v, want both spellings, %s among them", src, err, w) + } + } + } +} + func TestAJSONNumberOrBooleanIsItsText(t *testing.T) { f := newGenerator(t, writeData(t, map[string]string{ - "n": `{"format":"{a} {b} {c} {d}","a":5,"b":1.50,"c":12345678901234567890,"d":true}`, + "n": `{"format":"{x}","x":{"format":"{a} {b} {c} {d}","a":5,"b":1.50,"c":12345678901234567890,"d":true}}`, "l": `[1e3]`, }), WithSeed(1)) if v := fake(t, f, "n"); v != "5 1.50 12345678901234567890 true" { diff --git a/table_test.go b/table_test.go index 368e934..ddd4362 100644 --- a/table_test.go +++ b/table_test.go @@ -590,7 +590,7 @@ func TestTableFences(t *testing.T) { "format names no column": {map[string]string{"t.json": `{"format":"{b}","rows":"t.tsv"}`, "t.tsv": "a\nx\ny\n"}, `no column "b"`}, "format reads into a column": {map[string]string{"t.json": `{"format":"{a.x}","rows":"t.tsv"}`, "t.tsv": "a\nx\ny\n"}, `"a"`}, "a reference into a column": {with(base, map[string]string{"t.json": `"{/region.name.x}"`}), "column"}, - "a category referencing itself": {map[string]string{"t.json": `{"format":"{a}","rows":"t.tsv"}`, "t.tsv": "a\n{/t.a}\ny\n"}, "names the category it sits in"}, + "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(WithoutShippedData(), WithDataPath(writeFiles(t, c.files)))