1 // Copyright 2010 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.
20 func TestMultiReader(t
*testing
.T
) {
24 withFooBar
:= func(tests
func()) {
25 r1
:= strings
.NewReader("foo ")
26 r2
:= strings
.NewReader("")
27 r3
:= strings
.NewReader("bar")
28 mr
= MultiReader(r1
, r2
, r3
)
29 buf
= make([]byte, 20)
32 expectRead
:= func(size
int, expected
string, eerr error
) {
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
)
39 got
:= string(buf
[0:n
])
41 t
.Errorf("#%d, expected %q; got %q",
45 t
.Errorf("#%d, expected error %v; got %v",
51 expectRead(2, "fo", nil)
52 expectRead(5, "o ", nil)
53 expectRead(5, "bar", nil)
54 expectRead(5, "", EOF
)
57 expectRead(4, "foo ", nil)
58 expectRead(1, "b", nil)
59 expectRead(3, "ar", nil)
60 expectRead(1, "", EOF
)
63 expectRead(5, "foo ", nil)
67 func TestMultiWriter(t
*testing
.T
) {
68 sink
:= new(bytes
.Buffer
)
69 // Hide bytes.Buffer's WriteString method:
70 testMultiWriter(t
, struct {
76 func TestMultiWriter_String(t
*testing
.T
) {
77 testMultiWriter(t
, new(bytes
.Buffer
))
80 // test that a multiWriter.WriteString calls results in at most 1 allocation,
81 // even if multiple targets don't support WriteString.
82 func TestMultiWriter_WriteStringSingleAlloc(t
*testing
.T
) {
83 t
.Skip("skipping on gccgo until we have escape analysis")
84 var sink1
, sink2 bytes
.Buffer
85 type simpleWriter
struct { // hide bytes.Buffer's WriteString
88 mw
:= MultiWriter(simpleWriter
{&sink1
}, simpleWriter
{&sink2
})
89 allocs
:= int(testing
.AllocsPerRun(1000, func() {
90 WriteString(mw
, "foo")
93 t
.Errorf("num allocations = %d; want 1", allocs
)
97 type writeStringChecker
struct{ called
bool }
99 func (c
*writeStringChecker
) WriteString(s
string) (n
int, err error
) {
104 func (c
*writeStringChecker
) Write(p
[]byte) (n
int, err error
) {
108 func TestMultiWriter_StringCheckCall(t
*testing
.T
) {
109 var c writeStringChecker
110 mw
:= MultiWriter(&c
)
111 WriteString(mw
, "foo")
113 t
.Error("did not see WriteString call to writeStringChecker")
117 func testMultiWriter(t
*testing
.T
, sink
interface {
122 mw
:= MultiWriter(sha1
, sink
)
124 sourceString
:= "My input text."
125 source
:= strings
.NewReader(sourceString
)
126 written
, err
:= Copy(mw
, source
)
128 if written
!= int64(len(sourceString
)) {
129 t
.Errorf("short write of %d, not %d", written
, len(sourceString
))
133 t
.Errorf("unexpected error: %v", err
)
136 sha1hex
:= fmt
.Sprintf("%x", sha1
.Sum(nil))
137 if sha1hex
!= "01cb303fa8c30a64123067c5aa6284ba7ec2d31b" {
138 t
.Error("incorrect sha1 value")
141 if sink
.String() != sourceString
{
142 t
.Errorf("expected %q; got %q", sourceString
, sink
.String())
146 // Test that MultiReader copies the input slice and is insulated from future modification.
147 func TestMultiReaderCopy(t
*testing
.T
) {
148 slice
:= []Reader
{strings
.NewReader("hello world")}
149 r
:= MultiReader(slice
...)
151 data
, err
:= ioutil
.ReadAll(r
)
152 if err
!= nil ||
string(data
) != "hello world" {
153 t
.Errorf("ReadAll() = %q, %v, want %q, nil", data
, err
, "hello world")
157 // Test that MultiWriter copies the input slice and is insulated from future modification.
158 func TestMultiWriterCopy(t
*testing
.T
) {
160 slice
:= []Writer
{&buf
}
161 w
:= MultiWriter(slice
...)
163 n
, err
:= w
.Write([]byte("hello world"))
164 if err
!= nil || n
!= 11 {
165 t
.Errorf("Write(`hello world`) = %d, %v, want 11, nil", n
, err
)
167 if buf
.String() != "hello world" {
168 t
.Errorf("buf.String() = %q, want %q", buf
.String(), "hello world")
172 // readerFunc is an io.Reader implemented by the underlying func.
173 type readerFunc
func(p
[]byte) (int, error
)
175 func (f readerFunc
) Read(p
[]byte) (int, error
) {
179 // callDepth returns the logical call depth for the given PCs.
180 func callDepth(callers
[]uintptr) (depth
int) {
181 frames
:= runtime
.CallersFrames(callers
)
184 _
, more
= frames
.Next()
190 // Test that MultiReader properly flattens chained multiReaders when Read is called
191 func TestMultiReaderFlatten(t
*testing
.T
) {
192 pc
:= make([]uintptr, 1000) // 1000 should fit the full stack
193 n
:= runtime
.Callers(0, pc
)
194 var myDepth
= callDepth(pc
[:n
])
195 var readDepth
int // will contain the depth from which fakeReader.Read was called
196 var r Reader
= MultiReader(readerFunc(func(p
[]byte) (int, error
) {
197 n
:= runtime
.Callers(1, pc
)
198 readDepth
= callDepth(pc
[:n
])
199 return 0, errors
.New("irrelevant")
202 // chain a bunch of multiReaders
203 for i
:= 0; i
< 100; i
++ {
207 r
.Read(nil) // don't care about errors, just want to check the call-depth for Read
209 if readDepth
!= myDepth
+2 { // 2 should be multiReader.Read and fakeReader.Read
210 t
.Errorf("multiReader did not flatten chained multiReaders: expected readDepth %d, got %d",
211 myDepth
+2, readDepth
)
215 // byteAndEOFReader is a Reader which reads one byte (the underlying
216 // byte) and io.EOF at once in its Read call.
217 type byteAndEOFReader
byte
219 func (b byteAndEOFReader
) Read(p
[]byte) (n
int, err error
) {
221 // Read(0 bytes) is useless. We expect no such useless
222 // calls in this test.
223 panic("unexpected call")
229 // This used to yield bytes forever; issue 16795.
230 func TestMultiReaderSingleByteWithEOF(t
*testing
.T
) {
231 got
, err
:= ioutil
.ReadAll(LimitReader(MultiReader(byteAndEOFReader('a'), byteAndEOFReader('b')), 10))
236 if string(got
) != want
{
237 t
.Errorf("got %q; want %q", got
, want
)
241 // Test that a reader returning (n, EOF) at the end of an MultiReader
242 // chain continues to return EOF on its final read, rather than
243 // yielding a (0, EOF).
244 func TestMultiReaderFinalEOF(t
*testing
.T
) {
245 r
:= MultiReader(bytes
.NewReader(nil), byteAndEOFReader('a'))
246 buf
:= make([]byte, 2)
247 n
, err
:= r
.Read(buf
)
248 if n
!= 1 || err
!= EOF
{
249 t
.Errorf("got %v, %v; want 1, EOF", n
, err
)
253 func TestMultiReaderFreesExhaustedReaders(t
*testing
.T
) {
254 if runtime
.Compiler
== "gccgo" {
255 t
.Skip("skipping finalizer test on gccgo with conservative GC")
259 closed := make(chan struct{})
260 // The closure ensures that we don't have a live reference to buf1
261 // on our stack after MultiReader is inlined (Issue 18819). This
262 // is a work around for a limitation in liveness analysis.
264 buf1
:= bytes
.NewReader([]byte("foo"))
265 buf2
:= bytes
.NewReader([]byte("bar"))
266 mr
= MultiReader(buf1
, buf2
)
267 runtime
.SetFinalizer(buf1
, func(*bytes
.Reader
) {
272 buf
:= make([]byte, 4)
273 if n
, err
:= ReadFull(mr
, buf
); err
!= nil ||
string(buf
) != "foob" {
274 t
.Fatalf(`ReadFull = %d (%q), %v; want 3, "foo", nil`, n
, buf
[:n
], err
)
280 case <-time
.After(5 * time
.Second
):
281 t
.Fatal("timeout waiting for collection of buf1")
284 if n
, err
:= ReadFull(mr
, buf
[:2]); err
!= nil ||
string(buf
[:2]) != "ar" {
285 t
.Fatalf(`ReadFull = %d (%q), %v; want 2, "ar", nil`, n
, buf
[:n
], err
)
289 func TestInterleavedMultiReader(t
*testing
.T
) {
290 r1
:= strings
.NewReader("123")
291 r2
:= strings
.NewReader("45678")
293 mr1
:= MultiReader(r1
, r2
)
294 mr2
:= MultiReader(mr1
)
296 buf
:= make([]byte, 4)
298 // Have mr2 use mr1's []Readers.
299 // Consume r1 (and clear it for GC to handle) and consume part of r2.
300 n
, err
:= ReadFull(mr2
, buf
)
301 if got
:= string(buf
[:n
]); got
!= "1234" || err
!= nil {
302 t
.Errorf(`ReadFull(mr2) = (%q, %v), want ("1234", nil)`, got
, err
)
305 // Consume the rest of r2 via mr1.
306 // This should not panic even though mr2 cleared r1.
307 n
, err
= ReadFull(mr1
, buf
)
308 if got
:= string(buf
[:n
]); got
!= "5678" || err
!= nil {
309 t
.Errorf(`ReadFull(mr1) = (%q, %v), want ("5678", nil)`, got
, err
)