Make great documentation goal 1.2, and plan the README's reorganisation and the nested-template gaps #33
@@ -220,8 +220,6 @@ func TestRunMisuse(t *testing.T) {
|
|||||||
stdin string
|
stdin string
|
||||||
args []string
|
args []string
|
||||||
}{
|
}{
|
||||||
{"", nil},
|
|
||||||
{"", []string{"--data-path", svSE}},
|
|
||||||
{"{/person}", []string{"-d", svSE, "word"}},
|
{"{/person}", []string{"-d", svSE, "word"}},
|
||||||
{"", []string{"-d", svSE, "--list", "person"}},
|
{"", []string{"-d", svSE, "--list", "person"}},
|
||||||
{"{/sv_SE.person}", []string{"--no-shipped-data"}},
|
{"{/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"} {
|
for _, stdin := range []string{"", "\n", " \r\n\t"} {
|
||||||
if code, out, errb := runOut(stdin); code != 2 || out != "" || !strings.Contains(errb, "holds no template") {
|
if code, out, errb := runOut(stdin); code != 0 || out != stdin {
|
||||||
t.Errorf("run(%q) = %d, %q, %q; want misuse naming the empty stdin", stdin, code, out, errb)
|
t.Errorf("run(%q) = %d, %q, %q; want the blank template rendered as it is", stdin, code, out, errb)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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) {
|
func TestWalkLabelsWhatACategoryFileGetsWrong(t *testing.T) {
|
||||||
for _, c := range []struct {
|
for _, c := range []struct {
|
||||||
name string
|
name string
|
||||||
|
|||||||
+13
-10
@@ -218,17 +218,20 @@ func TestRecordColumnsReadingOneReferenceLoad(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRecordRejectsAColumnReadingItsOwnRecord(t *testing.T) {
|
func TestRecordColumnReadingItsOwnRecordIsAFreshDraw(t *testing.T) {
|
||||||
for _, c := range []struct{ name, column string }{
|
person := `{"format":"{first} {last}","first":["Ada","Bo"],"last":["Lovelace","Ek"],"other":"{/person.first}"}`
|
||||||
{"a path into itself", `"full":"{/person.first} {/person.last}"`},
|
f := newGenerator(t, writeData(t, map[string]string{"person": person}), WithSeed(1))
|
||||||
{"the record read whole", `"whole":"{/person}"`},
|
apart := false
|
||||||
{"the record as an operand", `"up":"{uppercase(/person)}"`},
|
for i := 0; i < 50 && !apart; i++ {
|
||||||
} {
|
r, err := f.FakeRecord("person")
|
||||||
person := `{"format":"{first} {last}","first":["Ada","Bo"],"last":["Lovelace","Ek"],` + c.column + `}`
|
if err != nil {
|
||||||
_, err := New(WithoutShippedData(), WithDataPath(writeData(t, map[string]string{"person": person})))
|
t.Fatal(err)
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
|
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")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+13
-10
@@ -129,19 +129,22 @@ func TestDotPrefixedDataEntriesAreSkipped(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestReferenceIntoItsOwnCategoryIsRejected pins the unit a category is: a reference
|
func TestAReferenceIntoItsOwnCategoryIsAFreshDraw(t *testing.T) {
|
||||||
// back into it describes a draw other than the fields beside it, whether the format
|
f := newGenerator(t, writeData(t, map[string]string{"cat": `{"format":"{y} {x}","x":"{/cat.y}","y":["1","2"]}`}), WithSeed(1))
|
||||||
// renders that field or not, so it is refused at load rather than left to disagree in
|
seen := map[string]bool{}
|
||||||
// the record view.
|
for i := 0; i < 50; i++ {
|
||||||
func TestReferenceIntoItsOwnCategoryIsRejected(t *testing.T) {
|
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{
|
for name, file := range map[string]string{
|
||||||
"the category whole": `{"format":"hi","x":"see {/cat}"}`,
|
"the category in its format": `{"format":"{/cat}"}`,
|
||||||
"a field of its own": `{"format":"hi","x":"{/cat.y}","y":"1"}`,
|
"a field reading itself": `{"format":"{x}","x":"{/cat.x}"}`,
|
||||||
"a path the format reads": `{"format":"{/cat.y}","y":"1"}`,
|
|
||||||
} {
|
} {
|
||||||
_, err := New(WithoutShippedData(), WithDataPath(writeData(t, map[string]string{"cat": file})))
|
_, err := New(WithoutShippedData(), WithDataPath(writeData(t, map[string]string{"cat": file})))
|
||||||
if err == nil || !strings.Contains(err.Error(), "names the category it sits in") {
|
if err == nil || !strings.Contains(err.Error(), "cycle") {
|
||||||
t.Errorf("%s: New = %v, want the reference into its own category refused", name, err)
|
t.Errorf("%s: New = %v, want the cycle refused", name, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Reading a sibling as a path is the spelling that stays.
|
// Reading a sibling as a path is the spelling that stays.
|
||||||
|
|||||||
+20
-1
@@ -30,6 +30,9 @@ func TestOneItemChoiceIsItsItem(t *testing.T) {
|
|||||||
if r, isTemplate := compiled(t, `[{"format":"","d":"x"}]`).(*template); !isTemplate || !r.isRecord {
|
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")
|
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) {
|
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) {
|
func TestAJSONNumberOrBooleanIsItsText(t *testing.T) {
|
||||||
f := newGenerator(t, writeData(t, map[string]string{
|
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]`,
|
"l": `[1e3]`,
|
||||||
}), WithSeed(1))
|
}), WithSeed(1))
|
||||||
if v := fake(t, f, "n"); v != "5 1.50 12345678901234567890 true" {
|
if v := fake(t, f, "n"); v != "5 1.50 12345678901234567890 true" {
|
||||||
|
|||||||
+1
-1
@@ -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 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"`},
|
"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 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 {
|
for name, c := range rejected {
|
||||||
_, err := New(WithoutShippedData(), WithDataPath(writeFiles(t, c.files)))
|
_, err := New(WithoutShippedData(), WithDataPath(writeFiles(t, c.files)))
|
||||||
|
|||||||
Reference in New Issue
Block a user