Source file test/closedchan.go

     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  

View as plain text