100 lines
4.7 KiB
Go
100 lines
4.7 KiB
Go
package configkit_test
|
|
|
|
import (
|
|
"errors"
|
|
"io/fs"
|
|
"os"
|
|
"path"
|
|
"path/filepath"
|
|
"testing"
|
|
|
|
configkit "gitea.maximumdirect.net/eric/ConfigKit"
|
|
)
|
|
|
|
func TestFacadeNativeDiscoveryPreservesAliasIdentity(t *testing.T) {
|
|
root := t.TempDir()
|
|
for name, contents := range map[string]string{
|
|
"data/item.yml": "configkit:\n imports:\n - path: helper.yml\nvalue: item\n",
|
|
"data/helper.yml": "owner: target\nresource: resource.txt\n",
|
|
"aliases/helper.yml": "owner: alias\nresource: resource.txt\n",
|
|
"data/resource.txt": "target resource",
|
|
"aliases/resource.txt": "alias resource",
|
|
} {
|
|
filename := filepath.Join(root, filepath.FromSlash(name))
|
|
if err := os.MkdirAll(filepath.Dir(filename), 0o700); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := os.WriteFile(filename, []byte(contents), 0o600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
for name, target := range map[string]string{"aliases/item.yml": "../data/item.yml", "linked": "data"} {
|
|
if err := os.Symlink(target, filepath.Join(root, filepath.FromSlash(name))); err != nil {
|
|
t.Skipf("symlinks unavailable: %v", err)
|
|
}
|
|
}
|
|
filesystem := configkit.NewFilesystem("aliases", os.DirFS(root))
|
|
type configuration struct {
|
|
Value string `yaml:"value"`
|
|
Owner string `yaml:"owner"`
|
|
Resource string `yaml:"resource"`
|
|
}
|
|
for _, test := range []struct {
|
|
name, declaration, item, helper, owner, resource string
|
|
}{
|
|
{"file/path", "path: aliases/item.yml", "aliases/item.yml", "aliases/helper.yml", "alias", "alias resource"},
|
|
{"file/dir", "dir: aliases\n pattern: item.yml", "aliases/item.yml", "aliases/helper.yml", "alias", "alias resource"},
|
|
{"file/glob", "glob: 'aliases/ite*.yml'", "aliases/item.yml", "aliases/helper.yml", "alias", "alias resource"},
|
|
{"directory/path", "path: linked/item.yml", "linked/item.yml", "linked/helper.yml", "target", "target resource"},
|
|
{"directory/dir", "dir: linked\n pattern: item.yml", "linked/item.yml", "linked/helper.yml", "target", "target resource"},
|
|
{"directory/glob", "glob: 'lin*/ite*.yml'", "linked/item.yml", "linked/helper.yml", "target", "target resource"},
|
|
} {
|
|
t.Run(test.name, func(t *testing.T) {
|
|
result, err := configkit.Load(configkit.Bytes("main", []byte("configkit:\n imports:\n - "+test.declaration+"\n")), configkit.Options[configuration]{
|
|
Imports: true, Filesystem: &configkit.FilesystemContext{FS: &filesystem, Root: ".", BaseDir: "."},
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if result.Config.Owner != test.owner || result.Config.Value != "item" {
|
|
t.Fatalf("configuration = %#v", result.Config)
|
|
}
|
|
sources := result.Sources()
|
|
if len(sources) != 3 || sources[1].Path != test.item || sources[2].Path != test.helper {
|
|
t.Fatalf("source identities = %#v", sources)
|
|
}
|
|
for field, source := range map[string]configkit.SourceInfo{"value": sources[1], "resource": sources[2]} {
|
|
info, ok := result.Metadata().Lookup(configkit.Keys(field))
|
|
if !ok || len(info.Origin.Locations) != 1 || info.Origin.Locations[0].SourceID != source.ID {
|
|
t.Fatalf("%s origin = %#v", field, info)
|
|
}
|
|
context, ok := result.SourceContext(source.ID)
|
|
if !ok || context.BaseDir != path.Dir(source.Path) {
|
|
t.Fatalf("%s context = %#v", field, context)
|
|
}
|
|
contents, err := fs.ReadFile(context.FS, path.Join(context.BaseDir, result.Config.Resource))
|
|
if err != nil || string(contents) != test.resource {
|
|
t.Fatalf("%s resource = %q, %v", field, contents, err)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
// The same native path is still a repeat when separately included. An alias
|
|
// to a leaf file remains a different native namespace path, as for path imports.
|
|
for _, selector := range []string{"path: aliases/item.yml", "dir: aliases\n pattern: item.yml", "glob: 'aliases/ite*.yml'"} {
|
|
_, err := configkit.Load(configkit.Bytes("main", []byte("configkit:\n imports:\n - "+selector+"\n - path: aliases/item.yml\n")), configkit.Options[configuration]{
|
|
Imports: true, Filesystem: &configkit.FilesystemContext{FS: &filesystem, Root: ".", BaseDir: "."},
|
|
})
|
|
var loadError *configkit.LoadError
|
|
if !errors.As(err, &loadError) || len(loadError.Diagnostics()) != 1 || loadError.Diagnostics()[0].Code != configkit.CodeImportRepeated {
|
|
t.Fatalf("repeated source: %v", err)
|
|
}
|
|
_, err = configkit.Load(configkit.Bytes("main", []byte("configkit:\n imports:\n - "+selector+"\n - path: data/item.yml\n")), configkit.Options[configuration]{
|
|
Imports: true, Filesystem: &configkit.FilesystemContext{FS: &filesystem, Root: ".", BaseDir: "."},
|
|
})
|
|
if !errors.As(err, &loadError) || len(loadError.Diagnostics()) == 0 || loadError.Diagnostics()[0].Code != configkit.CodeComposeConflict {
|
|
t.Fatalf("distinct native alias paths should reach composition: %v", err)
|
|
}
|
|
}
|
|
}
|