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  // }