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
26func testchan() {
27	s := ""
28	for i := range seq('a', 'z') {
29		s += string(i)
30	}
31	if s != "abcdefghijklmnopqrstuvwxyz" {
32		println("Wanted lowercase alphabet; got", s)
33		panic("fail")
34	}
35	n := 0
36	for range seq('a', 'z') {
37		n++
38	}
39	if n != 26 {
40		println("testchan wrong count", n, "want 26")
41	}
42}
43
44// test that range over slice only evaluates
45// the expression after "range" once.
46
47var nmake = 0
48
49func makeslice() []int {
50	nmake++
51	return []int{1, 2, 3, 4, 5}
52}
53
54func testslice() {
55	s := 0
56	nmake = 0
57	for _, v := range makeslice() {
58		s += v
59	}
60	if nmake != 1 {
61		println("range called makeslice", nmake, "times")
62		panic("fail")
63	}
64	if s != 15 {
65		println("wrong sum ranging over makeslice", s)
66		panic("fail")
67	}
68
69	x := []int{10, 20}
70	y := []int{99}
71	i := 1
72	for i, x[i] = range y {
73		break
74	}
75	if i != 0 || x[0] != 10 || x[1] != 99 {
76		println("wrong parallel assignment", i, x[0], x[1])
77		panic("fail")
78	}
79}
80
81func testslice1() {
82	s := 0
83	nmake = 0
84	for i := range makeslice() {
85		s += i
86	}
87	if nmake != 1 {
88		println("range called makeslice", nmake, "times")
89		panic("fail")
90	}
91	if s != 10 {
92		println("wrong sum ranging over makeslice", s)
93		panic("fail")
94	}
95}
96
97func testslice2() {
98	n := 0
99	nmake = 0
100	for range makeslice() {
101		n++
102	}
103	if nmake != 1 {
104		println("range called makeslice", nmake, "times")
105		panic("fail")
106	}
107	if n != 5 {
108		println("wrong count ranging over makeslice", n)
109		panic("fail")
110	}
111}
112
113// test that range over array only evaluates
114// the expression after "range" once.
115
116func makearray() [5]int {
117	nmake++
118	return [5]int{1, 2, 3, 4, 5}
119}
120
121func testarray() {
122	s := 0
123	nmake = 0
124	for _, v := range makearray() {
125		s += v
126	}
127	if nmake != 1 {
128		println("range called makearray", nmake, "times")
129		panic("fail")
130	}
131	if s != 15 {
132		println("wrong sum ranging over makearray", s)
133		panic("fail")
134	}
135}
136
137func testarray1() {
138	s := 0
139	nmake = 0
140	for i := range makearray() {
141		s += i
142	}
143	if nmake != 1 {
144		println("range called makearray", nmake, "times")
145		panic("fail")
146	}
147	if s != 10 {
148		println("wrong sum ranging over makearray", s)
149		panic("fail")
150	}
151}
152
153func testarray2() {
154	n := 0
155	nmake = 0
156	for range makearray() {
157		n++
158	}
159	if nmake != 1 {
160		println("range called makearray", nmake, "times")
161		panic("fail")
162	}
163	if n != 5 {
164		println("wrong count ranging over makearray", n)
165		panic("fail")
166	}
167}
168
169func makearrayptr() *[5]int {
170	nmake++
171	return &[5]int{1, 2, 3, 4, 5}
172}
173
174func testarrayptr() {
175	nmake = 0
176	x := len(makearrayptr())
177	if x != 5 || nmake != 1 {
178		println("len called makearrayptr", nmake, "times and got len", x)
179		panic("fail")
180	}
181	nmake = 0
182	x = cap(makearrayptr())
183	if x != 5 || nmake != 1 {
184		println("cap called makearrayptr", nmake, "times and got len", x)
185		panic("fail")
186	}
187	s := 0
188	nmake = 0
189	for _, v := range makearrayptr() {
190		s += v
191	}
192	if nmake != 1 {
193		println("range called makearrayptr", nmake, "times")
194		panic("fail")
195	}
196	if s != 15 {
197		println("wrong sum ranging over makearrayptr", s)
198		panic("fail")
199	}
200}
201
202func testarrayptr1() {
203	s := 0
204	nmake = 0
205	for i := range makearrayptr() {
206		s += i
207	}
208	if nmake != 1 {
209		println("range called makearrayptr", nmake, "times")
210		panic("fail")
211	}
212	if s != 10 {
213		println("wrong sum ranging over makearrayptr", s)
214		panic("fail")
215	}
216}
217
218func testarrayptr2() {
219	n := 0
220	nmake = 0
221	for range makearrayptr() {
222		n++
223	}
224	if nmake != 1 {
225		println("range called makearrayptr", nmake, "times")
226		panic("fail")
227	}
228	if n != 5 {
229		println("wrong count ranging over makearrayptr", n)
230		panic("fail")
231	}
232}
233
234// test that range over string only evaluates
235// the expression after "range" once.
236
237func makestring() string {
238	nmake++
239	return "abcd☺"
240}
241
242func teststring() {
243	var s rune
244	nmake = 0
245	for _, v := range makestring() {
246		s += v
247	}
248	if nmake != 1 {
249		println("range called makestring", nmake, "times")
250		panic("fail")
251	}
252	if s != 'a'+'b'+'c'+'d'+'☺' {
253		println("wrong sum ranging over makestring", s)
254		panic("fail")
255	}
256}
257
258func teststring1() {
259	s := 0
260	nmake = 0
261	for i := range makestring() {
262		s += i
263	}
264	if nmake != 1 {
265		println("range called makestring", nmake, "times")
266		panic("fail")
267	}
268	if s != 10 {
269		println("wrong sum ranging over makestring", s)
270		panic("fail")
271	}
272}
273
274func teststring2() {
275	n := 0
276	nmake = 0
277	for range makestring() {
278		n++
279	}
280	if nmake != 1 {
281		println("range called makestring", nmake, "times")
282		panic("fail")
283	}
284	if n != 5 {
285		println("wrong count ranging over makestring", n)
286		panic("fail")
287	}
288}
289
290// test that range over map only evaluates
291// the expression after "range" once.
292
293func makemap() map[int]int {
294	nmake++
295	return map[int]int{0: 'a', 1: 'b', 2: 'c', 3: 'd', 4: '☺'}
296}
297
298func testmap() {
299	s := 0
300	nmake = 0
301	for _, v := range makemap() {
302		s += v
303	}
304	if nmake != 1 {
305		println("range called makemap", nmake, "times")
306		panic("fail")
307	}
308	if s != 'a'+'b'+'c'+'d'+'☺' {
309		println("wrong sum ranging over makemap", s)
310		panic("fail")
311	}
312}
313
314func testmap1() {
315	s := 0
316	nmake = 0
317	for i := range makemap() {
318		s += i
319	}
320	if nmake != 1 {
321		println("range called makemap", nmake, "times")
322		panic("fail")
323	}
324	if s != 10 {
325		println("wrong sum ranging over makemap", s)
326		panic("fail")
327	}
328}
329
330func testmap2() {
331	n := 0
332	nmake = 0
333	for range makemap() {
334		n++
335	}
336	if nmake != 1 {
337		println("range called makemap", nmake, "times")
338		panic("fail")
339	}
340	if n != 5 {
341		println("wrong count ranging over makemap", n)
342		panic("fail")
343	}
344}
345
346// test that range evaluates the index and value expressions
347// exactly once per iteration.
348
349var ncalls = 0
350
351func getvar(p *int) *int {
352	ncalls++
353	return p
354}
355
356func testcalls() {
357	var i, v int
358	si := 0
359	sv := 0
360	for *getvar(&i), *getvar(&v) = range [2]int{1, 2} {
361		si += i
362		sv += v
363	}
364	if ncalls != 4 {
365		println("wrong number of calls:", ncalls, "!= 4")
366		panic("fail")
367	}
368	if si != 1 || sv != 3 {
369		println("wrong sum in testcalls", si, sv)
370		panic("fail")
371	}
372
373	ncalls = 0
374	for *getvar(&i), *getvar(&v) = range [0]int{} {
375		println("loop ran on empty array")
376		panic("fail")
377	}
378	if ncalls != 0 {
379		println("wrong number of calls:", ncalls, "!= 0")
380		panic("fail")
381	}
382}
383
384func main() {
385	testchan()
386	testarray()
387	testarray1()
388	testarray2()
389	testarrayptr()
390	testarrayptr1()
391	testarrayptr2()
392	testslice()
393	testslice1()
394	testslice2()
395	teststring()
396	teststring1()
397	teststring2()
398	testmap()
399	testmap1()
400	testmap2()
401	testcalls()
402}
403