Preserve item helper history in source order

This commit is contained in:
2026-10-17 04:44:29 +00:00
parent 4633a1b8a2
commit 26720b98f0
4 changed files with 89 additions and 18 deletions

View File

@@ -6,10 +6,71 @@ import (
"path/filepath"
"strings"
"testing"
"testing/fstest"
configkit "gitea.maximumdirect.net/eric/ConfigKit"
)
func TestFacadeItemHelperHistoryPreservesTraversalOrder(t *testing.T) {
t.Parallel()
filesystem := configkit.NewFilesystem("history", fstest.MapFS{
"main.yml": {Data: []byte("records: [{id: authored}]\nconfigkit: {imports: [{path: one.yml, destination: [records], placement: sequence-item}, {path: two.yml, destination: [records], placement: sequence-item}]}\n")},
"one.yml": {Data: []byte("id: one\nconfigkit: {imports: [{path: helper-one.yml}, {path: child.yml, destination: [children], placement: sequence-item}]}\n")},
"two.yml": {Data: []byte("id: two\nconfigkit: {imports: [{path: helper-two.yml}]}\n")},
"helper-one.yml": {Data: []byte("text: first helper\n")},
"helper-two.yml": {Data: []byte("text: second helper\n")},
"child.yml": {Data: []byte("id: child\nconfigkit: {imports: [{path: child-helper.yml}]}\n")},
"child-helper.yml": {Data: []byte("text: nested helper\n")},
})
result, err := configkit.Load(filesystem.File("main.yml"), configkit.Options[map[string]any]{
Imports: true, Definition: configkit.Definition[map[string]any]{SequenceCompositions: []configkit.SequenceComposition{{Path: configkit.Keys("records"), IdentityField: "id"}}},
})
if err != nil {
t.Fatal(err)
}
sourceOrder := make(map[string]int)
sourceFiles := make(map[string]string)
for index, source := range result.Sources() {
sourceOrder[source.ID] = index
sourceFiles[source.ID] = source.Path
}
for _, test := range []struct {
path configkit.Path
file, text string
}{
{configkit.Keys("records").Index(1).Key("text"), "helper-one.yml", "first helper\n"},
{configkit.Keys("records").Index(2).Key("text"), "helper-two.yml", "second helper\n"},
{configkit.Keys("records").Index(1).Key("children").Index(0).Key("text"), "child-helper.yml", "nested helper\n"},
} {
explanation, ok := result.Explain(test.path)
if !ok || explanation.Effective.YAML != test.text || len(explanation.History) != 1 {
t.Fatalf("helper history at %s = %#v", test.path.String(), explanation)
}
locations := explanation.History[0].Origin.Locations
if len(locations) != 1 || sourceFiles[locations[0].SourceID] != test.file {
t.Fatalf("helper origin at %s = %#v", test.path.String(), locations)
}
info, ok := result.Metadata().Lookup(test.path)
if !ok || len(info.Origin.Locations) != 1 || info.Origin.Locations[0].SourceID != locations[0].SourceID {
t.Fatal("metadata and explanation disagree")
}
}
explanation, ok := result.Explain(configkit.Keys())
if !ok {
t.Fatal("root explanation missing")
}
previous := -1
for _, change := range explanation.History {
for _, location := range change.Origin.Locations {
current := sourceOrder[location.SourceID]
if current < previous {
t.Fatalf("source %s replayed out of traversal order", location.SourceID)
}
previous = current
}
}
}
func TestFacadeSequencePlacementControlsAcrossLoadEntryPoints(t *testing.T) {
definition := configkit.Definition[map[string]any]{
SequenceCompositions: []configkit.SequenceComposition{{Path: configkit.Keys("entries"), IdentityField: "id"}},