blob: 0dbe662d84f985b6821c5d5260bd988a5dbbceec [file] [log] [blame]
// $G $D/$F.go && $L $F.$A && ./$A.out
// 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
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())
}
if x, ok := c.Recv2(); x != 0 || ok {
println("test1: recv2 on closed:", x, ok, c.Impl())
}
// 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())
}
x, ok, selected := c.Nbrecv2()
if x != 0 || ok || !selected {
println("test1: recv2 on closed nb:", x, ok, selected, c.Impl())
}
}
// 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())
}
// 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())
}
}
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())
}
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())
}
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())
}
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())
}
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)
})
}