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