github.com/3JoB/vfs@v1.0.0/memfs/memfs_test.go (about) 1 package memfs 2 3 import ( 4 "io" 5 "os" 6 "strings" 7 "testing" 8 "time" 9 10 "github.com/3JoB/vfs" 11 ) 12 13 func TestInterface(t *testing.T) { 14 _ = vfs.Filesystem(Create()) 15 } 16 17 func TestCreate(t *testing.T) { 18 fs := Create() 19 // Create file with absolute path 20 { 21 f, err := fs.OpenFile("/testfile", os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666) 22 if err != nil { 23 t.Fatalf("Unexpected error creating file: %s", err) 24 } 25 if name := f.Name(); name != "/testfile" { 26 t.Errorf("Wrong name: %s", name) 27 } 28 } 29 30 // Create same file again 31 { 32 _, err := fs.OpenFile("/testfile", os.O_RDWR|os.O_CREATE, 0666) 33 if err != nil { 34 t.Fatalf("Unexpected error creating file: %s", err) 35 } 36 } 37 38 // Create same file again, but truncate it 39 { 40 _, err := fs.OpenFile("/testfile", os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666) 41 if err != nil { 42 t.Fatalf("Unexpected error creating file: %s", err) 43 } 44 } 45 46 // Create same file again with O_CREATE|O_EXCL, which is an error 47 { 48 _, err := fs.OpenFile("/testfile", os.O_RDWR|os.O_CREATE|os.O_EXCL, 0666) 49 if err == nil { 50 t.Fatalf("Expected error creating file: %s", err) 51 } 52 } 53 54 // Create file with unkown parent 55 { 56 _, err := fs.OpenFile("/testfile/testfile", os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666) 57 if err == nil { 58 t.Errorf("Expected error creating file") 59 } 60 } 61 62 // Create file with relative path (workingDir == root) 63 { 64 f, err := fs.OpenFile("relFile", os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666) 65 if err != nil { 66 t.Fatalf("Unexpected error creating file: %s", err) 67 } 68 if name := f.Name(); name != "/relFile" { 69 t.Errorf("Wrong name: %s", name) 70 } 71 } 72 } 73 74 func TestMkdirAbsRel(t *testing.T) { 75 fs := Create() 76 77 // Create dir with absolute path 78 { 79 err := fs.Mkdir("/usr", 0) 80 if err != nil { 81 t.Fatalf("Unexpected error creating directory: %s", err) 82 } 83 } 84 85 // Create dir with relative path 86 { 87 err := fs.Mkdir("home", 0) 88 if err != nil { 89 t.Fatalf("Unexpected error creating directory: %s", err) 90 } 91 } 92 93 // Create dir twice 94 { 95 err := fs.Mkdir("/home", 0) 96 if err == nil { 97 t.Fatalf("Expecting error creating directory: %s", "/home") 98 } 99 } 100 } 101 102 func TestMkdirTree(t *testing.T) { 103 fs := Create() 104 105 err := fs.Mkdir("/home", 0) 106 if err != nil { 107 t.Fatalf("Unexpected error creating directory /home: %s", err) 108 } 109 110 err = fs.Mkdir("/home/blang", 0) 111 if err != nil { 112 t.Fatalf("Unexpected error creating directory /home/blang: %s", err) 113 } 114 115 err = fs.Mkdir("/home/blang/goprojects", 0) 116 if err != nil { 117 t.Fatalf("Unexpected error creating directory /home/blang/goprojects: %s", err) 118 } 119 120 err = fs.Mkdir("/home/johndoe/goprojects", 0) 121 if err == nil { 122 t.Errorf("Expected error creating directory with non-existing parent") 123 } 124 125 // TODO: Subdir of file 126 } 127 128 func TestSymlink(t *testing.T) { 129 fs := Create() 130 131 if err := vfs.MkdirAll(fs, "/tmp", 0755); err != nil { 132 t.Fatal("Unable to create /tmp:", err) 133 } 134 if err := vfs.WriteFile(fs, "/tmp/teacup", []byte("i am a teacup"), 0644); err != nil { 135 t.Fatal("Unable to fill teacup:", err) 136 } 137 err := fs.Symlink("/tmp/teacup", "/tmp/cup") 138 if err != nil { 139 t.Fatal("Symlink failed:", err) 140 } 141 fluid, err := vfs.ReadFile(fs, "/tmp/cup") 142 if err != nil { 143 t.Fatal("Failed to read from /tmp/cup:", err) 144 } 145 if string(fluid) != "i am a teacup" { 146 t.Fatal("Wrong contents in cup. got:", string(fluid)) 147 } 148 } 149 150 func TestDirectorySymlink(t *testing.T) { 151 fs := Create() 152 153 if err := vfs.MkdirAll(fs, "/foo/a/b", 0755); err != nil { 154 t.Fatal("Unable mkdir /foo/a/b:", err) 155 } 156 157 if err := vfs.WriteFile(fs, "/foo/a/b/c", []byte("I can \"c\" clearly now"), 0644); err != nil { 158 t.Fatal("Unable to write /foo/a/b/c:", err) 159 } 160 161 if err := fs.Symlink("/foo/a/b", "/foo/also_b"); err != nil { 162 t.Fatal("Unable to symlink /foo/also_b -> /foo/a/b:", err) 163 } 164 165 contents, err := vfs.ReadFile(fs, "/foo/also_b/c") 166 if err != nil { 167 t.Fatal("Unable to read /foo/also_b/c:", err) 168 } 169 if string(contents) != "I can \"c\" clearly now" { 170 t.Fatal("Unexpected contents read from c:", err) 171 } 172 } 173 174 func TestMultipleAndRelativeSymlinks(t *testing.T) { 175 fs := Create() 176 if err := vfs.MkdirAll(fs, "a/real_b/real_c", 0755); err != nil { 177 t.Fatal("Unable mkdir a/real_b/real_c:", err) 178 } 179 180 for _, fsEntry := range []struct { 181 name, link, content string 182 }{ 183 {name: "a/b", link: "real_b"}, 184 {name: "a/b/c", link: "real_c"}, 185 {name: "a/b/c/real_d", content: "Lah dee dah"}, 186 {name: "a/b/c/d", link: "real_d"}, 187 {name: "a/d", link: "b/c/d"}, 188 } { 189 if fsEntry.link != "" { 190 if err := fs.Symlink(fsEntry.link, fsEntry.name); err != nil { 191 t.Fatalf("Unable to symlink %s -> %s: %v", fsEntry.name, fsEntry.link, err) 192 } 193 } else if fsEntry.content != "" { 194 if err := vfs.WriteFile(fs, fsEntry.name, []byte(fsEntry.content), 0644); err != nil { 195 t.Fatalf("Unable to write %s: %v", fsEntry.name, err) 196 } 197 } 198 } 199 200 for _, fn := range []string{ 201 "a/b/c/d", 202 "a/d", 203 } { 204 contents, err := vfs.ReadFile(fs, fn) 205 if err != nil { 206 t.Fatalf("Unable to read %s: %v", fn, err) 207 } 208 if string(contents) != "Lah dee dah" { 209 t.Fatalf("Unexpected contents read from %s: %v", fn, err) 210 } 211 } 212 } 213 214 func TestSymlinkIsNotADirectory(t *testing.T) { 215 fs := Create() 216 if err := vfs.MkdirAll(fs, "a/real_b/real_c", 0755); err != nil { 217 t.Fatal("Unable mkdir a/real_b/real_c:", err) 218 } 219 if err := fs.Symlink("broken", "a/b"); err != nil { 220 t.Fatal("Unable to symlink a/b -> broken:", err) 221 } 222 if err := vfs.WriteFile(fs, "a/b/c", []byte("Whatever"), 0644); !strings.Contains(err.Error(), vfs.ErrNotDirectory.Error()) { 223 t.Fatal("Expected an error when writing a/b/c:", err) 224 } 225 } 226 227 // TODO: overwrite/remove symlinks 228 229 func TestReadDir(t *testing.T) { 230 fs := Create() 231 dirs := []string{"/home", "/home/linus", "/home/rob", "/home/pike", "/home/blang"} 232 expectNames := []string{"README.txt", "blang", "linus", "pike", "rob"} 233 for _, dir := range dirs { 234 err := fs.Mkdir(dir, 0777) 235 if err != nil { 236 t.Fatalf("Unexpected error creating directory %q: %s", dir, err) 237 } 238 } 239 f, err := fs.OpenFile("/home/README.txt", os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666) 240 if err != nil { 241 t.Fatalf("Unexpected error creating file: %s", err) 242 } 243 f.Close() 244 245 fis, err := fs.ReadDir("/home") 246 if err != nil { 247 t.Fatalf("Unexpected error readdir: %s", err) 248 } 249 if l := len(fis); l != len(expectNames) { 250 t.Errorf("Wrong size: %q (%d)", fis, l) 251 } 252 for i, n := range expectNames { 253 if fn := fis[i].Name(); fn != n { 254 t.Errorf("Expected name %q, got %q", n, fn) 255 } 256 } 257 258 // Readdir empty directory 259 if fis, err := fs.ReadDir("/home/blang"); err != nil { 260 t.Errorf("Error readdir(empty directory): %s", err) 261 } else if l := len(fis); l > 0 { 262 t.Errorf("Found entries in non-existing directory: %d", l) 263 } 264 265 // Readdir file 266 if _, err := fs.ReadDir("/home/README.txt"); err == nil { 267 t.Errorf("Expected error readdir(file)") 268 } 269 270 // Readdir subdir of file 271 if _, err := fs.ReadDir("/home/README.txt/info"); err == nil { 272 t.Errorf("Expected error readdir(subdir of file)") 273 } 274 275 // Readdir non existing directory 276 if _, err := fs.ReadDir("/usr"); err == nil { 277 t.Errorf("Expected error readdir(nofound)") 278 } 279 } 280 281 func TestRemove(t *testing.T) { 282 fs := Create() 283 err := fs.Mkdir("/tmp", 0777) 284 if err != nil { 285 t.Fatalf("Mkdir error: %s", err) 286 } 287 f, err := fs.OpenFile("/tmp/README.txt", os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666) 288 if err != nil { 289 t.Fatalf("Create error: %s", err) 290 } 291 if _, err := f.Write([]byte("test")); err != nil { 292 t.Fatalf("Write error: %s", err) 293 } 294 f.Close() 295 296 // remove non existing file 297 if err := fs.Remove("/nonexisting.txt"); err == nil { 298 t.Errorf("Expected remove to fail") 299 } 300 301 // remove non existing file from an non existing directory 302 if err := fs.Remove("/nonexisting/nonexisting.txt"); err == nil { 303 t.Errorf("Expected remove to fail") 304 } 305 306 // remove created file 307 err = fs.Remove(f.Name()) 308 if err != nil { 309 t.Errorf("Remove failed: %s", err) 310 } 311 312 if _, err = fs.OpenFile("/tmp/README.txt", os.O_RDWR, 0666); err == nil { 313 t.Errorf("Could open removed file!") 314 } 315 316 err = fs.Remove("/tmp") 317 if err != nil { 318 t.Errorf("Remove failed: %s", err) 319 } 320 if fis, err := fs.ReadDir("/"); err != nil { 321 t.Errorf("Readdir error: %s", err) 322 } else if len(fis) != 0 { 323 t.Errorf("Found files: %s", fis) 324 } 325 } 326 327 func TestReadWrite(t *testing.T) { 328 fs := Create() 329 f, err := fs.OpenFile("/readme.txt", os.O_CREATE|os.O_RDWR, 0666) 330 if err != nil { 331 t.Fatalf("Could not open file: %s", err) 332 } 333 334 // Write first dots 335 if n, err := f.Write([]byte(dots)); err != nil { 336 t.Errorf("Unexpected error: %s", err) 337 } else if n != len(dots) { 338 t.Errorf("Invalid write count: %d", n) 339 } 340 341 // Write abc 342 if n, err := f.Write([]byte(abc)); err != nil { 343 t.Errorf("Unexpected error: %s", err) 344 } else if n != len(abc) { 345 t.Errorf("Invalid write count: %d", n) 346 } 347 348 // Seek to beginning of file 349 if n, err := f.Seek(0, os.SEEK_SET); err != nil || n != 0 { 350 t.Errorf("Seek error: %d %s", n, err) 351 } 352 353 // Seek to end of file 354 if n, err := f.Seek(0, os.SEEK_END); err != nil || n != 32 { 355 t.Errorf("Seek error: %d %s", n, err) 356 } 357 358 // Write dots at end of file 359 if n, err := f.Write([]byte(dots)); err != nil { 360 t.Errorf("Unexpected error: %s", err) 361 } else if n != len(dots) { 362 t.Errorf("Invalid write count: %d", n) 363 } 364 365 // Seek to beginning of file 366 if n, err := f.Seek(0, os.SEEK_SET); err != nil || n != 0 { 367 t.Errorf("Seek error: %d %s", n, err) 368 } 369 370 p := make([]byte, len(dots)+len(abc)+len(dots)) 371 if n, err := f.Read(p); err != nil || n != len(dots)+len(abc)+len(dots) { 372 t.Errorf("Read error: %d %s", n, err) 373 } else if s := string(p); s != dots+abc+dots { 374 t.Errorf("Invalid read: %s", s) 375 } 376 } 377 378 func TestOpen(t *testing.T) { 379 fs := Create() 380 f, err := fs.OpenFile("/readme.txt", os.O_CREATE|os.O_RDWR, 0666) 381 if err != nil { 382 t.Fatalf("OpenFile: %s", err) 383 } 384 if _, err = f.Write([]byte("test")); err != nil { 385 t.Fatalf("Write: %s", err) 386 } 387 f.Close() 388 f2, err := fs.Open("/readme.txt") 389 if err != nil { 390 t.Errorf("Open: %s", err) 391 } 392 if err := f2.Close(); err != nil { 393 t.Errorf("Close: %s", err) 394 } 395 } 396 397 func TestOpenRO(t *testing.T) { 398 fs := Create() 399 f, err := fs.OpenFile("/readme.txt", os.O_CREATE|os.O_RDONLY, 0666) 400 if err != nil { 401 t.Fatalf("Could not open file: %s", err) 402 } 403 404 // Write first dots 405 if _, err := f.Write([]byte(dots)); err == nil { 406 t.Fatalf("Expected write error") 407 } 408 f.Close() 409 } 410 411 func TestOpenWO(t *testing.T) { 412 fs := Create() 413 f, err := fs.OpenFile("/readme.txt", os.O_CREATE|os.O_WRONLY, 0666) 414 if err != nil { 415 t.Fatalf("Could not open file: %s", err) 416 } 417 418 // Write first dots 419 if n, err := f.Write([]byte(dots)); err != nil { 420 t.Errorf("Unexpected error: %s", err) 421 } else if n != len(dots) { 422 t.Errorf("Invalid write count: %d", n) 423 } 424 425 // Seek to beginning of file 426 if n, err := f.Seek(0, os.SEEK_SET); err != nil || n != 0 { 427 t.Errorf("Seek error: %d %s", n, err) 428 } 429 430 // Try reading 431 p := make([]byte, len(dots)) 432 if n, err := f.Read(p); err == nil || n > 0 { 433 t.Errorf("Expected invalid read: %d %s", n, err) 434 } 435 436 f.Close() 437 } 438 439 func TestOpenAppend(t *testing.T) { 440 fs := Create() 441 f, err := fs.OpenFile("/readme.txt", os.O_CREATE|os.O_RDWR, 0666) 442 if err != nil { 443 t.Fatalf("Could not open file: %s", err) 444 } 445 446 // Write first dots 447 if n, err := f.Write([]byte(dots)); err != nil { 448 t.Errorf("Unexpected error: %s", err) 449 } else if n != len(dots) { 450 t.Errorf("Invalid write count: %d", n) 451 } 452 f.Close() 453 454 // Reopen file in append mode 455 f, err = fs.OpenFile("/readme.txt", os.O_APPEND|os.O_RDWR, 0666) 456 if err != nil { 457 t.Fatalf("Could not open file: %s", err) 458 } 459 460 // append dots 461 if n, err := f.Write([]byte(abc)); err != nil { 462 t.Errorf("Unexpected error: %s", err) 463 } else if n != len(abc) { 464 t.Errorf("Invalid write count: %d", n) 465 } 466 467 // Seek to beginning of file 468 if n, err := f.Seek(0, os.SEEK_SET); err != nil || n != 0 { 469 t.Errorf("Seek error: %d %s", n, err) 470 } 471 472 p := make([]byte, len(dots)+len(abc)) 473 if n, err := f.Read(p); err != nil || n != len(dots)+len(abc) { 474 t.Errorf("Read error: %d %s", n, err) 475 } else if s := string(p); s != dots+abc { 476 t.Errorf("Invalid read: %s", s) 477 } 478 f.Close() 479 } 480 481 func TestTruncateToLength(t *testing.T) { 482 var params = []struct { 483 size int64 484 err bool 485 }{ 486 {size: -1, err: true}, 487 {size: 0, err: false}, 488 {size: int64(len(dots) - 1), err: false}, 489 {size: int64(len(dots)), err: false}, 490 {size: int64(len(dots) + 1), err: false}, 491 } 492 for _, param := range params { 493 fs := Create() 494 f, err := fs.OpenFile("/readme.txt", os.O_CREATE|os.O_RDWR, 0666) 495 if err != nil { 496 t.Fatalf("Could not open file: %s", err) 497 } 498 if n, err := f.Write([]byte(dots)); err != nil { 499 t.Errorf("Unexpected error: %s", err) 500 } else if n != len(dots) { 501 t.Errorf("Invalid write count: %d", n) 502 } 503 f.Close() 504 505 newSize := param.size 506 err = f.Truncate(newSize) 507 if param.err { 508 if err == nil { 509 t.Errorf("Error expected truncating file to length %d", newSize) 510 } 511 return 512 } else if err != nil { 513 t.Errorf("Error truncating file: %s", err) 514 } 515 516 b, err := readFile(fs, "/readme.txt") 517 if err != nil { 518 t.Errorf("Error reading truncated file: %s", err) 519 } 520 if int64(len(b)) != newSize { 521 t.Errorf("File should be empty after truncation: %d", len(b)) 522 } 523 if fi, err := fs.Stat("/readme.txt"); err != nil { 524 t.Errorf("Error stat file: %s", err) 525 } else if fi.Size() != newSize { 526 t.Errorf("Filesize should be %d after truncation", newSize) 527 } 528 } 529 } 530 531 func TestTruncateToZero(t *testing.T) { 532 const content = "read me" 533 fs := Create() 534 if _, err := writeFile(fs, "/readme.txt", os.O_CREATE|os.O_RDWR, 0666, []byte(content)); err != nil { 535 t.Errorf("Unexpected error writing file: %s", err) 536 } 537 538 f, err := fs.OpenFile("/readme.txt", os.O_RDWR|os.O_TRUNC, 0666) 539 if err != nil { 540 t.Errorf("Error opening file truncated: %s", err) 541 } 542 f.Close() 543 544 b, err := readFile(fs, "/readme.txt") 545 if err != nil { 546 t.Errorf("Error reading truncated file: %s", err) 547 } 548 if len(b) != 0 { 549 t.Errorf("File should be empty after truncation") 550 } 551 if fi, err := fs.Stat("/readme.txt"); err != nil { 552 t.Errorf("Error stat file: %s", err) 553 } else if fi.Size() != 0 { 554 t.Errorf("Filesize should be 0 after truncation") 555 } 556 } 557 558 func TestStat(t *testing.T) { 559 fs := Create() 560 f, err := fs.OpenFile("/readme.txt", os.O_CREATE|os.O_RDWR, 0666) 561 if err != nil { 562 t.Fatalf("Could not open file: %s", err) 563 } 564 565 // Write first dots 566 if n, err := f.Write([]byte(dots)); err != nil { 567 t.Fatalf("Unexpected error: %s", err) 568 } else if n != len(dots) { 569 t.Fatalf("Invalid write count: %d", n) 570 } 571 f.Close() 572 573 if err := fs.Mkdir("/tmp", 0777); err != nil { 574 t.Fatalf("Mkdir error: %s", err) 575 } 576 577 fi, err := fs.Stat(f.Name()) 578 if err != nil { 579 t.Errorf("Stat error: %s", err) 580 } 581 582 // Fileinfo name is base name 583 if name := fi.Name(); name != "readme.txt" { 584 t.Errorf("Invalid fileinfo name: %s", name) 585 } 586 587 // File name is abs name 588 if name := f.Name(); name != "/readme.txt" { 589 t.Errorf("Invalid file name: %s", name) 590 } 591 592 if s := fi.Size(); s != int64(len(dots)) { 593 t.Errorf("Invalid size: %d", s) 594 } 595 if fi.IsDir() { 596 t.Errorf("Invalid IsDir") 597 } 598 if m := fi.Mode(); m != 0666 { 599 t.Errorf("Invalid mode: %d", m) 600 } 601 } 602 603 func writeFile(fs vfs.Filesystem, name string, flags int, mode os.FileMode, b []byte) (int, error) { 604 f, err := fs.OpenFile(name, flags, mode) 605 if err != nil { 606 return 0, err 607 } 608 return f.Write(b) 609 } 610 611 func readFile(fs vfs.Filesystem, name string) ([]byte, error) { 612 f, err := fs.OpenFile(name, os.O_RDONLY, 0) 613 if err != nil { 614 return nil, err 615 } 616 return io.ReadAll(f) 617 } 618 619 func TestRename(t *testing.T) { 620 const content = "read me" 621 fs := Create() 622 if _, err := writeFile(fs, "/readme.txt", os.O_CREATE|os.O_RDWR, 0666, []byte(content)); err != nil { 623 t.Errorf("Unexpected error writing file: %s", err) 624 } 625 626 if err := fs.Rename("/readme.txt", "/README.txt"); err != nil { 627 t.Errorf("Unexpected error renaming file: %s", err) 628 } 629 630 if _, err := fs.Stat("/readme.txt"); err == nil { 631 t.Errorf("Old file still exists") 632 } 633 634 if _, err := fs.Stat("/README.txt"); err != nil { 635 t.Errorf("Error stat newfile: %s", err) 636 } 637 if b, err := readFile(fs, "/README.txt"); err != nil { 638 t.Errorf("Error reading file: %s", err) 639 } else if s := string(b); s != content { 640 t.Errorf("Invalid content: %s", s) 641 } 642 643 // Rename unknown file 644 if err := fs.Rename("/nonexisting.txt", "/goodtarget.txt"); err == nil { 645 t.Errorf("Expected error renaming file") 646 } 647 648 // Rename unknown file in nonexisting directory 649 if err := fs.Rename("/nonexisting/nonexisting.txt", "/goodtarget.txt"); err == nil { 650 t.Errorf("Expected error renaming file") 651 } 652 653 // Rename existing file to nonexisting directory 654 if err := fs.Rename("/README.txt", "/nonexisting/nonexisting.txt"); err == nil { 655 t.Errorf("Expected error renaming file") 656 } 657 658 if err := fs.Mkdir("/newdirectory", 0777); err != nil { 659 t.Errorf("Error creating directory: %s", err) 660 } 661 662 if err := fs.Rename("/README.txt", "/newdirectory/README.txt"); err != nil { 663 t.Errorf("Error renaming file: %s", err) 664 } 665 666 // Create the same file again at root 667 if _, err := writeFile(fs, "/README.txt", os.O_CREATE|os.O_RDWR, 0666, []byte(content)); err != nil { 668 t.Errorf("Unexpected error writing file: %s", err) 669 } 670 671 // Overwrite existing file 672 if err := fs.Rename("/newdirectory/README.txt", "/README.txt"); err == nil { 673 t.Errorf("Expected error renaming file") 674 } 675 } 676 677 func TestModTime(t *testing.T) { 678 fs := Create() 679 680 tBeforeWrite := time.Now() 681 writeFile(fs, "/readme.txt", os.O_CREATE|os.O_RDWR, 0666, []byte{0, 0, 0}) 682 fi, _ := fs.Stat("/readme.txt") 683 mtimeAfterWrite := fi.ModTime() 684 685 if !mtimeAfterWrite.After(tBeforeWrite) { 686 t.Error("Open should modify mtime") 687 } 688 689 f, err := fs.OpenFile("/readme.txt", os.O_RDONLY, 0666) 690 if err != nil { 691 t.Fatalf("Could not open file: %s", err) 692 } 693 f.Close() 694 tAfterRead := fi.ModTime() 695 696 if tAfterRead != mtimeAfterWrite { 697 t.Error("Open with O_RDONLY should not modify mtime") 698 } 699 }