Test configuration source evidence

This commit is contained in:
2026-11-04 15:02:06 +00:00
parent 72099958d1
commit 42176a7ac4
2 changed files with 41 additions and 15 deletions

View File

@@ -1,6 +1,6 @@
# ConfigKit v1.1.0 adoption implementation plan # ConfigKit v1.1.0 adoption implementation plan
Status: Stages 1–2 complete; Stages 3–6 are not started. Status: Stages 1–3 complete; Stages 4–6 are not started.
This plan is for a Luna coding agent implementing the selected This plan is for a Luna coding agent implementing the selected
[ConfigKit adoption target](configkit-v1.1.0.md). Follow Stage 1 through Stage 6 [ConfigKit adoption target](configkit-v1.1.0.md). Follow Stage 1 through Stage 6
@@ -148,6 +148,10 @@ source inventory, explanation, diagnostic, and outcome semantics are retained.
## Stage 3: Update focused report and adapter coverage ## Stage 3: Update focused report and adapter coverage
**Completed.** Focused source tests cover the new text and YAML keys, native
main layer, ordered selections, empty lists, and nil/redacted evidence. The
offline `TestSources` suite passed with Go 1.27.0.
1. Extend `TestSourcesProjectNativeEvidenceInTextAndYAML` in `sources_test.go` 1. Extend `TestSourcesProjectNativeEvidenceInTextAndYAML` in `sources_test.go`
rather than building another report-test framework. Update fixtures and rather than building another report-test framework. Update fixtures and
assertions to the new native fields and report keys. Check that legacy assertions to the new native fields and report keys. Check that legacy

View File

