Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add DirEntryDelegator and FileInfoDelegator #11

Merged
merged 1 commit into from
Nov 16, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
118 changes: 115 additions & 3 deletions fsdelegator.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package io2

import (
"io/fs"
"time"
)

// OpenFSDelegator implements fs.FS interface.
Expand All @@ -17,7 +18,7 @@ func (d *OpenFSDelegator) Open(name string) (fs.File, error) {
return d.OpenFunc(name)
}

// DelegateOpenFS returns a OpenFSDelegator delegate fsys.Open.
// DelegateOpenFS returns a OpenFSDelegator delegates fsys.Open.
func DelegateOpenFS(fsys fs.FS) *OpenFSDelegator {
return &OpenFSDelegator{OpenFunc: fsys.Open}
}
Expand Down Expand Up @@ -137,7 +138,7 @@ func (d *FSDelegator) RemoveAll(path string) error {
return d.RemoveAllFunc(path)
}

// DelegateFS returns a FSDelegator delegate the functions of the specified filesystem.
// DelegateFS returns a FSDelegator delegates the functions of the specified filesystem.
// If you want to delegate an open only filesystem like os.DirFS(dir string) use DelegateOpenFS instead.
func DelegateFS(fsys fs.FS) *FSDelegator {
d := &FSDelegator{
Expand Down Expand Up @@ -245,7 +246,7 @@ func (f *FileDelegator) Write(p []byte) (int, error) {
return f.WriteFunc(p)
}

// DelegateFile returns a FileDelegator delegate the functions of the specified file.
// DelegateFile returns a FileDelegator delegates the functions of the specified file.
func DelegateFile(f fs.File) *FileDelegator {
d := &FileDelegator{
StatFunc: f.Stat,
Expand All @@ -260,3 +261,114 @@ func DelegateFile(f fs.File) *FileDelegator {
}
return d
}

// DirEntryValues holds values for fs.DirEntry.
type DirEntryValues struct {
Name string
IsDir bool
Type fs.FileMode
Info fs.FileInfo
}

// DirEntryDelegator implements fs.DirEntry.
type DirEntryDelegator struct {
Values DirEntryValues
InfoFunc func() (fs.FileInfo, error)
}

var _ (fs.DirEntry) = (*DirEntryDelegator)(nil)

// Name returns d.Values.Name.
func (d *DirEntryDelegator) Name() string {
return d.Values.Name
}

// IsDir returns d.Values.IsDir.
func (d *DirEntryDelegator) IsDir() bool {
return d.Values.IsDir
}

// Type returns d.Values.Type.
func (d *DirEntryDelegator) Type() fs.FileMode {
return d.Values.Type
}

// Info calls d.InfoFunc if the function is set otherwise returns d.Values.Info.
func (d *DirEntryDelegator) Info() (fs.FileInfo, error) {
if d.InfoFunc != nil {
return d.InfoFunc()
}
return d.Values.Info, nil
}

// DelegateDirEntry returns a DirEntryDelegator delegates the functions of the specified DirEntry.
func DelegateDirEntry(d fs.DirEntry) *DirEntryDelegator {
return &DirEntryDelegator{
Values: DirEntryValues{
Name: d.Name(),
IsDir: d.IsDir(),
Type: d.Type(),
},
InfoFunc: d.Info,
}
}

// FileInfoValues holds values for fs.FileInfo.
type FileInfoValues struct {
Name string
Size int64
Mode fs.FileMode
ModTime time.Time
IsDir bool
Sys interface{}
}

// FileInfoDelegator implements fs.FileInfo.
type FileInfoDelegator struct {
Values FileInfoValues
}

var _ (fs.FileInfo) = (*FileInfoDelegator)(nil)

// Name returns d.Values.Name.
func (d *FileInfoDelegator) Name() string {
return d.Values.Name
}

// Size returns d.Values.Size.
func (d *FileInfoDelegator) Size() int64 {
return d.Values.Size
}

// Mode returns d.Values.Mode.
func (d *FileInfoDelegator) Mode() fs.FileMode {
return d.Values.Mode
}

// ModTime returns d.Values.ModTime.
func (d *FileInfoDelegator) ModTime() time.Time {
return d.Values.ModTime
}

func (d *FileInfoDelegator) IsDir() bool {
return d.Values.IsDir
}

// Sys returns d.Values.Sys.
func (d *FileInfoDelegator) Sys() interface{} {
return d.Values.Sys
}

// DelegateFileInfo returns a FileInfoDelegator delegates the functions of the specified FileInfo.
func DelegateFileInfo(info fs.FileInfo) *FileInfoDelegator {
return &FileInfoDelegator{
Values: FileInfoValues{
Name: info.Name(),
Size: info.Size(),
Mode: info.Mode(),
ModTime: info.ModTime(),
IsDir: info.IsDir(),
Sys: info.Sys(),
},
}
}
120 changes: 96 additions & 24 deletions fsdelegator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (
func TestOpenFSDelegator_TestFS(t *testing.T) {
d := DelegateOpenFS(os.DirFS("osfs/testdata"))
if err := fstest.TestFS(d, "dir0/file01.txt"); err != nil {
t.Errorf("Error testing/fstest: %+v", err)
t.Errorf(`Error testing/fstest: %+v`, err)
}
}

Expand All @@ -21,51 +21,51 @@ func TestOpenFSDelegator_ErrNotImplemented(t *testing.T) {
var err error
_, err = d.Open("")
if !errors.Is(err, ErrNotImplemented) {
t.Errorf("Error unknown: %v", err)
t.Errorf(`Error unknown: %v`, err)
}
}

func TestFSDelegator_TestFS(t *testing.T) {
d := DelegateFS(os.DirFS("osfs/testdata"))
if err := fstest.TestFS(d, "dir0/file01.txt"); err != nil {
t.Errorf("Error testing/fstest: %+v", err)
t.Errorf(`Error testing/fstest: %+v`, err)
}
}

func testFSDelegatorErrors(t *testing.T, d *FSDelegator, wantErr error) {
var err error
if _, err = d.Open(""); !errors.Is(err, wantErr) {
t.Errorf("Error unknown: %v", err)
t.Errorf(`Error unknown: %v`, err)
}
if _, err = d.ReadDir(""); !errors.Is(err, wantErr) {
t.Errorf("Error unknown: %v", err)
t.Errorf(`Error unknown: %v`, err)
}
if _, err = d.ReadFile(""); !errors.Is(err, wantErr) {
t.Errorf("Error unknown: %v", err)
t.Errorf(`Error unknown: %v`, err)
}
if _, err = d.Glob(""); !errors.Is(err, wantErr) {
t.Errorf("Error unknown: %v", err)
t.Errorf(`Error unknown: %v`, err)
}
if _, err = d.Stat(""); !errors.Is(err, wantErr) {
t.Errorf("Error unknown: %v", err)
t.Errorf(`Error unknown: %v`, err)
}
if _, err = d.Sub(""); !errors.Is(err, wantErr) {
t.Errorf("Error unknown: %v", err)
t.Errorf(`Error unknown: %v`, err)
}
if err = d.MkdirAll("", fs.ModePerm); err != nil {
t.Errorf("Error unknown: %v", err)
t.Errorf(`Error unknown: %v`, err)
}
if _, err = d.CreateFile("", fs.ModePerm); !errors.Is(err, wantErr) {
t.Errorf("Error unknown: %v", err)
t.Errorf(`Error unknown: %v`, err)
}
if _, err = d.WriteFile("", []byte{}, fs.ModePerm); !errors.Is(err, wantErr) {
t.Errorf("Error unknown: %v", err)
t.Errorf(`Error unknown: %v`, err)
}
if err = d.RemoveFile(""); !errors.Is(err, wantErr) {
t.Errorf("Error unknown: %v", err)
t.Errorf(`Error unknown: %v`, err)
}
if err = d.RemoveAll(""); !errors.Is(err, wantErr) {
t.Errorf("Error unknown: %v", err)
t.Errorf(`Error unknown: %v`, err)
}
}

Expand Down Expand Up @@ -130,7 +130,7 @@ func TestDelegateFS_ReadDir(t *testing.T) {
t.Fatal(err)
}
if !reflect.DeepEqual(got, want) {
t.Errorf("Error ReadDir returns %v; want %v", got, want)
t.Errorf(`Error ReadDir returns %v; want %v`, got, want)
}
}

Expand All @@ -147,7 +147,7 @@ func TestDelegateFS_ReadFile(t *testing.T) {
t.Fatal(err)
}
if !reflect.DeepEqual(got, want) {
t.Errorf("Error ReadFile returns %v; want %v", got, want)
t.Errorf(`Error ReadFile returns %v; want %v`, got, want)
}
}

Expand All @@ -164,7 +164,7 @@ func TestDelegateFS_Glob(t *testing.T) {
t.Fatal(err)
}
if !reflect.DeepEqual(got, want) {
t.Errorf("Error ReadFile returns %v; want %v", got, want)
t.Errorf(`Error ReadFile returns %v; want %v`, got, want)
}
}

Expand All @@ -181,7 +181,7 @@ func TestDelegateFS_Stat(t *testing.T) {
t.Fatal(err)
}
if !reflect.DeepEqual(got, want) {
t.Errorf("Error Stat returns %v; want %v", got, want)
t.Errorf(`Error Stat returns %v; want %v`, got, want)
}
}

