Wire final import declarations through loading
This commit is contained in:
@@ -227,10 +227,11 @@ func TestLoadImportDirectiveValidationAndTemporaryGlobGate(t *testing.T) {
|
||||
{name: "unknown directive field", body: "configkit: {unknown: true}\n", code: CodeImportInvalid},
|
||||
{name: "imports kind", body: "configkit: {imports: {}}\n", code: CodeImportInvalid},
|
||||
{name: "declaration kind", body: "configkit: {imports: [file.yml]}\n", code: CodeImportInvalid},
|
||||
{name: "missing target", body: "configkit: {imports: [{optional: true}]}\n", code: CodeImportInvalid},
|
||||
{name: "missing target", body: "configkit: {imports: [{required: true}]}\n", code: CodeImportInvalid},
|
||||
{name: "two targets", body: "configkit: {imports: [{path: a.yml, glob: '*.yml'}]}\n", code: CodeImportInvalid},
|
||||
{name: "unknown declaration field", body: "configkit: {imports: [{path: a.yml, extra: true}]}\n", code: CodeImportInvalid},
|
||||
{name: "optional kind", body: "configkit: {imports: [{path: a.yml, optional: 'yes'}]}\n", code: CodeImportInvalid},
|
||||
{name: "removed optional field", body: "configkit: {imports: [{path: a.yml, optional: true}]}\n", code: CodeImportInvalid},
|
||||
{name: "required kind", body: "configkit: {imports: [{path: a.yml, required: 'yes'}]}\n", code: CodeImportInvalid},
|
||||
{name: "placement kind", body: "configkit: {imports: [{path: a.yml, placement: true}]}\n", code: CodeImportInvalid},
|
||||
{name: "placement value", body: "configkit: {imports: [{path: a.yml, placement: item}]}\n", code: CodeImportInvalid},
|
||||
{name: "nested directive", body: "nested: {configkit: {}}\n", code: CodeImportInvalid},
|
||||
@@ -473,9 +474,8 @@ func TestLoadItemGlobKeepsDefaultModeIndependentAndOptionalMissesAbsent(t *testi
|
||||
- glob: records/*.yml
|
||||
destination: [items]
|
||||
placement: sequence-item
|
||||
- path: absent/*.yml
|
||||
- glob: absent/*.yml
|
||||
destination: [items]
|
||||
optional: true
|
||||
placement: sequence-item
|
||||
- path: other.yml
|
||||
destination: [other]
|
||||
@@ -578,7 +578,7 @@ func TestParseImportDestinationUsesLiteralStringSegments(t *testing.T) {
|
||||
} {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
body := "configkit:\n imports:\n - path: child.yml\n" + test.destination
|
||||
declarations := parseImportDeclarationsYAML(t, body)
|
||||
declarations := parseImportSpecificationsYAML(t, body)
|
||||
if len(declarations) != 1 {
|
||||
t.Fatalf("declarations = %#v", declarations)
|
||||
}
|
||||
@@ -597,7 +597,7 @@ func TestParseImportDestinationUsesLiteralStringSegments(t *testing.T) {
|
||||
|
||||
func TestParseImportPlacementDefaultsPerDeclaration(t *testing.T) {
|
||||
t.Parallel()
|
||||
declarations := parseImportDeclarationsYAML(t, `configkit:
|
||||
declarations := parseImportSpecificationsYAML(t, `configkit:
|
||||
imports:
|
||||
- path: mapping.yml
|
||||
- glob: records/*.yml
|
||||
@@ -629,7 +629,7 @@ func TestParseImportDestinationRejectsInvalidShapesAndMembers(t *testing.T) {
|
||||
} {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
body := "configkit:\n imports:\n - path: child.yml\n destination: " + test.value + "\n"
|
||||
parsed, diagnostics := parseImportDeclarationYAML(body)
|
||||
parsed, diagnostics := parseImportSpecificationYAML(body)
|
||||
if len(diagnostics) != 1 || diagnostics[0].Code != CodeImportInvalid || diagnostics[0].Path.String() != test.wantPath {
|
||||
t.Fatalf("parse = %#v, want import.invalid at %q", diagnostics, test.wantPath)
|
||||
}
|
||||
@@ -652,12 +652,12 @@ func TestImportDestinationValidationPrecedesOptionalSuppression(t *testing.T) {
|
||||
}{
|
||||
{
|
||||
name: "optional missing path",
|
||||
body: "configkit:\n imports:\n - path: absent.yml\n optional: true\n destination: null\n",
|
||||
body: "configkit:\n imports:\n - path: absent.yml\n destination: null\n",
|
||||
path: "/configkit/imports/0/destination",
|
||||
},
|
||||
{
|
||||
name: "optional unmatched glob",
|
||||
body: "configkit:\n imports:\n - glob: absent/*.yml\n optional: true\n destination: [extends]\n",
|
||||
body: "configkit:\n imports:\n - glob: absent/*.yml\n destination: [extends]\n",
|
||||
path: "/configkit/imports/0/destination/0",
|
||||
},
|
||||
} {
|
||||
@@ -678,7 +678,6 @@ func TestLoadImportMissingContainmentAndRegularFileRules(t *testing.T) {
|
||||
mainPath := writeImportFile(t, directory, "main.yml", `configkit:
|
||||
imports:
|
||||
- path: missing.yml
|
||||
optional: true
|
||||
settings: {root: retained}
|
||||
`)
|
||||
result, err := testLoad[importTestConfig](File(mainPath), Options[importTestConfig]{Imports: true})
|
||||
@@ -711,12 +710,42 @@ settings: {root: retained}
|
||||
if test.setup != nil {
|
||||
test.setup(t, directory)
|
||||
}
|
||||
mainPath := writeImportFile(t, directory, "main.yml", "configkit:\n imports:\n - path: \""+test.path+"\"\n")
|
||||
required := ""
|
||||
if test.code == CodeImportMissing {
|
||||
required = "\n required: true"
|
||||
}
|
||||
mainPath := writeImportFile(t, directory, "main.yml", "configkit:\n imports:\n - path: \""+test.path+"\""+required+"\n")
|
||||
requireLoadCode(t, File(mainPath), Options[importTestConfig]{Imports: true}, test.code)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestImportDefaultsReachOrdinaryAndGroupedDeclarations(t *testing.T) {
|
||||
t.Parallel()
|
||||
required := true
|
||||
directory := t.TempDir()
|
||||
mainPath := writeImportFile(t, directory, "main.yml", "configkit: {imports: [{path: child.yml}]}\n")
|
||||
writeImportFile(t, directory, "child.yml", "configkit: {imports: [{path: absent.yml}]}\n")
|
||||
_, err := testLoad[importTestConfig](File(mainPath), Options[importTestConfig]{
|
||||
Imports: true, importDefaults: importDefaults{required: &required},
|
||||
})
|
||||
var loadError *LoadError
|
||||
if !errors.As(err, &loadError) || len(loadError.Diagnostics()) == 0 || loadError.Diagnostics()[0].Code != CodeImportMissing {
|
||||
t.Fatalf("ordinary transitive required default error = %#v", err)
|
||||
}
|
||||
|
||||
basePath := writeImportFile(t, directory, "base.yml", "settings: {root: base}\n")
|
||||
underlayPath := writeImportFile(t, directory, "underlay.yml", "configkit: {imports: [{path: absent.yml}]}\n")
|
||||
_, err = loadGroupedWithSecretLookup(loadRequest[importTestConfig]{
|
||||
main: loadInput{source: File(basePath)},
|
||||
underlays: []loadGroup{{inputs: []loadInput{{source: File(underlayPath), imports: true}}}},
|
||||
importDefaults: importDefaults{required: &required},
|
||||
}, testSecretBinding(), func(string) (string, bool) { return "", false })
|
||||
if !errors.As(err, &loadError) || len(loadError.Diagnostics()) == 0 || loadError.Diagnostics()[0].Code != CodeImportMissing {
|
||||
t.Fatalf("grouped underlay required default error = %#v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadImportIdentityReportsCyclesAndRepeatedRoutes(t *testing.T) {
|
||||
t.Run("cycle", func(t *testing.T) {
|
||||
directory := t.TempDir()
|
||||
@@ -1073,7 +1102,7 @@ func TestImportedParseAndDecodeDiagnosticsKeepTheirSource(t *testing.T) {
|
||||
|
||||
func TestOptionalImportDoesNotSuppressUnsafeOrUnreadableTargets(t *testing.T) {
|
||||
directory := t.TempDir()
|
||||
mainPath := writeImportFile(t, directory, "outside.yml", "configkit: {imports: [{path: ../missing.yml, optional: true}]}\n")
|
||||
mainPath := writeImportFile(t, directory, "outside.yml", "configkit: {imports: [{path: ../missing.yml}]}\n")
|
||||
requireLoadCode(t, File(mainPath), Options[importTestConfig]{Imports: true}, CodeImportOutsideRoot)
|
||||
|
||||
locked := writeImportFile(t, directory, "locked.yml", "settings: {root: locked}\n")
|
||||
@@ -1085,7 +1114,7 @@ func TestOptionalImportDoesNotSuppressUnsafeOrUnreadableTargets(t *testing.T) {
|
||||
_ = file.Close()
|
||||
t.Skip("filesystem does not enforce the unreadable-file fixture")
|
||||
}
|
||||
mainPath = writeImportFile(t, directory, "main.yml", "configkit: {imports: [{path: locked.yml, optional: true}]}\n")
|
||||
mainPath = writeImportFile(t, directory, "main.yml", "configkit: {imports: [{path: locked.yml}]}\n")
|
||||
requireLoadCode(t, File(mainPath), Options[importTestConfig]{Imports: true}, CodeSourcePermission)
|
||||
}
|
||||
|
||||
@@ -1195,16 +1224,16 @@ func parseImportMain(t *testing.T, filename string) parsedSource {
|
||||
return parsed
|
||||
}
|
||||
|
||||
func parseImportDeclarationsYAML(t *testing.T, input string) []importDeclaration {
|
||||
func parseImportSpecificationsYAML(t *testing.T, input string) []importDeclarationSpec {
|
||||
t.Helper()
|
||||
declarations, diagnostics := parseImportDeclarationYAML(input)
|
||||
declarations, diagnostics := parseImportSpecificationYAML(input)
|
||||
if len(diagnostics) != 0 {
|
||||
t.Fatalf("import parse diagnostics = %#v", diagnostics)
|
||||
}
|
||||
return declarations
|
||||
}
|
||||
|
||||
func parseImportDeclarationYAML(input string) ([]importDeclaration, []Diagnostic) {
|
||||
func parseImportSpecificationYAML(input string) ([]importDeclarationSpec, []Diagnostic) {
|
||||
parsed, diagnostics := parseSource(Bytes("import fixture", []byte(input)), "source-1", defaultParseLimits())
|
||||
if len(diagnostics) != 0 {
|
||||
return nil, diagnostics
|
||||
|
||||
Reference in New Issue
Block a user