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) } }