Share immutable in-memory filesystems
This commit is contained in:
153
internal/framework/readonlyfs/readonly_fs_test.go
Normal file
153
internal/framework/readonlyfs/readonly_fs_test.go
Normal file
@@ -0,0 +1,153 @@
|
||||
package readonlyfs
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
"io/fs"
|
||||
"testing"
|
||||
"testing/fstest"
|
||||
)
|
||||
|
||||
func TestNewPassesFSTest(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
name string
|
||||
files map[string][]byte
|
||||
paths []string
|
||||
}{
|
||||
{name: "empty", files: map[string][]byte{}, paths: nil},
|
||||
{name: "single file", files: map[string][]byte{"message.txt": []byte("hello")}, paths: []string{"message.txt"}},
|
||||
{name: "nested tree", files: map[string][]byte{"a/one.txt": []byte("one"), "a/b/two.txt": []byte("two")}, paths: []string{"a/one.txt", "a/b/two.txt"}},
|
||||
} {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
fsys, err := New(test.files)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := fstest.TestFS(fsys, test.paths...); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewOwnsConstructionAndReadBytes(t *testing.T) {
|
||||
input := []byte("value")
|
||||
fsys, err := New(map[string][]byte{"value.txt": input})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
input[0] = 'x'
|
||||
first, err := fsys.ReadFile("value.txt")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
first[0] = 'y'
|
||||
second, err := fsys.ReadFile("value.txt")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if string(second) != "value" {
|
||||
t.Fatalf("ReadFile() = %q, want owned bytes", second)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFilesystemStandardBehavior(t *testing.T) {
|
||||
fsys, err := New(map[string][]byte{
|
||||
"z.txt": []byte("z"),
|
||||
"nested/a.md": []byte("abc"),
|
||||
"nested/b.md": []byte("b"),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
entries, err := fsys.ReadDir("nested")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(entries) != 2 || entries[0].Name() != "a.md" || entries[1].Name() != "b.md" {
|
||||
t.Fatalf("ReadDir(nested) = %#v, want sorted entries", entries)
|
||||
}
|
||||
info, err := entries[0].Info()
|
||||
if err != nil || info.Mode().Perm() != 0o444 || info.Size() != 3 {
|
||||
t.Fatalf("file info = %#v, %v", info, err)
|
||||
}
|
||||
root, err := fsys.Open(".")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
rootInfo, err := root.Stat()
|
||||
if err != nil || !rootInfo.IsDir() || rootInfo.Mode() != fs.ModeDir|0o555 {
|
||||
t.Fatalf("root info = %#v, %v", rootInfo, err)
|
||||
}
|
||||
directory := root.(fs.ReadDirFile)
|
||||
first, err := directory.ReadDir(1)
|
||||
if err != nil || len(first) != 1 || first[0].Name() != "nested" {
|
||||
t.Fatalf("first directory page = %#v, %v", first, err)
|
||||
}
|
||||
second, err := directory.ReadDir(1)
|
||||
if err != nil || len(second) != 1 || second[0].Name() != "z.txt" {
|
||||
t.Fatalf("second directory page = %#v, %v", second, err)
|
||||
}
|
||||
if _, err := directory.ReadDir(1); !errors.Is(err, io.EOF) {
|
||||
t.Fatalf("final directory page error = %v, want EOF", err)
|
||||
}
|
||||
secondRoot, err := fsys.Open(".")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
secondDirectory := secondRoot.(fs.ReadDirFile)
|
||||
firstAgain, err := secondDirectory.ReadDir(1)
|
||||
if err != nil || len(firstAgain) != 1 || firstAgain[0].Name() != "nested" {
|
||||
t.Fatalf("independent directory handle page = %#v, %v", firstAgain, err)
|
||||
}
|
||||
|
||||
left, err := fsys.Open("nested/a.md")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
right, err := fsys.Open("nested/a.md")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
leftByte := make([]byte, 1)
|
||||
rightByte := make([]byte, 1)
|
||||
if _, err := left.Read(leftByte); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := right.Read(rightByte); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if string(leftByte) != "a" || string(rightByte) != "a" {
|
||||
t.Fatalf("independent file handles read %q and %q", leftByte, rightByte)
|
||||
}
|
||||
for _, test := range []struct {
|
||||
name string
|
||||
op func() error
|
||||
want error
|
||||
}{
|
||||
{name: "invalid open path", op: func() error { _, err := fsys.Open("../value"); return err }, want: fs.ErrInvalid},
|
||||
{name: "missing file", op: func() error { _, err := fsys.Open("missing"); return err }, want: fs.ErrNotExist},
|
||||
{name: "read directory", op: func() error { _, err := fsys.ReadFile("nested"); return err }, want: errIsDirectory},
|
||||
{name: "read directory from file", op: func() error { _, err := fsys.ReadDir("z.txt"); return err }, want: errNotDirectory},
|
||||
} {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
if err := test.op(); !errors.Is(err, test.want) {
|
||||
t.Fatalf("operation error = %v, want %v", err, test.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewRejectsInvalidAndConflictingPaths(t *testing.T) {
|
||||
for _, files := range []map[string][]byte{
|
||||
{".": []byte("root")},
|
||||
{"": []byte("empty")},
|
||||
{"../outside": []byte("outside")},
|
||||
{"nested//file": []byte("invalid")},
|
||||
{"file": []byte("file"), "file/nested": []byte("nested")},
|
||||
} {
|
||||
if _, err := New(files); err == nil {
|
||||
t.Fatalf("New(%#v) error = nil, want rejection", files)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user