go.starlark.net@v0.0.0-20231101134539-556fd59b42f6/starlark/testdata/dict.star (about) 1 # Tests of Starlark 'dict' 2 3 load("assert.star", "assert", "freeze") 4 5 # literals 6 assert.eq({}, {}) 7 assert.eq({"a": 1}, {"a": 1}) 8 assert.eq({"a": 1,}, {"a": 1}) 9 10 # truth 11 assert.true({False: False}) 12 assert.true(not {}) 13 14 # dict + dict is no longer supported. 15 assert.fails(lambda: {"a": 1} + {"b": 2}, 'unknown binary op: dict \\+ dict') 16 17 # dict comprehension 18 assert.eq({x: x*x for x in range(3)}, {0: 0, 1: 1, 2: 4}) 19 20 # dict.pop 21 x6 = {"a": 1, "b": 2} 22 assert.eq(x6.pop("a"), 1) 23 assert.eq(str(x6), '{"b": 2}') 24 assert.fails(lambda: x6.pop("c"), "pop: missing key") 25 assert.eq(x6.pop("c", 3), 3) 26 assert.eq(x6.pop("c", None), None) # default=None tests an edge case of UnpackArgs 27 assert.eq(x6.pop("b"), 2) 28 assert.eq(len(x6), 0) 29 30 # dict.popitem 31 x7 = {"a": 1, "b": 2} 32 assert.eq([x7.popitem(), x7.popitem()], [("a", 1), ("b", 2)]) 33 assert.fails(x7.popitem, "empty dict") 34 assert.eq(len(x7), 0) 35 36 # dict.keys, dict.values 37 x8 = {"a": 1, "b": 2} 38 assert.eq(x8.keys(), ["a", "b"]) 39 assert.eq(x8.values(), [1, 2]) 40 41 # equality 42 assert.eq({"a": 1, "b": 2}, {"a": 1, "b": 2}) 43 assert.eq({"a": 1, "b": 2,}, {"a": 1, "b": 2}) 44 assert.eq({"a": 1, "b": 2}, {"b": 2, "a": 1}) 45 46 # insertion order is preserved 47 assert.eq(dict([("a", 0), ("b", 1), ("c", 2), ("b", 3)]).keys(), ["a", "b", "c"]) 48 assert.eq(dict([("b", 0), ("a", 1), ("b", 2), ("c", 3)]).keys(), ["b", "a", "c"]) 49 assert.eq(dict([("b", 0), ("a", 1), ("b", 2), ("c", 3)])["b"], 2) 50 # ...even after rehashing (which currently occurs after key 'i'): 51 small = dict([("a", 0), ("b", 1), ("c", 2)]) 52 small.update([("d", 4), ("e", 5), ("f", 6), ("g", 7), ("h", 8), ("i", 9), ("j", 10), ("k", 11)]) 53 assert.eq(small.keys(), ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k"]) 54 55 # Duplicate keys are not permitted in dictionary expressions (see b/35698444). 56 # (Nor in keyword args to function calls---checked by resolver.) 57 assert.fails(lambda: {"aa": 1, "bb": 2, "cc": 3, "bb": 4}, 'duplicate key: "bb"') 58 59 # Check that even with many positional args, keyword collisions are detected. 60 assert.fails(lambda: dict({'b': 3}, a=4, **dict(a=5)), 'dict: duplicate keyword arg: "a"') 61 assert.fails(lambda: dict({'a': 2, 'b': 3}, a=4, **dict(a=5)), 'dict: duplicate keyword arg: "a"') 62 # positional/keyword arg key collisions are ok 63 assert.eq(dict((['a', 2], ), a=4), {'a': 4}) 64 assert.eq(dict((['a', 2], ['a', 3]), a=4), {'a': 4}) 65 66 # index 67 def setIndex(d, k, v): 68 d[k] = v 69 70 x9 = {} 71 assert.fails(lambda: x9["a"], 'key "a" not in dict') 72 x9["a"] = 1 73 assert.eq(x9["a"], 1) 74 assert.eq(x9, {"a": 1}) 75 assert.fails(lambda: setIndex(x9, [], 2), 'unhashable type: list') 76 freeze(x9) 77 assert.fails(lambda: setIndex(x9, "a", 3), 'cannot insert into frozen hash table') 78 79 x9a = {} 80 x9a[1, 2] = 3 # unparenthesized tuple is allowed here 81 assert.eq(x9a.keys()[0], (1, 2)) 82 83 # dict.get 84 x10 = {"a": 1} 85 assert.eq(x10.get("a"), 1) 86 assert.eq(x10.get("b"), None) 87 assert.eq(x10.get("a", 2), 1) 88 assert.eq(x10.get("b", 2), 2) 89 90 # dict.clear 91 x11 = {"a": 1} 92 assert.contains(x11, "a") 93 assert.eq(x11["a"], 1) 94 x11.clear() 95 assert.fails(lambda: x11["a"], 'key "a" not in dict') 96 assert.true("a" not in x11) 97 freeze(x11) 98 assert.fails(x11.clear, "cannot clear frozen hash table") 99 100 # dict.setdefault 101 x12 = {"a": 1} 102 assert.eq(x12.setdefault("a"), 1) 103 assert.eq(x12["a"], 1) 104 assert.eq(x12.setdefault("b"), None) 105 assert.eq(x12["b"], None) 106 assert.eq(x12.setdefault("c", 2), 2) 107 assert.eq(x12["c"], 2) 108 assert.eq(x12.setdefault("c", 3), 2) 109 assert.eq(x12["c"], 2) 110 freeze(x12) 111 assert.eq(x12.setdefault("a", 1), 1) # no change, no error 112 assert.fails(lambda: x12.setdefault("d", 1), "cannot insert into frozen hash table") 113 114 # dict.update 115 x13 = {"a": 1} 116 x13.update(a=2, b=3) 117 assert.eq(x13, {"a": 2, "b": 3}) 118 x13.update([("b", 4), ("c", 5)]) 119 assert.eq(x13, {"a": 2, "b": 4, "c": 5}) 120 x13.update({"c": 6, "d": 7}) 121 assert.eq(x13, {"a": 2, "b": 4, "c": 6, "d": 7}) 122 freeze(x13) 123 assert.fails(lambda: x13.update({"a": 8}), "cannot insert into frozen hash table") 124 125 # dict as a sequence 126 # 127 # for loop 128 x14 = {1:2, 3:4} 129 def keys(dict): 130 keys = [] 131 for k in dict: keys.append(k) 132 return keys 133 assert.eq(keys(x14), [1, 3]) 134 # 135 # comprehension 136 assert.eq([x for x in x14], [1, 3]) 137 # 138 # varargs 139 def varargs(*args): return args 140 x15 = {"one": 1} 141 assert.eq(varargs(*x15), ("one",)) 142 143 # kwargs parameter does not alias the **kwargs dict 144 def kwargs(**kwargs): return kwargs 145 x16 = kwargs(**x15) 146 assert.eq(x16, x15) 147 x15["two"] = 2 # mutate 148 assert.ne(x16, x15) 149 150 # iterator invalidation 151 def iterator1(): 152 dict = {1:1, 2:1} 153 for k in dict: 154 dict[2*k] = dict[k] 155 assert.fails(iterator1, "insert.*during iteration") 156 157 def iterator2(): 158 dict = {1:1, 2:1} 159 for k in dict: 160 dict.pop(k) 161 assert.fails(iterator2, "delete.*during iteration") 162 163 def iterator3(): 164 def f(d): 165 d[3] = 3 166 dict = {1:1, 2:1} 167 _ = [f(dict) for x in dict] 168 assert.fails(iterator3, "insert.*during iteration") 169 170 # This assignment is not a modification-during-iteration: 171 # the sequence x should be completely iterated before 172 # the assignment occurs. 173 def f(): 174 x = {1:2, 2:4} 175 a, x[0] = x 176 assert.eq(a, 1) 177 assert.eq(x, {1: 2, 2: 4, 0: 2}) 178 f() 179 180 # Regression test for a bug in hashtable.delete 181 def test_delete(): 182 d = {} 183 184 # delete tail first 185 d["one"] = 1 186 d["two"] = 2 187 assert.eq(str(d), '{"one": 1, "two": 2}') 188 d.pop("two") 189 assert.eq(str(d), '{"one": 1}') 190 d.pop("one") 191 assert.eq(str(d), '{}') 192 193 # delete head first 194 d["one"] = 1 195 d["two"] = 2 196 assert.eq(str(d), '{"one": 1, "two": 2}') 197 d.pop("one") 198 assert.eq(str(d), '{"two": 2}') 199 d.pop("two") 200 assert.eq(str(d), '{}') 201 202 # delete middle 203 d["one"] = 1 204 d["two"] = 2 205 d["three"] = 3 206 assert.eq(str(d), '{"one": 1, "two": 2, "three": 3}') 207 d.pop("two") 208 assert.eq(str(d), '{"one": 1, "three": 3}') 209 d.pop("three") 210 assert.eq(str(d), '{"one": 1}') 211 d.pop("one") 212 assert.eq(str(d), '{}') 213 214 test_delete() 215 216 # Regression test for github.com/google/starlark-go/issues/128. 217 assert.fails(lambda: dict(None), 'got NoneType, want iterable') 218 assert.fails(lambda: {}.update(None), 'got NoneType, want iterable') 219 220 --- 221 # Verify position of an "unhashable key" error in a dict literal. 222 223 _ = { 224 "one": 1, 225 ["two"]: 2, ### "unhashable type: list" 226 "three": 3, 227 } 228 229 --- 230 # Verify position of a "duplicate key" error in a dict literal. 231 232 _ = { 233 "one": 1, 234 "one": 1, ### `duplicate key: "one"` 235 "three": 3, 236 } 237 238 --- 239 # Verify position of an "unhashable key" error in a dict comprehension. 240 241 _ = { 242 k: v ### "unhashable type: list" 243 for k, v in [ 244 ("one", 1), 245 (["two"], 2), 246 ("three", 3), 247 ] 248 } 249 250 251 --- 252 # dict | dict (union) 253 254 load("assert.star", "assert", "freeze") 255 256 empty_dict = dict() 257 dict_with_a_b = dict(a=1, b=[1, 2]) 258 dict_with_b = dict(b=[1, 2]) 259 dict_with_other_b = dict(b=[3, 4]) 260 261 assert.eq(empty_dict | dict_with_a_b, dict_with_a_b) 262 # Verify iteration order. 263 assert.eq((empty_dict | dict_with_a_b).items(), dict_with_a_b.items()) 264 assert.eq(dict_with_a_b | empty_dict, dict_with_a_b) 265 assert.eq((dict_with_a_b | empty_dict).items(), dict_with_a_b.items()) 266 assert.eq(dict_with_b | dict_with_a_b, dict_with_a_b) 267 assert.eq((dict_with_b | dict_with_a_b).items(), dict(b=[1, 2], a=1).items()) 268 assert.eq(dict_with_a_b | dict_with_b, dict_with_a_b) 269 assert.eq((dict_with_a_b | dict_with_b).items(), dict_with_a_b.items()) 270 assert.eq(dict_with_b | dict_with_other_b, dict_with_other_b) 271 assert.eq((dict_with_b | dict_with_other_b).items(), dict_with_other_b.items()) 272 assert.eq(dict_with_other_b | dict_with_b, dict_with_b) 273 assert.eq((dict_with_other_b | dict_with_b).items(), dict_with_b.items()) 274 275 assert.eq(empty_dict, dict()) 276 assert.eq(dict_with_b, dict(b=[1,2])) 277 278 assert.fails(lambda: dict() | [], "unknown binary op: dict [|] list") 279 280 # dict |= dict (in-place union) 281 282 def test_dict_union_assignment(): 283 x = dict() 284 saved = x 285 x |= {"a": 1} 286 x |= {"b": 2} 287 x |= {"c": "3", 7: 4} 288 x |= {"b": "5", "e": 6} 289 want = {"a": 1, "b": "5", "c": "3", 7: 4, "e": 6} 290 assert.eq(x, want) 291 assert.eq(x.items(), want.items()) 292 assert.eq(saved, x) # they are aliases 293 294 a = {8: 1, "b": 2} 295 b = {"b": 1, "c": 6} 296 c = {"d": 7} 297 d = {(5, "a"): ("c", 8)} 298 orig_a, orig_c = a, c 299 a |= b 300 c |= a 301 c |= d 302 expected_2 = {"d": 7, 8: 1, "b": 1, "c": 6, (5, "a"): ("c", 8)} 303 assert.eq(c, expected_2) 304 assert.eq(c.items(), expected_2.items()) 305 assert.eq(b, {"b": 1, "c": 6}) 306 307 # aliasing: 308 assert.eq(a, orig_a) 309 assert.eq(c, orig_c) 310 a.clear() 311 c.clear() 312 assert.eq(a, orig_a) 313 assert.eq(c, orig_c) 314 315 test_dict_union_assignment() 316 317 def dict_union_assignment_type_mismatch(): 318 some_dict = dict() 319 some_dict |= [] 320 321 assert.fails(dict_union_assignment_type_mismatch, "unknown binary op: dict [|] list")