Tests for one spelling per draw, and a path into a repeating level

This commit is contained in:
M
2026-08-30 20:36:02 +02:00
committed by lilleman-tw
parent e05fed1190
commit 97ecbe208f
+47 -24
View File
@@ -41,15 +41,54 @@ func TestDottedTokenCorrelatesSiblingFields(t *testing.T) {
} }
} }
func TestBareTokenBindsWhenTheFormatAlsoTakesAPath(t *testing.T) { func TestRenderingALevelAndReadingIntoItIsRejected(t *testing.T) {
// A head any dotted token addresses is drawn once, so a bare {place} in the // One draw, one spelling. A token that renders a level and one that reads a
// same format reads that same draw rather than a second one. // path into it name the same draw two ways, and only the path reads what the
f := engine(2) // other rendered — so the pair is a load error rather than a shape whose two
for i := 0; i < 300; i++ { // halves can disagree.
got := mustRender(t, f, places("{place.postal-code} {place}")) rejected := map[string]string{
if !agree.MatchString(got) { "bare head beside a path": `{"format":"{p} + {p.first}","p":[{"format":"{first}","first":["Anna","Bo"]}]}`,
t.Fatalf("draw %d = %q, want the bare token to read the bound draw", i, got) "prefix path beside a path": `{"format":"{p.addr}|{p.addr.city}","p":[{"format":"{addr}","addr":[` +
`{"format":"{city}","city":["Kiruna","Boden"]},{"format":"{city}","city":["Malmö","Lund"]}]}]}`,
"either order": `{"format":"{p.first} + {p}","p":[{"format":"{first}","first":["Anna","Bo"]}]}`,
}
for name, file := range rejected {
_, err := New([]string{writeData(t, map[string]string{"cat": file})})
if err == nil {
t.Errorf("%s: New = nil error, want the overlapping tokens rejected", name)
continue
} }
if !strings.Contains(err.Error(), "reads a path into") {
t.Errorf("%s: New = %v, want it to name the overlap", name, err)
}
}
// The same path twice is one spelling, so it stays legal.
if _, err := New([]string{writeData(t, map[string]string{
"cat": `{"format":"{p.first} + {p.first}","p":[{"format":"{first}","first":["Anna","Bo"]}]}`,
})}); err != nil {
t.Errorf("New = %v, want one path read twice accepted", err)
}
}
func TestPathIntoARepeatingLevelIsRejected(t *testing.T) {
// A path reads one level's draw, so it can never apply that level's repeat.
// The engine rejects options that cannot take effect, and this is one.
_, err := New([]string{writeData(t, map[string]string{
"cat": `{"format":"[{p.a}]","p":{"format":"{a}","repeat":3,"separator":",","a":["z"]}}`,
})})
if err == nil || !strings.Contains(err.Error(), "repeat") {
t.Fatalf("New = %v, want a path into a repeating level rejected", err)
}
}
func TestPathIntoAPlainTemplateNamesTheMissingField(t *testing.T) {
// A head that is one template, not a choice, reports the missing segment
// directly — there are no variants to compare.
_, err := New([]string{writeData(t, map[string]string{
"cat": `{"format":"{a.nope}","a":{"format":"x","b":"1"}}`,
})})
if err == nil || !strings.Contains(err.Error(), `no field "nope"`) {
t.Fatalf("New = %v, want it to name the missing field", err)
} }
} }
@@ -288,22 +327,6 @@ func TestDeepPathsUnderOneHeadStayIndependentWhereTheyDiverge(t *testing.T) {
} }
} }
func TestAPathAndItsOwnPrefixShareTheDraw(t *testing.T) {
// {p.addr} and {p.addr.city} name the same level, so they must read the same
// draw of it — a path that is itself the prefix of another is still one draw.
f := engine(15)
tmpl := `{"format":"{p.addr}|{p.addr.city}","p":[{"format":"{addr}","addr":[
{"format":"{city}","city":"Kiruna","zip":"98100"},
{"format":"{city}","city":"Malmö","zip":"21100"}]}]}`
for i := 0; i < 400; i++ {
got := mustRender(t, f, tmpl)
parts := strings.Split(got, "|")
if parts[0] != parts[1] {
t.Fatalf("draw %d = %q, want one draw read by both", i, got)
}
}
}
func TestEmptyPathSegmentIsRejected(t *testing.T) { func TestEmptyPathSegmentIsRejected(t *testing.T) {
// "{a.}", "{.b}" and "{a..b}" are unfinished paths. A field really named "" // "{a.}", "{.b}" and "{a..b}" are unfinished paths. A field really named ""
// would otherwise make them resolve, which reads as a typo that worked. // would otherwise make them resolve, which reads as a typo that worked.