github.com/maxnasonov/afero@v1.8.4/iofs_test.go (about) 1 // +build go1.16 2 3 package afero 4 5 import ( 6 "bytes" 7 "errors" 8 "io" 9 "io/fs" 10 "os" 11 "testing" 12 "testing/fstest" 13 "time" 14 ) 15 16 func TestIOFS(t *testing.T) { 17 t.Parallel() 18 19 t.Run("use MemMapFs", func(t *testing.T) { 20 mmfs := NewMemMapFs() 21 22 err := mmfs.MkdirAll("dir1/dir2", os.ModePerm) 23 if err != nil { 24 t.Fatal("MkdirAll failed:", err) 25 } 26 27 f, err := mmfs.OpenFile("dir1/dir2/test.txt", os.O_RDWR|os.O_CREATE, os.ModePerm) 28 if err != nil { 29 t.Fatal("OpenFile (O_CREATE) failed:", err) 30 } 31 32 f.Close() 33 34 if err := fstest.TestFS(NewIOFS(mmfs), "dir1/dir2/test.txt"); err != nil { 35 t.Error(err) 36 } 37 }) 38 39 t.Run("use OsFs", func(t *testing.T) { 40 osfs := NewBasePathFs(NewOsFs(), t.TempDir()) 41 42 err := osfs.MkdirAll("dir1/dir2", os.ModePerm) 43 if err != nil { 44 t.Fatal("MkdirAll failed:", err) 45 } 46 47 f, err := osfs.OpenFile("dir1/dir2/test.txt", os.O_RDWR|os.O_CREATE, os.ModePerm) 48 if err != nil { 49 t.Fatal("OpenFile (O_CREATE) failed:", err) 50 } 51 52 f.Close() 53 54 if err := fstest.TestFS(NewIOFS(osfs), "dir1/dir2/test.txt"); err != nil { 55 t.Error(err) 56 } 57 }) 58 } 59 60 func TestFromIOFS(t *testing.T) { 61 t.Parallel() 62 63 fsys := fstest.MapFS{ 64 "test.txt": { 65 Data: []byte("File in root"), 66 Mode: fs.ModePerm, 67 ModTime: time.Now(), 68 }, 69 "dir1": { 70 Mode: fs.ModeDir | fs.ModePerm, 71 ModTime: time.Now(), 72 }, 73 "dir1/dir2": { 74 Mode: fs.ModeDir | fs.ModePerm, 75 ModTime: time.Now(), 76 }, 77 "dir1/dir2/hello.txt": { 78 Data: []byte("Hello world"), 79 Mode: fs.ModePerm, 80 ModTime: time.Now(), 81 }, 82 } 83 84 fromIOFS := FromIOFS{fsys} 85 86 t.Run("Create", func(t *testing.T) { 87 _, err := fromIOFS.Create("test") 88 assertPermissionError(t, err) 89 }) 90 91 t.Run("Mkdir", func(t *testing.T) { 92 err := fromIOFS.Mkdir("test", 0) 93 assertPermissionError(t, err) 94 }) 95 96 t.Run("MkdirAll", func(t *testing.T) { 97 err := fromIOFS.Mkdir("test", 0) 98 assertPermissionError(t, err) 99 }) 100 101 t.Run("Open", func(t *testing.T) { 102 t.Run("non existing file", func(t *testing.T) { 103 _, err := fromIOFS.Open("nonexisting") 104 if !errors.Is(err, fs.ErrNotExist) { 105 t.Errorf("Expected error to be fs.ErrNotExist, got %[1]T (%[1]v)", err) 106 } 107 }) 108 109 t.Run("directory", func(t *testing.T) { 110 dirFile, err := fromIOFS.Open("dir1") 111 if err != nil { 112 t.Errorf("dir1 open failed: %v", err) 113 return 114 } 115 116 defer dirFile.Close() 117 118 dirStat, err := dirFile.Stat() 119 if err != nil { 120 t.Errorf("dir1 stat failed: %v", err) 121 return 122 } 123 124 if !dirStat.IsDir() { 125 t.Errorf("dir1 stat told that it is not a directory") 126 return 127 } 128 }) 129 130 t.Run("simple file", func(t *testing.T) { 131 file, err := fromIOFS.Open("test.txt") 132 if err != nil { 133 t.Errorf("test.txt open failed: %v", err) 134 return 135 } 136 137 defer file.Close() 138 139 fileStat, err := file.Stat() 140 if err != nil { 141 t.Errorf("test.txt stat failed: %v", err) 142 return 143 } 144 145 if fileStat.IsDir() { 146 t.Errorf("test.txt stat told that it is a directory") 147 return 148 } 149 }) 150 }) 151 152 t.Run("Remove", func(t *testing.T) { 153 err := fromIOFS.Remove("test") 154 assertPermissionError(t, err) 155 }) 156 157 t.Run("Rename", func(t *testing.T) { 158 err := fromIOFS.Rename("test", "test2") 159 assertPermissionError(t, err) 160 }) 161 162 t.Run("Stat", func(t *testing.T) { 163 t.Run("non existing file", func(t *testing.T) { 164 _, err := fromIOFS.Stat("nonexisting") 165 if !errors.Is(err, fs.ErrNotExist) { 166 t.Errorf("Expected error to be fs.ErrNotExist, got %[1]T (%[1]v)", err) 167 } 168 }) 169 170 t.Run("directory", func(t *testing.T) { 171 stat, err := fromIOFS.Stat("dir1/dir2") 172 if err != nil { 173 t.Errorf("dir1/dir2 stat failed: %v", err) 174 return 175 } 176 177 if !stat.IsDir() { 178 t.Errorf("dir1/dir2 stat told that it is not a directory") 179 return 180 } 181 }) 182 183 t.Run("file", func(t *testing.T) { 184 stat, err := fromIOFS.Stat("dir1/dir2/hello.txt") 185 if err != nil { 186 t.Errorf("dir1/dir2 stat failed: %v", err) 187 return 188 } 189 190 if stat.IsDir() { 191 t.Errorf("dir1/dir2/hello.txt stat told that it is a directory") 192 return 193 } 194 195 if lenFile := len(fsys["dir1/dir2/hello.txt"].Data); int64(lenFile) != stat.Size() { 196 t.Errorf("dir1/dir2/hello.txt stat told invalid size: expected %d, got %d", lenFile, stat.Size()) 197 return 198 } 199 }) 200 }) 201 202 t.Run("Chmod", func(t *testing.T) { 203 err := fromIOFS.Chmod("test", os.ModePerm) 204 assertPermissionError(t, err) 205 }) 206 207 t.Run("Chown", func(t *testing.T) { 208 err := fromIOFS.Chown("test", 0, 0) 209 assertPermissionError(t, err) 210 }) 211 212 t.Run("Chtimes", func(t *testing.T) { 213 err := fromIOFS.Chtimes("test", time.Now(), time.Now()) 214 assertPermissionError(t, err) 215 }) 216 } 217 218 func TestFromIOFS_File(t *testing.T) { 219 t.Parallel() 220 221 fsys := fstest.MapFS{ 222 "test.txt": { 223 Data: []byte("File in root"), 224 Mode: fs.ModePerm, 225 ModTime: time.Now(), 226 }, 227 "dir1": { 228 Mode: fs.ModeDir | fs.ModePerm, 229 ModTime: time.Now(), 230 }, 231 "dir2": { 232 Mode: fs.ModeDir | fs.ModePerm, 233 ModTime: time.Now(), 234 }, 235 } 236 237 fromIOFS := FromIOFS{fsys} 238 239 file, err := fromIOFS.Open("test.txt") 240 if err != nil { 241 t.Errorf("test.txt open failed: %v", err) 242 return 243 } 244 245 defer file.Close() 246 247 fileStat, err := file.Stat() 248 if err != nil { 249 t.Errorf("test.txt stat failed: %v", err) 250 return 251 } 252 253 if fileStat.IsDir() { 254 t.Errorf("test.txt stat told that it is a directory") 255 return 256 } 257 258 t.Run("ReadAt", func(t *testing.T) { 259 // MapFS files implements io.ReaderAt 260 b := make([]byte, 2) 261 _, err := file.ReadAt(b, 2) 262 263 if err != nil { 264 t.Errorf("ReadAt failed: %v", err) 265 return 266 } 267 268 if expectedData := fsys["test.txt"].Data[2:4]; !bytes.Equal(b, expectedData) { 269 t.Errorf("Unexpected content read: %s, expected %s", b, expectedData) 270 } 271 }) 272 273 t.Run("Seek", func(t *testing.T) { 274 n, err := file.Seek(2, io.SeekStart) 275 if err != nil { 276 t.Errorf("Seek failed: %v", err) 277 return 278 } 279 280 if n != 2 { 281 t.Errorf("Seek returned unexpected value: %d, expected 2", n) 282 } 283 }) 284 285 t.Run("Write", func(t *testing.T) { 286 _, err := file.Write(nil) 287 assertPermissionError(t, err) 288 }) 289 290 t.Run("WriteAt", func(t *testing.T) { 291 _, err := file.WriteAt(nil, 0) 292 assertPermissionError(t, err) 293 }) 294 295 t.Run("Name", func(t *testing.T) { 296 if name := file.Name(); name != "test.txt" { 297 t.Errorf("expected file.Name() == test.txt, got %s", name) 298 } 299 }) 300 301 t.Run("Readdir", func(t *testing.T) { 302 t.Run("not directory", func(t *testing.T) { 303 _, err := file.Readdir(-1) 304 assertPermissionError(t, err) 305 }) 306 307 t.Run("root directory", func(t *testing.T) { 308 root, err := fromIOFS.Open(".") 309 if err != nil { 310 t.Errorf("root open failed: %v", err) 311 return 312 } 313 314 defer root.Close() 315 316 items, err := root.Readdir(-1) 317 if err != nil { 318 t.Errorf("Readdir error: %v", err) 319 return 320 } 321 322 var expectedItems = []struct { 323 Name string 324 IsDir bool 325 Size int64 326 }{ 327 {Name: "dir1", IsDir: true, Size: 0}, 328 {Name: "dir2", IsDir: true, Size: 0}, 329 {Name: "test.txt", IsDir: false, Size: int64(len(fsys["test.txt"].Data))}, 330 } 331 332 if len(expectedItems) != len(items) { 333 t.Errorf("Items count mismatch, expected %d, got %d", len(expectedItems), len(items)) 334 return 335 } 336 337 for i, item := range items { 338 if item.Name() != expectedItems[i].Name { 339 t.Errorf("Item %d: expected name %s, got %s", i, expectedItems[i].Name, item.Name()) 340 } 341 342 if item.IsDir() != expectedItems[i].IsDir { 343 t.Errorf("Item %d: expected IsDir %t, got %t", i, expectedItems[i].IsDir, item.IsDir()) 344 } 345 346 if item.Size() != expectedItems[i].Size { 347 t.Errorf("Item %d: expected IsDir %d, got %d", i, expectedItems[i].Size, item.Size()) 348 } 349 } 350 }) 351 }) 352 353 t.Run("Readdirnames", func(t *testing.T) { 354 t.Run("not directory", func(t *testing.T) { 355 _, err := file.Readdirnames(-1) 356 assertPermissionError(t, err) 357 }) 358 359 t.Run("root directory", func(t *testing.T) { 360 root, err := fromIOFS.Open(".") 361 if err != nil { 362 t.Errorf("root open failed: %v", err) 363 return 364 } 365 366 defer root.Close() 367 368 items, err := root.Readdirnames(-1) 369 if err != nil { 370 t.Errorf("Readdirnames error: %v", err) 371 return 372 } 373 374 var expectedItems = []string{"dir1", "dir2", "test.txt"} 375 376 if len(expectedItems) != len(items) { 377 t.Errorf("Items count mismatch, expected %d, got %d", len(expectedItems), len(items)) 378 return 379 } 380 381 for i, item := range items { 382 if item != expectedItems[i] { 383 t.Errorf("Item %d: expected name %s, got %s", i, expectedItems[i], item) 384 } 385 } 386 }) 387 }) 388 389 t.Run("Truncate", func(t *testing.T) { 390 err := file.Truncate(1) 391 assertPermissionError(t, err) 392 }) 393 394 t.Run("WriteString", func(t *testing.T) { 395 _, err := file.WriteString("a") 396 assertPermissionError(t, err) 397 }) 398 } 399 400 func assertPermissionError(t *testing.T, err error) { 401 t.Helper() 402 403 var perr *fs.PathError 404 if !errors.As(err, &perr) { 405 t.Errorf("Expected *fs.PathError, got %[1]T (%[1]v)", err) 406 return 407 } 408 409 if perr.Err != fs.ErrPermission { 410 t.Errorf("Expected (*fs.PathError).Err == fs.ErrPermisson, got %[1]T (%[1]v)", err) 411 } 412 }