]> Cypherpunks.ru repositories - gostls13.git/blob - src/io/pipe_test.go
cmd/compile/internal/inline: score call sites exposed by inlines
[gostls13.git] / src / io / pipe_test.go
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         "fmt"
10         . "io"
11         "sort"
12         "strings"
13         "testing"
14         "time"
15 )
16
17 func checkWrite(t *testing.T, w Writer, data []byte, c chan int) {
18         n, err := w.Write(data)
19         if err != nil {
20                 t.Errorf("write: %v", err)
21         }
22         if n != len(data) {
23                 t.Errorf("short write: %d != %d", n, len(data))
24         }
25         c <- 0
26 }
27
28 // Test a single read/write pair.
29 func TestPipe1(t *testing.T) {
30         c := make(chan int)
31         r, w := Pipe()
32         var buf = make([]byte, 64)
33         go checkWrite(t, w, []byte("hello, world"), c)
34         n, err := r.Read(buf)
35         if err != nil {
36                 t.Errorf("read: %v", err)
37         } else if n != 12 || string(buf[0:12]) != "hello, world" {
38                 t.Errorf("bad read: got %q", buf[0:n])
39         }
40         <-c
41         r.Close()
42         w.Close()
43 }
44
45 func reader(t *testing.T, r Reader, c chan int) {
46         var buf = make([]byte, 64)
47         for {
48                 n, err := r.Read(buf)
49                 if err == EOF {
50                         c <- 0
51                         break
52                 }
53                 if err != nil {
54                         t.Errorf("read: %v", err)
55                 }
56                 c <- n
57         }
58 }
59
60 // Test a sequence of read/write pairs.
61 func TestPipe2(t *testing.T) {
62         c := make(chan int)
63         r, w := Pipe()
64         go reader(t, r, c)
65         var buf = make([]byte, 64)
66         for i := 0; i < 5; i++ {
67                 p := buf[0 : 5+i*10]
68                 n, err := w.Write(p)
69                 if n != len(p) {
70                         t.Errorf("wrote %d, got %d", len(p), n)
71                 }
72                 if err != nil {
73                         t.Errorf("write: %v", err)
74                 }
75                 nn := <-c
76                 if nn != n {
77                         t.Errorf("wrote %d, read got %d", n, nn)
78                 }
79         }
80         w.Close()
81         nn := <-c
82         if nn != 0 {
83                 t.Errorf("final read got %d", nn)
84         }
85 }
86
87 type pipeReturn struct {
88         n   int
89         err error
90 }
91
92 // Test a large write that requires multiple reads to satisfy.
93 func writer(w WriteCloser, buf []byte, c chan pipeReturn) {
94         n, err := w.Write(buf)
95         w.Close()
96         c <- pipeReturn{n, err}
97 }
98
99 func TestPipe3(t *testing.T) {
100         c := make(chan pipeReturn)
101         r, w := Pipe()
102         var wdat = make([]byte, 128)
103         for i := 0; i < len(wdat); i++ {
104                 wdat[i] = byte(i)
105         }
106         go writer(w, wdat, c)
107         var rdat = make([]byte, 1024)
108         tot := 0
109         for n := 1; n <= 256; n *= 2 {
110                 nn, err := r.Read(rdat[tot : tot+n])
111                 if err != nil && err != EOF {
112                         t.Fatalf("read: %v", err)
113                 }
114
115                 // only final two reads should be short - 1 byte, then 0
116                 expect := n
117                 if n == 128 {
118                         expect = 1
119                 } else if n == 256 {
120                         expect = 0
121                         if err != EOF {
122                                 t.Fatalf("read at end: %v", err)
123                         }
124                 }
125                 if nn != expect {
126                         t.Fatalf("read %d, expected %d, got %d", n, expect, nn)
127                 }
128                 tot += nn
129         }
130         pr := <-c
131         if pr.n != 128 || pr.err != nil {
132                 t.Fatalf("write 128: %d, %v", pr.n, pr.err)
133         }
134         if tot != 128 {
135                 t.Fatalf("total read %d != 128", tot)
136         }
137         for i := 0; i < 128; i++ {
138                 if rdat[i] != byte(i) {
139                         t.Fatalf("rdat[%d] = %d", i, rdat[i])
140                 }
141         }
142 }
143
144 // Test read after/before writer close.
145
146 type closer interface {
147         CloseWithError(error) error
148         Close() error
149 }
150
151 type pipeTest struct {
152         async          bool
153         err            error
154         closeWithError bool
155 }
156
157 func (p pipeTest) String() string {
158         return fmt.Sprintf("async=%v err=%v closeWithError=%v", p.async, p.err, p.closeWithError)
159 }
160
161 var pipeTests = []pipeTest{
162         {true, nil, false},
163         {true, nil, true},
164         {true, ErrShortWrite, true},
165         {false, nil, false},
166         {false, nil, true},
167         {false, ErrShortWrite, true},
168 }
169
170 func delayClose(t *testing.T, cl closer, ch chan int, tt pipeTest) {
171         time.Sleep(1 * time.Millisecond)
172         var err error
173         if tt.closeWithError {
174                 err = cl.CloseWithError(tt.err)
175         } else {
176                 err = cl.Close()
177         }
178         if err != nil {
179                 t.Errorf("delayClose: %v", err)
180         }
181         ch <- 0
182 }
183
184 func TestPipeReadClose(t *testing.T) {
185         for _, tt := range pipeTests {
186                 c := make(chan int, 1)
187                 r, w := Pipe()
188                 if tt.async {
189                         go delayClose(t, w, c, tt)
190                 } else {
191                         delayClose(t, w, c, tt)
192                 }
193                 var buf = make([]byte, 64)
194                 n, err := r.Read(buf)
195                 <-c
196                 want := tt.err
197                 if want == nil {
198                         want = EOF
199                 }
200                 if err != want {
201                         t.Errorf("read from closed pipe: %v want %v", err, want)
202                 }
203                 if n != 0 {
204                         t.Errorf("read on closed pipe returned %d", n)
205                 }
206                 if err = r.Close(); err != nil {
207                         t.Errorf("r.Close: %v", err)
208                 }
209         }
210 }
211
212 // Test close on Read side during Read.
213 func TestPipeReadClose2(t *testing.T) {
214         c := make(chan int, 1)
215         r, _ := Pipe()
216         go delayClose(t, r, c, pipeTest{})
217         n, err := r.Read(make([]byte, 64))
218         <-c
219         if n != 0 || err != ErrClosedPipe {
220                 t.Errorf("read from closed pipe: %v, %v want %v, %v", n, err, 0, ErrClosedPipe)
221         }
222 }
223
224 // Test write after/before reader close.
225
226 func TestPipeWriteClose(t *testing.T) {
227         for _, tt := range pipeTests {
228                 c := make(chan int, 1)
229                 r, w := Pipe()
230                 if tt.async {
231                         go delayClose(t, r, c, tt)
232                 } else {
233                         delayClose(t, r, c, tt)
234                 }
235                 n, err := WriteString(w, "hello, world")
236                 <-c
237                 expect := tt.err
238                 if expect == nil {
239                         expect = ErrClosedPipe
240                 }
241                 if err != expect {
242                         t.Errorf("write on closed pipe: %v want %v", err, expect)
243                 }
244                 if n != 0 {
245                         t.Errorf("write on closed pipe returned %d", n)
246                 }
247                 if err = w.Close(); err != nil {
248                         t.Errorf("w.Close: %v", err)
249                 }
250         }
251 }
252
253 // Test close on Write side during Write.
254 func TestPipeWriteClose2(t *testing.T) {
255         c := make(chan int, 1)
256         _, w := Pipe()
257         go delayClose(t, w, c, pipeTest{})
258         n, err := w.Write(make([]byte, 64))
259         <-c
260         if n != 0 || err != ErrClosedPipe {
261                 t.Errorf("write to closed pipe: %v, %v want %v, %v", n, err, 0, ErrClosedPipe)
262         }
263 }
264
265 func TestWriteEmpty(t *testing.T) {
266         r, w := Pipe()
267         go func() {
268                 w.Write([]byte{})
269                 w.Close()
270         }()
271         var b [2]byte
272         ReadFull(r, b[0:2])
273         r.Close()
274 }
275
276 func TestWriteNil(t *testing.T) {
277         r, w := Pipe()
278         go func() {
279                 w.Write(nil)
280                 w.Close()
281         }()
282         var b [2]byte
283         ReadFull(r, b[0:2])
284         r.Close()
285 }
286
287 func TestWriteAfterWriterClose(t *testing.T) {
288         r, w := Pipe()
289
290         done := make(chan bool)
291         var writeErr error
292         go func() {
293                 _, err := w.Write([]byte("hello"))
294                 if err != nil {
295                         t.Errorf("got error: %q; expected none", err)
296                 }
297                 w.Close()
298                 _, writeErr = w.Write([]byte("world"))
299                 done <- true
300         }()
301
302         buf := make([]byte, 100)
303         var result string
304         n, err := ReadFull(r, buf)
305         if err != nil && err != ErrUnexpectedEOF {
306                 t.Fatalf("got: %q; want: %q", err, ErrUnexpectedEOF)
307         }
308         result = string(buf[0:n])
309         <-done
310
311         if result != "hello" {
312                 t.Errorf("got: %q; want: %q", result, "hello")
313         }
314         if writeErr != ErrClosedPipe {
315                 t.Errorf("got: %q; want: %q", writeErr, ErrClosedPipe)
316         }
317 }
318
319 func TestPipeCloseError(t *testing.T) {
320         type testError1 struct{ error }
321         type testError2 struct{ error }
322
323         r, w := Pipe()
324         r.CloseWithError(testError1{})
325         if _, err := w.Write(nil); err != (testError1{}) {
326                 t.Errorf("Write error: got %T, want testError1", err)
327         }
328         r.CloseWithError(testError2{})
329         if _, err := w.Write(nil); err != (testError1{}) {
330                 t.Errorf("Write error: got %T, want testError1", err)
331         }
332
333         r, w = Pipe()
334         w.CloseWithError(testError1{})
335         if _, err := r.Read(nil); err != (testError1{}) {
336                 t.Errorf("Read error: got %T, want testError1", err)
337         }
338         w.CloseWithError(testError2{})
339         if _, err := r.Read(nil); err != (testError1{}) {
340                 t.Errorf("Read error: got %T, want testError1", err)
341         }
342 }
343
344 func TestPipeConcurrent(t *testing.T) {
345         const (
346                 input    = "0123456789abcdef"
347                 count    = 8
348                 readSize = 2
349         )
350
351         t.Run("Write", func(t *testing.T) {
352                 r, w := Pipe()
353
354                 for i := 0; i < count; i++ {
355                         go func() {
356                                 time.Sleep(time.Millisecond) // Increase probability of race
357                                 if n, err := w.Write([]byte(input)); n != len(input) || err != nil {
358                                         t.Errorf("Write() = (%d, %v); want (%d, nil)", n, err, len(input))
359                                 }
360                         }()
361                 }
362
363                 buf := make([]byte, count*len(input))
364                 for i := 0; i < len(buf); i += readSize {
365                         if n, err := r.Read(buf[i : i+readSize]); n != readSize || err != nil {
366                                 t.Errorf("Read() = (%d, %v); want (%d, nil)", n, err, readSize)
367                         }
368                 }
369
370                 // Since each Write is fully gated, if multiple Read calls were needed,
371                 // the contents of Write should still appear together in the output.
372                 got := string(buf)
373                 want := strings.Repeat(input, count)
374                 if got != want {
375                         t.Errorf("got: %q; want: %q", got, want)
376                 }
377         })
378
379         t.Run("Read", func(t *testing.T) {
380                 r, w := Pipe()
381
382                 c := make(chan []byte, count*len(input)/readSize)
383                 for i := 0; i < cap(c); i++ {
384                         go func() {
385                                 time.Sleep(time.Millisecond) // Increase probability of race
386                                 buf := make([]byte, readSize)
387                                 if n, err := r.Read(buf); n != readSize || err != nil {
388                                         t.Errorf("Read() = (%d, %v); want (%d, nil)", n, err, readSize)
389                                 }
390                                 c <- buf
391                         }()
392                 }
393
394                 for i := 0; i < count; i++ {
395                         if n, err := w.Write([]byte(input)); n != len(input) || err != nil {
396                                 t.Errorf("Write() = (%d, %v); want (%d, nil)", n, err, len(input))
397                         }
398                 }
399
400                 // Since each read is independent, the only guarantee about the output
401                 // is that it is a permutation of the input in readSized groups.
402                 got := make([]byte, 0, count*len(input))
403                 for i := 0; i < cap(c); i++ {
404                         got = append(got, (<-c)...)
405                 }
406                 got = sortBytesInGroups(got, readSize)
407                 want := bytes.Repeat([]byte(input), count)
408                 want = sortBytesInGroups(want, readSize)
409                 if string(got) != string(want) {
410                         t.Errorf("got: %q; want: %q", got, want)
411                 }
412         })
413 }
414
415 func sortBytesInGroups(b []byte, n int) []byte {
416         var groups [][]byte
417         for len(b) > 0 {
418                 groups = append(groups, b[:n])
419                 b = b[n:]
420         }
421         sort.Slice(groups, func(i, j int) bool { return bytes.Compare(groups[i], groups[j]) < 0 })
422         return bytes.Join(groups, nil)
423 }