modernc.org/gc@v1.0.1-0.20240304020402-f0dba7c97c2b/testdata/errchk/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 if signal == never { 44 // Wait a long time to make sure that we don't miss our window by accident on a slow machine. 45 time.Sleep(10 * time.Second) 46 } else { 47 // Wait as short a time as we can without false negatives. 48 // 10ms should be long enough to catch most failures. 49 time.Sleep(10 * time.Millisecond) 50 } 51 c <- always // f blocked always 52 }() 53 if <-c != signal { 54 panic(signal + " block") 55 } 56 } 57 58 func main() { 59 const async = 1 // asynchronous channels 60 var nilch chan int 61 closedch := make(chan int) 62 close(closedch) 63 64 // sending/receiving from a nil channel blocks 65 testBlock(always, func() { 66 nilch <- 7 67 }) 68 testBlock(always, func() { 69 <-nilch 70 }) 71 72 // sending/receiving from a nil channel inside a select is never selected 73 testPanic(never, func() { 74 select { 75 case nilch <- 7: 76 unreachable() 77 default: 78 } 79 }) 80 testPanic(never, func() { 81 select { 82 case <-nilch: 83 unreachable() 84 default: 85 } 86 }) 87 88 // sending to an async channel with free buffer space never blocks 89 testBlock(never, func() { 90 ch := make(chan int, async) 91 ch <- 7 92 }) 93 94 // receiving from a closed channel never blocks 95 testBlock(never, func() { 96 for i := 0; i < 10; i++ { 97 if <-closedch != 0 { 98 panic("expected zero value when reading from closed channel") 99 } 100 if x, ok := <-closedch; x != 0 || ok { 101 println("closedch:", x, ok) 102 panic("expected 0, false from closed channel") 103 } 104 } 105 }) 106 107 // sending to a closed channel panics. 108 testPanic(always, func() { 109 closedch <- 7 110 }) 111 112 // receiving from a non-ready channel always blocks 113 testBlock(always, func() { 114 ch := make(chan int) 115 <-ch 116 }) 117 118 // empty selects always block 119 testBlock(always, func() { 120 select {} 121 }) 122 123 // selects with only nil channels always block 124 testBlock(always, func() { 125 select { 126 case <-nilch: 127 unreachable() 128 } 129 }) 130 testBlock(always, func() { 131 select { 132 case nilch <- 7: 133 unreachable() 134 } 135 }) 136 testBlock(always, func() { 137 select { 138 case <-nilch: 139 unreachable() 140 case nilch <- 7: 141 unreachable() 142 } 143 }) 144 145 // selects with non-ready non-nil channels always block 146 testBlock(always, func() { 147 ch := make(chan int) 148 select { 149 case <-ch: 150 unreachable() 151 } 152 }) 153 154 // selects with default cases don't block 155 testBlock(never, func() { 156 select { 157 default: 158 } 159 }) 160 testBlock(never, func() { 161 select { 162 case <-nilch: 163 unreachable() 164 default: 165 } 166 }) 167 testBlock(never, func() { 168 select { 169 case nilch <- 7: 170 unreachable() 171 default: 172 } 173 }) 174 175 // selects with ready channels don't block 176 testBlock(never, func() { 177 ch := make(chan int, async) 178 select { 179 case ch <- 7: 180 default: 181 unreachable() 182 } 183 }) 184 testBlock(never, func() { 185 ch := make(chan int, async) 186 ch <- 7 187 select { 188 case <-ch: 189 default: 190 unreachable() 191 } 192 }) 193 194 // selects with closed channels behave like ordinary operations 195 testBlock(never, func() { 196 select { 197 case <-closedch: 198 } 199 }) 200 testBlock(never, func() { 201 select { 202 case x := (<-closedch): 203 _ = x 204 } 205 }) 206 testBlock(never, func() { 207 select { 208 case x, ok := (<-closedch): 209 _, _ = x, ok 210 } 211 }) 212 testPanic(always, func() { 213 select { 214 case closedch <- 7: 215 } 216 }) 217 218 // select should not get confused if it sees itself 219 testBlock(always, func() { 220 c := make(chan int) 221 select { 222 case c <- 1: 223 case <-c: 224 } 225 }) 226 }