Files
fejkdata/name_test.go
T

261 lines
9.0 KiB
Go

package fejkdata
import (
"strings"
"testing"
)
// nameTables is a region table linked to by a municipality table.
func nameTables() map[string]string {
return map[string]string{
"region.json": `{"format":"{name}","rows":"region.tsv","key":"code"}`,
"region.tsv": "code\tname\n01\tStockholms län\n12\tSkåne län\n",
"municipality.json": `{"format":"{name}","rows":"municipality.tsv","key":"code","parent":"region"}`,
"municipality.tsv": "code\tname\tregion\n0180\tStockholm\t01\n0184\tSolna\t01\n1280\tMalmö\t12\n1281\tLund\t12\n",
}
}
var municipalityCode = map[string]string{"Stockholm": "0180", "Solna": "0184", "Malmö": "1280", "Lund": "1281"}
var municipalityRegion = map[string]string{"Stockholm": "Stockholms län", "Solna": "Stockholms län", "Malmö": "Skåne län", "Lund": "Skåne län"}
func TestANameIsOnePickOfEverythingUnderIt(t *testing.T) {
files := nameTables()
files["card.json"] = `"{/region as r}{r.name}|{r.municipality.name}|{r.municipality.code}|{r}"`
f := newGenerator(t, writeFiles(t, files), WithSeed(3))
for i := 0; i < 200; i++ {
got := strings.Split(fake(t, f, "card"), "|")
region, municipality, code, whole := got[0], got[1], got[2], got[3]
if municipalityCode[municipality] != code || municipalityRegion[municipality] != region || whole != region {
t.Fatalf("card = %q, want one region, and one municipality inside it", got)
}
}
}
func TestANameReadWholeAgreesWithItsPaths(t *testing.T) {
dir := writeData(t, map[string]string{
"person": `{"format":"{first} {last}","first":["Ada","Bo","Cy"],"last":["Byron","Ek","Lind"]}`,
"card": `"{/person as p}{p}|{p.last}|{p.first}"`,
})
f := newGenerator(t, dir, WithSeed(5))
for i := 0; i < 200; i++ {
got := strings.Split(fake(t, f, "card"), "|")
if got[0] != got[2]+" "+got[1] {
t.Fatalf("card = %q, want the whole person to match its parts", got)
}
}
}
func TestANameDrawsEachFieldUnderItOnce(t *testing.T) {
dir := writeData(t, map[string]string{
"word": `{"format":"{w}-{w}","w":["a","b","c","d","e","f","g","h"]}`,
"card": `"{/word as w}{w}"`,
})
f := newGenerator(t, dir, WithSeed(7))
for i := 0; i < 100; i++ {
if got := fake(t, f, "card"); got[0] != got[2] {
t.Fatalf("card = %q, want one draw of w under the name", got)
}
}
}
func TestABindingPrintsNothing(t *testing.T) {
dir := writeData(t, map[string]string{
"word": `["a","b"]`,
"card": `"<{/word as w}>{w}"`,
})
f := newGenerator(t, dir, WithSeed(1))
if got := fake(t, f, "card"); got != "<>a" && got != "<>b" {
t.Fatalf("card = %q, want the binding to print nothing", got)
}
}
func TestSiblingFieldsAndColumnsReadOneName(t *testing.T) {
dir := writeData(t, map[string]string{
"person": `{"format":"{first} {last}","first":["Ada","Bo","Cy"],"last":["Byron","Ek","Lind"]}`,
"row": `{"format":"{first} {last}","first":"{/person as p}{p.first}","last":"{p.last}","whole":"{p}"}`,
})
f := newGenerator(t, dir, WithSeed(9))
for i := 0; i < 100; i++ {
r, err := f.FakeRecord("row")
if err != nil {
t.Fatal(err)
}
c := r.Columns()
if c[2].Value != c[0].Value+" "+c[1].Value {
t.Fatalf("columns = %v, want one person across them", c)
}
if got := strings.Fields(fake(t, f, "row")); len(got) != 2 {
t.Fatalf("row = %q, want a first and a last name", got)
}
}
}
func TestAFieldReadsTheNameItsCategoryBinds(t *testing.T) {
dir := writeData(t, map[string]string{
"person": `{"format":"{first} {last}","first":"Ada","last":"Byron"}`,
"row": `{"format":"{first}","first":"{/person as p}{p.first}","last":"{p.last}"}`,
})
f := newGenerator(t, dir, WithSeed(1))
if got := fake(t, f, "row.last"); got != "Byron" {
t.Fatalf("row.last = %q, want Byron", got)
}
}
func TestANameInsideARepeatPicksEachIteration(t *testing.T) {
dir := writeData(t, map[string]string{
"word": `["a","b","c","d","e","f","g","h"]`,
"line": `{"format":"{each}","each":{"format":"{/word as w}{w}{w}","repeat":40,"separator":" "}}`,
})
f := newGenerator(t, dir, WithSeed(11))
seen := map[string]bool{}
for _, pair := range strings.Fields(fake(t, f, "line")) {
if pair[0] != pair[1] {
t.Fatalf("pair %q, want one pick per iteration", pair)
}
seen[pair] = true
}
if len(seen) < 2 {
t.Fatalf("pairs %v, want each iteration to pick anew", seen)
}
}
func TestANameOutsideARepeatKeepsItsPick(t *testing.T) {
dir := writeData(t, map[string]string{
"word": `["a","b","c","d","e","f","g","h"]`,
"line": `{"format":"{/word as w}{each}","each":{"format":"{w}","repeat":40,"separator":" "}}`,
})
f := newGenerator(t, dir, WithSeed(13))
got := strings.Fields(fake(t, f, "line"))
for _, w := range got {
if w != got[0] {
t.Fatalf("line = %q, want one pick on every line", got)
}
}
}
func TestTwoRendersPickTwice(t *testing.T) {
dir := writeData(t, map[string]string{
"word": `["a","b","c","d","e","f","g","h"]`,
"one": `"{/word as w}{w}"`,
"two": `"{/one}{/one}{/one}{/one}{/one}{/one}"`,
})
f := newGenerator(t, dir, WithSeed(17))
got := fake(t, f, "two")
if strings.Count(got, got[:1]) == len(got) {
t.Fatalf("two = %q, want each bare reference to its own pick", got)
}
}
func TestANameInAnInlineTemplate(t *testing.T) {
dir := writeData(t, map[string]string{
"person": `{"format":"{first} {last}","first":["Ada","Bo","Cy"],"last":["Byron","Ek","Lind"]}`,
})
f := newGenerator(t, dir, WithSeed(19))
for i := 0; i < 50; i++ {
got := strings.Split(fakeTemplate(t, f, "{/person as p}{p}|{p.first} {p.last}"), "|")
if got[0] != got[1] {
t.Fatalf("template = %q, want one person", got)
}
}
}
func TestNameErrors(t *testing.T) {
cases := []struct {
name string
files map[string]string
want string
}{
{"bound twice", map[string]string{"word": `["a","b"]`, "card": `{"format":"{x}{y}","x":"{/word as w}{w}","y":"{/word as w}"}`},
`name "w" is bound twice in one scope`},
{"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 already`},
{"a field too", map[string]string{"word": `["a","b"]`, "card": `{"format":"{/word as w}{w}","w":"x"}`},
`name "w" is a field too`},
{"an option", map[string]string{"word": `["a","b"]`, "card": `"{/word as format}{format}"`},
`"format" is an option and can never be a name`},
{"no reference", map[string]string{"card": `{"format":"{word as w}{w}","word":["a","b"]}`},
`"word" is no reference`},
{"read by nothing", map[string]string{"word": `["a","b"]`, "card": `"{/word as w}"`},
`nothing reads name "w"`},
{"unbound", map[string]string{"word": `["a","b"]`, "card": `{"format":"{x}{w}","x":{"format":"{/word as w}{w}","repeat":2}}`},
`no field "w"`},
{"padded", map[string]string{"word": `["a","b"]`, "card": `"{/word as w}{w}"`},
`write {/word as w}`},
{"selector after a name", map[string]string{"region.json": nameTables()["region.json"], "card": `"{/region as r}{r.municipality[0180].name}"`},
`a path through name "r" selects no row`},
{"in a table's format", map[string]string{"word": `["a","b"]`, "t.json": `{"format":"{/word as w}{w}","rows":"t.tsv","key":"k"}`, "t.tsv": "k\nx\ny\n"},
"a table binds no name"},
{"in a field's name", map[string]string{"card": `{"format":"{a as b}","a as b":"x"}`},
`contains " as "`},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
files := map[string]string{}
for name, body := range c.files {
if !strings.Contains(name, ".") {
name += ".json"
}
files[name] = body
}
if c.name == "selector after a name" {
for k, v := range nameTables() {
files[k] = v
}
}
_, err := New(WithoutShippedData(), WithDataPath(writeFiles(t, files)))
if err == nil || !strings.Contains(err.Error(), c.want) {
t.Fatalf("New() = %v, want an error holding %q", err, c.want)
}
})
}
}
func TestANameBindsAReferenceFromItsFolder(t *testing.T) {
dir := writeData(t, map[string]string{
"sv/word": `["a","b","c","d","e","f","g","h"]`,
"sv/card": `"{.word as w}{w}{w}"`,
})
f := newGenerator(t, dir, WithSeed(23))
for i := 0; i < 50; i++ {
if got := fake(t, f, "sv.card"); got[0] != got[1] {
t.Fatalf("sv.card = %q, want one pick", got)
}
}
}
func TestANameBindsAReferencePath(t *testing.T) {
dir := writeData(t, map[string]string{
"person": `{"format":"{first}","first":["Ada","Bo","Cy","Di"]}`,
"card": `"{/person.first as f}{f}|{f}"`,
})
f := newGenerator(t, dir, WithSeed(29))
for i := 0; i < 50; i++ {
got := strings.Split(fake(t, f, "card"), "|")
if got[0] != got[1] {
t.Fatalf("card = %q, want one pick", got)
}
}
}
type namedPerson struct {
First string `fake:"{/person as p}{p.first}"`
Whole string `fake:"{p}"`
}
func TestStructTagsReadOneName(t *testing.T) {
dir := writeData(t, map[string]string{
"person": `{"format":"{first} {last}","first":["Ada","Bo","Cy"],"last":["Byron","Ek","Lind"]}`,
})
f := newGenerator(t, dir, WithSeed(31))
for i := 0; i < 50; i++ {
var p namedPerson
if err := f.FakeStruct(&p); err != nil {
t.Fatal(err)
}
if !strings.HasPrefix(p.Whole, p.First+" ") {
t.Fatalf("struct = %+v, want one person", p)
}
}
}