package engine import ( "bytes" "strings" "testing" "gitea.maximumdirect.net/eric/ConfigKit/internal/document" ) func TestNestedInheritanceHistoryRetainsUnresolvedTemplates(t *testing.T) { input := `presets: base: settings: primary: {width: 10} secondary: {extends: primary} custom: extends: base settings: primary: {width: 20} grandchild: extends: custom settings: primary: {width: 30} ` loaded, err := Load[map[string]any](Bytes("nested", []byte(input)), testSecretBinding()) if err != nil { t.Fatal(err) } for name, width := range map[string]string{"custom": "20", "grandchild": "30"} { t.Run(name, func(t *testing.T) { root := Keys("presets", name) value, _ := loaded.Inspection.Explain(root.Key("settings").Key("secondary").Key("width")) introduced := false for _, change := range value.History { if change.Origin.Operation == ChangeInheritance && !change.Before.Present && change.After.YAML == width+"\n" { introduced = true } } if !introduced || value.Effective.YAML != width+"\n" { t.Fatalf("missing nested introduction: %#v", value) } controlPath := root.Key("settings").Key("secondary").Key("extends") control, _ := loaded.Inspection.Explain(controlPath) arrived, consumed := false, false for _, change := range control.History { arrived = arrived || change.After.YAML == "primary\n" consumed = consumed || (change.Before.YAML == "primary\n" && !change.After.Present) } if !arrived || !consumed || control.Effective.Present { t.Fatalf("missing control history: %#v", control) } container, _ := loaded.Inspection.Explain(root) unresolved := false for _, change := range container.History { if change.Origin.Operation == ChangeInheritance && strings.Contains(change.After.YAML, "extends: primary") { unresolved = true } } if !unresolved || strings.Contains(container.Effective.YAML, "extends:") { t.Fatalf("invalid enclosing snapshot: %#v", container) } if _, present := loaded.Inspection.Metadata().Lookup(controlPath); present { t.Fatal("control is effective") } if len(loaded.Inspection.Metadata().History(controlPath)) != len(control.History) { t.Fatal("metadata and explanation disagree") } }) } } func TestNestedInheritanceHistoryInsideSequence(t *testing.T) { input := `base: items: - first: {value: inherited} second: {extends: first} child: {extends: base} ` loaded, err := Load[map[string]any](Bytes("sequence", []byte(input)), testSecretBinding()) if err != nil { t.Fatal(err) } path := Keys("child", "items").Index(0).Key("second") control, _ := loaded.Inspection.Explain(path.Key("extends")) consumed := false for _, change := range control.History { consumed = consumed || (change.Before.YAML == "first\n" && !change.After.Present) } if !consumed || control.Effective.Present { t.Fatalf("sequence control history = %#v", control) } value, _ := loaded.Inspection.Explain(path.Key("value")) introduced := false for _, change := range value.History { introduced = introduced || (!change.Before.Present && change.After.YAML == "inherited\n") } if !introduced || value.Effective.YAML != "inherited\n" { t.Fatalf("sequence value history = %#v", value) } } func inheritanceInspectionForTest(t *testing.T, sources ...*document.Node) (*Inspection, *inheritanceScope) { t.Helper() composed, diagnostics := composeDocuments(sources...) if len(diagnostics) != 0 { t.Fatal(diagnostics) } return inheritanceInspectionFromComposition(t, composed) } func inheritanceInspectionFromComposition(t *testing.T, composed *composedDocument) (*Inspection, *inheritanceScope) { t.Helper() expanded, diagnostics := expandInheritanceWithOrigins(composed.root, composed.origins, defaultProjectionLimits()) if len(diagnostics) != 0 { t.Fatal(diagnostics) } baseline := &document.Node{Kind: document.Mapping} presence := make(map[string]inputPresence) collectPresence(expanded.root, Path{}, presence) decoded := decodedConfiguration{ baseline: baseline, final: expanded.root, presence: presence, origins: expanded.origins, } metadata := metadataFromDecoded(decoded) applyInheritanceMetadata(&metadata, composed.root, composed.origins, composed.overlays, expanded) finalizeMetadataPaths(&metadata, expanded.root, composed.applications, baseline, composed.root) return &Inspection{ metadata: metadata, baseline: baseline, input: expanded.root, inputOrigins: expanded.origins, final: expanded.root, applications: composed.applications, inheritance: expanded.operations, }, expanded } func TestInheritanceHistoryFollowsFinalParentAfterSourceOverlay(t *testing.T) { base, diagnostics := composeDocuments(parseCompositionDocument(t, "source-1", "parent: {value: original}\nchild: {extends: parent}\n")) if len(diagnostics) != 0 { t.Fatal(diagnostics) } assembly := newAssemblyAccumulator(base) if diagnostics := assembly.applyOverlay(parseCompositionDocument(t, "source-2", "parent: {value: latest}\n"), nil, nil, LayerOverlay); len(diagnostics) != 0 { t.Fatal(diagnostics) } inspection, _ := inheritanceInspectionFromComposition(t, assembly.current) path := Keys("child", "value") explanation, found := inspection.Explain(path) if !found || explanation.Effective.YAML != "latest\n" || len(explanation.History) == 0 || explanation.History[len(explanation.History)-1].Origin.Locations[0].SourceID != "source-2" { t.Fatalf("overlaid parent contribution = %#v, %v", explanation, found) } parentHistory := inspection.Metadata().History(Keys("parent", "value")) if len(parentHistory) < 2 || parentHistory[0].Origin.Layer != LayerBase || parentHistory[len(parentHistory)-1].Origin.Layer != LayerOverlay { t.Fatalf("parent source history = %#v", parentHistory) } } func TestInheritanceHistoryPreservesCancellationAndSupersededDirective(t *testing.T) { base, diagnostics := composeDocuments(parseCompositionDocument(t, "source-1", "parent: {value: one}\nchild: {extends: missing, value: own}\n")) if len(diagnostics) != 0 { t.Fatal(diagnostics) } assembly := newAssemblyAccumulator(base) if diagnostics := assembly.applyOverlay(parseCompositionDocument(t, "source-2", "child: {extends: null}\n"), nil, nil, LayerOverlay); len(diagnostics) != 0 { t.Fatal(diagnostics) } inspection, _ := inheritanceInspectionFromComposition(t, assembly.current) control := Keys("child", inheritanceKey) history := inspection.Metadata().History(control) if len(history) < 3 || history[0].Origin.Locations[0].SourceID != "source-1" || history[1].Origin.Locations[0].SourceID != "source-2" || history[len(history)-1].Origin.Operation != ChangeInheritance { t.Fatalf("superseded and cancelled directive history = %#v", history) } explanation, found := inspection.Explain(control) if !found || explanation.Effective.Present || len(explanation.History) < 3 || explanation.History[len(explanation.History)-1].After.Present { t.Fatalf("cancelled directive explanation = %#v, %v", explanation, found) } value, found := inspection.Explain(Keys("child", "value")) if !found || value.Effective.YAML != "own\n" { t.Fatalf("cancelled relationship changed own value = %#v, %v", value, found) } } func TestInheritanceHistoryProjectsNestedDestinationValues(t *testing.T) { inspection, _ := inheritanceInspectionForTest(t, parseCompositionDocument(t, "source-1", `base: settings: primary: {value: old} secondary: {extends: primary} custom: extends: base settings: primary: {value: new} `)) path := Keys("custom", "settings", "secondary", "value") history := inspection.Metadata().History(path) structural := 0 for _, change := range history { if change.Origin.Operation == ChangeInheritance { structural++ } } if structural == 0 { t.Fatalf("nested destination history = %#v", history) } explanation, found := inspection.Explain(path) if !found || explanation.Effective.YAML != "new\n" || len(explanation.Origin.Inheritance) == 0 || explanation.Origin.Inheritance[len(explanation.Origin.Inheritance)-1].To.String() != path.String() { t.Fatalf("nested destination explanation = %#v, %v", explanation, found) } for _, change := range explanation.History { if change.Origin.Operation == ChangeDecoding { t.Fatalf("nested inheritance was attributed to decoding: %#v", explanation.History) } } } func TestInheritanceHistoryShowsParentAndEqualChildContribution(t *testing.T) { inspection, _ := inheritanceInspectionForTest(t, parseCompositionDocument(t, "source-1", "parent: {value: same}\n"), parseCompositionDocument(t, "source-2", "child: {extends: parent, value: same}\n")) path := Keys("child", "value") history := inspection.Metadata().History(path) var structural []Change for _, change := range history { if change.Origin.Operation == ChangeInheritance { structural = append(structural, change) } } if len(structural) != 2 || structural[0].Origin.Locations[0].SourceID != "source-1" || structural[1].Origin.Locations[0].SourceID != "source-2" || len(structural[0].Dependencies) != 2 || structural[0].Dependencies[0].String() != "/parent" || len(structural[0].Origin.Inheritance) != 1 { t.Fatalf("equal-valued structural history = %#v", history) } explanation, found := inspection.Explain(path) if !found || explanation.Effective.YAML != "same\n" { t.Fatalf("explanation = %#v, %v", explanation, found) } var equalEvents int for _, change := range explanation.History { if change.Origin.Operation == ChangeDecoding { t.Fatalf("inheritance was attributed to decoding: %#v", explanation.History) } if change.Origin.Operation == ChangeInheritance && change.Before.YAML == change.After.YAML { equalEvents++ } } if equalEvents != 2 { t.Fatalf("equal parent and child operations = %#v", explanation.History) } parentHistory := inspection.Metadata().History(Keys("parent", "value")) for _, change := range parentHistory { if change.Origin.Operation == ChangeInheritance { t.Fatalf("source definition acquired a destination operation: %#v", parentHistory) } } } func TestInheritanceHistoryRetainsControlsAndDisplacedPaths(t *testing.T) { inspection, _ := inheritanceInspectionForTest(t, parseCompositionDocument(t, "source-1", "parent: {branch: {detail: inherited}}\n"), parseCompositionDocument(t, "source-2", "child: {extends: parent, branch: replaced}\n")) control := Keys("child", inheritanceKey) controlHistory := inspection.Metadata().History(control) if len(controlHistory) < 2 || controlHistory[len(controlHistory)-1].Origin.Operation != ChangeInheritance { t.Fatalf("control history = %#v", controlHistory) } controlExplanation, found := inspection.Explain(control) if !found || controlExplanation.Effective.Present || controlExplanation.History[len(controlExplanation.History)-1].After.Present { t.Fatalf("consumed control = %#v, %v", controlExplanation, found) } path := Keys("child", "branch", "detail") if _, found := inspection.Metadata().Lookup(path); found { t.Fatal("displaced descendant remained effective") } listed := false for _, historical := range inspection.Metadata().HistoricalPaths() { if historical.String() == path.String() { listed = true } } if !listed { t.Fatal("displaced inherited descendant was not enumerable") } history := inspection.Metadata().History(path) if len(history) < 2 || history[len(history)-1].Origin.Operation != ChangeInheritance { t.Fatalf("displaced descendant history = %#v", history) } explanation, found := inspection.Explain(path) if !found || explanation.Effective.Present { t.Fatalf("displaced descendant explanation = %#v, %v", explanation, found) } var sawInherited, sawRemoval bool for _, change := range explanation.History { if change.Origin.Operation != ChangeInheritance { continue } sawInherited = sawInherited || change.After.Present sawRemoval = sawRemoval || (change.Before.Present && !change.After.Present) } if !sawInherited || !sawRemoval { t.Fatalf("displaced value sequence = %#v", explanation.History) } var rendered bytes.Buffer if err := inspection.WriteExplanation(&rendered, path); err != nil || !strings.Contains(rendered.String(), "structural inheritance") { t.Fatalf("rendered structural explanation = %q, %v", rendered.String(), err) } } func TestInheritanceHistoryPrecedesApplicationResolution(t *testing.T) { inspection, _ := inheritanceInspectionForTest(t, parseCompositionDocument(t, "source-1", "parent: {value: original}\nchild: {extends: parent}\n")) path := Keys("child", "value") replacement := &document.Node{Kind: document.String, Text: "derived"} snapshot := resolutionSnapshot{ change: Change{Path: path, Origin: Origin{Layer: LayerResolution, Operation: ChangeNormalization}}, after: replacement, } final := document.Clone(inspection.final) replaceHistoryPath(&final, path, replacement) inspection.final = final inspection.resolution = []resolutionSnapshot{snapshot} inspection.metadata.history[path.String()] = append(inspection.metadata.history[path.String()], snapshot.change) inspection.metadata.fields[path.String()] = FieldInfo{Explicit: true, Origin: snapshot.change.Origin} history := inspection.Metadata().History(path) if len(history) < 2 || history[len(history)-2].Origin.Operation != ChangeInheritance || history[len(history)-1].Origin.Operation != ChangeNormalization { t.Fatalf("resolution order = %#v", history) } explanation, found := inspection.Explain(path) if !found || explanation.Effective.YAML != "derived\n" || explanation.History[len(explanation.History)-1].Origin.Operation != ChangeNormalization { t.Fatalf("resolved explanation = %#v, %v", explanation, found) } } func TestHistoryNodeBudgetCountsSharedInheritanceEvidenceOnce(t *testing.T) { shared := &document.Node{Kind: document.String, Text: "shared"} extra := &document.Node{Kind: document.String, Text: "extra"} expansion := &inheritanceScope{ root: shared, operations: []inheritanceOperation{{parent: shared, effective: shared}}, replacements: []inheritanceReplacement{{before: shared, after: extra}}, } if !historyNodesWithin(2, nil, nil, nil, nil, nil, expansion) || historyNodesWithin(1, nil, nil, nil, nil, nil, expansion) { t.Fatal("shared evidence node accounting is incorrect") } } func TestInheritanceExpansionEnforcesRetainedHistoryBudget(t *testing.T) { input := parseCompositionDocument(t, "source-1", "parent: {value: original}\nchild: {extends: parent, value: replacement}\n") if _, diagnostics := expandInheritanceWithBudgets(input, nil, defaultProjectionLimits(), 2); len(diagnostics) != 1 || diagnostics[0].Code != CodeExplainLimitExceeded { t.Fatalf("retained history limit = %#v", diagnostics) } if _, diagnostics := expandInheritanceWithBudgets(input, nil, defaultProjectionLimits(), 100); len(diagnostics) != 0 { t.Fatalf("sufficient retained history budget = %#v", diagnostics) } }