package engine import ( "strings" "testing" ) func TestMovedRemovedFieldHasConsistentHistory(t *testing.T) { type config struct { Items []map[string]any `yaml:"items"` } definition := DefinitionWithSequenceIdentityRegistrations(Definition[config]{ Resolve: func(value *config, r *Resolution) error { delete(value.Items[0], "extra") value.Items[0], value.Items[1] = value.Items[1], value.Items[0] r.RecordNormalization(Keys("items"), "remove field and reorder") return nil }, }, []SequenceIdentityRegistrationInput{{ExactPath: pathPointer(Keys("items")), IdentityFields: []string{"id"}}}) result, err := testLoad(Bytes("records", []byte("items: [{id: a, extra: own}, {id: b}]\n")), Options[config]{Definition: definition}) if err != nil { t.Fatal(err) } path := Keys("items").Index(1).Key("extra") if _, found := result.Metadata().Lookup(path); found { t.Fatal("removed field is effective") } explanation, found := result.Inspection.Explain(path) if !found || len(explanation.History) != 2 { t.Fatalf("explanation = %#v, %t", explanation, found) } history := result.Metadata().History(path) if len(history) != 2 || history[0].Origin.Layer != LayerMain || history[1].Origin.Operation != ChangeNormalization { t.Fatalf("metadata history = %#v", history) } last := explanation.History[1] if last.Before.YAML != "own\n" || last.After.Present { t.Fatalf("removal = %#v", last) } for _, unknown := range []Path{Keys("items", "1", "extra"), Keys("items").Index(1).Key("unknown")} { if history := result.Metadata().History(unknown); len(history) != 0 { t.Fatalf("unexpected history for %s: %#v", unknown.String(), history) } } } func TestMovedInheritedHistoryUsesFinalRecordPrefix(t *testing.T) { type config struct { Items []map[string]any `yaml:"items"` } field := Keys("items").Index(0).Key("nested").Key("more").Key("value") definition := DefinitionWithSequenceIdentityRegistrations(Definition[config]{ Resolve: func(value *config, r *Resolution) error { value.Items[0], value.Items[1] = value.Items[1], value.Items[0] r.RecordNormalization(Keys("items"), "reorder") r.RecordNormalization(field, "retain inherited field") return nil }, }, []SequenceIdentityRegistrationInput{{ExactPath: pathPointer(Keys("items")), IdentityFields: []string{"id"}}}) result, err := testLoad(Bytes("records", []byte("items:\n - id: parent\n nested: {more: {value: old}}\n - id: child\n extends: {id: parent}\n")), Options[config]{Definition: definition}) if err != nil { t.Fatal(err) } physical := result.Metadata().History(Keys("items")) sourceID := result.Inspection.Sources()[0].ID for _, query := range []Path{field, Keys("items").Index(0)} { inherited, recorded := false, false for _, change := range result.Metadata().History(query) { if change.Origin.Operation == ChangeInheritance { inherited = true if !pathContains(Keys("items").Index(0), change.Path) { t.Errorf("inheritance path for %s = %s", query.String(), change.Path.String()) } if query.String() == field.String() && change.Path.String() != "/items/0" { t.Errorf("container operation replaced by leaf path: %s", change.Path.String()) } for _, location := range change.Origin.Locations { if location.SourceID != sourceID || (query.String() == field.String() && location.Line != 3) { t.Errorf("source coordinates changed: %#v", location) } } } if change.Origin.Layer == LayerResolution && len(change.Reasons) == 1 && change.Reasons[0] == "retain inherited field" { recorded = true if change.Path.String() != field.String() { t.Errorf("final resolution path translated twice: %s", change.Path.String()) } } } if !inherited || !recorded { t.Errorf("missing inherited or recorded evidence for %s", query.String()) } } for _, change := range physical { if change.Origin.Operation == ChangeInheritance && !pathContains(Keys("items").Index(1), change.Path) { t.Errorf("collection history lost physical coordinates: %s", change.Path.String()) } } } func TestCyclicMatchingProtectsRemovedAndDerivedValues(t *testing.T) { type config struct { Items []map[string]any `yaml:"items"` Derived string `yaml:"derived"` } removed := Keys("items").Index(1).Key("extra") definition := DefinitionWithSequenceIdentityRegistrations(Definition[config]{ Secret: func(path Path) bool { return path.String() == "/items/0/extra" }, Resolve: func(value *config, r *Resolution) error { value.Derived = value.Items[0]["extra"].(string) delete(value.Items[0], "extra") last := value.Items[len(value.Items)-1] copy(value.Items[1:], value.Items[:len(value.Items)-1]) value.Items[0] = last r.RecordNormalization(Keys("items"), "remove field and rotate") r.RecordDerivedDefault(Keys("derived"), "derive from removed value", removed) return nil }, }, []SequenceIdentityRegistrationInput{{ExactPath: pathPointer(Keys("items")), IdentityFields: []string{"id"}}}) result, err := testLoad(Bytes("records", []byte("items: [{id: a, extra: CYCLIC_PRIVATE_CANARY}, {id: b}, {id: c}, {id: d}]\n")), Options[config]{Definition: definition}) if err != nil { t.Fatal(err) } for _, path := range []Path{Keys("items"), removed, Keys("derived")} { explanation, found := result.Inspection.Explain(path) if !found { t.Fatalf("missing explanation for %s", path.String()) } if strings.Contains(explanation.Effective.YAML, "CYCLIC_PRIVATE_CANARY") { t.Fatalf("effective value leaked at %s", path.String()) } for _, change := range explanation.History { if strings.Contains(change.Before.YAML, "CYCLIC_PRIVATE_CANARY") || strings.Contains(change.After.YAML, "CYCLIC_PRIVATE_CANARY") { t.Fatalf("history leaked at %s", path.String()) } } } var output strings.Builder if err := result.Inspection.WriteEffective(&output); err != nil { t.Fatal(err) } if strings.Contains(output.String(), "CYCLIC_PRIVATE_CANARY") { t.Fatal("effective rendering leaked") } } func TestCorrespondenceIndexPreservesPathShapes(t *testing.T) { destination := Keys("groups", "0", "a/b~") policy, diagnostics := compileSequenceIdentityPolicy([]sequenceIdentityRegistration{{ selector: sequenceIdentitySelector{ literalSequenceSelector("groups"), literalSequenceSelector("0"), literalSequenceSelector("a/b~"), }, identityFields: []string{"id"}, }}) if len(diagnostics) != 0 { t.Fatal(diagnostics) } before := parseCompositionDocument(t, "before", "groups: {'0': {'a/b~': [{id: a}, {id: b}]}}") after := parseCompositionDocument(t, "after", "groups: {'0': {'a/b~': [{id: b}, {id: a}, {id: new}]}}") matching := buildResolutionCorrespondence(before, after, policy) parsed, err := ParsePath("/groups/0/a~1b~0/0/field") if err != nil { t.Fatal(err) } for _, path := range []Path{destination.Index(0).Key("field"), parsed} { entry, found := matching.entryPath(path) if !found || entry.String() != destination.Index(1).Key("field").String() { t.Fatalf("entry = %s, %t", entry.String(), found) } final, found := matching.finalPath(entry) if !found || final.String() != path.String() { t.Fatalf("round trip = %s, %t", final.String(), found) } } for _, path := range []Path{ Keys("groups").Index(0).Key("a/b~").Index(0), destination.Key("0"), destination.Index(8), destination, } { entry, found := matching.entryPath(path) if !found || entry.String() != path.String() { t.Fatalf("positional path %s became %s, %t", path.String(), entry.String(), found) } } if _, found := matching.entryPath(destination.Index(2)); found { t.Fatal("new identity acquired entry evidence") } }