Keep reference algorithms in tests
This commit is contained in:
@@ -8,8 +8,8 @@ membership maps broadly match the selected architecture. Whole-tree replay and
|
|||||||
the expressly deferred ownership/trace changes remain unchanged.
|
the expressly deferred ownership/trace changes remain unchanged.
|
||||||
|
|
||||||
The review found no reproduced functional regression or unintentionally stronger
|
The review found no reproduced functional regression or unintentionally stronger
|
||||||
public contract. The following bounded implementation and test-quality findings
|
public contract. All three bounded implementation and test-quality findings
|
||||||
remain to be addressed. They do not authorize changes to public semantics,
|
below are now addressed. They do not authorize changes to public semantics,
|
||||||
dependencies, resource limits, release gates, or credential handling.
|
dependencies, resource limits, release gates, or credential handling.
|
||||||
|
|
||||||
The older, completed ReleaseKit review record remains in Git history at
|
The older, completed ReleaseKit review record remains in Git history at
|
||||||
@@ -78,7 +78,12 @@ is missing regression protection, not an observed sensitivity leak.
|
|||||||
|
|
||||||
## 3. Finish moving reference-only machinery out of production (P3)
|
## 3. Finish moving reference-only machinery out of production (P3)
|
||||||
|
|
||||||
Status: Open.
|
Status: Complete. Reference containment/deduplication is String-based and
|
||||||
|
test-only. The unused constructor/comparator/path helpers are removed; coverage
|
||||||
|
tests exercise both live record/snapshot adapters, and dependency membership
|
||||||
|
tests exercise the actual resolution record. Required live helpers and immutable
|
||||||
|
inspection evidence are unchanged. Focused tests, `./scripts/check.sh`, and
|
||||||
|
`go test -race ./...` passed; code search found no remaining obsolete symbols.
|
||||||
|
|
||||||
Affected: [resolution.go](../../internal/engine/resolution.go),
|
Affected: [resolution.go](../../internal/engine/resolution.go),
|
||||||
`newResolutionCoverageIndex` (lines 373–382), `appendUniqueString`,
|
`newResolutionCoverageIndex` (lines 373–382), `appendUniqueString`,
|
||||||
|
|||||||
@@ -102,10 +102,6 @@ func canonicalDiagnostics(diagnostics []Diagnostic) []Diagnostic {
|
|||||||
return canonical
|
return canonical
|
||||||
}
|
}
|
||||||
|
|
||||||
func compareDiagnostic(left, right Diagnostic) int {
|
|
||||||
return compareDiagnosticWithPaths(left, right, left.Path.String(), right.Path.String())
|
|
||||||
}
|
|
||||||
|
|
||||||
func compareDiagnosticWithPaths(left, right Diagnostic, leftPath, rightPath string) int {
|
func compareDiagnosticWithPaths(left, right Diagnostic, leftPath, rightPath string) int {
|
||||||
if order := compareOptionalLocation(left.Primary, right.Primary); order != 0 {
|
if order := compareOptionalLocation(left.Primary, right.Primary); order != 0 {
|
||||||
return order
|
return order
|
||||||
|
|||||||
@@ -155,18 +155,6 @@ func pathIndexSpellingEqual(index int, token string) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func pathSpellingEqual(left, right Path) bool {
|
|
||||||
if len(left.segments) != len(right.segments) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
for i, segment := range left.segments {
|
|
||||||
if !pathTokenSpellingEqual(segment, right.segments[i]) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func escapePathToken(token string) string {
|
func escapePathToken(token string) string {
|
||||||
token = strings.ReplaceAll(token, "~", "~0")
|
token = strings.ReplaceAll(token, "~", "~0")
|
||||||
return strings.ReplaceAll(token, "/", "~1")
|
return strings.ReplaceAll(token, "/", "~1")
|
||||||
|
|||||||
@@ -96,37 +96,6 @@ func TestPathContainmentMatchesPointerSpelling(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAppendUniquePathMatchesPointerSpelling(t *testing.T) {
|
|
||||||
parse := func(pointer string) Path {
|
|
||||||
path, err := ParsePath(pointer)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("ParsePath(%q) error = %v", pointer, err)
|
|
||||||
}
|
|
||||||
return path
|
|
||||||
}
|
|
||||||
paths := []Path{
|
|
||||||
Keys("a/b"), parse("/a~1b"),
|
|
||||||
Keys("a~1b"), parse("/a~01b"),
|
|
||||||
Keys("items").Index(0), parse("/items/0"), Keys("items", "0"),
|
|
||||||
Keys("items", "01"), parse("/items/01"),
|
|
||||||
Path{}.Index(-1), Keys("-1"),
|
|
||||||
Keys("a", "b"), Keys("a/b"),
|
|
||||||
}
|
|
||||||
var got, want []Path
|
|
||||||
for _, path := range paths {
|
|
||||||
got = appendUniquePath(got, path)
|
|
||||||
want = appendUniquePathByPointer(want, path)
|
|
||||||
}
|
|
||||||
if len(got) != len(want) {
|
|
||||||
t.Fatalf("unique path counts = %d, want %d", len(got), len(want))
|
|
||||||
}
|
|
||||||
for i := range got {
|
|
||||||
if got[i].String() != want[i].String() {
|
|
||||||
t.Fatalf("unique path %d = %q, want %q", i, got[i].String(), want[i].String())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func pathContainsByPointer(container, descendant Path) bool {
|
func pathContainsByPointer(container, descendant Path) bool {
|
||||||
if !container.valid() || !descendant.valid() || len(container.segments) > len(descendant.segments) {
|
if !container.valid() || !descendant.valid() || len(container.segments) > len(descendant.segments) {
|
||||||
return false
|
return false
|
||||||
@@ -139,15 +108,6 @@ func pathContainsByPointer(container, descendant Path) bool {
|
|||||||
return value == prefix || len(value) > len(prefix) && value[:len(prefix)] == prefix && value[len(prefix)] == '/'
|
return value == prefix || len(value) > len(prefix) && value[:len(prefix)] == prefix && value[len(prefix)] == '/'
|
||||||
}
|
}
|
||||||
|
|
||||||
func appendUniquePathByPointer(paths []Path, path Path) []Path {
|
|
||||||
for _, existing := range paths {
|
|
||||||
if existing.String() == path.String() {
|
|
||||||
return paths
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return append(paths, path.clone())
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestPathPreservesSegmentIntentAndImmutability(t *testing.T) {
|
func TestPathPreservesSegmentIntentAndImmutability(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
|
|||||||
@@ -370,17 +370,6 @@ type resolutionCoverageIndex struct {
|
|||||||
depths []int
|
depths []int
|
||||||
}
|
}
|
||||||
|
|
||||||
func newResolutionCoverageIndex(paths []Path) *resolutionCoverageIndex {
|
|
||||||
index := &resolutionCoverageIndex{depths: make([]int, len(paths))}
|
|
||||||
for id, path := range paths {
|
|
||||||
index.depths[id] = len(path.segments)
|
|
||||||
if path.valid() {
|
|
||||||
index.prefix.insert(path.String(), id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return index
|
|
||||||
}
|
|
||||||
|
|
||||||
func newResolutionCoverageIndexFromRecords(records []*resolutionRecord) *resolutionCoverageIndex {
|
func newResolutionCoverageIndexFromRecords(records []*resolutionRecord) *resolutionCoverageIndex {
|
||||||
index := &resolutionCoverageIndex{depths: make([]int, len(records))}
|
index := &resolutionCoverageIndex{depths: make([]int, len(records))}
|
||||||
for id, record := range records {
|
for id, record := range records {
|
||||||
@@ -436,22 +425,6 @@ func pathContains(container, descendant Path) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func appendUniqueString(values []string, value string) []string {
|
|
||||||
if !slices.Contains(values, value) {
|
|
||||||
return append(values, value)
|
|
||||||
}
|
|
||||||
return values
|
|
||||||
}
|
|
||||||
|
|
||||||
func appendUniquePath(paths []Path, path Path) []Path {
|
|
||||||
for _, existing := range paths {
|
|
||||||
if pathSpellingEqual(existing, path) {
|
|
||||||
return paths
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return append(paths, path.clone())
|
|
||||||
}
|
|
||||||
|
|
||||||
func clonePaths(paths []Path) []Path {
|
func clonePaths(paths []Path) []Path {
|
||||||
if paths == nil {
|
if paths == nil {
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package engine
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"slices"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"gitea.maximumdirect.net/eric/ConfigKit/internal/document"
|
"gitea.maximumdirect.net/eric/ConfigKit/internal/document"
|
||||||
@@ -36,14 +37,14 @@ func coalescedResolutionSnapshotsByScan(snapshots []resolutionSnapshot) []resolu
|
|||||||
for _, snapshot := range snapshots {
|
for _, snapshot := range snapshots {
|
||||||
merged := false
|
merged := false
|
||||||
for i := range groups {
|
for i := range groups {
|
||||||
if !pathContains(groups[i].change.Path, snapshot.change.Path) {
|
if !pathContainsByPointer(groups[i].change.Path, snapshot.change.Path) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
for _, reason := range snapshot.change.Reasons {
|
for _, reason := range snapshot.change.Reasons {
|
||||||
groups[i].change.Reasons = appendUniqueString(groups[i].change.Reasons, reason)
|
groups[i].change.Reasons = appendUniqueStringByScan(groups[i].change.Reasons, reason)
|
||||||
}
|
}
|
||||||
for _, dependency := range snapshot.change.Dependencies {
|
for _, dependency := range snapshot.change.Dependencies {
|
||||||
groups[i].change.Dependencies = appendUniquePath(groups[i].change.Dependencies, dependency)
|
groups[i].change.Dependencies = appendUniquePathByPointer(groups[i].change.Dependencies, dependency)
|
||||||
}
|
}
|
||||||
if snapshot.change.Origin.Operation == ChangeNormalization {
|
if snapshot.change.Origin.Operation == ChangeNormalization {
|
||||||
groups[i].change.Origin.Operation = ChangeNormalization
|
groups[i].change.Origin.Operation = ChangeNormalization
|
||||||
@@ -59,6 +60,49 @@ func coalescedResolutionSnapshotsByScan(snapshots []resolutionSnapshot) []resolu
|
|||||||
return groups
|
return groups
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func appendUniqueStringByScan(values []string, value string) []string {
|
||||||
|
if !slices.Contains(values, value) {
|
||||||
|
return append(values, value)
|
||||||
|
}
|
||||||
|
return values
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendUniquePathByPointer(paths []Path, path Path) []Path {
|
||||||
|
for _, existing := range paths {
|
||||||
|
if existing.String() == path.String() {
|
||||||
|
return paths
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return append(paths, path.clone())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestResolutionDependencyMembershipMatchesPointerSpelling(t *testing.T) {
|
||||||
|
parse := func(pointer string) Path {
|
||||||
|
path, err := ParsePath(pointer)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("ParsePath(%q) error = %v", pointer, err)
|
||||||
|
}
|
||||||
|
return path
|
||||||
|
}
|
||||||
|
paths := []Path{
|
||||||
|
Keys("a/b"), parse("/a~1b"),
|
||||||
|
Keys("a~1b"), parse("/a~01b"),
|
||||||
|
Keys("items").Index(0), parse("/items/0"), Keys("items", "0"),
|
||||||
|
Keys("items", "01"), parse("/items/01"),
|
||||||
|
Keys("-1"), parse("/-1"),
|
||||||
|
Keys("a", "b"), Keys("a/b"),
|
||||||
|
}
|
||||||
|
var record resolutionRecord
|
||||||
|
var want []Path
|
||||||
|
for _, path := range paths {
|
||||||
|
record.addDependency(path)
|
||||||
|
want = appendUniquePathByPointer(want, path)
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(record.dependencies, want) {
|
||||||
|
t.Fatalf("resolution dependencies = %#v, want %#v", record.dependencies, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestResolutionCoverageIndexMatchesOrderedScan(t *testing.T) {
|
func TestResolutionCoverageIndexMatchesOrderedScan(t *testing.T) {
|
||||||
paths := []Path{
|
paths := []Path{
|
||||||
Keys("group"),
|
Keys("group"),
|
||||||
@@ -67,7 +111,18 @@ func TestResolutionCoverageIndexMatchesOrderedScan(t *testing.T) {
|
|||||||
Keys("group", "field", "nested"),
|
Keys("group", "field", "nested"),
|
||||||
Keys("other"),
|
Keys("other"),
|
||||||
}
|
}
|
||||||
index := newResolutionCoverageIndex(paths)
|
records := make([]*resolutionRecord, len(paths))
|
||||||
|
snapshots := make([]resolutionSnapshot, len(paths))
|
||||||
|
for id, path := range paths {
|
||||||
|
records[id] = &resolutionRecord{path: path}
|
||||||
|
snapshots[id] = resolutionSnapshot{change: Change{Path: path}}
|
||||||
|
}
|
||||||
|
snapshotIndex, pointers := newResolutionCoverageIndexFromSnapshots(snapshots)
|
||||||
|
for id, pointer := range pointers {
|
||||||
|
if pointer != paths[id].String() {
|
||||||
|
t.Errorf("snapshot pointer %d = %q, want %q", id, pointer, paths[id].String())
|
||||||
|
}
|
||||||
|
}
|
||||||
queries := []Path{
|
queries := []Path{
|
||||||
Path{},
|
Path{},
|
||||||
Keys("group"),
|
Keys("group"),
|
||||||
@@ -77,17 +132,27 @@ func TestResolutionCoverageIndexMatchesOrderedScan(t *testing.T) {
|
|||||||
Keys("other", "child"),
|
Keys("other", "child"),
|
||||||
Keys("group").Index(-1),
|
Keys("group").Index(-1),
|
||||||
}
|
}
|
||||||
for _, query := range queries {
|
for _, test := range []struct {
|
||||||
wantID, wantDepth, wantFound := 0, -1, false
|
name string
|
||||||
for id, candidate := range paths {
|
index *resolutionCoverageIndex
|
||||||
if pathContains(candidate, query) && (!wantFound || len(candidate.segments) > wantDepth) {
|
}{
|
||||||
wantID, wantDepth, wantFound = id, len(candidate.segments), true
|
{"records", newResolutionCoverageIndexFromRecords(records)},
|
||||||
|
{"snapshots", snapshotIndex},
|
||||||
|
} {
|
||||||
|
t.Run(test.name, func(t *testing.T) {
|
||||||
|
for _, query := range queries {
|
||||||
|
wantID, wantDepth, wantFound := 0, -1, false
|
||||||
|
for id, candidate := range paths {
|
||||||
|
if pathContainsByPointer(candidate, query) && (!wantFound || len(candidate.segments) > wantDepth) {
|
||||||
|
wantID, wantDepth, wantFound = id, len(candidate.segments), true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gotID, gotFound := test.index.deepestCoveringID(query)
|
||||||
|
if gotID != wantID || gotFound != wantFound {
|
||||||
|
t.Errorf("deepestCoveringID(%s) = %d, %v; want %d, %v", query.String(), gotID, gotFound, wantID, wantFound)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
gotID, gotFound := index.deepestCoveringID(query)
|
|
||||||
if gotID != wantID || gotFound != wantFound {
|
|
||||||
t.Errorf("deepestCoveringID(%s) = %d, %v; want %d, %v", query.String(), gotID, gotFound, wantID, wantFound)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user