Make great documentation goal 1.2, and plan the README's reorganisation and the nested-template gaps #33
+15
-10
@@ -22,21 +22,26 @@ func grammarLoneReference(text string) (string, bool) {
|
||||
|
||||
func TestLoneReferenceAgreesWithTheGrammar(t *testing.T) {
|
||||
for _, text := range []string{
|
||||
"{/sv_SE.person}",
|
||||
" {/x}",
|
||||
"x",
|
||||
"{.x}",
|
||||
"{/.x}",
|
||||
"{//x}",
|
||||
"{/a...b}",
|
||||
"{/a..b}",
|
||||
"{/a..}",
|
||||
"{/a.[x]}",
|
||||
"{/a.}",
|
||||
"{/a|/b}",
|
||||
"{/a}{/b}",
|
||||
"{/misc.currency[US Dollar (Next day)]}",
|
||||
"{/sv_SE.person}",
|
||||
"{/t[a as b].c}",
|
||||
"{/t[f(x)]}",
|
||||
"{/a}{/b}",
|
||||
"{/x as p}",
|
||||
"{/x(1)}",
|
||||
"{/x}}",
|
||||
"{/}",
|
||||
"{/.x}",
|
||||
" {/x}",
|
||||
"{/a|/b}",
|
||||
"{/x as p}",
|
||||
"{//x}",
|
||||
"{/x(1)}",
|
||||
"{.x}",
|
||||
"x",
|
||||
} {
|
||||
path, lone := loneReference(text)
|
||||
want, wantLone := grammarLoneReference(text)
|
||||
|
||||
@@ -495,8 +495,8 @@ func TestRunTemplateMisuse(t *testing.T) {
|
||||
"42": "number",
|
||||
"42\n": "number",
|
||||
"true\n": "boolean",
|
||||
"null\n": "only null",
|
||||
" null ": "only null",
|
||||
"null\n": `write ""`,
|
||||
" null ": `write ""`,
|
||||
"{//sv_SE.person}": "write {/sv_SE.person}",
|
||||
} {
|
||||
code, out, errb := runOut(stdin, "--seed", "1")
|
||||
|
||||
+3
-1
@@ -30,7 +30,9 @@ func TestDatatypeSitsOnlyInAColumn(t *testing.T) {
|
||||
`{"format":"{int(1,9)}","datatype":"integer"}`: "datatype only types a record column",
|
||||
`[{"format":"1","datatype":"integer"},"x"]`: "datatype only types a record column",
|
||||
`{"format":"{p}","p":{"format":"{n}","n":{"format":"1","datatype":"integer"}}}`: "datatype only types a record column",
|
||||
`{"format":"{n}","repeat":2,"n":{"format":"1","datatype":"integer"}}`: "datatype only types a record column",
|
||||
`{"format":"{n}","repeat":2,"n":{"format":"1","datatype":"integer"}}`: `so it has no effect here; drop "datatype"`,
|
||||
`null`: `so write ""`,
|
||||
`{"format":"{p}","p":{"format":"{x}","x":[null,"a"]}}`: `so write ""`,
|
||||
} {
|
||||
if _, err := resolved(t, src); err == nil || !strings.Contains(err.Error(), want) {
|
||||
t.Errorf("compile(%s) = %v, want an error containing %q", src, err, want)
|
||||
|
||||
+5
-5
@@ -226,23 +226,23 @@ func TestNewErrors(t *testing.T) {
|
||||
}{
|
||||
"separator without repeat": {
|
||||
map[string]string{"a": `{"format":"{x}","x":"1","separator":","}`},
|
||||
"has no effect without a repeat above 1",
|
||||
`drop "separator"`,
|
||||
},
|
||||
"separator with an explicit repeat of 1": {
|
||||
map[string]string{"a": `{"format":"{x}","x":"1","separator":","}`},
|
||||
"has no effect without a repeat above 1",
|
||||
`drop "separator"`,
|
||||
},
|
||||
"weight outside a choice": {
|
||||
map[string]string{"a": `{"format":"x","weight":5}`},
|
||||
"weight only skews a choice's items",
|
||||
`drop "weight"`,
|
||||
},
|
||||
"non-numeric weight outside a choice": {
|
||||
map[string]string{"a": `{"format":"x","weight":"bad"}`},
|
||||
"weight only skews a choice's items",
|
||||
"takes a number, not a string",
|
||||
},
|
||||
"weight used as a field": {
|
||||
map[string]string{"a": `{"format":"{name} {weight}kg","name":"Anvil","weight":["7"]}`},
|
||||
"can never be a field",
|
||||
`a field cannot be named "weight"`,
|
||||
},
|
||||
"an option name used as a token": {
|
||||
map[string]string{"a": `"{weight}"`},
|
||||
|
||||
@@ -192,6 +192,12 @@ func TestNameErrors(t *testing.T) {
|
||||
`no field "zz"`},
|
||||
{"read by nothing", map[string]string{"word": `["a","b"]`, "card": `"{/word as w}"`},
|
||||
`nothing reads name "w"`},
|
||||
{"one arm read twice in an alternation", map[string]string{"cat": `{"format":"{w|w}","w":["a","b"]}`, "card": `"{/cat as n}{n} {n.w}"`},
|
||||
""},
|
||||
{"a field and a path into it in one alternation", map[string]string{"cat": `{"format":"{w|w.x}","w":{"format":"{x}","x":["a","b"]}}`, "card": `"{/cat as n}{n} {n.w}"`},
|
||||
""},
|
||||
{"one field read in two alternations", map[string]string{"cat": `{"format":"{w|v}{w|v}","w":["a","b"],"v":["c","d"]}`, "card": `"{/cat as n}{n} {n.w}"`},
|
||||
`renders field "w" twice`},
|
||||
{"read in a repeat", map[string]string{"nm.json": `{"format":"{first}","rows":"nm.tsv"}`, "nm.tsv": "first\tlast\nAda\tByron\nBo\tEk\n", "person": `{"format":"{first} {last}","first":"{/nm.first}","last":"{/nm.last}"}`, "card": `{"format":"{/person as p}{each}","each":{"format":"{p.first}","repeat":2}}`},
|
||||
""},
|
||||
{"a misspelt name", map[string]string{"word": `["a","b"]`, "card": `"{/word as p}{p}{p}{pp}"`},
|
||||
|
||||
+17
-5
@@ -29,8 +29,18 @@ 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":2}]`); err == nil || !strings.Contains(err.Error(), "no effect here") {
|
||||
t.Errorf("a weight on a one-item choice's item = %v, want it refused as doing nothing", err)
|
||||
}
|
||||
|
||||
func TestAWeightWithNothingToDrawAgainstIsRejected(t *testing.T) {
|
||||
for _, src := range []string{
|
||||
`{"format":"a","weight":2}`,
|
||||
`{"format":"{x}","x":{"format":"a","weight":2}}`,
|
||||
`[{"format":"a","weight":2}]`,
|
||||
} {
|
||||
_, err := resolved(t, src)
|
||||
if err == nil || !strings.Contains(err.Error(), `drop "weight"`) || strings.Contains(err.Error(), "can never be a field") || strings.Contains(err.Error(), "only skews a choice's items") {
|
||||
t.Errorf("compile(%s) = %v, want the weight refused as drawn against nothing, naming the drop", src, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,7 +63,7 @@ func TestARepeatedItemCountsAsWritten(t *testing.T) {
|
||||
|
||||
func TestASeparatorWithoutARepeatIsRejected(t *testing.T) {
|
||||
for src, want := range map[string]string{
|
||||
`{"format":"{x}","x":"v","separator":","}`: "separator",
|
||||
`{"format":"{x}","x":"v","separator":","}`: `drop "separator"`,
|
||||
} {
|
||||
if _, err := resolved(t, src); err == nil || !strings.Contains(err.Error(), want) {
|
||||
t.Errorf("compile(%s) = %v, want an error mentioning %s", src, err, want)
|
||||
@@ -69,8 +79,10 @@ func TestADefaultWrittenOutIsTheDefault(t *testing.T) {
|
||||
`{"format":"{x}","x":["a","b"],"repeat":1}`: `{"format":"{x}","x":["a","b"]}`,
|
||||
`{"format":"{x}","x":["a","b"],"repeat":2,"separator":""}`: `{"format":"{x}","x":["a","b"],"repeat":2}`,
|
||||
`{"format":"","n":{"format":"{x}","x":["1","2"],"datatype":"string"}}`: `{"format":"","n":{"format":"{x}","x":["1","2"]}}`,
|
||||
`null`: `""`,
|
||||
`{"format":"{p}","p":{"format":"{x}","x":[null,"a"]}}`: `{"format":"{p}","p":{"format":"{x}","x":["","a"]}}`,
|
||||
`{"format":"a","weight":1}`: `"a"`,
|
||||
`[{"format":"a","weight":1}]`: `"a"`,
|
||||
`{"format":"{x}","x":{"format":"a","weight":1}}`: `{"format":"{x}","x":"a"}`,
|
||||
`{"format":"{x}","x":["a","b"],"separator":""}`: `{"format":"{x}","x":["a","b"]}`,
|
||||
} {
|
||||
sameRenders(t, long, short)
|
||||
}
|
||||
|
||||
+14
-4
@@ -243,6 +243,16 @@ func TestFakeStructReadsAPathInEachSpelling(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestFakeStructTakesTheDatatypeItsGoTypeSets(t *testing.T) {
|
||||
v := struct {
|
||||
N int `fake:"{\"format\":\"{int(1,9)}\",\"datatype\":\"integer\"}"`
|
||||
S string `fake:"{\"format\":\"x\",\"datatype\":\"string\"}"`
|
||||
}{}
|
||||
if err := structData(t).FakeStruct(&v); err != nil || v.N < 1 || v.N > 9 || v.S != "x" {
|
||||
t.Errorf("FakeStruct = %+v, %v, want each tag's datatype taken as its Go type's", v, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFakeStructErrors(t *testing.T) {
|
||||
f := structData(t)
|
||||
for _, c := range []struct {
|
||||
@@ -267,11 +277,11 @@ func TestFakeStructErrors(t *testing.T) {
|
||||
A structPlace `fake:"place"`
|
||||
}{}, ".A: a struct field fills from the tags on its own fields"},
|
||||
{&struct {
|
||||
A int `fake:"{\"format\":\"{int(1,9)}\",\"datatype\":\"integer\"}"`
|
||||
}{}, `its Go type int sets the datatype; drop "datatype"`},
|
||||
A int `fake:"{\"format\":\"{int(1,9)}\",\"datatype\":\"number\"}"`
|
||||
}{}, `its Go type int sets the datatype integer; drop "datatype"`},
|
||||
{&struct {
|
||||
A string `fake:"{\"format\":\"x\",\"datatype\":\"string\"}"`
|
||||
}{}, `its Go type string sets the datatype; drop "datatype"`},
|
||||
A string `fake:"{\"format\":\"1\",\"datatype\":\"integer\"}"`
|
||||
}{}, `its Go type string sets the datatype string; drop "datatype"`},
|
||||
{&struct {
|
||||
A int `fake:"[null,\"{int(1,9)}\"]"`
|
||||
}{}, "can draw null, which int cannot hold; make it *int"},
|
||||
|
||||
Reference in New Issue
Block a user