mirror of
https://github.com/rclone/rclone.git
synced 2024-12-25 00:19:13 +01:00
7e20e16cff
This is in preparation for removing the Lister code and replacing the fundamental operation in the Fs with listing a single directory.
334 lines
6.6 KiB
Go
334 lines
6.6 KiB
Go
package fs
|
|
|
|
import (
|
|
"sync"
|
|
"testing"
|
|
|
|
"github.com/pkg/errors"
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
type (
|
|
listResult struct {
|
|
entries DirEntries
|
|
err error
|
|
}
|
|
|
|
listResults map[string]listResult
|
|
|
|
errorMap map[string]error
|
|
|
|
listDirs struct {
|
|
mu sync.Mutex
|
|
t *testing.T
|
|
fs Fs
|
|
includeAll bool
|
|
results listResults
|
|
walkResults listResults
|
|
walkErrors errorMap
|
|
finalError error
|
|
checkMaps bool
|
|
maxLevel int
|
|
}
|
|
)
|
|
|
|
func newListDirs(t *testing.T, f Fs, includeAll bool, results listResults, walkErrors errorMap, finalError error) *listDirs {
|
|
return &listDirs{
|
|
t: t,
|
|
fs: f,
|
|
includeAll: includeAll,
|
|
results: results,
|
|
walkErrors: walkErrors,
|
|
walkResults: listResults{},
|
|
finalError: finalError,
|
|
checkMaps: true,
|
|
maxLevel: -1,
|
|
}
|
|
}
|
|
|
|
// NoCheckMaps marks the maps as to be ignored at the end
|
|
func (ls *listDirs) NoCheckMaps() *listDirs {
|
|
ls.checkMaps = false
|
|
return ls
|
|
}
|
|
|
|
// SetLevel(1) turns off recursion
|
|
func (ls *listDirs) SetLevel(maxLevel int) *listDirs {
|
|
ls.maxLevel = maxLevel
|
|
return ls
|
|
}
|
|
|
|
// ListDir returns the expected listing for the directory
|
|
func (ls *listDirs) ListDir(f Fs, includeAll bool, dir string) (entries DirEntries, err error) {
|
|
ls.mu.Lock()
|
|
defer ls.mu.Unlock()
|
|
assert.Equal(ls.t, ls.fs, f)
|
|
assert.Equal(ls.t, ls.includeAll, includeAll)
|
|
|
|
// Fetch results for this path
|
|
result, ok := ls.results[dir]
|
|
if !ok {
|
|
ls.t.Errorf("Unexpected list of %q", dir)
|
|
return nil, errors.New("unexpected list")
|
|
}
|
|
delete(ls.results, dir)
|
|
|
|
// Put expected results for call of WalkFn
|
|
ls.walkResults[dir] = result
|
|
|
|
return result.entries, result.err
|
|
}
|
|
|
|
// IsFinished checks everything expected was used up
|
|
func (ls *listDirs) IsFinished() {
|
|
if ls.checkMaps {
|
|
assert.Equal(ls.t, errorMap{}, ls.walkErrors)
|
|
assert.Equal(ls.t, listResults{}, ls.results)
|
|
assert.Equal(ls.t, listResults{}, ls.walkResults)
|
|
}
|
|
}
|
|
|
|
// WalkFn is called by the walk to test the expectations
|
|
func (ls *listDirs) WalkFn(dir string, entries DirEntries, err error) error {
|
|
ls.mu.Lock()
|
|
defer ls.mu.Unlock()
|
|
|
|
// Fetch expected entries and err
|
|
result, ok := ls.walkResults[dir]
|
|
if !ok {
|
|
ls.t.Errorf("Unexpected walk of %q (result not found)", dir)
|
|
return errors.New("result not found")
|
|
}
|
|
delete(ls.walkResults, dir)
|
|
|
|
// Check arguments are as expected
|
|
assert.Equal(ls.t, result.entries, entries)
|
|
assert.Equal(ls.t, result.err, err)
|
|
|
|
// Fetch return value
|
|
returnErr, ok := ls.walkErrors[dir]
|
|
if !ok {
|
|
ls.t.Errorf("Unexpected walk of %q (error not found)", dir)
|
|
return errors.New("error not found")
|
|
}
|
|
delete(ls.walkErrors, dir)
|
|
|
|
return returnErr
|
|
}
|
|
|
|
// Walk does the walk and tests the expectations
|
|
func (ls *listDirs) Walk() {
|
|
err := walk(nil, "", ls.includeAll, ls.maxLevel, ls.WalkFn, ls.ListDir)
|
|
assert.Equal(ls.t, ls.finalError, err)
|
|
ls.IsFinished()
|
|
}
|
|
|
|
func newDir(name string) *Dir {
|
|
return &Dir{Name: name}
|
|
}
|
|
|
|
func TestWalkEmpty(t *testing.T) {
|
|
newListDirs(t, nil, false,
|
|
listResults{
|
|
"": {entries: DirEntries{}, err: nil},
|
|
},
|
|
errorMap{
|
|
"": nil,
|
|
},
|
|
nil,
|
|
).Walk()
|
|
}
|
|
|
|
func TestWalkEmptySkip(t *testing.T) {
|
|
newListDirs(t, nil, true,
|
|
listResults{
|
|
"": {entries: DirEntries{}, err: nil},
|
|
},
|
|
errorMap{
|
|
"": ErrorSkipDir,
|
|
},
|
|
nil,
|
|
).Walk()
|
|
}
|
|
|
|
func TestWalkNotFound(t *testing.T) {
|
|
newListDirs(t, nil, true,
|
|
listResults{
|
|
"": {err: ErrorDirNotFound},
|
|
},
|
|
errorMap{
|
|
"": ErrorDirNotFound,
|
|
},
|
|
ErrorDirNotFound,
|
|
).Walk()
|
|
}
|
|
|
|
func TestWalkNotFoundMaskError(t *testing.T) {
|
|
newListDirs(t, nil, true,
|
|
listResults{
|
|
"": {err: ErrorDirNotFound},
|
|
},
|
|
errorMap{
|
|
"": nil,
|
|
},
|
|
nil,
|
|
).Walk()
|
|
}
|
|
|
|
func TestWalkNotFoundSkipkError(t *testing.T) {
|
|
newListDirs(t, nil, true,
|
|
listResults{
|
|
"": {err: ErrorDirNotFound},
|
|
},
|
|
errorMap{
|
|
"": ErrorSkipDir,
|
|
},
|
|
nil,
|
|
).Walk()
|
|
}
|
|
|
|
func testWalkLevels(t *testing.T, maxLevel int) {
|
|
da := newDir("a")
|
|
db := newDir("a/b")
|
|
dc := newDir("a/b/c")
|
|
dd := newDir("a/b/c/d")
|
|
newListDirs(t, nil, false,
|
|
listResults{
|
|
"": {entries: DirEntries{da}, err: nil},
|
|
"a": {entries: DirEntries{db}, err: nil},
|
|
"a/b": {entries: DirEntries{dc}, err: nil},
|
|
"a/b/c": {entries: DirEntries{dd}, err: nil},
|
|
"a/b/c/d": {entries: DirEntries{}, err: nil},
|
|
},
|
|
errorMap{
|
|
"": nil,
|
|
"a": nil,
|
|
"a/b": nil,
|
|
"a/b/c": nil,
|
|
"a/b/c/d": nil,
|
|
},
|
|
nil,
|
|
).SetLevel(maxLevel).Walk()
|
|
}
|
|
|
|
func TestWalkLevels(t *testing.T) {
|
|
testWalkLevels(t, -1)
|
|
}
|
|
|
|
func TestWalkLevelsNoRecursive10(t *testing.T) {
|
|
testWalkLevels(t, 10)
|
|
}
|
|
|
|
func TestWalkLevelsNoRecursive(t *testing.T) {
|
|
da := newDir("a")
|
|
newListDirs(t, nil, false,
|
|
listResults{
|
|
"": {entries: DirEntries{da}, err: nil},
|
|
},
|
|
errorMap{
|
|
"": nil,
|
|
},
|
|
nil,
|
|
).SetLevel(1).Walk()
|
|
}
|
|
|
|
func TestWalkLevels2(t *testing.T) {
|
|
da := newDir("a")
|
|
db := newDir("a/b")
|
|
newListDirs(t, nil, false,
|
|
listResults{
|
|
"": {entries: DirEntries{da}, err: nil},
|
|
"a": {entries: DirEntries{db}, err: nil},
|
|
},
|
|
errorMap{
|
|
"": nil,
|
|
"a": nil,
|
|
},
|
|
nil,
|
|
).SetLevel(2).Walk()
|
|
}
|
|
|
|
func TestWalkSkip(t *testing.T) {
|
|
da := newDir("a")
|
|
db := newDir("a/b")
|
|
dc := newDir("a/b/c")
|
|
newListDirs(t, nil, false,
|
|
listResults{
|
|
"": {entries: DirEntries{da}, err: nil},
|
|
"a": {entries: DirEntries{db}, err: nil},
|
|
"a/b": {entries: DirEntries{dc}, err: nil},
|
|
},
|
|
errorMap{
|
|
"": nil,
|
|
"a": nil,
|
|
"a/b": ErrorSkipDir,
|
|
},
|
|
nil,
|
|
).Walk()
|
|
}
|
|
|
|
func TestWalkErrors(t *testing.T) {
|
|
lr := listResults{}
|
|
em := errorMap{}
|
|
de := make(DirEntries, 10)
|
|
for i := range de {
|
|
path := string('0' + i)
|
|
de[i] = newDir(path)
|
|
lr[path] = listResult{entries: nil, err: ErrorDirNotFound}
|
|
em[path] = ErrorDirNotFound
|
|
}
|
|
lr[""] = listResult{entries: de, err: nil}
|
|
em[""] = nil
|
|
newListDirs(t, nil, true,
|
|
lr,
|
|
em,
|
|
ErrorDirNotFound,
|
|
).NoCheckMaps().Walk()
|
|
}
|
|
|
|
var errorBoom = errors.New("boom")
|
|
|
|
func makeTree(level int, terminalErrors bool) (listResults, errorMap) {
|
|
lr := listResults{}
|
|
em := errorMap{}
|
|
var fill func(path string, level int)
|
|
fill = func(path string, level int) {
|
|
de := DirEntries{}
|
|
if level > 0 {
|
|
for _, a := range "0123456789" {
|
|
subPath := string(a)
|
|
if path != "" {
|
|
subPath = path + "/" + subPath
|
|
}
|
|
de = append(de, newDir(subPath))
|
|
fill(subPath, level-1)
|
|
}
|
|
}
|
|
lr[path] = listResult{entries: de, err: nil}
|
|
em[path] = nil
|
|
if level == 0 && terminalErrors {
|
|
em[path] = errorBoom
|
|
}
|
|
}
|
|
fill("", level)
|
|
return lr, em
|
|
}
|
|
|
|
func TestWalkMulti(t *testing.T) {
|
|
lr, em := makeTree(3, false)
|
|
newListDirs(t, nil, true,
|
|
lr,
|
|
em,
|
|
nil,
|
|
).Walk()
|
|
}
|
|
|
|
func TestWalkMultiErrors(t *testing.T) {
|
|
lr, em := makeTree(3, true)
|
|
newListDirs(t, nil, true,
|
|
lr,
|
|
em,
|
|
errorBoom,
|
|
).NoCheckMaps().Walk()
|
|
}
|