Tests for a path token rendering its leaf, not the level it starts from
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
package fakes
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
"testing"
|
||||
@@ -117,6 +118,61 @@ func TestReferenceNamingABoundLevelIsRejected(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestCycleReachedOnlyByAPathTokenIsRejected(t *testing.T) {
|
||||
// A path token renders what it lands on, not the level it started from, so the
|
||||
// cycle walk has to follow it there. A head whose own format names nothing
|
||||
// would otherwise hide the cycle until render, where it is fatal.
|
||||
_, err := New([]string{writeData(t, map[string]string{
|
||||
"a": `{"format":"{p.x}","p":{"format":"static","x":{"format":"{..a}"}}}`,
|
||||
})})
|
||||
if err == nil || !strings.Contains(err.Error(), "reference cycle") {
|
||||
t.Fatalf("New = %v, want the cycle through {p.x} rejected", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestALevelRenderedOnlyByAPathTokenIsHeld(t *testing.T) {
|
||||
// {p.a} renders q, so it is a route to the level {q.x} holds — even though p's
|
||||
// own format names nothing.
|
||||
_, err := New([]string{writeData(t, map[string]string{
|
||||
"thing": `{"format":"{p.a} {q.x}","p":{"format":"static","a":{"format":"{..thing.q}"}},` +
|
||||
`"q":{"format":"{x}","x":["1","2"]}}`,
|
||||
})})
|
||||
if err == nil || !strings.Contains(err.Error(), "reads a path into") {
|
||||
t.Fatalf("New = %v, want the second route to q rejected", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestALevelAPathNeverRendersIsAccepted(t *testing.T) {
|
||||
// A path token does not expand its head's format, so a reference sitting in
|
||||
// that format is not a second route to anything: it is never rendered by the
|
||||
// path at all. Both orders must load.
|
||||
accepted := map[string]string{
|
||||
"reference in the head's own format": `{"format":"{p.first} {q.a}",` +
|
||||
`"p":{"format":"{first} {..thing.q}","first":["A","B"]},"q":{"format":"{a}","a":["1","2"]}}`,
|
||||
"the mirror shape": `{"format":"{p.first} {q.a}",` +
|
||||
`"p":{"format":"{first}","first":["A","B"]},"q":{"format":"{a} {..thing.p}","a":["1","2"]}}`,
|
||||
}
|
||||
for name, file := range accepted {
|
||||
if _, err := New([]string{writeData(t, map[string]string{"thing": file})}); err != nil {
|
||||
t.Errorf("%s: New = %v, want it accepted", name, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestADeepDiamondChainLoads(t *testing.T) {
|
||||
// A diamond chain is 2^n routes through n nodes. The search past a bound level
|
||||
// must walk each node once, not once per route, or a deep chain never loads.
|
||||
files := map[string]string{"l0": `["x"]`}
|
||||
for i := 1; i <= 30; i++ {
|
||||
files[fmt.Sprintf("l%d", i)] = fmt.Sprintf(
|
||||
`{"format":"{a}{b}","a":{"format":"{..l%d}"},"b":{"format":"{..l%d}"}}`, i-1, i-1)
|
||||
}
|
||||
files["thing"] = `{"format":"{p.first} {..l30}","p":{"format":"x","first":["A","B"]}}`
|
||||
if _, err := New([]string{writeData(t, files)}); err != nil {
|
||||
t.Fatalf("New = %v, want a deep diamond chain to load", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestASharedNodeIsWalkedOnce(t *testing.T) {
|
||||
// Two fields reaching one node make the render graph a diamond, not a tree.
|
||||
// The search past a bound level must take that in its stride rather than walk
|
||||
|
||||
Reference in New Issue
Block a user