147 lines
3.4 KiB
Go
147 lines
3.4 KiB
Go
package fs
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"sort"
|
|
"testing"
|
|
)
|
|
|
|
func TestLocalFSWriteReadListStat(t *testing.T) {
|
|
root := t.TempDir()
|
|
fsys := NewLocal(root)
|
|
|
|
content := []byte("package main\n")
|
|
if err := fsys.Write("dir/main.go", content); err != nil {
|
|
t.Fatalf("Write: %v", err)
|
|
}
|
|
|
|
got, err := fsys.Read("dir/main.go")
|
|
if err != nil {
|
|
t.Fatalf("Read: %v", err)
|
|
}
|
|
if string(got) != string(content) {
|
|
t.Errorf("Read = %q, want %q", got, content)
|
|
}
|
|
|
|
entries, err := fsys.List("dir")
|
|
if err != nil {
|
|
t.Fatalf("List: %v", err)
|
|
}
|
|
if len(entries) != 1 {
|
|
t.Fatalf("List returned %d entries, want 1", len(entries))
|
|
}
|
|
if entries[0].Name != "main.go" {
|
|
t.Errorf("entry name = %q, want main.go", entries[0].Name)
|
|
}
|
|
if entries[0].Path != "dir/main.go" {
|
|
t.Errorf("entry path = %q, want dir/main.go", entries[0].Path)
|
|
}
|
|
if entries[0].IsDir {
|
|
t.Error("expected IsDir=false")
|
|
}
|
|
|
|
info, err := fsys.Stat("dir/main.go")
|
|
if err != nil {
|
|
t.Fatalf("Stat: %v", err)
|
|
}
|
|
if info.Size != int64(len(content)) {
|
|
t.Errorf("Stat size = %d, want %d", info.Size, len(content))
|
|
}
|
|
}
|
|
|
|
func TestLocalFSRejectsPathEscape(t *testing.T) {
|
|
root := t.TempDir()
|
|
fsys := NewLocal(root)
|
|
|
|
// Create an outside file to verify writes don't reach it.
|
|
outside := filepath.Join(root, "..", "outside_escape_test")
|
|
defer os.Remove(outside)
|
|
|
|
ops := []struct {
|
|
name string
|
|
fn func() error
|
|
}{
|
|
{"Read", func() error { _, err := fsys.Read("../outside_escape_test"); return err }},
|
|
{"Write", func() error { return fsys.Write("../outside_escape_test", []byte("x")) }},
|
|
{"Mkdir", func() error { return fsys.Mkdir("../outside_escape_dir") }},
|
|
{"Remove", func() error { return fsys.Remove("../outside_escape_test") }},
|
|
{"Rename", func() error { return fsys.Rename("file", "../outside_escape_test") }},
|
|
}
|
|
|
|
for _, op := range ops {
|
|
if err := op.fn(); err == nil {
|
|
t.Errorf("%s with ../ path should fail", op.name)
|
|
}
|
|
}
|
|
|
|
if _, err := os.Stat(outside); err == nil {
|
|
t.Error("outside file should not have been created")
|
|
}
|
|
}
|
|
|
|
func TestLocalFSRenameAndRemove(t *testing.T) {
|
|
root := t.TempDir()
|
|
fsys := NewLocal(root)
|
|
|
|
if err := fsys.Write("old.txt", []byte("hello")); err != nil {
|
|
t.Fatalf("Write: %v", err)
|
|
}
|
|
|
|
if err := fsys.Rename("old.txt", "new.txt"); err != nil {
|
|
t.Fatalf("Rename: %v", err)
|
|
}
|
|
|
|
if _, err := fsys.Stat("old.txt"); err == nil {
|
|
t.Error("old.txt should not exist after rename")
|
|
}
|
|
|
|
data, err := fsys.Read("new.txt")
|
|
if err != nil {
|
|
t.Fatalf("Read new.txt: %v", err)
|
|
}
|
|
if string(data) != "hello" {
|
|
t.Errorf("Read new.txt = %q, want hello", data)
|
|
}
|
|
|
|
if err := fsys.Remove("new.txt"); err != nil {
|
|
t.Fatalf("Remove: %v", err)
|
|
}
|
|
if _, err := fsys.Stat("new.txt"); err == nil {
|
|
t.Error("new.txt should not exist after remove")
|
|
}
|
|
}
|
|
|
|
func TestLocalFSListSorted(t *testing.T) {
|
|
root := t.TempDir()
|
|
fsys := NewLocal(root)
|
|
|
|
for _, name := range []string{"c.txt", "a.txt", "b.txt"} {
|
|
if err := fsys.Write(name, []byte("x")); err != nil {
|
|
t.Fatalf("Write %s: %v", name, err)
|
|
}
|
|
}
|
|
|
|
entries, err := fsys.List(".")
|
|
if err != nil {
|
|
t.Fatalf("List: %v", err)
|
|
}
|
|
|
|
names := make([]string, len(entries))
|
|
for i, e := range entries {
|
|
names[i] = e.Name
|
|
}
|
|
if !sort.StringsAreSorted(names) {
|
|
t.Errorf("List not sorted: %v", names)
|
|
}
|
|
}
|
|
|
|
func TestLocalFSRejectsRemoveRoot(t *testing.T) {
|
|
fsys := NewLocal(t.TempDir())
|
|
for _, path := range []string{"", "."} {
|
|
if err := fsys.Remove(path); err == nil {
|
|
t.Fatalf("Remove(%q) expected error", path)
|
|
}
|
|
}
|
|
}
|