github.com/gnolang/gno@v0.0.0-20240520182011-228e9d0192ce/gnovm/stdlibs/io/io_test.gno (about) 1 package io_test 2 3 // Copyright 2009 The Go Authors. All rights reserved. 4 // Use of this source code is governed by a BSD-style 5 // license that can be found in the LICENSE file. 6 7 import ( 8 "bytes" 9 "errors" 10 "fmt" 11 "io" 12 "os" 13 "strings" 14 "testing" 15 ) 16 17 // A version of bytes.Buffer without ReadFrom and WriteTo 18 type Buffer struct { 19 bytes.Buffer 20 io.ReaderFrom // conflicts with and hides bytes.Buffer's ReaderFrom. 21 io.WriterTo // conflicts with and hides bytes.Buffer's WriterTo. 22 } 23 24 // Simple tests, primarily to verify the ReadFrom and WriteTo callouts inside Copy, CopyBuffer and CopyN. 25 26 func TestCopy(t *testing.T) { 27 rb := new(Buffer) 28 wb := new(Buffer) 29 rb.WriteString("hello, world.") 30 io.Copy(wb, rb) 31 if wb.String() != "hello, world." { 32 t.Errorf("Copy did not work properly") 33 } 34 } 35 36 func TestCopyNegative(t *testing.T) { 37 rb := new(Buffer) 38 wb := new(Buffer) 39 rb.WriteString("hello") 40 io.Copy(wb, &io.LimitedReader{R: rb, N: -1}) 41 if wb.String() != "" { 42 t.Errorf("Copy on LimitedReader with N<0 copied data") 43 } 44 45 io.CopyN(wb, rb, -1) 46 if wb.String() != "" { 47 t.Errorf("CopyN with N<0 copied data") 48 } 49 } 50 51 func TestCopyBuffer(t *testing.T) { 52 rb := new(Buffer) 53 wb := new(Buffer) 54 rb.WriteString("hello, world.") 55 io.CopyBuffer(wb, rb, make([]byte, 1)) // Tiny buffer to keep it honest. 56 if wb.String() != "hello, world." { 57 t.Errorf("CopyBuffer did not work properly") 58 } 59 } 60 61 func TestCopyBufferNil(t *testing.T) { 62 rb := new(Buffer) 63 wb := new(Buffer) 64 rb.WriteString("hello, world.") 65 io.CopyBuffer(wb, rb, nil) // Should allocate a buffer. 66 if wb.String() != "hello, world." { 67 t.Errorf("CopyBuffer did not work properly") 68 } 69 } 70 71 func TestCopyReadFrom(t *testing.T) { 72 rb := new(Buffer) 73 wb := new(bytes.Buffer) // implements ReadFrom. 74 rb.WriteString("hello, world.") 75 io.Copy(wb, rb) 76 if wb.String() != "hello, world." { 77 t.Errorf("Copy did not work properly") 78 } 79 } 80 81 func TestCopyWriteTo(t *testing.T) { 82 rb := new(bytes.Buffer) // implements WriteTo. 83 wb := new(Buffer) 84 rb.WriteString("hello, world.") 85 io.Copy(wb, rb) 86 if wb.String() != "hello, world." { 87 t.Errorf("Copy did not work properly") 88 } 89 } 90 91 // Version of bytes.Buffer that checks whether WriteTo was called or not 92 type writeToChecker struct { 93 bytes.Buffer 94 writeToCalled bool 95 } 96 97 func (wt *writeToChecker) WriteTo(w io.Writer) (int64, error) { 98 wt.writeToCalled = true 99 return wt.Buffer.WriteTo(w) 100 } 101 102 // It's preferable to choose WriterTo over ReaderFrom, since a WriterTo can issue one large write, 103 // while the ReaderFrom must read until EOF, potentially allocating when running out of buffer. 104 // Make sure that we choose WriterTo when both are implemented. 105 func TestCopyPriority(t *testing.T) { 106 rb := new(writeToChecker) 107 wb := new(bytes.Buffer) 108 rb.WriteString("hello, world.") 109 io.Copy(wb, rb) 110 if wb.String() != "hello, world." { 111 t.Errorf("Copy did not work properly") 112 } else if !rb.writeToCalled { 113 t.Errorf("WriteTo was not prioritized over ReadFrom") 114 } 115 } 116 117 type zeroErrReader struct { 118 err error 119 } 120 121 func (r zeroErrReader) Read(p []byte) (int, error) { 122 return copy(p, []byte{0}), r.err 123 } 124 125 type errWriter struct { 126 err error 127 } 128 129 func (w errWriter) Write([]byte) (int, error) { 130 return 0, w.err 131 } 132 133 // In case a Read results in an error with non-zero bytes read, and 134 // the subsequent Write also results in an error, the error from Write 135 // is returned, as it is the one that prevented progressing further. 136 func TestCopyReadErrWriteErr(t *testing.T) { 137 er, ew := errors.New("readError"), errors.New("writeError") 138 r, w := zeroErrReader{err: er}, errWriter{err: ew} 139 n, err := io.Copy(w, r) 140 if n != 0 || err != ew { 141 t.Errorf("Copy(zeroErrReader, errWriter) = %d, %v; want 0, writeError", n, err) 142 } 143 } 144 145 func TestCopyN(t *testing.T) { 146 rb := new(Buffer) 147 wb := new(Buffer) 148 rb.WriteString("hello, world.") 149 io.CopyN(wb, rb, 5) 150 if wb.String() != "hello" { 151 t.Errorf("CopyN did not work properly") 152 } 153 } 154 155 func TestCopyNReadFrom(t *testing.T) { 156 rb := new(Buffer) 157 wb := new(bytes.Buffer) // implements ReadFrom. 158 rb.WriteString("hello") 159 io.CopyN(wb, rb, 5) 160 if wb.String() != "hello" { 161 t.Errorf("CopyN did not work properly") 162 } 163 } 164 165 func TestCopyNWriteTo(t *testing.T) { 166 rb := new(bytes.Buffer) // implements WriteTo. 167 wb := new(Buffer) 168 rb.WriteString("hello, world.") 169 io.CopyN(wb, rb, 5) 170 if wb.String() != "hello" { 171 t.Errorf("CopyN did not work properly") 172 } 173 } 174 175 func BenchmarkCopyNSmall(b *testing.B) { 176 bs := bytes.Repeat([]byte{0}, 512+1) 177 rd := bytes.NewReader(bs) 178 buf := new(Buffer) 179 b.ResetTimer() 180 181 for i := 0; i < b.N; i++ { 182 io.CopyN(buf, rd, 512) 183 rd.Reset(bs) 184 } 185 } 186 187 func BenchmarkCopyNLarge(b *testing.B) { 188 bs := bytes.Repeat([]byte{0}, (32*1024)+1) 189 rd := bytes.NewReader(bs) 190 buf := new(Buffer) 191 b.ResetTimer() 192 193 for i := 0; i < b.N; i++ { 194 io.CopyN(buf, rd, 32*1024) 195 rd.Reset(bs) 196 } 197 } 198 199 type noReadFrom struct { 200 w io.Writer 201 } 202 203 func (w *noReadFrom) Write(p []byte) (n int, err error) { 204 return w.w.Write(p) 205 } 206 207 type wantedAndErrReader struct{} 208 209 func (wantedAndErrReader) Read(p []byte) (int, error) { 210 return len(p), errors.New("wantedAndErrReader error") 211 } 212 213 func TestCopyNEOF(t *testing.T) { 214 // Test that EOF behavior is the same regardless of whether 215 // argument to CopyN has ReadFrom. 216 217 b := new(bytes.Buffer) 218 219 n, err := io.CopyN(&noReadFrom{b}, strings.NewReader("foo"), 3) 220 if n != 3 || err != nil { 221 t.Errorf("CopyN(noReadFrom, foo, 3) = %d, %v; want 3, nil", n, err) 222 } 223 224 n, err = io.CopyN(&noReadFrom{b}, strings.NewReader("foo"), 4) 225 if n != 3 || err != io.EOF { 226 t.Errorf("CopyN(noReadFrom, foo, 4) = %d, %v; want 3, EOF", n, err) 227 } 228 229 n, err = io.CopyN(b, strings.NewReader("foo"), 3) // b has read from 230 if n != 3 || err != nil { 231 t.Errorf("CopyN(bytes.Buffer, foo, 3) = %d, %v; want 3, nil", n, err) 232 } 233 234 n, err = io.CopyN(b, strings.NewReader("foo"), 4) // b has read from 235 if n != 3 || err != io.EOF { 236 t.Errorf("CopyN(bytes.Buffer, foo, 4) = %d, %v; want 3, EOF", n, err) 237 } 238 239 n, err = io.CopyN(b, wantedAndErrReader{}, 5) 240 if n != 5 || err != nil { 241 t.Errorf("CopyN(bytes.Buffer, wantedAndErrReader, 5) = %d, %v; want 5, nil", n, err) 242 } 243 244 n, err = io.CopyN(&noReadFrom{b}, wantedAndErrReader{}, 5) 245 if n != 5 || err != nil { 246 t.Errorf("CopyN(noReadFrom, wantedAndErrReader, 5) = %d, %v; want 5, nil", n, err) 247 } 248 } 249 250 func TestReadAtLeast(t *testing.T) { 251 var rb bytes.Buffer 252 testReadAtLeast(t, &rb) 253 } 254 255 // A version of bytes.Buffer that returns n > 0, err on Read 256 // when the input is exhausted. 257 type dataAndErrorBuffer struct { 258 err error 259 bytes.Buffer 260 } 261 262 func (r *dataAndErrorBuffer) Read(p []byte) (n int, err error) { 263 n, err = r.Buffer.Read(p) 264 if n > 0 && r.Buffer.Len() == 0 && err == nil { 265 err = r.err 266 } 267 return 268 } 269 270 func TestReadAtLeastWithDataAndEOF(t *testing.T) { 271 var rb dataAndErrorBuffer 272 rb.err = io.EOF 273 testReadAtLeast(t, &rb) 274 } 275 276 func TestReadAtLeastWithDataAndError(t *testing.T) { 277 var rb dataAndErrorBuffer 278 rb.err = fmt.Errorf("fake error") 279 testReadAtLeast(t, &rb) 280 } 281 282 func testReadAtLeast(t *testing.T, rb io.ReadWriter) { 283 rb.Write([]byte("0123")) 284 buf := make([]byte, 2) 285 n, err := io.ReadAtLeast(rb, buf, 2) 286 if err != nil { 287 t.Error(err) 288 } 289 if n != 2 { 290 t.Errorf("expected to have read 2 bytes, got %v", n) 291 } 292 n, err = io.ReadAtLeast(rb, buf, 4) 293 if err != io.ErrShortBuffer { 294 t.Errorf("expected ErrShortBuffer got %v", err) 295 } 296 if n != 0 { 297 t.Errorf("expected to have read 0 bytes, got %v", n) 298 } 299 n, err = io.ReadAtLeast(rb, buf, 1) 300 if err != nil { 301 t.Error(err) 302 } 303 if n != 2 { 304 t.Errorf("expected to have read 2 bytes, got %v", n) 305 } 306 n, err = io.ReadAtLeast(rb, buf, 2) 307 if err != io.EOF { 308 t.Errorf("expected EOF, got %v", err) 309 } 310 if n != 0 { 311 t.Errorf("expected to have read 0 bytes, got %v", n) 312 } 313 rb.Write([]byte("4")) 314 n, err = io.ReadAtLeast(rb, buf, 2) 315 want := io.ErrUnexpectedEOF 316 if rb, ok := rb.(*dataAndErrorBuffer); ok && rb.err != io.EOF { 317 want = rb.err 318 } 319 if err != want { 320 t.Errorf("expected %v, got %v", want, err) 321 } 322 if n != 1 { 323 t.Errorf("expected to have read 1 bytes, got %v", n) 324 } 325 } 326 327 /* XXX no io.Pipe() no chan 328 func TestTeeReader(t *testing.T) { 329 src := []byte("hello, world") 330 dst := make([]byte, len(src)) 331 rb := bytes.NewBuffer(src) 332 wb := new(bytes.Buffer) 333 r := io.TeeReader(rb, wb) 334 if n, err := io.ReadFull(r, dst); err != nil || n != len(src) { 335 t.Fatalf("ReadFull(r, dst) = %d, %v; want %d, nil", n, err, len(src)) 336 } 337 if !bytes.Equal(dst, src) { 338 t.Errorf("bytes read = %q want %q", dst, src) 339 } 340 if !bytes.Equal(wb.Bytes(), src) { 341 t.Errorf("bytes written = %q want %q", wb.Bytes(), src) 342 } 343 if n, err := r.Read(dst); n != 0 || err != io.EOF { 344 t.Errorf("r.Read at EOF = %d, %v want 0, EOF", n, err) 345 } 346 rb = bytes.NewBuffer(src) 347 pr, pw := io.Pipe() 348 pr.Close() 349 r = io.TeeReader(rb, pw) 350 if n, err := io.ReadFull(r, dst); n != 0 || err != io.ErrClosedPipe { 351 t.Errorf("closed tee: ReadFull(r, dst) = %d, %v; want 0, EPIPE", n, err) 352 } 353 } 354 */ 355 356 func TestSectionReader_ReadAt(t *testing.T) { 357 dat := "a long sample data, 1234567890" 358 tests := []struct { 359 data string 360 off int 361 n int 362 bufLen int 363 at int 364 exp string 365 err error 366 }{ 367 {data: "", off: 0, n: 10, bufLen: 2, at: 0, exp: "", err: io.EOF}, 368 {data: dat, off: 0, n: len(dat), bufLen: 0, at: 0, exp: "", err: nil}, 369 {data: dat, off: len(dat), n: 1, bufLen: 1, at: 0, exp: "", err: io.EOF}, 370 {data: dat, off: 0, n: len(dat) + 2, bufLen: len(dat), at: 0, exp: dat, err: nil}, 371 {data: dat, off: 0, n: len(dat), bufLen: len(dat) / 2, at: 0, exp: dat[:len(dat)/2], err: nil}, 372 {data: dat, off: 0, n: len(dat), bufLen: len(dat), at: 0, exp: dat, err: nil}, 373 {data: dat, off: 0, n: len(dat), bufLen: len(dat) / 2, at: 2, exp: dat[2 : 2+len(dat)/2], err: nil}, 374 {data: dat, off: 3, n: len(dat), bufLen: len(dat) / 2, at: 2, exp: dat[5 : 5+len(dat)/2], err: nil}, 375 {data: dat, off: 3, n: len(dat) / 2, bufLen: len(dat)/2 - 2, at: 2, exp: dat[5 : 5+len(dat)/2-2], err: nil}, 376 {data: dat, off: 3, n: len(dat) / 2, bufLen: len(dat)/2 + 2, at: 2, exp: dat[5 : 5+len(dat)/2-2], err: io.EOF}, 377 {data: dat, off: 0, n: 0, bufLen: 0, at: -1, exp: "", err: io.EOF}, 378 {data: dat, off: 0, n: 0, bufLen: 0, at: 1, exp: "", err: io.EOF}, 379 } 380 for i, tt := range tests { 381 r := strings.NewReader(tt.data) 382 s := io.NewSectionReader(r, int64(tt.off), int64(tt.n)) 383 buf := make([]byte, tt.bufLen) 384 if n, err := s.ReadAt(buf, int64(tt.at)); n != len(tt.exp) || string(buf[:n]) != tt.exp || err != tt.err { 385 t.Fatalf("%d: ReadAt(%d) = %q, %v; expected %q, %v", i, tt.at, buf[:n], err, tt.exp, tt.err) 386 } 387 } 388 } 389 390 func TestSectionReader_Seek(t *testing.T) { 391 // Verifies that NewSectionReader's Seeker behaves like bytes.NewReader (which is like strings.NewReader) 392 br := bytes.NewReader([]byte("foo")) 393 sr := io.NewSectionReader(br, 0, int64(len("foo"))) 394 395 for _, whence := range []int{io.SeekStart, io.SeekCurrent, io.SeekEnd} { 396 for offset := int64(-3); offset <= 4; offset++ { 397 brOff, brErr := br.Seek(offset, whence) 398 srOff, srErr := sr.Seek(offset, whence) 399 if (brErr != nil) != (srErr != nil) || brOff != srOff { 400 t.Errorf("For whence %d, offset %d: bytes.Reader.Seek = (%v, %v) != SectionReader.Seek = (%v, %v)", 401 whence, offset, brOff, brErr, srErr, srOff) 402 } 403 } 404 } 405 406 // And verify we can just seek past the end and get an EOF 407 got, err := sr.Seek(100, io.SeekStart) 408 if err != nil || got != 100 { 409 t.Errorf("Seek = %v, %v; want 100, nil", got, err) 410 } 411 412 n, err := sr.Read(make([]byte, 10)) 413 if n != 0 || err != io.EOF { 414 t.Errorf("Read = %v, %v; want 0, EOF", n, err) 415 } 416 } 417 418 func TestSectionReader_Size(t *testing.T) { 419 tests := []struct { 420 data string 421 want int64 422 }{ 423 {"a long sample data, 1234567890", 30}, 424 {"", 0}, 425 } 426 427 for _, tt := range tests { 428 r := strings.NewReader(tt.data) 429 sr := io.NewSectionReader(r, 0, int64(len(tt.data))) 430 if got := sr.Size(); got != tt.want { 431 t.Errorf("Size = %v; want %v", got, tt.want) 432 } 433 } 434 } 435 436 // largeWriter returns an invalid count that is larger than the number 437 // of bytes provided (issue 39978). 438 type largeWriter struct { 439 err error 440 } 441 442 func (w largeWriter) Write(p []byte) (int, error) { 443 return len(p) + 1, w.err 444 } 445 446 func TestCopyLargeWriter(t *testing.T) { 447 want := io.ErrInvalidWrite 448 rb := new(Buffer) 449 wb := largeWriter{} 450 rb.WriteString("hello, world.") 451 if _, err := io.Copy(wb, rb); err != want { 452 t.Errorf("Copy error: got %v, want %v", err, want) 453 } 454 455 want = errors.New("largeWriterError") 456 rb = new(Buffer) 457 wb = largeWriter{err: want} 458 rb.WriteString("hello, world.") 459 if _, err := io.Copy(wb, rb); err != want { 460 t.Errorf("Copy error: got %v, want %v", err, want) 461 } 462 } 463 464 func TestNopCloserWriterToForwarding(t *testing.T) { 465 for _, tc := range [...]struct { 466 Name string 467 r io.Reader 468 }{ 469 {"not a WriterTo", io.Reader(nil)}, 470 {"a WriterTo", struct { 471 io.Reader 472 io.WriterTo 473 }{}}, 474 } { 475 nc := io.NopCloser(tc.r) 476 477 _, expected := tc.r.(io.WriterTo) 478 _, got := nc.(io.WriterTo) 479 if expected != got { 480 t.Errorf("NopCloser incorrectly forwards WriterTo for %s, got %t want %t", tc.Name, got, expected) 481 } 482 } 483 } 484 485 // XXX os.CreateTemp is not available for now 486 // func TestOffsetWriter_Seek(t *testing.T) { 487 // tmpfilename := "TestOffsetWriter_Seek" 488 // tmpfile, err := os.CreateTemp(t.TempDir(), tmpfilename) 489 // if err != nil || tmpfile == nil { 490 // t.Fatalf("CreateTemp(%s) failed: %v", tmpfilename, err) 491 // } 492 // defer tmpfile.Close() 493 // w := NewOffsetWriter(tmpfile, 0) 494 495 // // Should throw error errWhence if whence is not valid 496 // t.Run("errWhence", func(t *testing.T) { 497 // for _, whence := range []int{-3, -2, -1, 3, 4, 5} { 498 // var offset int64 = 0 499 // gotOff, gotErr := w.Seek(offset, whence) 500 // if gotOff != 0 || gotErr != ErrWhence { 501 // t.Errorf("For whence %d, offset %d, OffsetWriter.Seek got: (%d, %v), want: (%d, %v)", 502 // whence, offset, gotOff, gotErr, 0, ErrWhence) 503 // } 504 // } 505 // }) 506 507 // // Should throw error errOffset if offset is negative 508 // t.Run("errOffset", func(t *testing.T) { 509 // for _, whence := range []int{SeekStart, SeekCurrent} { 510 // for offset := int64(-3); offset < 0; offset++ { 511 // gotOff, gotErr := w.Seek(offset, whence) 512 // if gotOff != 0 || gotErr != ErrOffset { 513 // t.Errorf("For whence %d, offset %d, OffsetWriter.Seek got: (%d, %v), want: (%d, %v)", 514 // whence, offset, gotOff, gotErr, 0, ErrOffset) 515 // } 516 // } 517 // } 518 // }) 519 520 // // Normal tests 521 // t.Run("normal", func(t *testing.T) { 522 // tests := []struct { 523 // offset int64 524 // whence int 525 // returnOff int64 526 // }{ 527 // // keep in order 528 // {whence: SeekStart, offset: 1, returnOff: 1}, 529 // {whence: SeekStart, offset: 2, returnOff: 2}, 530 // {whence: SeekStart, offset: 3, returnOff: 3}, 531 // {whence: SeekCurrent, offset: 1, returnOff: 4}, 532 // {whence: SeekCurrent, offset: 2, returnOff: 6}, 533 // {whence: SeekCurrent, offset: 3, returnOff: 9}, 534 // } 535 // for idx, tt := range tests { 536 // gotOff, gotErr := w.Seek(tt.offset, tt.whence) 537 // if gotOff != tt.returnOff || gotErr != nil { 538 // t.Errorf("%d:: For whence %d, offset %d, OffsetWriter.Seek got: (%d, %v), want: (%d, <nil>)", 539 // idx+1, tt.whence, tt.offset, gotOff, gotErr, tt.returnOff) 540 // } 541 // } 542 // }) 543 // }