@@ -34,7 +34,11 @@ func TestSourcesProjectNativeEvidenceInTextAndYAML(t *testing.T) {
reader := &sourceInventory{values: []configkit.SourceInfo{ reader := &sourceInventory{values: []configkit.SourceInfo{
{ {
ID: "root", Label: "root source", Path: "root.yml", ID: "root", Label: "root source", Path: "root.yml",
PlacementMode: configkit.PlacementModeMapping, PlacementMode: configkit.PlacementModeMapping, Layer: configkit.LayerMain,
EmptyImportSelections: []configkit.EmptyImportSelection{
{Path: configkit.Keys("imports", "first"), Location: configkit.Location{SourceID: "root.yml", Line: 3, Column: 4}, Selector: configkit.ImportSelectorGlob},
{Path: configkit.Keys("imports", "second"), Location: configkit.Location{}, Selector: configkit.ImportSelectorPath},
},
}, },
{ {
ID: "item", Label: "sequence item", Path: "item.yml", ID: "item", Label: "sequence item", Path: "item.yml",
@@ -70,11 +74,13 @@ func TestSourcesProjectNativeEvidenceInTextAndYAML(t *testing.T) {
var report struct { var report struct {
Scope string `yaml:"scope"` Scope string `yaml:"scope"`
Sources []struct { Sources []struct {
ID string `yaml:"id"` ID string `yaml:"id"`
Destination string `yaml:"destination"` Destination string `yaml:"destination"`
Placement string `yaml:"placement"` Placement string `yaml:"placement"`
DestinationUnresolved bool `yaml:"destination_unresolved"` Layer string `yaml:"layer"`
VersionCheck *struct { EmptyImportSelections []emptyImportSelectionDTO `yaml:"empty_import_selections"`
DestinationIsFallback bool `yaml:"destination_is_fallback"`
VersionEvidence *struct {
Path string `yaml:"path"` Path string `yaml:"path"`
Version struct { Version struct {
Present bool `yaml:"present"` Present bool `yaml:"present"`
@@ -87,7 +93,7 @@ func TestSourcesProjectNativeEvidenceInTextAndYAML(t *testing.T) {
Column int `yaml:"column"` Column int `yaml:"column"`
} `yaml:"location"` } `yaml:"location"`
Redacted bool `yaml:"redacted"` Redacted bool `yaml:"redacted"`
} `yaml:"version_check"` } `yaml:"version_evidence"`
} `yaml:"sources"` } `yaml:"sources"`
} }
if err := yaml.Unmarshal(yamlOutput.Bytes(), &report); err != nil { if err := yaml.Unmarshal(yamlOutput.Bytes(), &report); err != nil {
@@ -99,21 +105,31 @@ func TestSourcesProjectNativeEvidenceInTextAndYAML(t *testing.T) {
if got := []string{report.Sources[0].ID, report.Sources[1].ID, report.Sources[2].ID}; !reflect.DeepEqual(got, []string{"root", "item", "null"}) { if got := []string{report.Sources[0].ID, report.Sources[1].ID, report.Sources[2].ID}; !reflect.DeepEqual(got, []string{"root", "item", "null"}) {
t.Fatalf("source order = %v", got) t.Fatalf("source order = %v", got)
} }
if root := report.Sources[0]; root.Destination != "" || root.Placement != "mapping" || root.DestinationUnresolved || root.VersionCheck != nil { if root := report.Sources[0]; root.Destination != "" || root.Placement != "mapping" || root.DestinationIsFallback || root.VersionEvidence != nil || root.Layer != "main" {
t.Errorf("root source projection = %#v", root) t.Errorf("root source projection = %#v", root)
} }
wantSelections := []emptyImportSelectionDTO{
{Path: "/imports/first", Location: locationDTO{SourceID: "root.yml", Line: 3, Column: 4}, Selector: "glob"},
{Path: "/imports/second", Location: locationDTO{}, Selector: "path"},
}
if !reflect.DeepEqual(report.Sources[0].EmptyImportSelections, wantSelections) || report.Sources[1].EmptyImportSelections == nil || len(report.Sources[1].EmptyImportSelections) != 0 {
t.Fatalf("import selections: %#v", report.Sources)
}
if strings.Contains(yamlOutput.String(), "destination_unresolved:") || strings.Contains(yamlOutput.String(), "version_check:") {
t.Fatal("legacy YAML keys present")
}
item := report.Sources[1] item := report.Sources[1]
if item.Destination != "/services" || item.Placement != "sequence_item" || !item.DestinationUnresolved { if item.Destination != "/services" || item.Placement != "sequence_item" || !item.DestinationIsFallback {
t.Errorf("sequence item projection = %#v", item) t.Errorf("sequence item projection = %#v", item)
} }
if check := item.VersionCheck; check == nil || check.Path != "/version" || !check.Version.Present || check.Version.Null || check.Version.Text != "v2" || check.Location == nil || check.Location.SourceID != "item.yml" || check.Location.Line != 4 || check.Location.Column != 2 || check.Redacted { if check := item.VersionEvidence; check == nil || check.Path != "/version" || !check.Version.Present || check.Version.Null || check.Version.Text != "v2" || check.Location == nil || check.Location.SourceID != "item.yml" || check.Location.Line != 4 || check.Location.Column != 2 || check.Redacted {
t.Errorf("text version evidence projection = %#v", check) t.Errorf("text version evidence projection = %#v", check)
} }
nullSource := report.Sources[2] nullSource := report.Sources[2]
if nullSource.Destination != "/other" || nullSource.Placement != "mapping" || nullSource.DestinationUnresolved { if nullSource.Destination != "/other" || nullSource.Placement != "mapping" || nullSource.DestinationIsFallback {
t.Errorf("mapping projection = %#v", nullSource) t.Errorf("mapping projection = %#v", nullSource)
} }
if check := nullSource.VersionCheck; check == nil || check.Path != "/metadata/version" || !check.Version.Present || !check.Version.Null || check.Version.Text != "" || check.Location != nil || !check.Redacted { if check := nullSource.VersionEvidence; check == nil || check.Path != "/metadata/version" || !check.Version.Present || !check.Version.Null || check.Version.Text != "" || check.Location != nil || !check.Redacted {
t.Errorf("null/redacted version evidence projection = %#v", check) t.Errorf("null/redacted version evidence projection = %#v", check)
} }
@@ -122,9 +138,15 @@ func TestSourcesProjectNativeEvidenceInTextAndYAML(t *testing.T) {
if outcome.Kind != commandkit.OutcomeSuccess || reader.calls != 2 { if outcome.Kind != commandkit.OutcomeSuccess || reader.calls != 2 {
t.Fatalf("text source report outcome=%#v calls=%d", outcome, reader.calls) t.Fatalf("text source report outcome=%#v calls=%d", outcome, reader.calls)
} }
if strings.Contains(textOutput.String(), "destination_unresolved:") || strings.Contains(textOutput.String(), "version_check:") {
t.Fatal("legacy text keys present")
}
if strings.Index(textOutput.String(), `path: "/imports/first"`) > strings.Index(textOutput.String(), `path: "/imports/second"`) {
t.Fatal("import selection order changed")
}
for _, fragment := range []string{ for _, fragment := range []string{
`id: "root"`, `destination: ""`, `placement: "mapping"`, "destination_unresolved: false", "version_check: null", `id: "root"`, `destination: ""`, `placement: "mapping"`, `layer: "main"`, "destination_is_fallback: false", "version_evidence: null", `path: "/imports/first"`, `location: {source_id: "root.yml", line: 3, column: 4}`, `selector: "glob"`, `path: "/imports/second"`, `location: {source_id: "", line: 0, column: 0}`, `selector: "path"`, "empty_import_selections: []",
`destination: "/services"`, `placement: "sequence_item"`, "destination_unresolved: true", `path: "/version"`, `text: "v2"`, `destination: "/services"`, `placement: "sequence_item"`, "destination_is_fallback: true", `path: "/version"`, `text: "v2"`,
`destination: "/other"`, `path: "/metadata/version"`, "null: true", `text: ""`, "location: null", "redacted: true", `destination: "/other"`, `path: "/metadata/version"`, "null: true", `text: ""`, "location: null", "redacted: true",
} { } {
if !strings.Contains(textOutput.String(), fragment) { if !strings.Contains(textOutput.String(), fragment) {