]> Cypherpunks repositories - gostls13.git/commitdiff
io/fs: add Stat and StatFS
authorRuss Cox <rsc@golang.org>
Mon, 6 Jul 2020 15:26:45 +0000 (11:26 -0400)
committerRuss Cox <rsc@golang.org>
Tue, 20 Oct 2020 17:53:02 +0000 (17:53 +0000)
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>
src/io/fs/stat.go [new file with mode: 0644]
src/io/fs/stat_test.go [new file with mode: 0644]
src/testing/fstest/mapfs.go
src/testing/fstest/testfs.go

diff --git a/src/io/fs/stat.go b/src/io/fs/stat.go
new file mode 100644 (file)
index 0000000..735a6e3
--- /dev/null
@@ -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()
+}
diff --git a/src/io/fs/stat_test.go b/src/io/fs/stat_test.go
new file mode 100644 (file)
index 0000000..e312b6f
--- /dev/null
@@ -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)
+}
index e969ac2bd1466fdfc33a123cce729e631881ca2d..b01911e5894d47290a056e174384dd58031a93d4 100644 (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
index 66725ca2a43e90f955a78e9192aa08a7a21d6774..290d2596cc3d8acbc0d5cceeb0c4a918f4da26f8 100644 (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)
+               }
        }
 }