package engine import ( "slices" "strings" "testing" ) func TestPathPrefixIndexMatchesPointerScans(t *testing.T) { entries := []struct { pointer string id int }{ {pointer: "", id: 12}, {pointer: "/", id: 9}, {pointer: "/a", id: 6}, {pointer: "/a", id: 2}, {pointer: "/a/b", id: 4}, {pointer: "/a/b/c", id: 0}, {pointer: "/a/bc", id: 10}, {pointer: "/a~1b", id: 3}, {pointer: "/a~0b", id: 1}, {pointer: "/a~01b", id: 5}, {pointer: "/items/0", id: 8}, {pointer: "/items/01", id: 7}, {pointer: "/items/+1", id: 11}, } var index pathPrefixIndex for _, entry := range entries { index.insert(entry.pointer, entry.id) } queries := []string{ "", "/", "/a", "/a/b", "/a/b/c", "/a/b/c/d", "/a/bc", "/a/bc/d", "/a~1b", "/a~0b", "/a~01b", "/items", "/items/0", "/items/01", "/items/1", "/missing", } for _, query := range queries { gotAncestors := make([]int, 0) index.visitAncestors(query, func(id int) { gotAncestors = append(gotAncestors, id) }) wantAncestors := make([]int, 0) gotDescendants := make([]int, 0) wantDescendants := make([]int, 0) wantEarliest, foundEarliest := 0, false for _, entry := range entries { if pointerContainsByString(entry.pointer, query) { wantAncestors = append(wantAncestors, entry.id) } if pointerContainsByString(query, entry.pointer) { wantDescendants = append(wantDescendants, entry.id) } if pointerContainsByString(entry.pointer, query) || pointerContainsByString(query, entry.pointer) { if !foundEarliest || entry.id < wantEarliest { wantEarliest, foundEarliest = entry.id, true } } } index.visitDescendants(query, func(id int) { gotDescendants = append(gotDescendants, id) }) if !slices.Equal(sortedPrefixIDs(gotAncestors), sortedPrefixIDs(wantAncestors)) { t.Errorf("ancestors(%q) = %v, want %v", query, sortedPrefixIDs(gotAncestors), sortedPrefixIDs(wantAncestors)) } if !slices.Equal(sortedPrefixIDs(gotDescendants), sortedPrefixIDs(wantDescendants)) { t.Errorf("descendants(%q) = %v, want %v", query, sortedPrefixIDs(gotDescendants), sortedPrefixIDs(wantDescendants)) } gotEarliest, gotFound := index.earliestIntersectingID(query) if gotEarliest != wantEarliest || gotFound != foundEarliest { t.Errorf("earliestIntersectingID(%q) = %d, %v, want %d, %v", query, gotEarliest, gotFound, wantEarliest, foundEarliest) } } } func pointerContainsByString(container, descendant string) bool { if container == "" { return true } return descendant == container || strings.HasPrefix(descendant, container+"/") } func sortedPrefixIDs(ids []int) []int { result := slices.Clone(ids) slices.Sort(result) return result }