github.com/gnolang/gno@v0.0.0-20240520182011-228e9d0192ce/gnovm/stdlibs/io/multi_test.gno (about) 1 package io_test 2 3 // Copyright 2010 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 "crypto/sha1" 10 "fmt" 11 "io" 12 "strings" 13 "testing" 14 ) 15 16 type Stringer interface { 17 String() string 18 } 19 20 func TestMultiReader(t *testing.T) { 21 var mr io.Reader 22 var buf []byte 23 nread := 0 24 withFooBar := func(tests func()) { 25 r1 := strings.NewReader("foo ") 26 r2 := strings.NewReader("") 27 r3 := strings.NewReader("bar") 28 mr = io.MultiReader(r1, r2, r3) 29 buf = make([]byte, 20) 30 tests() 31 } 32 expectRead := func(size int, expected string, eerr error) { 33 nread++ 34 n, gerr := mr.Read(buf[0:size]) 35 if n != len(expected) { 36 t.Errorf("#%d, expected %d bytes; got %d", 37 nread, len(expected), n) 38 } 39 got := string(buf[0:n]) 40 if got != expected { 41 t.Errorf("#%d, expected %q; got %q", 42 nread, expected, got) 43 } 44 if gerr != eerr { 45 t.Errorf("#%d, expected error %v; got %v", 46 nread, eerr, gerr) 47 } 48 buf = buf[n:] 49 } 50 withFooBar(func() { 51 expectRead(2, "fo", nil) 52 expectRead(5, "o ", nil) 53 expectRead(5, "bar", nil) 54 expectRead(5, "", io.EOF) 55 }) 56 withFooBar(func() { 57 expectRead(4, "foo ", nil) 58 expectRead(1, "b", nil) 59 expectRead(3, "ar", nil) 60 expectRead(1, "", io.EOF) 61 }) 62 withFooBar(func() { 63 expectRead(5, "foo ", nil) 64 }) 65 } 66 67 func TestMultiWriter(t *testing.T) { 68 sink := new(bytes.Buffer) 69 // Hide bytes.Buffer's WriteString method: 70 testMultiWriter(t, struct { 71 io.Writer 72 Stringer 73 }{sink, sink}) 74 } 75 76 func TestMultiWriter_String(t *testing.T) { 77 testMultiWriter(t, new(bytes.Buffer)) 78 } 79 80 /* XXX disabling because testing.AllocsPerRun* doesn't work. 81 // Test that a multiWriter.WriteString calls results in at most 1 allocation, 82 // even if multiple targets don't support WriteString. 83 func TestMultiWriter_WriteStringSingleAlloc(t *testing.T) { 84 var sink1, sink2 bytes.Buffer 85 type simpleWriter struct { // hide bytes.Buffer's WriteString 86 io.Writer 87 } 88 mw := io.MultiWriter(simpleWriter{&sink1}, simpleWriter{&sink2}) 89 allocs := int(testing.AllocsPerRun2(1000, func() { 90 io.WriteString(mw, "foo") 91 })) 92 if allocs != 1 { 93 t.Errorf("num allocations = %d; want 1", allocs) 94 } 95 } 96 */ 97 98 type writeStringChecker struct{ called bool } 99 100 func (c *writeStringChecker) WriteString(s string) (n int, err error) { 101 c.called = true 102 return len(s), nil 103 } 104 105 func (c *writeStringChecker) Write(p []byte) (n int, err error) { 106 return len(p), nil 107 } 108 109 func TestMultiWriter_StringCheckCall(t *testing.T) { 110 var c writeStringChecker 111 mw := io.MultiWriter(&c) 112 io.WriteString(mw, "foo") 113 if !c.called { 114 t.Error("did not see WriteString call to writeStringChecker") 115 } 116 } 117 118 func testMultiWriter(t *testing.T, sink interface { 119 io.Writer 120 Stringer 121 }, 122 ) { 123 sha1 := sha1.New() 124 mw := io.MultiWriter(sha1, sink) 125 126 sourceString := "My input text." 127 source := strings.NewReader(sourceString) 128 written, err := io.Copy(mw, source) 129 130 if written != int64(len(sourceString)) { 131 t.Errorf("short write of %d, not %d", written, len(sourceString)) 132 } 133 134 if err != nil { 135 t.Errorf("unexpected error: %v", err) 136 } 137 138 sha1hex := fmt.Sprintf("%x", sha1.Sum(nil)) 139 if sha1hex != "01cb303fa8c30a64123067c5aa6284ba7ec2d31b" { 140 t.Error("incorrect sha1 value") 141 } 142 143 if sink.String() != sourceString { 144 t.Errorf("expected %q; got %q", sourceString, sink.String()) 145 } 146 } 147 148 // writerFunc is an Writer implemented by the underlying func. 149 type writerFunc func(p []byte) (int, error) 150 151 func (f writerFunc) Write(p []byte) (int, error) { 152 return f(p) 153 } 154 155 /* 156 // Test that MultiWriter properly flattens chained multiWriters. 157 func TestMultiWriterSingleChainFlatten(t *testing.T) { 158 pc := make([]uintptr, 1000) // 1000 should fit the full stack 159 n := runtime.Callers(0, pc) 160 var myDepth = callDepth(pc[:n]) 161 var writeDepth int // will contain the depth from which writerFunc.Writer was called 162 var w Writer = MultiWriter(writerFunc(func(p []byte) (int, error) { 163 n := runtime.Callers(1, pc) 164 writeDepth += callDepth(pc[:n]) 165 return 0, nil 166 })) 167 168 mw := w 169 // chain a bunch of multiWriters 170 for i := 0; i < 100; i++ { 171 mw = MultiWriter(w) 172 } 173 174 mw = MultiWriter(w, mw, w, mw) 175 mw.Write(nil) // don't care about errors, just want to check the call-depth for Write 176 177 if writeDepth != 4*(myDepth+2) { // 2 should be multiWriter.Write and writerFunc.Write 178 t.Errorf("multiWriter did not flatten chained multiWriters: expected writeDepth %d, got %d", 179 4*(myDepth+2), writeDepth) 180 } 181 } 182 */ 183 184 func TestMultiWriterError(t *testing.T) { 185 f1 := writerFunc(func(p []byte) (int, error) { 186 return len(p) / 2, io.ErrShortWrite 187 }) 188 f2 := writerFunc(func(p []byte) (int, error) { 189 t.Errorf("MultiWriter called f2.Write") 190 return len(p), nil 191 }) 192 w := io.MultiWriter(f1, f2) 193 n, err := w.Write(make([]byte, 100)) 194 if n != 50 || err != io.ErrShortWrite { 195 t.Errorf("Write = %d, %v, want 50, ErrShortWrite", n, err) 196 } 197 } 198 199 // Test that MultiReader copies the input slice and is insulated from future modification. 200 func TestMultiReaderCopy(t *testing.T) { 201 slice := []io.Reader{strings.NewReader("hello world")} 202 r := io.MultiReader(slice...) 203 slice[0] = nil 204 data, err := io.ReadAll(r) 205 if err != nil || string(data) != "hello world" { 206 t.Errorf("ReadAll() = %q, %v, want %q, nil", data, err, "hello world") 207 } 208 } 209 210 // Test that MultiWriter copies the input slice and is insulated from future modification. 211 func TestMultiWriterCopy(t *testing.T) { 212 var buf bytes.Buffer 213 slice := []io.Writer{&buf} 214 w := io.MultiWriter(slice...) 215 slice[0] = nil 216 n, err := w.Write([]byte("hello world")) 217 if err != nil || n != 11 { 218 t.Errorf("Write(`hello world`) = %d, %v, want 11, nil", n, err) 219 } 220 if buf.String() != "hello world" { 221 t.Errorf("buf.String() = %q, want %q", buf.String(), "hello world") 222 } 223 } 224 225 // readerFunc is an Reader implemented by the underlying func. 226 type readerFunc func(p []byte) (int, error) 227 228 func (f readerFunc) Read(p []byte) (int, error) { 229 return f(p) 230 } 231 232 /* 233 // callDepth returns the logical call depth for the given PCs. 234 func callDepth(callers []uintptr) (depth int) { 235 frames := runtime.CallersFrames(callers) 236 more := true 237 for more { 238 _, more = frames.Next() 239 depth++ 240 } 241 return 242 } 243 244 // Test that MultiReader properly flattens chained multiReaders when Read is called 245 func TestMultiReaderFlatten(t *testing.T) { 246 pc := make([]uintptr, 1000) // 1000 should fit the full stack 247 n := runtime.Callers(0, pc) 248 var myDepth = callDepth(pc[:n]) 249 var readDepth int // will contain the depth from which fakeReader.Read was called 250 var r Reader = MultiReader(readerFunc(func(p []byte) (int, error) { 251 n := runtime.Callers(1, pc) 252 readDepth = callDepth(pc[:n]) 253 return 0, errors.New("irrelevant") 254 })) 255 256 // chain a bunch of multiReaders 257 for i := 0; i < 100; i++ { 258 r = MultiReader(r) 259 } 260 261 r.Read(nil) // don't care about errors, just want to check the call-depth for Read 262 263 if readDepth != myDepth+2 { // 2 should be multiReader.Read and fakeReader.Read 264 t.Errorf("multiReader did not flatten chained multiReaders: expected readDepth %d, got %d", 265 myDepth+2, readDepth) 266 } 267 } 268 */ 269 270 // byteAndEOFReader is a Reader which reads one byte (the underlying 271 // byte) and EOF at once in its Read call. 272 type byteAndEOFReader byte 273 274 func (b byteAndEOFReader) Read(p []byte) (n int, err error) { 275 if len(p) == 0 { 276 // Read(0 bytes) is useless. We expect no such useless 277 // calls in this test. 278 panic("unexpected call") 279 } 280 p[0] = byte(b) 281 return 1, io.EOF 282 } 283 284 // This used to yield bytes forever; issue 16795. 285 func TestMultiReaderSingleByteWithEOF(t *testing.T) { 286 got, err := io.ReadAll(io.LimitReader(io.MultiReader(byteAndEOFReader('a'), byteAndEOFReader('b')), 10)) 287 if err != nil { 288 t.Fatal(err) 289 } 290 const want = "ab" 291 if string(got) != want { 292 t.Errorf("got %q; want %q", got, want) 293 } 294 } 295 296 // Test that a reader returning (n, EOF) at the end of a MultiReader 297 // chain continues to return EOF on its final read, rather than 298 // yielding a (0, EOF). 299 func TestMultiReaderFinalEOF(t *testing.T) { 300 r := io.MultiReader(bytes.NewReader(nil), byteAndEOFReader('a')) 301 buf := make([]byte, 2) 302 n, err := r.Read(buf) 303 if n != 1 || err != io.EOF { 304 t.Errorf("got %v, %v; want 1, EOF", n, err) 305 } 306 } 307 308 /* 309 func TestMultiReaderFreesExhaustedReaders(t *testing.T) { 310 var mr Reader 311 closed := make(chan struct{}) 312 // The closure ensures that we don't have a live reference to buf1 313 // on our stack after MultiReader is inlined (Issue 18819). This 314 // is a work around for a limitation in liveness analysis. 315 func() { 316 buf1 := bytes.NewReader([]byte("foo")) 317 buf2 := bytes.NewReader([]byte("bar")) 318 mr = MultiReader(buf1, buf2) 319 runtime.SetFinalizer(buf1, func(*bytes.Reader) { 320 close(closed) 321 }) 322 }() 323 324 buf := make([]byte, 4) 325 if n, err := ReadFull(mr, buf); err != nil || string(buf) != "foob" { 326 t.Fatalf(`ReadFull = %d (%q), %v; want 3, "foo", nil`, n, buf[:n], err) 327 } 328 329 runtime.GC() 330 select { 331 case <-closed: 332 case <-time.After(5 * time.Second): 333 t.Fatal("timeout waiting for collection of buf1") 334 } 335 336 if n, err := ReadFull(mr, buf[:2]); err != nil || string(buf[:2]) != "ar" { 337 t.Fatalf(`ReadFull = %d (%q), %v; want 2, "ar", nil`, n, buf[:n], err) 338 } 339 } 340 */ 341 342 func TestInterleavedMultiReader(t *testing.T) { 343 r1 := strings.NewReader("123") 344 r2 := strings.NewReader("45678") 345 346 mr1 := io.MultiReader(r1, r2) 347 mr2 := io.MultiReader(mr1) 348 349 buf := make([]byte, 4) 350 351 // Have mr2 use mr1's []Readers. 352 // Consume r1 (and clear it for GC to handle) and consume part of r2. 353 n, err := io.ReadFull(mr2, buf) 354 if got := string(buf[:n]); got != "1234" || err != nil { 355 t.Errorf(`ReadFull(mr2) = (%q, %v), want ("1234", nil)`, got, err) 356 } 357 358 // Consume the rest of r2 via mr1. 359 // This should not panic even though mr2 cleared r1. 360 n, err = io.ReadFull(mr1, buf) 361 if got := string(buf[:n]); got != "5678" || err != nil { 362 t.Errorf(`ReadFull(mr1) = (%q, %v), want ("5678", nil)`, got, err) 363 } 364 }