1 // $G $D/$F.go && $L $F.$A && ./$A.out >tmp.go &&
2 // $G tmp.go && $L tmp.$A && ./$A.out || echo BUG: select5
5 // Copyright 2011 The Go Authors. All rights reserved.
6 // Use of this source code is governed by a BSD-style
7 // license that can be found in the LICENSE file.
9 // Generate test of channel operations and simple selects.
10 // Only doing one real send or receive at a time, but phrased
11 // in various ways that the compiler may or may not rewrite
12 // into simpler expressions.
25 out := bufio.NewWriter(os.Stdout)
26 fmt.Fprintln(out, header)
29 // Generate each kind of test as a separate function to avoid
30 // hitting the 6g optimizer with one enormous function.
31 // If we name all the functions init we don't have to
32 // maintain a list of which ones to run.
33 do := func(t *template.Template) {
34 fmt.Fprintln(out, `func init() {`)
35 for ; next(); a.reset() {
38 fmt.Fprintln(out, `}`)
47 fmt.Fprintln(out, "//", a.nreset, "cases")
51 func run(t *template.Template, a interface{}, out io.Writer) {
52 if err := t.Execute(out, a); err != nil {
62 func (a *arg) Maybe() bool {
66 func (a *arg) MaybeDefault() bool {
74 func (a *arg) MustDefault() bool {
78 func (a *arg) reset() {
83 const header = `// GENERATED BY select5.go; DO NOT EDIT
87 // channel is buffered so test is single-goroutine.
88 // we are not interested in the concurrency aspects
89 // of select, just testing that the right calls happen.
90 var c = make(chan int, 1)
95 var dummy = make(chan int)
96 var m = make(map[int]int)
103 // check order of operations by ensuring that
104 // successive calls to checkorder have increasing o values.
105 func checkorder(o int) {
107 println("invalid order", o, "after", order)
113 func fc(c chan int, o int) chan int {
118 func fp(p *int, o int) *int {
123 func fn(n, o int) int {
129 println("have", x, "want", n)
134 // everything happens in init funcs
138 func parse(name, s string) *template.Template {
139 t, err := template.New(name).Parse(s)
141 panic(fmt.Sprintf("%q: %s", name, err))
146 var recv = parse("recv", `
147 {{/* Send n, receive it one way or another into x, check that they match. */}}
153 {{/* Blocking or non-blocking, before the receive. */}}
154 {{/* The compiler implements two-case select where one is default with custom code, */}}
155 {{/* so test the default branch both before and after the send. */}}
160 {{/* Receive from c. Different cases are direct, indirect, :=, interface, and map assignment. */}}
163 {{else}}{{if .Maybe}}
165 {{else}}{{if .Maybe}}
168 {{else}}{{if .Maybe}}
174 {{end}}{{end}}{{end}}{{end}}
175 {{/* Blocking or non-blocking again, after the receive. */}}
180 {{/* Dummy send, receive to keep compiler from optimizing select. */}}
187 panic("dummy receive")
189 {{/* Nil channel send, receive to keep compiler from optimizing select. */}}
206 var recvOrder = parse("recvOrder", `
207 {{/* Send n, receive it one way or another into x, check that they match. */}}
208 {{/* Check order of operations along the way by calling functions that check */}}
209 {{/* that the argument sequence is strictly increasing. */}}
213 {{/* Outside of select, left-to-right rule applies. */}}
214 {{/* (Inside select, assignment waits until case is chosen, */}}
215 {{/* so right hand side happens before anything on left hand side. */}}
216 *fp(&x, 1) = <-fc(c, 2)
217 {{else}}{{if .Maybe}}
218 m[fn(13, 1)] = <-fc(c, 2)
222 {{/* Blocking or non-blocking, before the receive. */}}
223 {{/* The compiler implements two-case select where one is default with custom code, */}}
224 {{/* so test the default branch both before and after the send. */}}
229 {{/* Receive from c. Different cases are direct, indirect, :=, interface, and map assignment. */}}
231 case *fp(&x, 100) = <-fc(c, 1):
232 {{else}}{{if .Maybe}}
233 case y := <-fc(c, 1):
235 {{else}}{{if .Maybe}}
239 case m[fn(13, 100)] = <-fc(c, 1):
241 {{end}}{{end}}{{end}}
242 {{/* Blocking or non-blocking again, after the receive. */}}
247 {{/* Dummy send, receive to keep compiler from optimizing select. */}}
249 case fc(dummy, 2) <- fn(1, 3):
254 panic("dummy receive")
256 {{/* Nil channel send, receive to keep compiler from optimizing select. */}}
258 case fc(nilch, 5) <- fn(1, 6):
273 var send = parse("send", `
274 {{/* Send n one way or another, receive it into x, check that they match. */}}
279 {{/* Blocking or non-blocking, before the receive (same reason as in recv). */}}
284 {{/* Send c <- n. No real special cases here, because no values come back */}}
285 {{/* from the send operation. */}}
287 {{/* Blocking or non-blocking. */}}
292 {{/* Dummy send, receive to keep compiler from optimizing select. */}}
299 panic("dummy receive")
301 {{/* Nil channel send, receive to keep compiler from optimizing select. */}}
319 var sendOrder = parse("sendOrder", `
320 {{/* Send n one way or another, receive it into x, check that they match. */}}
321 {{/* Check order of operations along the way by calling functions that check */}}
322 {{/* that the argument sequence is strictly increasing. */}}
328 {{/* Blocking or non-blocking, before the receive (same reason as in recv). */}}
333 {{/* Send c <- n. No real special cases here, because no values come back */}}
334 {{/* from the send operation. */}}
335 case fc(c, 1) <- fn(n, 2):
336 {{/* Blocking or non-blocking. */}}
341 {{/* Dummy send, receive to keep compiler from optimizing select. */}}
343 case fc(dummy, 3) <- fn(1, 4):
348 panic("dummy receive")
350 {{/* Nil channel send, receive to keep compiler from optimizing select. */}}
352 case fc(nilch, 6) <- fn(1, 7):
368 var nonblock = parse("nonblock", `
370 {{/* Test various combinations of non-blocking operations. */}}
371 {{/* Receive assignments must not edit or even attempt to compute the address of the lhs. */}}
393 case **(**int)(nil) = <-dummy:
394 panic("<-dummy (and didn't crash saving result!)")
405 case **(**int)(nil) = <-nilch:
406 panic("<-nilch (and didn't crash saving result!)")
418 // Code for enumerating all possible paths through
419 // some logic. The logic should call choose(n) when
420 // it wants to choose between n possibilities.
421 // On successive runs through the logic, choose(n)
422 // will return 0, 1, ..., n-1. The helper maybe() is
423 // similar but returns true and then false.
425 // Given a function gen that generates an output
426 // using choose and maybe, code can generate all
427 // possible outputs using
441 return choose(2) == 0
444 func choose(n int) int {
445 if cp >= len(choices) {
446 // never asked this before: start with 0.
447 choices = append(choices, choice{0, n})
451 // otherwise give recorded answer
452 if n != choices[cp].n {
453 panic("inconsistent choices")
467 // increment last choice sequence
468 cp = len(choices) - 1
469 for cp >= 0 && choices[cp].i == choices[cp].n-1 {
473 choices = choices[:0]
477 choices = choices[:cp+1]