Prepare ConfigKit v0.1.1
This commit is contained in:
@@ -22,16 +22,37 @@ type importTestConfig struct {
|
||||
Items map[string]string `yaml:"items"`
|
||||
}
|
||||
|
||||
func TestLoadFormerDirectiveKeyIsApplicationData(t *testing.T) {
|
||||
type config struct {
|
||||
Legacy struct {
|
||||
Imports []struct {
|
||||
Path string `yaml:"path"`
|
||||
} `yaml:"imports"`
|
||||
} `yaml:"_configkit"`
|
||||
}
|
||||
for _, imports := range []bool{false, true} {
|
||||
directory := t.TempDir()
|
||||
mainPath := writeImportFile(t, directory, "main.yml", "_configkit:\n imports:\n - path: nonexistent.yml\n")
|
||||
result, err := Load[config](File(mainPath), Options[config]{Imports: imports})
|
||||
if err != nil {
|
||||
t.Fatalf("Imports=%v: %v", imports, err)
|
||||
}
|
||||
if len(result.Config.Legacy.Imports) != 1 || result.Config.Legacy.Imports[0].Path != "nonexistent.yml" || len(result.Sources()) != 1 {
|
||||
t.Fatalf("Imports=%v: former directive was not retained as application data: %#v", imports, result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadTraversesPathImportsDepthFirstAndComposesOrigins(t *testing.T) {
|
||||
directory := t.TempDir()
|
||||
mainPath := writeImportFile(t, directory, "main.yml", `_configkit:
|
||||
mainPath := writeImportFile(t, directory, "main.yml", `configkit:
|
||||
imports:
|
||||
- path: first.yml
|
||||
- path: second.yml
|
||||
settings:
|
||||
root: root
|
||||
`)
|
||||
firstPath := writeImportFile(t, directory, "first.yml", `_configkit:
|
||||
firstPath := writeImportFile(t, directory, "first.yml", `configkit:
|
||||
imports:
|
||||
- path: nested/third.yml
|
||||
settings:
|
||||
@@ -71,7 +92,7 @@ settings:
|
||||
func TestLoadRejectsImportConflictsAndFragmentVersions(t *testing.T) {
|
||||
t.Run("all duplicate claimants", func(t *testing.T) {
|
||||
directory := t.TempDir()
|
||||
mainPath := writeImportFile(t, directory, "main.yml", `_configkit:
|
||||
mainPath := writeImportFile(t, directory, "main.yml", `configkit:
|
||||
imports:
|
||||
- path: one.yml
|
||||
- path: two.yml
|
||||
@@ -97,7 +118,7 @@ func TestLoadRejectsImportConflictsAndFragmentVersions(t *testing.T) {
|
||||
} {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
directory := t.TempDir()
|
||||
mainPath := writeImportFile(t, directory, "main.yml", "_configkit:\n imports:\n - path: fragment.yml\n")
|
||||
mainPath := writeImportFile(t, directory, "main.yml", "configkit:\n imports:\n - path: fragment.yml\n")
|
||||
writeImportFile(t, directory, "fragment.yml", test.fragment)
|
||||
loadError := requireLoadCode(t, File(mainPath), Options[importTestConfig]{Imports: true, Definition: Definition[importTestConfig]{Version: versionRule}}, CodeImportVersion)
|
||||
diagnostic := loadError.Diagnostics()[0]
|
||||
@@ -114,15 +135,15 @@ func TestLoadImportDirectiveValidationAndTemporaryGlobGate(t *testing.T) {
|
||||
body string
|
||||
code Code
|
||||
}{
|
||||
{name: "directive kind", body: "_configkit: []\n", code: CodeImportInvalid},
|
||||
{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: "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: "nested directive", body: "nested: {_configkit: {}}\n", code: CodeImportInvalid},
|
||||
{name: "directive kind", body: "configkit: []\n", code: CodeImportInvalid},
|
||||
{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: "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: "nested directive", body: "nested: {configkit: {}}\n", code: CodeImportInvalid},
|
||||
}
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
@@ -136,7 +157,7 @@ func TestLoadImportDirectiveValidationAndTemporaryGlobGate(t *testing.T) {
|
||||
func TestLoadImportMissingContainmentAndRegularFileRules(t *testing.T) {
|
||||
t.Run("optional missing", func(t *testing.T) {
|
||||
directory := t.TempDir()
|
||||
mainPath := writeImportFile(t, directory, "main.yml", `_configkit:
|
||||
mainPath := writeImportFile(t, directory, "main.yml", `configkit:
|
||||
imports:
|
||||
- path: missing.yml
|
||||
optional: true
|
||||
@@ -172,7 +193,7 @@ 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")
|
||||
mainPath := writeImportFile(t, directory, "main.yml", "configkit:\n imports:\n - path: \""+test.path+"\"\n")
|
||||
requireLoadCode(t, File(mainPath), Options[importTestConfig]{Imports: true}, test.code)
|
||||
})
|
||||
}
|
||||
@@ -181,9 +202,9 @@ settings: {root: retained}
|
||||
func TestLoadImportIdentityReportsCyclesAndRepeatedRoutes(t *testing.T) {
|
||||
t.Run("cycle", func(t *testing.T) {
|
||||
directory := t.TempDir()
|
||||
mainPath := writeImportFile(t, directory, "main.yml", "_configkit:\n imports: [{path: a.yml}]\n")
|
||||
writeImportFile(t, directory, "a.yml", "_configkit:\n imports: [{path: b.yml}]\n")
|
||||
writeImportFile(t, directory, "b.yml", "_configkit:\n imports: [{path: main.yml}]\n")
|
||||
mainPath := writeImportFile(t, directory, "main.yml", "configkit:\n imports: [{path: a.yml}]\n")
|
||||
writeImportFile(t, directory, "a.yml", "configkit:\n imports: [{path: b.yml}]\n")
|
||||
writeImportFile(t, directory, "b.yml", "configkit:\n imports: [{path: main.yml}]\n")
|
||||
loadError := requireLoadCode(t, File(mainPath), Options[importTestConfig]{Imports: true}, CodeImportCycle)
|
||||
diagnostic := loadError.Diagnostics()[0]
|
||||
if diagnostic.Primary == nil || len(diagnostic.Related) != 2 || !strings.Contains(diagnostic.Message, "main.yml") || !strings.Contains(diagnostic.Message, "a.yml") || !strings.Contains(diagnostic.Message, "b.yml") {
|
||||
@@ -193,9 +214,9 @@ func TestLoadImportIdentityReportsCyclesAndRepeatedRoutes(t *testing.T) {
|
||||
|
||||
t.Run("diamond", func(t *testing.T) {
|
||||
directory := t.TempDir()
|
||||
mainPath := writeImportFile(t, directory, "main.yml", "_configkit:\n imports: [{path: left.yml}, {path: right.yml}]\n")
|
||||
writeImportFile(t, directory, "left.yml", "_configkit:\n imports: [{path: shared.yml}]\n")
|
||||
writeImportFile(t, directory, "right.yml", "_configkit:\n imports: [{path: shared.yml}]\n")
|
||||
mainPath := writeImportFile(t, directory, "main.yml", "configkit:\n imports: [{path: left.yml}, {path: right.yml}]\n")
|
||||
writeImportFile(t, directory, "left.yml", "configkit:\n imports: [{path: shared.yml}]\n")
|
||||
writeImportFile(t, directory, "right.yml", "configkit:\n imports: [{path: shared.yml}]\n")
|
||||
writeImportFile(t, directory, "shared.yml", "settings: {root: shared}\n")
|
||||
loadError := requireLoadCode(t, File(mainPath), Options[importTestConfig]{Imports: true}, CodeImportRepeated)
|
||||
diagnostic := loadError.Diagnostics()[0]
|
||||
@@ -216,7 +237,7 @@ func TestLoadImportIdentityReportsCyclesAndRepeatedRoutes(t *testing.T) {
|
||||
if err := os.Symlink("target.yml", filepath.Join(directory, "second-link.yml")); err != nil {
|
||||
t.Skipf("symlinks unavailable: %v", err)
|
||||
}
|
||||
mainPath := writeImportFile(t, directory, "main.yml", "_configkit: {imports: [{path: first-link.yml}, {path: second-link.yml}]}\n")
|
||||
mainPath := writeImportFile(t, directory, "main.yml", "configkit: {imports: [{path: first-link.yml}, {path: second-link.yml}]}\n")
|
||||
requireLoadCode(t, File(mainPath), Options[importTestConfig]{Imports: true}, CodeImportRepeated)
|
||||
})
|
||||
}
|
||||
@@ -231,7 +252,7 @@ func TestLoadImportsCanonicalSymlinksAndKeepsHardLinksDistinct(t *testing.T) {
|
||||
if err := os.Symlink(target, filepath.Join(directory, "link.yml")); err != nil {
|
||||
t.Skipf("symlinks unavailable: %v", err)
|
||||
}
|
||||
mainPath := writeImportFile(t, directory, "main.yml", "_configkit: {imports: [{path: link.yml}]}\n")
|
||||
mainPath := writeImportFile(t, directory, "main.yml", "configkit: {imports: [{path: link.yml}]}\n")
|
||||
result, err := Load[importTestConfig](File(mainPath), Options[importTestConfig]{Imports: true})
|
||||
if err != nil || result.Config.Settings.First != "linked" || result.Sources()[1].Path != canonicalTestPath(t, target) {
|
||||
t.Fatalf("symlink result = %#v, %v", result, err)
|
||||
@@ -245,7 +266,7 @@ func TestLoadImportsCanonicalSymlinksAndKeepsHardLinksDistinct(t *testing.T) {
|
||||
if err := os.Symlink(target, filepath.Join(root, "escape.yml")); err != nil {
|
||||
t.Skipf("symlinks unavailable: %v", err)
|
||||
}
|
||||
mainPath := writeImportFile(t, root, "main.yml", "_configkit: {imports: [{path: escape.yml}]}\n")
|
||||
mainPath := writeImportFile(t, root, "main.yml", "configkit: {imports: [{path: escape.yml}]}\n")
|
||||
requireLoadCode(t, File(mainPath), Options[importTestConfig]{Imports: true}, CodeImportOutsideRoot)
|
||||
})
|
||||
|
||||
@@ -255,7 +276,7 @@ func TestLoadImportsCanonicalSymlinksAndKeepsHardLinksDistinct(t *testing.T) {
|
||||
if err := os.Link(one, filepath.Join(directory, "two.yml")); err != nil {
|
||||
t.Skipf("hard links unavailable: %v", err)
|
||||
}
|
||||
mainPath := writeImportFile(t, directory, "main.yml", "_configkit: {imports: [{path: one.yml}, {path: two.yml}]}\n")
|
||||
mainPath := writeImportFile(t, directory, "main.yml", "configkit: {imports: [{path: one.yml}, {path: two.yml}]}\n")
|
||||
requireLoadCode(t, File(mainPath), Options[importTestConfig]{Imports: true}, CodeComposeConflict)
|
||||
})
|
||||
|
||||
@@ -264,7 +285,7 @@ func TestLoadImportsCanonicalSymlinksAndKeepsHardLinksDistinct(t *testing.T) {
|
||||
if err := os.Symlink("loop.yml", filepath.Join(directory, "loop.yml")); err != nil {
|
||||
t.Skipf("symlinks unavailable: %v", err)
|
||||
}
|
||||
mainPath := writeImportFile(t, directory, "main.yml", "_configkit: {imports: [{path: loop.yml}]}\n")
|
||||
mainPath := writeImportFile(t, directory, "main.yml", "configkit: {imports: [{path: loop.yml}]}\n")
|
||||
requireLoadCode(t, File(mainPath), Options[importTestConfig]{Imports: true}, CodeImportInvalid)
|
||||
})
|
||||
}
|
||||
@@ -272,7 +293,7 @@ func TestLoadImportsCanonicalSymlinksAndKeepsHardLinksDistinct(t *testing.T) {
|
||||
func TestLoadByteAndReaderImportsRequireExplicitFilesystemContext(t *testing.T) {
|
||||
directory := t.TempDir()
|
||||
writeImportFile(t, directory, "fragment.yml", "settings: {first: imported}\n")
|
||||
input := []byte("_configkit: {imports: [{path: fragment.yml}]}\n")
|
||||
input := []byte("configkit: {imports: [{path: fragment.yml}]}\n")
|
||||
context := &FilesystemContext{BaseDir: directory, Root: directory}
|
||||
for _, test := range []struct {
|
||||
name string
|
||||
@@ -295,7 +316,7 @@ func TestLoadByteAndReaderImportsRequireExplicitFilesystemContext(t *testing.T)
|
||||
|
||||
func TestFileImportRootCanContainTheSelectedFileDirectory(t *testing.T) {
|
||||
root := t.TempDir()
|
||||
mainPath := writeImportFile(t, root, "configs/main.yml", "_configkit: {imports: [{path: ../shared.yml}]}\n")
|
||||
mainPath := writeImportFile(t, root, "configs/main.yml", "configkit: {imports: [{path: ../shared.yml}]}\n")
|
||||
writeImportFile(t, root, "shared.yml", "settings: {root: shared}\n")
|
||||
result, err := Load[importTestConfig](File(mainPath), Options[importTestConfig]{
|
||||
Imports: true, Filesystem: &FilesystemContext{Root: root},
|
||||
@@ -309,7 +330,7 @@ func TestFileImportRootCanContainTheSelectedFileDirectory(t *testing.T) {
|
||||
func TestImportedParseAndDecodeDiagnosticsKeepTheirSource(t *testing.T) {
|
||||
t.Run("parse", func(t *testing.T) {
|
||||
directory := t.TempDir()
|
||||
mainPath := writeImportFile(t, directory, "main.yml", "_configkit: {imports: [{path: broken.yml}]}\n")
|
||||
mainPath := writeImportFile(t, directory, "main.yml", "configkit: {imports: [{path: broken.yml}]}\n")
|
||||
writeImportFile(t, directory, "broken.yml", "settings: [\n")
|
||||
loadError := requireAnyLoadError(t, File(mainPath), Options[importTestConfig]{Imports: true})
|
||||
diagnostics := loadError.Diagnostics()
|
||||
@@ -320,7 +341,7 @@ func TestImportedParseAndDecodeDiagnosticsKeepTheirSource(t *testing.T) {
|
||||
|
||||
t.Run("decode", func(t *testing.T) {
|
||||
directory := t.TempDir()
|
||||
mainPath := writeImportFile(t, directory, "main.yml", "_configkit: {imports: [{path: unknown.yml}]}\n")
|
||||
mainPath := writeImportFile(t, directory, "main.yml", "configkit: {imports: [{path: unknown.yml}]}\n")
|
||||
writeImportFile(t, directory, "unknown.yml", "unknown: value\n")
|
||||
loadError := requireLoadCode(t, File(mainPath), Options[importTestConfig]{Imports: true}, CodeDecodeUnknownField)
|
||||
diagnostic := loadError.Diagnostics()[0]
|
||||
@@ -332,7 +353,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, optional: true}]}\n")
|
||||
requireLoadCode(t, File(mainPath), Options[importTestConfig]{Imports: true}, CodeImportOutsideRoot)
|
||||
|
||||
locked := writeImportFile(t, directory, "locked.yml", "settings: {root: locked}\n")
|
||||
@@ -344,13 +365,13 @@ 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, optional: true}]}\n")
|
||||
requireLoadCode(t, File(mainPath), Options[importTestConfig]{Imports: true}, CodeSourcePermission)
|
||||
}
|
||||
|
||||
func TestImportTraversalEnforcesPrivateBudgets(t *testing.T) {
|
||||
directory := t.TempDir()
|
||||
mainPath := writeImportFile(t, directory, "main.yml", "_configkit: {imports: [{path: one.yml}, {path: two.yml}]}\n")
|
||||
mainPath := writeImportFile(t, directory, "main.yml", "configkit: {imports: [{path: one.yml}, {path: two.yml}]}\n")
|
||||
writeImportFile(t, directory, "one.yml", "settings: {first: one}\n")
|
||||
writeImportFile(t, directory, "two.yml", "settings: {second: two}\n")
|
||||
main := parseImportMain(t, mainPath)
|
||||
@@ -370,7 +391,7 @@ func TestImportTraversalEnforcesPrivateBudgets(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
writeImportFile(t, directory, "one.yml", "_configkit: {imports: [{path: nested.yml}]}\n")
|
||||
writeImportFile(t, directory, "one.yml", "configkit: {imports: [{path: nested.yml}]}\n")
|
||||
writeImportFile(t, directory, "nested.yml", "settings: {nested: nested}\n")
|
||||
main = parseImportMain(t, mainPath)
|
||||
_, _, diagnostics := loadImportedDocuments(File(mainPath), nil, main, nil, importLimits{depth: 1, sources: 8, bytes: maxTotalBytes, nodes: maxDocumentNodes})
|
||||
@@ -381,7 +402,7 @@ func TestImportTraversalEnforcesPrivateBudgets(t *testing.T) {
|
||||
|
||||
func TestImportTraversalAcceptsExactPrivateBudgets(t *testing.T) {
|
||||
directory := t.TempDir()
|
||||
mainPath := writeImportFile(t, directory, "main.yml", "_configkit: {imports: [{path: imported.yml}]}\n")
|
||||
mainPath := writeImportFile(t, directory, "main.yml", "configkit: {imports: [{path: imported.yml}]}\n")
|
||||
importedPath := writeImportFile(t, directory, "imported.yml", "settings: {first: imported}\n")
|
||||
main := parseImportMain(t, mainPath)
|
||||
imported := parseImportMain(t, importedPath)
|
||||
|
||||
Reference in New Issue
Block a user