Add pathtools.Filesystem.Stat for soong_zip

Stat is used by soong_zip.  Add it to the FileSystem interface
and add tests for it.

Test: fs_test.go
Change-Id: I1baa2b27398846a4e55bcf4fa291c62f507a4e9d
This commit is contained in:
Colin Cross 2018-09-27 15:49:45 -07:00
parent 15fbefb87e
commit 3316a5ee54
2 changed files with 120 additions and 13 deletions

View file

@ -106,6 +106,9 @@ type FileSystem interface {
// Lstat returns info on a file without following symlinks.
Lstat(name string) (os.FileInfo, error)
// Lstat returns info on a file.
Stat(name string) (os.FileInfo, error)
// ListDirsRecursive returns a list of all the directories in a path, following symlinks if requested.
ListDirsRecursive(name string, follow ShouldFollowSymlinks) (dirs []string, err error)
@ -159,6 +162,10 @@ func (osFs) Lstat(path string) (stats os.FileInfo, err error) {
return os.Lstat(path)
}
func (osFs) Stat(path string) (stats os.FileInfo, err error) {
return os.Stat(path)
}
// Returns a list of all directories under dir
func (osFs) ListDirsRecursive(name string, follow ShouldFollowSymlinks) (dirs []string, err error) {
return listDirsRecursive(OsFs, name, follow)
@ -349,24 +356,46 @@ func (ms *mockStat) ModTime() time.Time { return time.Time{} }
func (ms *mockStat) Sys() interface{} { return nil }
func (m *mockFs) Lstat(name string) (os.FileInfo, error) {
name = filepath.Clean(name)
dir, file := saneSplit(name)
dir = m.followSymlinks(dir)
name = filepath.Join(dir, file)
ms := mockStat{
name: name,
name: file,
}
if symlink, isSymlink := m.symlinks[name]; isSymlink {
ms.mode = os.ModeSymlink
ms.size = int64(len(symlink))
} else if _, isDir := m.dirs[name]; isDir {
ms.mode = os.ModeDir
} else if _, isFile := m.files[name]; isFile {
ms.mode = 0
ms.size = int64(len(m.files[name]))
} else {
return nil, os.ErrNotExist
}
return &ms, nil
}
func (m *mockFs) Stat(name string) (os.FileInfo, error) {
name = filepath.Clean(name)
origName := name
name = m.followSymlinks(name)
ms := mockStat{
name: filepath.Base(origName),
size: int64(len(m.files[name])),
}
if isSymlink, err := m.IsSymlink(name); err != nil {
// IsSymlink handles ErrNotExist
return nil, err
} else if isSymlink {
ms.mode = os.ModeSymlink
} else if isDir, err := m.IsDir(name); err != nil {
return nil, err
} else if isDir {
if _, isDir := m.dirs[name]; isDir {
ms.mode = os.ModeDir
} else {
} else if _, isFile := m.files[name]; isFile {
ms.mode = 0
ms.size = int64(len(m.files[name]))
} else {
return nil, os.ErrNotExist
}
return &ms, nil

View file

@ -409,11 +409,89 @@ func TestFs_Lstat(t *testing.T) {
return
}
if got.Mode()&os.ModeType != test.mode {
t.Errorf("fs.Readlink(%q).Mode()&os.ModeType want: %x, got %x",
t.Errorf("fs.Lstat(%q).Mode()&os.ModeType want: %x, got %x",
test.name, test.mode, got.Mode()&os.ModeType)
}
if test.mode == 0 && got.Size() != test.size {
t.Errorf("fs.Readlink(%q).Size() want: %d, got %d", test.name, test.size, got.Size())
t.Errorf("fs.Lstat(%q).Size() want: %d, got %d", test.name, test.size, got.Size())
}
})
}
})
}
}
func TestFs_Stat(t *testing.T) {
testCases := []struct {
name string
mode os.FileMode
size int64
err error
}{
{".", os.ModeDir, 0, nil},
{"/", os.ModeDir, 0, nil},
{"a", os.ModeDir, 0, nil},
{"a/a", os.ModeDir, 0, nil},
{"a/a/a", 0, 0, nil},
{"a/a/f", 0, 0, nil},
{"b", os.ModeDir, 0, nil},
{"b/a", os.ModeDir, 0, nil},
{"b/a/a", 0, 0, nil},
{"b/a/f", 0, 0, nil},
{"c", os.ModeDir, 0, nil},
{"c/a", 0, 0, nil},
{"c/f", 0, 0, nil},
{"d/a", 0, 0, nil},
{"d/f", 0, 0, nil},
{"e", 0, 0, nil},
{"f", 0, 0, nil},
{"dangling", 0, 0, os.ErrNotExist},
{"a/missing", 0, 0, os.ErrNotExist},
{"b/missing", 0, 0, os.ErrNotExist},
{"c/missing", 0, 0, os.ErrNotExist},
{"d/missing", 0, 0, os.ErrNotExist},
{"e/missing", 0, 0, os.ErrNotExist},
{"dangling/missing", 0, 0, os.ErrNotExist},
{"a/missing/missing", 0, 0, os.ErrNotExist},
{"b/missing/missing", 0, 0, os.ErrNotExist},
{"c/missing/missing", 0, 0, os.ErrNotExist},
{"d/missing/missing", 0, 0, os.ErrNotExist},
{"e/missing/missing", 0, 0, os.ErrNotExist},
{"dangling/missing/missing", 0, 0, os.ErrNotExist},
}
mock := symlinkMockFs()
fsList := []FileSystem{mock, OsFs}
names := []string{"mock", "os"}
os.Chdir("testdata/dangling")
defer os.Chdir("../..")
for i, fs := range fsList {
t.Run(names[i], func(t *testing.T) {
for _, test := range testCases {
t.Run(test.name, func(t *testing.T) {
got, err := fs.Stat(test.name)
checkErr(t, test.err, err)
if err != nil {
return
}
if got.Mode()&os.ModeType != test.mode {
t.Errorf("fs.Stat(%q).Mode()&os.ModeType want: %x, got %x",
test.name, test.mode, got.Mode()&os.ModeType)
}
if test.mode == 0 && got.Size() != test.size {
t.Errorf("fs.Stat(%q).Size() want: %d, got %d", test.name, test.size, got.Size())
}
})
}