modernc.org/gc@v1.0.1-0.20240304020402-f0dba7c97c2b/testdata/errchk/test/closedchan.go (about) 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 }