120 lines
4.5 KiB
Go
120 lines
4.5 KiB
Go
package configkit_test
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
|
|
configkit "gitea.maximumdirect.net/eric/ConfigKit"
|
|
)
|
|
|
|
func TestFacadeDirectoryRootBelowContainedAbsoluteSymlink(t *testing.T) {
|
|
root, err := filepath.EvalSymlinks(t.TempDir())
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
parts := filepath.Join(root, "real", "parts")
|
|
if err := os.MkdirAll(parts, 0o700); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
partPath := filepath.Join(parts, "part.yml")
|
|
if err := os.WriteFile(partPath, []byte("value: included\n"), 0o600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := os.Symlink(filepath.Join(root, "real"), filepath.Join(root, "absolute")); err != nil {
|
|
t.Skipf("symlinks unavailable: %v", err)
|
|
}
|
|
for _, follow := range []bool{true, false} {
|
|
t.Run(fmt.Sprintf("follow=%t", follow), func(t *testing.T) {
|
|
mainPath := filepath.Join(root, "main.yml")
|
|
contents := fmt.Sprintf("configkit:\n imports:\n - dir: absolute/parts\n pattern: '*.yml'\n follow: %t\n", follow)
|
|
if err := os.WriteFile(mainPath, []byte(contents), 0o600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
result, err := configkit.Load[map[string]any](configkit.File(mainPath), configkit.Options[map[string]any]{Imports: true})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if result.Config["value"] != "included" {
|
|
t.Fatalf("configuration = %#v", result.Config)
|
|
}
|
|
if sources := result.Sources(); len(sources) != 2 || sources[1].Path != partPath {
|
|
t.Fatalf("canonical imported source = %#v", sources)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestFacadeNativeDiscoveryWithNestedRoot(t *testing.T) {
|
|
root := t.TempDir()
|
|
parts := filepath.Join(root, "nested/root/parts")
|
|
if err := os.MkdirAll(parts, 0o700); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := os.WriteFile(filepath.Join(parts, "value.yml"), []byte("value: 1\n"), 0o600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := os.Symlink("parts", filepath.Join(root, "nested/root/linked")); err != nil {
|
|
t.Skipf("symlinks unavailable: %v", err)
|
|
}
|
|
filesystem := configkit.NewFilesystem("nested", os.DirFS(root))
|
|
context := &configkit.FilesystemContext{FS: &filesystem, Root: "nested/root", BaseDir: "nested/root"}
|
|
for _, selector := range []string{
|
|
"dir: parts", "glob: 'parts/*.yml'", "dir: linked", "glob: 'lin*/*.yml'",
|
|
} {
|
|
t.Run(selector, func(t *testing.T) {
|
|
result, err := configkit.Load(configkit.Bytes("main", []byte("configkit:\n imports:\n - "+selector+"\n")), configkit.Options[map[string]any]{Imports: true, Filesystem: context})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if result.Config["value"] != int64(1) {
|
|
t.Fatalf("configuration = %#v", result.Config)
|
|
}
|
|
})
|
|
}
|
|
if err := os.WriteFile(filepath.Join(root, "nested/outside.yml"), []byte("value: outside\n"), 0o600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := os.Symlink("../../outside.yml", filepath.Join(parts, "escape.yml")); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
for _, selector := range []string{"dir: parts", "glob: 'parts/*.yml'"} {
|
|
_, err := configkit.Load(configkit.Bytes("main", []byte("configkit:\n imports:\n - "+selector+"\n")), configkit.Options[map[string]any]{Imports: true, Filesystem: context})
|
|
var loadError *configkit.LoadError
|
|
if !errors.As(err, &loadError) || len(loadError.Diagnostics()) != 1 || loadError.Diagnostics()[0].Code != configkit.CodeImportOutsideRoot {
|
|
t.Fatalf("escaping %s: %v", selector, err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestFacadeDiscoveryAllowsFiniteLinkReuse(t *testing.T) {
|
|
root := t.TempDir()
|
|
if err := os.Mkdir(filepath.Join(root, "parts"), 0o700); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := os.WriteFile(filepath.Join(root, "parts/value.yml"), []byte("value: 1\n"), 0o600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := os.Symlink("..", filepath.Join(root, "parts/up")); err != nil {
|
|
t.Skipf("symlinks unavailable: %v", err)
|
|
}
|
|
filesystem := configkit.NewFilesystem("finite", os.DirFS(root))
|
|
for _, native := range []bool{false, true} {
|
|
for _, selector := range []string{"dir: parts/up/parts/up/parts\n pattern: '*.yml'", "glob: 'parts/up/parts/up/parts/*.yml'"} {
|
|
context := &configkit.FilesystemContext{Root: root, BaseDir: root}
|
|
if native {
|
|
context = &configkit.FilesystemContext{FS: &filesystem, Root: ".", BaseDir: "."}
|
|
}
|
|
result, err := configkit.Load(configkit.Bytes("main", []byte("configkit:\n imports:\n - "+selector+"\n")), configkit.Options[map[string]any]{Imports: true, Filesystem: context})
|
|
if err != nil {
|
|
t.Fatalf("native=%v selector=%s: %v", native, selector, err)
|
|
}
|
|
if result.Config["value"] != int64(1) {
|
|
t.Fatalf("configuration = %#v", result.Config)
|
|
}
|
|
}
|
|
}
|
|
}
|