refactor(fs): use underlyingPath to determine virtual files more reliably (#9302)

Signed-off-by: nikpivkin <nikita.pivkin@smartforce.io>
This commit is contained in:
Nikita Pivkin
2025-09-23 20:36:35 +06:00
committed by GitHub
parent d57b1606c9
commit 352855ef64
3 changed files with 99 additions and 3 deletions

View File

@@ -28,7 +28,7 @@ type file struct {
}
func (f *file) isVirtual() bool {
return len(f.data) != 0 || f.stat.IsDir()
return f.underlyingPath == ""
}
func (f *file) Open(name string) (fs.File, error) {
@@ -59,7 +59,7 @@ func (f *file) open() (fs.File, error) {
fileStat: f.stat,
entry: entries,
}, nil
case len(f.data) != 0: // Virtual file
case f.isVirtual(): // Virtual file
return &openMapFile{
path: f.stat.name,
file: f,

View File

@@ -1,6 +1,7 @@
package mapfs
import (
"errors"
"fmt"
"io"
"io/fs"
@@ -98,7 +99,7 @@ func (m *FS) FilterFunc(fn func(path string, d fs.DirEntry) (bool, error)) (*FS,
return xerrors.Errorf("unable to get %s: %w", path, err)
}
// Virtual file
if f.underlyingPath == "" {
if f.isVirtual() {
return newFS.WriteVirtualFile(path, f.data, f.stat.mode)
}
return newFS.WriteFile(path, f.underlyingPath)
@@ -197,6 +198,9 @@ func (m *FS) Open(name string) (fs.File, error) {
// WriteFile creates a mapping between path and underlyingPath.
func (m *FS) WriteFile(path, underlyingPath string) error {
if underlyingPath == "" {
return errors.New("underlying path must not be empty")
}
return m.root.WriteFile(cleanPath(path), underlyingPath)
}

View File

@@ -40,6 +40,12 @@ var (
isDir: false,
size: 7,
}
emptyVirtualFileInfo = fileInfo{
name: "empty-virtual.txt",
fileMode: 0o600,
isDir: false,
size: 0,
}
cdirFileInfo = fileInfo{
name: "c",
fileMode: fs.FileMode(0o700) | fs.ModeDir,
@@ -57,6 +63,7 @@ func initFS(t *testing.T) *mapfs.FS {
require.NoError(t, fsys.WriteFile("a/b/c/c.txt", "testdata/c.txt"))
require.NoError(t, fsys.WriteFile("a/b/c/.dotfile", "testdata/dotfile"))
require.NoError(t, fsys.WriteVirtualFile("a/b/c/virtual.txt", []byte("virtual"), 0o600))
require.NoError(t, fsys.WriteVirtualFile("a/b/c/empty-virtual.txt", []byte{}, 0o600))
return fsys
}
@@ -119,6 +126,12 @@ func TestFS_Stat(t *testing.T) {
want: virtualFileInfo,
wantErr: assert.NoError,
},
{
name: "empty virtual file",
filePath: "a/b/c/empty-virtual.txt",
want: emptyVirtualFileInfo,
wantErr: assert.NoError,
},
{
name: "dir",
filePath: "a/b/c",
@@ -142,6 +155,55 @@ func TestFS_Stat(t *testing.T) {
}
}
func TestFS_WriteFile(t *testing.T) {
tests := []struct {
name string
dstPath string
underlyingPath string
wantErr assert.ErrorAssertionFunc
}{
{
name: "write file",
dstPath: "hello.txt",
underlyingPath: "testdata/hello.txt",
wantErr: assert.NoError,
},
{
name: "write file to non-existent dir",
dstPath: "test/hello.txt",
underlyingPath: "testdata/hello.txt",
wantErr: assert.Error,
},
{
name: "write file to existent dir",
dstPath: "subdir/hello.txt",
underlyingPath: "testdata/hello.txt",
wantErr: assert.NoError,
},
{
name: "empty underlying path",
dstPath: "copy/empty.txt",
underlyingPath: "",
wantErr: assert.Error,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
fsys := mapfs.New()
require.NoError(t, fsys.MkdirAll("subdir", 0o700))
err := fsys.WriteFile(tt.dstPath, tt.underlyingPath)
tt.wantErr(t, err)
if err == nil {
_, statErr := fsys.Stat(tt.dstPath)
assert.NoError(t, statErr)
}
})
}
}
func TestFS_ReadDir(t *testing.T) {
type dirEntry struct {
name string
@@ -211,6 +273,13 @@ func TestFS_ReadDir(t *testing.T) {
size: 0,
},
},
{
name: "empty-virtual.txt",
fileMode: 0o600,
isDir: false,
size: 0,
fileInfo: emptyVirtualFileInfo,
},
{
name: "virtual.txt",
fileMode: 0o600,
@@ -278,6 +347,15 @@ func TestFS_Open(t *testing.T) {
},
wantErr: assert.NoError,
},
{
name: "empty virtual file",
filePath: "a/b/c/empty-virtual.txt",
want: file{
fileInfo: emptyVirtualFileInfo,
body: "",
},
wantErr: assert.NoError,
},
{
name: "dir",
filePath: "a/b/c",
@@ -337,6 +415,12 @@ func TestFS_ReadFile(t *testing.T) {
want: "virtual",
wantErr: assert.NoError,
},
{
name: "empty virtual file",
filePath: "a/b/c/empty-virtual.txt",
want: "",
wantErr: assert.NoError,
},
{
name: "no such file",
filePath: "nosuch.txt",
@@ -385,6 +469,7 @@ func TestFS_Glob(t *testing.T) {
pattern: "*/b/c/*.txt",
want: []string{
"a/b/c/c.txt",
"a/b/c/empty-virtual.txt",
"a/b/c/virtual.txt",
},
wantErr: assert.NoError,
@@ -432,6 +517,11 @@ func TestFS_Remove(t *testing.T) {
path: "a/b/c/virtual.txt",
wantErr: assert.NoError,
},
{
name: "empty virtual file",
path: "a/b/c/empty-virtual.txt",
wantErr: assert.NoError,
},
{
name: "empty dir",
path: "a/b/empty",
@@ -481,6 +571,8 @@ func TestFS_RemoveAll(t *testing.T) {
require.ErrorIs(t, err, fs.ErrNotExist)
_, err = fsys.Stat("a/b/c/virtual.txt")
require.ErrorIs(t, err, fs.ErrNotExist)
_, err = fsys.Stat("a/b/c/empty-virtual.txt")
require.ErrorIs(t, err, fs.ErrNotExist)
})
}