xref: /aosp_15_r20/external/starlark-go/starlark/testdata/list.star (revision 4947cdc739c985f6d86941e22894f5cefe7c9e9a)
1# Tests of Starlark 'list'
2
3load("assert.star", "assert", "freeze")
4
5# literals
6assert.eq([], [])
7assert.eq([1], [1])
8assert.eq([1], [1])
9assert.eq([1, 2], [1, 2])
10assert.ne([1, 2, 3], [1, 2, 4])
11
12# truth
13assert.true([0])
14assert.true(not [])
15
16# indexing, x[i]
17abc = list("abc".elems())
18assert.fails(lambda: abc[-4], "list index -4 out of range \\[-3:2]")
19assert.eq(abc[-3], "a")
20assert.eq(abc[-2], "b")
21assert.eq(abc[-1], "c")
22assert.eq(abc[0], "a")
23assert.eq(abc[1], "b")
24assert.eq(abc[2], "c")
25assert.fails(lambda: abc[3], "list index 3 out of range \\[-3:2]")
26
27# x[i] = ...
28x3 = [0, 1, 2]
29x3[1] = 2
30x3[2] += 3
31assert.eq(x3, [0, 2, 5])
32
33def f2():
34    x3[3] = 4
35
36assert.fails(f2, "out of range")
37freeze(x3)
38
39def f3():
40    x3[0] = 0
41
42assert.fails(f3, "cannot assign to element of frozen list")
43assert.fails(x3.clear, "cannot clear frozen list")
44
45# list + list
46assert.eq([1, 2, 3] + [3, 4, 5], [1, 2, 3, 3, 4, 5])
47assert.fails(lambda: [1, 2] + (3, 4), "unknown.*list \\+ tuple")
48assert.fails(lambda: (1, 2) + [3, 4], "unknown.*tuple \\+ list")
49
50# list * int,  int * list
51assert.eq(abc * 0, [])
52assert.eq(abc * -1, [])
53assert.eq(abc * 1, abc)
54assert.eq(abc * 3, ["a", "b", "c", "a", "b", "c", "a", "b", "c"])
55assert.eq(0 * abc, [])
56assert.eq(-1 * abc, [])
57assert.eq(1 * abc, abc)
58assert.eq(3 * abc, ["a", "b", "c", "a", "b", "c", "a", "b", "c"])
59
60# list comprehensions
61assert.eq([2 * x for x in [1, 2, 3]], [2, 4, 6])
62assert.eq([2 * x for x in [1, 2, 3] if x > 1], [4, 6])
63assert.eq(
64    [(x, y) for x in [1, 2] for y in [3, 4]],
65    [(1, 3), (1, 4), (2, 3), (2, 4)],
66)
67assert.eq([(x, y) for x in [1, 2] if x == 2 for y in [3, 4]], [(2, 3), (2, 4)])
68assert.eq([2 * x for x in (1, 2, 3)], [2, 4, 6])
69assert.eq([x for x in "abc".elems()], ["a", "b", "c"])
70assert.eq([x for x in {"a": 1, "b": 2}], ["a", "b"])
71assert.eq([(y, x) for x, y in {1: 2, 3: 4}.items()], [(2, 1), (4, 3)])
72
73# corner cases of parsing:
74assert.eq([x for x in range(12) if x % 2 == 0 if x % 3 == 0], [0, 6])
75assert.eq([x for x in [1, 2] if lambda: None], [1, 2])
76assert.eq([x for x in [1, 2] if (lambda: 3 if True else 4)], [1, 2])
77
78# list function
79assert.eq(list(), [])
80assert.eq(list("ab".elems()), ["a", "b"])
81
82# A list comprehension defines a separate lexical block,
83# whether at top-level...
84a = [1, 2]
85b = [a for a in [3, 4]]
86assert.eq(a, [1, 2])
87assert.eq(b, [3, 4])
88
89# ...or local to a function.
90def listcompblock():
91    c = [1, 2]
92    d = [c for c in [3, 4]]
93    assert.eq(c, [1, 2])
94    assert.eq(d, [3, 4])
95
96listcompblock()
97
98# list.pop
99x4 = [1, 2, 3, 4, 5]
100assert.fails(lambda: x4.pop(-6), "index -6 out of range \\[-5:4]")
101assert.fails(lambda: x4.pop(6), "index 6 out of range \\[-5:4]")
102assert.eq(x4.pop(), 5)
103assert.eq(x4, [1, 2, 3, 4])
104assert.eq(x4.pop(1), 2)
105assert.eq(x4, [1, 3, 4])
106assert.eq(x4.pop(0), 1)
107assert.eq(x4, [3, 4])
108assert.eq(x4.pop(-2), 3)
109assert.eq(x4, [4])
110assert.eq(x4.pop(-1), 4)
111assert.eq(x4, [])
112
113# TODO(adonovan): test uses of list as sequence
114# (for loop, comprehension, library functions).
115
116# x += y for lists is equivalent to x.extend(y).
117# y may be a sequence.
118# TODO: Test that side-effects of 'x' occur only once.
119def list_extend():
120    a = [1, 2, 3]
121    b = a
122    a = a + [4]  # creates a new list
123    assert.eq(a, [1, 2, 3, 4])
124    assert.eq(b, [1, 2, 3])  # b is unchanged
125
126    a = [1, 2, 3]
127    b = a
128    a += [4]  # updates a (and thus b) in place
129    assert.eq(a, [1, 2, 3, 4])
130    assert.eq(b, [1, 2, 3, 4])  # alias observes the change
131
132    a = [1, 2, 3]
133    b = a
134    a.extend([4])  # updates existing list
135    assert.eq(a, [1, 2, 3, 4])
136    assert.eq(b, [1, 2, 3, 4])  # alias observes the change
137
138list_extend()
139
140# Unlike list.extend(iterable), list += iterable makes its LHS name local.
141a_list = []
142
143def f4():
144    a_list += [1]  # binding use => a_list is a local var
145
146assert.fails(f4, "local variable a_list referenced before assignment")
147
148# list += <not iterable>
149def f5():
150    x = []
151    x += 1
152
153assert.fails(f5, "unknown binary op: list \\+ int")
154
155# frozen list += iterable
156def f6():
157    x = []
158    freeze(x)
159    x += [1]
160
161assert.fails(f6, "cannot apply \\+= to frozen list")
162
163# list += hasfields (hasfields is not iterable but defines list+hasfields)
164def f7():
165    x = []
166    x += hasfields()
167    return x
168
169assert.eq(f7(), 42)  # weird, but exercises a corner case in list+=x.
170
171# append
172x5 = [1, 2, 3]
173x5.append(4)
174x5.append("abc")
175assert.eq(x5, [1, 2, 3, 4, "abc"])
176
177# extend
178x5a = [1, 2, 3]
179x5a.extend("abc".elems())  # string
180x5a.extend((True, False))  # tuple
181assert.eq(x5a, [1, 2, 3, "a", "b", "c", True, False])
182
183# list.insert
184def insert_at(index):
185    x = list(range(3))
186    x.insert(index, 42)
187    return x
188
189assert.eq(insert_at(-99), [42, 0, 1, 2])
190assert.eq(insert_at(-2), [0, 42, 1, 2])
191assert.eq(insert_at(-1), [0, 1, 42, 2])
192assert.eq(insert_at(0), [42, 0, 1, 2])
193assert.eq(insert_at(1), [0, 42, 1, 2])
194assert.eq(insert_at(2), [0, 1, 42, 2])
195assert.eq(insert_at(3), [0, 1, 2, 42])
196assert.eq(insert_at(4), [0, 1, 2, 42])
197
198# list.remove
199def remove(v):
200    x = [3, 1, 4, 1]
201    x.remove(v)
202    return x
203
204assert.eq(remove(3), [1, 4, 1])
205assert.eq(remove(1), [3, 4, 1])
206assert.eq(remove(4), [3, 1, 1])
207assert.fails(lambda: [3, 1, 4, 1].remove(42), "remove: element not found")
208
209# list.index
210bananas = list("bananas".elems())
211assert.eq(bananas.index("a"), 1)  # bAnanas
212assert.fails(lambda: bananas.index("d"), "value not in list")
213
214# start
215assert.eq(bananas.index("a", -1000), 1)  # bAnanas
216assert.eq(bananas.index("a", 0), 1)  # bAnanas
217assert.eq(bananas.index("a", 1), 1)  # bAnanas
218assert.eq(bananas.index("a", 2), 3)  # banAnas
219assert.eq(bananas.index("a", 3), 3)  # banAnas
220assert.eq(bananas.index("b", 0), 0)  # Bananas
221assert.eq(bananas.index("n", -3), 4)  # banaNas
222assert.fails(lambda: bananas.index("n", -2), "value not in list")
223assert.eq(bananas.index("s", -2), 6)  # bananaS
224assert.fails(lambda: bananas.index("b", 1), "value not in list")
225
226# start, end
227assert.eq(bananas.index("s", -1000, 7), 6)  # bananaS
228assert.fails(lambda: bananas.index("s", -1000, 6), "value not in list")
229assert.fails(lambda: bananas.index("d", -1000, 1000), "value not in list")
230
231# slicing, x[i:j:k]
232assert.eq(bananas[6::-2], list("snnb".elems()))
233assert.eq(bananas[5::-2], list("aaa".elems()))
234assert.eq(bananas[4::-2], list("nnb".elems()))
235assert.eq(bananas[99::-2], list("snnb".elems()))
236assert.eq(bananas[100::-2], list("snnb".elems()))
237# TODO(adonovan): many more tests
238
239# iterator invalidation
240def iterator1():
241    list = [0, 1, 2]
242    for x in list:
243        list[x] = 2 * x
244    return list
245
246assert.fails(iterator1, "assign to element.* during iteration")
247
248def iterator2():
249    list = [0, 1, 2]
250    for x in list:
251        list.remove(x)
252
253assert.fails(iterator2, "remove.*during iteration")
254
255def iterator3():
256    list = [0, 1, 2]
257    for x in list:
258        list.append(3)
259
260assert.fails(iterator3, "append.*during iteration")
261
262def iterator4():
263    list = [0, 1, 2]
264    for x in list:
265        list.extend([3, 4])
266
267assert.fails(iterator4, "extend.*during iteration")
268
269def iterator5():
270    def f(x):
271        x.append(4)
272
273    list = [1, 2, 3]
274    _ = [f(list) for x in list]
275
276assert.fails(iterator5, "append.*during iteration")
277