github.com/tinygo-org/tinygo@v0.31.3-0.20240404173401-90b0bf646c27/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 "fmt" 9 "io" 10 "os" 11 . "os" 12 "runtime" 13 "strings" 14 "syscall" 15 "testing" 16 ) 17 18 // localTmp returns a local temporary directory not on NFS. 19 func localTmp() string { 20 return TempDir() 21 } 22 23 func newFile(testName string, t *testing.T) (f *File) { 24 f, err := CreateTemp("", testName) 25 if err != nil { 26 t.Fatalf("newFile %s: CreateTemp fails with %s", testName, err) 27 } 28 return 29 } 30 31 // Read with length 0 should not return EOF. 32 func TestRead0(t *testing.T) { 33 f := newFile("TestRead0", t) 34 defer Remove(f.Name()) 35 defer f.Close() 36 37 const data = "hello, world\n" 38 io.WriteString(f, data) 39 f.Close() 40 f, err := Open(f.Name()) 41 if err != nil { 42 t.Errorf("failed to reopen") 43 } 44 45 b := make([]byte, 0) 46 n, err := f.Read(b) 47 if n != 0 || err != nil { 48 t.Errorf("Read(0) = %d, %v, want 0, nil", n, err) 49 } 50 b = make([]byte, 5) 51 n, err = f.Read(b) 52 if n <= 0 || err != nil { 53 t.Errorf("Read(5) = %d, %v, want >0, nil", n, err) 54 } 55 } 56 57 // ReadAt with length 0 should not return EOF. 58 func TestReadAt0(t *testing.T) { 59 if runtime.GOOS == "windows" { 60 t.Log("TODO: implement Pread for Windows") 61 return 62 } 63 f := newFile("TestReadAt0", t) 64 defer Remove(f.Name()) 65 defer f.Close() 66 67 const data = "hello, world\n" 68 io.WriteString(f, data) 69 70 b := make([]byte, 0) 71 n, err := f.ReadAt(b, 0) 72 if n != 0 || err != nil { 73 t.Errorf("ReadAt(0,0) = %d, %v, want 0, nil", n, err) 74 } 75 b = make([]byte, 5) 76 n, err = f.ReadAt(b, 0) 77 if n <= 0 || err != nil { 78 t.Errorf("ReadAt(5,0) = %d, %v, want >0, nil", n, err) 79 } 80 } 81 82 func checkMode(t *testing.T, path string, mode FileMode) { 83 dir, err := Stat(path) 84 if err != nil { 85 t.Fatalf("Stat %q (looking for mode %#o): %s", path, mode, err) 86 } 87 if dir.Mode()&ModePerm != mode { 88 t.Errorf("Stat %q: mode %#o want %#o", path, dir.Mode(), mode) 89 } 90 } 91 92 func TestSeek(t *testing.T) { 93 if runtime.GOARCH == "386" || runtime.GOARCH == "arm" { 94 t.Log("TODO: implement seek for 386 and arm") 95 return 96 } 97 f := newFile("TestSeek", t) 98 if f == nil { 99 t.Fatalf("f is nil") 100 return // TODO: remove 101 } 102 defer Remove(f.Name()) 103 defer f.Close() 104 105 const data = "hello, world\n" 106 io.WriteString(f, data) 107 108 type test struct { 109 in int64 110 whence int 111 out int64 112 } 113 var tests = []test{ 114 {0, io.SeekCurrent, int64(len(data))}, 115 {0, io.SeekStart, 0}, 116 {5, io.SeekStart, 5}, 117 {0, io.SeekEnd, int64(len(data))}, 118 {0, io.SeekStart, 0}, 119 {-1, io.SeekEnd, int64(len(data)) - 1}, 120 {1 << 33, io.SeekStart, 1 << 33}, 121 {1 << 33, io.SeekEnd, 1<<33 + int64(len(data))}, 122 123 // Issue 21681, Windows 4G-1, etc: 124 {1<<32 - 1, io.SeekStart, 1<<32 - 1}, 125 {0, io.SeekCurrent, 1<<32 - 1}, 126 {2<<32 - 1, io.SeekStart, 2<<32 - 1}, 127 {0, io.SeekCurrent, 2<<32 - 1}, 128 } 129 for i, tt := range tests { 130 off, err := f.Seek(tt.in, tt.whence) 131 if off != tt.out || err != nil { 132 if e, ok := err.(*PathError); ok && e.Err == syscall.EINVAL && tt.out > 1<<32 && runtime.GOOS == "linux" { 133 mounts, _ := os.ReadFile("/proc/mounts") 134 if strings.Contains(string(mounts), "reiserfs") { 135 // Reiserfs rejects the big seeks. 136 t.Skipf("skipping test known to fail on reiserfs; https://golang.org/issue/91") 137 } 138 } 139 t.Errorf("#%d: Seek(%v, %v) = %v, %v want %v, nil", i, tt.in, tt.whence, off, err, tt.out) 140 } 141 } 142 } 143 144 func TestReadAt(t *testing.T) { 145 if runtime.GOOS == "windows" { 146 t.Log("TODO: implement Pread for Windows") 147 return 148 } 149 f := newFile("TestReadAt", t) 150 defer Remove(f.Name()) 151 defer f.Close() 152 153 const data = "hello, world\n" 154 io.WriteString(f, data) 155 156 b := make([]byte, 5) 157 n, err := f.ReadAt(b, 7) 158 if err != nil || n != len(b) { 159 t.Fatalf("ReadAt 7: %d, %v", n, err) 160 } 161 if string(b) != "world" { 162 t.Fatalf("ReadAt 7: have %q want %q", string(b), "world") 163 } 164 } 165 166 // Verify that ReadAt doesn't affect seek offset. 167 // In the Plan 9 kernel, there used to be a bug in the implementation of 168 // the pread syscall, where the channel offset was erroneously updated after 169 // calling pread on a file. 170 func TestReadAtOffset(t *testing.T) { 171 if runtime.GOOS == "windows" { 172 t.Log("TODO: implement Pread for Windows") 173 return 174 } 175 f := newFile("TestReadAtOffset", t) 176 defer Remove(f.Name()) 177 defer f.Close() 178 179 const data = "hello, world\n" 180 io.WriteString(f, data) 181 f.Close() 182 f, err := Open(f.Name()) 183 if err != nil { 184 t.Errorf("failed to reopen") 185 } 186 187 b := make([]byte, 5) 188 189 n, err := f.ReadAt(b, 7) 190 if err != nil || n != len(b) { 191 t.Fatalf("ReadAt 7: %d, %v", n, err) 192 } 193 if string(b) != "world" { 194 t.Fatalf("ReadAt 7: have %q want %q", string(b), "world") 195 } 196 197 n, err = f.Read(b) 198 if err != nil || n != len(b) { 199 t.Fatalf("Read: %d, %v", n, err) 200 } 201 if string(b) != "hello" { 202 t.Fatalf("Read: have %q want %q", string(b), "hello") 203 } 204 } 205 206 // Verify that ReadAt doesn't allow negative offset. 207 func TestReadAtNegativeOffset(t *testing.T) { 208 if runtime.GOOS == "windows" { 209 t.Log("TODO: implement Pread for Windows") 210 return 211 } 212 f := newFile("TestReadAtNegativeOffset", t) 213 defer Remove(f.Name()) 214 defer f.Close() 215 216 const data = "hello, world\n" 217 io.WriteString(f, data) 218 f.Close() 219 f, err := Open(f.Name()) 220 if err != nil { 221 t.Errorf("failed to reopen") 222 } 223 224 b := make([]byte, 5) 225 226 n, err := f.ReadAt(b, -10) 227 228 const wantsub = "negative offset" 229 if !strings.Contains(err.Error(), wantsub) || n != 0 { 230 t.Errorf("ReadAt(-10) = %v, %v; want 0, ...%q...", n, err, wantsub) 231 } 232 } 233 234 func TestReadAtEOF(t *testing.T) { 235 if runtime.GOOS == "windows" { 236 t.Log("TODO: implement Pread for Windows") 237 return 238 } 239 f := newFile("TestReadAtEOF", t) 240 defer Remove(f.Name()) 241 defer f.Close() 242 243 _, err := f.ReadAt(make([]byte, 10), 0) 244 switch err { 245 case io.EOF: 246 // all good 247 case nil: 248 t.Fatalf("ReadAt succeeded") 249 default: 250 t.Fatalf("ReadAt failed: %s", err) 251 } 252 } 253 254 func TestWriteAt(t *testing.T) { 255 if runtime.GOOS == "windows" { 256 t.Log("TODO: implement Pwrite for Windows") 257 return 258 } 259 f := newFile("TestWriteAt", t) 260 defer Remove(f.Name()) 261 defer f.Close() 262 263 const data = "hello, world\n" 264 io.WriteString(f, data) 265 266 n, err := f.WriteAt([]byte("WORLD"), 7) 267 if err != nil || n != 5 { 268 t.Fatalf("WriteAt 7: %d, %v", n, err) 269 } 270 271 b, err := os.ReadFile(f.Name()) 272 if err != nil { 273 t.Fatalf("ReadFile %s: %v", f.Name(), err) 274 } 275 if string(b) != "hello, WORLD\n" { 276 t.Fatalf("after write: have %q want %q", string(b), "hello, WORLD\n") 277 } 278 } 279 280 // Verify that WriteAt doesn't allow negative offset. 281 func TestWriteAtNegativeOffset(t *testing.T) { 282 if runtime.GOOS == "windows" { 283 t.Log("TODO: implement Pwrite for Windows") 284 return 285 } 286 f := newFile("TestWriteAtNegativeOffset", t) 287 defer Remove(f.Name()) 288 defer f.Close() 289 290 n, err := f.WriteAt([]byte("WORLD"), -10) 291 292 const wantsub = "negative offset" 293 if !strings.Contains(fmt.Sprint(err), wantsub) || n != 0 { 294 t.Errorf("WriteAt(-10) = %v, %v; want 0, ...%q...", n, err, wantsub) 295 } 296 } 297 298 // Verify that WriteAt doesn't work in append mode. 299 func TestWriteAtInAppendMode(t *testing.T) { 300 if runtime.GOOS == "windows" { 301 t.Log("TODO: implement Pwrite for Windows") 302 return 303 } 304 defer chtmpdir(t)() 305 f, err := OpenFile("write_at_in_append_mode.txt", O_APPEND|O_CREATE|O_WRONLY, 0666) 306 if err != nil { 307 t.Fatalf("OpenFile: %v", err) 308 } 309 defer f.Close() 310 311 _, err = f.WriteAt([]byte(""), 1) 312 if err != ErrWriteAtInAppendMode { 313 t.Fatalf("f.WriteAt returned %v, expected %v", err, ErrWriteAtInAppendMode) 314 } 315 }