Home | History | Annotate | Download | only in test
      1 // run
      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 // Test close(c), receive of closed channel.
      8 //
      9 // TODO(rsc): Doesn't check behavior of close(c) when there
     10 // are blocked senders/receivers.
     11 
     12 package main
     13 
     14 import "os"
     15 
     16 var failed bool
     17 
     18 type Chan interface {
     19 	Send(int)
     20 	Nbsend(int) bool
     21 	Recv() (int)
     22 	Nbrecv() (int, bool)
     23 	Recv2() (int, bool)
     24 	Nbrecv2() (int, bool, bool)
     25 	Close()
     26 	Impl() string
     27 }
     28 
     29 // direct channel operations when possible
     30 type XChan chan int
     31 
     32 func (c XChan) Send(x int) {
     33 	c <- x
     34 }
     35 
     36 func (c XChan) Nbsend(x int) bool {
     37 	select {
     38 	case c <- x:
     39 		return true
     40 	default:
     41 		return false
     42 	}
     43 	panic("nbsend")
     44 }
     45 
     46 func (c XChan) Recv() int {
     47 	return <-c
     48 }
     49 
     50 func (c XChan) Nbrecv() (int, bool) {
     51 	select {
     52 	case x := <-c:
     53 		return x, true
     54 	default:
     55 		return 0, false
     56 	}
     57 	panic("nbrecv")
     58 }
     59 
     60 func (c XChan) Recv2() (int, bool) {
     61 	x, ok := <-c
     62 	return x, ok
     63 }
     64 
     65 func (c XChan) Nbrecv2() (int, bool, bool) {
     66 	select {
     67 	case x, ok := <-c:
     68 		return x, ok, true
     69 	default:
     70 		return 0, false, false
     71 	}
     72 	panic("nbrecv2")
     73 }
     74 
     75 func (c XChan) Close() {
     76 	close(c)
     77 }
     78 
     79 func (c XChan) Impl() string {
     80 	return "(<- operator)"
     81 }
     82 
     83 // indirect operations via select
     84 type SChan chan int
     85 
     86 func (c SChan) Send(x int) {
     87 	select {
     88 	case c <- x:
     89 	}
     90 }
     91 
     92 func (c SChan) Nbsend(x int) bool {
     93 	select {
     94 	default:
     95 		return false
     96 	case c <- x:
     97 		return true
     98 	}
     99 	panic("nbsend")
    100 }
    101 
    102 func (c SChan) Recv() int {
    103 	select {
    104 	case x := <-c:
    105 		return x
    106 	}
    107 	panic("recv")
    108 }
    109 
    110 func (c SChan) Nbrecv() (int, bool) {
    111 	select {
    112 	default:
    113 		return 0, false
    114 	case x := <-c:
    115 		return x, true
    116 	}
    117 	panic("nbrecv")
    118 }
    119 
    120 func (c SChan) Recv2() (int, bool) {
    121 	select {
    122 	case x, ok := <-c:
    123 		return x, ok
    124 	}
    125 	panic("recv")
    126 }
    127 
    128 func (c SChan) Nbrecv2() (int, bool, bool) {
    129 	select {
    130 	default:
    131 		return 0, false, false
    132 	case x, ok := <-c:
    133 		return x, ok, true
    134 	}
    135 	panic("nbrecv")
    136 }
    137 
    138 func (c SChan) Close() {
    139 	close(c)
    140 }
    141 
    142 func (c SChan) Impl() string {
    143 	return "(select)"
    144 }
    145 
    146 // indirect operations via larger selects
    147 var dummy = make(chan bool)
    148 
    149 type SSChan chan int
    150 
    151 func (c SSChan) Send(x int) {
    152 	select {
    153 	case c <- x:
    154 	case <-dummy:
    155 	}
    156 }
    157 
    158 func (c SSChan) Nbsend(x int) bool {
    159 	select {
    160 	default:
    161 		return false
    162 	case <-dummy:
    163 	case c <- x:
    164 		return true
    165 	}
    166 	panic("nbsend")
    167 }
    168 
    169 func (c SSChan) Recv() int {
    170 	select {
    171 	case <-dummy:
    172 	case x := <-c:
    173 		return x
    174 	}
    175 	panic("recv")
    176 }
    177 
    178 func (c SSChan) Nbrecv() (int, bool) {
    179 	select {
    180 	case <-dummy:
    181 	default:
    182 		return 0, false
    183 	case x := <-c:
    184 		return x, true
    185 	}
    186 	panic("nbrecv")
    187 }
    188 
    189 func (c SSChan) Recv2() (int, bool) {
    190 	select {
    191 	case <-dummy:
    192 	case x, ok := <-c:
    193 		return x, ok
    194 	}
    195 	panic("recv")
    196 }
    197 
    198 func (c SSChan) Nbrecv2() (int, bool, bool) {
    199 	select {
    200 	case <-dummy:
    201 	default:
    202 		return 0, false, false
    203 	case x, ok := <-c:
    204 		return x, ok, true
    205 	}
    206 	panic("nbrecv")
    207 }
    208 
    209 func (c SSChan) Close() {
    210 	close(c)
    211 }
    212 
    213 func (c SSChan) Impl() string {
    214 	return "(select)"
    215 }
    216 
    217 
    218 func shouldPanic(f func()) {
    219 	defer func() {
    220 		if recover() == nil {
    221 			panic("did not panic")
    222 		}
    223 	}()
    224 	f()
    225 }
    226 
    227 func test1(c Chan) {
    228 	for i := 0; i < 3; i++ {
    229 		// recv a close signal (a zero value)
    230 		if x := c.Recv(); x != 0 {
    231 			println("test1: recv on closed:", x, c.Impl())
    232 			failed = true
    233 		}
    234 		if x, ok := c.Recv2(); x != 0 || ok {
    235 			println("test1: recv2 on closed:", x, ok, c.Impl())
    236 			failed = true
    237 		}
    238 
    239 		// should work with select: received a value without blocking, so selected == true.
    240 		x, selected := c.Nbrecv()
    241 		if x != 0 || !selected {
    242 			println("test1: recv on closed nb:", x, selected, c.Impl())
    243 			failed = true
    244 		}
    245 		x, ok, selected := c.Nbrecv2()
    246 		if x != 0 || ok || !selected {
    247 			println("test1: recv2 on closed nb:", x, ok, selected, c.Impl())
    248 			failed = true
    249 		}
    250 	}
    251 
    252 	// send should work with ,ok too: sent a value without blocking, so ok == true.
    253 	shouldPanic(func() { c.Nbsend(1) })
    254 
    255 	// the value should have been discarded.
    256 	if x := c.Recv(); x != 0 {
    257 		println("test1: recv on closed got non-zero after send on closed:", x, c.Impl())
    258 		failed = true
    259 	}
    260 
    261 	// similarly Send.
    262 	shouldPanic(func() { c.Send(2) })
    263 	if x := c.Recv(); x != 0 {
    264 		println("test1: recv on closed got non-zero after send on closed:", x, c.Impl())
    265 		failed = true
    266 	}
    267 }
    268 
    269 func testasync1(c Chan) {
    270 	// should be able to get the last value via Recv
    271 	if x := c.Recv(); x != 1 {
    272 		println("testasync1: Recv did not get 1:", x, c.Impl())
    273 		failed = true
    274 	}
    275 
    276 	test1(c)
    277 }
    278 
    279 func testasync2(c Chan) {
    280 	// should be able to get the last value via Recv2
    281 	if x, ok := c.Recv2(); x != 1 || !ok {
    282 		println("testasync1: Recv did not get 1, true:", x, ok, c.Impl())
    283 		failed = true
    284 	}
    285 
    286 	test1(c)
    287 }
    288 
    289 func testasync3(c Chan) {
    290 	// should be able to get the last value via Nbrecv
    291 	if x, selected := c.Nbrecv(); x != 1 || !selected {
    292 		println("testasync2: Nbrecv did not get 1, true:", x, selected, c.Impl())
    293 		failed = true
    294 	}
    295 
    296 	test1(c)
    297 }
    298 
    299 func testasync4(c Chan) {
    300 	// should be able to get the last value via Nbrecv2
    301 	if x, ok, selected := c.Nbrecv2(); x != 1 || !ok || !selected {
    302 		println("testasync2: Nbrecv did not get 1, true, true:", x, ok, selected, c.Impl())
    303 		failed = true
    304 	}
    305 	test1(c)
    306 }
    307 
    308 func closedsync() chan int {
    309 	c := make(chan int)
    310 	close(c)
    311 	return c
    312 }
    313 
    314 func closedasync() chan int {
    315 	c := make(chan int, 2)
    316 	c <- 1
    317 	close(c)
    318 	return c
    319 }
    320 
    321 var mks = []func(chan int) Chan {
    322 	func(c chan int) Chan { return XChan(c) },
    323 	func(c chan int) Chan { return SChan(c) },
    324 	func(c chan int) Chan { return SSChan(c) },
    325 }
    326 
    327 var testcloseds = []func(Chan) {
    328 	testasync1,
    329 	testasync2,
    330 	testasync3,
    331 	testasync4,
    332 }
    333 
    334 func main() {
    335 	for _, mk := range mks {
    336 		test1(mk(closedsync()))
    337 	}
    338 	
    339 	for _, testclosed := range testcloseds {
    340 		for _, mk := range mks {
    341 			testclosed(mk(closedasync()))
    342 		}
    343 	}
    344 	
    345 	var ch chan int	
    346 	shouldPanic(func() {
    347 		close(ch)
    348 	})
    349 	
    350 	ch = make(chan int)
    351 	close(ch)
    352 	shouldPanic(func() {
    353 		close(ch)
    354 	})
    355 
    356 	if failed {
    357 		os.Exit(1)
    358 	}
    359 }
    360