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