From 7c7bee5cd9efe96b164b7ee0c0d5ddc50c7a52b6 Mon Sep 17 00:00:00 2001 From: Lilleman auf Larv Date: Thu, 3 Sep 2026 20:31:49 +0200 Subject: [PATCH] Tests: one fence sequence, inline folder sigils rejected, JSON string arguments, quoted names, and shape misuse before load --- cmd/fejkdata/main_test.go | 45 +++++++++++++++++++------- faketemplate_test.go => inline_test.go | 19 ++++++++++- loading_test.go | 6 ++-- one_spelling_test.go | 10 ++++++ 4 files changed, 65 insertions(+), 15 deletions(-) rename faketemplate_test.go => inline_test.go (85%) diff --git a/cmd/fejkdata/main_test.go b/cmd/fejkdata/main_test.go index 07a29d8..a62fa21 100644 --- a/cmd/fejkdata/main_test.go +++ b/cmd/fejkdata/main_test.go @@ -301,21 +301,34 @@ func TestRunShippedDataByDefault(t *testing.T) { } } -func TestIsTemplate(t *testing.T) { - for arg, want := range map[string]bool{ - "sv_SE.person": false, - "person.last": false, - "[abc]": false, // a [ that is not valid JSON is not a template - "[abc].field": false, - "name: {x}": true, // a { token: a path can never carry a brace - `{"format":"x"}`: true, - `["a","b"]`: true, // a JSON array carries no brace - `[1, 2]`: true, +func TestClassify(t *testing.T) { + for arg, want := range map[string]argKind{ + "sv_SE.person": argPath, + "person.last": argPath, + `"abc`: argPath, // a quote opening no JSON string is part of a name + "name: {x}": argTemplate, // a { token: a path can never carry a brace + `{"format":"x"}`: argTemplate, + `["a","b"]`: argTemplate, // a JSON array carries no brace + `[1, 2]`: argTemplate, + `"hello"`: argTemplate, // a JSON string, the spelling a format-only object names } { - if got := isTemplate(arg); got != want { - t.Errorf("isTemplate(%q) = %v, want %v", arg, got, want) + got, err := classify(arg) + if err != nil || got != want { + t.Errorf("classify(%q) = %v, %v; want %v", arg, got, err, want) } } + for _, arg := range []string{"[abc]", "[abc].field", "x[1]", "a]b"} { + if _, err := classify(arg); err == nil { + t.Errorf("classify(%q) = no error; want the bracket rejected", arg) + } + } +} + +func TestRunShapeMisuseBeforeLoad(t *testing.T) { + code, _, errb := runOut("--no-shipped-data", "[abc]") + if code != 2 || !strings.Contains(errb, "[abc]") || strings.Contains(errb, "--data-path") { + t.Fatalf("shape misuse with no data = %d, %q; want the shape error before any load", code, errb) + } } func TestRunInlineTemplate(t *testing.T) { @@ -327,6 +340,10 @@ func TestRunInlineTemplate(t *testing.T) { if code != 0 || (out != "name: bosse\n" && out != "name: lina\n") { t.Fatalf("inline JSON template = %d, %q, want one name, stderr %q", code, out, errb) } + code, out, errb = runOut("--seed", "1", `"name: {/sv_SE.person.last}"`) + if code != 0 || !strings.HasPrefix(out, "name: ") || strings.Contains(out, "{") { + t.Fatalf("inline JSON string = %d, %q, stderr %q", code, out, errb) + } code, out, errb = runOut("--seed", "1", "-n", "2", `{digits(1)}`) if code != 0 || len(strings.Split(strings.TrimRight(out, "\n"), "\n")) != 2 { t.Fatalf("inline template with --repeat = %d, %q, stderr %q", code, out, errb) @@ -339,11 +356,15 @@ func TestRunTemplateMisuse(t *testing.T) { "[red,green]", // a near-miss JSON array (unquoted strings) `{"format":"x"}`, // an object holding only a format "{/no.such.path}", // a reference into nothing + "x[1]", // a bracket no path may hold } { code, out, errb := runOut("--seed", "1", arg) if code != 2 || out != "" || !strings.Contains(errb, "try 'fejkdata --help'") { t.Errorf("run(%q) = %d, %q, %q; want misuse naming --help", arg, code, out, errb) } + if strings.Contains(errb, "fejkdata: fejkdata:") { + t.Errorf("run(%q) doubled the program prefix: %q", arg, errb) + } } } diff --git a/faketemplate_test.go b/inline_test.go similarity index 85% rename from faketemplate_test.go rename to inline_test.go index 3cef4dd..31be71e 100644 --- a/faketemplate_test.go +++ b/inline_test.go @@ -94,7 +94,7 @@ func TestFakeTemplateErrors(t *testing.T) { {`"{x}"`, `no field "x"`}, {`"{digits(0)}"`, "must be positive"}, {`name: {/no.such.path}`, "no entry"}, - {`name: {..nope}`, "no folder above"}, + {`name: {..nope}`, "write {/nope}"}, {`{"format":"x"}`, "is a string"}, {`{/misc.country} {/misc.country.alpha2}`, "renders a level"}, } { @@ -105,6 +105,23 @@ func TestFakeTemplateErrors(t *testing.T) { } } +func TestFakeTemplateJSONString(t *testing.T) { + f := shipped(t) + got := tmpl(t, f, `"name: {/sv_SE.person.last}"`) + if !strings.HasPrefix(got, "name: ") || strings.Contains(got, "{") { + t.Fatalf("FakeTemplate(JSON string) = %q, want a rendered last name after the prefix", got) + } +} + +func TestPaddedJSONIsRejected(t *testing.T) { + f := shipped(t) + in := `{"format":"{x}","x":["a","b"]}` + _, err := f.NewTemplate(" " + in + " ") + if err == nil || !strings.Contains(err.Error(), "write "+in) { + t.Fatalf("NewTemplate(padded JSON) = %v, want an error naming the unpadded spelling", err) + } +} + func TestNewTemplateReusable(t *testing.T) { f := shipped(t) tmpl, err := f.NewTemplate(`{digits(2)}`) diff --git a/loading_test.go b/loading_test.go index b841b07..681fe67 100644 --- a/loading_test.go +++ b/loading_test.go @@ -275,8 +275,6 @@ func TestNewErrors(t *testing.T) { map[string]string{"a|b": `"1"`}, `category "a|b" contains "|"`, }, - // A bracket is not a token-grammar character, but the CLI reads an argument - // starting with [ as a JSON array, so a name carrying one would be misread. "field name with a bracket": { map[string]string{"a": `{"format":"{x}","x":"1","b[c":"2"}`}, `field "b[c" contains "["`, @@ -285,6 +283,10 @@ func TestNewErrors(t *testing.T) { map[string]string{"[abc]": `"1"`}, `category "[abc]" contains "["`, }, + "field name with a quote": { + map[string]string{"a": `{"format":"{x}","x":"1","b\"c":"2"}`}, + `field "b\"c" contains "\""`, + }, // An empty name is not a path segment, so List never offered it — while a // bare {}, a trailing dot in Fake("a.") and a {/a.} reference all reached // it. The engine accepted spellings it would never advertise. diff --git a/one_spelling_test.go b/one_spelling_test.go index f866609..d5bbd8b 100644 --- a/one_spelling_test.go +++ b/one_spelling_test.go @@ -47,3 +47,13 @@ func TestInertObjectIsRejected(t *testing.T) { } } } + +func TestInlineFolderSigilsAreRejected(t *testing.T) { + f := shipped(t) + for _, input := range []string{"{.sv_SE.person.last}", "{..sv_SE.person.last}"} { + _, err := f.NewTemplate(input) + if err == nil || !strings.Contains(err.Error(), "write {/sv_SE.person.last}") { + t.Errorf("NewTemplate(%q) = %v, want an error naming the root spelling", input, err) + } + } +}