1package ninep23import "testing"45func TestPermString(t *testing.T) {6 tests := []struct {7 name string8 perm Perm9 want string10 }{11 {"dir 0755", DMDIR | 0755, "drwxr-xr-x"},12 {"file 0644", 0644, "-rw-r--r--"},13 {"file 0600", 0600, "-rw-------"},14 {"file 0777", 0777, "-rwxrwxrwx"},15 {"file 0000", 0, "----------"},16 {"append only", DMAPPEND | 0644, "arw-r--r--"},17 {"exclusive", DMEXCL | 0600, "lrw-------"},18 {"dir default", DirPerm, "drwxr-xr-x"},19 {"file default", FilePerm, "-rw-r--r--"},20 }21 for _, tt := range tests {22 if got := tt.perm.String(); got != tt.want {23 t.Errorf("%s: got %q, want %q", tt.name, got, tt.want)24 }25 }26}2728func TestPermIsDir(t *testing.T) {29 if !(DMDIR | 0755).IsDir() {30 t.Error("DMDIR|0755 should be a directory")31 }32 if Perm(0644).IsDir() {33 t.Error("0644 should not be a directory")34 }35}3637func TestQidString(t *testing.T) {38 tests := []struct {39 name string40 qid Qid41 want string42 }{43 {"root", Qid{Type: QTDIR, Version: 0, Path: 0}, "(0 0 d)"},44 {"file", Qid{Type: QTFILE, Version: 3, Path: 17}, "(11 3 f)"},45 {"big path", Qid{Type: QTFILE, Version: 1, Path: 255}, "(ff 1 f)"},46 }47 for _, tt := range tests {48 if got := tt.qid.String(); got != tt.want {49 t.Errorf("%s: got %q, want %q", tt.name, got, tt.want)50 }51 }52}5354func TestStatLine(t *testing.T) {55 s := Stat{56 Qid: Qid{Type: QTFILE, Path: 2, Version: 1},57 Mode: 0644,58 Length: 12,59 Name: "greeting",60 Uid: "glenda",61 Gid: "sys",62 }63 want := "-rw-r--r-- glenda sys 12 greeting"64 if got := s.Line(); got != want {65 t.Errorf("got %q, want %q", got, want)66 }67}6869func TestValidName(t *testing.T) {70 tests := []struct {71 name string72 want bool73 }{74 {"dev", true},75 {"a.b", true},76 {"with space", true},77 {"", false},78 {".", false},79 {"..", false},80 {"a/b", false},81 {"/", false},82 }83 for _, tt := range tests {84 if got := ValidName(tt.name); got != tt.want {85 t.Errorf("ValidName(%q): got %v, want %v", tt.name, got, tt.want)86 }87 }88}8990func TestClean(t *testing.T) {91 tests := []struct {92 in string93 want string94 }{95 {"", "/"},96 {"/", "/"},97 {"dev", "/dev"},98 {"/dev/", "/dev"},99 {"/dev//height", "/dev/height"},100 {"/dev/./height", "/dev/height"},101 {"/dev/../srv", "/srv"},102 {"/../..", "/"},103 {"/a/b/../../c", "/c"},104 }105 for _, tt := range tests {106 if got := Clean(tt.in); got != tt.want {107 t.Errorf("Clean(%q): got %q, want %q", tt.in, got, tt.want)108 }109 }110}111112func TestAbs(t *testing.T) {113 tests := []struct {114 cwd string115 in string116 want string117 }{118 {"/", "dev", "/dev"},119 {"/usr/glenda", "bin", "/usr/glenda/bin"},120 {"/usr/glenda", "/dev", "/dev"},121 {"/usr/glenda", "..", "/usr"},122 {"/usr/glenda", "", "/usr/glenda"},123 {"", "dev", "/dev"},124 }125 for _, tt := range tests {126 if got := Abs(tt.cwd, tt.in); got != tt.want {127 t.Errorf("Abs(%q, %q): got %q, want %q", tt.cwd, tt.in, got, tt.want)128 }129 }130}131132func TestElems(t *testing.T) {133 tests := []struct {134 in string135 want []string136 }{137 {"/", nil},138 {"", nil},139 {"/dev", []string{"dev"}},140 {"/dev/height", []string{"dev", "height"}},141 {"/a/b/../c", []string{"a", "c"}},142 }143 for _, tt := range tests {144 got := Elems(tt.in)145 if len(got) != len(tt.want) {146 t.Errorf("Elems(%q): got %v, want %v", tt.in, got, tt.want)147 continue148 }149 for i := range got {150 if got[i] != tt.want[i] {151 t.Errorf("Elems(%q)[%d]: got %q, want %q", tt.in, i, got[i], tt.want[i])152 }153 }154 }155}156157func TestBaseDirJoin(t *testing.T) {158 if got := Base("/dev/height"); got != "height" {159 t.Errorf("Base: got %q", got)160 }161 if got := Base("/"); got != "/" {162 t.Errorf("Base of root: got %q", got)163 }164 if got := Dir("/dev/height"); got != "/dev" {165 t.Errorf("Dir: got %q", got)166 }167 if got := Join("/dev", "height"); got != "/dev/height" {168 t.Errorf("Join: got %q", got)169 }170 if got := Join("/", "dev"); got != "/dev" {171 t.Errorf("Join at root: got %q", got)172 }173}174175func TestSlice(t *testing.T) {176 const s = "hello world"177 tests := []struct {178 name string179 off int64180 count int64181 want string182 }{183 {"whole", 0, -1, "hello world"},184 {"prefix", 0, 5, "hello"},185 {"middle", 6, 5, "world"},186 {"past end", 99, 5, ""},187 {"count past end", 6, 99, "world"},188 {"negative offset clamps", -4, 5, "hello"},189 {"zero count", 0, 0, ""},190 }191 for _, tt := range tests {192 if got := Slice(s, tt.off, tt.count); got != tt.want {193 t.Errorf("%s: got %q, want %q", tt.name, got, tt.want)194 }195 }196}197Signatures reconstructed verbatim from vm/qfuncs — interface params keep their inline definitions.