Home | History | Annotate | Download | only in io
      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 	"fmt"
      9 	. "io"
     10 	"testing"
     11 	"time"
     12 )
     13 
     14 func checkWrite(t *testing.T, w Writer, data []byte, c chan int) {
     15 	n, err := w.Write(data)
     16 	if err != nil {
     17 		t.Errorf("write: %v", err)
     18 	}
     19 	if n != len(data) {
     20 		t.Errorf("short write: %d != %d", n, len(data))
     21 	}
     22 	c <- 0
     23 }
     24 
     25 // Test a single read/write pair.
     26 func TestPipe1(t *testing.T) {
     27 	c := make(chan int)
     28 	r, w := Pipe()
     29 	var buf = make([]byte, 64)
     30 	go checkWrite(t, w, []byte("hello, world"), c)
     31 	n, err := r.Read(buf)
     32 	if err != nil {
     33 		t.Errorf("read: %v", err)
     34 	} else if n != 12 || string(buf[0:12]) != "hello, world" {
     35 		t.Errorf("bad read: got %q", buf[0:n])
     36 	}
     37 	<-c
     38 	r.Close()
     39 	w.Close()
     40 }
     41 
     42 func reader(t *testing.T, r Reader, c chan int) {
     43 	var buf = make([]byte, 64)
     44 	for {
     45 		n, err := r.Read(buf)
     46 		if err == EOF {
     47 			c <- 0
     48 			break
     49 		}
     50 		if err != nil {
     51 			t.Errorf("read: %v", err)
     52 		}
     53 		c <- n
     54 	}
     55 }
     56 
     57 // Test a sequence of read/write pairs.
     58 func TestPipe2(t *testing.T) {
     59 	c := make(chan int)
     60 	r, w := Pipe()
     61 	go reader(t, r, c)
     62 	var buf = make([]byte, 64)
     63 	for i := 0; i < 5; i++ {
     64 		p := buf[0 : 5+i*10]
     65 		n, err := w.Write(p)
     66 		if n != len(p) {
     67 			t.Errorf("wrote %d, got %d", len(p), n)
     68 		}
     69 		if err != nil {
     70 			t.Errorf("write: %v", err)
     71 		}
     72 		nn := <-c
     73 		if nn != n {
     74 			t.Errorf("wrote %d, read got %d", n, nn)
     75 		}
     76 	}
     77 	w.Close()
     78 	nn := <-c
     79 	if nn != 0 {
     80 		t.Errorf("final read got %d", nn)
     81 	}
     82 }
     83 
     84 type pipeReturn struct {
     85 	n   int
     86 	err error
     87 }
     88 
     89 // Test a large write that requires multiple reads to satisfy.
     90 func writer(w WriteCloser, buf []byte, c chan pipeReturn) {
     91 	n, err := w.Write(buf)
     92 	w.Close()
     93 	c <- pipeReturn{n, err}
     94 }
     95 
     96 func TestPipe3(t *testing.T) {
     97 	c := make(chan pipeReturn)
     98 	r, w := Pipe()
     99 	var wdat = make([]byte, 128)
    100 	for i := 0; i < len(wdat); i++ {
    101 		wdat[i] = byte(i)
    102 	}
    103 	go writer(w, wdat, c)
    104 	var rdat = make([]byte, 1024)
    105 	tot := 0
    106 	for n := 1; n <= 256; n *= 2 {
    107 		nn, err := r.Read(rdat[tot : tot+n])
    108 		if err != nil && err != EOF {
    109 			t.Fatalf("read: %v", err)
    110 		}
    111 
    112 		// only final two reads should be short - 1 byte, then 0
    113 		expect := n
    114 		if n == 128 {
    115 			expect = 1
    116 		} else if n == 256 {
    117 			expect = 0
    118 			if err != EOF {
    119 				t.Fatalf("read at end: %v", err)
    120 			}
    121 		}
    122 		if nn != expect {
    123 			t.Fatalf("read %d, expected %d, got %d", n, expect, nn)
    124 		}
    125 		tot += nn
    126 	}
    127 	pr := <-c
    128 	if pr.n != 128 || pr.err != nil {
    129 		t.Fatalf("write 128: %d, %v", pr.n, pr.err)
    130 	}
    131 	if tot != 128 {
    132 		t.Fatalf("total read %d != 128", tot)
    133 	}
    134 	for i := 0; i < 128; i++ {
    135 		if rdat[i] != byte(i) {
    136 			t.Fatalf("rdat[%d] = %d", i, rdat[i])
    137 		}
    138 	}
    139 }
    140 
    141 // Test read after/before writer close.
    142 
    143 type closer interface {
    144 	CloseWithError(error) error
    145 	Close() error
    146 }
    147 
    148 type pipeTest struct {
    149 	async          bool
    150 	err            error
    151 	closeWithError bool
    152 }
    153 
    154 func (p pipeTest) String() string {
    155 	return fmt.Sprintf("async=%v err=%v closeWithError=%v", p.async, p.err, p.closeWithError)
    156 }
    157 
    158 var pipeTests = []pipeTest{
    159 	{true, nil, false},
    160 	{true, nil, true},
    161 	{true, ErrShortWrite, true},
    162 	{false, nil, false},
    163 	{false, nil, true},
    164 	{false, ErrShortWrite, true},
    165 }
    166 
    167 func delayClose(t *testing.T, cl closer, ch chan int, tt pipeTest) {
    168 	time.Sleep(1 * time.Millisecond)
    169 	var err error
    170 	if tt.closeWithError {
    171 		err = cl.CloseWithError(tt.err)
    172 	} else {
    173 		err = cl.Close()
    174 	}
    175 	if err != nil {
    176 		t.Errorf("delayClose: %v", err)
    177 	}
    178 	ch <- 0
    179 }
    180 
    181 func TestPipeReadClose(t *testing.T) {
    182 	for _, tt := range pipeTests {
    183 		c := make(chan int, 1)
    184 		r, w := Pipe()
    185 		if tt.async {
    186 			go delayClose(t, w, c, tt)
    187 		} else {
    188 			delayClose(t, w, c, tt)
    189 		}
    190 		var buf = make([]byte, 64)
    191 		n, err := r.Read(buf)
    192 		<-c
    193 		want := tt.err
    194 		if want == nil {
    195 			want = EOF
    196 		}
    197 		if err != want {
    198 			t.Errorf("read from closed pipe: %v want %v", err, want)
    199 		}
    200 		if n != 0 {
    201 			t.Errorf("read on closed pipe returned %d", n)
    202 		}
    203 		if err = r.Close(); err != nil {
    204 			t.Errorf("r.Close: %v", err)
    205 		}
    206 	}
    207 }
    208 
    209 // Test close on Read side during Read.
    210 func TestPipeReadClose2(t *testing.T) {
    211 	c := make(chan int, 1)
    212 	r, _ := Pipe()
    213 	go delayClose(t, r, c, pipeTest{})
    214 	n, err := r.Read(make([]byte, 64))
    215 	<-c
    216 	if n != 0 || err != ErrClosedPipe {
    217 		t.Errorf("read from closed pipe: %v, %v want %v, %v", n, err, 0, ErrClosedPipe)
    218 	}
    219 }
    220 
    221 // Test write after/before reader close.
    222 
    223 func TestPipeWriteClose(t *testing.T) {
    224 	for _, tt := range pipeTests {
    225 		c := make(chan int, 1)
    226 		r, w := Pipe()
    227 		if tt.async {
    228 			go delayClose(t, r, c, tt)
    229 		} else {
    230 			delayClose(t, r, c, tt)
    231 		}
    232 		n, err := WriteString(w, "hello, world")
    233 		<-c
    234 		expect := tt.err
    235 		if expect == nil {
    236 			expect = ErrClosedPipe
    237 		}
    238 		if err != expect {
    239 			t.Errorf("write on closed pipe: %v want %v", err, expect)
    240 		}
    241 		if n != 0 {
    242 			t.Errorf("write on closed pipe returned %d", n)
    243 		}
    244 		if err = w.Close(); err != nil {
    245 			t.Errorf("w.Close: %v", err)
    246 		}
    247 	}
    248 }
    249 
    250 // Test close on Write side during Write.
    251 func TestPipeWriteClose2(t *testing.T) {
    252 	c := make(chan int, 1)
    253 	_, w := Pipe()
    254 	go delayClose(t, w, c, pipeTest{})
    255 	n, err := w.Write(make([]byte, 64))
    256 	<-c
    257 	if n != 0 || err != ErrClosedPipe {
    258 		t.Errorf("write to closed pipe: %v, %v want %v, %v", n, err, 0, ErrClosedPipe)
    259 	}
    260 }
    261 
    262 func TestWriteEmpty(t *testing.T) {
    263 	r, w := Pipe()
    264 	go func() {
    265 		w.Write([]byte{})
    266 		w.Close()
    267 	}()
    268 	var b [2]byte
    269 	ReadFull(r, b[0:2])
    270 	r.Close()
    271 }
    272 
    273 func TestWriteNil(t *testing.T) {
    274 	r, w := Pipe()
    275 	go func() {
    276 		w.Write(nil)
    277 		w.Close()
    278 	}()
    279 	var b [2]byte
    280 	ReadFull(r, b[0:2])
    281 	r.Close()
    282 }
    283 
    284 func TestWriteAfterWriterClose(t *testing.T) {
    285 	r, w := Pipe()
    286 
    287 	done := make(chan bool)
    288 	var writeErr error
    289 	go func() {
    290 		_, err := w.Write([]byte("hello"))
    291 		if err != nil {
    292 			t.Errorf("got error: %q; expected none", err)
    293 		}
    294 		w.Close()
    295 		_, writeErr = w.Write([]byte("world"))
    296 		done <- true
    297 	}()
    298 
    299 	buf := make([]byte, 100)
    300 	var result string
    301 	n, err := ReadFull(r, buf)
    302 	if err != nil && err != ErrUnexpectedEOF {
    303 		t.Fatalf("got: %q; want: %q", err, ErrUnexpectedEOF)
    304 	}
    305 	result = string(buf[0:n])
    306 	<-done
    307 
    308 	if result != "hello" {
    309 		t.Errorf("got: %q; want: %q", result, "hello")
    310 	}
    311 	if writeErr != ErrClosedPipe {
    312 		t.Errorf("got: %q; want: %q", writeErr, ErrClosedPipe)
    313 	}
    314 }
    315