|  | // runoutput | 
|  |  | 
|  | // Copyright 2011 The Go Authors.  All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style | 
|  | // license that can be found in the LICENSE file. | 
|  |  | 
|  | // Generate test of channel operations and simple selects. | 
|  | // The output of this program is compiled and run to do the | 
|  | // actual test. | 
|  |  | 
|  | // Each test does only one real send or receive at a time, but phrased | 
|  | // in various ways that the compiler may or may not rewrite | 
|  | // into simpler expressions. | 
|  |  | 
|  | package main | 
|  |  | 
|  | import ( | 
|  | "bufio" | 
|  | "fmt" | 
|  | "io" | 
|  | "os" | 
|  | "text/template" | 
|  | ) | 
|  |  | 
|  | func main() { | 
|  | out := bufio.NewWriter(os.Stdout) | 
|  | fmt.Fprintln(out, header) | 
|  | a := new(arg) | 
|  |  | 
|  | // Generate each test as a separate function to avoid | 
|  | // hitting the gc optimizer with one enormous function. | 
|  | // If we name all the functions init we don't have to | 
|  | // maintain a list of which ones to run. | 
|  | do := func(t *template.Template) { | 
|  | for ; next(); a.reset() { | 
|  | fmt.Fprintln(out, `func init() {`) | 
|  | run(t, a, out) | 
|  | fmt.Fprintln(out, `}`) | 
|  | } | 
|  | } | 
|  |  | 
|  | do(recv) | 
|  | do(send) | 
|  | do(recvOrder) | 
|  | do(sendOrder) | 
|  | do(nonblock) | 
|  |  | 
|  | fmt.Fprintln(out, "//", a.nreset, "cases") | 
|  | out.Flush() | 
|  | } | 
|  |  | 
|  | func run(t *template.Template, a interface{}, out io.Writer) { | 
|  | if err := t.Execute(out, a); err != nil { | 
|  | panic(err) | 
|  | } | 
|  | } | 
|  |  | 
|  | type arg struct { | 
|  | def    bool | 
|  | nreset int | 
|  | } | 
|  |  | 
|  | func (a *arg) Maybe() bool { | 
|  | return maybe() | 
|  | } | 
|  |  | 
|  | func (a *arg) MaybeDefault() bool { | 
|  | if a.def { | 
|  | return false | 
|  | } | 
|  | a.def = maybe() | 
|  | return a.def | 
|  | } | 
|  |  | 
|  | func (a *arg) MustDefault() bool { | 
|  | return !a.def | 
|  | } | 
|  |  | 
|  | func (a *arg) reset() { | 
|  | a.def = false | 
|  | a.nreset++ | 
|  | } | 
|  |  | 
|  | const header = `// GENERATED BY select5.go; DO NOT EDIT | 
|  |  | 
|  | package main | 
|  |  | 
|  | // channel is buffered so test is single-goroutine. | 
|  | // we are not interested in the concurrency aspects | 
|  | // of select, just testing that the right calls happen. | 
|  | var c = make(chan int, 1) | 
|  | var nilch chan int | 
|  | var n = 1 | 
|  | var x int | 
|  | var i interface{} | 
|  | var dummy = make(chan int) | 
|  | var m = make(map[int]int) | 
|  | var order = 0 | 
|  |  | 
|  | func f(p *int) *int { | 
|  | return p | 
|  | } | 
|  |  | 
|  | // check order of operations by ensuring that | 
|  | // successive calls to checkorder have increasing o values. | 
|  | func checkorder(o int) { | 
|  | if o <= order { | 
|  | println("invalid order", o, "after", order) | 
|  | panic("order") | 
|  | } | 
|  | order = o | 
|  | } | 
|  |  | 
|  | func fc(c chan int, o int) chan int { | 
|  | checkorder(o) | 
|  | return c | 
|  | } | 
|  |  | 
|  | func fp(p *int, o int) *int { | 
|  | checkorder(o) | 
|  | return p | 
|  | } | 
|  |  | 
|  | func fn(n, o int) int { | 
|  | checkorder(o) | 
|  | return n | 
|  | } | 
|  |  | 
|  | func die(x int) { | 
|  | println("have", x, "want", n) | 
|  | panic("chan") | 
|  | } | 
|  |  | 
|  | func main() { | 
|  | // everything happens in init funcs | 
|  | } | 
|  | ` | 
|  |  | 
|  | func parse(name, s string) *template.Template { | 
|  | t, err := template.New(name).Parse(s) | 
|  | if err != nil { | 
|  | panic(fmt.Sprintf("%q: %s", name, err)) | 
|  | } | 
|  | return t | 
|  | } | 
|  |  | 
|  | var recv = parse("recv", ` | 
|  | {{/*  Send n, receive it one way or another into x, check that they match. */}} | 
|  | c <- n | 
|  | {{if .Maybe}} | 
|  | x = <-c | 
|  | {{else}} | 
|  | select { | 
|  | {{/*  Blocking or non-blocking, before the receive. */}} | 
|  | {{/*  The compiler implements two-case select where one is default with custom code, */}} | 
|  | {{/*  so test the default branch both before and after the send. */}} | 
|  | {{if .MaybeDefault}} | 
|  | default: | 
|  | panic("nonblock") | 
|  | {{end}} | 
|  | {{/*  Receive from c.  Different cases are direct, indirect, :=, interface, and map assignment. */}} | 
|  | {{if .Maybe}} | 
|  | case x = <-c: | 
|  | {{else}}{{if .Maybe}} | 
|  | case *f(&x) = <-c: | 
|  | {{else}}{{if .Maybe}} | 
|  | case y := <-c: | 
|  | x = y | 
|  | {{else}}{{if .Maybe}} | 
|  | case i = <-c: | 
|  | x = i.(int) | 
|  | {{else}} | 
|  | case m[13] = <-c: | 
|  | x = m[13] | 
|  | {{end}}{{end}}{{end}}{{end}} | 
|  | {{/*  Blocking or non-blocking again, after the receive. */}} | 
|  | {{if .MaybeDefault}} | 
|  | default: | 
|  | panic("nonblock") | 
|  | {{end}} | 
|  | {{/*  Dummy send, receive to keep compiler from optimizing select. */}} | 
|  | {{if .Maybe}} | 
|  | case dummy <- 1: | 
|  | panic("dummy send") | 
|  | {{end}} | 
|  | {{if .Maybe}} | 
|  | case <-dummy: | 
|  | panic("dummy receive") | 
|  | {{end}} | 
|  | {{/*  Nil channel send, receive to keep compiler from optimizing select. */}} | 
|  | {{if .Maybe}} | 
|  | case nilch <- 1: | 
|  | panic("nilch send") | 
|  | {{end}} | 
|  | {{if .Maybe}} | 
|  | case <-nilch: | 
|  | panic("nilch recv") | 
|  | {{end}} | 
|  | } | 
|  | {{end}} | 
|  | if x != n { | 
|  | die(x) | 
|  | } | 
|  | n++ | 
|  | `) | 
|  |  | 
|  | var recvOrder = parse("recvOrder", ` | 
|  | {{/*  Send n, receive it one way or another into x, check that they match. */}} | 
|  | {{/*  Check order of operations along the way by calling functions that check */}} | 
|  | {{/*  that the argument sequence is strictly increasing. */}} | 
|  | order = 0 | 
|  | c <- n | 
|  | {{if .Maybe}} | 
|  | {{/*  Outside of select, left-to-right rule applies. */}} | 
|  | {{/*  (Inside select, assignment waits until case is chosen, */}} | 
|  | {{/*  so right hand side happens before anything on left hand side. */}} | 
|  | *fp(&x, 1) = <-fc(c, 2) | 
|  | {{else}}{{if .Maybe}} | 
|  | m[fn(13, 1)] = <-fc(c, 2) | 
|  | x = m[13] | 
|  | {{else}} | 
|  | select { | 
|  | {{/*  Blocking or non-blocking, before the receive. */}} | 
|  | {{/*  The compiler implements two-case select where one is default with custom code, */}} | 
|  | {{/*  so test the default branch both before and after the send. */}} | 
|  | {{if .MaybeDefault}} | 
|  | default: | 
|  | panic("nonblock") | 
|  | {{end}} | 
|  | {{/*  Receive from c.  Different cases are direct, indirect, :=, interface, and map assignment. */}} | 
|  | {{if .Maybe}} | 
|  | case *fp(&x, 100) = <-fc(c, 1): | 
|  | {{else}}{{if .Maybe}} | 
|  | case y := <-fc(c, 1): | 
|  | x = y | 
|  | {{else}}{{if .Maybe}} | 
|  | case i = <-fc(c, 1): | 
|  | x = i.(int) | 
|  | {{else}} | 
|  | case m[fn(13, 100)] = <-fc(c, 1): | 
|  | x = m[13] | 
|  | {{end}}{{end}}{{end}} | 
|  | {{/*  Blocking or non-blocking again, after the receive. */}} | 
|  | {{if .MaybeDefault}} | 
|  | default: | 
|  | panic("nonblock") | 
|  | {{end}} | 
|  | {{/*  Dummy send, receive to keep compiler from optimizing select. */}} | 
|  | {{if .Maybe}} | 
|  | case fc(dummy, 2) <- fn(1, 3): | 
|  | panic("dummy send") | 
|  | {{end}} | 
|  | {{if .Maybe}} | 
|  | case <-fc(dummy, 4): | 
|  | panic("dummy receive") | 
|  | {{end}} | 
|  | {{/*  Nil channel send, receive to keep compiler from optimizing select. */}} | 
|  | {{if .Maybe}} | 
|  | case fc(nilch, 5) <- fn(1, 6): | 
|  | panic("nilch send") | 
|  | {{end}} | 
|  | {{if .Maybe}} | 
|  | case <-fc(nilch, 7): | 
|  | panic("nilch recv") | 
|  | {{end}} | 
|  | } | 
|  | {{end}}{{end}} | 
|  | if x != n { | 
|  | die(x) | 
|  | } | 
|  | n++ | 
|  | `) | 
|  |  | 
|  | var send = parse("send", ` | 
|  | {{/*  Send n one way or another, receive it into x, check that they match. */}} | 
|  | {{if .Maybe}} | 
|  | c <- n | 
|  | {{else}} | 
|  | select { | 
|  | {{/*  Blocking or non-blocking, before the receive (same reason as in recv). */}} | 
|  | {{if .MaybeDefault}} | 
|  | default: | 
|  | panic("nonblock") | 
|  | {{end}} | 
|  | {{/*  Send c <- n.  No real special cases here, because no values come back */}} | 
|  | {{/*  from the send operation. */}} | 
|  | case c <- n: | 
|  | {{/*  Blocking or non-blocking. */}} | 
|  | {{if .MaybeDefault}} | 
|  | default: | 
|  | panic("nonblock") | 
|  | {{end}} | 
|  | {{/*  Dummy send, receive to keep compiler from optimizing select. */}} | 
|  | {{if .Maybe}} | 
|  | case dummy <- 1: | 
|  | panic("dummy send") | 
|  | {{end}} | 
|  | {{if .Maybe}} | 
|  | case <-dummy: | 
|  | panic("dummy receive") | 
|  | {{end}} | 
|  | {{/*  Nil channel send, receive to keep compiler from optimizing select. */}} | 
|  | {{if .Maybe}} | 
|  | case nilch <- 1: | 
|  | panic("nilch send") | 
|  | {{end}} | 
|  | {{if .Maybe}} | 
|  | case <-nilch: | 
|  | panic("nilch recv") | 
|  | {{end}} | 
|  | } | 
|  | {{end}} | 
|  | x = <-c | 
|  | if x != n { | 
|  | die(x) | 
|  | } | 
|  | n++ | 
|  | `) | 
|  |  | 
|  | var sendOrder = parse("sendOrder", ` | 
|  | {{/*  Send n one way or another, receive it into x, check that they match. */}} | 
|  | {{/*  Check order of operations along the way by calling functions that check */}} | 
|  | {{/*  that the argument sequence is strictly increasing. */}} | 
|  | order = 0 | 
|  | {{if .Maybe}} | 
|  | fc(c, 1) <- fn(n, 2) | 
|  | {{else}} | 
|  | select { | 
|  | {{/*  Blocking or non-blocking, before the receive (same reason as in recv). */}} | 
|  | {{if .MaybeDefault}} | 
|  | default: | 
|  | panic("nonblock") | 
|  | {{end}} | 
|  | {{/*  Send c <- n.  No real special cases here, because no values come back */}} | 
|  | {{/*  from the send operation. */}} | 
|  | case fc(c, 1) <- fn(n, 2): | 
|  | {{/*  Blocking or non-blocking. */}} | 
|  | {{if .MaybeDefault}} | 
|  | default: | 
|  | panic("nonblock") | 
|  | {{end}} | 
|  | {{/*  Dummy send, receive to keep compiler from optimizing select. */}} | 
|  | {{if .Maybe}} | 
|  | case fc(dummy, 3) <- fn(1, 4): | 
|  | panic("dummy send") | 
|  | {{end}} | 
|  | {{if .Maybe}} | 
|  | case <-fc(dummy, 5): | 
|  | panic("dummy receive") | 
|  | {{end}} | 
|  | {{/*  Nil channel send, receive to keep compiler from optimizing select. */}} | 
|  | {{if .Maybe}} | 
|  | case fc(nilch, 6) <- fn(1, 7): | 
|  | panic("nilch send") | 
|  | {{end}} | 
|  | {{if .Maybe}} | 
|  | case <-fc(nilch, 8): | 
|  | panic("nilch recv") | 
|  | {{end}} | 
|  | } | 
|  | {{end}} | 
|  | x = <-c | 
|  | if x != n { | 
|  | die(x) | 
|  | } | 
|  | n++ | 
|  | `) | 
|  |  | 
|  | var nonblock = parse("nonblock", ` | 
|  | x = n | 
|  | {{/*  Test various combinations of non-blocking operations. */}} | 
|  | {{/*  Receive assignments must not edit or even attempt to compute the address of the lhs. */}} | 
|  | select { | 
|  | {{if .MaybeDefault}} | 
|  | default: | 
|  | {{end}} | 
|  | {{if .Maybe}} | 
|  | case dummy <- 1: | 
|  | panic("dummy <- 1") | 
|  | {{end}} | 
|  | {{if .Maybe}} | 
|  | case nilch <- 1: | 
|  | panic("nilch <- 1") | 
|  | {{end}} | 
|  | {{if .Maybe}} | 
|  | case <-dummy: | 
|  | panic("<-dummy") | 
|  | {{end}} | 
|  | {{if .Maybe}} | 
|  | case x = <-dummy: | 
|  | panic("<-dummy x") | 
|  | {{end}} | 
|  | {{if .Maybe}} | 
|  | case **(**int)(nil) = <-dummy: | 
|  | panic("<-dummy (and didn't crash saving result!)") | 
|  | {{end}} | 
|  | {{if .Maybe}} | 
|  | case <-nilch: | 
|  | panic("<-nilch") | 
|  | {{end}} | 
|  | {{if .Maybe}} | 
|  | case x = <-nilch: | 
|  | panic("<-nilch x") | 
|  | {{end}} | 
|  | {{if .Maybe}} | 
|  | case **(**int)(nil) = <-nilch: | 
|  | panic("<-nilch (and didn't crash saving result!)") | 
|  | {{end}} | 
|  | {{if .MustDefault}} | 
|  | default: | 
|  | {{end}} | 
|  | } | 
|  | if x != n { | 
|  | die(x) | 
|  | } | 
|  | n++ | 
|  | `) | 
|  |  | 
|  | // Code for enumerating all possible paths through | 
|  | // some logic.  The logic should call choose(n) when | 
|  | // it wants to choose between n possibilities. | 
|  | // On successive runs through the logic, choose(n) | 
|  | // will return 0, 1, ..., n-1.  The helper maybe() is | 
|  | // similar but returns true and then false. | 
|  | // | 
|  | // Given a function gen that generates an output | 
|  | // using choose and maybe, code can generate all | 
|  | // possible outputs using | 
|  | // | 
|  | //	for next() { | 
|  | //		gen() | 
|  | //	} | 
|  |  | 
|  | type choice struct { | 
|  | i, n int | 
|  | } | 
|  |  | 
|  | var choices []choice | 
|  | var cp int = -1 | 
|  |  | 
|  | func maybe() bool { | 
|  | return choose(2) == 0 | 
|  | } | 
|  |  | 
|  | func choose(n int) int { | 
|  | if cp >= len(choices) { | 
|  | // never asked this before: start with 0. | 
|  | choices = append(choices, choice{0, n}) | 
|  | cp = len(choices) | 
|  | return 0 | 
|  | } | 
|  | // otherwise give recorded answer | 
|  | if n != choices[cp].n { | 
|  | panic("inconsistent choices") | 
|  | } | 
|  | i := choices[cp].i | 
|  | cp++ | 
|  | return i | 
|  | } | 
|  |  | 
|  | func next() bool { | 
|  | if cp < 0 { | 
|  | // start a new round | 
|  | cp = 0 | 
|  | return true | 
|  | } | 
|  |  | 
|  | // increment last choice sequence | 
|  | cp = len(choices) - 1 | 
|  | for cp >= 0 && choices[cp].i == choices[cp].n-1 { | 
|  | cp-- | 
|  | } | 
|  | if cp < 0 { | 
|  | choices = choices[:0] | 
|  | return false | 
|  | } | 
|  | choices[cp].i++ | 
|  | choices = choices[:cp+1] | 
|  | cp = 0 | 
|  | return true | 
|  | } |