PathrockNetwork Gno Explorer
HomeBlocksTransactionsTokensRealmsPackagesValidatorsAnalytics

PathrockNetwork Gno Explorer — an independent explorer for Gno.land Mainnet (gnoland-1), operated by PathrockNetwork. Not an official Gno.land service.

gnowebarchive RPC

gno.land/p/moul/x/plan9/ns/v0

Package
Open in gnoweb ↗

Overview

Kind
Pure package
Name
v0
Namespace
moul / x / plan9 / ns
Files
4 (README)(gnomod.toml)
Exported functions
n/a — not supported for pure packages by the node (vm/qfuncs)
Module
gno.land/p/moul/x/plan9/ns/v0
gno
0.9

Files (4)

  • README.mdmarkdown
  • gnomod.tomltoml
  • ns.gnogno
  • ns_test.gnogno
ns_test.gnogno
1package ns23import (4	"testing"56	memfs "gno.land/p/moul/x/plan9/memfs/v0"7	ninep "gno.land/p/moul/x/plan9/ninep/v0"8)910// newNs builds a namespace over a fresh ram tree seeded with files.11func newNs(t *testing.T, files ...string) (*Ns, *memfs.FS) {12	t.Helper()13	fs := memfs.New("glenda", 1)14	for _, f := range files {15		if err := fs.WriteFile(f, "contents of "+f+"\n", 1); err != nil {16			t.Fatalf("seed %s: %v", f, err)17		}18	}19	return New(fs.Root()), fs20}2122func names(ents []ninep.Stat) []string {23	out := []string{}24	for _, e := range ents {25		out = append(out, e.Name)26	}27	return out28}2930func eq(a, b []string) bool {31	if len(a) != len(b) {32		return false33	}34	for i := range a {35		if a[i] != b[i] {36			return false37		}38	}39	return true40}4142func TestResolveRoot(t *testing.T) {43	n, _ := newNs(t, "/bin/ls", "/bin/cat")44	st, err := n.Stat("/")45	if err != nil {46		t.Fatalf("stat root: %v", err)47	}48	if !st.IsDir() {49		t.Error("root is not a directory")50	}51	ents, err := n.ReadDir("/", false)52	if err != nil {53		t.Fatalf("readdir: %v", err)54	}55	if !eq(names(ents), []string{"bin"}) {56		t.Errorf("root listing: %v", names(ents))57	}58}5960func TestReadFileAndMissing(t *testing.T) {61	n, _ := newNs(t, "/bin/ls")62	got, err := n.ReadFile("/bin/ls")63	if err != nil {64		t.Fatalf("readfile: %v", err)65	}66	if got != "contents of /bin/ls\n" {67		t.Errorf("got %q", got)68	}69	if _, err := n.ReadFile("/bin/absent"); err != ninep.ErrNotExist {70		t.Errorf("missing: got %v, want ErrNotExist", err)71	}72}7374func TestDotDotIsLexical(t *testing.T) {75	n, _ := newNs(t, "/a/b/c")76	// /a/b/../b/c never asks a server about "..".77	if _, err := n.Stat("/a/b/../b/c"); err != nil {78		t.Fatalf("lexical dotdot: %v", err)79	}80	// Above the root stays at the root.81	if _, err := n.Stat("/../../a"); err != nil {82		t.Fatalf("dotdot above root: %v", err)83	}84}8586func TestBindReplace(t *testing.T) {87	n, _ := newNs(t, "/bin/ls", "/usr/glenda/bin/rc")88	if err := n.Bind("/usr/glenda/bin", "/bin", MREPL); err != nil {89		t.Fatalf("bind: %v", err)90	}91	ents, _ := n.ReadDir("/bin", false)92	if !eq(names(ents), []string{"rc"}) {93		t.Errorf("after MREPL /bin should hold only rc, got %v", names(ents))94	}95	if _, err := n.Stat("/bin/ls"); err != ninep.ErrNotExist {96		t.Errorf("replaced file still reachable: %v", err)97	}98}99100func TestBindAfterUnion(t *testing.T) {101	n, _ := newNs(t, "/bin/ls", "/usr/glenda/bin/rc")102	if err := n.Bind("/usr/glenda/bin", "/bin", MAFTER); err != nil {103		t.Fatalf("bind -a: %v", err)104	}105	ents, _ := n.ReadDir("/bin", false)106	if !eq(names(ents), []string{"ls", "rc"}) {107		t.Errorf("union order: got %v, want [ls rc]", names(ents))108	}109	if _, err := n.Stat("/bin/rc"); err != nil {110		t.Errorf("unioned file not reachable: %v", err)111	}112	if _, err := n.Stat("/bin/ls"); err != nil {113		t.Errorf("original file lost: %v", err)114	}115}116117func TestBindBeforeUnion(t *testing.T) {118	n, _ := newNs(t, "/bin/ls", "/usr/glenda/bin/rc")119	if err := n.Bind("/usr/glenda/bin", "/bin", MBEFORE); err != nil {120		t.Fatalf("bind -b: %v", err)121	}122	ents, _ := n.ReadDir("/bin", false)123	if !eq(names(ents), []string{"rc", "ls"}) {124		t.Errorf("union order: got %v, want [rc ls]", names(ents))125	}126}127128func TestUnionShadowingIsVisible(t *testing.T) {129	// Both directories hold a file called "ls". Plan 9 concatenates, so the130	// listing shows the duplicate and makes the shadowing visible.131	fs := memfs.New("glenda", 1)132	fs.WriteFile("/bin/ls", "system ls\n", 1)133	fs.WriteFile("/usr/glenda/bin/ls", "my ls\n", 1)134	n := New(fs.Root())135136	if err := n.Bind("/usr/glenda/bin", "/bin", MBEFORE); err != nil {137		t.Fatalf("bind: %v", err)138	}139	ents, _ := n.ReadDir("/bin", false)140	if !eq(names(ents), []string{"ls", "ls"}) {141		t.Errorf("concatenation should show both: got %v", names(ents))142	}143	uniq, _ := n.ReadDir("/bin", true)144	if !eq(names(uniq), []string{"ls"}) {145		t.Errorf("unique listing: got %v", names(uniq))146	}147	// A walk reaches the first member, which is the one bound before.148	got, err := n.ReadFile("/bin/ls")149	if err != nil {150		t.Fatalf("read: %v", err)151	}152	if got != "my ls\n" {153		t.Errorf("shadowing: got %q, want my ls", got)154	}155}156157func TestUnionIsTopLevelOnly(t *testing.T) {158	// /a and /b each hold a directory "sub", but only /a/sub/x exists.159	// Unioning /b onto /a does NOT union /a/sub with /b/sub.160	fs := memfs.New("glenda", 1)161	fs.WriteFile("/a/sub/x", "x\n", 1)162	fs.WriteFile("/b/sub/y", "y\n", 1)163	n := New(fs.Root())164	if err := n.Bind("/b", "/a", MAFTER); err != nil {165		t.Fatalf("bind: %v", err)166	}167	if _, err := n.Stat("/a/sub/x"); err != nil {168		t.Errorf("/a/sub/x should still resolve: %v", err)169	}170	if _, err := n.Stat("/a/sub/y"); err != ninep.ErrNotExist {171		t.Errorf("unions are top level only, /a/sub/y must not resolve: %v", err)172	}173}174175func TestBindCapturesAChannelNotAName(t *testing.T) {176	fs := memfs.New("glenda", 1)177	fs.WriteFile("/one/f", "one\n", 1)178	fs.WriteFile("/two/f", "two\n", 1)179	n := New(fs.Root())180181	if err := n.Bind("/one", "/mnt", MREPL); err != nil {182		// /mnt does not exist yet, so this must fail: see the next test.183		fs.MkdirAll("/mnt", 1)184		if err := n.Bind("/one", "/mnt", MREPL); err != nil {185			t.Fatalf("bind: %v", err)186		}187	}188	// Now rebind the SOURCE name elsewhere. The earlier bind captured the189	// directory, so /mnt must not follow.190	if err := n.Bind("/two", "/one", MREPL); err != nil {191		t.Fatalf("rebind source: %v", err)192	}193	got, _ := n.ReadFile("/mnt/f")194	if got != "one\n" {195		t.Errorf("bind should have captured the channel: /mnt/f is %q", got)196	}197	got, _ = n.ReadFile("/one/f")198	if got != "two\n" {199		t.Errorf("/one/f is %q, want two", got)200	}201}202203func TestBindTargetMustExist(t *testing.T) {204	n, _ := newNs(t, "/bin/ls")205	if err := n.Bind("/bin", "/nowhere", MREPL); err != ninep.ErrNotExist {206		t.Errorf("bind onto a missing name: got %v, want ErrNotExist", err)207	}208	if err := n.Bind("/nowhere", "/bin", MREPL); err != ninep.ErrNotExist {209		t.Errorf("bind from a missing name: got %v, want ErrNotExist", err)210	}211}212213func TestCreateTargetNeedsMCREATE(t *testing.T) {214	fs := memfs.New("glenda", 1)215	fs.MkdirAll("/bin", 1)216	fs.MkdirAll("/usr/glenda/bin", 1)217	n := New(fs.Root())218219	// A plain directory takes creates with no flag at all.220	if _, err := n.CreateTarget("/bin"); err != nil {221		t.Fatalf("plain directory should accept a create: %v", err)222	}223224	// Made into a union with no MCREATE anywhere, creation is refused.225	if err := n.Bind("/usr/glenda/bin", "/bin", MAFTER); err != nil {226		t.Fatalf("bind: %v", err)227	}228	if _, err := n.CreateTarget("/bin"); err != ninep.ErrNoCreate {229		t.Errorf("union without MCREATE: got %v, want ErrNoCreate", err)230	}231232	// Rebinding with MCREATE picks that member.233	if err := n.Bind("/usr/glenda/bin", "/bin", MAFTER|MCREATE); err != nil {234		t.Fatalf("bind -ac: %v", err)235	}236	target, err := n.CreateTarget("/bin")237	if err != nil {238		t.Fatalf("union with MCREATE: %v", err)239	}240	if _, err := target.Create("new", ninep.FilePerm, 2); err != nil {241		t.Fatalf("create: %v", err)242	}243	// It landed in the MCREATE member, not in /bin's own directory.244	if _, err := ninep.Walk(fs.Root(), ninep.Elems("/usr/glenda/bin/new")); err != nil {245		t.Errorf("create went to the wrong member: %v", err)246	}247}248249func TestUnmount(t *testing.T) {250	n, _ := newNs(t, "/bin/ls", "/usr/glenda/bin/rc")251	n.Bind("/usr/glenda/bin", "/bin", MAFTER)252	ents, _ := n.ReadDir("/bin", false)253	if len(ents) != 2 {254		t.Fatalf("setup: %v", names(ents))255	}256257	if err := n.Unmount("/usr/glenda/bin", "/bin"); err != nil {258		t.Fatalf("unmount: %v", err)259	}260	ents, _ = n.ReadDir("/bin", false)261	if !eq(names(ents), []string{"ls"}) {262		t.Errorf("after unmount: %v", names(ents))263	}264	if err := n.Unmount("", "/bin"); err != ErrNotBound {265		t.Errorf("unmount of an unbound name: got %v, want ErrNotBound", err)266	}267}268269func TestUnmountAll(t *testing.T) {270	n, _ := newNs(t, "/bin/ls", "/usr/glenda/bin/rc")271	n.Bind("/usr/glenda/bin", "/bin", MAFTER)272	if err := n.Unmount("", "/bin"); err != nil {273		t.Fatalf("unmount all: %v", err)274	}275	ents, _ := n.ReadDir("/bin", false)276	if !eq(names(ents), []string{"ls"}) {277		t.Errorf("name should be restored to its original contents: %v", names(ents))278	}279	if len(n.Ops()) != 0 {280		t.Errorf("ops should be gone: %v", n.Ops())281	}282}283284func TestCd(t *testing.T) {285	n, _ := newNs(t, "/usr/glenda/lib/profile")286	if err := n.Cd("/usr/glenda"); err != nil {287		t.Fatalf("cd: %v", err)288	}289	if n.Cwd() != "/usr/glenda" {290		t.Errorf("cwd: %q", n.Cwd())291	}292	got, err := n.ReadFile("lib/profile")293	if err != nil {294		t.Fatalf("relative read: %v", err)295	}296	if got == "" {297		t.Error("relative read came back empty")298	}299	if err := n.Cd("lib/profile"); err != ninep.ErrNotDir {300		t.Errorf("cd into a file: got %v, want ErrNotDir", err)301	}302	if err := n.Cd("/nowhere"); err != ninep.ErrNotExist {303		t.Errorf("cd nowhere: got %v", err)304	}305}306307func TestStringMatchesNsFormat(t *testing.T) {308	n, _ := newNs(t, "/bin/ls", "/usr/glenda/bin/rc", "/tmp/x")309	n.Bind("/usr/glenda/bin", "/bin", MAFTER|MCREATE)310	n.Bind("/tmp", "/usr/glenda", MBEFORE)311	n.Cd("/usr/glenda")312313	want := "bind -ac /usr/glenda/bin /bin\n" +314		"bind -b /tmp /usr/glenda\n" +315		"cd /usr/glenda\n"316	if got := n.String(); got != want {317		t.Errorf("ns output:\ngot:\n%s\nwant:\n%s", got, want)318	}319}320321func TestFlagString(t *testing.T) {322	tests := []struct {323		flag Flag324		want string325	}{326		{MREPL, ""},327		{MBEFORE, "-b"},328		{MAFTER, "-a"},329		{MCREATE, "-c"},330		{MAFTER | MCREATE, "-ac"},331		{MBEFORE | MCREATE, "-bc"},332	}333	for _, tt := range tests {334		if got := tt.flag.String(); got != tt.want {335			t.Errorf("Flag(%d): got %q, want %q", uint32(tt.flag), got, tt.want)336		}337	}338}339340func TestUnionWidthIsBounded(t *testing.T) {341	fs := memfs.New("glenda", 1)342	fs.MkdirAll("/bin", 1)343	for i := 0; i < MaxUnion+2; i++ {344		fs.MkdirAll("/d"+string(rune('a'+i)), 1)345	}346	n := New(fs.Root())347	var err error348	for i := 0; i < MaxUnion+2; i++ {349		err = n.Bind("/d"+string(rune('a'+i)), "/bin", MAFTER)350		if err != nil {351			break352		}353	}354	if err != ErrWideUnion {355		t.Errorf("got %v, want ErrWideUnion", err)356	}357}358359func TestReadDirOnAFile(t *testing.T) {360	n, _ := newNs(t, "/bin/ls")361	if _, err := n.ReadDir("/bin/ls", false); err != ninep.ErrNotDir {362		t.Errorf("got %v, want ErrNotDir", err)363	}364}365366func TestDepthIsBounded(t *testing.T) {367	n, _ := newNs(t, "/a")368	p := ""369	for i := 0; i <= ninep.MaxDepth; i++ {370		p += "/x"371	}372	if _, err := n.Stat(p); err != ninep.ErrTooDeep {373		t.Errorf("got %v, want ErrTooDeep", err)374	}375}376

Functions

not supported for pure packages by the node (vm/qfuncs)

Signatures reconstructed verbatim from vm/qfuncs — interface params keep their inline definitions.