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