1 // runoutput 2 3 // Copyright 2011 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 // Generate test of channel operations and simple selects. 8 // The output of this program is compiled and run to do the 9 // actual test. 10 11 // Each test does only one real send or receive at a time, but phrased 12 // in various ways that the compiler may or may not rewrite 13 // into simpler expressions. 14 15 package main 16 17 import ( 18 "bufio" 19 "fmt" 20 "io" 21 "os" 22 "text/template" 23 ) 24 25 func main() { 26 out := bufio.NewWriter(os.Stdout) 27 fmt.Fprintln(out, header) 28 a := new(arg) 29 30 // Generate each test as a separate function to avoid 31 // hitting the gc optimizer with one enormous function. 32 // If we name all the functions init we don't have to 33 // maintain a list of which ones to run. 34 do := func(t *template.Template) { 35 for ; next(); a.reset() { 36 fmt.Fprintln(out, `func init() {`) 37 run(t, a, out) 38 fmt.Fprintln(out, `}`) 39 } 40 } 41 42 do(recv) 43 do(send) 44 do(recvOrder) 45 do(sendOrder) 46 do(nonblock) 47 48 fmt.Fprintln(out, "//", a.nreset, "cases") 49 out.Flush() 50 } 51 52 func run(t *template.Template, a interface{}, out io.Writer) { 53 if err := t.Execute(out, a); err != nil { 54 panic(err) 55 } 56 } 57 58 type arg struct { 59 def bool 60 nreset int 61 } 62 63 func (a *arg) Maybe() bool { 64 return maybe() 65 } 66 67 func (a *arg) MaybeDefault() bool { 68 if a.def { 69 return false 70 } 71 a.def = maybe() 72 return a.def 73 } 74 75 func (a *arg) MustDefault() bool { 76 return !a.def 77 } 78 79 func (a *arg) reset() { 80 a.def = false 81 a.nreset++ 82 } 83 84 const header = `// GENERATED BY select5.go; DO NOT EDIT 85 86 package main 87 88 // channel is buffered so test is single-goroutine. 89 // we are not interested in the concurrency aspects 90 // of select, just testing that the right calls happen. 91 var c = make(chan int, 1) 92 var nilch chan int 93 var n = 1 94 var x int 95 var i interface{} 96 var dummy = make(chan int) 97 var m = make(map[int]int) 98 var order = 0 99 100 func f(p *int) *int { 101 return p 102 } 103 104 // check order of operations by ensuring that 105 // successive calls to checkorder have increasing o values. 106 func checkorder(o int) { 107 if o <= order { 108 println("invalid order", o, "after", order) 109 panic("order") 110 } 111 order = o 112 } 113 114 func fc(c chan int, o int) chan int { 115 checkorder(o) 116 return c 117 } 118 119 func fp(p *int, o int) *int { 120 checkorder(o) 121 return p 122 } 123 124 func fn(n, o int) int { 125 checkorder(o) 126 return n 127 } 128 129 func die(x int) { 130 println("have", x, "want", n) 131 panic("chan") 132 } 133 134 func main() { 135 // everything happens in init funcs 136 } 137 ` 138 139 func parse(name, s string) *template.Template { 140 t, err := template.New(name).Parse(s) 141 if err != nil { 142 panic(fmt.Sprintf("%q: %s", name, err)) 143 } 144 return t 145 } 146 147 var recv = parse("recv", ` 148 {{/* Send n, receive it one way or another into x, check that they match. */}} 149 c <- n 150 {{if .Maybe}} 151 x = <-c 152 {{else}} 153 select { 154 {{/* Blocking or non-blocking, before the receive. */}} 155 {{/* The compiler implements two-case select where one is default with custom code, */}} 156 {{/* so test the default branch both before and after the send. */}} 157 {{if .MaybeDefault}} 158 default: 159 panic("nonblock") 160 {{end}} 161 {{/* Receive from c. Different cases are direct, indirect, :=, interface, and map assignment. */}} 162 {{if .Maybe}} 163 case x = <-c: 164 {{else}}{{if .Maybe}} 165 case *f(&x) = <-c: 166 {{else}}{{if .Maybe}} 167 case y := <-c: 168 x = y 169 {{else}}{{if .Maybe}} 170 case i = <-c: 171 x = i.(int) 172 {{else}} 173 case m[13] = <-c: 174 x = m[13] 175 {{end}}{{end}}{{end}}{{end}} 176 {{/* Blocking or non-blocking again, after the receive. */}} 177 {{if .MaybeDefault}} 178 default: 179 panic("nonblock") 180 {{end}} 181 {{/* Dummy send, receive to keep compiler from optimizing select. */}} 182 {{if .Maybe}} 183 case dummy <- 1: 184 panic("dummy send") 185 {{end}} 186 {{if .Maybe}} 187 case <-dummy: 188 panic("dummy receive") 189 {{end}} 190 {{/* Nil channel send, receive to keep compiler from optimizing select. */}} 191 {{if .Maybe}} 192 case nilch <- 1: 193 panic("nilch send") 194 {{end}} 195 {{if .Maybe}} 196 case <-nilch: 197 panic("nilch recv") 198 {{end}} 199 } 200 {{end}} 201 if x != n { 202 die(x) 203 } 204 n++ 205 `) 206 207 var recvOrder = parse("recvOrder", ` 208 {{/* Send n, receive it one way or another into x, check that they match. */}} 209 {{/* Check order of operations along the way by calling functions that check */}} 210 {{/* that the argument sequence is strictly increasing. */}} 211 order = 0 212 c <- n 213 {{if .Maybe}} 214 {{/* Outside of select, left-to-right rule applies. */}} 215 {{/* (Inside select, assignment waits until case is chosen, */}} 216 {{/* so right hand side happens before anything on left hand side. */}} 217 *fp(&x, 1) = <-fc(c, 2) 218 {{else}}{{if .Maybe}} 219 m[fn(13, 1)] = <-fc(c, 2) 220 x = m[13] 221 {{else}} 222 select { 223 {{/* Blocking or non-blocking, before the receive. */}} 224 {{/* The compiler implements two-case select where one is default with custom code, */}} 225 {{/* so test the default branch both before and after the send. */}} 226 {{if .MaybeDefault}} 227 default: 228 panic("nonblock") 229 {{end}} 230 {{/* Receive from c. Different cases are direct, indirect, :=, interface, and map assignment. */}} 231 {{if .Maybe}} 232 case *fp(&x, 100) = <-fc(c, 1): 233 {{else}}{{if .Maybe}} 234 case y := <-fc(c, 1): 235 x = y 236 {{else}}{{if .Maybe}} 237 case i = <-fc(c, 1): 238 x = i.(int) 239 {{else}} 240 case m[fn(13, 100)] = <-fc(c, 1): 241 x = m[13] 242 {{end}}{{end}}{{end}} 243 {{/* Blocking or non-blocking again, after the receive. */}} 244 {{if .MaybeDefault}} 245 default: 246 panic("nonblock") 247 {{end}} 248 {{/* Dummy send, receive to keep compiler from optimizing select. */}} 249 {{if .Maybe}} 250 case fc(dummy, 2) <- fn(1, 3): 251 panic("dummy send") 252 {{end}} 253 {{if .Maybe}} 254 case <-fc(dummy, 4): 255 panic("dummy receive") 256 {{end}} 257 {{/* Nil channel send, receive to keep compiler from optimizing select. */}} 258 {{if .Maybe}} 259 case fc(nilch, 5) <- fn(1, 6): 260 panic("nilch send") 261 {{end}} 262 {{if .Maybe}} 263 case <-fc(nilch, 7): 264 panic("nilch recv") 265 {{end}} 266 } 267 {{end}}{{end}} 268 if x != n { 269 die(x) 270 } 271 n++ 272 `) 273 274 var send = parse("send", ` 275 {{/* Send n one way or another, receive it into x, check that they match. */}} 276 {{if .Maybe}} 277 c <- n 278 {{else}} 279 select { 280 {{/* Blocking or non-blocking, before the receive (same reason as in recv). */}} 281 {{if .MaybeDefault}} 282 default: 283 panic("nonblock") 284 {{end}} 285 {{/* Send c <- n. No real special cases here, because no values come back */}} 286 {{/* from the send operation. */}} 287 case c <- n: 288 {{/* Blocking or non-blocking. */}} 289 {{if .MaybeDefault}} 290 default: 291 panic("nonblock") 292 {{end}} 293 {{/* Dummy send, receive to keep compiler from optimizing select. */}} 294 {{if .Maybe}} 295 case dummy <- 1: 296 panic("dummy send") 297 {{end}} 298 {{if .Maybe}} 299 case <-dummy: 300 panic("dummy receive") 301 {{end}} 302 {{/* Nil channel send, receive to keep compiler from optimizing select. */}} 303 {{if .Maybe}} 304 case nilch <- 1: 305 panic("nilch send") 306 {{end}} 307 {{if .Maybe}} 308 case <-nilch: 309 panic("nilch recv") 310 {{end}} 311 } 312 {{end}} 313 x = <-c 314 if x != n { 315 die(x) 316 } 317 n++ 318 `) 319 320 var sendOrder = parse("sendOrder", ` 321 {{/* Send n one way or another, receive it into x, check that they match. */}} 322 {{/* Check order of operations along the way by calling functions that check */}} 323 {{/* that the argument sequence is strictly increasing. */}} 324 order = 0 325 {{if .Maybe}} 326 fc(c, 1) <- fn(n, 2) 327 {{else}} 328 select { 329 {{/* Blocking or non-blocking, before the receive (same reason as in recv). */}} 330 {{if .MaybeDefault}} 331 default: 332 panic("nonblock") 333 {{end}} 334 {{/* Send c <- n. No real special cases here, because no values come back */}} 335 {{/* from the send operation. */}} 336 case fc(c, 1) <- fn(n, 2): 337 {{/* Blocking or non-blocking. */}} 338 {{if .MaybeDefault}} 339 default: 340 panic("nonblock") 341 {{end}} 342 {{/* Dummy send, receive to keep compiler from optimizing select. */}} 343 {{if .Maybe}} 344 case fc(dummy, 3) <- fn(1, 4): 345 panic("dummy send") 346 {{end}} 347 {{if .Maybe}} 348 case <-fc(dummy, 5): 349 panic("dummy receive") 350 {{end}} 351 {{/* Nil channel send, receive to keep compiler from optimizing select. */}} 352 {{if .Maybe}} 353 case fc(nilch, 6) <- fn(1, 7): 354 panic("nilch send") 355 {{end}} 356 {{if .Maybe}} 357 case <-fc(nilch, 8): 358 panic("nilch recv") 359 {{end}} 360 } 361 {{end}} 362 x = <-c 363 if x != n { 364 die(x) 365 } 366 n++ 367 `) 368 369 var nonblock = parse("nonblock", ` 370 x = n 371 {{/* Test various combinations of non-blocking operations. */}} 372 {{/* Receive assignments must not edit or even attempt to compute the address of the lhs. */}} 373 select { 374 {{if .MaybeDefault}} 375 default: 376 {{end}} 377 {{if .Maybe}} 378 case dummy <- 1: 379 panic("dummy <- 1") 380 {{end}} 381 {{if .Maybe}} 382 case nilch <- 1: 383 panic("nilch <- 1") 384 {{end}} 385 {{if .Maybe}} 386 case <-dummy: 387 panic("<-dummy") 388 {{end}} 389 {{if .Maybe}} 390 case x = <-dummy: 391 panic("<-dummy x") 392 {{end}} 393 {{if .Maybe}} 394 case **(**int)(nil) = <-dummy: 395 panic("<-dummy (and didn't crash saving result!)") 396 {{end}} 397 {{if .Maybe}} 398 case <-nilch: 399 panic("<-nilch") 400 {{end}} 401 {{if .Maybe}} 402 case x = <-nilch: 403 panic("<-nilch x") 404 {{end}} 405 {{if .Maybe}} 406 case **(**int)(nil) = <-nilch: 407 panic("<-nilch (and didn't crash saving result!)") 408 {{end}} 409 {{if .MustDefault}} 410 default: 411 {{end}} 412 } 413 if x != n { 414 die(x) 415 } 416 n++ 417 `) 418 419 // Code for enumerating all possible paths through 420 // some logic. The logic should call choose(n) when 421 // it wants to choose between n possibilities. 422 // On successive runs through the logic, choose(n) 423 // will return 0, 1, ..., n-1. The helper maybe() is 424 // similar but returns true and then false. 425 // 426 // Given a function gen that generates an output 427 // using choose and maybe, code can generate all 428 // possible outputs using 429 // 430 // for next() { 431 // gen() 432 // } 433 434 type choice struct { 435 i, n int 436 } 437 438 var choices []choice 439 var cp int = -1 440 441 func maybe() bool { 442 return choose(2) == 0 443 } 444 445 func choose(n int) int { 446 if cp >= len(choices) { 447 // never asked this before: start with 0. 448 choices = append(choices, choice{0, n}) 449 cp = len(choices) 450 return 0 451 } 452 // otherwise give recorded answer 453 if n != choices[cp].n { 454 panic("inconsistent choices") 455 } 456 i := choices[cp].i 457 cp++ 458 return i 459 } 460 461 func next() bool { 462 if cp < 0 { 463 // start a new round 464 cp = 0 465 return true 466 } 467 468 // increment last choice sequence 469 cp = len(choices) - 1 470 for cp >= 0 && choices[cp].i == choices[cp].n-1 { 471 cp-- 472 } 473 if cp < 0 { 474 choices = choices[:0] 475 return false 476 } 477 choices[cp].i++ 478 choices = choices[:cp+1] 479 cp = 0 480 return true 481 } 482