| // run | |
| // Copyright 2009 The Go Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style | |
| // license that can be found in the LICENSE file. | |
| // Test close(c), receive of closed channel. | |
| // | |
| // TODO(rsc): Doesn't check behavior of close(c) when there | |
| // are blocked senders/receivers. | |
| package main | |
| import "os" | |
| var failed bool | |
| type Chan interface { | |
| Send(int) | |
| Nbsend(int) bool | |
| Recv() (int) | |
| Nbrecv() (int, bool) | |
| Recv2() (int, bool) | |
| Nbrecv2() (int, bool, bool) | |
| Close() | |
| Impl() string | |
| } | |
| // direct channel operations when possible | |
| type XChan chan int | |
| func (c XChan) Send(x int) { | |
| c <- x | |
| } | |
| func (c XChan) Nbsend(x int) bool { | |
| select { | |
| case c <- x: | |
| return true | |
| default: | |
| return false | |
| } | |
| panic("nbsend") | |
| } | |
| func (c XChan) Recv() int { | |
| return <-c | |
| } | |
| func (c XChan) Nbrecv() (int, bool) { | |
| select { | |
| case x := <-c: | |
| return x, true | |
| default: | |
| return 0, false | |
| } | |
| panic("nbrecv") | |
| } | |
| func (c XChan) Recv2() (int, bool) { | |
| x, ok := <-c | |
| return x, ok | |
| } | |
| func (c XChan) Nbrecv2() (int, bool, bool) { | |
| select { | |
| case x, ok := <-c: | |
| return x, ok, true | |
| default: | |
| return 0, false, false | |
| } | |
| panic("nbrecv2") | |
| } | |
| func (c XChan) Close() { | |
| close(c) | |
| } | |
| func (c XChan) Impl() string { | |
| return "(<- operator)" | |
| } | |
| // indirect operations via select | |
| type SChan chan int | |
| func (c SChan) Send(x int) { | |
| select { | |
| case c <- x: | |
| } | |
| } | |
| func (c SChan) Nbsend(x int) bool { | |
| select { | |
| default: | |
| return false | |
| case c <- x: | |
| return true | |
| } | |
| panic("nbsend") | |
| } | |
| func (c SChan) Recv() int { | |
| select { | |
| case x := <-c: | |
| return x | |
| } | |
| panic("recv") | |
| } | |
| func (c SChan) Nbrecv() (int, bool) { | |
| select { | |
| default: | |
| return 0, false | |
| case x := <-c: | |
| return x, true | |
| } | |
| panic("nbrecv") | |
| } | |
| func (c SChan) Recv2() (int, bool) { | |
| select { | |
| case x, ok := <-c: | |
| return x, ok | |
| } | |
| panic("recv") | |
| } | |
| func (c SChan) Nbrecv2() (int, bool, bool) { | |
| select { | |
| default: | |
| return 0, false, false | |
| case x, ok := <-c: | |
| return x, ok, true | |
| } | |
| panic("nbrecv") | |
| } | |
| func (c SChan) Close() { | |
| close(c) | |
| } | |
| func (c SChan) Impl() string { | |
| return "(select)" | |
| } | |
| // indirect operations via larger selects | |
| var dummy = make(chan bool) | |
| type SSChan chan int | |
| func (c SSChan) Send(x int) { | |
| select { | |
| case c <- x: | |
| case <-dummy: | |
| } | |
| } | |
| func (c SSChan) Nbsend(x int) bool { | |
| select { | |
| default: | |
| return false | |
| case <-dummy: | |
| case c <- x: | |
| return true | |
| } | |
| panic("nbsend") | |
| } | |
| func (c SSChan) Recv() int { | |
| select { | |
| case <-dummy: | |
| case x := <-c: | |
| return x | |
| } | |
| panic("recv") | |
| } | |
| func (c SSChan) Nbrecv() (int, bool) { | |
| select { | |
| case <-dummy: | |
| default: | |
| return 0, false | |
| case x := <-c: | |
| return x, true | |
| } | |
| panic("nbrecv") | |
| } | |
| func (c SSChan) Recv2() (int, bool) { | |
| select { | |
| case <-dummy: | |
| case x, ok := <-c: | |
| return x, ok | |
| } | |
| panic("recv") | |
| } | |
| func (c SSChan) Nbrecv2() (int, bool, bool) { | |
| select { | |
| case <-dummy: | |
| default: | |
| return 0, false, false | |
| case x, ok := <-c: | |
| return x, ok, true | |
| } | |
| panic("nbrecv") | |
| } | |
| func (c SSChan) Close() { | |
| close(c) | |
| } | |
| func (c SSChan) Impl() string { | |
| return "(select)" | |
| } | |
| func shouldPanic(f func()) { | |
| defer func() { | |
| if recover() == nil { | |
| panic("did not panic") | |
| } | |
| }() | |
| f() | |
| } | |
| func test1(c Chan) { | |
| for i := 0; i < 3; i++ { | |
| // recv a close signal (a zero value) | |
| if x := c.Recv(); x != 0 { | |
| println("test1: recv on closed:", x, c.Impl()) | |
| failed = true | |
| } | |
| if x, ok := c.Recv2(); x != 0 || ok { | |
| println("test1: recv2 on closed:", x, ok, c.Impl()) | |
| failed = true | |
| } | |
| // should work with select: received a value without blocking, so selected == true. | |
| x, selected := c.Nbrecv() | |
| if x != 0 || !selected { | |
| println("test1: recv on closed nb:", x, selected, c.Impl()) | |
| failed = true | |
| } | |
| x, ok, selected := c.Nbrecv2() | |
| if x != 0 || ok || !selected { | |
| println("test1: recv2 on closed nb:", x, ok, selected, c.Impl()) | |
| failed = true | |
| } | |
| } | |
| // send should work with ,ok too: sent a value without blocking, so ok == true. | |
| shouldPanic(func() { c.Nbsend(1) }) | |
| // the value should have been discarded. | |
| if x := c.Recv(); x != 0 { | |
| println("test1: recv on closed got non-zero after send on closed:", x, c.Impl()) | |
| failed = true | |
| } | |
| // similarly Send. | |
| shouldPanic(func() { c.Send(2) }) | |
| if x := c.Recv(); x != 0 { | |
| println("test1: recv on closed got non-zero after send on closed:", x, c.Impl()) | |
| failed = true | |
| } | |
| } | |
| func testasync1(c Chan) { | |
| // should be able to get the last value via Recv | |
| if x := c.Recv(); x != 1 { | |
| println("testasync1: Recv did not get 1:", x, c.Impl()) | |
| failed = true | |
| } | |
| test1(c) | |
| } | |
| func testasync2(c Chan) { | |
| // should be able to get the last value via Recv2 | |
| if x, ok := c.Recv2(); x != 1 || !ok { | |
| println("testasync1: Recv did not get 1, true:", x, ok, c.Impl()) | |
| failed = true | |
| } | |
| test1(c) | |
| } | |
| func testasync3(c Chan) { | |
| // should be able to get the last value via Nbrecv | |
| if x, selected := c.Nbrecv(); x != 1 || !selected { | |
| println("testasync2: Nbrecv did not get 1, true:", x, selected, c.Impl()) | |
| failed = true | |
| } | |
| test1(c) | |
| } | |
| func testasync4(c Chan) { | |
| // should be able to get the last value via Nbrecv2 | |
| if x, ok, selected := c.Nbrecv2(); x != 1 || !ok || !selected { | |
| println("testasync2: Nbrecv did not get 1, true, true:", x, ok, selected, c.Impl()) | |
| failed = true | |
| } | |
| test1(c) | |
| } | |
| func closedsync() chan int { | |
| c := make(chan int) | |
| close(c) | |
| return c | |
| } | |
| func closedasync() chan int { | |
| c := make(chan int, 2) | |
| c <- 1 | |
| close(c) | |
| return c | |
| } | |
| var mks = []func(chan int) Chan { | |
| func(c chan int) Chan { return XChan(c) }, | |
| func(c chan int) Chan { return SChan(c) }, | |
| func(c chan int) Chan { return SSChan(c) }, | |
| } | |
| var testcloseds = []func(Chan) { | |
| testasync1, | |
| testasync2, | |
| testasync3, | |
| testasync4, | |
| } | |
| func main() { | |
| for _, mk := range mks { | |
| test1(mk(closedsync())) | |
| } | |
| for _, testclosed := range testcloseds { | |
| for _, mk := range mks { | |
| testclosed(mk(closedasync())) | |
| } | |
| } | |
| var ch chan int | |
| shouldPanic(func() { | |
| close(ch) | |
| }) | |
| ch = make(chan int) | |
| close(ch) | |
| shouldPanic(func() { | |
| close(ch) | |
| }) | |
| if failed { | |
| os.Exit(1) | |
| } | |
| } |