1// run
2
3// Copyright 2009 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 close(c), receive of closed channel.
8//
9// TODO(rsc): Doesn't check behavior of close(c) when there
10// are blocked senders/receivers.
11
12package main
13
14import "os"
15
16var failed bool
17
18type Chan interface {
19	Send(int)
20	Nbsend(int) bool
21	Recv() (int)
22	Nbrecv() (int, bool)
23	Recv2() (int, bool)
24	Nbrecv2() (int, bool, bool)
25	Close()
26	Impl() string
27}
28
29// direct channel operations when possible
30type XChan chan int
31
32func (c XChan) Send(x int) {
33	c <- x
34}
35
36func (c XChan) Nbsend(x int) bool {
37	select {
38	case c <- x:
39		return true
40	default:
41		return false
42	}
43	panic("nbsend")
44}
45
46func (c XChan) Recv() int {
47	return <-c
48}
49
50func (c XChan) Nbrecv() (int, bool) {
51	select {
52	case x := <-c:
53		return x, true
54	default:
55		return 0, false
56	}
57	panic("nbrecv")
58}
59
60func (c XChan) Recv2() (int, bool) {
61	x, ok := <-c
62	return x, ok
63}
64
65func (c XChan) Nbrecv2() (int, bool, bool) {
66	select {
67	case x, ok := <-c:
68		return x, ok, true
69	default:
70		return 0, false, false
71	}
72	panic("nbrecv2")
73}
74
75func (c XChan) Close() {
76	close(c)
77}
78
79func (c XChan) Impl() string {
80	return "(<- operator)"
81}
82
83// indirect operations via select
84type SChan chan int
85
86func (c SChan) Send(x int) {
87	select {
88	case c <- x:
89	}
90}
91
92func (c SChan) Nbsend(x int) bool {
93	select {
94	default:
95		return false
96	case c <- x:
97		return true
98	}
99	panic("nbsend")
100}
101
102func (c SChan) Recv() int {
103	select {
104	case x := <-c:
105		return x
106	}
107	panic("recv")
108}
109
110func (c SChan) Nbrecv() (int, bool) {
111	select {
112	default:
113		return 0, false
114	case x := <-c:
115		return x, true
116	}
117	panic("nbrecv")
118}
119
120func (c SChan) Recv2() (int, bool) {
121	select {
122	case x, ok := <-c:
123		return x, ok
124	}
125	panic("recv")
126}
127
128func (c SChan) Nbrecv2() (int, bool, bool) {
129	select {
130	default:
131		return 0, false, false
132	case x, ok := <-c:
133		return x, ok, true
134	}
135	panic("nbrecv")
136}
137
138func (c SChan) Close() {
139	close(c)
140}
141
142func (c SChan) Impl() string {
143	return "(select)"
144}
145
146// indirect operations via larger selects
147var dummy = make(chan bool)
148
149type SSChan chan int
150
151func (c SSChan) Send(x int) {
152	select {
153	case c <- x:
154	case <-dummy:
155	}
156}
157
158func (c SSChan) Nbsend(x int) bool {
159	select {
160	default:
161		return false
162	case <-dummy:
163	case c <- x:
164		return true
165	}
166	panic("nbsend")
167}
168
169func (c SSChan) Recv() int {
170	select {
171	case <-dummy:
172	case x := <-c:
173		return x
174	}
175	panic("recv")
176}
177
178func (c SSChan) Nbrecv() (int, bool) {
179	select {
180	case <-dummy:
181	default:
182		return 0, false
183	case x := <-c:
184		return x, true
185	}
186	panic("nbrecv")
187}
188
189func (c SSChan) Recv2() (int, bool) {
190	select {
191	case <-dummy:
192	case x, ok := <-c:
193		return x, ok
194	}
195	panic("recv")
196}
197
198func (c SSChan) Nbrecv2() (int, bool, bool) {
199	select {
200	case <-dummy:
201	default:
202		return 0, false, false
203	case x, ok := <-c:
204		return x, ok, true
205	}
206	panic("nbrecv")
207}
208
209func (c SSChan) Close() {
210	close(c)
211}
212
213func (c SSChan) Impl() string {
214	return "(select)"
215}
216
217
218func shouldPanic(f func()) {
219	defer func() {
220		if recover() == nil {
221			panic("did not panic")
222		}
223	}()
224	f()
225}
226
227func test1(c Chan) {
228	for i := 0; i < 3; i++ {
229		// recv a close signal (a zero value)
230		if x := c.Recv(); x != 0 {
231			println("test1: recv on closed:", x, c.Impl())
232			failed = true
233		}
234		if x, ok := c.Recv2(); x != 0 || ok {
235			println("test1: recv2 on closed:", x, ok, c.Impl())
236			failed = true
237		}
238
239		// should work with select: received a value without blocking, so selected == true.
240		x, selected := c.Nbrecv()
241		if x != 0 || !selected {
242			println("test1: recv on closed nb:", x, selected, c.Impl())
243			failed = true
244		}
245		x, ok, selected := c.Nbrecv2()
246		if x != 0 || ok || !selected {
247			println("test1: recv2 on closed nb:", x, ok, selected, c.Impl())
248			failed = true
249		}
250	}
251
252	// send should work with ,ok too: sent a value without blocking, so ok == true.
253	shouldPanic(func() { c.Nbsend(1) })
254
255	// the value should have been discarded.
256	if x := c.Recv(); x != 0 {
257		println("test1: recv on closed got non-zero after send on closed:", x, c.Impl())
258		failed = true
259	}
260
261	// similarly Send.
262	shouldPanic(func() { c.Send(2) })
263	if x := c.Recv(); x != 0 {
264		println("test1: recv on closed got non-zero after send on closed:", x, c.Impl())
265		failed = true
266	}
267}
268
269func testasync1(c Chan) {
270	// should be able to get the last value via Recv
271	if x := c.Recv(); x != 1 {
272		println("testasync1: Recv did not get 1:", x, c.Impl())
273		failed = true
274	}
275
276	test1(c)
277}
278
279func testasync2(c Chan) {
280	// should be able to get the last value via Recv2
281	if x, ok := c.Recv2(); x != 1 || !ok {
282		println("testasync1: Recv did not get 1, true:", x, ok, c.Impl())
283		failed = true
284	}
285
286	test1(c)
287}
288
289func testasync3(c Chan) {
290	// should be able to get the last value via Nbrecv
291	if x, selected := c.Nbrecv(); x != 1 || !selected {
292		println("testasync2: Nbrecv did not get 1, true:", x, selected, c.Impl())
293		failed = true
294	}
295
296	test1(c)
297}
298
299func testasync4(c Chan) {
300	// should be able to get the last value via Nbrecv2
301	if x, ok, selected := c.Nbrecv2(); x != 1 || !ok || !selected {
302		println("testasync2: Nbrecv did not get 1, true, true:", x, ok, selected, c.Impl())
303		failed = true
304	}
305	test1(c)
306}
307
308func closedsync() chan int {
309	c := make(chan int)
310	close(c)
311	return c
312}
313
314func closedasync() chan int {
315	c := make(chan int, 2)
316	c <- 1
317	close(c)
318	return c
319}
320
321var mks = []func(chan int) Chan {
322	func(c chan int) Chan { return XChan(c) },
323	func(c chan int) Chan { return SChan(c) },
324	func(c chan int) Chan { return SSChan(c) },
325}
326
327var testcloseds = []func(Chan) {
328	testasync1,
329	testasync2,
330	testasync3,
331	testasync4,
332}
333
334func main() {
335	for _, mk := range mks {
336		test1(mk(closedsync()))
337	}
338
339	for _, testclosed := range testcloseds {
340		for _, mk := range mks {
341			testclosed(mk(closedasync()))
342		}
343	}
344
345	var ch chan int
346	shouldPanic(func() {
347		close(ch)
348	})
349
350	ch = make(chan int)
351	close(ch)
352	shouldPanic(func() {
353		close(ch)
354	})
355
356	if failed {
357		os.Exit(1)
358	}
359}
360