Initial commit: Go 1.23 release state
This commit is contained in:
226
test/chan/select3.go
Normal file
226
test/chan/select3.go
Normal file
@@ -0,0 +1,226 @@
|
||||
// run
|
||||
|
||||
// Copyright 2010 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.
|
||||
|
||||
// Test the semantics of the select statement
|
||||
// for basic empty/non-empty cases.
|
||||
|
||||
package main
|
||||
|
||||
import "time"
|
||||
|
||||
const always = "function did not"
|
||||
const never = "function did"
|
||||
|
||||
func unreachable() {
|
||||
panic("control flow shouldn't reach here")
|
||||
}
|
||||
|
||||
// Calls f and verifies that f always/never panics depending on signal.
|
||||
func testPanic(signal string, f func()) {
|
||||
defer func() {
|
||||
s := never
|
||||
if recover() != nil {
|
||||
s = always // f panicked
|
||||
}
|
||||
if s != signal {
|
||||
panic(signal + " panic")
|
||||
}
|
||||
}()
|
||||
f()
|
||||
}
|
||||
|
||||
// Calls f and empirically verifies that f always/never blocks depending on signal.
|
||||
func testBlock(signal string, f func()) {
|
||||
c := make(chan string)
|
||||
go func() {
|
||||
f()
|
||||
c <- never // f didn't block
|
||||
}()
|
||||
go func() {
|
||||
if signal == never {
|
||||
// Wait a long time to make sure that we don't miss our window by accident on a slow machine.
|
||||
time.Sleep(10 * time.Second)
|
||||
} else {
|
||||
// Wait as short a time as we can without false negatives.
|
||||
// 10ms should be long enough to catch most failures.
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
}
|
||||
c <- always // f blocked always
|
||||
}()
|
||||
if <-c != signal {
|
||||
panic(signal + " block")
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
const async = 1 // asynchronous channels
|
||||
var nilch chan int
|
||||
closedch := make(chan int)
|
||||
close(closedch)
|
||||
|
||||
// sending/receiving from a nil channel blocks
|
||||
testBlock(always, func() {
|
||||
nilch <- 7
|
||||
})
|
||||
testBlock(always, func() {
|
||||
<-nilch
|
||||
})
|
||||
|
||||
// sending/receiving from a nil channel inside a select is never selected
|
||||
testPanic(never, func() {
|
||||
select {
|
||||
case nilch <- 7:
|
||||
unreachable()
|
||||
default:
|
||||
}
|
||||
})
|
||||
testPanic(never, func() {
|
||||
select {
|
||||
case <-nilch:
|
||||
unreachable()
|
||||
default:
|
||||
}
|
||||
})
|
||||
|
||||
// sending to an async channel with free buffer space never blocks
|
||||
testBlock(never, func() {
|
||||
ch := make(chan int, async)
|
||||
ch <- 7
|
||||
})
|
||||
|
||||
// receiving from a closed channel never blocks
|
||||
testBlock(never, func() {
|
||||
for i := 0; i < 10; i++ {
|
||||
if <-closedch != 0 {
|
||||
panic("expected zero value when reading from closed channel")
|
||||
}
|
||||
if x, ok := <-closedch; x != 0 || ok {
|
||||
println("closedch:", x, ok)
|
||||
panic("expected 0, false from closed channel")
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// sending to a closed channel panics.
|
||||
testPanic(always, func() {
|
||||
closedch <- 7
|
||||
})
|
||||
|
||||
// receiving from a non-ready channel always blocks
|
||||
testBlock(always, func() {
|
||||
ch := make(chan int)
|
||||
<-ch
|
||||
})
|
||||
|
||||
// empty selects always block
|
||||
testBlock(always, func() {
|
||||
select {}
|
||||
})
|
||||
|
||||
// selects with only nil channels always block
|
||||
testBlock(always, func() {
|
||||
select {
|
||||
case <-nilch:
|
||||
unreachable()
|
||||
}
|
||||
})
|
||||
testBlock(always, func() {
|
||||
select {
|
||||
case nilch <- 7:
|
||||
unreachable()
|
||||
}
|
||||
})
|
||||
testBlock(always, func() {
|
||||
select {
|
||||
case <-nilch:
|
||||
unreachable()
|
||||
case nilch <- 7:
|
||||
unreachable()
|
||||
}
|
||||
})
|
||||
|
||||
// selects with non-ready non-nil channels always block
|
||||
testBlock(always, func() {
|
||||
ch := make(chan int)
|
||||
select {
|
||||
case <-ch:
|
||||
unreachable()
|
||||
}
|
||||
})
|
||||
|
||||
// selects with default cases don't block
|
||||
testBlock(never, func() {
|
||||
select {
|
||||
default:
|
||||
}
|
||||
})
|
||||
testBlock(never, func() {
|
||||
select {
|
||||
case <-nilch:
|
||||
unreachable()
|
||||
default:
|
||||
}
|
||||
})
|
||||
testBlock(never, func() {
|
||||
select {
|
||||
case nilch <- 7:
|
||||
unreachable()
|
||||
default:
|
||||
}
|
||||
})
|
||||
|
||||
// selects with ready channels don't block
|
||||
testBlock(never, func() {
|
||||
ch := make(chan int, async)
|
||||
select {
|
||||
case ch <- 7:
|
||||
default:
|
||||
unreachable()
|
||||
}
|
||||
})
|
||||
testBlock(never, func() {
|
||||
ch := make(chan int, async)
|
||||
ch <- 7
|
||||
select {
|
||||
case <-ch:
|
||||
default:
|
||||
unreachable()
|
||||
}
|
||||
})
|
||||
|
||||
// selects with closed channels behave like ordinary operations
|
||||
testBlock(never, func() {
|
||||
select {
|
||||
case <-closedch:
|
||||
}
|
||||
})
|
||||
testBlock(never, func() {
|
||||
select {
|
||||
case x := (<-closedch):
|
||||
_ = x
|
||||
}
|
||||
})
|
||||
testBlock(never, func() {
|
||||
select {
|
||||
case x, ok := (<-closedch):
|
||||
_, _ = x, ok
|
||||
}
|
||||
})
|
||||
testPanic(always, func() {
|
||||
select {
|
||||
case closedch <- 7:
|
||||
}
|
||||
})
|
||||
|
||||
// select should not get confused if it sees itself
|
||||
testBlock(always, func() {
|
||||
c := make(chan int)
|
||||
select {
|
||||
case c <- 1:
|
||||
case <-c:
|
||||
}
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user