]> Cypherpunks repositories - gostls13.git/commitdiff
select statement: initial set of test cases for corner cases
authorRobert Griesemer <gri@golang.org>
Wed, 14 Jul 2010 16:55:08 +0000 (09:55 -0700)
committerRobert Griesemer <gri@golang.org>
Wed, 14 Jul 2010 16:55:08 +0000 (09:55 -0700)
R=r, rsc
CC=golang-dev
https://golang.org/cl/1772043

test/chan/select3.go [new file with mode: 0644]

diff --git a/test/chan/select3.go b/test/chan/select3.go
new file mode 100644 (file)
index 0000000..f429f9e
--- /dev/null
@@ -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()
+               }
+       })
+}