...
Run Format

Source file test/closedchan.go

Documentation: test

  // 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)
  	}
  }
  

View as plain text