github.com/sanprasirt/go@v0.0.0-20170607001320-a027466e4b6d/test/chan/select3.go (about)

     1  // run
     2  
     3  // Copyright 2010 The Go Authors. All rights reserved.
     4  // Use of this source code is governed by a BSD-style
     5  // license that can be found in the LICENSE file.
     6  
     7  // Test the semantics of the select statement
     8  // for basic empty/non-empty cases.
     9  
    10  package main
    11  
    12  import "time"
    13  
    14  const always = "function did not"
    15  const never = "function did"
    16  
    17  func unreachable() {
    18  	panic("control flow shouldn't reach here")
    19  }
    20  
    21  // Calls f and verifies that f always/never panics depending on signal.
    22  func testPanic(signal string, f func()) {
    23  	defer func() {
    24  		s := never
    25  		if recover() != nil {
    26  			s = always // f panicked
    27  		}
    28  		if s != signal {
    29  			panic(signal + " panic")
    30  		}
    31  	}()
    32  	f()
    33  }
    34  
    35  // Calls f and empirically verifies that f always/never blocks depending on signal.
    36  func testBlock(signal string, f func()) {
    37  	c := make(chan string)
    38  	go func() {
    39  		f()
    40  		c <- never // f didn't block
    41  	}()
    42  	go func() {
    43  		time.Sleep(1e8) // 0.1s seems plenty long
    44  		c <- always     // f blocked always
    45  	}()
    46  	if <-c != signal {
    47  		panic(signal + " block")
    48  	}
    49  }
    50  
    51  func main() {
    52  	const async = 1 // asynchronous channels
    53  	var nilch chan int
    54  	closedch := make(chan int)
    55  	close(closedch)
    56  
    57  	// sending/receiving from a nil channel blocks
    58  	testBlock(always, func() {
    59  		nilch <- 7
    60  	})
    61  	testBlock(always, func() {
    62  		<-nilch
    63  	})
    64  
    65  	// sending/receiving from a nil channel inside a select is never selected
    66  	testPanic(never, func() {
    67  		select {
    68  		case nilch <- 7:
    69  			unreachable()
    70  		default:
    71  		}
    72  	})
    73  	testPanic(never, func() {
    74  		select {
    75  		case <-nilch:
    76  			unreachable()
    77  		default:
    78  		}
    79  	})
    80  
    81  	// sending to an async channel with free buffer space never blocks
    82  	testBlock(never, func() {
    83  		ch := make(chan int, async)
    84  		ch <- 7
    85  	})
    86  
    87  	// receiving from a closed channel never blocks
    88  	testBlock(never, func() {
    89  		for i := 0; i < 10; i++ {
    90  			if <-closedch != 0 {
    91  				panic("expected zero value when reading from closed channel")
    92  			}
    93  			if x, ok := <-closedch; x != 0 || ok {
    94  				println("closedch:", x, ok)
    95  				panic("expected 0, false from closed channel")
    96  			}
    97  		}
    98  	})
    99  
   100  	// sending to a closed channel panics.
   101  	testPanic(always, func() {
   102  		closedch <- 7
   103  	})
   104  
   105  	// receiving from a non-ready channel always blocks
   106  	testBlock(always, func() {
   107  		ch := make(chan int)
   108  		<-ch
   109  	})
   110  
   111  	// empty selects always block
   112  	testBlock(always, func() {
   113  		select {}
   114  	})
   115  
   116  	// selects with only nil channels always block
   117  	testBlock(always, func() {
   118  		select {
   119  		case <-nilch:
   120  			unreachable()
   121  		}
   122  	})
   123  	testBlock(always, func() {
   124  		select {
   125  		case nilch <- 7:
   126  			unreachable()
   127  		}
   128  	})
   129  	testBlock(always, func() {
   130  		select {
   131  		case <-nilch:
   132  			unreachable()
   133  		case nilch <- 7:
   134  			unreachable()
   135  		}
   136  	})
   137  
   138  	// selects with non-ready non-nil channels always block
   139  	testBlock(always, func() {
   140  		ch := make(chan int)
   141  		select {
   142  		case <-ch:
   143  			unreachable()
   144  		}
   145  	})
   146  
   147  	// selects with default cases don't block
   148  	testBlock(never, func() {
   149  		select {
   150  		default:
   151  		}
   152  	})
   153  	testBlock(never, func() {
   154  		select {
   155  		case <-nilch:
   156  			unreachable()
   157  		default:
   158  		}
   159  	})
   160  	testBlock(never, func() {
   161  		select {
   162  		case nilch <- 7:
   163  			unreachable()
   164  		default:
   165  		}
   166  	})
   167  
   168  	// selects with ready channels don't block
   169  	testBlock(never, func() {
   170  		ch := make(chan int, async)
   171  		select {
   172  		case ch <- 7:
   173  		default:
   174  			unreachable()
   175  		}
   176  	})
   177  	testBlock(never, func() {
   178  		ch := make(chan int, async)
   179  		ch <- 7
   180  		select {
   181  		case <-ch:
   182  		default:
   183  			unreachable()
   184  		}
   185  	})
   186  
   187  	// selects with closed channels behave like ordinary operations
   188  	testBlock(never, func() {
   189  		select {
   190  		case <-closedch:
   191  		}
   192  	})
   193  	testBlock(never, func() {
   194  		select {
   195  		case x := (<-closedch):
   196  			_ = x
   197  		}
   198  	})
   199  	testBlock(never, func() {
   200  		select {
   201  		case x, ok := (<-closedch):
   202  			_, _ = x, ok
   203  		}
   204  	})
   205  	testPanic(always, func() {
   206  		select {
   207  		case closedch <- 7:
   208  		}
   209  	})
   210  
   211  	// select should not get confused if it sees itself
   212  	testBlock(always, func() {
   213  		c := make(chan int)
   214  		select {
   215  		case c <- 1:
   216  		case <-c:
   217  		}
   218  	})
   219  }