From d00b479888247e240c59d444c8aec1fad4b26f1c Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Wed, 14 Jul 2010 09:55:08 -0700 Subject: [PATCH] select statement: initial set of test cases for corner cases R=r, rsc CC=golang-dev https://golang.org/cl/1772043 --- test/chan/select3.go | 176 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 176 insertions(+) create mode 100644 test/chan/select3.go diff --git a/test/chan/select3.go b/test/chan/select3.go new file mode 100644 index 0000000000..f429f9e8f9 --- /dev/null +++ b/test/chan/select3.go @@ -0,0 +1,176 @@ +// $G $D/$F.go && $L $F.$A && ./$A.out + +// 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. + +// Tests verifying 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() { + time.Sleep(1e8) // 0.1s seems plenty long + c <- always // f blocked always + }() + if <-c != signal { + panic(signal + " block") + } +} + + +func main() { + const async = 1 // asynchronous channels + var nilch chan int + + // sending/receiving from a nil channel outside a select panics + testPanic(always, func() { + nilch <- 7 + }) + testPanic(always, func() { + <-nilch + }) + + // sending/receiving from a nil channel inside a select never panics + 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 non-ready channel always blocks + testBlock(always, func() { + ch := make(chan int) + <-ch + }) + + // TODO(gri) remove this if once 6g accepts empty selects + enabled := false + if enabled { + // empty selects always block + testBlock(always, func() { + select { + case <-make(chan int): // remove this once 6g accepts empty selects + } + }) + + // 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() + } + }) +}