github.com/ice-blockchain/go/src@v0.0.0-20240403114104-1564d284e521/io/io_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 io_test 6 7 import ( 8 "bytes" 9 "errors" 10 "fmt" 11 . "io" 12 "os" 13 "strings" 14 "sync" 15 "sync/atomic" 16 "testing" 17 ) 18 19 // A version of bytes.Buffer without ReadFrom and WriteTo 20 type Buffer struct { 21 bytes.Buffer 22 ReaderFrom // conflicts with and hides bytes.Buffer's ReaderFrom. 23 WriterTo // conflicts with and hides bytes.Buffer's WriterTo. 24 } 25 26 // Simple tests, primarily to verify the ReadFrom and WriteTo callouts inside Copy, CopyBuffer and CopyN. 27 28 func TestCopy(t *testing.T) { 29 rb := new(Buffer) 30 wb := new(Buffer) 31 rb.WriteString("hello, world.") 32 Copy(wb, rb) 33 if wb.String() != "hello, world." { 34 t.Errorf("Copy did not work properly") 35 } 36 } 37 38 func TestCopyNegative(t *testing.T) { 39 rb := new(Buffer) 40 wb := new(Buffer) 41 rb.WriteString("hello") 42 Copy(wb, &LimitedReader{R: rb, N: -1}) 43 if wb.String() != "" { 44 t.Errorf("Copy on LimitedReader with N<0 copied data") 45 } 46 47 CopyN(wb, rb, -1) 48 if wb.String() != "" { 49 t.Errorf("CopyN with N<0 copied data") 50 } 51 } 52 53 func TestCopyBuffer(t *testing.T) { 54 rb := new(Buffer) 55 wb := new(Buffer) 56 rb.WriteString("hello, world.") 57 CopyBuffer(wb, rb, make([]byte, 1)) // Tiny buffer to keep it honest. 58 if wb.String() != "hello, world." { 59 t.Errorf("CopyBuffer did not work properly") 60 } 61 } 62 63 func TestCopyBufferNil(t *testing.T) { 64 rb := new(Buffer) 65 wb := new(Buffer) 66 rb.WriteString("hello, world.") 67 CopyBuffer(wb, rb, nil) // Should allocate a buffer. 68 if wb.String() != "hello, world." { 69 t.Errorf("CopyBuffer did not work properly") 70 } 71 } 72 73 func TestCopyReadFrom(t *testing.T) { 74 rb := new(Buffer) 75 wb := new(bytes.Buffer) // implements ReadFrom. 76 rb.WriteString("hello, world.") 77 Copy(wb, rb) 78 if wb.String() != "hello, world." { 79 t.Errorf("Copy did not work properly") 80 } 81 } 82 83 func TestCopyWriteTo(t *testing.T) { 84 rb := new(bytes.Buffer) // implements WriteTo. 85 wb := new(Buffer) 86 rb.WriteString("hello, world.") 87 Copy(wb, rb) 88 if wb.String() != "hello, world." { 89 t.Errorf("Copy did not work properly") 90 } 91 } 92 93 // Version of bytes.Buffer that checks whether WriteTo was called or not 94 type writeToChecker struct { 95 bytes.Buffer 96 writeToCalled bool 97 } 98 99 func (wt *writeToChecker) WriteTo(w Writer) (int64, error) { 100 wt.writeToCalled = true 101 return wt.Buffer.WriteTo(w) 102 } 103 104 // It's preferable to choose WriterTo over ReaderFrom, since a WriterTo can issue one large write, 105 // while the ReaderFrom must read until EOF, potentially allocating when running out of buffer. 106 // Make sure that we choose WriterTo when both are implemented. 107 func TestCopyPriority(t *testing.T) { 108 rb := new(writeToChecker) 109 wb := new(bytes.Buffer) 110 rb.WriteString("hello, world.") 111 Copy(wb, rb) 112 if wb.String() != "hello, world." { 113 t.Errorf("Copy did not work properly") 114 } else if !rb.writeToCalled { 115 t.Errorf("WriteTo was not prioritized over ReadFrom") 116 } 117 } 118 119 type zeroErrReader struct { 120 err error 121 } 122 123 func (r zeroErrReader) Read(p []byte) (int, error) { 124 return copy(p, []byte{0}), r.err 125 } 126 127 type errWriter struct { 128 err error 129 } 130 131 func (w errWriter) Write([]byte) (int, error) { 132 return 0, w.err 133 } 134 135 // In case a Read results in an error with non-zero bytes read, and 136 // the subsequent Write also results in an error, the error from Write 137 // is returned, as it is the one that prevented progressing further. 138 func TestCopyReadErrWriteErr(t *testing.T) { 139 er, ew := errors.New("readError"), errors.New("writeError") 140 r, w := zeroErrReader{err: er}, errWriter{err: ew} 141 n, err := Copy(w, r) 142 if n != 0 || err != ew { 143 t.Errorf("Copy(zeroErrReader, errWriter) = %d, %v; want 0, writeError", n, err) 144 } 145 } 146 147 func TestCopyN(t *testing.T) { 148 rb := new(Buffer) 149 wb := new(Buffer) 150 rb.WriteString("hello, world.") 151 CopyN(wb, rb, 5) 152 if wb.String() != "hello" { 153 t.Errorf("CopyN did not work properly") 154 } 155 } 156 157 func TestCopyNReadFrom(t *testing.T) { 158 rb := new(Buffer) 159 wb := new(bytes.Buffer) // implements ReadFrom. 160 rb.WriteString("hello") 161 CopyN(wb, rb, 5) 162 if wb.String() != "hello" { 163 t.Errorf("CopyN did not work properly") 164 } 165 } 166 167 func TestCopyNWriteTo(t *testing.T) { 168 rb := new(bytes.Buffer) // implements WriteTo. 169 wb := new(Buffer) 170 rb.WriteString("hello, world.") 171 CopyN(wb, rb, 5) 172 if wb.String() != "hello" { 173 t.Errorf("CopyN did not work properly") 174 } 175 } 176 177 func BenchmarkCopyNSmall(b *testing.B) { 178 bs := bytes.Repeat([]byte{0}, 512+1) 179 rd := bytes.NewReader(bs) 180 buf := new(Buffer) 181 b.ResetTimer() 182 183 for i := 0; i < b.N; i++ { 184 CopyN(buf, rd, 512) 185 rd.Reset(bs) 186 } 187 } 188 189 func BenchmarkCopyNLarge(b *testing.B) { 190 bs := bytes.Repeat([]byte{0}, (32*1024)+1) 191 rd := bytes.NewReader(bs) 192 buf := new(Buffer) 193 b.ResetTimer() 194 195 for i := 0; i < b.N; i++ { 196 CopyN(buf, rd, 32*1024) 197 rd.Reset(bs) 198 } 199 } 200 201 type noReadFrom struct { 202 w Writer 203 } 204 205 func (w *noReadFrom) Write(p []byte) (n int, err error) { 206 return w.w.Write(p) 207 } 208 209 type wantedAndErrReader struct{} 210 211 func (wantedAndErrReader) Read(p []byte) (int, error) { 212 return len(p), errors.New("wantedAndErrReader error") 213 } 214 215 func TestCopyNEOF(t *testing.T) { 216 // Test that EOF behavior is the same regardless of whether 217 // argument to CopyN has ReadFrom. 218 219 b := new(bytes.Buffer) 220 221 n, err := CopyN(&noReadFrom{b}, strings.NewReader("foo"), 3) 222 if n != 3 || err != nil { 223 t.Errorf("CopyN(noReadFrom, foo, 3) = %d, %v; want 3, nil", n, err) 224 } 225 226 n, err = CopyN(&noReadFrom{b}, strings.NewReader("foo"), 4) 227 if n != 3 || err != EOF { 228 t.Errorf("CopyN(noReadFrom, foo, 4) = %d, %v; want 3, EOF", n, err) 229 } 230 231 n, err = CopyN(b, strings.NewReader("foo"), 3) // b has read from 232 if n != 3 || err != nil { 233 t.Errorf("CopyN(bytes.Buffer, foo, 3) = %d, %v; want 3, nil", n, err) 234 } 235 236 n, err = CopyN(b, strings.NewReader("foo"), 4) // b has read from 237 if n != 3 || err != EOF { 238 t.Errorf("CopyN(bytes.Buffer, foo, 4) = %d, %v; want 3, EOF", n, err) 239 } 240 241 n, err = CopyN(b, wantedAndErrReader{}, 5) 242 if n != 5 || err != nil { 243 t.Errorf("CopyN(bytes.Buffer, wantedAndErrReader, 5) = %d, %v; want 5, nil", n, err) 244 } 245 246 n, err = CopyN(&noReadFrom{b}, wantedAndErrReader{}, 5) 247 if n != 5 || err != nil { 248 t.Errorf("CopyN(noReadFrom, wantedAndErrReader, 5) = %d, %v; want 5, nil", n, err) 249 } 250 } 251 252 func TestReadAtLeast(t *testing.T) { 253 var rb bytes.Buffer 254 testReadAtLeast(t, &rb) 255 } 256 257 // A version of bytes.Buffer that returns n > 0, err on Read 258 // when the input is exhausted. 259 type dataAndErrorBuffer struct { 260 err error 261 bytes.Buffer 262 } 263 264 func (r *dataAndErrorBuffer) Read(p []byte) (n int, err error) { 265 n, err = r.Buffer.Read(p) 266 if n > 0 && r.Buffer.Len() == 0 && err == nil { 267 err = r.err 268 } 269 return 270 } 271 272 func TestReadAtLeastWithDataAndEOF(t *testing.T) { 273 var rb dataAndErrorBuffer 274 rb.err = EOF 275 testReadAtLeast(t, &rb) 276 } 277 278 func TestReadAtLeastWithDataAndError(t *testing.T) { 279 var rb dataAndErrorBuffer 280 rb.err = fmt.Errorf("fake error") 281 testReadAtLeast(t, &rb) 282 } 283 284 func testReadAtLeast(t *testing.T, rb ReadWriter) { 285 rb.Write([]byte("0123")) 286 buf := make([]byte, 2) 287 n, err := ReadAtLeast(rb, buf, 2) 288 if err != nil { 289 t.Error(err) 290 } 291 if n != 2 { 292 t.Errorf("expected to have read 2 bytes, got %v", n) 293 } 294 n, err = ReadAtLeast(rb, buf, 4) 295 if err != ErrShortBuffer { 296 t.Errorf("expected ErrShortBuffer got %v", err) 297 } 298 if n != 0 { 299 t.Errorf("expected to have read 0 bytes, got %v", n) 300 } 301 n, err = ReadAtLeast(rb, buf, 1) 302 if err != nil { 303 t.Error(err) 304 } 305 if n != 2 { 306 t.Errorf("expected to have read 2 bytes, got %v", n) 307 } 308 n, err = ReadAtLeast(rb, buf, 2) 309 if err != EOF { 310 t.Errorf("expected EOF, got %v", err) 311 } 312 if n != 0 { 313 t.Errorf("expected to have read 0 bytes, got %v", n) 314 } 315 rb.Write([]byte("4")) 316 n, err = ReadAtLeast(rb, buf, 2) 317 want := ErrUnexpectedEOF 318 if rb, ok := rb.(*dataAndErrorBuffer); ok && rb.err != EOF { 319 want = rb.err 320 } 321 if err != want { 322 t.Errorf("expected %v, got %v", want, err) 323 } 324 if n != 1 { 325 t.Errorf("expected to have read 1 bytes, got %v", n) 326 } 327 } 328 329 func TestTeeReader(t *testing.T) { 330 src := []byte("hello, world") 331 dst := make([]byte, len(src)) 332 rb := bytes.NewBuffer(src) 333 wb := new(bytes.Buffer) 334 r := TeeReader(rb, wb) 335 if n, err := ReadFull(r, dst); err != nil || n != len(src) { 336 t.Fatalf("ReadFull(r, dst) = %d, %v; want %d, nil", n, err, len(src)) 337 } 338 if !bytes.Equal(dst, src) { 339 t.Errorf("bytes read = %q want %q", dst, src) 340 } 341 if !bytes.Equal(wb.Bytes(), src) { 342 t.Errorf("bytes written = %q want %q", wb.Bytes(), src) 343 } 344 if n, err := r.Read(dst); n != 0 || err != EOF { 345 t.Errorf("r.Read at EOF = %d, %v want 0, EOF", n, err) 346 } 347 rb = bytes.NewBuffer(src) 348 pr, pw := Pipe() 349 pr.Close() 350 r = TeeReader(rb, pw) 351 if n, err := ReadFull(r, dst); n != 0 || err != ErrClosedPipe { 352 t.Errorf("closed tee: ReadFull(r, dst) = %d, %v; want 0, EPIPE", n, err) 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: 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: 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: EOF}, 377 {data: dat, off: 0, n: 0, bufLen: 0, at: -1, exp: "", err: EOF}, 378 {data: dat, off: 0, n: 0, bufLen: 0, at: 1, exp: "", err: EOF}, 379 } 380 for i, tt := range tests { 381 r := strings.NewReader(tt.data) 382 s := 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 if _r, off, n := s.Outer(); _r != r || off != int64(tt.off) || n != int64(tt.n) { 388 t.Fatalf("%d: Outer() = %v, %d, %d; expected %v, %d, %d", i, _r, off, n, r, tt.off, tt.n) 389 } 390 } 391 } 392 393 func TestSectionReader_Seek(t *testing.T) { 394 // Verifies that NewSectionReader's Seeker behaves like bytes.NewReader (which is like strings.NewReader) 395 br := bytes.NewReader([]byte("foo")) 396 sr := NewSectionReader(br, 0, int64(len("foo"))) 397 398 for _, whence := range []int{SeekStart, SeekCurrent, SeekEnd} { 399 for offset := int64(-3); offset <= 4; offset++ { 400 brOff, brErr := br.Seek(offset, whence) 401 srOff, srErr := sr.Seek(offset, whence) 402 if (brErr != nil) != (srErr != nil) || brOff != srOff { 403 t.Errorf("For whence %d, offset %d: bytes.Reader.Seek = (%v, %v) != SectionReader.Seek = (%v, %v)", 404 whence, offset, brOff, brErr, srErr, srOff) 405 } 406 } 407 } 408 409 // And verify we can just seek past the end and get an EOF 410 got, err := sr.Seek(100, SeekStart) 411 if err != nil || got != 100 { 412 t.Errorf("Seek = %v, %v; want 100, nil", got, err) 413 } 414 415 n, err := sr.Read(make([]byte, 10)) 416 if n != 0 || err != EOF { 417 t.Errorf("Read = %v, %v; want 0, EOF", n, err) 418 } 419 } 420 421 func TestSectionReader_Size(t *testing.T) { 422 tests := []struct { 423 data string 424 want int64 425 }{ 426 {"a long sample data, 1234567890", 30}, 427 {"", 0}, 428 } 429 430 for _, tt := range tests { 431 r := strings.NewReader(tt.data) 432 sr := NewSectionReader(r, 0, int64(len(tt.data))) 433 if got := sr.Size(); got != tt.want { 434 t.Errorf("Size = %v; want %v", got, tt.want) 435 } 436 } 437 } 438 439 func TestSectionReader_Max(t *testing.T) { 440 r := strings.NewReader("abcdef") 441 const maxint64 = 1<<63 - 1 442 sr := NewSectionReader(r, 3, maxint64) 443 n, err := sr.Read(make([]byte, 3)) 444 if n != 3 || err != nil { 445 t.Errorf("Read = %v %v, want 3, nil", n, err) 446 } 447 n, err = sr.Read(make([]byte, 3)) 448 if n != 0 || err != EOF { 449 t.Errorf("Read = %v, %v, want 0, EOF", n, err) 450 } 451 if _r, off, n := sr.Outer(); _r != r || off != 3 || n != maxint64 { 452 t.Fatalf("Outer = %v, %d, %d; expected %v, %d, %d", _r, off, n, r, 3, int64(maxint64)) 453 } 454 } 455 456 // largeWriter returns an invalid count that is larger than the number 457 // of bytes provided (issue 39978). 458 type largeWriter struct { 459 err error 460 } 461 462 func (w largeWriter) Write(p []byte) (int, error) { 463 return len(p) + 1, w.err 464 } 465 466 func TestCopyLargeWriter(t *testing.T) { 467 want := ErrInvalidWrite 468 rb := new(Buffer) 469 wb := largeWriter{} 470 rb.WriteString("hello, world.") 471 if _, err := Copy(wb, rb); err != want { 472 t.Errorf("Copy error: got %v, want %v", err, want) 473 } 474 475 want = errors.New("largeWriterError") 476 rb = new(Buffer) 477 wb = largeWriter{err: want} 478 rb.WriteString("hello, world.") 479 if _, err := Copy(wb, rb); err != want { 480 t.Errorf("Copy error: got %v, want %v", err, want) 481 } 482 } 483 484 func TestNopCloserWriterToForwarding(t *testing.T) { 485 for _, tc := range [...]struct { 486 Name string 487 r Reader 488 }{ 489 {"not a WriterTo", Reader(nil)}, 490 {"a WriterTo", struct { 491 Reader 492 WriterTo 493 }{}}, 494 } { 495 nc := NopCloser(tc.r) 496 497 _, expected := tc.r.(WriterTo) 498 _, got := nc.(WriterTo) 499 if expected != got { 500 t.Errorf("NopCloser incorrectly forwards WriterTo for %s, got %t want %t", tc.Name, got, expected) 501 } 502 } 503 } 504 505 func TestOffsetWriter_Seek(t *testing.T) { 506 tmpfilename := "TestOffsetWriter_Seek" 507 tmpfile, err := os.CreateTemp(t.TempDir(), tmpfilename) 508 if err != nil || tmpfile == nil { 509 t.Fatalf("CreateTemp(%s) failed: %v", tmpfilename, err) 510 } 511 defer tmpfile.Close() 512 w := NewOffsetWriter(tmpfile, 0) 513 514 // Should throw error errWhence if whence is not valid 515 t.Run("errWhence", func(t *testing.T) { 516 for _, whence := range []int{-3, -2, -1, 3, 4, 5} { 517 var offset int64 = 0 518 gotOff, gotErr := w.Seek(offset, whence) 519 if gotOff != 0 || gotErr != ErrWhence { 520 t.Errorf("For whence %d, offset %d, OffsetWriter.Seek got: (%d, %v), want: (%d, %v)", 521 whence, offset, gotOff, gotErr, 0, ErrWhence) 522 } 523 } 524 }) 525 526 // Should throw error errOffset if offset is negative 527 t.Run("errOffset", func(t *testing.T) { 528 for _, whence := range []int{SeekStart, SeekCurrent} { 529 for offset := int64(-3); offset < 0; offset++ { 530 gotOff, gotErr := w.Seek(offset, whence) 531 if gotOff != 0 || gotErr != ErrOffset { 532 t.Errorf("For whence %d, offset %d, OffsetWriter.Seek got: (%d, %v), want: (%d, %v)", 533 whence, offset, gotOff, gotErr, 0, ErrOffset) 534 } 535 } 536 } 537 }) 538 539 // Normal tests 540 t.Run("normal", func(t *testing.T) { 541 tests := []struct { 542 offset int64 543 whence int 544 returnOff int64 545 }{ 546 // keep in order 547 {whence: SeekStart, offset: 1, returnOff: 1}, 548 {whence: SeekStart, offset: 2, returnOff: 2}, 549 {whence: SeekStart, offset: 3, returnOff: 3}, 550 {whence: SeekCurrent, offset: 1, returnOff: 4}, 551 {whence: SeekCurrent, offset: 2, returnOff: 6}, 552 {whence: SeekCurrent, offset: 3, returnOff: 9}, 553 } 554 for idx, tt := range tests { 555 gotOff, gotErr := w.Seek(tt.offset, tt.whence) 556 if gotOff != tt.returnOff || gotErr != nil { 557 t.Errorf("%d:: For whence %d, offset %d, OffsetWriter.Seek got: (%d, %v), want: (%d, <nil>)", 558 idx+1, tt.whence, tt.offset, gotOff, gotErr, tt.returnOff) 559 } 560 } 561 }) 562 } 563 564 func TestOffsetWriter_WriteAt(t *testing.T) { 565 const content = "0123456789ABCDEF" 566 contentSize := int64(len(content)) 567 tmpdir, err := os.MkdirTemp(t.TempDir(), "TestOffsetWriter_WriteAt") 568 if err != nil { 569 t.Fatal(err) 570 } 571 572 work := func(off, at int64) { 573 position := fmt.Sprintf("off_%d_at_%d", off, at) 574 tmpfile, err := os.CreateTemp(tmpdir, position) 575 if err != nil || tmpfile == nil { 576 t.Fatalf("CreateTemp(%s) failed: %v", position, err) 577 } 578 defer tmpfile.Close() 579 580 var writeN int64 581 var wg sync.WaitGroup 582 // Concurrent writes, one byte at a time 583 for step, value := range []byte(content) { 584 wg.Add(1) 585 go func(wg *sync.WaitGroup, tmpfile *os.File, value byte, off, at int64, step int) { 586 defer wg.Done() 587 588 w := NewOffsetWriter(tmpfile, off) 589 n, e := w.WriteAt([]byte{value}, at+int64(step)) 590 if e != nil { 591 t.Errorf("WriteAt failed. off: %d, at: %d, step: %d\n error: %v", off, at, step, e) 592 } 593 atomic.AddInt64(&writeN, int64(n)) 594 }(&wg, tmpfile, value, off, at, step) 595 } 596 wg.Wait() 597 598 // Read one more byte to reach EOF 599 buf := make([]byte, contentSize+1) 600 readN, err := tmpfile.ReadAt(buf, off+at) 601 if err != EOF { 602 t.Fatalf("ReadAt failed: %v", err) 603 } 604 readContent := string(buf[:contentSize]) 605 if writeN != int64(readN) || writeN != contentSize || readContent != content { 606 t.Fatalf("%s:: WriteAt(%s, %d) error. \ngot n: %v, content: %s \nexpected n: %v, content: %v", 607 position, content, at, readN, readContent, contentSize, content) 608 } 609 } 610 for off := int64(0); off < 2; off++ { 611 for at := int64(0); at < 2; at++ { 612 work(off, at) 613 } 614 } 615 } 616 617 func TestWriteAt_PositionPriorToBase(t *testing.T) { 618 tmpdir := t.TempDir() 619 tmpfilename := "TestOffsetWriter_WriteAt" 620 tmpfile, err := os.CreateTemp(tmpdir, tmpfilename) 621 if err != nil { 622 t.Fatalf("CreateTemp(%s) failed: %v", tmpfilename, err) 623 } 624 defer tmpfile.Close() 625 626 // start writing position in OffsetWriter 627 offset := int64(10) 628 // position we want to write to the tmpfile 629 at := int64(-1) 630 w := NewOffsetWriter(tmpfile, offset) 631 _, e := w.WriteAt([]byte("hello"), at) 632 if e == nil { 633 t.Errorf("error expected to be not nil") 634 } 635 } 636 637 func TestOffsetWriter_Write(t *testing.T) { 638 const content = "0123456789ABCDEF" 639 contentSize := len(content) 640 tmpdir := t.TempDir() 641 642 makeOffsetWriter := func(name string) (*OffsetWriter, *os.File) { 643 tmpfilename := "TestOffsetWriter_Write_" + name 644 tmpfile, err := os.CreateTemp(tmpdir, tmpfilename) 645 if err != nil || tmpfile == nil { 646 t.Fatalf("CreateTemp(%s) failed: %v", tmpfilename, err) 647 } 648 return NewOffsetWriter(tmpfile, 0), tmpfile 649 } 650 checkContent := func(name string, f *os.File) { 651 // Read one more byte to reach EOF 652 buf := make([]byte, contentSize+1) 653 readN, err := f.ReadAt(buf, 0) 654 if err != EOF { 655 t.Fatalf("ReadAt failed, err: %v", err) 656 } 657 readContent := string(buf[:contentSize]) 658 if readN != contentSize || readContent != content { 659 t.Fatalf("%s error. \ngot n: %v, content: %s \nexpected n: %v, content: %v", 660 name, readN, readContent, contentSize, content) 661 } 662 } 663 664 var name string 665 name = "Write" 666 t.Run(name, func(t *testing.T) { 667 // Write directly (off: 0, at: 0) 668 // Write content to file 669 w, f := makeOffsetWriter(name) 670 defer f.Close() 671 for _, value := range []byte(content) { 672 n, err := w.Write([]byte{value}) 673 if err != nil { 674 t.Fatalf("Write failed, n: %d, err: %v", n, err) 675 } 676 } 677 checkContent(name, f) 678 679 // Copy -> Write 680 // Copy file f to file f2 681 name = "Copy" 682 w2, f2 := makeOffsetWriter(name) 683 defer f2.Close() 684 Copy(w2, f) 685 checkContent(name, f2) 686 }) 687 688 // Copy -> WriteTo -> Write 689 // Note: strings.Reader implements the io.WriterTo interface. 690 name = "Write_Of_Copy_WriteTo" 691 t.Run(name, func(t *testing.T) { 692 w, f := makeOffsetWriter(name) 693 defer f.Close() 694 Copy(w, strings.NewReader(content)) 695 checkContent(name, f) 696 }) 697 }