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.

synfs_test.gno

4.34 Kb · 174 lines
  1package synfs
  2
  3import (
  4	"strconv"
  5	"strings"
  6	"testing"
  7
  8	ninep "gno.land/p/nym-moultest123/x/plan9/ninep/v0"
  9)
 10
 11func fixedClock(h int64) func() int64 { return func() int64 { return h } }
 12
 13func TestTreeShape(t *testing.T) {
 14	tr := New("dev", "sys", fixedClock(42))
 15	tr.Root().
 16		Add("sysname", func() string { return "gnoland-1" }).
 17		Add("height", func() string { return "42" })
 18
 19	st := tr.Root().Stat()
 20	if st.Name != "dev" {
 21		t.Errorf("root name %q", st.Name)
 22	}
 23	if !st.IsDir() {
 24		t.Error("root should be a directory")
 25	}
 26	if st.Mtime != 42 {
 27		t.Errorf("mtime %d, want 42", st.Mtime)
 28	}
 29	if st.Mode.String() != "dr-xr-xr-x" {
 30		t.Errorf("mode %q, want dr-xr-xr-x", st.Mode.String())
 31	}
 32}
 33
 34func TestReadComputed(t *testing.T) {
 35	height := int64(100)
 36	tr := New("dev", "sys", func() int64 { return height })
 37	tr.Root().Add("height", func() string { return strconv.FormatInt(height, 10) })
 38
 39	f, err := tr.Root().Walk("height")
 40	if err != nil {
 41		t.Fatalf("walk: %v", err)
 42	}
 43	got, _ := ninep.ReadAll(f)
 44	if got != "100" {
 45		t.Errorf("got %q", got)
 46	}
 47	// The generator runs on every read, so the file follows the chain.
 48	height = 101
 49	got, _ = ninep.ReadAll(f)
 50	if got != "101" {
 51		t.Errorf("after the block advanced: got %q", got)
 52	}
 53	if v := f.Stat().Qid.Version; v != 0 {
 54		t.Errorf("a synthetic file pins version 0, got %d", v)
 55	}
 56}
 57
 58func TestReadWindow(t *testing.T) {
 59	tr := New("dev", "sys", nil)
 60	tr.Root().Add("msg", func() string { return "hello world" })
 61	f, _ := tr.Root().Walk("msg")
 62
 63	tests := []struct {
 64		off, count int64
 65		want       string
 66	}{
 67		{0, -1, "hello world"},
 68		{0, 5, "hello"},
 69		{6, 5, "world"},
 70		{99, 5, ""},
 71	}
 72	for _, tt := range tests {
 73		got, err := f.Read(tt.off, tt.count)
 74		if err != nil {
 75			t.Fatalf("read: %v", err)
 76		}
 77		if got != tt.want {
 78			t.Errorf("Read(%d,%d): got %q, want %q", tt.off, tt.count, got, tt.want)
 79		}
 80	}
 81}
 82
 83func TestAddRangeEndlessFile(t *testing.T) {
 84	// /dev/zero has no end: it must serve the window rather than a value.
 85	tr := New("dev", "sys", nil)
 86	tr.Root().AddRange("zero", 0444, func(off, count int64) (string, error) {
 87		if count < 0 {
 88			count = 0
 89		}
 90		return strings.Repeat("0", int(count)), nil
 91	})
 92	f, _ := tr.Root().Walk("zero")
 93	got, _ := f.Read(0, 4)
 94	if got != "0000" {
 95		t.Errorf("got %q", got)
 96	}
 97	got, _ = f.Read(0, -1)
 98	if got != "" {
 99		t.Errorf("an unbounded read of an endless file must not hang or grow: got %q", got)
100	}
101}
102
103func TestReadDirIsOrdered(t *testing.T) {
104	tr := New("dev", "sys", fixedClock(1))
105	tr.Root().
106		Add("zero", func() string { return "" }).
107		Add("null", func() string { return "" }).
108		Add("time", func() string { return "" })
109
110	ents, err := tr.Root().ReadDir()
111	if err != nil {
112		t.Fatalf("readdir: %v", err)
113	}
114	want := []string{"null", "time", "zero"}
115	if len(ents) != len(want) {
116		t.Fatalf("got %d entries", len(ents))
117	}
118	for i, w := range want {
119		if ents[i].Name != w {
120			t.Errorf("entry %d: got %q, want %q", i, ents[i].Name, w)
121		}
122	}
123	if got := tr.Root().Names(); len(got) != 3 || got[0] != "null" {
124		t.Errorf("Names: %v", got)
125	}
126}
127
128func TestSubdirectories(t *testing.T) {
129	tr := New("proc", "sys", fixedClock(7))
130	sub := tr.NewDir("1")
131	sub.Add("status", func() string { return "running" })
132	tr.Root().AddDir(sub)
133
134	f, err := ninep.Walk(tr.Root(), ninep.Elems("/1/status"))
135	if err != nil {
136		t.Fatalf("walk: %v", err)
137	}
138	got, _ := ninep.ReadAll(f)
139	if got != "running" {
140		t.Errorf("got %q", got)
141	}
142}
143
144func TestErrors(t *testing.T) {
145	tr := New("dev", "sys", nil)
146	tr.Root().Add("null", func() string { return "" })
147
148	if _, err := tr.Root().Read(0, -1); err != ninep.ErrIsDir {
149		t.Errorf("read a directory: got %v", err)
150	}
151	if _, err := tr.Root().Walk("absent"); err != ninep.ErrNotExist {
152		t.Errorf("walk missing: got %v", err)
153	}
154	if _, err := tr.Root().Walk("a/b"); err != ninep.ErrBadName {
155		t.Errorf("walk bad name: got %v", err)
156	}
157	f, _ := tr.Root().Walk("null")
158	if _, err := f.Walk("x"); err != ninep.ErrNotDir {
159		t.Errorf("walk through a file: got %v", err)
160	}
161	if _, err := f.ReadDir(); err != ninep.ErrNotDir {
162		t.Errorf("readdir a file: got %v", err)
163	}
164}
165
166func TestSyntheticTreeIsReadOnly(t *testing.T) {
167	// The whole point: a synthetic tree implements File and NOT Mutable, so
168	// it is safe to hand to a namespace owned by somebody else.
169	tr := New("dev", "sys", nil)
170	var f ninep.File = tr.Root()
171	if _, ok := f.(ninep.Mutable); ok {
172		t.Error("a synthetic tree must not be Mutable")
173	}
174}