github.com/IBM/fsgo@v0.0.0-20220920202152-e16fd2119d49/fsgo_test.go (about) 1 package fsgo 2 3 import ( 4 "bytes" 5 "fmt" 6 "io" 7 iofs "io/fs" 8 "io/ioutil" 9 "os" 10 "path/filepath" 11 "runtime" 12 "strings" 13 "syscall" 14 "testing" 15 ) 16 17 var testName = "test.txt" 18 var Fss = []Fs{&MemMapFs{}, &OsFs{}} 19 20 var testRegistry map[Fs][]string = make(map[Fs][]string) 21 22 func testDir(fs Fs) string { 23 name, err := TempDir(fs, "", "fsgo") 24 if err != nil { 25 panic(fmt.Sprint("unable to work with test dir", err)) 26 } 27 testRegistry[fs] = append(testRegistry[fs], name) 28 29 return name 30 } 31 32 func tmpFile(fs Fs) File { 33 x, err := TempFile(fs, "", "fsgo") 34 35 if err != nil { 36 panic(fmt.Sprint("unable to work with temp file", err)) 37 } 38 39 testRegistry[fs] = append(testRegistry[fs], x.Name()) 40 41 return x 42 } 43 44 // Read with length 0 should not return EOF. 45 func TestRead0(t *testing.T) { 46 for _, fs := range Fss { 47 f := tmpFile(fs) 48 defer f.Close() 49 f.WriteString("Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.") 50 51 var b []byte 52 // b := make([]byte, 0) 53 n, err := f.Read(b) 54 if n != 0 || err != nil { 55 t.Errorf("%v: Read(0) = %d, %v, want 0, nil", fs.Name(), n, err) 56 } 57 f.Seek(0, 0) 58 b = make([]byte, 100) 59 n, err = f.Read(b) 60 if n <= 0 || err != nil { 61 t.Errorf("%v: Read(100) = %d, %v, want >0, nil", fs.Name(), n, err) 62 } 63 } 64 } 65 66 func TestOpenFile(t *testing.T) { 67 defer removeAllTestFiles(t) 68 for _, fs := range Fss { 69 tmp := testDir(fs) 70 path := filepath.Join(tmp, testName) 71 72 f, err := fs.OpenFile(path, os.O_RDWR|os.O_CREATE, 0600) 73 if err != nil { 74 t.Error(fs.Name(), "OpenFile (O_CREATE) failed:", err) 75 continue 76 } 77 io.WriteString(f, "initial") 78 f.Close() 79 80 f, err = fs.OpenFile(path, os.O_WRONLY|os.O_APPEND, 0600) 81 if err != nil { 82 t.Error(fs.Name(), "OpenFile (O_APPEND) failed:", err) 83 continue 84 } 85 io.WriteString(f, "|append") 86 f.Close() 87 88 f, _ = fs.OpenFile(path, os.O_RDONLY, 0600) 89 contents, _ := ioutil.ReadAll(f) 90 expectedContents := "initial|append" 91 if string(contents) != expectedContents { 92 t.Errorf("%v: appending, expected '%v', got: '%v'", fs.Name(), expectedContents, string(contents)) 93 } 94 f.Close() 95 96 f, err = fs.OpenFile(path, os.O_RDWR|os.O_TRUNC, 0600) 97 if err != nil { 98 t.Error(fs.Name(), "OpenFile (O_TRUNC) failed:", err) 99 continue 100 } 101 contents, _ = ioutil.ReadAll(f) 102 if string(contents) != "" { 103 t.Errorf("%v: expected truncated file, got: '%v'", fs.Name(), string(contents)) 104 } 105 f.Close() 106 } 107 } 108 109 func TestCreate(t *testing.T) { 110 defer removeAllTestFiles(t) 111 for _, fs := range Fss { 112 tmp := testDir(fs) 113 path := filepath.Join(tmp, testName) 114 115 f, err := fs.Create(path) 116 if err != nil { 117 t.Error(fs.Name(), "Create failed:", err) 118 f.Close() 119 continue 120 } 121 io.WriteString(f, "initial") 122 f.Close() 123 124 f, err = fs.Create(path) 125 if err != nil { 126 t.Error(fs.Name(), "Create failed:", err) 127 f.Close() 128 continue 129 } 130 secondContent := "second create" 131 io.WriteString(f, secondContent) 132 f.Close() 133 134 f, err = fs.Open(path) 135 if err != nil { 136 t.Error(fs.Name(), "Open failed:", err) 137 f.Close() 138 continue 139 } 140 buf, err := ReadAll(f) 141 if err != nil { 142 t.Error(fs.Name(), "ReadAll failed:", err) 143 f.Close() 144 continue 145 } 146 if string(buf) != secondContent { 147 t.Error(fs.Name(), "Content should be", "\""+secondContent+"\" but is \""+string(buf)+"\"") 148 f.Close() 149 continue 150 } 151 f.Close() 152 } 153 } 154 155 func TestMemFileRead(t *testing.T) { 156 f := tmpFile(new(MemMapFs)) 157 // f := MemFileCreate("testfile") 158 f.WriteString("abcd") 159 f.Seek(0, 0) 160 b := make([]byte, 8) 161 n, err := f.Read(b) 162 if n != 4 { 163 t.Errorf("didn't read all bytes: %v %v %v", n, err, b) 164 } 165 if err != nil { 166 t.Errorf("err is not nil: %v %v %v", n, err, b) 167 } 168 n, err = f.Read(b) 169 if n != 0 { 170 t.Errorf("read more bytes: %v %v %v", n, err, b) 171 } 172 if err != io.EOF { 173 t.Errorf("error is not EOF: %v %v %v", n, err, b) 174 } 175 } 176 177 func TestRename(t *testing.T) { 178 defer removeAllTestFiles(t) 179 for _, fs := range Fss { 180 tDir := testDir(fs) 181 from := filepath.Join(tDir, "/renamefrom") 182 to := filepath.Join(tDir, "/renameto") 183 exists := filepath.Join(tDir, "/renameexists") 184 file, err := fs.Create(from) 185 if err != nil { 186 t.Fatalf("%s: open %q failed: %v", fs.Name(), to, err) 187 } 188 if err = file.Close(); err != nil { 189 t.Errorf("%s: close %q failed: %v", fs.Name(), to, err) 190 } 191 file, err = fs.Create(exists) 192 if err != nil { 193 t.Fatalf("%s: open %q failed: %v", fs.Name(), to, err) 194 } 195 if err = file.Close(); err != nil { 196 t.Errorf("%s: close %q failed: %v", fs.Name(), to, err) 197 } 198 err = fs.Rename(from, to) 199 if err != nil { 200 t.Fatalf("%s: rename %q, %q failed: %v", fs.Name(), to, from, err) 201 } 202 file, err = fs.Create(from) 203 if err != nil { 204 t.Fatalf("%s: open %q failed: %v", fs.Name(), to, err) 205 } 206 if err = file.Close(); err != nil { 207 t.Errorf("%s: close %q failed: %v", fs.Name(), to, err) 208 } 209 err = fs.Rename(from, exists) 210 if err != nil { 211 t.Errorf("%s: rename %q, %q failed: %v", fs.Name(), exists, from, err) 212 } 213 names, err := readDirNames(fs, tDir) 214 if err != nil { 215 t.Errorf("%s: readDirNames error: %v", fs.Name(), err) 216 } 217 found := false 218 for _, e := range names { 219 if e == "renamefrom" { 220 t.Error("File is still called renamefrom") 221 } 222 if e == "renameto" { 223 found = true 224 } 225 } 226 if !found { 227 t.Error("File was not renamed to renameto") 228 } 229 230 _, err = fs.Stat(to) 231 if err != nil { 232 t.Errorf("%s: stat %q failed: %v", fs.Name(), to, err) 233 } 234 } 235 } 236 237 func TestRemove(t *testing.T) { 238 for _, fs := range Fss { 239 240 x, err := TempFile(fs, "", "fsgo") 241 if err != nil { 242 t.Error(fmt.Sprint("unable to work with temp file", err)) 243 } 244 245 path := x.Name() 246 x.Close() 247 248 tDir := filepath.Dir(path) 249 250 err = fs.Remove(path) 251 if err != nil { 252 t.Errorf("%v: Remove() failed: %v", fs.Name(), err) 253 continue 254 } 255 256 _, err = fs.Stat(path) 257 if !os.IsNotExist(err) { 258 t.Errorf("%v: Remove() didn't remove file", fs.Name()) 259 continue 260 } 261 262 // Deleting non-existent file should raise error 263 err = fs.Remove(path) 264 if !os.IsNotExist(err) { 265 t.Errorf("%v: Remove() didn't raise error for non-existent file", fs.Name()) 266 } 267 268 f, err := fs.Open(tDir) 269 if err != nil { 270 t.Error("TestDir should still exist:", err) 271 } 272 273 names, err := f.Readdirnames(-1) 274 if err != nil { 275 t.Error("Readdirnames failed:", err) 276 } 277 278 for _, e := range names { 279 if e == testName { 280 t.Error("File was not removed from parent directory") 281 } 282 } 283 } 284 } 285 286 func TestTruncate(t *testing.T) { 287 defer removeAllTestFiles(t) 288 for _, fs := range Fss { 289 f := tmpFile(fs) 290 defer f.Close() 291 292 checkSize(t, f, 0) 293 f.Write([]byte("hello, world\n")) 294 checkSize(t, f, 13) 295 f.Truncate(10) 296 checkSize(t, f, 10) 297 f.Truncate(1024) 298 checkSize(t, f, 1024) 299 f.Truncate(0) 300 checkSize(t, f, 0) 301 _, err := f.Write([]byte("surprise!")) 302 if err == nil { 303 checkSize(t, f, 13+9) // wrote at offset past where hello, world was. 304 } 305 } 306 } 307 308 func TestSeek(t *testing.T) { 309 defer removeAllTestFiles(t) 310 for _, fs := range Fss { 311 f := tmpFile(fs) 312 defer f.Close() 313 314 const data = "hello, world\n" 315 io.WriteString(f, data) 316 317 type test struct { 318 in int64 319 whence int 320 out int64 321 } 322 var tests = []test{ 323 {0, 1, int64(len(data))}, 324 {0, 0, 0}, 325 {5, 0, 5}, 326 {0, 2, int64(len(data))}, 327 {0, 0, 0}, 328 {-1, 2, int64(len(data)) - 1}, 329 {1 << 33, 0, 1 << 33}, 330 {1 << 33, 2, 1<<33 + int64(len(data))}, 331 } 332 for i, tt := range tests { 333 off, err := f.Seek(tt.in, tt.whence) 334 if off != tt.out || err != nil { 335 if e, ok := err.(*os.PathError); ok && e.Err == syscall.EINVAL && tt.out > 1<<32 { 336 // Reiserfs rejects the big seeks. 337 // http://code.google.com/p/go/issues/detail?id=91 338 break 339 } 340 t.Errorf("#%d: Seek(%v, %v) = %v, %v want %v, nil", i, tt.in, tt.whence, off, err, tt.out) 341 } 342 } 343 } 344 } 345 346 func TestReadAt(t *testing.T) { 347 defer removeAllTestFiles(t) 348 for _, fs := range Fss { 349 f := tmpFile(fs) 350 defer f.Close() 351 352 const data = "hello, world\n" 353 io.WriteString(f, data) 354 355 b := make([]byte, 5) 356 n, err := f.ReadAt(b, 7) 357 if err != nil || n != len(b) { 358 t.Fatalf("ReadAt 7: %d, %v", n, err) 359 } 360 if string(b) != "world" { 361 t.Fatalf("ReadAt 7: have %q want %q", string(b), "world") 362 } 363 } 364 } 365 366 func TestWriteAt(t *testing.T) { 367 defer removeAllTestFiles(t) 368 for _, fs := range Fss { 369 f := tmpFile(fs) 370 defer f.Close() 371 372 const data = "hello, world\n" 373 io.WriteString(f, data) 374 375 n, err := f.WriteAt([]byte("WORLD"), 7) 376 if err != nil || n != 5 { 377 t.Fatalf("WriteAt 7: %d, %v", n, err) 378 } 379 380 f2, err := fs.Open(f.Name()) 381 if err != nil { 382 t.Fatalf("%v: ReadFile %s: %v", fs.Name(), f.Name(), err) 383 } 384 defer f2.Close() 385 buf := new(bytes.Buffer) 386 buf.ReadFrom(f2) 387 b := buf.Bytes() 388 if string(b) != "hello, WORLD\n" { 389 t.Fatalf("after write: have %q want %q", string(b), "hello, WORLD\n") 390 } 391 392 } 393 } 394 395 func setupTestDir(t *testing.T, fs Fs) string { 396 path := testDir(fs) 397 return setupTestFiles(t, fs, path) 398 } 399 400 func setupTestDirRoot(t *testing.T, fs Fs) string { 401 path := testDir(fs) 402 setupTestFiles(t, fs, path) 403 return path 404 } 405 406 func setupTestDirReusePath(t *testing.T, fs Fs, path string) string { 407 testRegistry[fs] = append(testRegistry[fs], path) 408 return setupTestFiles(t, fs, path) 409 } 410 411 func setupTestFiles(t *testing.T, fs Fs, path string) string { 412 testSubDir := filepath.Join(path, "more", "subdirectories", "for", "testing", "we") 413 err := fs.MkdirAll(testSubDir, 0700) 414 if err != nil && !os.IsExist(err) { 415 t.Fatal(err) 416 } 417 418 f, err := fs.Create(filepath.Join(testSubDir, "testfile1")) 419 if err != nil { 420 t.Fatal(err) 421 } 422 f.WriteString("Testfile 1 content") 423 f.Close() 424 425 f, err = fs.Create(filepath.Join(testSubDir, "testfile2")) 426 if err != nil { 427 t.Fatal(err) 428 } 429 f.WriteString("Testfile 2 content") 430 f.Close() 431 432 f, err = fs.Create(filepath.Join(testSubDir, "testfile3")) 433 if err != nil { 434 t.Fatal(err) 435 } 436 f.WriteString("Testfile 3 content") 437 f.Close() 438 439 f, err = fs.Create(filepath.Join(testSubDir, "testfile4")) 440 if err != nil { 441 t.Fatal(err) 442 } 443 f.WriteString("Testfile 4 content") 444 f.Close() 445 return testSubDir 446 } 447 448 func TestReaddirnames(t *testing.T) { 449 defer removeAllTestFiles(t) 450 for _, fs := range Fss { 451 testSubDir := setupTestDir(t, fs) 452 tDir := filepath.Dir(testSubDir) 453 454 root, err := fs.Open(tDir) 455 if err != nil { 456 t.Fatal(fs.Name(), tDir, err) 457 } 458 defer root.Close() 459 460 namesRoot, err := root.Readdirnames(-1) 461 if err != nil { 462 t.Fatal(fs.Name(), namesRoot, err) 463 } 464 465 sub, err := fs.Open(testSubDir) 466 if err != nil { 467 t.Fatal(err) 468 } 469 defer sub.Close() 470 471 namesSub, err := sub.Readdirnames(-1) 472 if err != nil { 473 t.Fatal(fs.Name(), namesSub, err) 474 } 475 476 findNames(fs, t, tDir, testSubDir, namesRoot, namesSub) 477 } 478 } 479 480 func TestReaddirSimple(t *testing.T) { 481 defer removeAllTestFiles(t) 482 for _, fs := range Fss { 483 testSubDir := setupTestDir(t, fs) 484 tDir := filepath.Dir(testSubDir) 485 486 root, err := fs.Open(tDir) 487 if err != nil { 488 t.Fatal(err) 489 } 490 defer root.Close() 491 492 rootInfo, err := root.Readdir(1) 493 if err != nil { 494 t.Log(myFileInfo(rootInfo)) 495 t.Error(err) 496 } 497 498 rootInfo, err = root.Readdir(5) 499 if err != io.EOF { 500 t.Log(myFileInfo(rootInfo)) 501 t.Error(err) 502 } 503 504 sub, err := fs.Open(testSubDir) 505 if err != nil { 506 t.Fatal(err) 507 } 508 defer sub.Close() 509 510 subInfo, err := sub.Readdir(5) 511 if err != nil { 512 t.Log(myFileInfo(subInfo)) 513 t.Error(err) 514 } 515 } 516 } 517 518 func TestReaddir(t *testing.T) { 519 defer removeAllTestFiles(t) 520 const nums = 6 521 for num := 0; num < nums; num++ { 522 outputs := make([]string, len(Fss)) 523 infos := make([]string, len(Fss)) 524 for i, fs := range Fss { 525 testSubDir := setupTestDir(t, fs) 526 root, err := fs.Open(testSubDir) 527 if err != nil { 528 t.Fatal(err) 529 } 530 531 infosn := make([]string, nums) 532 533 for j := 0; j < nums; j++ { 534 info, err := root.Readdir(num) 535 outputs[i] += fmt.Sprintf("%v Error: %v\n", myFileInfo(info), err) 536 s := fmt.Sprintln(len(info), err) 537 infosn[j] = s 538 infos[i] += s 539 } 540 root.Close() 541 542 // Also check fs.ReadDirFile interface if implemented 543 if _, ok := root.(iofs.ReadDirFile); ok { 544 root, err = fs.Open(testSubDir) 545 if err != nil { 546 t.Fatal(err) 547 } 548 defer root.Close() 549 550 for j := 0; j < nums; j++ { 551 dirEntries, err := root.(iofs.ReadDirFile).ReadDir(num) 552 s := fmt.Sprintln(len(dirEntries), err) 553 if s != infosn[j] { 554 t.Fatalf("%s: %s != %s", fs.Name(), s, infosn[j]) 555 } 556 } 557 } 558 } 559 560 fail := false 561 for i, o := range infos { 562 if i == 0 { 563 continue 564 } 565 if o != infos[i-1] { 566 fail = true 567 break 568 } 569 } 570 if fail { 571 t.Log("Readdir outputs not equal for Readdir(", num, ")") 572 for i, o := range outputs { 573 t.Log(Fss[i].Name()) 574 t.Log(o) 575 } 576 t.Fail() 577 } 578 } 579 } 580 581 // https://github.com/spf13/fsgo/issues/169 582 func TestReaddirRegularFile(t *testing.T) { 583 defer removeAllTestFiles(t) 584 for _, fs := range Fss { 585 f := tmpFile(fs) 586 defer f.Close() 587 588 _, err := f.Readdirnames(-1) 589 if err == nil { 590 t.Fatal("Expected error") 591 } 592 593 _, err = f.Readdir(-1) 594 if err == nil { 595 t.Fatal("Expected error") 596 } 597 } 598 } 599 600 type myFileInfo []os.FileInfo 601 602 func (m myFileInfo) String() string { 603 out := "Fileinfos:\n" 604 for _, e := range m { 605 out += " " + e.Name() + "\n" 606 } 607 return out 608 } 609 610 func TestReaddirAll(t *testing.T) { 611 defer removeAllTestFiles(t) 612 for _, fs := range Fss { 613 testSubDir := setupTestDir(t, fs) 614 tDir := filepath.Dir(testSubDir) 615 616 root, err := fs.Open(tDir) 617 if err != nil { 618 t.Fatal(err) 619 } 620 defer root.Close() 621 622 rootInfo, err := root.Readdir(-1) 623 if err != nil { 624 t.Fatal(err) 625 } 626 var namesRoot = []string{} 627 for _, e := range rootInfo { 628 namesRoot = append(namesRoot, e.Name()) 629 } 630 631 sub, err := fs.Open(testSubDir) 632 if err != nil { 633 t.Fatal(err) 634 } 635 defer sub.Close() 636 637 subInfo, err := sub.Readdir(-1) 638 if err != nil { 639 t.Fatal(err) 640 } 641 var namesSub = []string{} 642 for _, e := range subInfo { 643 namesSub = append(namesSub, e.Name()) 644 } 645 646 findNames(fs, t, tDir, testSubDir, namesRoot, namesSub) 647 } 648 } 649 650 func findNames(fs Fs, t *testing.T, tDir, testSubDir string, root, sub []string) { 651 var foundRoot bool 652 for _, e := range root { 653 f, err := fs.Open(filepath.Join(tDir, e)) 654 if err != nil { 655 t.Error("Open", filepath.Join(tDir, e), ":", err) 656 } 657 defer f.Close() 658 659 if equal(e, "we") { 660 foundRoot = true 661 } 662 } 663 if !foundRoot { 664 t.Logf("Names root: %v", root) 665 t.Logf("Names sub: %v", sub) 666 t.Error("Didn't find subdirectory we") 667 } 668 669 var found1, found2 bool 670 for _, e := range sub { 671 f, err := fs.Open(filepath.Join(testSubDir, e)) 672 if err != nil { 673 t.Error("Open", filepath.Join(testSubDir, e), ":", err) 674 } 675 defer f.Close() 676 677 if equal(e, "testfile1") { 678 found1 = true 679 } 680 if equal(e, "testfile2") { 681 found2 = true 682 } 683 } 684 685 if !found1 { 686 t.Logf("Names root: %v", root) 687 t.Logf("Names sub: %v", sub) 688 t.Error("Didn't find testfile1") 689 } 690 if !found2 { 691 t.Logf("Names root: %v", root) 692 t.Logf("Names sub: %v", sub) 693 t.Error("Didn't find testfile2") 694 } 695 } 696 697 func removeAllTestFiles(t *testing.T) { 698 for fs, list := range testRegistry { 699 for _, path := range list { 700 if err := fs.RemoveAll(path); err != nil { 701 t.Error(fs.Name(), err) 702 } 703 } 704 } 705 testRegistry = make(map[Fs][]string) 706 } 707 708 func equal(name1, name2 string) (r bool) { 709 switch runtime.GOOS { 710 case "windows": 711 r = strings.EqualFold(name1, name2) 712 default: 713 r = name1 == name2 714 } 715 return 716 } 717 718 func checkSize(t *testing.T, f File, size int64) { 719 dir, err := f.Stat() 720 if err != nil { 721 t.Fatalf("Stat %q (looking for size %d): %s", f.Name(), size, err) 722 } 723 if dir.Size() != size { 724 t.Errorf("Stat %q: size %d want %d", f.Name(), dir.Size(), size) 725 } 726 }