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}
36
37// test that range over slice only evaluates
38// the expression after "range" once.
39
40var nmake = 0
41
42func makeslice() []int {
43	nmake++
44	return []int{1, 2, 3, 4, 5}
45}
46
47func testslice() {
48	s := 0
49	nmake = 0
50	for _, v := range makeslice() {
51		s += v
52	}
53	if nmake != 1 {
54		println("range called makeslice", nmake, "times")
55		panic("fail")
56	}
57	if s != 15 {
58		println("wrong sum ranging over makeslice", s)
59		panic("fail")
60	}
61
62	x := []int{10, 20}
63	y := []int{99}
64	i := 1
65	for i, x[i] = range y {
66		break
67	}
68	if i != 0 || x[0] != 10 || x[1] != 99 {
69		println("wrong parallel assignment", i, x[0], x[1])
70		panic("fail")
71	}
72}
73
74func testslice1() {
75	s := 0
76	nmake = 0
77	for i := range makeslice() {
78		s += i
79	}
80	if nmake != 1 {
81		println("range called makeslice", nmake, "times")
82		panic("fail")
83	}
84	if s != 10 {
85		println("wrong sum ranging over makeslice", s)
86		panic("fail")
87	}
88}
89
90// test that range over array only evaluates
91// the expression after "range" once.
92
93func makearray() [5]int {
94	nmake++
95	return [5]int{1, 2, 3, 4, 5}
96}
97
98func testarray() {
99	s := 0
100	nmake = 0
101	for _, v := range makearray() {
102		s += v
103	}
104	if nmake != 1 {
105		println("range called makearray", nmake, "times")
106		panic("fail")
107	}
108	if s != 15 {
109		println("wrong sum ranging over makearray", s)
110		panic("fail")
111	}
112}
113
114func testarray1() {
115	s := 0
116	nmake = 0
117	for i := range makearray() {
118		s += i
119	}
120	if nmake != 1 {
121		println("range called makearray", nmake, "times")
122		panic("fail")
123	}
124	if s != 10 {
125		println("wrong sum ranging over makearray", s)
126		panic("fail")
127	}
128}
129
130func makearrayptr() *[5]int {
131	nmake++
132	return &[5]int{1, 2, 3, 4, 5}
133}
134
135func testarrayptr() {
136	nmake = 0
137	x := len(makearrayptr())
138	if x != 5 || nmake != 1 {
139		println("len called makearrayptr", nmake, "times and got len", x)
140		panic("fail")
141	}
142	nmake = 0
143	x = cap(makearrayptr())
144	if x != 5 || nmake != 1 {
145		println("cap called makearrayptr", nmake, "times and got len", x)
146		panic("fail")
147	}
148	s := 0
149	nmake = 0
150	for _, v := range makearrayptr() {
151		s += v
152	}
153	if nmake != 1 {
154		println("range called makearrayptr", nmake, "times")
155		panic("fail")
156	}
157	if s != 15 {
158		println("wrong sum ranging over makearrayptr", s)
159		panic("fail")
160	}
161}
162
163func testarrayptr1() {
164	s := 0
165	nmake = 0
166	for i := range makearrayptr() {
167		s += i
168	}
169	if nmake != 1 {
170		println("range called makearrayptr", nmake, "times")
171		panic("fail")
172	}
173	if s != 10 {
174		println("wrong sum ranging over makearrayptr", s)
175		panic("fail")
176	}
177}
178
179// test that range over string only evaluates
180// the expression after "range" once.
181
182func makestring() string {
183	nmake++
184	return "abcd☺"
185}
186
187func teststring() {
188	var s rune
189	nmake = 0
190	for _, v := range makestring() {
191		s += v
192	}
193	if nmake != 1 {
194		println("range called makestring", nmake, "times")
195		panic("fail")
196	}
197	if s != 'a'+'b'+'c'+'d'+'☺' {
198		println("wrong sum ranging over makestring", s)
199		panic("fail")
200	}
201}
202
203func teststring1() {
204	s := 0
205	nmake = 0
206	for i := range makestring() {
207		s += i
208	}
209	if nmake != 1 {
210		println("range called makestring", nmake, "times")
211		panic("fail")
212	}
213	if s != 10 {
214		println("wrong sum ranging over makestring", s)
215		panic("fail")
216	}
217}
218
219// test that range over map only evaluates
220// the expression after "range" once.
221
222func makemap() map[int]int {
223	nmake++
224	return map[int]int{0: 'a', 1: 'b', 2: 'c', 3: 'd', 4: '☺'}
225}
226
227func testmap() {
228	s := 0
229	nmake = 0
230	for _, v := range makemap() {
231		s += v
232	}
233	if nmake != 1 {
234		println("range called makemap", nmake, "times")
235		panic("fail")
236	}
237	if s != 'a'+'b'+'c'+'d'+'☺' {
238		println("wrong sum ranging over makemap", s)
239		panic("fail")
240	}
241}
242
243func testmap1() {
244	s := 0
245	nmake = 0
246	for i := range makemap() {
247		s += i
248	}
249	if nmake != 1 {
250		println("range called makemap", nmake, "times")
251		panic("fail")
252	}
253	if s != 10 {
254		println("wrong sum ranging over makemap", s)
255		panic("fail")
256	}
257}
258
259// test that range evaluates the index and value expressions
260// exactly once per iteration.
261
262var ncalls = 0
263
264func getvar(p *int) *int {
265	ncalls++
266	return p
267}
268
269func testcalls() {
270	var i, v int
271	si := 0
272	sv := 0
273	for *getvar(&i), *getvar(&v) = range [2]int{1, 2} {
274		si += i
275		sv += v
276	}
277	if ncalls != 4 {
278		println("wrong number of calls:", ncalls, "!= 4")
279		panic("fail")
280	}
281	if si != 1 || sv != 3 {
282		println("wrong sum in testcalls", si, sv)
283		panic("fail")
284	}
285
286	ncalls = 0
287	for *getvar(&i), *getvar(&v) = range [0]int{} {
288		println("loop ran on empty array")
289		panic("fail")
290	}
291	if ncalls != 0 {
292		println("wrong number of calls:", ncalls, "!= 0")
293		panic("fail")
294	}
295}
296
297func main() {
298	testchan()
299	testarray()
300	testarray1()
301	testarrayptr()
302	testarrayptr1()
303	testslice()
304	testslice1()
305	teststring()
306	teststring1()
307	testmap()
308	testmap1()
309	testcalls()
310}
311