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