Expand All @@ -198,7 +198,7 @@ func TestDelegateFS_Sub(t *testing.T) {
t.Fatal(err)
}
if !reflect.DeepEqual(got, want) {
t.Errorf("Error Sub returns %v; want %v", got, want)
t.Errorf(`Error Sub returns %v; want %v`, got, want)
}
}

Expand All @@ -209,19 +209,19 @@ func TestDelegateFile(t *testing.T) {
func testFileDelegatorErrors(t *testing.T, d *FileDelegator, wantErr error) {
var err error
if _, err = d.Stat(); !errors.Is(err, wantErr) {
t.Errorf("Error unknown: %v", err)
t.Errorf(`Error unknown: %v`, err)
}
if _, err = d.Read([]byte{}); !errors.Is(err, wantErr) {
t.Errorf("Error unknown: %v", err)
t.Errorf(`Error unknown: %v`, err)
}
if err = d.Close(); err != nil {
t.Errorf("Error unknown: %v", err)
t.Errorf(`Error unknown: %v`, err)
}
if _, err = d.ReadDir(-1); !errors.Is(err, wantErr) {
t.Errorf("Error unknown: %v", err)
t.Errorf(`Error unknown: %v`, err)
}
if _, err = d.Write([]byte{}); !errors.Is(err, wantErr) {
t.Errorf("Error unknown: %v", err)
t.Errorf(`Error unknown: %v`, err)
}
}

Expand Down Expand Up @@ -250,3 +250,75 @@ func TestFileDelegator(t *testing.T) {
},
}, wantErr)
}

