Skip to content

Commit 12eb9b1

Browse files
committed
*: Expand tests covering fs.Rename
Ahead of making changes to Rename, ensures that the behaviour across the built-in implementations are aligned by expanding tests, so that we avoid future regression. Signed-off-by: Paulo Gomes <[email protected]>
1 parent 529dad7 commit 12eb9b1

File tree

6 files changed

+121
-29
lines changed

6 files changed

+121
-29
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ $(GOLANGCI):
1414

1515
.PHONY: test
1616
test:
17-
$(GOTEST) -race ./...
17+
$(GOTEST) -race -timeout 60s ./...
1818

1919
test-coverage:
2020
echo "" > $(COVERAGE_REPORT); \

fs.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,11 @@ import (
88
)
99

1010
var (
11-
ErrReadOnly = errors.New("read-only filesystem")
12-
ErrNotSupported = errors.New("feature not supported")
13-
ErrCrossedBoundary = errors.New("chroot boundary crossed")
11+
ErrReadOnly = errors.New("read-only filesystem")
12+
ErrNotSupported = errors.New("feature not supported")
13+
ErrCrossedBoundary = errors.New("chroot boundary crossed")
14+
ErrBaseDirCannotBeRemoved = errors.New("base dir cannot be removed")
15+
ErrBaseDirCannotBeRenamed = errors.New("base dir cannot be renamed")
1416
)
1517

1618
// Capability holds the supported features of a billy filesystem. This does

osfs/os_bound.go

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
package osfs
2121

