From 5ba38a82814985dbff66ad38db3094098c046cf3 Mon Sep 17 00:00:00 2001 From: Lilleman auf Larv Date: Thu, 3 Sep 2026 17:27:51 +0200 Subject: [PATCH] Tests for FakeTemplate: inline format strings, JSON templates, references, and their errors --- faketemplate_test.go | 106 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 faketemplate_test.go diff --git a/faketemplate_test.go b/faketemplate_test.go new file mode 100644 index 0000000..4b0bb1c --- /dev/null +++ b/faketemplate_test.go @@ -0,0 +1,106 @@ +package fejkdata + +import ( + "strings" + "testing" +) + +func tmpl(t *testing.T, f *Generator, input string) string { + t.Helper() + s, err := f.FakeTemplate(input) + if err != nil { + t.Fatalf("FakeTemplate(%q): %v", input, err) + } + return s +} + +func shipped(t *testing.T, opts ...Option) *Generator { + t.Helper() + f, err := New(append([]Option{WithSeed(1)}, opts...)...) + if err != nil { + t.Fatal(err) + } + return f +} + +func TestFakeTemplateFormatString(t *testing.T) { + f := shipped(t) + got := tmpl(t, f, "name: {/sv_SE.person.last}") + if !strings.HasPrefix(got, "name: ") || strings.HasSuffix(got, " ") || strings.Contains(got, "{") { + t.Fatalf("FakeTemplate = %q, want a rendered last name after the prefix", got) + } +} + +func TestFakeTemplateJSONObject(t *testing.T) { + f := shipped(t) + seen := map[string]bool{} + for i := 0; i < 50; i++ { + seen[tmpl(t, f, `{"format":"name: {x}","x":["bosse","lina"]}`)] = true + } + if !seen["name: bosse"] || !seen["name: lina"] || len(seen) != 2 { + t.Fatalf("JSON template produced %v, want both names", seen) + } +} + +func TestFakeTemplateJSONArray(t *testing.T) { + f := shipped(t) + seen := map[string]bool{} + for i := 0; i < 50; i++ { + seen[tmpl(t, f, `["foo","bar","baz"]`)] = true + } + if len(seen) != 3 { + t.Fatalf("JSON array choice produced %v, want three items", seen) + } +} + +func TestFakeTemplateCorrelatedReferences(t *testing.T) { + dir := writeData(t, map[string]string{ + "person": `[{"format":"{first} {last}","first":"Ada","last":"Lovelace"},{"format":"{first} {last}","first":"Bo","last":"Ek"}]`, + }) + f := newGenerator(t, dir, WithSeed(1)) + for i := 0; i < 100; i++ { + got := tmpl(t, f, "{/person.first} {/person.last}") + if got != "Ada Lovelace" && got != "Bo Ek" { + t.Fatalf("correlated references = %q, want one person's first and last", got) + } + } +} + +func TestFakeTemplateDeterministic(t *testing.T) { + a, b := shipped(t), shipped(t) + for i := 0; i < 20; i++ { + in := "row: {/misc.uuid} {digits(3)}" + if x, y := tmpl(t, a, in), tmpl(t, b, in); x != y { + t.Fatalf("same seed diverged: %q != %q", x, y) + } + } +} + +func TestFakeTemplateErrors(t *testing.T) { + f := shipped(t) + for _, c := range []struct { + input string + want string + }{ + {`{"x":"Q"}`, "missing string \"format\""}, + {`"{x}"`, `no field "x"`}, + {`"{digits(0)}"`, "must be positive"}, + {`name: {/no.such.path}`, "no entry"}, + {`name: {..nope}`, "no folder above"}, + {`{"format":"x"}`, "is a string"}, + {`{/misc.country} {/misc.country.alpha2}`, "renders a level"}, + } { + _, err := f.FakeTemplate(c.input) + if err == nil || !strings.Contains(err.Error(), c.want) { + t.Errorf("FakeTemplate(%q) = %v, want an error containing %q", c.input, err, c.want) + } + } +} + +func TestFakeTemplateRepeatBound(t *testing.T) { + f := shipped(t) + _, err := f.FakeTemplate(`{"format":"{x}","repeat":200,"x":{"format":"{y}","repeat":200,"y":{"format":"z","repeat":200}}}`) + if err == nil || !strings.Contains(err.Error(), "maximum") { + t.Errorf("nested repeat over the cap = %v, want it rejected naming the maximum", err) + } +}