forked from TrueCloudLab/restic
ff7ef5007e
The ioutil functions are deprecated since Go 1.17 and only wrap another library function. Thus directly call the underlying function. This commit only mechanically replaces the function calls.
445 lines
8.4 KiB
Go
445 lines
8.4 KiB
Go
package fs
|
|
|
|
import (
|
|
"bytes"
|
|
"io"
|
|
"os"
|
|
"path"
|
|
"sort"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/google/go-cmp/cmp"
|
|
"github.com/restic/restic/internal/test"
|
|
)
|
|
|
|
func verifyFileContentOpen(t testing.TB, fs FS, filename string, want []byte) {
|
|
f, err := fs.Open(filename)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
buf, err := io.ReadAll(f)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
err = f.Close()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if !cmp.Equal(want, buf) {
|
|
t.Error(cmp.Diff(want, buf))
|
|
}
|
|
}
|
|
|
|
func verifyFileContentOpenFile(t testing.TB, fs FS, filename string, want []byte) {
|
|
f, err := fs.OpenFile(filename, O_RDONLY, 0)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
buf, err := io.ReadAll(f)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
err = f.Close()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if !cmp.Equal(want, buf) {
|
|
t.Error(cmp.Diff(want, buf))
|
|
}
|
|
}
|
|
|
|
func verifyDirectoryContents(t testing.TB, fs FS, dir string, want []string) {
|
|
f, err := fs.Open(dir)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
entries, err := f.Readdirnames(-1)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
err = f.Close()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
sort.Strings(want)
|
|
sort.Strings(entries)
|
|
|
|
if !cmp.Equal(want, entries) {
|
|
t.Error(cmp.Diff(want, entries))
|
|
}
|
|
}
|
|
|
|
type fiSlice []os.FileInfo
|
|
|
|
func (s fiSlice) Len() int {
|
|
return len(s)
|
|
}
|
|
|
|
func (s fiSlice) Less(i, j int) bool {
|
|
return s[i].Name() < s[j].Name()
|
|
}
|
|
|
|
func (s fiSlice) Swap(i, j int) {
|
|
s[i], s[j] = s[j], s[i]
|
|
}
|
|
|
|
func verifyDirectoryContentsFI(t testing.TB, fs FS, dir string, want []os.FileInfo) {
|
|
f, err := fs.Open(dir)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
entries, err := f.Readdir(-1)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
err = f.Close()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
sort.Sort(fiSlice(want))
|
|
sort.Sort(fiSlice(entries))
|
|
|
|
if len(want) != len(entries) {
|
|
t.Errorf("wrong number of entries returned, want %d, got %d", len(want), len(entries))
|
|
}
|
|
max := len(want)
|
|
if len(entries) < max {
|
|
max = len(entries)
|
|
}
|
|
|
|
for i := 0; i < max; i++ {
|
|
fi1 := want[i]
|
|
fi2 := entries[i]
|
|
|
|
if fi1.Name() != fi2.Name() {
|
|
t.Errorf("entry %d: wrong value for Name: want %q, got %q", i, fi1.Name(), fi2.Name())
|
|
}
|
|
|
|
if fi1.IsDir() != fi2.IsDir() {
|
|
t.Errorf("entry %d: wrong value for IsDir: want %v, got %v", i, fi1.IsDir(), fi2.IsDir())
|
|
}
|
|
|
|
if fi1.Mode() != fi2.Mode() {
|
|
t.Errorf("entry %d: wrong value for Mode: want %v, got %v", i, fi1.Mode(), fi2.Mode())
|
|
}
|
|
|
|
if fi1.ModTime() != fi2.ModTime() {
|
|
t.Errorf("entry %d: wrong value for ModTime: want %v, got %v", i, fi1.ModTime(), fi2.ModTime())
|
|
}
|
|
|
|
if fi1.Size() != fi2.Size() {
|
|
t.Errorf("entry %d: wrong value for Size: want %v, got %v", i, fi1.Size(), fi2.Size())
|
|
}
|
|
|
|
if fi1.Sys() != fi2.Sys() {
|
|
t.Errorf("entry %d: wrong value for Sys: want %v, got %v", i, fi1.Sys(), fi2.Sys())
|
|
}
|
|
}
|
|
}
|
|
|
|
func checkFileInfo(t testing.TB, fi os.FileInfo, filename string, modtime time.Time, mode os.FileMode, isdir bool) {
|
|
if fi.IsDir() != isdir {
|
|
t.Errorf("IsDir returned %t, want %t", fi.IsDir(), isdir)
|
|
}
|
|
|
|
if fi.Mode() != mode {
|
|
t.Errorf("Mode() returned wrong value, want 0%o, got 0%o", mode, fi.Mode())
|
|
}
|
|
|
|
if !modtime.Equal(time.Time{}) && !fi.ModTime().Equal(modtime) {
|
|
t.Errorf("ModTime() returned wrong value, want %v, got %v", modtime, fi.ModTime())
|
|
}
|
|
|
|
if path.Base(fi.Name()) != fi.Name() {
|
|
t.Errorf("Name() returned is not base, want %q, got %q", path.Base(fi.Name()), fi.Name())
|
|
}
|
|
|
|
if fi.Name() != path.Base(filename) {
|
|
t.Errorf("Name() returned wrong value, want %q, got %q", path.Base(filename), fi.Name())
|
|
}
|
|
}
|
|
|
|
func TestFSReader(t *testing.T) {
|
|
data := test.Random(55, 1<<18+588)
|
|
now := time.Now()
|
|
filename := "foobar"
|
|
|
|
var tests = []struct {
|
|
name string
|
|
f func(t *testing.T, fs FS)
|
|
}{
|
|
{
|
|
name: "Readdirnames-slash",
|
|
f: func(t *testing.T, fs FS) {
|
|
verifyDirectoryContents(t, fs, "/", []string{filename})
|
|
},
|
|
},
|
|
{
|
|
name: "Readdirnames-current",
|
|
f: func(t *testing.T, fs FS) {
|
|
verifyDirectoryContents(t, fs, ".", []string{filename})
|
|
},
|
|
},
|
|
{
|
|
name: "Readdir-slash",
|
|
f: func(t *testing.T, fs FS) {
|
|
fi := fakeFileInfo{
|
|
mode: 0644,
|
|
modtime: now,
|
|
name: filename,
|
|
size: int64(len(data)),
|
|
}
|
|
verifyDirectoryContentsFI(t, fs, "/", []os.FileInfo{fi})
|
|
},
|
|
},
|
|
{
|
|
name: "Readdir-current",
|
|
f: func(t *testing.T, fs FS) {
|
|
fi := fakeFileInfo{
|
|
mode: 0644,
|
|
modtime: now,
|
|
name: filename,
|
|
size: int64(len(data)),
|
|
}
|
|
verifyDirectoryContentsFI(t, fs, ".", []os.FileInfo{fi})
|
|
},
|
|
},
|
|
{
|
|
name: "file/Open",
|
|
f: func(t *testing.T, fs FS) {
|
|
verifyFileContentOpen(t, fs, filename, data)
|
|
},
|
|
},
|
|
{
|
|
name: "file/OpenFile",
|
|
f: func(t *testing.T, fs FS) {
|
|
verifyFileContentOpenFile(t, fs, filename, data)
|
|
},
|
|
},
|
|
{
|
|
name: "file/Lstat",
|
|
f: func(t *testing.T, fs FS) {
|
|
fi, err := fs.Lstat(filename)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
checkFileInfo(t, fi, filename, now, 0644, false)
|
|
},
|
|
},
|
|
{
|
|
name: "file/Stat",
|
|
f: func(t *testing.T, fs FS) {
|
|
f, err := fs.Open(filename)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
fi, err := f.Stat()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
err = f.Close()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
checkFileInfo(t, fi, filename, now, 0644, false)
|
|
},
|
|
},
|
|
{
|
|
name: "dir/Lstat-slash",
|
|
f: func(t *testing.T, fs FS) {
|
|
fi, err := fs.Lstat("/")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
checkFileInfo(t, fi, "/", time.Time{}, os.ModeDir|0755, true)
|
|
},
|
|
},
|
|
{
|
|
name: "dir/Lstat-current",
|
|
f: func(t *testing.T, fs FS) {
|
|
fi, err := fs.Lstat(".")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
checkFileInfo(t, fi, ".", time.Time{}, os.ModeDir|0755, true)
|
|
},
|
|
},
|
|
{
|
|
name: "dir/Lstat-error-not-exist",
|
|
f: func(t *testing.T, fs FS) {
|
|
_, err := fs.Lstat("other")
|
|
if err != os.ErrNotExist {
|
|
t.Fatal(err)
|
|
}
|
|
},
|
|
},
|
|
{
|
|
name: "dir/Open-slash",
|
|
f: func(t *testing.T, fs FS) {
|
|
fi, err := fs.Lstat("/")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
checkFileInfo(t, fi, "/", time.Time{}, os.ModeDir|0755, true)
|
|
},
|
|
},
|
|
{
|
|
name: "dir/Open-current",
|
|
f: func(t *testing.T, fs FS) {
|
|
fi, err := fs.Lstat(".")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
checkFileInfo(t, fi, ".", time.Time{}, os.ModeDir|0755, true)
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
fs := &Reader{
|
|
Name: filename,
|
|
ReadCloser: io.NopCloser(bytes.NewReader(data)),
|
|
|
|
Mode: 0644,
|
|
Size: int64(len(data)),
|
|
ModTime: now,
|
|
}
|
|
|
|
t.Run(test.name, func(t *testing.T) {
|
|
test.f(t, fs)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestFSReaderDir(t *testing.T) {
|
|
data := test.Random(55, 1<<18+588)
|
|
now := time.Now()
|
|
|
|
var tests = []struct {
|
|
name string
|
|
filename string
|
|
}{
|
|
{
|
|
name: "Lstat-absolute",
|
|
filename: "/path/to/foobar",
|
|
},
|
|
{
|
|
name: "Lstat-relative",
|
|
filename: "path/to/foobar",
|
|
},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
t.Run(test.name, func(t *testing.T) {
|
|
fs := &Reader{
|
|
Name: test.filename,
|
|
ReadCloser: io.NopCloser(bytes.NewReader(data)),
|
|
|
|
Mode: 0644,
|
|
Size: int64(len(data)),
|
|
ModTime: now,
|
|
}
|
|
|
|
dir := path.Dir(fs.Name)
|
|
for {
|
|
if dir == "/" || dir == "." {
|
|
break
|
|
}
|
|
|
|
fi, err := fs.Lstat(dir)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
checkFileInfo(t, fi, dir, time.Time{}, os.ModeDir|0755, true)
|
|
|
|
dir = path.Dir(dir)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestFSReaderMinFileSize(t *testing.T) {
|
|
var tests = []struct {
|
|
name string
|
|
data string
|
|
allowEmpty bool
|
|
readMustErr bool
|
|
}{
|
|
{
|
|
name: "regular",
|
|
data: "foobar",
|
|
},
|
|
{
|
|
name: "empty",
|
|
data: "",
|
|
allowEmpty: false,
|
|
readMustErr: true,
|
|
},
|
|
{
|
|
name: "empty2",
|
|
data: "",
|
|
allowEmpty: true,
|
|
readMustErr: false,
|
|
},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
t.Run(test.name, func(t *testing.T) {
|
|
fs := &Reader{
|
|
Name: "testfile",
|
|
ReadCloser: io.NopCloser(strings.NewReader(test.data)),
|
|
Mode: 0644,
|
|
ModTime: time.Now(),
|
|
AllowEmptyFile: test.allowEmpty,
|
|
}
|
|
|
|
f, err := fs.Open("testfile")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
buf, err := io.ReadAll(f)
|
|
if test.readMustErr {
|
|
if err == nil {
|
|
t.Fatal("expected error not found, got nil")
|
|
}
|
|
} else {
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
if string(buf) != test.data {
|
|
t.Fatalf("wrong data returned, want %q, got %q", test.data, string(buf))
|
|
}
|
|
|
|
err = f.Close()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
})
|
|
}
|
|
}
|