2222
import (
23-
"errors"
2423
"fmt"
2524
"io/fs"
2625
"os"
@@ -32,9 +31,6 @@ import (
3231
)
3332

3433
var (
35-
ErrBaseDirCannotBeRemoved = errors.New("base dir cannot be removed")
36-
ErrBaseDirCannotBeRenamed = errors.New("base dir cannot be renamed")
37-
3834
dotPrefixes = []string{"./", ".\\"}
3935
)
4036

@@ -84,15 +80,21 @@ func (fs *BoundOS) ReadDir(path string) ([]os.FileInfo, error) {
8480

8581
func (fs *BoundOS) Rename(from, to string) error {
8682
if from == "." || from == fs.baseDir {
87-
return ErrBaseDirCannotBeRenamed
83+
return billy.ErrBaseDirCannotBeRenamed
8884
}
8985

9086
from = fs.expandDot(from)
91-
to = fs.expandDot(to)
87+
_, err := fs.Lstat(from)
88+
if err != nil {
89+
return err
90+
}
91+
9292
f, err := fs.abs(from)
9393
if err != nil {
9494
return err
9595
}
96+
97+
to = fs.expandDot(to)
9698
t, err := fs.abs(to)
9799
if err != nil {
98100
return err
@@ -130,7 +132,7 @@ func (fs *BoundOS) Stat(filename string) (os.FileInfo, error) {
130132

131133
func (fs *BoundOS) Remove(filename string) error {
132134
if filename == "." || filename == fs.baseDir {
133-
return ErrBaseDirCannotBeRemoved
135+
return billy.ErrBaseDirCannotBeRemoved
134136
}
135137

136138
fn, err := fs.abs(filename)
@@ -161,7 +163,7 @@ func (fs *BoundOS) Join(elem ...string) string {
161163

162164
func (fs *BoundOS) RemoveAll(path string) error {
163165
if path == "." || path == fs.baseDir {
164-
return ErrBaseDirCannotBeRemoved
166+
return billy.ErrBaseDirCannotBeRemoved
165167
}
166168

167169
path = fs.expandDot(path)

osfs/os_bound_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1293,10 +1293,10 @@ func TestRename(t *testing.T) {
12931293
assert.NotNil(fi)
12941294

12951295
err = fs.Rename(filepath.FromSlash("/tmp/outside/cwd/file1"), newFile)
1296-
require.ErrorContains(t, err, notFoundError())
1296+
require.ErrorIs(t, err, os.ErrNotExist)
12971297

12981298
err = fs.Rename(oldFile, filepath.FromSlash("/tmp/outside/cwd/file2"))
1299-
require.ErrorContains(t, err, notFoundError())
1299+
require.ErrorIs(t, err, os.ErrNotExist)
13001300
}
13011301

13021302
func mustExist(filename string) {

osfs/os_chroot.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,12 @@ func (fs *ChrootOS) ReadDir(dir string) ([]os.FileInfo, error) {
5252
}
5353

5454
func (fs *ChrootOS) Rename(from, to string) error {
55-
if err := fs.createDir(to); err != nil {
55+
_, err := fs.Lstat(from)
56+
if err != nil {
57+
return err
58+
}
59+
60+
if err = fs.createDir(to); err != nil {
5661
return err
5762
}
5863

test/basic_test.go

Lines changed: 97 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,17 @@ import (
44
"bytes"
55
"fmt"
66
"io"
7+
stdfs "io/fs"
78
"os"
89
"path/filepath"
10+
"reflect"
11+
"slices"
12+
"strings"
913
"testing"
1014

15+
"github.com/go-git/go-billy/v6"
1116
. "github.com/go-git/go-billy/v6" //nolint
17+
"github.com/go-git/go-billy/v6/osfs"
1218
"github.com/go-git/go-billy/v6/util"
1319
"github.com/stretchr/testify/assert"
1420
"github.com/stretchr/testify/require"
@@ -469,24 +475,101 @@ func TestStatNonExistent(t *testing.T) {
469475
}
470476

471477
func TestRename(t *testing.T) {
472-
eachBasicFS(t, func(t *testing.T, fs Basic) {
473-
t.Helper()
474-
err := util.WriteFile(fs, "foo", nil, 0644)
475-
require.NoError(t, err)
476-
477-
err = fs.Rename("foo", "bar")
478-
require.NoError(t, err)
479-
480-
foo, err := fs.Stat("foo")
481-
assert.Nil(t, foo)
482-
assert.ErrorIs(t, err, os.ErrNotExist)
478+
tests := []struct {
479+
name string
480+
before func(*testing.T, billy.Filesystem)
481+
from string
482+
to string
483+
wantErr *error
484+
wantFiles []string
485+
}{
486+
{
487+
name: "from not found",
488+
from: "foo",
489+
to: "bar",
490+
wantErr: &os.ErrNotExist,
491+
},
492+
{
493+
name: "file rename",
494+
before: func(t *testing.T, fs billy.Filesystem) {
495+
root := fsRoot(fs)
496+
_, err := fs.Create(fs.Join(root, "foo"))
497+
require.NoError(t, err)
498+
},
499+
from: "foo",
500+
to: "bar",
501+
wantFiles: []string{"/bar"},
502+
},
503+
{
504+
name: "dir rename",
505+
before: func(t *testing.T, fs billy.Filesystem) {
506+
root := fsRoot(fs)
507+
_, err := fs.Create(fs.Join(root, "foo", "bar1"))
508+
require.NoError(t, err)
509+
_, err = fs.Create(fs.Join(root, "foo", "bar2"))
510+
require.NoError(t, err)
511+
},
512+
from: "foo",
513+
to: "bar",
514+
wantFiles: []string{"/bar/bar1", "/bar/bar2"},
515+
},
516+
}
483517

484-
bar, err := fs.Stat("bar")
485-
require.NoError(t, err)
486-
assert.NotNil(t, bar)
518+
eachFS(t, func(t *testing.T, fs Filesystem) {
519+
t.Helper()
520+
521+
root := fsRoot(fs)
522+
for _, tc := range tests {
523+
t.Run(tc.name, func(t *testing.T) {
524+
if tc.before != nil {
525+
tc.before(t, fs)
526+
}
527+
528+
err := fs.Rename(fs.Join(root, tc.from), fs.Join(root, tc.to))
529+
if tc.wantErr == nil {
530+
require.NoError(t, err)
531+
} else {
532+
require.ErrorIs(t, err, *tc.wantErr)
533+
}
534+
535+
err = util.Walk(fs, root, func(path string, fi stdfs.FileInfo, err error) error {
536+
if err != nil {
537+
return err
538+
}
539+
540+
if fi.IsDir() {
541+
return nil
542+
}
543+
544+
if root != "/" {
545+
path = strings.TrimPrefix(path, root)
546+
}
547+
if !slices.Contains(tc.wantFiles, path) {
548+
assert.Fail(t, "file not found", "name", path)
549+
}
550+
551+
return nil
552+
})
553+
require.NoError(t, err)
554+
555+
fis, _ := fs.ReadDir(root)
556+
for _, fi := range fis {
557+
cpath := fs.Join(root, fi.Name())
558+
err := util.RemoveAll(fs, cpath)
559+
require.NoError(t, err)
560+
}
561+
})
562+
}
487563
})
488564
}
489565

566+
func fsRoot(fs billy.Filesystem) string {
567+
if reflect.TypeOf(fs) == reflect.TypeOf(&osfs.BoundOS{}) {
568+
return fs.Root()
569+
}
570+
return "/"
571+
}
572+
490573
func TestOpenAndWrite(t *testing.T) {
491574
eachBasicFS(t, func(t *testing.T, fs Basic) {
492575
t.Helper()

0 commit comments

Comments
 (0)