github.com/aloncn/graphics-go@v0.0.1/src/os/os_test.go (about) 1 // Copyright 2009 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package os_test 6 7 import ( 8 "bytes" 9 "errors" 10 "flag" 11 "fmt" 12 "internal/testenv" 13 "io" 14 "io/ioutil" 15 . "os" 16 osexec "os/exec" 17 "path/filepath" 18 "reflect" 19 "runtime" 20 "sort" 21 "strings" 22 "sync" 23 "syscall" 24 "testing" 25 "time" 26 ) 27 28 var supportsSymlinks = true 29 30 var dot = []string{ 31 "dir_unix.go", 32 "env.go", 33 "error.go", 34 "file.go", 35 "os_test.go", 36 "types.go", 37 "stat_darwin.go", 38 "stat_linux.go", 39 } 40 41 type sysDir struct { 42 name string 43 files []string 44 } 45 46 var sysdir = func() *sysDir { 47 switch runtime.GOOS { 48 case "android": 49 return &sysDir{ 50 "/system/framework", 51 []string{ 52 "ext.jar", 53 "framework.jar", 54 }, 55 } 56 case "darwin": 57 switch runtime.GOARCH { 58 case "arm", "arm64": 59 wd, err := syscall.Getwd() 60 if err != nil { 61 wd = err.Error() 62 } 63 return &sysDir{ 64 filepath.Join(wd, "..", ".."), 65 []string{ 66 "ResourceRules.plist", 67 "Info.plist", 68 }, 69 } 70 } 71 case "windows": 72 return &sysDir{ 73 Getenv("SystemRoot") + "\\system32\\drivers\\etc", 74 []string{ 75 "networks", 76 "protocol", 77 "services", 78 }, 79 } 80 case "plan9": 81 return &sysDir{ 82 "/lib/ndb", 83 []string{ 84 "common", 85 "local", 86 }, 87 } 88 } 89 return &sysDir{ 90 "/etc", 91 []string{ 92 "group", 93 "hosts", 94 "passwd", 95 }, 96 } 97 }() 98 99 func size(name string, t *testing.T) int64 { 100 file, err := Open(name) 101 if err != nil { 102 t.Fatal("open failed:", err) 103 } 104 defer file.Close() 105 var buf [100]byte 106 len := 0 107 for { 108 n, e := file.Read(buf[0:]) 109 len += n 110 if e == io.EOF { 111 break 112 } 113 if e != nil { 114 t.Fatal("read failed:", err) 115 } 116 } 117 return int64(len) 118 } 119 120 func equal(name1, name2 string) (r bool) { 121 switch runtime.GOOS { 122 case "windows": 123 r = strings.ToLower(name1) == strings.ToLower(name2) 124 default: 125 r = name1 == name2 126 } 127 return 128 } 129 130 // localTmp returns a local temporary directory not on NFS. 131 func localTmp() string { 132 switch runtime.GOOS { 133 case "android", "windows": 134 return TempDir() 135 case "darwin": 136 switch runtime.GOARCH { 137 case "arm", "arm64": 138 return TempDir() 139 } 140 } 141 return "/tmp" 142 } 143 144 func newFile(testName string, t *testing.T) (f *File) { 145 f, err := ioutil.TempFile(localTmp(), "_Go_"+testName) 146 if err != nil { 147 t.Fatalf("TempFile %s: %s", testName, err) 148 } 149 return 150 } 151 152 func newDir(testName string, t *testing.T) (name string) { 153 name, err := ioutil.TempDir(localTmp(), "_Go_"+testName) 154 if err != nil { 155 t.Fatalf("TempDir %s: %s", testName, err) 156 } 157 return 158 } 159 160 var sfdir = sysdir.name 161 var sfname = sysdir.files[0] 162 163 func TestStat(t *testing.T) { 164 path := sfdir + "/" + sfname 165 dir, err := Stat(path) 166 if err != nil { 167 t.Fatal("stat failed:", err) 168 } 169 if !equal(sfname, dir.Name()) { 170 t.Error("name should be ", sfname, "; is", dir.Name()) 171 } 172 filesize := size(path, t) 173 if dir.Size() != filesize { 174 t.Error("size should be", filesize, "; is", dir.Size()) 175 } 176 } 177 178 func TestFstat(t *testing.T) { 179 path := sfdir + "/" + sfname 180 file, err1 := Open(path) 181 if err1 != nil { 182 t.Fatal("open failed:", err1) 183 } 184 defer file.Close() 185 dir, err2 := file.Stat() 186 if err2 != nil { 187 t.Fatal("fstat failed:", err2) 188 } 189 if !equal(sfname, dir.Name()) { 190 t.Error("name should be ", sfname, "; is", dir.Name()) 191 } 192 filesize := size(path, t) 193 if dir.Size() != filesize { 194 t.Error("size should be", filesize, "; is", dir.Size()) 195 } 196 } 197 198 func TestLstat(t *testing.T) { 199 path := sfdir + "/" + sfname 200 dir, err := Lstat(path) 201 if err != nil { 202 t.Fatal("lstat failed:", err) 203 } 204 if !equal(sfname, dir.Name()) { 205 t.Error("name should be ", sfname, "; is", dir.Name()) 206 } 207 filesize := size(path, t) 208 if dir.Size() != filesize { 209 t.Error("size should be", filesize, "; is", dir.Size()) 210 } 211 } 212 213 // Read with length 0 should not return EOF. 214 func TestRead0(t *testing.T) { 215 path := sfdir + "/" + sfname 216 f, err := Open(path) 217 if err != nil { 218 t.Fatal("open failed:", err) 219 } 220 defer f.Close() 221 222 b := make([]byte, 0) 223 n, err := f.Read(b) 224 if n != 0 || err != nil { 225 t.Errorf("Read(0) = %d, %v, want 0, nil", n, err) 226 } 227 b = make([]byte, 100) 228 n, err = f.Read(b) 229 if n <= 0 || err != nil { 230 t.Errorf("Read(100) = %d, %v, want >0, nil", n, err) 231 } 232 } 233 234 func testReaddirnames(dir string, contents []string, t *testing.T) { 235 file, err := Open(dir) 236 if err != nil { 237 t.Fatalf("open %q failed: %v", dir, err) 238 } 239 defer file.Close() 240 s, err2 := file.Readdirnames(-1) 241 if err2 != nil { 242 t.Fatalf("readdirnames %q failed: %v", dir, err2) 243 } 244 for _, m := range contents { 245 found := false 246 for _, n := range s { 247 if n == "." || n == ".." { 248 t.Errorf("got %s in directory", n) 249 } 250 if equal(m, n) { 251 if found { 252 t.Error("present twice:", m) 253 } 254 found = true 255 } 256 } 257 if !found { 258 t.Error("could not find", m) 259 } 260 } 261 } 262 263 func testReaddir(dir string, contents []string, t *testing.T) { 264 file, err := Open(dir) 265 if err != nil { 266 t.Fatalf("open %q failed: %v", dir, err) 267 } 268 defer file.Close() 269 s, err2 := file.Readdir(-1) 270 if err2 != nil { 271 t.Fatalf("readdir %q failed: %v", dir, err2) 272 } 273 for _, m := range contents { 274 found := false 275 for _, n := range s { 276 if equal(m, n.Name()) { 277 if found { 278 t.Error("present twice:", m) 279 } 280 found = true 281 } 282 } 283 if !found { 284 t.Error("could not find", m) 285 } 286 } 287 } 288 289 func TestReaddirnames(t *testing.T) { 290 testReaddirnames(".", dot, t) 291 testReaddirnames(sysdir.name, sysdir.files, t) 292 } 293 294 func TestReaddir(t *testing.T) { 295 testReaddir(".", dot, t) 296 testReaddir(sysdir.name, sysdir.files, t) 297 } 298 299 func benchmarkReaddirname(path string, b *testing.B) { 300 var nentries int 301 for i := 0; i < b.N; i++ { 302 f, err := Open(path) 303 if err != nil { 304 b.Fatalf("open %q failed: %v", path, err) 305 } 306 ns, err := f.Readdirnames(-1) 307 f.Close() 308 if err != nil { 309 b.Fatalf("readdirnames %q failed: %v", path, err) 310 } 311 nentries = len(ns) 312 } 313 b.Logf("benchmarkReaddirname %q: %d entries", path, nentries) 314 } 315 316 func benchmarkReaddir(path string, b *testing.B) { 317 var nentries int 318 for i := 0; i < b.N; i++ { 319 f, err := Open(path) 320 if err != nil { 321 b.Fatalf("open %q failed: %v", path, err) 322 } 323 fs, err := f.Readdir(-1) 324 f.Close() 325 if err != nil { 326 b.Fatalf("readdir %q failed: %v", path, err) 327 } 328 nentries = len(fs) 329 } 330 b.Logf("benchmarkReaddir %q: %d entries", path, nentries) 331 } 332 333 func BenchmarkReaddirname(b *testing.B) { 334 benchmarkReaddirname(".", b) 335 } 336 337 func BenchmarkReaddir(b *testing.B) { 338 benchmarkReaddir(".", b) 339 } 340 341 // Read the directory one entry at a time. 342 func smallReaddirnames(file *File, length int, t *testing.T) []string { 343 names := make([]string, length) 344 count := 0 345 for { 346 d, err := file.Readdirnames(1) 347 if err == io.EOF { 348 break 349 } 350 if err != nil { 351 t.Fatalf("readdirnames %q failed: %v", file.Name(), err) 352 } 353 if len(d) == 0 { 354 t.Fatalf("readdirnames %q returned empty slice and no error", file.Name()) 355 } 356 names[count] = d[0] 357 count++ 358 } 359 return names[0:count] 360 } 361 362 // Check that reading a directory one entry at a time gives the same result 363 // as reading it all at once. 364 func TestReaddirnamesOneAtATime(t *testing.T) { 365 // big directory that doesn't change often. 366 dir := "/usr/bin" 367 switch runtime.GOOS { 368 case "android": 369 dir = "/system/bin" 370 case "darwin": 371 switch runtime.GOARCH { 372 case "arm", "arm64": 373 wd, err := Getwd() 374 if err != nil { 375 t.Fatal(err) 376 } 377 dir = wd 378 } 379 case "plan9": 380 dir = "/bin" 381 case "windows": 382 dir = Getenv("SystemRoot") + "\\system32" 383 } 384 file, err := Open(dir) 385 if err != nil { 386 t.Fatalf("open %q failed: %v", dir, err) 387 } 388 defer file.Close() 389 all, err1 := file.Readdirnames(-1) 390 if err1 != nil { 391 t.Fatalf("readdirnames %q failed: %v", dir, err1) 392 } 393 file1, err2 := Open(dir) 394 if err2 != nil { 395 t.Fatalf("open %q failed: %v", dir, err2) 396 } 397 defer file1.Close() 398 small := smallReaddirnames(file1, len(all)+100, t) // +100 in case we screw up 399 if len(small) < len(all) { 400 t.Fatalf("len(small) is %d, less than %d", len(small), len(all)) 401 } 402 for i, n := range all { 403 if small[i] != n { 404 t.Errorf("small read %q mismatch: %v", small[i], n) 405 } 406 } 407 } 408 409 func TestReaddirNValues(t *testing.T) { 410 if testing.Short() { 411 t.Skip("test.short; skipping") 412 } 413 dir, err := ioutil.TempDir("", "") 414 if err != nil { 415 t.Fatalf("TempDir: %v", err) 416 } 417 defer RemoveAll(dir) 418 for i := 1; i <= 105; i++ { 419 f, err := Create(filepath.Join(dir, fmt.Sprintf("%d", i))) 420 if err != nil { 421 t.Fatalf("Create: %v", err) 422 } 423 f.Write([]byte(strings.Repeat("X", i))) 424 f.Close() 425 } 426 427 var d *File 428 openDir := func() { 429 var err error 430 d, err = Open(dir) 431 if err != nil { 432 t.Fatalf("Open directory: %v", err) 433 } 434 } 435 436 readDirExpect := func(n, want int, wantErr error) { 437 fi, err := d.Readdir(n) 438 if err != wantErr { 439 t.Fatalf("Readdir of %d got error %v, want %v", n, err, wantErr) 440 } 441 if g, e := len(fi), want; g != e { 442 t.Errorf("Readdir of %d got %d files, want %d", n, g, e) 443 } 444 } 445 446 readDirNamesExpect := func(n, want int, wantErr error) { 447 fi, err := d.Readdirnames(n) 448 if err != wantErr { 449 t.Fatalf("Readdirnames of %d got error %v, want %v", n, err, wantErr) 450 } 451 if g, e := len(fi), want; g != e { 452 t.Errorf("Readdirnames of %d got %d files, want %d", n, g, e) 453 } 454 } 455 456 for _, fn := range []func(int, int, error){readDirExpect, readDirNamesExpect} { 457 // Test the slurp case 458 openDir() 459 fn(0, 105, nil) 460 fn(0, 0, nil) 461 d.Close() 462 463 // Slurp with -1 instead 464 openDir() 465 fn(-1, 105, nil) 466 fn(-2, 0, nil) 467 fn(0, 0, nil) 468 d.Close() 469 470 // Test the bounded case 471 openDir() 472 fn(1, 1, nil) 473 fn(2, 2, nil) 474 fn(105, 102, nil) // and tests buffer >100 case 475 fn(3, 0, io.EOF) 476 d.Close() 477 } 478 } 479 480 func touch(t *testing.T, name string) { 481 f, err := Create(name) 482 if err != nil { 483 t.Fatal(err) 484 } 485 if err := f.Close(); err != nil { 486 t.Fatal(err) 487 } 488 } 489 490 func TestReaddirStatFailures(t *testing.T) { 491 switch runtime.GOOS { 492 case "windows", "plan9": 493 // Windows and Plan 9 already do this correctly, 494 // but are structured with different syscalls such 495 // that they don't use Lstat, so the hook below for 496 // testing it wouldn't work. 497 t.Skipf("skipping test on %v", runtime.GOOS) 498 } 499 dir, err := ioutil.TempDir("", "") 500 if err != nil { 501 t.Fatalf("TempDir: %v", err) 502 } 503 defer RemoveAll(dir) 504 touch(t, filepath.Join(dir, "good1")) 505 touch(t, filepath.Join(dir, "x")) // will disappear or have an error 506 touch(t, filepath.Join(dir, "good2")) 507 defer func() { 508 *LstatP = Lstat 509 }() 510 var xerr error // error to return for x 511 *LstatP = func(path string) (FileInfo, error) { 512 if xerr != nil && strings.HasSuffix(path, "x") { 513 return nil, xerr 514 } 515 return Lstat(path) 516 } 517 readDir := func() ([]FileInfo, error) { 518 d, err := Open(dir) 519 if err != nil { 520 t.Fatal(err) 521 } 522 defer d.Close() 523 return d.Readdir(-1) 524 } 525 mustReadDir := func(testName string) []FileInfo { 526 fis, err := readDir() 527 if err != nil { 528 t.Fatalf("%s: Readdir: %v", testName, err) 529 } 530 return fis 531 } 532 names := func(fis []FileInfo) []string { 533 s := make([]string, len(fis)) 534 for i, fi := range fis { 535 s[i] = fi.Name() 536 } 537 sort.Strings(s) 538 return s 539 } 540 541 if got, want := names(mustReadDir("inital readdir")), 542 []string{"good1", "good2", "x"}; !reflect.DeepEqual(got, want) { 543 t.Errorf("initial readdir got %q; want %q", got, want) 544 } 545 546 xerr = ErrNotExist 547 if got, want := names(mustReadDir("with x disappearing")), 548 []string{"good1", "good2"}; !reflect.DeepEqual(got, want) { 549 t.Errorf("with x disappearing, got %q; want %q", got, want) 550 } 551 552 xerr = errors.New("some real error") 553 if _, err := readDir(); err != xerr { 554 t.Errorf("with a non-ErrNotExist error, got error %v; want %v", err, xerr) 555 } 556 } 557 558 // Readdir on a regular file should fail. 559 func TestReaddirOfFile(t *testing.T) { 560 f, err := ioutil.TempFile("", "_Go_ReaddirOfFile") 561 if err != nil { 562 t.Fatal(err) 563 } 564 defer Remove(f.Name()) 565 f.Write([]byte("foo")) 566 f.Close() 567 reg, err := Open(f.Name()) 568 if err != nil { 569 t.Fatal(err) 570 } 571 defer reg.Close() 572 573 names, err := reg.Readdirnames(-1) 574 if err == nil { 575 t.Error("Readdirnames succeeded; want non-nil error") 576 } 577 if len(names) > 0 { 578 t.Errorf("unexpected dir names in regular file: %q", names) 579 } 580 } 581 582 func TestHardLink(t *testing.T) { 583 if runtime.GOOS == "plan9" { 584 t.Skip("skipping on plan9, hardlinks not supported") 585 } 586 // From Android release M (Marshmallow), hard linking files is blocked 587 // and an attempt to call link() on a file will return EACCES. 588 // - https://code.google.com/p/android-developer-preview/issues/detail?id=3150 589 if runtime.GOOS == "android" { 590 t.Skip("skipping on android, hardlinks not supported") 591 } 592 defer chtmpdir(t)() 593 from, to := "hardlinktestfrom", "hardlinktestto" 594 Remove(from) // Just in case. 595 file, err := Create(to) 596 if err != nil { 597 t.Fatalf("open %q failed: %v", to, err) 598 } 599 defer Remove(to) 600 if err = file.Close(); err != nil { 601 t.Errorf("close %q failed: %v", to, err) 602 } 603 err = Link(to, from) 604 if err != nil { 605 t.Fatalf("link %q, %q failed: %v", to, from, err) 606 } 607 608 none := "hardlinktestnone" 609 err = Link(none, none) 610 // Check the returned error is well-formed. 611 if lerr, ok := err.(*LinkError); !ok || lerr.Error() == "" { 612 t.Errorf("link %q, %q failed to return a valid error", none, none) 613 } 614 615 defer Remove(from) 616 tostat, err := Stat(to) 617 if err != nil { 618 t.Fatalf("stat %q failed: %v", to, err) 619 } 620 fromstat, err := Stat(from) 621 if err != nil { 622 t.Fatalf("stat %q failed: %v", from, err) 623 } 624 if !SameFile(tostat, fromstat) { 625 t.Errorf("link %q, %q did not create hard link", to, from) 626 } 627 } 628 629 // chtmpdir changes the working directory to a new temporary directory and 630 // provides a cleanup function. Used when PWD is read-only. 631 func chtmpdir(t *testing.T) func() { 632 if runtime.GOOS != "darwin" || (runtime.GOARCH != "arm" && runtime.GOARCH != "arm64") { 633 return func() {} // only needed on darwin/arm{,64} 634 } 635 oldwd, err := Getwd() 636 if err != nil { 637 t.Fatalf("chtmpdir: %v", err) 638 } 639 d, err := ioutil.TempDir("", "test") 640 if err != nil { 641 t.Fatalf("chtmpdir: %v", err) 642 } 643 if err := Chdir(d); err != nil { 644 t.Fatalf("chtmpdir: %v", err) 645 } 646 return func() { 647 if err := Chdir(oldwd); err != nil { 648 t.Fatalf("chtmpdir: %v", err) 649 } 650 RemoveAll(d) 651 } 652 } 653 654 func TestSymlink(t *testing.T) { 655 switch runtime.GOOS { 656 case "android", "nacl", "plan9": 657 t.Skipf("skipping on %s", runtime.GOOS) 658 case "windows": 659 if !supportsSymlinks { 660 t.Skipf("skipping on %s", runtime.GOOS) 661 } 662 } 663 defer chtmpdir(t)() 664 from, to := "symlinktestfrom", "symlinktestto" 665 Remove(from) // Just in case. 666 file, err := Create(to) 667 if err != nil { 668 t.Fatalf("open %q failed: %v", to, err) 669 } 670 defer Remove(to) 671 if err = file.Close(); err != nil { 672 t.Errorf("close %q failed: %v", to, err) 673 } 674 err = Symlink(to, from) 675 if err != nil { 676 t.Fatalf("symlink %q, %q failed: %v", to, from, err) 677 } 678 defer Remove(from) 679 tostat, err := Lstat(to) 680 if err != nil { 681 t.Fatalf("stat %q failed: %v", to, err) 682 } 683 if tostat.Mode()&ModeSymlink != 0 { 684 t.Fatalf("stat %q claims to have found a symlink", to) 685 } 686 fromstat, err := Stat(from) 687 if err != nil { 688 t.Fatalf("stat %q failed: %v", from, err) 689 } 690 if !SameFile(tostat, fromstat) { 691 t.Errorf("symlink %q, %q did not create symlink", to, from) 692 } 693 fromstat, err = Lstat(from) 694 if err != nil { 695 t.Fatalf("lstat %q failed: %v", from, err) 696 } 697 if fromstat.Mode()&ModeSymlink == 0 { 698 t.Fatalf("symlink %q, %q did not create symlink", to, from) 699 } 700 fromstat, err = Stat(from) 701 if err != nil { 702 t.Fatalf("stat %q failed: %v", from, err) 703 } 704 if fromstat.Mode()&ModeSymlink != 0 { 705 t.Fatalf("stat %q did not follow symlink", from) 706 } 707 s, err := Readlink(from) 708 if err != nil { 709 t.Fatalf("readlink %q failed: %v", from, err) 710 } 711 if s != to { 712 t.Fatalf("after symlink %q != %q", s, to) 713 } 714 file, err = Open(from) 715 if err != nil { 716 t.Fatalf("open %q failed: %v", from, err) 717 } 718 file.Close() 719 } 720 721 func TestLongSymlink(t *testing.T) { 722 switch runtime.GOOS { 723 case "android", "plan9", "nacl": 724 t.Skipf("skipping on %s", runtime.GOOS) 725 case "windows": 726 if !supportsSymlinks { 727 t.Skipf("skipping on %s", runtime.GOOS) 728 } 729 } 730 defer chtmpdir(t)() 731 s := "0123456789abcdef" 732 // Long, but not too long: a common limit is 255. 733 s = s + s + s + s + s + s + s + s + s + s + s + s + s + s + s 734 from := "longsymlinktestfrom" 735 Remove(from) // Just in case. 736 err := Symlink(s, from) 737 if err != nil { 738 t.Fatalf("symlink %q, %q failed: %v", s, from, err) 739 } 740 defer Remove(from) 741 r, err := Readlink(from) 742 if err != nil { 743 t.Fatalf("readlink %q failed: %v", from, err) 744 } 745 if r != s { 746 t.Fatalf("after symlink %q != %q", r, s) 747 } 748 } 749 750 func TestRename(t *testing.T) { 751 defer chtmpdir(t)() 752 from, to := "renamefrom", "renameto" 753 // Ensure we are not testing the overwrite case here. 754 Remove(from) 755 Remove(to) 756 757 file, err := Create(from) 758 if err != nil { 759 t.Fatalf("open %q failed: %v", from, err) 760 } 761 if err = file.Close(); err != nil { 762 t.Errorf("close %q failed: %v", from, err) 763 } 764 err = Rename(from, to) 765 if err != nil { 766 t.Fatalf("rename %q, %q failed: %v", to, from, err) 767 } 768 defer Remove(to) 769 _, err = Stat(to) 770 if err != nil { 771 t.Errorf("stat %q failed: %v", to, err) 772 } 773 } 774 775 func TestRenameOverwriteDest(t *testing.T) { 776 defer chtmpdir(t)() 777 from, to := "renamefrom", "renameto" 778 // Just in case. 779 Remove(from) 780 Remove(to) 781 782 toData := []byte("to") 783 fromData := []byte("from") 784 785 err := ioutil.WriteFile(to, toData, 0777) 786 if err != nil { 787 t.Fatalf("write file %q failed: %v", to, err) 788 } 789 790 err = ioutil.WriteFile(from, fromData, 0777) 791 if err != nil { 792 t.Fatalf("write file %q failed: %v", from, err) 793 } 794 err = Rename(from, to) 795 if err != nil { 796 t.Fatalf("rename %q, %q failed: %v", to, from, err) 797 } 798 defer Remove(to) 799 800 _, err = Stat(from) 801 if err == nil { 802 t.Errorf("from file %q still exists", from) 803 } 804 if err != nil && !IsNotExist(err) { 805 t.Fatalf("stat from: %v", err) 806 } 807 toFi, err := Stat(to) 808 if err != nil { 809 t.Fatalf("stat %q failed: %v", to, err) 810 } 811 if toFi.Size() != int64(len(fromData)) { 812 t.Errorf(`"to" size = %d; want %d (old "from" size)`, toFi.Size(), len(fromData)) 813 } 814 } 815 816 func TestRenameFailed(t *testing.T) { 817 defer chtmpdir(t)() 818 from, to := "renamefrom", "renameto" 819 // Ensure we are not testing the overwrite case here. 820 Remove(from) 821 Remove(to) 822 823 err := Rename(from, to) 824 switch err := err.(type) { 825 case *LinkError: 826 if err.Op != "rename" { 827 t.Errorf("rename %q, %q: err.Op: want %q, got %q", from, to, "rename", err.Op) 828 } 829 if err.Old != from { 830 t.Errorf("rename %q, %q: err.Old: want %q, got %q", from, to, from, err.Old) 831 } 832 if err.New != to { 833 t.Errorf("rename %q, %q: err.New: want %q, got %q", from, to, to, err.New) 834 } 835 case nil: 836 t.Errorf("rename %q, %q: expected error, got nil", from, to) 837 838 // cleanup whatever was placed in "renameto" 839 Remove(to) 840 default: 841 t.Errorf("rename %q, %q: expected %T, got %T %v", from, to, new(LinkError), err, err) 842 } 843 } 844 845 func exec(t *testing.T, dir, cmd string, args []string, expect string) { 846 r, w, err := Pipe() 847 if err != nil { 848 t.Fatalf("Pipe: %v", err) 849 } 850 defer r.Close() 851 attr := &ProcAttr{Dir: dir, Files: []*File{nil, w, Stderr}} 852 p, err := StartProcess(cmd, args, attr) 853 if err != nil { 854 t.Fatalf("StartProcess: %v", err) 855 } 856 w.Close() 857 858 var b bytes.Buffer 859 io.Copy(&b, r) 860 output := b.String() 861 862 fi1, _ := Stat(strings.TrimSpace(output)) 863 fi2, _ := Stat(expect) 864 if !SameFile(fi1, fi2) { 865 t.Errorf("exec %q returned %q wanted %q", 866 strings.Join(append([]string{cmd}, args...), " "), output, expect) 867 } 868 p.Wait() 869 } 870 871 func TestStartProcess(t *testing.T) { 872 testenv.MustHaveExec(t) 873 874 var dir, cmd string 875 var args []string 876 switch runtime.GOOS { 877 case "android": 878 t.Skip("android doesn't have /bin/pwd") 879 case "windows": 880 cmd = Getenv("COMSPEC") 881 dir = Getenv("SystemRoot") 882 args = []string{"/c", "cd"} 883 default: 884 cmd = "/bin/pwd" 885 dir = "/" 886 args = []string{} 887 } 888 cmddir, cmdbase := filepath.Split(cmd) 889 args = append([]string{cmdbase}, args...) 890 // Test absolute executable path. 891 exec(t, dir, cmd, args, dir) 892 // Test relative executable path. 893 exec(t, cmddir, cmdbase, args, cmddir) 894 } 895 896 func checkMode(t *testing.T, path string, mode FileMode) { 897 dir, err := Stat(path) 898 if err != nil { 899 t.Fatalf("Stat %q (looking for mode %#o): %s", path, mode, err) 900 } 901 if dir.Mode()&0777 != mode { 902 t.Errorf("Stat %q: mode %#o want %#o", path, dir.Mode(), mode) 903 } 904 } 905 906 func TestChmod(t *testing.T) { 907 // Chmod is not supported under windows. 908 if runtime.GOOS == "windows" { 909 return 910 } 911 f := newFile("TestChmod", t) 912 defer Remove(f.Name()) 913 defer f.Close() 914 915 if err := Chmod(f.Name(), 0456); err != nil { 916 t.Fatalf("chmod %s 0456: %s", f.Name(), err) 917 } 918 checkMode(t, f.Name(), 0456) 919 920 if err := f.Chmod(0123); err != nil { 921 t.Fatalf("chmod %s 0123: %s", f.Name(), err) 922 } 923 checkMode(t, f.Name(), 0123) 924 } 925 926 func checkSize(t *testing.T, f *File, size int64) { 927 dir, err := f.Stat() 928 if err != nil { 929 t.Fatalf("Stat %q (looking for size %d): %s", f.Name(), size, err) 930 } 931 if dir.Size() != size { 932 t.Errorf("Stat %q: size %d want %d", f.Name(), dir.Size(), size) 933 } 934 } 935 936 func TestFTruncate(t *testing.T) { 937 f := newFile("TestFTruncate", t) 938 defer Remove(f.Name()) 939 defer f.Close() 940 941 checkSize(t, f, 0) 942 f.Write([]byte("hello, world\n")) 943 checkSize(t, f, 13) 944 f.Truncate(10) 945 checkSize(t, f, 10) 946 f.Truncate(1024) 947 checkSize(t, f, 1024) 948 f.Truncate(0) 949 checkSize(t, f, 0) 950 _, err := f.Write([]byte("surprise!")) 951 if err == nil { 952 checkSize(t, f, 13+9) // wrote at offset past where hello, world was. 953 } 954 } 955 956 func TestTruncate(t *testing.T) { 957 f := newFile("TestTruncate", t) 958 defer Remove(f.Name()) 959 defer f.Close() 960 961 checkSize(t, f, 0) 962 f.Write([]byte("hello, world\n")) 963 checkSize(t, f, 13) 964 Truncate(f.Name(), 10) 965 checkSize(t, f, 10) 966 Truncate(f.Name(), 1024) 967 checkSize(t, f, 1024) 968 Truncate(f.Name(), 0) 969 checkSize(t, f, 0) 970 _, err := f.Write([]byte("surprise!")) 971 if err == nil { 972 checkSize(t, f, 13+9) // wrote at offset past where hello, world was. 973 } 974 } 975 976 // Use TempDir (via newFile) to make sure we're on a local file system, 977 // so that timings are not distorted by latency and caching. 978 // On NFS, timings can be off due to caching of meta-data on 979 // NFS servers (Issue 848). 980 func TestChtimes(t *testing.T) { 981 f := newFile("TestChtimes", t) 982 defer Remove(f.Name()) 983 984 f.Write([]byte("hello, world\n")) 985 f.Close() 986 987 testChtimes(t, f.Name()) 988 } 989 990 // Use TempDir (via newDir) to make sure we're on a local file system, 991 // so that timings are not distorted by latency and caching. 992 // On NFS, timings can be off due to caching of meta-data on 993 // NFS servers (Issue 848). 994 func TestChtimesDir(t *testing.T) { 995 name := newDir("TestChtimes", t) 996 defer RemoveAll(name) 997 998 testChtimes(t, name) 999 } 1000 1001 func testChtimes(t *testing.T, name string) { 1002 st, err := Stat(name) 1003 if err != nil { 1004 t.Fatalf("Stat %s: %s", name, err) 1005 } 1006 preStat := st 1007 1008 // Move access and modification time back a second 1009 at := Atime(preStat) 1010 mt := preStat.ModTime() 1011 err = Chtimes(name, at.Add(-time.Second), mt.Add(-time.Second)) 1012 if err != nil { 1013 t.Fatalf("Chtimes %s: %s", name, err) 1014 } 1015 1016 st, err = Stat(name) 1017 if err != nil { 1018 t.Fatalf("second Stat %s: %s", name, err) 1019 } 1020 postStat := st 1021 1022 /* Plan 9, NaCl: 1023 Mtime is the time of the last change of content. Similarly, atime is set whenever the 1024 contents are accessed; also, it is set whenever mtime is set. 1025 */ 1026 pat := Atime(postStat) 1027 pmt := postStat.ModTime() 1028 if !pat.Before(at) && runtime.GOOS != "plan9" && runtime.GOOS != "nacl" { 1029 t.Errorf("AccessTime didn't go backwards; was=%d, after=%d", at, pat) 1030 } 1031 1032 if !pmt.Before(mt) { 1033 t.Errorf("ModTime didn't go backwards; was=%d, after=%d", mt, pmt) 1034 } 1035 } 1036 1037 func TestChdirAndGetwd(t *testing.T) { 1038 // TODO(brainman): file.Chdir() is not implemented on windows. 1039 if runtime.GOOS == "windows" { 1040 return 1041 } 1042 fd, err := Open(".") 1043 if err != nil { 1044 t.Fatalf("Open .: %s", err) 1045 } 1046 // These are chosen carefully not to be symlinks on a Mac 1047 // (unlike, say, /var, /etc), except /tmp, which we handle below. 1048 dirs := []string{"/", "/usr/bin", "/tmp"} 1049 // /usr/bin does not usually exist on Plan 9 or Android. 1050 switch runtime.GOOS { 1051 case "android": 1052 dirs = []string{"/", "/system/bin"} 1053 case "plan9": 1054 dirs = []string{"/", "/usr"} 1055 case "darwin": 1056 switch runtime.GOARCH { 1057 case "arm", "arm64": 1058 d1, err := ioutil.TempDir("", "d1") 1059 if err != nil { 1060 t.Fatalf("TempDir: %v", err) 1061 } 1062 d2, err := ioutil.TempDir("", "d2") 1063 if err != nil { 1064 t.Fatalf("TempDir: %v", err) 1065 } 1066 dirs = []string{d1, d2} 1067 } 1068 } 1069 oldwd := Getenv("PWD") 1070 for mode := 0; mode < 2; mode++ { 1071 for _, d := range dirs { 1072 if mode == 0 { 1073 err = Chdir(d) 1074 } else { 1075 fd1, err := Open(d) 1076 if err != nil { 1077 t.Errorf("Open %s: %s", d, err) 1078 continue 1079 } 1080 err = fd1.Chdir() 1081 fd1.Close() 1082 } 1083 if d == "/tmp" { 1084 Setenv("PWD", "/tmp") 1085 } 1086 pwd, err1 := Getwd() 1087 Setenv("PWD", oldwd) 1088 err2 := fd.Chdir() 1089 if err2 != nil { 1090 // We changed the current directory and cannot go back. 1091 // Don't let the tests continue; they'll scribble 1092 // all over some other directory. 1093 fmt.Fprintf(Stderr, "fchdir back to dot failed: %s\n", err2) 1094 Exit(1) 1095 } 1096 if err != nil { 1097 fd.Close() 1098 t.Fatalf("Chdir %s: %s", d, err) 1099 } 1100 if err1 != nil { 1101 fd.Close() 1102 t.Fatalf("Getwd in %s: %s", d, err1) 1103 } 1104 if pwd != d { 1105 fd.Close() 1106 t.Fatalf("Getwd returned %q want %q", pwd, d) 1107 } 1108 } 1109 } 1110 fd.Close() 1111 } 1112 1113 // Test that Chdir+Getwd is program-wide. 1114 func TestProgWideChdir(t *testing.T) { 1115 const N = 10 1116 c := make(chan bool) 1117 cpwd := make(chan string) 1118 for i := 0; i < N; i++ { 1119 go func(i int) { 1120 // Lock half the goroutines in their own operating system 1121 // thread to exercise more scheduler possibilities. 1122 if i%2 == 1 { 1123 // On Plan 9, after calling LockOSThread, the goroutines 1124 // run on different processes which don't share the working 1125 // directory. This used to be an issue because Go expects 1126 // the working directory to be program-wide. 1127 // See issue 9428. 1128 runtime.LockOSThread() 1129 } 1130 <-c 1131 pwd, err := Getwd() 1132 if err != nil { 1133 t.Errorf("Getwd on goroutine %d: %v", i, err) 1134 return 1135 } 1136 cpwd <- pwd 1137 }(i) 1138 } 1139 oldwd, err := Getwd() 1140 if err != nil { 1141 t.Fatalf("Getwd: %v", err) 1142 } 1143 d, err := ioutil.TempDir("", "test") 1144 if err != nil { 1145 t.Fatalf("TempDir: %v", err) 1146 } 1147 defer func() { 1148 if err := Chdir(oldwd); err != nil { 1149 t.Fatalf("Chdir: %v", err) 1150 } 1151 RemoveAll(d) 1152 }() 1153 if err := Chdir(d); err != nil { 1154 t.Fatalf("Chdir: %v", err) 1155 } 1156 // OS X sets TMPDIR to a symbolic link. 1157 // So we resolve our working directory again before the test. 1158 d, err = Getwd() 1159 if err != nil { 1160 t.Fatalf("Getwd: %v", err) 1161 } 1162 close(c) 1163 for i := 0; i < N; i++ { 1164 pwd := <-cpwd 1165 if pwd != d { 1166 t.Errorf("Getwd returned %q; want %q", pwd, d) 1167 } 1168 } 1169 } 1170 1171 func TestSeek(t *testing.T) { 1172 f := newFile("TestSeek", t) 1173 defer Remove(f.Name()) 1174 defer f.Close() 1175 1176 const data = "hello, world\n" 1177 io.WriteString(f, data) 1178 1179 type test struct { 1180 in int64 1181 whence int 1182 out int64 1183 } 1184 var tests = []test{ 1185 {0, 1, int64(len(data))}, 1186 {0, 0, 0}, 1187 {5, 0, 5}, 1188 {0, 2, int64(len(data))}, 1189 {0, 0, 0}, 1190 {-1, 2, int64(len(data)) - 1}, 1191 {1 << 33, 0, 1 << 33}, 1192 {1 << 33, 2, 1<<33 + int64(len(data))}, 1193 } 1194 for i, tt := range tests { 1195 off, err := f.Seek(tt.in, tt.whence) 1196 if off != tt.out || err != nil { 1197 if e, ok := err.(*PathError); ok && e.Err == syscall.EINVAL && tt.out > 1<<32 { 1198 // Reiserfs rejects the big seeks. 1199 // https://golang.org/issue/91 1200 break 1201 } 1202 t.Errorf("#%d: Seek(%v, %v) = %v, %v want %v, nil", i, tt.in, tt.whence, off, err, tt.out) 1203 } 1204 } 1205 } 1206 1207 type openErrorTest struct { 1208 path string 1209 mode int 1210 error error 1211 } 1212 1213 var openErrorTests = []openErrorTest{ 1214 { 1215 sfdir + "/no-such-file", 1216 O_RDONLY, 1217 syscall.ENOENT, 1218 }, 1219 { 1220 sfdir, 1221 O_WRONLY, 1222 syscall.EISDIR, 1223 }, 1224 { 1225 sfdir + "/" + sfname + "/no-such-file", 1226 O_WRONLY, 1227 syscall.ENOTDIR, 1228 }, 1229 } 1230 1231 func TestOpenError(t *testing.T) { 1232 for _, tt := range openErrorTests { 1233 f, err := OpenFile(tt.path, tt.mode, 0) 1234 if err == nil { 1235 t.Errorf("Open(%q, %d) succeeded", tt.path, tt.mode) 1236 f.Close() 1237 continue 1238 } 1239 perr, ok := err.(*PathError) 1240 if !ok { 1241 t.Errorf("Open(%q, %d) returns error of %T type; want *PathError", tt.path, tt.mode, err) 1242 } 1243 if perr.Err != tt.error { 1244 if runtime.GOOS == "plan9" { 1245 syscallErrStr := perr.Err.Error() 1246 expectedErrStr := strings.Replace(tt.error.Error(), "file ", "", 1) 1247 if !strings.HasSuffix(syscallErrStr, expectedErrStr) { 1248 // Some Plan 9 file servers incorrectly return 1249 // EACCES rather than EISDIR when a directory is 1250 // opened for write. 1251 if tt.error == syscall.EISDIR && strings.HasSuffix(syscallErrStr, syscall.EACCES.Error()) { 1252 continue 1253 } 1254 t.Errorf("Open(%q, %d) = _, %q; want suffix %q", tt.path, tt.mode, syscallErrStr, expectedErrStr) 1255 } 1256 continue 1257 } 1258 if runtime.GOOS == "dragonfly" { 1259 // DragonFly incorrectly returns EACCES rather 1260 // EISDIR when a directory is opened for write. 1261 if tt.error == syscall.EISDIR && perr.Err == syscall.EACCES { 1262 continue 1263 } 1264 } 1265 t.Errorf("Open(%q, %d) = _, %q; want %q", tt.path, tt.mode, perr.Err.Error(), tt.error.Error()) 1266 } 1267 } 1268 } 1269 1270 func TestOpenNoName(t *testing.T) { 1271 f, err := Open("") 1272 if err == nil { 1273 t.Fatal(`Open("") succeeded`) 1274 f.Close() 1275 } 1276 } 1277 1278 func run(t *testing.T, cmd []string) string { 1279 // Run /bin/hostname and collect output. 1280 r, w, err := Pipe() 1281 if err != nil { 1282 t.Fatal(err) 1283 } 1284 defer r.Close() 1285 p, err := StartProcess("/bin/hostname", []string{"hostname"}, &ProcAttr{Files: []*File{nil, w, Stderr}}) 1286 if err != nil { 1287 t.Fatal(err) 1288 } 1289 w.Close() 1290 1291 var b bytes.Buffer 1292 io.Copy(&b, r) 1293 _, err = p.Wait() 1294 if err != nil { 1295 t.Fatalf("run hostname Wait: %v", err) 1296 } 1297 err = p.Kill() 1298 if err == nil { 1299 t.Errorf("expected an error from Kill running 'hostname'") 1300 } 1301 output := b.String() 1302 if n := len(output); n > 0 && output[n-1] == '\n' { 1303 output = output[0 : n-1] 1304 } 1305 if output == "" { 1306 t.Fatalf("%v produced no output", cmd) 1307 } 1308 1309 return output 1310 } 1311 1312 func testWindowsHostname(t *testing.T) { 1313 hostname, err := Hostname() 1314 if err != nil { 1315 t.Fatal(err) 1316 } 1317 cmd := osexec.Command("hostname") 1318 out, err := cmd.CombinedOutput() 1319 if err != nil { 1320 t.Fatalf("Failed to execute hostname command: %v %s", err, out) 1321 } 1322 want := strings.Trim(string(out), "\r\n") 1323 if hostname != want { 1324 t.Fatalf("Hostname() = %q, want %q", hostname, want) 1325 } 1326 } 1327 1328 func TestHostname(t *testing.T) { 1329 // There is no other way to fetch hostname on windows, but via winapi. 1330 // On Plan 9 it can be taken from #c/sysname as Hostname() does. 1331 switch runtime.GOOS { 1332 case "android", "plan9": 1333 t.Skipf("%s doesn't have /bin/hostname", runtime.GOOS) 1334 case "windows": 1335 testWindowsHostname(t) 1336 return 1337 } 1338 1339 testenv.MustHaveExec(t) 1340 1341 // Check internal Hostname() against the output of /bin/hostname. 1342 // Allow that the internal Hostname returns a Fully Qualified Domain Name 1343 // and the /bin/hostname only returns the first component 1344 hostname, err := Hostname() 1345 if err != nil { 1346 t.Fatalf("%v", err) 1347 } 1348 want := run(t, []string{"/bin/hostname"}) 1349 if hostname != want { 1350 i := strings.Index(hostname, ".") 1351 if i < 0 || hostname[0:i] != want { 1352 t.Errorf("Hostname() = %q, want %q", hostname, want) 1353 } 1354 } 1355 } 1356 1357 func TestReadAt(t *testing.T) { 1358 f := newFile("TestReadAt", t) 1359 defer Remove(f.Name()) 1360 defer f.Close() 1361 1362 const data = "hello, world\n" 1363 io.WriteString(f, data) 1364 1365 b := make([]byte, 5) 1366 n, err := f.ReadAt(b, 7) 1367 if err != nil || n != len(b) { 1368 t.Fatalf("ReadAt 7: %d, %v", n, err) 1369 } 1370 if string(b) != "world" { 1371 t.Fatalf("ReadAt 7: have %q want %q", string(b), "world") 1372 } 1373 } 1374 1375 func TestWriteAt(t *testing.T) { 1376 f := newFile("TestWriteAt", t) 1377 defer Remove(f.Name()) 1378 defer f.Close() 1379 1380 const data = "hello, world\n" 1381 io.WriteString(f, data) 1382 1383 n, err := f.WriteAt([]byte("WORLD"), 7) 1384 if err != nil || n != 5 { 1385 t.Fatalf("WriteAt 7: %d, %v", n, err) 1386 } 1387 1388 b, err := ioutil.ReadFile(f.Name()) 1389 if err != nil { 1390 t.Fatalf("ReadFile %s: %v", f.Name(), err) 1391 } 1392 if string(b) != "hello, WORLD\n" { 1393 t.Fatalf("after write: have %q want %q", string(b), "hello, WORLD\n") 1394 } 1395 } 1396 1397 func writeFile(t *testing.T, fname string, flag int, text string) string { 1398 f, err := OpenFile(fname, flag, 0666) 1399 if err != nil { 1400 t.Fatalf("Open: %v", err) 1401 } 1402 n, err := io.WriteString(f, text) 1403 if err != nil { 1404 t.Fatalf("WriteString: %d, %v", n, err) 1405 } 1406 f.Close() 1407 data, err := ioutil.ReadFile(fname) 1408 if err != nil { 1409 t.Fatalf("ReadFile: %v", err) 1410 } 1411 return string(data) 1412 } 1413 1414 func TestAppend(t *testing.T) { 1415 defer chtmpdir(t)() 1416 const f = "append.txt" 1417 defer Remove(f) 1418 s := writeFile(t, f, O_CREATE|O_TRUNC|O_RDWR, "new") 1419 if s != "new" { 1420 t.Fatalf("writeFile: have %q want %q", s, "new") 1421 } 1422 s = writeFile(t, f, O_APPEND|O_RDWR, "|append") 1423 if s != "new|append" { 1424 t.Fatalf("writeFile: have %q want %q", s, "new|append") 1425 } 1426 s = writeFile(t, f, O_CREATE|O_APPEND|O_RDWR, "|append") 1427 if s != "new|append|append" { 1428 t.Fatalf("writeFile: have %q want %q", s, "new|append|append") 1429 } 1430 err := Remove(f) 1431 if err != nil { 1432 t.Fatalf("Remove: %v", err) 1433 } 1434 s = writeFile(t, f, O_CREATE|O_APPEND|O_RDWR, "new&append") 1435 if s != "new&append" { 1436 t.Fatalf("writeFile: after append have %q want %q", s, "new&append") 1437 } 1438 s = writeFile(t, f, O_CREATE|O_RDWR, "old") 1439 if s != "old&append" { 1440 t.Fatalf("writeFile: after create have %q want %q", s, "old&append") 1441 } 1442 s = writeFile(t, f, O_CREATE|O_TRUNC|O_RDWR, "new") 1443 if s != "new" { 1444 t.Fatalf("writeFile: after truncate have %q want %q", s, "new") 1445 } 1446 } 1447 1448 func TestStatDirWithTrailingSlash(t *testing.T) { 1449 // Create new temporary directory and arrange to clean it up. 1450 path, err := ioutil.TempDir("", "/_TestStatDirWithSlash_") 1451 if err != nil { 1452 t.Fatalf("TempDir: %s", err) 1453 } 1454 defer RemoveAll(path) 1455 1456 // Stat of path should succeed. 1457 _, err = Stat(path) 1458 if err != nil { 1459 t.Fatalf("stat %s failed: %s", path, err) 1460 } 1461 1462 // Stat of path+"/" should succeed too. 1463 path += "/" 1464 _, err = Stat(path) 1465 if err != nil { 1466 t.Fatalf("stat %s failed: %s", path, err) 1467 } 1468 } 1469 1470 func TestNilProcessStateString(t *testing.T) { 1471 var ps *ProcessState 1472 s := ps.String() 1473 if s != "<nil>" { 1474 t.Errorf("(*ProcessState)(nil).String() = %q, want %q", s, "<nil>") 1475 } 1476 } 1477 1478 func TestSameFile(t *testing.T) { 1479 defer chtmpdir(t)() 1480 fa, err := Create("a") 1481 if err != nil { 1482 t.Fatalf("Create(a): %v", err) 1483 } 1484 defer Remove(fa.Name()) 1485 fa.Close() 1486 fb, err := Create("b") 1487 if err != nil { 1488 t.Fatalf("Create(b): %v", err) 1489 } 1490 defer Remove(fb.Name()) 1491 fb.Close() 1492 1493 ia1, err := Stat("a") 1494 if err != nil { 1495 t.Fatalf("Stat(a): %v", err) 1496 } 1497 ia2, err := Stat("a") 1498 if err != nil { 1499 t.Fatalf("Stat(a): %v", err) 1500 } 1501 if !SameFile(ia1, ia2) { 1502 t.Errorf("files should be same") 1503 } 1504 1505 ib, err := Stat("b") 1506 if err != nil { 1507 t.Fatalf("Stat(b): %v", err) 1508 } 1509 if SameFile(ia1, ib) { 1510 t.Errorf("files should be different") 1511 } 1512 } 1513 1514 func TestDevNullFile(t *testing.T) { 1515 f, err := Open(DevNull) 1516 if err != nil { 1517 t.Fatalf("Open(%s): %v", DevNull, err) 1518 } 1519 defer f.Close() 1520 fi, err := f.Stat() 1521 if err != nil { 1522 t.Fatalf("Stat(%s): %v", DevNull, err) 1523 } 1524 name := filepath.Base(DevNull) 1525 if fi.Name() != name { 1526 t.Fatalf("wrong file name have %v want %v", fi.Name(), name) 1527 } 1528 if fi.Size() != 0 { 1529 t.Fatalf("wrong file size have %d want 0", fi.Size()) 1530 } 1531 } 1532 1533 var testLargeWrite = flag.Bool("large_write", false, "run TestLargeWriteToConsole test that floods console with output") 1534 1535 func TestLargeWriteToConsole(t *testing.T) { 1536 if !*testLargeWrite { 1537 t.Skip("skipping console-flooding test; enable with -large_write") 1538 } 1539 b := make([]byte, 32000) 1540 for i := range b { 1541 b[i] = '.' 1542 } 1543 b[len(b)-1] = '\n' 1544 n, err := Stdout.Write(b) 1545 if err != nil { 1546 t.Fatalf("Write to os.Stdout failed: %v", err) 1547 } 1548 if n != len(b) { 1549 t.Errorf("Write to os.Stdout should return %d; got %d", len(b), n) 1550 } 1551 n, err = Stderr.Write(b) 1552 if err != nil { 1553 t.Fatalf("Write to os.Stderr failed: %v", err) 1554 } 1555 if n != len(b) { 1556 t.Errorf("Write to os.Stderr should return %d; got %d", len(b), n) 1557 } 1558 } 1559 1560 func TestStatDirModeExec(t *testing.T) { 1561 const mode = 0111 1562 1563 path, err := ioutil.TempDir("", "go-build") 1564 if err != nil { 1565 t.Fatalf("Failed to create temp directory: %v", err) 1566 } 1567 defer RemoveAll(path) 1568 1569 if err := Chmod(path, 0777); err != nil { 1570 t.Fatalf("Chmod %q 0777: %v", path, err) 1571 } 1572 1573 dir, err := Stat(path) 1574 if err != nil { 1575 t.Fatalf("Stat %q (looking for mode %#o): %s", path, mode, err) 1576 } 1577 if dir.Mode()&mode != mode { 1578 t.Errorf("Stat %q: mode %#o want %#o", path, dir.Mode()&mode, mode) 1579 } 1580 } 1581 1582 func TestReadAtEOF(t *testing.T) { 1583 f := newFile("TestReadAtEOF", t) 1584 defer Remove(f.Name()) 1585 defer f.Close() 1586 1587 _, err := f.ReadAt(make([]byte, 10), 0) 1588 switch err { 1589 case io.EOF: 1590 // all good 1591 case nil: 1592 t.Fatalf("ReadAt succeeded") 1593 default: 1594 t.Fatalf("ReadAt failed: %s", err) 1595 } 1596 } 1597 1598 func testKillProcess(t *testing.T, processKiller func(p *Process)) { 1599 testenv.MustHaveExec(t) 1600 1601 // Re-exec the test binary itself to emulate "sleep 1". 1602 cmd := osexec.Command(Args[0], "-test.run", "TestSleep") 1603 err := cmd.Start() 1604 if err != nil { 1605 t.Fatalf("Failed to start test process: %v", err) 1606 } 1607 go func() { 1608 time.Sleep(100 * time.Millisecond) 1609 processKiller(cmd.Process) 1610 }() 1611 err = cmd.Wait() 1612 if err == nil { 1613 t.Errorf("Test process succeeded, but expected to fail") 1614 } 1615 } 1616 1617 // TestSleep emulates "sleep 1". It is a helper for testKillProcess, so we 1618 // don't have to rely on an external "sleep" command being available. 1619 func TestSleep(t *testing.T) { 1620 if testing.Short() { 1621 t.Skip("Skipping in short mode") 1622 } 1623 time.Sleep(time.Second) 1624 } 1625 1626 func TestKillStartProcess(t *testing.T) { 1627 testKillProcess(t, func(p *Process) { 1628 err := p.Kill() 1629 if err != nil { 1630 t.Fatalf("Failed to kill test process: %v", err) 1631 } 1632 }) 1633 } 1634 1635 func TestGetppid(t *testing.T) { 1636 if runtime.GOOS == "plan9" { 1637 // TODO: golang.org/issue/8206 1638 t.Skipf("skipping test on plan9; see issue 8206") 1639 } 1640 1641 testenv.MustHaveExec(t) 1642 1643 if Getenv("GO_WANT_HELPER_PROCESS") == "1" { 1644 fmt.Print(Getppid()) 1645 Exit(0) 1646 } 1647 1648 cmd := osexec.Command(Args[0], "-test.run=TestGetppid") 1649 cmd.Env = append(Environ(), "GO_WANT_HELPER_PROCESS=1") 1650 1651 // verify that Getppid() from the forked process reports our process id 1652 output, err := cmd.CombinedOutput() 1653 if err != nil { 1654 t.Fatalf("Failed to spawn child process: %v %q", err, string(output)) 1655 } 1656 1657 childPpid := string(output) 1658 ourPid := fmt.Sprintf("%d", Getpid()) 1659 if childPpid != ourPid { 1660 t.Fatalf("Child process reports parent process id '%v', expected '%v'", childPpid, ourPid) 1661 } 1662 } 1663 1664 func TestKillFindProcess(t *testing.T) { 1665 testKillProcess(t, func(p *Process) { 1666 p2, err := FindProcess(p.Pid) 1667 if err != nil { 1668 t.Fatalf("Failed to find test process: %v", err) 1669 } 1670 err = p2.Kill() 1671 if err != nil { 1672 t.Fatalf("Failed to kill test process: %v", err) 1673 } 1674 }) 1675 } 1676 1677 var nilFileMethodTests = []struct { 1678 name string 1679 f func(*File) error 1680 }{ 1681 {"Chdir", func(f *File) error { return f.Chdir() }}, 1682 {"Close", func(f *File) error { return f.Close() }}, 1683 {"Chmod", func(f *File) error { return f.Chmod(0) }}, 1684 {"Chown", func(f *File) error { return f.Chown(0, 0) }}, 1685 {"Read", func(f *File) error { _, err := f.Read(make([]byte, 0)); return err }}, 1686 {"ReadAt", func(f *File) error { _, err := f.ReadAt(make([]byte, 0), 0); return err }}, 1687 {"Readdir", func(f *File) error { _, err := f.Readdir(1); return err }}, 1688 {"Readdirnames", func(f *File) error { _, err := f.Readdirnames(1); return err }}, 1689 {"Seek", func(f *File) error { _, err := f.Seek(0, 0); return err }}, 1690 {"Stat", func(f *File) error { _, err := f.Stat(); return err }}, 1691 {"Sync", func(f *File) error { return f.Sync() }}, 1692 {"Truncate", func(f *File) error { return f.Truncate(0) }}, 1693 {"Write", func(f *File) error { _, err := f.Write(make([]byte, 0)); return err }}, 1694 {"WriteAt", func(f *File) error { _, err := f.WriteAt(make([]byte, 0), 0); return err }}, 1695 {"WriteString", func(f *File) error { _, err := f.WriteString(""); return err }}, 1696 } 1697 1698 // Test that all File methods give ErrInvalid if the receiver is nil. 1699 func TestNilFileMethods(t *testing.T) { 1700 for _, tt := range nilFileMethodTests { 1701 var file *File 1702 got := tt.f(file) 1703 if got != ErrInvalid { 1704 t.Errorf("%v should fail when f is nil; got %v", tt.name, got) 1705 } 1706 } 1707 } 1708 1709 func mkdirTree(t *testing.T, root string, level, max int) { 1710 if level >= max { 1711 return 1712 } 1713 level++ 1714 for i := 'a'; i < 'c'; i++ { 1715 dir := filepath.Join(root, string(i)) 1716 if err := Mkdir(dir, 0700); err != nil { 1717 t.Fatal(err) 1718 } 1719 mkdirTree(t, dir, level, max) 1720 } 1721 } 1722 1723 // Test that simultaneous RemoveAll do not report an error. 1724 // As long as it gets removed, we should be happy. 1725 func TestRemoveAllRace(t *testing.T) { 1726 if runtime.GOOS == "windows" { 1727 // Windows has very strict rules about things like 1728 // removing directories while someone else has 1729 // them open. The racing doesn't work out nicely 1730 // like it does on Unix. 1731 t.Skip("skipping on windows") 1732 } 1733 1734 n := runtime.GOMAXPROCS(16) 1735 defer runtime.GOMAXPROCS(n) 1736 root, err := ioutil.TempDir("", "issue") 1737 if err != nil { 1738 t.Fatal(err) 1739 } 1740 mkdirTree(t, root, 1, 6) 1741 hold := make(chan struct{}) 1742 var wg sync.WaitGroup 1743 for i := 0; i < 4; i++ { 1744 wg.Add(1) 1745 go func() { 1746 defer wg.Done() 1747 <-hold 1748 err := RemoveAll(root) 1749 if err != nil { 1750 t.Errorf("unexpected error: %T, %q", err, err) 1751 } 1752 }() 1753 } 1754 close(hold) // let workers race to remove root 1755 wg.Wait() 1756 }