From f5efd90fbeb37bee14f48d41b60e8110da689c20 Mon Sep 17 00:00:00 2001 From: Ollie Agent Date: Sun, 9 Aug 2026 12:30:33 +0200 Subject: [PATCH] =?UTF-8?q?refactor:=20audit=20fsedsl=20exports=20?= =?UTF-8?q?=E2=80=94=20remove=20dead=20code,=20unexport=20internals?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Dead code removed: - CreateFile option + FsNodeDecl.Create field (never set in production) - Alias option function (Binding.Aliases field retained — used by fs/) - FileTree interface (unused anywhere) - Validation for Create-on-non-dir (no longer possible) Unexported (internal-only plumbing): - NewTree → newTree, TreeOption → treeOption - WithLister/Creator/Deleter/Renamer/Opener/Stat/Readdir → with* - FileConfig → fileConfig - SyntheticEntry → syntheticEntry - FileEntry/DirEntry → fileEntry/dirEntry Retained (used by fs/): - Tree, BuildTree, FsNodeDecl, File, SyntheticFileInfo - All active NodeOptions (Read/Write/Stream/BlockOnce/Request/ RemoveNode/StatOverride/UID/GID/Bind/Doc) - Perm* constants, Binding, Each, DirNode, FileNode - GenerateHelp, NodeOption type --- fsedsl/builder.go | 40 +++++++++-------------- fsedsl/decl.go | 13 +------- fsedsl/decl_test.go | 79 ++++++++++++--------------------------------- fsedsl/file.go | 78 +++++++++++++++++++------------------------- fsedsl/tree.go | 40 +++++++++++------------ fsedsl/tree_test.go | 64 ++++++++++++++++++------------------ 6 files changed, 123 insertions(+), 191 deletions(-) diff --git a/fsedsl/builder.go b/fsedsl/builder.go index 451217d..0b983d6 100644 --- a/fsedsl/builder.go +++ b/fsedsl/builder.go @@ -21,7 +21,6 @@ func validate[Ctx any](d *FsNodeDecl[Ctx], path string) { hasChildren := len(d.Children) > 0 hasBindings := d.Bindings != nil hasFileHandlers := d.Read != nil || d.Write != nil || d.BlockOnce != nil || d.Stream != nil || d.Request != nil - hasCreate := d.Create != nil hasRemove := d.Remove != nil // A node is a directory if it has children. @@ -55,10 +54,6 @@ func validate[Ctx any](d *FsNodeDecl[Ctx], path string) { panic(fmt.Sprintf("BuildTree: %q: at most one of BlockOnce, Stream, Request may be set", fullPath)) } - // Create only valid on directory nodes. - if hasCreate && !isDir { - panic(fmt.Sprintf("BuildTree: %q: Create on non-directory node", fullPath)) - } // Remove is valid on directories and file templates (Bindings with file handlers). isFileTemplate := hasBindings && !isDir && hasFileHandlers if hasRemove && !isDir && !isFileTemplate { @@ -99,29 +94,26 @@ func build[Ctx any](d *FsNodeDecl[Ctx], parentUid, parentGid string, parentCtx C mode = 0755 } - t := NewTree(nil, mode, - WithLister(func(_ []string) ([]os.DirEntry, error) { + t := newTree(nil, mode, + withLister(func(_ []string) ([]os.DirEntry, error) { return listDir(d, uid, gid, parentCtx) }), - WithReaddir(func(_ []string, name string) ([]os.DirEntry, error) { + withReaddir(func(_ []string, name string) ([]os.DirEntry, error) { return readdirDir(d, uid, gid, name, parentCtx) }), - WithStat(func(_ []string, name string) (os.FileInfo, error) { + withStat(func(_ []string, name string) (os.FileInfo, error) { return statDir(d, uid, gid, name, parentCtx) }), - WithOpener(func(_ []string, name string) (File, error) { + withOpener(func(_ []string, name string) (File, error) { return openDir(d, uid, gid, name, parentCtx) }), - WithDeleter(func(_ []string, name string) error { + withDeleter(func(_ []string, name string) error { return deleteDir(d, name, parentCtx) }), - WithCreator(func(_ []string, name string, _ os.FileMode) error { - if d.Create != nil { - return d.Create(parentCtx, name) - } + withCreator(func(_ []string, name string, _ os.FileMode) error { return fmt.Errorf("create not supported") }), - WithRenamer(func(_ []string, old, new string) error { + withRenamer(func(_ []string, old, new string) error { return renameDir(d, old, new, parentCtx) }), ) @@ -132,11 +124,11 @@ func build[Ctx any](d *FsNodeDecl[Ctx], parentUid, parentGid string, parentCtx C if mode == 0 { mode = 0444 } - return NewTree(nil, 0, - WithLister(func(_ []string) ([]os.DirEntry, error) { + return newTree(nil, 0, + withLister(func(_ []string) ([]os.DirEntry, error) { return nil, fmt.Errorf("%s: is a file", d.Name) }), - WithOpener(func(_ []string, name string) (File, error) { + withOpener(func(_ []string, name string) (File, error) { return openLeaf(d, uid, gid, mode, parentCtx, name) }), ) @@ -165,9 +157,9 @@ func listDir[Ctx any](d *FsNodeDecl[Ctx], uid, gid string, ctx Ctx) ([]os.DirEnt m = 0755 } if isFileTemplate { - entries = append(entries, FileEntry(b.Name, m)) + entries = append(entries, fileEntry(b.Name, m)) } else { - entries = append(entries, DirEntry(b.Name, m)) + entries = append(entries, dirEntry(b.Name, m)) } } } @@ -181,9 +173,9 @@ func listDir[Ctx any](d *FsNodeDecl[Ctx], uid, gid string, ctx Ctx) ([]os.DirEnt hasFileHandlers := c.Read != nil || c.Write != nil || c.BlockOnce != nil || c.Stream != nil || c.Request != nil isDir := len(c.Children) > 0 || (c.Bindings != nil && !hasFileHandlers) if isDir { - entries = append(entries, DirEntry(c.Name, m)) + entries = append(entries, dirEntry(c.Name, m)) } else { - entries = append(entries, FileEntry(c.Name, m)) + entries = append(entries, fileEntry(c.Name, m)) } } return entries, nil @@ -323,7 +315,7 @@ func openLeaf[Ctx any](d *FsNodeDecl[Ctx], uid, gid string, mode os.FileMode, ct blockFn = notBlocking } - return &FileConfig{ + return &fileConfig{ StatFn: func() (os.FileInfo, error) { if d.Stat != nil { return d.Stat(), nil diff --git a/fsedsl/decl.go b/fsedsl/decl.go index 31525c9..20b4e1a 100644 --- a/fsedsl/decl.go +++ b/fsedsl/decl.go @@ -68,8 +68,7 @@ type FsNodeDecl[Ctx any] struct { // Request — rdwr: write triggers result, read returns it once. Request func(ctx Ctx, data []byte) ([]byte, error) - // Tcreate + Tremove + Trename (directory ops). - Create func(ctx Ctx, name string) error + // Tremove + Trename (directory ops). Remove func(ctx Ctx) error Rename func(newName string) error } @@ -181,11 +180,6 @@ func Request[Ctx any](fn func(Ctx, []byte) ([]byte, error)) NodeOption[Ctx] { return func(d *FsNodeDecl[Ctx]) { d.Request = fn } } -// CreateFile sets the file creation handler for a directory node. -func CreateFile[Ctx any](fn func(Ctx, string) error) NodeOption[Ctx] { - return func(d *FsNodeDecl[Ctx]) { d.Create = fn } -} - // RemoveNode sets the removal handler for a node. func RemoveNode[Ctx any](fn func(Ctx) error) NodeOption[Ctx] { return func(d *FsNodeDecl[Ctx]) { d.Remove = fn } @@ -206,11 +200,6 @@ func GID[Ctx any](gid string) NodeOption[Ctx] { return func(d *FsNodeDecl[Ctx]) { d.GID = gid } } -// Alias adds alternate names for resolving this node. -func Alias[Ctx any](names ...string) NodeOption[Ctx] { - return func(d *FsNodeDecl[Ctx]) { d.Aliases = append(d.Aliases, names...) } -} - // Bind declares how Each bindings populate the context. // This is advisory metadata; the actual binding is done by Binding.Applier. func Bind[Ctx any](targets ...BindTarget) NodeOption[Ctx] { diff --git a/fsedsl/decl_test.go b/fsedsl/decl_test.go index fb98c6c..d2c2fa7 100644 --- a/fsedsl/decl_test.go +++ b/fsedsl/decl_test.go @@ -51,20 +51,6 @@ func TestNodeOptions(t *testing.T) { } }) - // Test CreateFile option - t.Run("CreateFile", func(t *testing.T) { - createFn := func(ctx TestCtx, name string) error { - return nil - } - spec := DirNode[TestCtx]("test", - FileNode[TestCtx]("child", 0444), - CreateFile[TestCtx](createFn), - ) - if spec.Create == nil { - t.Error("Create not set") - } - }) - // Test RemoveNode option t.Run("RemoveNode", func(t *testing.T) { removeFn := func(ctx TestCtx) error { @@ -107,16 +93,6 @@ func TestNodeOptions(t *testing.T) { }) // Test Alias option - t.Run("Alias", func(t *testing.T) { - spec := FileNode[TestCtx]("test", 0444, Alias[TestCtx]("alt1", "alt2")) - if len(spec.Aliases) != 2 { - t.Errorf("Aliases = %v, want 2 elements", spec.Aliases) - } - if spec.Aliases[0] != "alt1" || spec.Aliases[1] != "alt2" { - t.Errorf("Aliases = %v, want [alt1, alt2]", spec.Aliases) - } - }) - // Test Bind option t.Run("Bind", func(t *testing.T) { spec := DirNode[TestCtx]("test", @@ -134,10 +110,10 @@ func TestNodeOptions(t *testing.T) { // ══════════════════════════════════════════════════════════════════ func TestTreeMount(t *testing.T) { - parent := NewTree(nil, 0755) - child := NewTree(nil, 0755, - WithLister(func(_ []string) ([]os.DirEntry, error) { - return []os.DirEntry{FileEntry("childfile", 0444)}, nil + parent := newTree(nil, 0755) + child := newTree(nil, 0755, + withLister(func(_ []string) ([]os.DirEntry, error) { + return []os.DirEntry{fileEntry("childfile", 0444)}, nil }), ) @@ -166,8 +142,8 @@ func TestTreeMount(t *testing.T) { } func TestTreeSplit(t *testing.T) { - parent := NewTree(nil, 0755) - child := NewTree(nil, 0755) + parent := newTree(nil, 0755) + child := newTree(nil, 0755) parent.Mount("sub", child) // Test exact match @@ -201,7 +177,7 @@ func TestTreeSplit(t *testing.T) { } // Test tree without children - empty := NewTree(nil, 0755) + empty := newTree(nil, 0755) _, _, ok4 := empty.split("anything") if ok4 { t.Error("split should not find anything in empty tree") @@ -219,11 +195,11 @@ func TestTreeIndexOf(t *testing.T) { } // ══════════════════════════════════════════════════════════════════ -// FileConfig tests +// fileConfig tests // ══════════════════════════════════════════════════════════════════ func TestFileConfigMethods(t *testing.T) { - fc := &FileConfig{ + fc := &fileConfig{ StatFn: func() (os.FileInfo, error) { return &SyntheticFileInfo{Name_: "test"}, nil }, ReadFn: func() ([]byte, error) { return []byte("content"), nil }, WriteFn: func(data []byte) error { return nil }, @@ -257,25 +233,25 @@ func TestFileConfigMethods(t *testing.T) { func TestFileConfigModes(t *testing.T) { // Default: all false - fc := &FileConfig{} + fc := &fileConfig{} if fc.BlockingReadMode() || fc.StreamMode() || fc.RequestRespMode() { t.Error("default modes should be false") } // BlockingReadMode - fc2 := &FileConfig{BlockingRead_: true} + fc2 := &fileConfig{BlockingRead_: true} if !fc2.BlockingReadMode() { t.Error("BlockingReadMode should be true") } // StreamMode - fc3 := &FileConfig{StreamMode_: true} + fc3 := &fileConfig{StreamMode_: true} if !fc3.StreamMode() { t.Error("StreamMode should be true") } // RequestRespMode - fc4 := &FileConfig{RequestResp_: true} + fc4 := &fileConfig{RequestResp_: true} if !fc4.RequestRespMode() { t.Error("RequestRespMode should be true") } @@ -323,12 +299,12 @@ func TestSyntheticFileInfo(t *testing.T) { } // ══════════════════════════════════════════════════════════════════ -// SyntheticEntry tests +// syntheticEntry tests // ══════════════════════════════════════════════════════════════════ func TestSyntheticEntry(t *testing.T) { // File entry - fe := &SyntheticEntry{Name_: "file", Mode_: 0644, IsDir_: false} + fe := &syntheticEntry{name: "file", mode: 0644, isDir: false} if fe.Name() != "file" { t.Errorf("Name = %q", fe.Name()) } @@ -347,7 +323,7 @@ func TestSyntheticEntry(t *testing.T) { } // Dir entry - de := &SyntheticEntry{Name_: "dir", Mode_: 0755, IsDir_: true} + de := &syntheticEntry{name: "dir", mode: 0755, isDir: true} if !de.IsDir() { t.Error("IsDir should be true") } @@ -357,12 +333,12 @@ func TestSyntheticEntry(t *testing.T) { } func TestFileEntryAndDirEntry(t *testing.T) { - fe := FileEntry("myfile", 0644) + fe := fileEntry("myfile", 0644) if fe.Name() != "myfile" || fe.IsDir() { - t.Error("FileEntry wrong") + t.Error("fileEntry wrong") } - de := DirEntry("mydir", 0755) + de := dirEntry("mydir", 0755) if de.Name() != "mydir" || !de.IsDir() { t.Error("DirEntry wrong") } @@ -730,21 +706,6 @@ func TestValidateMultipleBlockingModes(t *testing.T) { BuildTree(spec, TestCtx{}) } -func TestValidateCreateOnNonDir(t *testing.T) { - defer func() { - if r := recover(); r == nil { - t.Error("should panic for Create on non-dir") - } - }() - - spec := DirNode[TestCtx]("/", - FileNode[TestCtx]("file", 0444, - CreateFile(func(ctx TestCtx, name string) error { return nil }), - ), - ) - BuildTree(spec, TestCtx{}) -} - func TestValidateTemplateWithoutBindings(t *testing.T) { defer func() { if r := recover(); r == nil { @@ -1010,7 +971,7 @@ func TestStatDirNotFound(t *testing.T) { func TestCreateNotSupported(t *testing.T) { spec := DirNode[TestCtx]("/", FileNode[TestCtx]("file", 0444), - // No CreateFile handler + // No create handler — always returns error ) tree := BuildTree(spec, TestCtx{}) diff --git a/fsedsl/file.go b/fsedsl/file.go index ee5a085..8e1a776 100644 --- a/fsedsl/file.go +++ b/fsedsl/file.go @@ -6,6 +6,14 @@ import ( "time" ) +// Standard permission constants for EDSL-built trees. +const ( + PermChildDir os.FileMode = 0555 + PermIdx os.FileMode = 0444 + PermMkdir os.FileMode = 0755 + PermMkdirPrivate os.FileMode = 0700 +) + // File is an open handle to a single named blob. type File interface { Stat() (os.FileInfo, error) @@ -22,18 +30,8 @@ type File interface { RequestRespMode() bool } -// FileTree is a named collection of entries. -type FileTree interface { - Stat(name string) (os.FileInfo, error) - List() ([]os.DirEntry, error) - Open(name string) (File, error) - Create(name string) error - Delete(name string) error - Rename(oldName, newName string) error -} - -// FileConfig implements File via function pointers. -type FileConfig struct { +// fileConfig implements File via function pointers. +type fileConfig struct { StatFn func() (os.FileInfo, error) ReadFn func() ([]byte, error) WriteFn func([]byte) error @@ -43,15 +41,15 @@ type FileConfig struct { RequestResp_ bool // rdwr: write blocks on write, read returns result once } -func (e *FileConfig) Stat() (os.FileInfo, error) { return e.StatFn() } -func (e *FileConfig) Read() ([]byte, error) { return e.ReadFn() } -func (e *FileConfig) Write(data []byte) error { return e.WriteFn(data) } -func (e *FileConfig) BlockingRead(ctx context.Context, base string) ([]byte, string, error) { +func (e *fileConfig) Stat() (os.FileInfo, error) { return e.StatFn() } +func (e *fileConfig) Read() ([]byte, error) { return e.ReadFn() } +func (e *fileConfig) Write(data []byte) error { return e.WriteFn(data) } +func (e *fileConfig) BlockingRead(ctx context.Context, base string) ([]byte, string, error) { return e.BlockingReadFn(ctx, base) } -func (e *FileConfig) BlockingReadMode() bool { return e.BlockingRead_ } -func (e *FileConfig) StreamMode() bool { return e.StreamMode_ } -func (e *FileConfig) RequestRespMode() bool { return e.RequestResp_ } +func (e *fileConfig) BlockingReadMode() bool { return e.BlockingRead_ } +func (e *fileConfig) StreamMode() bool { return e.StreamMode_ } +func (e *fileConfig) RequestRespMode() bool { return e.RequestResp_ } // SyntheticFileInfo implements os.FileInfo for entries with no backing file. type SyntheticFileInfo struct { @@ -71,39 +69,31 @@ func (f *SyntheticFileInfo) ModTime() time.Time { return time.Time{} } func (f *SyntheticFileInfo) IsDir() bool { return f.IsDir_ } func (f *SyntheticFileInfo) Sys() any { return nil } -// SyntheticEntry implements os.DirEntry for entries with no backing file. -type SyntheticEntry struct { - Name_ string - Mode_ os.FileMode - IsDir_ bool +// syntheticEntry implements os.DirEntry for entries with no backing file. +type syntheticEntry struct { + name string + mode os.FileMode + isDir bool } -func (e *SyntheticEntry) Name() string { return e.Name_ } -func (e *SyntheticEntry) IsDir() bool { return e.IsDir_ } -func (e *SyntheticEntry) Type() os.FileMode { - if e.IsDir_ { +func (e *syntheticEntry) Name() string { return e.name } +func (e *syntheticEntry) IsDir() bool { return e.isDir } +func (e *syntheticEntry) Type() os.FileMode { + if e.isDir { return os.ModeDir } return 0 } -func (e *SyntheticEntry) Info() (os.FileInfo, error) { - return &SyntheticFileInfo{Name_: e.Name_, Mode_: e.Mode_, IsDir_: e.IsDir_}, nil +func (e *syntheticEntry) Info() (os.FileInfo, error) { + return &SyntheticFileInfo{Name_: e.name, Mode_: e.mode, IsDir_: e.isDir}, nil } -// FileEntry returns a synthetic file DirEntry. -func FileEntry(name string, mode os.FileMode) os.DirEntry { - return &SyntheticEntry{Name_: name, Mode_: mode} +// fileEntry returns a synthetic file DirEntry. +func fileEntry(name string, mode os.FileMode) os.DirEntry { + return &syntheticEntry{name: name, mode: mode} } -// DirEntry returns a synthetic directory DirEntry. -func DirEntry(name string, mode os.FileMode) os.DirEntry { - return &SyntheticEntry{Name_: name, Mode_: mode, IsDir_: true} +// dirEntry returns a synthetic directory DirEntry. +func dirEntry(name string, mode os.FileMode) os.DirEntry { + return &syntheticEntry{name: name, mode: mode, isDir: true} } - -// Structural permissions — used by Tree for mounted children and synthetic files. -const ( - PermChildDir os.FileMode = 0555 - PermIdx os.FileMode = 0444 - PermMkdir os.FileMode = 0755 - PermMkdirPrivate os.FileMode = 0700 -) diff --git a/fsedsl/tree.go b/fsedsl/tree.go index a570081..7dbf3ac 100644 --- a/fsedsl/tree.go +++ b/fsedsl/tree.go @@ -22,47 +22,47 @@ type Tree struct { Data any // user-attached state } -// TreeOption configures a Tree. -type TreeOption func(*Tree) +// treeOption configures a Tree. +type treeOption func(*Tree) -// WithLister overrides how the tree lists its entries. -func WithLister(fn func(dirs []string) ([]os.DirEntry, error)) TreeOption { +// withLister overrides how the tree lists its entries. +func withLister(fn func(dirs []string) ([]os.DirEntry, error)) treeOption { return func(d *Tree) { d.listFn = fn } } -// WithCreator overrides file creation logic. -func WithCreator(fn func(dirs []string, name string, perm os.FileMode) error) TreeOption { +// withCreator overrides file creation logic. +func withCreator(fn func(dirs []string, name string, perm os.FileMode) error) treeOption { return func(d *Tree) { d.createFn = fn } } -// WithDeleter overrides file deletion logic. -func WithDeleter(fn func(dirs []string, name string) error) TreeOption { +// withDeleter overrides file deletion logic. +func withDeleter(fn func(dirs []string, name string) error) treeOption { return func(d *Tree) { d.deleteFn = fn } } -// WithRenamer overrides rename logic. -func WithRenamer(fn func(dirs []string, old, new string) error) TreeOption { +// withRenamer overrides rename logic. +func withRenamer(fn func(dirs []string, old, new string) error) treeOption { return func(d *Tree) { d.renameFn = fn } } -// WithOpener overrides how entries are opened. -func WithOpener(fn func(dirs []string, name string) (File, error)) TreeOption { +// withOpener overrides how entries are opened. +func withOpener(fn func(dirs []string, name string) (File, error)) treeOption { return func(d *Tree) { d.openFn = fn } } -// WithStat overrides how entries are stat'd. -func WithStat(fn func(dirs []string, name string) (os.FileInfo, error)) TreeOption { +// withStat overrides how entries are stat'd. +func withStat(fn func(dirs []string, name string) (os.FileInfo, error)) treeOption { return func(d *Tree) { d.statFn = fn } } -// WithReaddir overrides subdirectory listing. -func WithReaddir(fn func(dirs []string, name string) ([]os.DirEntry, error)) TreeOption { +// withReaddir overrides subdirectory listing. +func withReaddir(fn func(dirs []string, name string) ([]os.DirEntry, error)) treeOption { return func(d *Tree) { d.readdirFn = fn } } -// NewTree creates a Tree. In EDSL usage, dirs is nil and all behavior +// newTree creates a Tree. In EDSL usage, dirs is nil and all behavior // is provided via options. -func NewTree(dirs []string, perm os.FileMode, opts ...TreeOption) *Tree { +func newTree(dirs []string, perm os.FileMode, opts ...treeOption) *Tree { d := &Tree{Tree: dirs, perm: perm} for _, o := range opts { o(d) @@ -144,14 +144,14 @@ func (d *Tree) List() ([]os.DirEntry, error) { return nil, err } for name := range d.children { - entries = append(entries, DirEntry(name, PermChildDir)) + entries = append(entries, dirEntry(name, PermChildDir)) } return entries, nil } // No list function and no backing dirs — return children only. var result []os.DirEntry for name := range d.children { - result = append(result, DirEntry(name, PermChildDir)) + result = append(result, dirEntry(name, PermChildDir)) } return result, nil } diff --git a/fsedsl/tree_test.go b/fsedsl/tree_test.go index fb9d897..ebf4528 100644 --- a/fsedsl/tree_test.go +++ b/fsedsl/tree_test.go @@ -9,7 +9,7 @@ import ( func TestTreeMkdirAll(t *testing.T) { tmpDir := t.TempDir() - tree := NewTree([]string{tmpDir}, 0755) + tree := newTree([]string{tmpDir}, 0755) err := tree.MkdirAll("a/b/c") if err != nil { @@ -25,7 +25,7 @@ func TestTreeMkdirAll(t *testing.T) { } func TestTreeMkdirAllNoBackingDir(t *testing.T) { - tree := NewTree(nil, 0755) + tree := newTree(nil, 0755) err := tree.MkdirAll("somedir") if err == nil { t.Fatal("expected error for nil backing dir") @@ -34,10 +34,10 @@ func TestTreeMkdirAllNoBackingDir(t *testing.T) { func TestTreeWithCustomFunctions(t *testing.T) { listed := false - tree := NewTree(nil, 0755, - WithLister(func(_ []string) ([]os.DirEntry, error) { + tree := newTree(nil, 0755, + withLister(func(_ []string) ([]os.DirEntry, error) { listed = true - return []os.DirEntry{FileEntry("a", 0644)}, nil + return []os.DirEntry{fileEntry("a", 0644)}, nil }), ) entries, err := tree.List() @@ -53,9 +53,9 @@ func TestTreeWithCustomFunctions(t *testing.T) { } func TestTreeOpen(t *testing.T) { - tree := NewTree(nil, 0644, - WithOpener(func(_ []string, name string) (File, error) { - return &FileConfig{ + tree := newTree(nil, 0644, + withOpener(func(_ []string, name string) (File, error) { + return &fileConfig{ StatFn: func() (os.FileInfo, error) { return &SyntheticFileInfo{Name_: name}, nil }, ReadFn: func() ([]byte, error) { return []byte("content"), nil }, WriteFn: func([]byte) error { return nil }, @@ -77,7 +77,7 @@ func TestTreeOpen(t *testing.T) { } func TestTreeOpenNotFound(t *testing.T) { - tree := NewTree(nil, 0644) + tree := newTree(nil, 0644) _, err := tree.Open("nonexistent") if err == nil { t.Fatal("expected error") @@ -85,8 +85,8 @@ func TestTreeOpenNotFound(t *testing.T) { } func TestTreeStat(t *testing.T) { - tree := NewTree(nil, 0755, - WithStat(func(_ []string, name string) (os.FileInfo, error) { + tree := newTree(nil, 0755, + withStat(func(_ []string, name string) (os.FileInfo, error) { return &SyntheticFileInfo{Name_: name, Mode_: 0644, Size_: 42}, nil }), ) @@ -100,9 +100,9 @@ func TestTreeStat(t *testing.T) { } func TestTreeStatOpenerFallback(t *testing.T) { - tree := NewTree(nil, 0755, - WithOpener(func(_ []string, name string) (File, error) { - return &FileConfig{ + tree := newTree(nil, 0755, + withOpener(func(_ []string, name string) (File, error) { + return &fileConfig{ StatFn: func() (os.FileInfo, error) { return &SyntheticFileInfo{Name_: name, Size_: 99}, nil }, @@ -122,21 +122,21 @@ func TestTreeStatOpenerFallback(t *testing.T) { } func TestTreeChildDelegation(t *testing.T) { - child := NewTree(nil, 0755, - WithOpener(func(_ []string, name string) (File, error) { - return &FileConfig{ + child := newTree(nil, 0755, + withOpener(func(_ []string, name string) (File, error) { + return &fileConfig{ StatFn: func() (os.FileInfo, error) { return &SyntheticFileInfo{Name_: name}, nil }, ReadFn: func() ([]byte, error) { return []byte("child:" + name), nil }, WriteFn: func([]byte) error { return nil }, BlockingReadFn: func(context.Context, string) ([]byte, string, error) { return nil, "", nil }, }, nil }), - WithLister(func(_ []string) ([]os.DirEntry, error) { - return []os.DirEntry{FileEntry("inner", 0644)}, nil + withLister(func(_ []string) ([]os.DirEntry, error) { + return []os.DirEntry{fileEntry("inner", 0644)}, nil }), ) - parent := NewTree(nil, 0755) + parent := newTree(nil, 0755) parent.Mount("sub", child) // Open delegated to child @@ -176,8 +176,8 @@ func TestTreeChildDelegation(t *testing.T) { func TestTreeChildMkdirAll(t *testing.T) { tmpDir := t.TempDir() - child := NewTree([]string{tmpDir}, 0755) - parent := NewTree(nil, 0755) + child := newTree([]string{tmpDir}, 0755) + parent := newTree(nil, 0755) parent.Mount("sub", child) err := parent.MkdirAll("sub/new/deep/path") @@ -192,8 +192,8 @@ func TestTreeChildMkdirAll(t *testing.T) { func TestTreeCreate(t *testing.T) { created := "" - tree := NewTree(nil, 0644, - WithCreator(func(_ []string, name string, _ os.FileMode) error { + tree := newTree(nil, 0644, + withCreator(func(_ []string, name string, _ os.FileMode) error { created = name return nil }), @@ -208,8 +208,8 @@ func TestTreeCreate(t *testing.T) { func TestTreeDelete(t *testing.T) { deleted := "" - tree := NewTree(nil, 0644, - WithDeleter(func(_ []string, name string) error { + tree := newTree(nil, 0644, + withDeleter(func(_ []string, name string) error { deleted = name return nil }), @@ -224,8 +224,8 @@ func TestTreeDelete(t *testing.T) { func TestTreeRename(t *testing.T) { var oldN, newN string - tree := NewTree(nil, 0644, - WithRenamer(func(_ []string, old, new string) error { + tree := newTree(nil, 0644, + withRenamer(func(_ []string, old, new string) error { oldN, newN = old, new return nil }), @@ -239,9 +239,9 @@ func TestTreeRename(t *testing.T) { } func TestTreeReaddir(t *testing.T) { - tree := NewTree(nil, 0755, - WithReaddir(func(_ []string, name string) ([]os.DirEntry, error) { - return []os.DirEntry{FileEntry("child", 0644)}, nil + tree := newTree(nil, 0755, + withReaddir(func(_ []string, name string) ([]os.DirEntry, error) { + return []os.DirEntry{fileEntry("child", 0644)}, nil }), ) entries, err := tree.Readdir("subdir") @@ -254,7 +254,7 @@ func TestTreeReaddir(t *testing.T) { } func TestReaddirNotFound(t *testing.T) { - tree := NewTree(nil, 0755) + tree := newTree(nil, 0755) _, err := tree.Readdir("nowhere") if err == nil { t.Fatal("expected error")