Index inherited compound identity restoration
This commit is contained in:
@@ -1030,6 +1030,14 @@ templates remain correct. Source review establishes O(K + C + M) lookup work plu
|
|||||||
required copied values for K identity fields and C/M mapping entries.
|
required copied values for K identity fields and C/M mapping entries.
|
||||||
Focused check: `go test ./internal/engine -run 'Identified|Identity|Inheritance'`.
|
Focused check: `go test ./internal/engine -run 'Identified|Identity|Inheritance'`.
|
||||||
|
|
||||||
|
Status: **complete** (E05). Prior completed commits include `549fca2`,
|
||||||
|
`3a1b6ff`, `d172a5e`, `1dd94a3`, and `75e209e`. Validation passed:
|
||||||
|
`env GOTOOLCHAIN=local GOPROXY=off GOTELEMETRY=off go test ./internal/engine -run 'Identified|Identity|Inheritance' -count=1`,
|
||||||
|
`env GOTOOLCHAIN=local GOPROXY=off GOTELEMETRY=off go test ./internal/engine -count=1`,
|
||||||
|
`env GOTOOLCHAIN=local GOPROXY=off GOTELEMETRY=off go test ./... -count=1`,
|
||||||
|
`env GOTOOLCHAIN=local GOPROXY=off GOTELEMETRY=off go test -race ./...`,
|
||||||
|
and `git diff --check`.
|
||||||
|
|
||||||
## Stage 32 — Index Secret Failure Locations Only When Needed
|
## Stage 32 — Index Secret Failure Locations Only When Needed
|
||||||
|
|
||||||
Finding: **F08**.
|
Finding: **F08**.
|
||||||
|
|||||||
@@ -24,6 +24,83 @@ func parseIdentifiedInheritanceSequence(t *testing.T, sourceID, input string) *d
|
|||||||
return sequence
|
return sequence
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestPreserveInheritanceIdentityIndexesCompoundFields(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
mergedEntries := []document.Entry{
|
||||||
|
{Key: "before", Value: &document.Node{Kind: document.String, Text: "keep"}},
|
||||||
|
{Key: "id", KeyLocation: document.Location{SourceID: "parent", Line: 2}, ValueLocation: document.Location{SourceID: "parent", Line: 2}, Value: &document.Node{Kind: document.String, Text: "parent-id"}},
|
||||||
|
}
|
||||||
|
for index := 0; index < 64; index++ {
|
||||||
|
key := "setting-" + string(rune('a'+index))
|
||||||
|
mergedEntries = append(mergedEntries, document.Entry{Key: key, Value: &document.Node{Kind: document.String, Text: key}})
|
||||||
|
}
|
||||||
|
mergedEntries = append(mergedEntries,
|
||||||
|
document.Entry{Key: "a/b~c", KeyLocation: document.Location{SourceID: "parent", Line: 70}, ValueLocation: document.Location{SourceID: "parent", Line: 70}, Value: &document.Node{Kind: document.String, Text: "parent-literal"}},
|
||||||
|
document.Entry{Key: "missing", Value: &document.Node{Kind: document.String, Text: "retained"}},
|
||||||
|
document.Entry{Key: "after", Value: &document.Node{Kind: document.String, Text: "keep"}},
|
||||||
|
)
|
||||||
|
merged := &document.Node{Kind: document.Mapping, Mapping: mergedEntries}
|
||||||
|
child := &document.Node{Kind: document.Mapping, Mapping: []document.Entry{
|
||||||
|
{Key: "a/b~c", KeyLocation: document.Location{SourceID: "child", Line: 9, Column: 3}, ValueLocation: document.Location{SourceID: "child", Line: 9, Column: 10}, Value: &document.Node{Kind: document.String, Text: "child-literal", Location: document.Location{SourceID: "child", Line: 9, Column: 10}}},
|
||||||
|
{Key: "id", KeyLocation: document.Location{SourceID: "child", Line: 3, Column: 3}, ValueLocation: document.Location{SourceID: "child", Line: 3, Column: 7}, Value: &document.Node{Kind: document.String, Text: "child-id", Location: document.Location{SourceID: "child", Line: 3, Column: 7}}},
|
||||||
|
}}
|
||||||
|
beforeKeys := make([]string, len(merged.Mapping))
|
||||||
|
for index, entry := range merged.Mapping {
|
||||||
|
beforeKeys[index] = entry.Key
|
||||||
|
}
|
||||||
|
untouched := merged.Mapping[2].Value
|
||||||
|
|
||||||
|
preserveInheritanceIdentityFields(merged, child, []string{"id", "a/b~c", "missing"})
|
||||||
|
|
||||||
|
for index, entry := range merged.Mapping {
|
||||||
|
if entry.Key != beforeKeys[index] {
|
||||||
|
t.Fatalf("mapping order changed at %d: %q, want %q", index, entry.Key, beforeKeys[index])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, want := range []struct {
|
||||||
|
key string
|
||||||
|
text string
|
||||||
|
keyLine int
|
||||||
|
keyColumn int
|
||||||
|
valueLine int
|
||||||
|
valueColumn int
|
||||||
|
}{
|
||||||
|
{key: "id", text: "child-id", keyLine: 3, keyColumn: 3, valueLine: 3, valueColumn: 7},
|
||||||
|
{key: "a/b~c", text: "child-literal", keyLine: 9, keyColumn: 3, valueLine: 9, valueColumn: 10},
|
||||||
|
} {
|
||||||
|
var got document.Entry
|
||||||
|
for _, entry := range merged.Mapping {
|
||||||
|
if entry.Key == want.key {
|
||||||
|
got = entry
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if got.Value == nil || got.Value.Text != want.text || got.KeyLocation.SourceID != "child" || got.KeyLocation.Line != want.keyLine || got.KeyLocation.Column != want.keyColumn ||
|
||||||
|
got.ValueLocation.SourceID != "child" || got.ValueLocation.Line != want.valueLine || got.ValueLocation.Column != want.valueColumn ||
|
||||||
|
got.Value.Location.SourceID != "child" || got.Value.Location.Line != want.valueLine || got.Value.Location.Column != want.valueColumn {
|
||||||
|
t.Fatalf("restored identity %q = %#v", want.key, got)
|
||||||
|
}
|
||||||
|
if got.Value == child.Mapping[0].Value || (want.key == "id" && got.Value == child.Mapping[1].Value) {
|
||||||
|
t.Fatalf("restored identity %q borrows its child value", want.key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if merged.Mapping[2].Value != untouched {
|
||||||
|
t.Fatal("nonidentity sibling was replaced")
|
||||||
|
}
|
||||||
|
for _, entry := range merged.Mapping {
|
||||||
|
if entry.Key == "missing" && entry.Value.Text != "retained" {
|
||||||
|
t.Fatalf("identity absent from child was changed: %#v", entry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
child.Mapping[0].Value.Text = "mutated"
|
||||||
|
for _, entry := range merged.Mapping {
|
||||||
|
if entry.Key == "a/b~c" && entry.Value.Text != "child-literal" {
|
||||||
|
t.Fatal("restored identity value aliases the child template")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestIdentifiedInheritanceGraphSchedulesForwardReferencesInPlace(t *testing.T) {
|
func TestIdentifiedInheritanceGraphSchedulesForwardReferencesInPlace(t *testing.T) {
|
||||||
sequence := parseIdentifiedInheritanceSequence(t, "identified-graph", `- id: 2
|
sequence := parseIdentifiedInheritanceSequence(t, "identified-graph", `- id: 2
|
||||||
tenant: acme
|
tenant: acme
|
||||||
|
|||||||
@@ -144,18 +144,24 @@ func preserveInheritanceIdentityFields(merged, child *document.Node, fields []st
|
|||||||
if len(fields) == 0 || merged == nil || merged.Kind != document.Mapping || child == nil || child.Kind != document.Mapping {
|
if len(fields) == 0 || merged == nil || merged.Kind != document.Mapping || child == nil || child.Kind != document.Mapping {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
identityFields := make(map[string]struct{}, len(fields))
|
||||||
for _, field := range fields {
|
for _, field := range fields {
|
||||||
|
identityFields[field] = struct{}{}
|
||||||
|
}
|
||||||
|
positions := make(map[string]int, len(merged.Mapping))
|
||||||
|
for index, entry := range merged.Mapping {
|
||||||
|
if _, exists := positions[entry.Key]; !exists {
|
||||||
|
positions[entry.Key] = index
|
||||||
|
}
|
||||||
|
}
|
||||||
for _, entry := range child.Mapping {
|
for _, entry := range child.Mapping {
|
||||||
if entry.Key != field {
|
if _, identity := identityFields[entry.Key]; !identity {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
for index := range merged.Mapping {
|
delete(identityFields, entry.Key)
|
||||||
if merged.Mapping[index].Key == field {
|
if index, exists := positions[entry.Key]; exists {
|
||||||
merged.Mapping[index] = document.Entry{Key: field, Value: document.Clone(entry.Value)}
|
entry.Value = document.Clone(entry.Value)
|
||||||
break
|
merged.Mapping[index] = entry
|
||||||
}
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user