99 lines
2.6 KiB
Go
99 lines
2.6 KiB
Go
package engine
|
|
|
|
import (
|
|
"strconv"
|
|
"testing"
|
|
)
|
|
|
|
func TestPathRoundTripsSemanticKeys(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tests := []struct {
|
|
name string
|
|
pointer string
|
|
}{
|
|
{name: "root", pointer: ""},
|
|
{name: "slash and tilde", pointer: "/a~1b/c~0d"},
|
|
{name: "empty key", pointer: "/"},
|
|
{name: "dotted key", pointer: "/outputs/a.b"},
|
|
{name: "numeric key", pointer: "/outputs/0"},
|
|
{name: "dot keys", pointer: "/./.."},
|
|
{name: "percent text", pointer: "/%2F/%7E"},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
t.Run(test.name, func(t *testing.T) {
|
|
parsed, err := ParsePath(test.pointer)
|
|
if err != nil {
|
|
t.Fatalf("ParsePath() error = %v", err)
|
|
}
|
|
if got := parsed.String(); got != test.pointer {
|
|
t.Fatalf("String() = %q, want %q", got, test.pointer)
|
|
}
|
|
})
|
|
}
|
|
|
|
if got := Keys("a/b", "c~d", "", "..").String(); got != "/a~1b/c~0d//.." {
|
|
t.Fatalf("Keys().String() = %q", got)
|
|
}
|
|
if got := Keys("items").Index(12).Key("name").String(); got != "/items/12/name" {
|
|
t.Fatalf("indexed path = %q", got)
|
|
}
|
|
maximum := int(^uint(0) >> 1)
|
|
for _, index := range []int{100, maximum, -1, -maximum - 1} {
|
|
want := "/items/" + strconv.Itoa(index)
|
|
if got := Keys("items").Index(index).String(); got != want {
|
|
t.Fatalf("indexed path = %q, want %q", got, want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestPathPreservesSegmentIntentAndImmutability(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
key := Keys("items", "0")
|
|
index := Keys("items").Index(0)
|
|
parsed, err := ParsePath("/items/0")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if key.String() != index.String() || index.String() != parsed.String() {
|
|
t.Fatal("equivalent textual paths should share a JSON Pointer spelling")
|
|
}
|
|
if key.segments[1].kind != pathSegmentKey {
|
|
t.Fatal("Keys numeric segment lost mapping-key intent")
|
|
}
|
|
if index.segments[1].kind != pathSegmentIndex {
|
|
t.Fatal("Index segment lost sequence intent")
|
|
}
|
|
if parsed.segments[1].kind != pathSegmentParsed {
|
|
t.Fatal("parsed numeric segment was resolved before traversal")
|
|
}
|
|
|
|
base := Keys("parent")
|
|
child := base.Key("child")
|
|
child.segments[0].key = "changed"
|
|
if got := base.String(); got != "/parent" {
|
|
t.Fatalf("builder mutated parent: %q", got)
|
|
}
|
|
|
|
negative := Path{}.Index(-1)
|
|
if negative.valid() {
|
|
t.Fatal("negative index must produce an invalid path")
|
|
}
|
|
}
|
|
|
|
func TestParsePathRejectsMalformedPointers(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
for _, pointer := range []string{"relative", "~0", "/bad~", "/bad~2", "/bad~01~"} {
|
|
if _, err := ParsePath(pointer); err == nil {
|
|
t.Errorf("ParsePath(%q) succeeded", pointer)
|
|
}
|
|
}
|
|
|
|
if parsed, err := ParsePath("/missing"); err != nil || !parsed.valid() {
|
|
t.Fatalf("valid missing path rejected: path=%v error=%v", parsed, err)
|
|
}
|
|
}
|