Test a generator with no data, a repeat or count of 0 rendering nothing, and a name a choice's item binds and reads
This commit is contained in:
+1
-4
@@ -203,7 +203,7 @@ func mustPanic(t *testing.T, name string, call func()) {
|
||||
}
|
||||
|
||||
func TestClassBuiltinArgs(t *testing.T) {
|
||||
for _, bad := range []string{`"{digits(0)}"`, `"{digits(2000000000)}"`, `"{upper(-1)}"`, `"{lower(x)}"`, `"{digits()}"`, `"{upper(1,2)}"`} {
|
||||
for _, bad := range []string{`"{digits(2000000000)}"`, `"{upper(-1)}"`, `"{lower(x)}"`, `"{digits()}"`, `"{upper(1,2)}"`} {
|
||||
if _, err := resolved(t, bad); err == nil {
|
||||
t.Errorf("compile(%s) = nil error, want the arg rejected", bad)
|
||||
}
|
||||
@@ -379,13 +379,10 @@ func TestFunctionTokenLuhn(t *testing.T) {
|
||||
|
||||
func TestBuiltinCompileErrors(t *testing.T) {
|
||||
for _, bad := range []string{
|
||||
`"{digits(0)}"`, // count must be positive
|
||||
`"{upper(x)}"`, // count must be an integer
|
||||
`"{int(a,b)}"`, // non-integer args
|
||||
`"{int(5,1)}"`, // min > max
|
||||
`"{hex(0)}"`, // count must be positive
|
||||
`"{nanoid(-1)}"`, // negative count
|
||||
`"{base64(0)}"`, // count must be positive
|
||||
`"{float(1,2,-1)}"`, // negative decimals
|
||||
`"{float(NaN,NaN,2)}"`, // bounds must be finite
|
||||
`"{float(Inf,Inf,2)}"`, // same-sign infinities
|
||||
|
||||
@@ -333,3 +333,9 @@ func TestATypedColumnProvesACalcOverAName(t *testing.T) {
|
||||
t.Fatalf("New = %v, want the typed column refused over an operand that is not always a number", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestARepeatOfZeroIsNoConstant(t *testing.T) {
|
||||
if got := mustRender(t, engine(1), `{"format":"{calc(x / y)}","x":"1","y":{"format":"0","repeat":0}}`); got != "NaN" {
|
||||
t.Errorf("a divisor rendering nothing = %q, want NaN", got)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -516,9 +516,11 @@ func TestRunNoShippedData(t *testing.T) {
|
||||
if code != 0 || strings.TrimSpace(out) == "" {
|
||||
t.Errorf("run = %d, out=%q", code, out)
|
||||
}
|
||||
code, _, errb = runOut("{/sv_SE.person}", "--no-shipped-data")
|
||||
if code != 2 || !strings.Contains(errb, "--no-shipped-data needs at least one --data-path") {
|
||||
t.Errorf("--no-shipped-data alone = %d, %q, want misuse naming --data-path", code, errb)
|
||||
if code, out, errb := runOut("{digits(3)}", "--no-shipped-data"); code != 0 || len(out) != 3 {
|
||||
t.Errorf("--no-shipped-data alone = %d, %q, %q, want a template reading no data rendered", code, out, errb)
|
||||
}
|
||||
if code, _, errb := runOut("{/sv_SE.person}", "--no-shipped-data"); code != 2 || !strings.Contains(errb, "no entry") {
|
||||
t.Errorf("--no-shipped-data alone = %d, %q, want a reference to nothing refused", code, errb)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -104,7 +104,7 @@ func TestFakeTemplateErrors(t *testing.T) {
|
||||
}{
|
||||
{`{"x":"Q"}`, "missing string \"format\""},
|
||||
{`"{x}"`, `no field "x"`},
|
||||
{`"{digits(0)}"`, "must be positive"},
|
||||
{`"{digits(-1)}"`, "must not be negative"},
|
||||
{`name: {/no.such.path}`, "no entry"},
|
||||
{`name: {..nope}`, "write {/nope}"},
|
||||
} {
|
||||
|
||||
@@ -59,12 +59,6 @@ func TestNewLoadsAnyDirName(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewEmptyDirErrors(t *testing.T) {
|
||||
if _, err := New(WithoutShippedData(), WithDataPath(writeData(t, nil))); err == nil {
|
||||
t.Fatal("New(empty dir) = nil error")
|
||||
}
|
||||
}
|
||||
|
||||
// TestFoldersBecomeDotPaths checks the core of the new model: a subfolder is a
|
||||
// namespace, so data/<loc>/person.json is reachable as "<loc>.person".
|
||||
func TestFoldersBecomeDotPaths(t *testing.T) {
|
||||
|
||||
+17
-1
@@ -166,6 +166,22 @@ func TestANameInAnInlineTemplate(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestAChoiceItemKeepsTheNamesItBinds(t *testing.T) {
|
||||
f, n, both := engine(1), compiled(t, `{"format":"{x}","x":[{"format":"{v as w}{w}{w}","v":["a","b"]},"c"]}`), 0
|
||||
for i := 0; i < 100; i++ {
|
||||
switch renderOnce(f.drawState, n) {
|
||||
case "aa", "bb":
|
||||
both++
|
||||
case "c":
|
||||
default:
|
||||
t.Fatal("a name bound in a choice's item read two picks")
|
||||
}
|
||||
}
|
||||
if both == 0 {
|
||||
t.Error("100 renders never drew the item binding a name")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNameErrors(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
@@ -177,7 +193,7 @@ func TestNameErrors(t *testing.T) {
|
||||
{"bound inside a repeat written first", map[string]string{"word": `["a","b"]`, "card": `{"format":"{a}{z}","a":{"format":"{/word as w}{w}","repeat":2},"z":"{/word as w}{w}"}`},
|
||||
`name "w" is bound outside this repeat too`},
|
||||
{"bound in a choice's item", map[string]string{"word": `["a","b"]`, "card": `{"format":"{x}{w}","x":["{/word as w}","b"]}`},
|
||||
`a choice's item binds no name`},
|
||||
`name "w" is bound at field "x", inside an item of a choice, which a read outside that item cannot see`},
|
||||
{"bound outside the repeat too", map[string]string{"word": `["a","b"]`, "card": `{"format":"{/word as w}{x}","x":{"format":"{/word as w}{w}","repeat":2}}`},
|
||||
`name "w" is bound outside this repeat too`},
|
||||
{"a field too", map[string]string{"word": `["a","b"]`, "card": `{"format":"{/word as w}{w}","w":"x"}`},
|
||||
|
||||
@@ -53,7 +53,6 @@ func TestNodeCompileErrors(t *testing.T) {
|
||||
`[{"format":"A","weight":0},{"format":"B","weight":0}]`, // weights sum to zero
|
||||
`[{"format":"A","weight":1e308},{"format":"B","weight":1e308}]`, // weights overflow to +Inf
|
||||
`{"format":"A","weight":"heavy"}`, // non-numeric weight
|
||||
`{"format":"x","repeat":0}`, // repeat below 1
|
||||
`{"format":"x","repeat":-2}`, // negative repeat
|
||||
`{"format":"x","repeat":1.5}`, // non-integer repeat
|
||||
`{"format":"x","repeat":"two"}`, // non-numeric repeat
|
||||
|
||||
+15
-5
@@ -1,7 +1,6 @@
|
||||
package fejkdata
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"reflect"
|
||||
"slices"
|
||||
"strings"
|
||||
@@ -54,10 +53,21 @@ func TestUserDataMayReferenceShipped(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestWithoutShippedDataNeedsASource(t *testing.T) {
|
||||
_, err := New(WithoutShippedData())
|
||||
if err == nil || !strings.Contains(err.Error(), "WithDataPath") || !errors.Is(err, ErrNoData) {
|
||||
t.Fatalf("New(WithoutShippedData()) = %v, want ErrNoData naming WithDataPath", err)
|
||||
func TestAGeneratorWithNoDataRendersWhatReadsNone(t *testing.T) {
|
||||
for name, opts := range map[string][]Option{
|
||||
"no source": {WithoutShippedData()},
|
||||
"empty folder": {WithoutShippedData(), WithDataPath(t.TempDir())},
|
||||
} {
|
||||
f, err := New(opts...)
|
||||
if err != nil {
|
||||
t.Fatalf("%s: New = %v, want a generator holding no data", name, err)
|
||||
}
|
||||
if v, err := f.FakeTemplate("{digits(3)}"); err != nil || len(v) != 3 {
|
||||
t.Errorf("%s: FakeTemplate = %q, %v, want three digits", name, v, err)
|
||||
}
|
||||
if _, err := f.Fake("x"); err == nil || !strings.Contains(err.Error(), "no entry") {
|
||||
t.Errorf("%s: Fake(x) = %v, want a reference to nothing refused", name, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+3
-1
@@ -51,7 +51,9 @@ func TestAPartWithNoEffectRendersAsWithoutIt(t *testing.T) {
|
||||
`{"format":"{word as w}x","word":["a","b"]}`: `"x"`,
|
||||
`null`: `""`,
|
||||
`{"format":"{p}","p":{"format":"{x}","x":[null,"a"]}}`: `{"format":"{p}","p":{"format":"{x}","x":["","a"]}}`,
|
||||
`"{int(5,5)}"`: `"5"`,
|
||||
`"{int(5,5)}"`: `"5"`,
|
||||
`{"format":"{x}","x":["a","b"],"repeat":0}`: `""`,
|
||||
`"{digits(0)}{upper(0)}{lower(0)}{hex(0)}{base64(0)}{nanoid(0)}"`: `""`,
|
||||
`"{float(1,1,2)}"`: `"1.00"`,
|
||||
`"{date(1990-01-01,1990-01-01,'2006-01-02')}"`: `"1990-01-01"`,
|
||||
`"{date(1990-01-01,1990-12-31,'x')}"`: `"x"`,
|
||||
|
||||
Reference in New Issue
Block a user