Skip to content Search Apps Documentation Source Content File Folder Download Copy Actions State String Boolean Number Struct Map Slice Pointer Function Closure Reference Nil Package Type Interface Unknown

Community realm. Read the code first. Community realm, deployed by its author. Read the code before you interact or send coins.

memfs_test.gno

7.39 Kb · 279 lines
  1package memfs
  2
  3import (
  4	"testing"
  5
  6	ninep "gno.land/p/nym-moultest123/x/plan9/ninep/v0"
  7)
  8
  9func TestRootStat(t *testing.T) {
 10	fs := New("glenda", 100)
 11	s := fs.Root().Stat()
 12	if s.Name != "/" {
 13		t.Errorf("root name: got %q", s.Name)
 14	}
 15	if !s.IsDir() {
 16		t.Error("root should be a directory")
 17	}
 18	if s.Length != 0 {
 19		t.Errorf("a directory reports length 0 in 9P, got %d", s.Length)
 20	}
 21	if s.Uid != "glenda" || s.Gid != "glenda" {
 22		t.Errorf("owner: got %q/%q", s.Uid, s.Gid)
 23	}
 24	if s.Mtime != 100 {
 25		t.Errorf("mtime: got %d, want 100", s.Mtime)
 26	}
 27}
 28
 29func TestCreateWalkRead(t *testing.T) {
 30	fs := New("glenda", 1)
 31	root := fs.RootMutable()
 32
 33	f, err := root.Create("greeting", ninep.FilePerm, 2)
 34	if err != nil {
 35		t.Fatalf("create: %v", err)
 36	}
 37	m := f.(ninep.Mutable)
 38	n, err := m.Write(0, "hello world", 3)
 39	if err != nil {
 40		t.Fatalf("write: %v", err)
 41	}
 42	if n != 11 {
 43		t.Errorf("wrote %d bytes, want 11", n)
 44	}
 45
 46	got, err := root.Walk("greeting")
 47	if err != nil {
 48		t.Fatalf("walk: %v", err)
 49	}
 50	data, err := ninep.ReadAll(got)
 51	if err != nil {
 52		t.Fatalf("read: %v", err)
 53	}
 54	if data != "hello world" {
 55		t.Errorf("read back %q", data)
 56	}
 57	if l := got.Stat().Length; l != 11 {
 58		t.Errorf("length %d, want 11", l)
 59	}
 60}
 61
 62func TestWalkErrors(t *testing.T) {
 63	fs := New("glenda", 1)
 64	root := fs.RootMutable()
 65	root.Create("file", ninep.FilePerm, 1)
 66
 67	if _, err := root.Walk("absent"); err != ninep.ErrNotExist {
 68		t.Errorf("missing name: got %v, want ErrNotExist", err)
 69	}
 70	if _, err := root.Walk("a/b"); err != ninep.ErrBadName {
 71		t.Errorf("slash in name: got %v, want ErrBadName", err)
 72	}
 73	f, _ := root.Walk("file")
 74	if _, err := f.Walk("x"); err != ninep.ErrNotDir {
 75		t.Errorf("walk through a file: got %v, want ErrNotDir", err)
 76	}
 77	if _, err := f.ReadDir(); err != ninep.ErrNotDir {
 78		t.Errorf("readdir of a file: got %v, want ErrNotDir", err)
 79	}
 80	if _, err := root.Read(0, -1); err != ninep.ErrIsDir {
 81		t.Errorf("read of a directory: got %v, want ErrIsDir", err)
 82	}
 83}
 84
 85func TestReadDirIsOrdered(t *testing.T) {
 86	fs := New("glenda", 1)
 87	root := fs.RootMutable()
 88	for _, name := range []string{"zulu", "alpha", "mike", "bravo"} {
 89		if _, err := root.Create(name, ninep.FilePerm, 1); err != nil {
 90			t.Fatalf("create %s: %v", name, err)
 91		}
 92	}
 93	ents, err := root.ReadDir()
 94	if err != nil {
 95		t.Fatalf("readdir: %v", err)
 96	}
 97	want := []string{"alpha", "bravo", "mike", "zulu"}
 98	if len(ents) != len(want) {
 99		t.Fatalf("got %d entries, want %d", len(ents), len(want))
100	}
101	for i, w := range want {
102		if ents[i].Name != w {
103			t.Errorf("entry %d: got %q, want %q", i, ents[i].Name, w)
104		}
105	}
106}
107
108func TestCreateDuplicate(t *testing.T) {
109	fs := New("glenda", 1)
110	root := fs.RootMutable()
111	root.Create("x", ninep.FilePerm, 1)
112	if _, err := root.Create("x", ninep.FilePerm, 1); err != ninep.ErrExist {
113		t.Errorf("got %v, want ErrExist", err)
114	}
115	if _, err := root.Create("", ninep.FilePerm, 1); err != ninep.ErrBadName {
116		t.Errorf("empty name: got %v, want ErrBadName", err)
117	}
118	if _, err := root.Create("..", ninep.FilePerm, 1); err != ninep.ErrBadName {
119		t.Errorf("dotdot: got %v, want ErrBadName", err)
120	}
121}
122
123func TestRemove(t *testing.T) {
124	fs := New("glenda", 1)
125	root := fs.RootMutable()
126	root.Create("file", ninep.FilePerm, 1)
127	d, _ := root.Create("dir", ninep.DirPerm, 1)
128	d.(ninep.Mutable).Create("inner", ninep.FilePerm, 1)
129
130	if err := root.Remove("absent"); err != ninep.ErrNotExist {
131		t.Errorf("remove missing: got %v", err)
132	}
133	if err := root.Remove("dir"); err != ninep.ErrNotEmpty {
134		t.Errorf("remove non-empty dir: got %v, want ErrNotEmpty", err)
135	}
136	if err := d.(ninep.Mutable).Remove("inner"); err != nil {
137		t.Fatalf("remove inner: %v", err)
138	}
139	if err := root.Remove("dir"); err != nil {
140		t.Fatalf("remove emptied dir: %v", err)
141	}
142	if err := root.Remove("file"); err != nil {
143		t.Fatalf("remove file: %v", err)
144	}
145	ents, _ := root.ReadDir()
146	if len(ents) != 0 {
147		t.Errorf("root should be empty, has %d entries", len(ents))
148	}
149}
150
151func TestWriteOffsets(t *testing.T) {
152	tests := []struct {
153		name  string
154		start string
155		off   int64
156		data  string
157		want  string
158	}{
159		{"append at end", "abc", 3, "def", "abcdef"},
160		{"overwrite middle", "abcdef", 2, "XY", "abXYef"},
161		{"overwrite past end", "abc", 2, "XYZ", "abXYZ"},
162		{"from zero", "abcdef", 0, "ZZ", "ZZcdef"},
163		{"gap is nul filled", "ab", 4, "Z", "ab\x00\x00Z"},
164		{"negative offset clamps", "abc", -2, "Z", "Zbc"},
165	}
166	for _, tt := range tests {
167		fs := New("glenda", 1)
168		root := fs.RootMutable()
169		f, _ := root.Create("f", ninep.FilePerm, 1)
170		m := f.(ninep.Mutable)
171		m.Write(0, tt.start, 1)
172		m.Write(tt.off, tt.data, 2)
173		got, _ := ninep.ReadAll(f)
174		if got != tt.want {
175			t.Errorf("%s: got %q, want %q", tt.name, got, tt.want)
176		}
177	}
178}
179
180func TestAppendOnlyIgnoresOffset(t *testing.T) {
181	fs := New("glenda", 1)
182	root := fs.RootMutable()
183	f, _ := root.Create("log", ninep.DMAPPEND|0644, 1)
184	m := f.(ninep.Mutable)
185	m.Write(0, "one\n", 1)
186	m.Write(0, "two\n", 2) // offset 0, but append-only pins it to the end
187	got, _ := ninep.ReadAll(f)
188	if got != "one\ntwo\n" {
189		t.Errorf("got %q", got)
190	}
191}
192
193func TestTruncate(t *testing.T) {
194	fs := New("glenda", 1)
195	root := fs.RootMutable()
196	f, _ := root.Create("f", ninep.FilePerm, 1)
197	m := f.(ninep.Mutable)
198	m.Write(0, "abcdef", 1)
199
200	m.Truncate(3, 2)
201	if got, _ := ninep.ReadAll(f); got != "abc" {
202		t.Errorf("shrink: got %q", got)
203	}
204	m.Truncate(5, 3)
205	if got, _ := ninep.ReadAll(f); got != "abc\x00\x00" {
206		t.Errorf("grow: got %q", got)
207	}
208	m.Truncate(0, 4)
209	if got, _ := ninep.ReadAll(f); got != "" {
210		t.Errorf("zero: got %q", got)
211	}
212}
213
214func TestQidVersionAndPath(t *testing.T) {
215	fs := New("glenda", 1)
216	root := fs.RootMutable()
217	a, _ := root.Create("a", ninep.FilePerm, 1)
218	b, _ := root.Create("b", ninep.FilePerm, 1)
219
220	if a.Stat().Qid.Path == b.Stat().Qid.Path {
221		t.Error("two files share a qid path")
222	}
223	v0 := a.Stat().Qid.Version
224	a.(ninep.Mutable).Write(0, "x", 2)
225	if a.Stat().Qid.Version != v0+1 {
226		t.Errorf("version did not advance on write: %d -> %d", v0, a.Stat().Qid.Version)
227	}
228	if a.Stat().Mtime != 2 {
229		t.Errorf("mtime: got %d, want 2", a.Stat().Mtime)
230	}
231}
232
233func TestMkdirAllAndWriteFile(t *testing.T) {
234	fs := New("glenda", 1)
235	if _, err := fs.MkdirAll("/usr/glenda/lib", 1); err != nil {
236		t.Fatalf("mkdirall: %v", err)
237	}
238	// idempotent
239	if _, err := fs.MkdirAll("/usr/glenda", 1); err != nil {
240		t.Fatalf("mkdirall again: %v", err)
241	}
242	if err := fs.WriteFile("/usr/glenda/lib/profile", "font=pelm\n", 2); err != nil {
243		t.Fatalf("writefile: %v", err)
244	}
245	f, err := ninep.Walk(fs.Root(), ninep.Elems("/usr/glenda/lib/profile"))
246	if err != nil {
247		t.Fatalf("walk: %v", err)
248	}
249	if got, _ := ninep.ReadAll(f); got != "font=pelm\n" {
250		t.Errorf("got %q", got)
251	}
252	// rewriting replaces rather than appends
253	if err := fs.WriteFile("/usr/glenda/lib/profile", "font=lucida\n", 3); err != nil {
254		t.Fatalf("rewrite: %v", err)
255	}
256	f, _ = ninep.Walk(fs.Root(), ninep.Elems("/usr/glenda/lib/profile"))
257	if got, _ := ninep.ReadAll(f); got != "font=lucida\n" {
258		t.Errorf("rewrite got %q", got)
259	}
260}
261
262func TestMkdirAllThroughAFileFails(t *testing.T) {
263	fs := New("glenda", 1)
264	fs.WriteFile("/etc", "not a directory", 1)
265	if _, err := fs.MkdirAll("/etc/passwd", 2); err != ninep.ErrNotDir {
266		t.Errorf("got %v, want ErrNotDir", err)
267	}
268}
269
270func TestWalkDepthLimit(t *testing.T) {
271	fs := New("glenda", 1)
272	elems := []string{}
273	for i := 0; i <= ninep.MaxDepth; i++ {
274		elems = append(elems, "x")
275	}
276	if _, err := ninep.Walk(fs.Root(), elems); err != ninep.ErrTooDeep {
277		t.Errorf("got %v, want ErrTooDeep", err)
278	}
279}