1
0
mirror of https://github.com/golang/go synced 2024-09-29 10:24:34 -06:00

io/fs: add Stat and StatFS

Add Stat helper function, StatFS interface, and test.
Add Stat method to fstest.MapFS.
Add testing of Stat method to fstest.TestFS.

For #41190.

Change-Id: Icf8b6eb1c3fa6f93a9be8405ec5a9468fb1da97b
Reviewed-on: https://go-review.googlesource.com/c/go/+/243913
Trust: Russ Cox <rsc@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
This commit is contained in:
Russ Cox 2020-07-06 11:26:45 -04:00
parent f098ccf04a
commit 10a1a1a37c
4 changed files with 95 additions and 1 deletions

31
src/io/fs/stat.go Normal file
View File

@ -0,0 +1,31 @@
// Copyright 2020 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 fs
// A StatFS is a file system with a Stat method.
type StatFS interface {
FS
// Stat returns a FileInfo describing the file.
// If there is an error, it should be of type *PathError.
Stat(name string) (FileInfo, error)
}
// Stat returns a FileInfo describing the named file from the file system.
//
// If fs implements StatFS, Stat calls fs.Stat.
// Otherwise, Stat opens the file to stat it.
func Stat(fsys FS, name string) (FileInfo, error) {
if fsys, ok := fsys.(StatFS); ok {
return fsys.Stat(name)
}
file, err := fsys.Open(name)
if err != nil {
return nil, err
}
defer file.Close()
return file.Stat()
}

36
src/io/fs/stat_test.go Normal file
View File

@ -0,0 +1,36 @@
// Copyright 2020 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 fs_test
import (
"fmt"
. "io/fs"
"testing"
)
type statOnly struct{ StatFS }
func (statOnly) Open(name string) (File, error) { return nil, ErrNotExist }
func TestStat(t *testing.T) {
check := func(desc string, info FileInfo, err error) {
t.Helper()
if err != nil || info == nil || info.Mode() != 0456 {
infoStr := "<nil>"
if info != nil {
infoStr = fmt.Sprintf("FileInfo(Mode: %#o)", info.Mode())
}
t.Fatalf("Stat(%s) = %v, %v, want Mode:0456, nil", desc, infoStr, err)
}
}
// Test that Stat uses the method when present.
info, err := Stat(statOnly{testFsys}, "hello.txt")
check("statOnly", info, err)
// Test that Stat uses Open when the method is not present.
info, err = Stat(openOnly{testFsys}, "hello.txt")
check("openOnly", info, err)
}

View File

@ -120,6 +120,10 @@ func (fsys MapFS) ReadFile(name string) ([]byte, error) {
return fs.ReadFile(fsOnly{fsys}, name)
}
func (fsys MapFS) Stat(name string) (fs.FileInfo, error) {
return fs.Stat(fsOnly{fsys}, name)
}
// A mapFileInfo implements fs.FileInfo and fs.DirEntry for a given map file.
type mapFileInfo struct {
name string

View File

@ -230,7 +230,30 @@ func (t *fsTester) checkStat(path string, entry fs.DirEntry) {
fentry := formatEntry(entry)
finfo := formatInfoEntry(info)
if fentry != finfo {
t.errorf("%s: mismatch:\n\tentry = %v\n\tfile.Stat() = %v", path, fentry, finfo)
t.errorf("%s: mismatch:\n\tentry = %s\n\tfile.Stat() = %s", path, fentry, finfo)
}
info2, err := fs.Stat(t.fsys, path)
if err != nil {
t.errorf("%s: fs.Stat: %v", path, err)
return
}
finfo = formatInfo(info)
finfo2 := formatInfo(info2)
if finfo2 != finfo {
t.errorf("%s: fs.Stat(...) = %s\n\twant %s", path, finfo2, finfo)
}
if fsys, ok := t.fsys.(fs.StatFS); ok {
info2, err := fsys.Stat(path)
if err != nil {
t.errorf("%s: fsys.Stat: %v", path, err)
return
}
finfo2 := formatInfo(info2)
if finfo2 != finfo {
t.errorf("%s: fsys.Stat(...) = %s\n\twant %s", path, finfo2, finfo)
}
}
}