diff --git a/builtins_test.go b/builtins_test.go index b19c95d..ee72939 100644 --- a/builtins_test.go +++ b/builtins_test.go @@ -142,7 +142,7 @@ func TestBuiltinArgLimits(t *testing.T) { `{"format":"{x}","x":"1","repeat":2000000000}`, // repeat -> multi-GB join } for _, tmpl := range bad { - if _, err := compile(parse(t, tmpl)); err == nil { + if _, err := linked(t, tmpl); err == nil { t.Errorf("compile(%s) = nil error, want a limit rejection", tmpl) } } @@ -226,12 +226,12 @@ 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)}"`} { - if _, err := compile(parse(t, bad)); err == nil { + if _, err := linked(t, bad); err == nil { t.Errorf("compile(%s) = nil error, want the arg rejected", bad) } } for _, ok := range []string{`"{digits(1048576)}"`, `"{upper(1)}"`, `"{lower(26)}"`} { - if _, err := compile(parse(t, ok)); err != nil { + if _, err := linked(t, ok); err != nil { t.Errorf("compile(%s) = %v", ok, err) } } @@ -313,7 +313,7 @@ func TestBuiltinDateArgs(t *testing.T) { `"{time('x')}"`: "text", `"{date(1990-01-01,1990-12-31,'15:04')}"`: "time('15:04')", } { - _, err := compile(parse(t, tmpl)) + _, err := linked(t, tmpl) if err == nil || !strings.Contains(err.Error(), want) { t.Errorf("compile(%s) = %v, want an error mentioning %q", tmpl, err, want) } @@ -427,7 +427,7 @@ func TestBuiltinCompileErrors(t *testing.T) { `"{iban(US)}"`, // unsupported country `"{seq(a,b)}"`, // seq takes at most one name } { - if _, err := compile(parse(t, bad)); err == nil { + if _, err := linked(t, bad); err == nil { t.Errorf("compile(%s) = nil error, want error", bad) } } @@ -441,7 +441,7 @@ func TestArgErrorsNameTheSpelling(t *testing.T) { `"{hex(99999999999999999999)}"`: "exceeds the maximum", `"{int(007,9)}"`: "write 7", } { - if _, err := compile(parse(t, src)); err == nil || !strings.Contains(err.Error(), want) { + if _, err := linked(t, src); err == nil || !strings.Contains(err.Error(), want) { t.Errorf("compile(%s) = %v, want an error saying %q", src, err, want) } } diff --git a/calc_test.go b/calc_test.go index 0ae7cd8..a43c159 100644 --- a/calc_test.go +++ b/calc_test.go @@ -229,7 +229,7 @@ func TestCalcOverANeverNumericOperandIsRejected(t *testing.T) { `{"format":"{calc(x * 2)}","x":["a","b"]}`: `"x"`, `{"format":"{calc(x + y)}","x":"1","y":"{{2}}"}`: `"{2}"`, } { - _, err := compile(parse(t, src)) + _, err := linked(t, src) if err == nil || !strings.Contains(err.Error(), want) || !strings.Contains(err.Error(), "never a number") { t.Errorf("compile(%s) = %v, want the operand rejected naming %s", src, err, want) } @@ -240,7 +240,7 @@ func TestCalcOverANeverNumericOperandIsRejected(t *testing.T) { `{"format":"{calc(x * 2)}","x":["1","abc"]}`, `{"format":"{calc(x * 2)}","x":"{digits(2)}"}`, } { - if _, err := compile(parse(t, ok)); err != nil { + if _, err := linked(t, ok); err != nil { t.Errorf("compile(%s) = %v, want it accepted", ok, err) } } @@ -255,7 +255,7 @@ func TestCalcConstantZeroDivisorIsRejected(t *testing.T) { `{"format":"{calc((a/0)+b)}","a":"1","b":"2"}`: "divides by 0", `{"format":"{calc(a/-0)}","a":"1"}`: "divides by -0", } { - if _, err := compile(parse(t, src)); err == nil || !strings.Contains(err.Error(), want) { + if _, err := linked(t, src); err == nil || !strings.Contains(err.Error(), want) { t.Errorf("compile(%s) = %v, want the constant zero divisor rejected naming %q", src, err, want) } } @@ -284,7 +284,7 @@ func TestCalcCompileErrors(t *testing.T) { `"{calc(1, x)}"`, // decimals arg not an integer `"{calc(1, -1)}"`, // decimals negative } { - if _, err := compile(parse(t, bad)); err == nil { + if _, err := linked(t, bad); err == nil { t.Errorf("compile(%s) = nil error, want error", bad) } } diff --git a/datatype_test.go b/datatype_test.go index 61143b7..46824bb 100644 --- a/datatype_test.go +++ b/datatype_test.go @@ -18,7 +18,7 @@ func TestDatatypeAndNullSitOnlyInAColumn(t *testing.T) { `{"format":"","age":[null,{"format":"{int(18,99)}","datatype":"integer","weight":9}]}`, `{"format":"","pick":[[null,"a"],"b"]}`, } { - if _, err := compile(parse(t, src)); err != nil { + if _, err := linked(t, src); err != nil { t.Errorf("compile(%s) = %v, want a column to take a datatype and null", src, err) } } @@ -32,7 +32,7 @@ func TestDatatypeAndNullSitOnlyInAColumn(t *testing.T) { `null`: `so write ""`, `{"format":"{p}","p":{"format":"{x}","x":[null,"a"]}}`: `so write ""`, } { - if _, err := compile(parse(t, src)); err == nil || !strings.Contains(err.Error(), want) { + if _, err := linked(t, src); err == nil || !strings.Contains(err.Error(), want) { t.Errorf("compile(%s) = %v, want an error containing %q", src, err, want) } } diff --git a/fejkdata_test.go b/fejkdata_test.go index bbefb3b..f108855 100644 --- a/fejkdata_test.go +++ b/fejkdata_test.go @@ -113,10 +113,20 @@ func parse(t *testing.T, s string) any { return v } -// compiled parses and compiles a JSON fragment into a node. -func compiled(t *testing.T, s string) node { +// linked compiles a JSON fragment and links it against no data. +func linked(t *testing.T, s string) (node, error) { t.Helper() n, err := compile(parse(t, s)) + if err != nil { + return nil, err + } + return n, linkNodeRefs(inlineScope(n, "template"), nil) +} + +// compiled parses, compiles and links a JSON fragment into a node. +func compiled(t *testing.T, s string) node { + t.Helper() + n, err := linked(t, s) if err != nil { t.Fatalf("compile %q: %v", s, err) } diff --git a/format_test.go b/format_test.go index 8df1f38..eae7414 100644 --- a/format_test.go +++ b/format_test.go @@ -21,7 +21,7 @@ func TestStringIsAFormat(t *testing.T) { if got := mustRender(t, f, `"{digits(3)}"`); !regexp.MustCompile(`^[0-9]{3}$`).MatchString(got) { t.Errorf(`render("{digits(3)}") = %q, want three digits`, got) } - if _, err := compile(parse(t, `"{x}"`)); err == nil || !strings.Contains(err.Error(), `no field "x"`) { + if _, err := linked(t, `"{x}"`); err == nil || !strings.Contains(err.Error(), `no field "x"`) { t.Errorf(`compile("{x}") = %v, want a no-field error`, err) } } @@ -51,7 +51,7 @@ func TestBraceEscapes(t *testing.T) { `{"format":"{a{b}","a":"Q"}`: "'{'", `"{x"`: "unterminated", } { - if _, err := compile(parse(t, src)); err == nil || !strings.Contains(err.Error(), want) { + if _, err := linked(t, src); err == nil || !strings.Contains(err.Error(), want) { t.Errorf("compile(%s) = %v, want an error mentioning %s", src, err, want) } } @@ -126,7 +126,7 @@ func TestFormatCompileErrors(t *testing.T) { `"{int(1)}"`, // wrong arity `"{float(1,2)}"`, // wrong arity } { - if _, err := compile(parse(t, bad)); err == nil { + if _, err := linked(t, bad); err == nil { t.Errorf("compile(%s) = nil error, want error", bad) } } diff --git a/hold_test.go b/hold_test.go index 06c691e..5419a42 100644 --- a/hold_test.go +++ b/hold_test.go @@ -743,7 +743,7 @@ func TestRepeatedBareTokenOfAHeldNameIsRejected(t *testing.T) { `{"format":"{n} + {n} = {calc(n * 2)}","n":["1","2"]}`: "write {n} once", `{"format":"{p.a} {q} {q} {lowercase(q)}","p":{"format":"{a}","a":"1"},"q":["A","B"]}`: "write {q} once", } { - _, err := compile(parse(t, src)) + _, err := linked(t, src) if err == nil || !strings.Contains(err.Error(), want) || !strings.Contains(err.Error(), "holds") { t.Errorf("compile(%s) = %v, want the repeated token rejected naming %s", src, err, want) } @@ -754,7 +754,7 @@ func TestRepeatedBareTokenOfAHeldNameIsRejected(t *testing.T) { `{"format":"{net} x {qty} = {calc(net * qty, 2)}","net":["19.99","5.00"],"qty":["3","7"]}`, `{"format":"{uppercase(w)} {uppercase(w)}","w":["a","b"]}`, } { - if _, err := compile(parse(t, ok)); err != nil { + if _, err := linked(t, ok); err != nil { t.Errorf("compile(%s) = %v, want it accepted", ok, err) } } diff --git a/node_test.go b/node_test.go index f0cee3d..f939618 100644 --- a/node_test.go +++ b/node_test.go @@ -7,7 +7,7 @@ import ( ) func TestWeightZeroIsRejected(t *testing.T) { - _, err := compile(parse(t, `[{"format":"X","weight":0},"Y"]`)) + _, err := linked(t, `[{"format":"X","weight":0},"Y"]`) if err == nil || !strings.Contains(err.Error(), "weight 0") || !strings.Contains(err.Error(), "remove") { t.Fatalf("compile(weight 0) = %v, want it rejected naming the fix", err) } @@ -75,7 +75,7 @@ func TestNodeCompileErrors(t *testing.T) { `{"format":"x","repeat":2,"separator":5}`, // non-string separator `{"format":"{x}","x":"v","repeat":2,"separator":""}`, // separator "" is the default } { - if _, err := compile(parse(t, bad)); err == nil { + if _, err := linked(t, bad); err == nil { t.Errorf("compile(%s) = nil error, want error", bad) } } diff --git a/one_spelling_test.go b/one_spelling_test.go index 6f1f559..8673873 100644 --- a/one_spelling_test.go +++ b/one_spelling_test.go @@ -7,7 +7,7 @@ import ( func TestOneItemChoiceIsRejected(t *testing.T) { for _, src := range []string{`["x"]`, `[{"format":"{d}","d":"x"}]`, `{"format":"{w}","w":["only"]}`} { - if _, err := compile(parse(t, src)); err == nil || !strings.Contains(err.Error(), "one-item choice") { + if _, err := linked(t, src); err == nil || !strings.Contains(err.Error(), "one-item choice") { t.Errorf("compile(%s) = %v, want the one-item choice rejected", src, err) } } @@ -20,11 +20,11 @@ func TestRepeatedChoiceItemIsRejected(t *testing.T) { `{"format":"{w}","w":["", "", "x"]}`: `{ "format": "", "weight": 2 }`, `{"format":"","w":[null,null,"a"]}`: "a null takes no weight", } { - if _, err := compile(parse(t, src)); err == nil || !strings.Contains(err.Error(), want) { + if _, err := linked(t, src); err == nil || !strings.Contains(err.Error(), want) { t.Errorf("compile(%s) = %v, want an error naming %s", src, err, want) } } - if _, err := compile(parse(t, `[{"format":"a","weight":2}, "b"]`)); err != nil { + if _, err := linked(t, `[{"format":"a","weight":2}, "b"]`); err != nil { t.Errorf("compile(weighted a, b) = %v", err) } } @@ -41,7 +41,7 @@ func TestInertObjectIsRejected(t *testing.T) { `{"format":"{x}","x":{"format":"{y}","y":"v","drawGroup":""}}`: `drawGroup "" is the default`, `{"format":"{x}","x":{"format":"{y}","y":"v","drawGroup":1}}`: "drawGroup must be a string", } { - if _, err := compile(parse(t, src)); err == nil || !strings.Contains(err.Error(), want) { + if _, err := linked(t, src); err == nil || !strings.Contains(err.Error(), want) { t.Errorf("compile(%s) = %v, want an error mentioning %s", src, err, want) } } diff --git a/transform_test.go b/transform_test.go index 740212d..668ea6f 100644 --- a/transform_test.go +++ b/transform_test.go @@ -46,7 +46,7 @@ func TestTransformArgs(t *testing.T) { `{"format":"{lowercase(hex(2))}","x":"v"}`, `{"format":"{lowercase(x)} {x.a}","x":{"format":"{a}","a":"1"}}`, } { - if _, err := compile(parse(t, bad)); err == nil { + if _, err := linked(t, bad); err == nil { t.Errorf("compile(%s) = nil error, want it rejected", bad) } }