func TestDirEntryDelegator(t *testing.T) {
fsys := os.DirFS("osfs/testdata")
ds, err := fs.ReadDir(fsys, ".")
if err != nil {
t.Fatal(err)
}
if len(ds) == 0 {
t.Fatal(`Fatal ReadDir returns empty.`)
}

want := ds[0]
got := DelegateDirEntry(want)
if got.Name() != want.Name() {
t.Errorf(`Error Name got %s; want %s`, got.Name(), want.Name())
}
if got.IsDir() != want.IsDir() {
t.Errorf(`Error IsDir got %v; want %v`, got.IsDir(), want.IsDir())
}
if got.Type() != want.Type() {
t.Errorf(`Error Type got %v; want %v`, got.Type(), want.Type())
}

wantInfo, err := want.Info()
if err != nil {
t.Fatal(err)
}
gotInfo, err := got.Info()
if err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(gotInfo, wantInfo) {
t.Errorf(`Error Info returns %v; want %v`, gotInfo, wantInfo)
}

got.InfoFunc = nil
gotInfo, err = got.Info()
if err != nil {
t.Fatal(err)
}
if gotInfo != nil {
t.Errorf(`Error info returns %v; want nil`, gotInfo)
}
}

func TestInfoInfoDelegator(t *testing.T) {
fsys := os.DirFS("osfs/testdata")
want, err := fs.Stat(fsys, "dir0/file01.txt")
if err != nil {
t.Fatal(err)
}

got := DelegateFileInfo(want)
if got.Name() != want.Name() {
t.Errorf(`Error Name got %s; want %s`, got.Name(), want.Name())
}
if got.Size() != want.Size() {
t.Errorf(`Error Size got %d; want %d`, got.Size(), want.Size())
}
if got.Mode() != want.Mode() {
t.Errorf(`Error Mode got %v; want %v`, got.Mode(), want.Mode())
}
if got.ModTime() != want.ModTime() {
t.Errorf(`Error ModTime got %v; want %v`, got.ModTime(), want.ModTime())
}
if got.IsDir() != want.IsDir() {
t.Errorf(`Error IsDir got %v; want %v`, got.IsDir(), want.IsDir())
}
if got.Sys() != want.Sys() {
t.Errorf(`Error Sys got %v; want %v`, got.Sys(), want.Sys())
}
}