1 // run 2 3 // Copyright 2010 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 the semantics of the select statement 8 // for basic empty/non-empty cases. 9 10 package main 11 12 import "time" 13 14 const always = "function did not" 15 const never = "function did" 16 17 18 func unreachable() { 19 panic("control flow shouldn't reach here") 20 } 21 22 23 // Calls f and verifies that f always/never panics depending on signal. 24 func testPanic(signal string, f func()) { 25 defer func() { 26 s := never 27 if recover() != nil { 28 s = always // f panicked 29 } 30 if s != signal { 31 panic(signal + " panic") 32 } 33 }() 34 f() 35 } 36 37 38 // Calls f and empirically verifies that f always/never blocks depending on signal. 39 func testBlock(signal string, f func()) { 40 c := make(chan string) 41 go func() { 42 f() 43 c <- never // f didn't block 44 }() 45 go func() { 46 time.Sleep(1e8) // 0.1s seems plenty long 47 c <- always // f blocked always 48 }() 49 if <-c != signal { 50 panic(signal + " block") 51 } 52 } 53 54 55 func main() { 56 const async = 1 // asynchronous channels 57 var nilch chan int 58 closedch := make(chan int) 59 close(closedch) 60 61 // sending/receiving from a nil channel blocks 62 testBlock(always, func() { 63 nilch <- 7 64 }) 65 testBlock(always, func() { 66 <-nilch 67 }) 68 69 // sending/receiving from a nil channel inside a select is never selected 70 testPanic(never, func() { 71 select { 72 case nilch <- 7: 73 unreachable() 74 default: 75 } 76 }) 77 testPanic(never, func() { 78 select { 79 case <-nilch: 80 unreachable() 81 default: 82 } 83 }) 84 85 // sending to an async channel with free buffer space never blocks 86 testBlock(never, func() { 87 ch := make(chan int, async) 88 ch <- 7 89 }) 90 91 // receiving from a closed channel never blocks 92 testBlock(never, func() { 93 for i := 0; i < 10; i++ { 94 if <-closedch != 0 { 95 panic("expected zero value when reading from closed channel") 96 } 97 if x, ok := <-closedch; x != 0 || ok { 98 println("closedch:", x, ok) 99 panic("expected 0, false from closed channel") 100 } 101 } 102 }) 103 104 // sending to a closed channel panics. 105 testPanic(always, func() { 106 closedch <- 7 107 }) 108 109 // receiving from a non-ready channel always blocks 110 testBlock(always, func() { 111 ch := make(chan int) 112 <-ch 113 }) 114 115 // empty selects always block 116 testBlock(always, func() { 117 select { 118 } 119 }) 120 121 // selects with only nil channels always block 122 testBlock(always, func() { 123 select { 124 case <-nilch: 125 unreachable() 126 } 127 }) 128 testBlock(always, func() { 129 select { 130 case nilch <- 7: 131 unreachable() 132 } 133 }) 134 testBlock(always, func() { 135 select { 136 case <-nilch: 137 unreachable() 138 case nilch <- 7: 139 unreachable() 140 } 141 }) 142 143 // selects with non-ready non-nil channels always block 144 testBlock(always, func() { 145 ch := make(chan int) 146 select { 147 case <-ch: 148 unreachable() 149 } 150 }) 151 152 // selects with default cases don't block 153 testBlock(never, func() { 154 select { 155 default: 156 } 157 }) 158 testBlock(never, func() { 159 select { 160 case <-nilch: 161 unreachable() 162 default: 163 } 164 }) 165 testBlock(never, func() { 166 select { 167 case nilch <- 7: 168 unreachable() 169 default: 170 } 171 }) 172 173 // selects with ready channels don't block 174 testBlock(never, func() { 175 ch := make(chan int, async) 176 select { 177 case ch <- 7: 178 default: 179 unreachable() 180 } 181 }) 182 testBlock(never, func() { 183 ch := make(chan int, async) 184 ch <- 7 185 select { 186 case <-ch: 187 default: 188 unreachable() 189 } 190 }) 191 192 // selects with closed channels behave like ordinary operations 193 testBlock(never, func() { 194 select { 195 case <-closedch: 196 } 197 }) 198 testBlock(never, func() { 199 select { 200 case x := (<-closedch): 201 _ = x 202 } 203 }) 204 testBlock(never, func() { 205 select { 206 case x, ok := (<-closedch): 207 _, _ = x, ok 208 } 209 }) 210 testPanic(always, func() { 211 select { 212 case closedch <- 7: 213 } 214 }) 215 216 // select should not get confused if it sees itself 217 testBlock(always, func() { 218 c := make(chan int) 219 select { 220 case c <- 1: 221 case <-c: 222 } 223 }) 224 } 225