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 the 'for range' construct.
8
9package main
10
11// test range over channels
12
13func gen(c chan int, lo, hi int) {
14	for i := lo; i <= hi; i++ {
15		c <- i
16	}
17	close(c)
18}
19
20func seq(lo, hi int) chan int {
21	c := make(chan int)
22	go gen(c, lo, hi)
23	return c
24}
25
26const alphabet = "abcdefghijklmnopqrstuvwxyz"
27
28func testblankvars() {
29	n := 0
30	for range alphabet {
31		n++
32	}
33	if n != 26 {
34		println("for range: wrong count", n, "want 26")
35		panic("fail")
36	}
37	n = 0
38	for _ = range alphabet {
39		n++
40	}
41	if n != 26 {
42		println("for _ = range: wrong count", n, "want 26")
43		panic("fail")
44	}
45	n = 0
46	for _, _ = range alphabet {
47		n++
48	}
49	if n != 26 {
50		println("for _, _ = range: wrong count", n, "want 26")
51		panic("fail")
52	}
53	s := 0
54	for i, _ := range alphabet {
55		s += i
56	}
57	if s != 325 {
58		println("for i, _ := range: wrong sum", s, "want 325")
59		panic("fail")
60	}
61	r := rune(0)
62	for _, v := range alphabet {
63		r += v
64	}
65	if r != 2847 {
66		println("for _, v := range: wrong sum", r, "want 2847")
67		panic("fail")
68	}
69}
70
71func testchan() {
72	s := ""
73	for i := range seq('a', 'z') {
74		s += string(i)
75	}
76	if s != alphabet {
77		println("Wanted lowercase alphabet; got", s)
78		panic("fail")
79	}
80	n := 0
81	for range seq('a', 'z') {
82		n++
83	}
84	if n != 26 {
85		println("testchan wrong count", n, "want 26")
86		panic("fail")
87	}
88}
89
90// test that range over slice only evaluates
91// the expression after "range" once.
92
93var nmake = 0
94
95func makeslice() []int {
96	nmake++
97	return []int{1, 2, 3, 4, 5}
98}
99
100func testslice() {
101	s := 0
102	nmake = 0
103	for _, v := range makeslice() {
104		s += v
105	}
106	if nmake != 1 {
107		println("range called makeslice", nmake, "times")
108		panic("fail")
109	}
110	if s != 15 {
111		println("wrong sum ranging over makeslice", s)
112		panic("fail")
113	}
114
115	x := []int{10, 20}
116	y := []int{99}
117	i := 1
118	for i, x[i] = range y {
119		break
120	}
121	if i != 0 || x[0] != 10 || x[1] != 99 {
122		println("wrong parallel assignment", i, x[0], x[1])
123		panic("fail")
124	}
125}
126
127func testslice1() {
128	s := 0
129	nmake = 0
130	for i := range makeslice() {
131		s += i
132	}
133	if nmake != 1 {
134		println("range called makeslice", nmake, "times")
135		panic("fail")
136	}
137	if s != 10 {
138		println("wrong sum ranging over makeslice", s)
139		panic("fail")
140	}
141}
142
143func testslice2() {
144	n := 0
145	nmake = 0
146	for range makeslice() {
147		n++
148	}
149	if nmake != 1 {
150		println("range called makeslice", nmake, "times")
151		panic("fail")
152	}
153	if n != 5 {
154		println("wrong count ranging over makeslice", n)
155		panic("fail")
156	}
157}
158
159// test that range over []byte(string) only evaluates
160// the expression after "range" once.
161
162func makenumstring() string {
163	nmake++
164	return "\x01\x02\x03\x04\x05"
165}
166
167func testslice3() {
168	s := byte(0)
169	nmake = 0
170	for _, v := range []byte(makenumstring()) {
171		s += v
172	}
173	if nmake != 1 {
174		println("range called makenumstring", nmake, "times")
175		panic("fail")
176	}
177	if s != 15 {
178		println("wrong sum ranging over []byte(makenumstring)", s)
179		panic("fail")
180	}
181}
182
183// test that range over array only evaluates
184// the expression after "range" once.
185
186func makearray() [5]int {
187	nmake++
188	return [5]int{1, 2, 3, 4, 5}
189}
190
191func testarray() {
192	s := 0
193	nmake = 0
194	for _, v := range makearray() {
195		s += v
196	}
197	if nmake != 1 {
198		println("range called makearray", nmake, "times")
199		panic("fail")
200	}
201	if s != 15 {
202		println("wrong sum ranging over makearray", s)
203		panic("fail")
204	}
205}
206
207func testarray1() {
208	s := 0
209	nmake = 0
210	for i := range makearray() {
211		s += i
212	}
213	if nmake != 1 {
214		println("range called makearray", nmake, "times")
215		panic("fail")
216	}
217	if s != 10 {
218		println("wrong sum ranging over makearray", s)
219		panic("fail")
220	}
221}
222
223func testarray2() {
224	n := 0
225	nmake = 0
226	for range makearray() {
227		n++
228	}
229	if nmake != 1 {
230		println("range called makearray", nmake, "times")
231		panic("fail")
232	}
233	if n != 5 {
234		println("wrong count ranging over makearray", n)
235		panic("fail")
236	}
237}
238
239func makearrayptr() *[5]int {
240	nmake++
241	return &[5]int{1, 2, 3, 4, 5}
242}
243
244func testarrayptr() {
245	nmake = 0
246	x := len(makearrayptr())
247	if x != 5 || nmake != 1 {
248		println("len called makearrayptr", nmake, "times and got len", x)
249		panic("fail")
250	}
251	nmake = 0
252	x = cap(makearrayptr())
253	if x != 5 || nmake != 1 {
254		println("cap called makearrayptr", nmake, "times and got len", x)
255		panic("fail")
256	}
257	s := 0
258	nmake = 0
259	for _, v := range makearrayptr() {
260		s += v
261	}
262	if nmake != 1 {
263		println("range called makearrayptr", nmake, "times")
264		panic("fail")
265	}
266	if s != 15 {
267		println("wrong sum ranging over makearrayptr", s)
268		panic("fail")
269	}
270}
271
272func testarrayptr1() {
273	s := 0
274	nmake = 0
275	for i := range makearrayptr() {
276		s += i
277	}
278	if nmake != 1 {
279		println("range called makearrayptr", nmake, "times")
280		panic("fail")
281	}
282	if s != 10 {
283		println("wrong sum ranging over makearrayptr", s)
284		panic("fail")
285	}
286}
287
288func testarrayptr2() {
289	n := 0
290	nmake = 0
291	for range makearrayptr() {
292		n++
293	}
294	if nmake != 1 {
295		println("range called makearrayptr", nmake, "times")
296		panic("fail")
297	}
298	if n != 5 {
299		println("wrong count ranging over makearrayptr", n)
300		panic("fail")
301	}
302}
303
304// test that range over string only evaluates
305// the expression after "range" once.
306
307func makestring() string {
308	nmake++
309	return "abcd☺"
310}
311
312func teststring() {
313	var s rune
314	nmake = 0
315	for _, v := range makestring() {
316		s += v
317	}
318	if nmake != 1 {
319		println("range called makestring", nmake, "times")
320		panic("fail")
321	}
322	if s != 'a'+'b'+'c'+'d'+'☺' {
323		println("wrong sum ranging over makestring", s)
324		panic("fail")
325	}
326
327	x := []rune{'a', 'b'}
328	i := 1
329	for i, x[i] = range "c" {
330		break
331	}
332	if i != 0 || x[0] != 'a' || x[1] != 'c' {
333		println("wrong parallel assignment", i, x[0], x[1])
334		panic("fail")
335	}
336
337	y := []int{1, 2, 3}
338	r := rune(1)
339	for y[r], r = range "\x02" {
340		break
341	}
342	if r != 2 || y[0] != 1 || y[1] != 0 || y[2] != 3 {
343		println("wrong parallel assignment", r, y[0], y[1], y[2])
344		panic("fail")
345	}
346}
347
348func teststring1() {
349	s := 0
350	nmake = 0
351	for i := range makestring() {
352		s += i
353	}
354	if nmake != 1 {
355		println("range called makestring", nmake, "times")
356		panic("fail")
357	}
358	if s != 10 {
359		println("wrong sum ranging over makestring", s)
360		panic("fail")
361	}
362}
363
364func teststring2() {
365	n := 0
366	nmake = 0
367	for range makestring() {
368		n++
369	}
370	if nmake != 1 {
371		println("range called makestring", nmake, "times")
372		panic("fail")
373	}
374	if n != 5 {
375		println("wrong count ranging over makestring", n)
376		panic("fail")
377	}
378}
379
380// test that range over map only evaluates
381// the expression after "range" once.
382
383func makemap() map[int]int {
384	nmake++
385	return map[int]int{0: 'a', 1: 'b', 2: 'c', 3: 'd', 4: '☺'}
386}
387
388func testmap() {
389	s := 0
390	nmake = 0
391	for _, v := range makemap() {
392		s += v
393	}
394	if nmake != 1 {
395		println("range called makemap", nmake, "times")
396		panic("fail")
397	}
398	if s != 'a'+'b'+'c'+'d'+'☺' {
399		println("wrong sum ranging over makemap", s)
400		panic("fail")
401	}
402}
403
404func testmap1() {
405	s := 0
406	nmake = 0
407	for i := range makemap() {
408		s += i
409	}
410	if nmake != 1 {
411		println("range called makemap", nmake, "times")
412		panic("fail")
413	}
414	if s != 10 {
415		println("wrong sum ranging over makemap", s)
416		panic("fail")
417	}
418}
419
420func testmap2() {
421	n := 0
422	nmake = 0
423	for range makemap() {
424		n++
425	}
426	if nmake != 1 {
427		println("range called makemap", nmake, "times")
428		panic("fail")
429	}
430	if n != 5 {
431		println("wrong count ranging over makemap", n)
432		panic("fail")
433	}
434}
435
436// test that range evaluates the index and value expressions
437// exactly once per iteration.
438
439var ncalls = 0
440
441func getvar(p *int) *int {
442	ncalls++
443	return p
444}
445
446func testcalls() {
447	var i, v int
448	si := 0
449	sv := 0
450	for *getvar(&i), *getvar(&v) = range [2]int{1, 2} {
451		si += i
452		sv += v
453	}
454	if ncalls != 4 {
455		println("wrong number of calls:", ncalls, "!= 4")
456		panic("fail")
457	}
458	if si != 1 || sv != 3 {
459		println("wrong sum in testcalls", si, sv)
460		panic("fail")
461	}
462
463	ncalls = 0
464	for *getvar(&i), *getvar(&v) = range [0]int{} {
465		println("loop ran on empty array")
466		panic("fail")
467	}
468	if ncalls != 0 {
469		println("wrong number of calls:", ncalls, "!= 0")
470		panic("fail")
471	}
472}
473
474func main() {
475	testblankvars()
476	testchan()
477	testarray()
478	testarray1()
479	testarray2()
480	testarrayptr()
481	testarrayptr1()
482	testarrayptr2()
483	testslice()
484	testslice1()
485	testslice2()
486	testslice3()
487	teststring()
488	teststring1()
489	teststring2()
490	testmap()
491	testmap1()
492	testmap2()
493	testcalls()
494}
495