package engine import ( "errors" "io/fs" "os" "path/filepath" "testing" ) func TestImportLinkResolutionTracksActiveExpansions(t *testing.T) { root := t.TempDir() if err := os.Mkdir(filepath.Join(root, "parts"), 0o700); err != nil { t.Fatal(err) } for name, target := range map[string]string{"parts/up": "..", "self": "self", "first": "second", "second": "first"} { if err := os.Symlink(target, filepath.Join(root, filepath.FromSlash(name))); err != nil { t.Skipf("symlinks unavailable: %v", err) } } host, err := openHostAccess(root) if err != nil { t.Fatal(err) } defer host.close() filesystem := os.DirFS(root) links, ok := filesystem.(fs.ReadLinkFS) if !ok { t.Fatal("native directory filesystem does not expose link inspection") } native := newNativeAccess(filesystem, ".", &namespaceToken{}) for name, resolve := range map[string]func(string) (string, error){ "host": func(name string) (string, error) { return resolveHostImportPath(host, name) }, "native": func(name string) (string, error) { return resolveNativeImportPath(native, links, name) }, } { t.Run(name, func(t *testing.T) { if got, err := resolve("parts/up/parts/up/parts"); err != nil || got != "parts" { t.Errorf("finite link reuse = %q, %v", got, err) } for _, cycle := range []string{"self", "first"} { if _, err := resolve(cycle); !errors.Is(err, errImportDirectoryLinkCycle) { t.Errorf("%s cycle = %v", cycle, err) } } }) } }