github.com/petermattis/pebble@v0.0.0-20190905164901-ab51a2166067/vfs/mem_fs_test.go (about) 1 // Copyright 2012 The LevelDB-Go and Pebble Authors. All rights reserved. Use 2 // of this source code is governed by a BSD-style license that can be found in 3 // the LICENSE file. 4 5 package vfs 6 7 import ( 8 "io" 9 "os" 10 "sort" 11 "strconv" 12 "strings" 13 "testing" 14 ) 15 16 func normalize(name string) string { 17 if os.PathSeparator == '/' { 18 return name 19 } 20 return strings.Replace(name, "/", string(os.PathSeparator), -1) 21 } 22 23 func TestBasics(t *testing.T) { 24 fs := NewMem() 25 testCases := []string{ 26 // Create a top-level file. 27 "1a: create /foo", 28 // Create a child of that file. It should fail, since /foo is not a directory. 29 "2a: create /foo/x fails", 30 // Create a third-level file. It should fail, since /bar has not been created. 31 // Similarly, opening that file should fail. 32 "3a: create /bar/baz/y fails", 33 "3b: open /bar/baz/y fails", 34 // Make the /bar/baz directory; create a third-level file. Creation should now succeed. 35 "4a: mkdirall /bar/baz", 36 "4b: f = create /bar/baz/y", 37 "4c: f.stat.name == y", 38 // Write some data; read it back. 39 "5a: f.write abcde", 40 "5b: f.close", 41 "5c: f = open /bar/baz/y", 42 "5d: f.read 5 == abcde", 43 "5e: f.readat 2 1 == bc", 44 "5f: f.close", 45 // Link /bar/baz/y to /bar/baz/z. We should be able to read from both files 46 // and remove them independently. 47 "6a: link /bar/baz/y /bar/baz/z", 48 "6b: f = open /bar/baz/z", 49 "6c: f.read 5 == abcde", 50 "6d: f.close", 51 "6e: remove /bar/baz/z", 52 "6f: f = open /bar/baz/y", 53 "6g: f.read 5 == abcde", 54 "6h: f.close", 55 // Remove the file twice. The first should succeed, the second should fail. 56 "7a: remove /bar/baz/y", 57 "7b: remove /bar/baz/y fails", 58 "7c: open /bar/baz/y fails", 59 // Rename /foo to /goo. Trying to open /foo should succeed before the rename and 60 // fail afterwards, and vice versa for /goo. 61 "8a: open /foo", 62 "8b: open /goo fails", 63 "8c: rename /foo /goo", 64 "8d: open /foo fails", 65 "8e: open /goo", 66 // Create /bar/baz/z and rename /bar/baz to /bar/caz. 67 "9a: create /bar/baz/z", 68 "9b: open /bar/baz/z", 69 "9c: open /bar/caz/z fails", 70 "9d: rename /bar/baz /bar/caz", 71 "9e: open /bar/baz/z fails", 72 "9f: open /bar/caz/z", 73 } 74 var f File 75 for _, tc := range testCases { 76 s := strings.Split(tc, " ")[1:] 77 78 saveF := s[0] == "f" && s[1] == "=" 79 if saveF { 80 s = s[2:] 81 } 82 83 fails := s[len(s)-1] == "fails" 84 if fails { 85 s = s[:len(s)-1] 86 } 87 88 var ( 89 fi os.FileInfo 90 g File 91 err error 92 ) 93 switch s[0] { 94 case "create": 95 g, err = fs.Create(normalize(s[1])) 96 case "link": 97 err = fs.Link(normalize(s[1]), normalize(s[2])) 98 case "open": 99 g, err = fs.Open(normalize(s[1])) 100 case "mkdirall": 101 err = fs.MkdirAll(normalize(s[1]), 0755) 102 case "remove": 103 err = fs.Remove(normalize(s[1])) 104 case "rename": 105 err = fs.Rename(normalize(s[1]), normalize(s[2])) 106 case "f.write": 107 _, err = f.Write([]byte(s[1])) 108 case "f.read": 109 n, _ := strconv.Atoi(s[1]) 110 buf := make([]byte, n) 111 _, err = io.ReadFull(f, buf) 112 if err != nil { 113 break 114 } 115 if got, want := string(buf), s[3]; got != want { 116 t.Fatalf("%q: got %q, want %q", tc, got, want) 117 } 118 case "f.readat": 119 n, _ := strconv.Atoi(s[1]) 120 off, _ := strconv.Atoi(s[2]) 121 buf := make([]byte, n) 122 _, err = f.ReadAt(buf, int64(off)) 123 if err != nil { 124 break 125 } 126 if got, want := string(buf), s[4]; got != want { 127 t.Fatalf("%q: got %q, want %q", tc, got, want) 128 } 129 case "f.close": 130 f, err = nil, f.Close() 131 case "f.stat.name": 132 fi, err = f.Stat() 133 if err != nil { 134 break 135 } 136 if got, want := fi.Name(), s[2]; got != want { 137 t.Fatalf("%q: got %q, want %q", tc, got, want) 138 } 139 default: 140 t.Fatalf("bad test case: %q", tc) 141 } 142 143 if saveF { 144 f, g = g, nil 145 } else if g != nil { 146 g.Close() 147 } 148 149 if fails { 150 if err == nil { 151 t.Fatalf("%q: got nil error, want non-nil", tc) 152 } 153 } else { 154 if err != nil { 155 t.Fatalf("%q: %v", tc, err) 156 } 157 } 158 } 159 } 160 161 func TestList(t *testing.T) { 162 fs := NewMem() 163 164 dirnames := []string{ 165 "/bar", 166 "/foo/2", 167 } 168 for _, dirname := range dirnames { 169 err := fs.MkdirAll(normalize(dirname), 0755) 170 if err != nil { 171 t.Fatalf("MkdirAll %q: %v", dirname, err) 172 } 173 } 174 175 filenames := []string{ 176 "/a", 177 "/bar/baz", 178 "/foo/0", 179 "/foo/1", 180 "/foo/2/a", 181 "/foo/2/b", 182 "/foo/3", 183 "/foot", 184 } 185 for _, filename := range filenames { 186 f, err := fs.Create(normalize(filename)) 187 if err != nil { 188 t.Fatalf("Create %q: %v", filename, err) 189 } 190 if err := f.Close(); err != nil { 191 t.Fatalf("Close %q: %v", filename, err) 192 } 193 } 194 195 { 196 got := fs.(*memFS).String() 197 want := normalize(` / 198 0 a 199 bar/ 200 0 baz 201 foo/ 202 0 0 203 0 1 204 2/ 205 0 a 206 0 b 207 0 3 208 0 foot 209 `) 210 if got != want { 211 t.Fatalf("String:\n----got----\n%s----want----\n%s", got, want) 212 } 213 } 214 215 testCases := []string{ 216 "/:a bar foo foot", 217 "/bar:baz", 218 "/bar/:baz", 219 "/baz:", 220 "/baz/:", 221 "/foo:0 1 2 3", 222 "/foo/:0 1 2 3", 223 "/foo/1:", 224 "/foo/1/:", 225 "/foo/2:a b", 226 "/foo/2/:a b", 227 "/foot:", 228 "/foot/:", 229 } 230 for _, tc := range testCases { 231 s := strings.Split(tc, ":") 232 list, _ := fs.List(normalize(s[0])) 233 sort.Strings(list) 234 got := strings.Join(list, " ") 235 want := s[1] 236 if got != want { 237 t.Errorf("List %q: got %q, want %q", s[0], got, want) 238 } 239 } 240 }