diff --git a/helper/iofs/iofs.go b/helper/iofs/iofs.go index 6c71078..eb5a4b4 100644 --- a/helper/iofs/iofs.go +++ b/helper/iofs/iofs.go @@ -20,18 +20,19 @@ type adapterFs struct { fs billyfs.Filesystem } +// Type assertion that adapterFS implements the following interfaces: var _ fs.FS = (*adapterFs)(nil) var _ fs.ReadDirFS = (*adapterFs)(nil) var _ fs.StatFS = (*adapterFs)(nil) var _ fs.ReadFileFS = (*adapterFs)(nil) -// GlobFS would be harder, we don't implement for now. +// TODO: implement fs.GlobFS, which will be a fair bit more code. -// Open implements fs.FS. +// Open opens the named file on the underlying FS, implementing fs.FS (returning a file or error). func (a *adapterFs) Open(name string) (fs.File, error) { if name[0] == '/' || name != filepath.Clean(name) { - // fstest.TestFS explicitly checks that these should return error - // MemFS is performs the clean internally, so we need to block that here for testing. + // fstest.TestFS explicitly checks that these should return error. + // MemFS performs the clean internally, so we need to block that here for testing purposes. return nil, &fs.PathError{Op: "open", Path: name, Err: fs.ErrInvalid} } stat, err := a.fs.Stat(name) @@ -49,7 +50,7 @@ func (a *adapterFs) Open(name string) (fs.File, error) { return &adapterFile{file: file, info: stat}, err } -// ReadDir implements fs.ReadDirFS. +// ReadDir reads the named directory, implementing fs.ReadDirFS (returning a listing or error). func (a *adapterFs) ReadDir(name string) ([]fs.DirEntry, error) { items, err := a.fs.ReadDir(name) if err != nil { @@ -62,12 +63,12 @@ func (a *adapterFs) ReadDir(name string) ([]fs.DirEntry, error) { return entries, nil } -// Stat implements fs.StatFS. +// Stat returns information on the named file, implementing fs.StatFS (returning FileInfo or error). func (a *adapterFs) Stat(name string) (fs.FileInfo, error) { return a.fs.Stat(name) } -// ReadFile implements fs.ReadFileFS. +// ReadFile reads the named file and returns its contents, implementing fs.ReadFileFS (returning contents or error). func (a *adapterFs) ReadFile(name string) ([]byte, error) { stat, err := a.fs.Stat(name) if err != nil { @@ -90,17 +91,17 @@ type adapterFile struct { var _ fs.File = (*adapterFile)(nil) -// Close implements fs.File. +// Close closes the file, implementing fs.File (and io.Closer). func (a *adapterFile) Close() error { return a.file.Close() } -// Read implements fs.File. +// Read reads bytes from the file, implementing fs.File (and io.Reader). func (a *adapterFile) Read(b []byte) (int, error) { return a.file.Read(b) } -// Stat implements fs.File. +// Stat returns file information, implementing fs.File (returning FileInfo or error). func (a *adapterFile) Stat() (fs.FileInfo, error) { return a.info, nil } @@ -119,24 +120,21 @@ func makeDir(stat fs.FileInfo, entries []fs.DirEntry) *adapterDirFile { } } -// Close implements fs.File. +// Close closes the directory, implementing fs.File (and io.Closer). // Subtle: note that this is shadowing adapterFile.Close. func (a *adapterDirFile) Close() error { return nil } -// ReadDir implements fs.ReadDirFile. +// ReadDir reads the directory contents, implementing fs.ReadDirFile (returning directory listing or error). func (a *adapterDirFile) ReadDir(n int) ([]fs.DirEntry, error) { if len(a.entries) == 0 && n > 0 { return nil, io.EOF } - if n <= 0 { - n = len(a.entries) - } - if n > len(a.entries) { + if n <= 0 || n > len(a.entries) { n = len(a.entries) } entries := a.entries[:n] a.entries = a.entries[n:] return entries, nil -} \ No newline at end of file +} diff --git a/helper/iofs/iofs_test.go b/helper/iofs/iofs_test.go index 4f14765..e9bfd8c 100644 --- a/helper/iofs/iofs_test.go +++ b/helper/iofs/iofs_test.go @@ -21,16 +21,16 @@ type wrappedError interface { Unwrap() error } -// TestWithFSTest leverages the packaged Go fstest package, which seems comprehensive +// TestWithFSTest leverages the packaged Go fstest package, which seems comprehensive. func TestWithFSTest(t *testing.T) { t.Parallel() memfs := memfs.New() iofs := Wrap(memfs) files := map[string]string{ - "foo.txt": "hello, world", - "bar.txt": "goodbye, world", - "dir/baz.txt": "こんにちわ, world", + "foo.txt": "hello, world", + "bar.txt": "goodbye, world", + filepath.Join("dir", "baz.txt"): "こんにちわ, world", } created_files := make([]string, 0, len(files)) for filename, contents := range files { @@ -38,6 +38,10 @@ func TestWithFSTest(t *testing.T) { created_files = append(created_files, filename) } + if runtime.GOOS == "windows" { + t.Skip("fstest.TestFS is not yet windows path aware") + } + err := fstest.TestFS(iofs, created_files...) if err != nil { checkFsTestError(t, err, files)