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