Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
go
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
go
Commits
7247d6b9
Commit
7247d6b9
authored
Jan 30, 2011
by
Russ Cox
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
test: another select test
R=r CC=golang-dev
https://golang.org/cl/4004044
parent
08a206cc
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
482 additions
and
0 deletions
+482
-0
test/chan/select5.go
test/chan/select5.go
+482
-0
No files found.
test/chan/select5.go
0 → 100644
View file @
7247d6b9
// $G $D/$F.go && $L $F.$A && ./$A.out >tmp.go &&
// $G tmp.go && $L tmp.$A && ./$A.out || echo BUG: select5
// rm -f tmp.go
// 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.
// Only doing 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"
"template"
)
func
main
()
{
out
:=
bufio
.
NewWriter
(
os
.
Stdout
)
fmt
.
Fprintln
(
out
,
header
)
a
:=
new
(
arg
)
// Generate each kind of test as a separate function to avoid
// hitting the 6g 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
)
{
fmt
.
Fprintln
(
out
,
`func init() {`
)
for
;
next
();
a
.
reset
()
{
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
(
a
,
out
);
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
(
s
string
)
*
template
.
Template
{
t
:=
template
.
New
(
nil
)
t
.
SetDelims
(
"〈"
,
"〉"
)
if
err
:=
t
.
Parse
(
s
);
err
!=
nil
{
panic
(
s
)
}
return
t
}
var
recv
=
parse
(
`
〈# Send n, receive it one way or another into x, check that they match.〉
c <- n
〈.section Maybe〉
x = <-c
〈.or〉
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.〉
〈.section MaybeDefault〉
default:
panic("nonblock")
〈.end〉
〈# Receive from c. Different cases are direct, indirect, :=, interface, and map assignment.〉
〈.section Maybe〉
case x = <-c:
〈.or〉〈.section Maybe〉
case *f(&x) = <-c:
〈.or〉〈.section Maybe〉
case y := <-c:
x = y
〈.or〉〈.section Maybe〉
case i = <-c:
x = i.(int)
〈.or〉
case m[13] = <-c:
x = m[13]
〈.end〉〈.end〉〈.end〉〈.end〉
〈# Blocking or non-blocking again, after the receive.〉
〈.section MaybeDefault〉
default:
panic("nonblock")
〈.end〉
〈# Dummy send, receive to keep compiler from optimizing select.〉
〈.section Maybe〉
case dummy <- 1:
panic("dummy send")
〈.end〉
〈.section Maybe〉
case <-dummy:
panic("dummy receive")
〈.end〉
〈# Nil channel send, receive to keep compiler from optimizing select.〉
〈.section Maybe〉
case nilch <- 1:
panic("nilch send")
〈.end〉
〈.section Maybe〉
case <-nilch:
panic("nilch recv")
〈.end〉
}
〈.end〉
if x != n {
die(x)
}
n++
`
)
var
recvOrder
=
parse
(
`
〈# 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
〈.section 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)
〈.or〉〈.section Maybe〉
m[fn(13, 1)] = <-fc(c, 2)
x = m[13]
〈.or〉
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.〉
〈.section MaybeDefault〉
default:
panic("nonblock")
〈.end〉
〈# Receive from c. Different cases are direct, indirect, :=, interface, and map assignment.〉
〈.section Maybe〉
case *fp(&x, 100) = <-fc(c, 1):
〈.or〉〈.section Maybe〉
case y := <-fc(c, 1):
x = y
〈.or〉〈.section Maybe〉
case i = <-fc(c, 1):
x = i.(int)
〈.or〉
case m[fn(13, 100)] = <-fc(c, 1):
x = m[13]
〈.end〉〈.end〉〈.end〉
〈# Blocking or non-blocking again, after the receive.〉
〈.section MaybeDefault〉
default:
panic("nonblock")
〈.end〉
〈# Dummy send, receive to keep compiler from optimizing select.〉
〈.section Maybe〉
case fc(dummy, 2) <- fn(1, 3):
panic("dummy send")
〈.end〉
〈.section Maybe〉
case <-fc(dummy, 4):
panic("dummy receive")
〈.end〉
〈# Nil channel send, receive to keep compiler from optimizing select.〉
〈.section Maybe〉
case fc(nilch, 5) <- fn(1, 6):
panic("nilch send")
〈.end〉
〈.section Maybe〉
case <-fc(nilch, 7):
panic("nilch recv")
〈.end〉
}
〈.end〉〈.end〉
if x != n {
die(x)
}
n++
`
)
var
send
=
parse
(
`
〈# Send n one way or another, receive it into x, check that they match.〉
〈.section Maybe〉
c <- n
〈.or〉
select {
〈# Blocking or non-blocking, before the receive (same reason as in recv).〉
〈.section 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.〉
〈.section MaybeDefault〉
default:
panic("nonblock")
〈.end〉
〈# Dummy send, receive to keep compiler from optimizing select.〉
〈.section Maybe〉
case dummy <- 1:
panic("dummy send")
〈.end〉
〈.section Maybe〉
case <-dummy:
panic("dummy receive")
〈.end〉
〈# Nil channel send, receive to keep compiler from optimizing select.〉
〈.section Maybe〉
case nilch <- 1:
panic("nilch send")
〈.end〉
〈.section Maybe〉
case <-nilch:
panic("nilch recv")
〈.end〉
}
〈.end〉
x = <-c
if x != n {
die(x)
}
n++
`
)
var
sendOrder
=
parse
(
`
〈# 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
〈.section Maybe〉
fc(c, 1) <- fn(n, 2)
〈.or〉
select {
〈# Blocking or non-blocking, before the receive (same reason as in recv).〉
〈.section 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.〉
〈.section MaybeDefault〉
default:
panic("nonblock")
〈.end〉
〈# Dummy send, receive to keep compiler from optimizing select.〉
〈.section Maybe〉
case fc(dummy, 3) <- fn(1, 4):
panic("dummy send")
〈.end〉
〈.section Maybe〉
case <-fc(dummy, 5):
panic("dummy receive")
〈.end〉
〈# Nil channel send, receive to keep compiler from optimizing select.〉
〈.section Maybe〉
case fc(nilch, 6) <- fn(1, 7):
panic("nilch send")
〈.end〉
〈.section Maybe〉
case <-fc(nilch, 8):
panic("nilch recv")
〈.end〉
}
〈.end〉
x = <-c
if x != n {
die(x)
}
n++
`
)
var
nonblock
=
parse
(
`
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 {
〈.section MaybeDefault〉
default:
〈.end〉
〈.section Maybe〉
case dummy <- 1:
panic("dummy <- 1")
〈.end〉
〈.section Maybe〉
case nilch <- 1:
panic("nilch <- 1")
〈.end〉
〈.section Maybe〉
case <-dummy:
panic("<-dummy")
〈.end〉
〈.section Maybe〉
case x = <-dummy:
panic("<-dummy x")
〈.end〉
〈.section Maybe〉
case **(**int)(nil) = <-dummy:
panic("<-dummy (and didn't crash saving result!)")
〈.end〉
〈.section Maybe〉
case <-nilch:
panic("<-nilch")
〈.end〉
〈.section Maybe〉
case x = <-nilch:
panic("<-nilch x")
〈.end〉
〈.section Maybe〉
case **(**int)(nil) = <-nilch:
panic("<-nilch (and didn't crash saving result!)")
〈.end〉
〈.section 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
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment