Handle companion imports without a filesystem base

This commit is contained in:
2026-11-09 20:38:55 +00:00
parent e47960d377
commit b93cbb0639
5 changed files with 187 additions and 1 deletions

View File

@@ -68,3 +68,91 @@ func TestMainRelativeContextSelection(t *testing.T) {
t.Fatalf("fallback value = %q", got)
}
}
func TestMainRelativeWithoutBase(t *testing.T) {
tests := []struct {
name, source string
requireBase bool
wantCode configkit.Code
}{
{"optional", "config: {imports: [{path: missing.yml}]}\ncount: 7\n", false, ""},
{"required", "config: {imports: [{path: missing.yml, required: true}]}\n", false, configkit.CodeImportMissing},
{"required directory", "config: {imports: [{dir: missing, required: true}]}\n", false, configkit.CodeImportMissing},
{"required glob", "config: {imports: [{glob: '*.yml', required: true}]}\n", false, configkit.CodeImportMissing},
{"empty required", "config: {imports: [{path: [], required: true}]}\ncount: 7\n", false, ""},
{"base required", "count: 7\n", true, configkit.CodeOptionsInvalid},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
input := configkit.Input{Source: configkit.Bytes("companion", []byte(test.source)), Imports: true, MainRelative: &configkit.MainRelativeContext{RequireBase: test.requireBase}}
result, err := configkit.LoadLayered(configkit.Input{Source: configkit.NoSource()}, configkit.LayeredOptions[layeredFacadeConfig]{Underlays: []configkit.Underlay{{Inputs: []configkit.Input{input}}}})
if test.wantCode != "" {
if err == nil {
t.Fatal("expected failure")
}
for _, d := range err.(*configkit.LoadError).Diagnostics() {
if d.Code == test.wantCode {
return
}
}
t.Fatalf("diagnostics: %#v", err.(*configkit.LoadError).Diagnostics())
}
if err != nil {
t.Fatalf("%v: %#v", err, err.(*configkit.LoadError).Diagnostics())
}
if result.Config.Count != 7 {
t.Fatalf("config = %#v", result.Config)
}
if sources := result.Sources(); len(sources) != 1 || len(sources[0].EmptyImportSelections) != 0 {
t.Fatalf("sources = %#v", sources)
}
})
}
}
func TestMainRelativeWithoutBaseSequenceItem(t *testing.T) {
type item struct {
Name string `yaml:"name"`
}
type config struct {
Items []item `yaml:"items"`
}
input := configkit.Input{Source: configkit.Bytes("item", []byte("config: {imports: [{path: missing.yml}]}\nname: example\n")), Imports: true, MainRelative: configkit.MainRelative(), Destination: configkit.Keys("items"), PlacementMode: configkit.PlacementModeSequenceItem}
result, err := configkit.LoadLayered(configkit.Input{Source: configkit.NoSource()}, configkit.LayeredOptions[config]{Underlays: []configkit.Underlay{{Inputs: []configkit.Input{input}}}})
if err != nil {
t.Fatalf("%v: %#v", err, err.(*configkit.LoadError).Diagnostics())
}
if len(result.Config.Items) != 1 || result.Config.Items[0].Name != "example" {
t.Fatalf("config = %#v", result.Config)
}
}
func TestMainRelativeWithoutBaseImportDefaults(t *testing.T) {
required := true
tests := []struct {
name, source string
imports bool
requireBase bool
code configkit.Code
}{
{"default required", "config: {imports: [{path: missing.yml}]}\n", true, false, configkit.CodeImportMissing},
{"malformed", "config: {imports: [{path: 42}]}\n", true, false, configkit.CodeImportInvalid},
{"imports disabled", "config: {imports: [{path: missing.yml}]}\n", false, false, configkit.CodeImportDisabled},
{"base required without imports", "count: 1\n", false, true, configkit.CodeOptionsInvalid},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
input := configkit.Input{Source: configkit.Bytes("companion", []byte(test.source)), Imports: test.imports, MainRelative: &configkit.MainRelativeContext{RequireBase: test.requireBase}}
_, err := configkit.LoadLayered(configkit.Input{Source: configkit.NoSource()}, configkit.LayeredOptions[layeredFacadeConfig]{ImportDefaults: configkit.ImportDefaults{Required: &required}, Underlays: []configkit.Underlay{{Inputs: []configkit.Input{input}}}})
if err == nil {
t.Fatal("expected failure")
}
for _, diagnostic := range err.(*configkit.LoadError).Diagnostics() {
if diagnostic.Code == test.code {
return
}
}
t.Fatalf("diagnostics = %#v", err.(*configkit.LoadError).Diagnostics())
})
}
}