blob: f56a34da3e080f3c1928b9b0b2a95a3245fe5366 [file] [log] [blame]
// Copyright 2023 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package os_test
import (
"internal/testenv"
"io/fs"
. "os"
"path/filepath"
"testing"
)
func TestDirFSReadLink(t *testing.T) {
testenv.MustHaveSymlink(t)
root := t.TempDir()
subdir := filepath.Join(root, "dir")
if err := Mkdir(subdir, 0o777); err != nil {
t.Fatal(err)
}
links := map[string]string{
filepath.Join(root, "parent-link"): filepath.Join("..", "foo"),
filepath.Join(root, "sneaky-parent-link"): filepath.Join("dir", "..", "..", "foo"),
filepath.Join(root, "abs-link"): filepath.Join(root, "foo"),
filepath.Join(root, "rel-link"): "foo",
filepath.Join(root, "rel-sub-link"): filepath.Join("dir", "foo"),
filepath.Join(subdir, "parent-link"): filepath.Join("..", "foo"),
}
for newname, oldname := range links {
if err := Symlink(oldname, newname); err != nil {
t.Fatal(err)
}
}
fsys := DirFS(root)
want := map[string]string{
"rel-link": "foo",
"rel-sub-link": filepath.Join("dir", "foo"),
"dir/parent-link": filepath.Join("..", "foo"),
"parent-link": filepath.Join("..", "foo"),
"sneaky-parent-link": filepath.Join("dir", "..", "..", "foo"),
"abs-link": filepath.Join(root, "foo"),
}
for name, want := range want {
got, err := fs.ReadLink(fsys, name)
if got != want || err != nil {
t.Errorf("fs.ReadLink(fsys, %q) = %q, %v; want %q, <nil>", name, got, err, want)
}
}
}
func TestDirFSLstat(t *testing.T) {
testenv.MustHaveSymlink(t)
root := t.TempDir()
subdir := filepath.Join(root, "dir")
if err := Mkdir(subdir, 0o777); err != nil {
t.Fatal(err)
}
if err := Symlink("dir", filepath.Join(root, "link")); err != nil {
t.Fatal(err)
}
fsys := DirFS(root)
want := map[string]fs.FileMode{
"link": fs.ModeSymlink,
"dir": fs.ModeDir,
}
for name, want := range want {
info, err := fs.Lstat(fsys, name)
var got fs.FileMode
if info != nil {
got = info.Mode().Type()
}
if got != want || err != nil {
t.Errorf("fs.Lstat(fsys, %q).Mode().Type() = %v, %v; want %v, <nil>", name, got, err, want)
}
}
}
func TestDirFSWalkDir(t *testing.T) {
testenv.MustHaveSymlink(t)
root := t.TempDir()
subdir := filepath.Join(root, "dir")
if err := Mkdir(subdir, 0o777); err != nil {
t.Fatal(err)
}
if err := Symlink("dir", filepath.Join(root, "link")); err != nil {
t.Fatal(err)
}
if err := WriteFile(filepath.Join(root, "dir", "a"), nil, 0o666); err != nil {
t.Fatal(err)
}
fsys := DirFS(root)
t.Run("SymlinkRoot", func(t *testing.T) {
wantTypes := map[string]fs.FileMode{
"link": fs.ModeDir,
"link/a": 0,
}
marks := make(map[string]int)
err := fs.WalkDir(fsys, "link", func(path string, entry fs.DirEntry, err error) error {
marks[path]++
if want, ok := wantTypes[path]; !ok {
t.Errorf("Unexpected path %q in walk", path)
} else if got := entry.Type(); got != want {
t.Errorf("%s entry type = %v; want %v", path, got, want)
}
if err != nil {
t.Errorf("%s: %v", path, err)
}
return nil
})
if err != nil {
t.Fatal(err)
}
for path := range wantTypes {
if got := marks[path]; got != 1 {
t.Errorf("%s visited %d times; expected 1", path, got)
}
}
})
t.Run("SymlinkPresent", func(t *testing.T) {
wantTypes := map[string]fs.FileMode{
".": fs.ModeDir,
"dir": fs.ModeDir,
"dir/a": 0,
"link": fs.ModeSymlink,
}
marks := make(map[string]int)
err := fs.WalkDir(fsys, ".", func(path string, entry fs.DirEntry, err error) error {
marks[path]++
if want, ok := wantTypes[path]; !ok {
t.Errorf("Unexpected path %q in walk", path)
} else if got := entry.Type(); got != want {
t.Errorf("%s entry type = %v; want %v", path, got, want)
}
if err != nil {
t.Errorf("%s: %v", path, err)
}
return nil
})
if err != nil {
t.Fatal(err)
}
for path := range wantTypes {
if got := marks[path]; got != 1 {
t.Errorf("%s visited %d times; expected 1", path, got)
}
}
})
}