whatcanGOwrong
This commit is contained in:
+321
@@ -0,0 +1,321 @@
|
||||
# Tests of Starlark 'dict'
|
||||
|
||||
load("assert.star", "assert", "freeze")
|
||||
|
||||
# literals
|
||||
assert.eq({}, {})
|
||||
assert.eq({"a": 1}, {"a": 1})
|
||||
assert.eq({"a": 1,}, {"a": 1})
|
||||
|
||||
# truth
|
||||
assert.true({False: False})
|
||||
assert.true(not {})
|
||||
|
||||
# dict + dict is no longer supported.
|
||||
assert.fails(lambda: {"a": 1} + {"b": 2}, 'unknown binary op: dict \\+ dict')
|
||||
|
||||
# dict comprehension
|
||||
assert.eq({x: x*x for x in range(3)}, {0: 0, 1: 1, 2: 4})
|
||||
|
||||
# dict.pop
|
||||
x6 = {"a": 1, "b": 2}
|
||||
assert.eq(x6.pop("a"), 1)
|
||||
assert.eq(str(x6), '{"b": 2}')
|
||||
assert.fails(lambda: x6.pop("c"), "pop: missing key")
|
||||
assert.eq(x6.pop("c", 3), 3)
|
||||
assert.eq(x6.pop("c", None), None) # default=None tests an edge case of UnpackArgs
|
||||
assert.eq(x6.pop("b"), 2)
|
||||
assert.eq(len(x6), 0)
|
||||
|
||||
# dict.popitem
|
||||
x7 = {"a": 1, "b": 2}
|
||||
assert.eq([x7.popitem(), x7.popitem()], [("a", 1), ("b", 2)])
|
||||
assert.fails(x7.popitem, "empty dict")
|
||||
assert.eq(len(x7), 0)
|
||||
|
||||
# dict.keys, dict.values
|
||||
x8 = {"a": 1, "b": 2}
|
||||
assert.eq(x8.keys(), ["a", "b"])
|
||||
assert.eq(x8.values(), [1, 2])
|
||||
|
||||
# equality
|
||||
assert.eq({"a": 1, "b": 2}, {"a": 1, "b": 2})
|
||||
assert.eq({"a": 1, "b": 2,}, {"a": 1, "b": 2})
|
||||
assert.eq({"a": 1, "b": 2}, {"b": 2, "a": 1})
|
||||
|
||||
# insertion order is preserved
|
||||
assert.eq(dict([("a", 0), ("b", 1), ("c", 2), ("b", 3)]).keys(), ["a", "b", "c"])
|
||||
assert.eq(dict([("b", 0), ("a", 1), ("b", 2), ("c", 3)]).keys(), ["b", "a", "c"])
|
||||
assert.eq(dict([("b", 0), ("a", 1), ("b", 2), ("c", 3)])["b"], 2)
|
||||
# ...even after rehashing (which currently occurs after key 'i'):
|
||||
small = dict([("a", 0), ("b", 1), ("c", 2)])
|
||||
small.update([("d", 4), ("e", 5), ("f", 6), ("g", 7), ("h", 8), ("i", 9), ("j", 10), ("k", 11)])
|
||||
assert.eq(small.keys(), ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k"])
|
||||
|
||||
# Duplicate keys are not permitted in dictionary expressions (see b/35698444).
|
||||
# (Nor in keyword args to function calls---checked by resolver.)
|
||||
assert.fails(lambda: {"aa": 1, "bb": 2, "cc": 3, "bb": 4}, 'duplicate key: "bb"')
|
||||
|
||||
# Check that even with many positional args, keyword collisions are detected.
|
||||
assert.fails(lambda: dict({'b': 3}, a=4, **dict(a=5)), 'dict: duplicate keyword arg: "a"')
|
||||
assert.fails(lambda: dict({'a': 2, 'b': 3}, a=4, **dict(a=5)), 'dict: duplicate keyword arg: "a"')
|
||||
# positional/keyword arg key collisions are ok
|
||||
assert.eq(dict((['a', 2], ), a=4), {'a': 4})
|
||||
assert.eq(dict((['a', 2], ['a', 3]), a=4), {'a': 4})
|
||||
|
||||
# index
|
||||
def setIndex(d, k, v):
|
||||
d[k] = v
|
||||
|
||||
x9 = {}
|
||||
assert.fails(lambda: x9["a"], 'key "a" not in dict')
|
||||
x9["a"] = 1
|
||||
assert.eq(x9["a"], 1)
|
||||
assert.eq(x9, {"a": 1})
|
||||
assert.fails(lambda: setIndex(x9, [], 2), 'unhashable type: list')
|
||||
freeze(x9)
|
||||
assert.fails(lambda: setIndex(x9, "a", 3), 'cannot insert into frozen hash table')
|
||||
|
||||
x9a = {}
|
||||
x9a[1, 2] = 3 # unparenthesized tuple is allowed here
|
||||
assert.eq(x9a.keys()[0], (1, 2))
|
||||
|
||||
# dict.get
|
||||
x10 = {"a": 1}
|
||||
assert.eq(x10.get("a"), 1)
|
||||
assert.eq(x10.get("b"), None)
|
||||
assert.eq(x10.get("a", 2), 1)
|
||||
assert.eq(x10.get("b", 2), 2)
|
||||
|
||||
# dict.clear
|
||||
x11 = {"a": 1}
|
||||
assert.contains(x11, "a")
|
||||
assert.eq(x11["a"], 1)
|
||||
x11.clear()
|
||||
assert.fails(lambda: x11["a"], 'key "a" not in dict')
|
||||
assert.true("a" not in x11)
|
||||
freeze(x11)
|
||||
assert.fails(x11.clear, "cannot clear frozen hash table")
|
||||
|
||||
# dict.setdefault
|
||||
x12 = {"a": 1}
|
||||
assert.eq(x12.setdefault("a"), 1)
|
||||
assert.eq(x12["a"], 1)
|
||||
assert.eq(x12.setdefault("b"), None)
|
||||
assert.eq(x12["b"], None)
|
||||
assert.eq(x12.setdefault("c", 2), 2)
|
||||
assert.eq(x12["c"], 2)
|
||||
assert.eq(x12.setdefault("c", 3), 2)
|
||||
assert.eq(x12["c"], 2)
|
||||
freeze(x12)
|
||||
assert.eq(x12.setdefault("a", 1), 1) # no change, no error
|
||||
assert.fails(lambda: x12.setdefault("d", 1), "cannot insert into frozen hash table")
|
||||
|
||||
# dict.update
|
||||
x13 = {"a": 1}
|
||||
x13.update(a=2, b=3)
|
||||
assert.eq(x13, {"a": 2, "b": 3})
|
||||
x13.update([("b", 4), ("c", 5)])
|
||||
assert.eq(x13, {"a": 2, "b": 4, "c": 5})
|
||||
x13.update({"c": 6, "d": 7})
|
||||
assert.eq(x13, {"a": 2, "b": 4, "c": 6, "d": 7})
|
||||
freeze(x13)
|
||||
assert.fails(lambda: x13.update({"a": 8}), "cannot insert into frozen hash table")
|
||||
|
||||
# dict as a sequence
|
||||
#
|
||||
# for loop
|
||||
x14 = {1:2, 3:4}
|
||||
def keys(dict):
|
||||
keys = []
|
||||
for k in dict: keys.append(k)
|
||||
return keys
|
||||
assert.eq(keys(x14), [1, 3])
|
||||
#
|
||||
# comprehension
|
||||
assert.eq([x for x in x14], [1, 3])
|
||||
#
|
||||
# varargs
|
||||
def varargs(*args): return args
|
||||
x15 = {"one": 1}
|
||||
assert.eq(varargs(*x15), ("one",))
|
||||
|
||||
# kwargs parameter does not alias the **kwargs dict
|
||||
def kwargs(**kwargs): return kwargs
|
||||
x16 = kwargs(**x15)
|
||||
assert.eq(x16, x15)
|
||||
x15["two"] = 2 # mutate
|
||||
assert.ne(x16, x15)
|
||||
|
||||
# iterator invalidation
|
||||
def iterator1():
|
||||
dict = {1:1, 2:1}
|
||||
for k in dict:
|
||||
dict[2*k] = dict[k]
|
||||
assert.fails(iterator1, "insert.*during iteration")
|
||||
|
||||
def iterator2():
|
||||
dict = {1:1, 2:1}
|
||||
for k in dict:
|
||||
dict.pop(k)
|
||||
assert.fails(iterator2, "delete.*during iteration")
|
||||
|
||||
def iterator3():
|
||||
def f(d):
|
||||
d[3] = 3
|
||||
dict = {1:1, 2:1}
|
||||
_ = [f(dict) for x in dict]
|
||||
assert.fails(iterator3, "insert.*during iteration")
|
||||
|
||||
# This assignment is not a modification-during-iteration:
|
||||
# the sequence x should be completely iterated before
|
||||
# the assignment occurs.
|
||||
def f():
|
||||
x = {1:2, 2:4}
|
||||
a, x[0] = x
|
||||
assert.eq(a, 1)
|
||||
assert.eq(x, {1: 2, 2: 4, 0: 2})
|
||||
f()
|
||||
|
||||
# Regression test for a bug in hashtable.delete
|
||||
def test_delete():
|
||||
d = {}
|
||||
|
||||
# delete tail first
|
||||
d["one"] = 1
|
||||
d["two"] = 2
|
||||
assert.eq(str(d), '{"one": 1, "two": 2}')
|
||||
d.pop("two")
|
||||
assert.eq(str(d), '{"one": 1}')
|
||||
d.pop("one")
|
||||
assert.eq(str(d), '{}')
|
||||
|
||||
# delete head first
|
||||
d["one"] = 1
|
||||
d["two"] = 2
|
||||
assert.eq(str(d), '{"one": 1, "two": 2}')
|
||||
d.pop("one")
|
||||
assert.eq(str(d), '{"two": 2}')
|
||||
d.pop("two")
|
||||
assert.eq(str(d), '{}')
|
||||
|
||||
# delete middle
|
||||
d["one"] = 1
|
||||
d["two"] = 2
|
||||
d["three"] = 3
|
||||
assert.eq(str(d), '{"one": 1, "two": 2, "three": 3}')
|
||||
d.pop("two")
|
||||
assert.eq(str(d), '{"one": 1, "three": 3}')
|
||||
d.pop("three")
|
||||
assert.eq(str(d), '{"one": 1}')
|
||||
d.pop("one")
|
||||
assert.eq(str(d), '{}')
|
||||
|
||||
test_delete()
|
||||
|
||||
# Regression test for github.com/google/starlark-go/issues/128.
|
||||
assert.fails(lambda: dict(None), 'got NoneType, want iterable')
|
||||
assert.fails(lambda: {}.update(None), 'got NoneType, want iterable')
|
||||
|
||||
---
|
||||
# Verify position of an "unhashable key" error in a dict literal.
|
||||
|
||||
_ = {
|
||||
"one": 1,
|
||||
["two"]: 2, ### "unhashable type: list"
|
||||
"three": 3,
|
||||
}
|
||||
|
||||
---
|
||||
# Verify position of a "duplicate key" error in a dict literal.
|
||||
|
||||
_ = {
|
||||
"one": 1,
|
||||
"one": 1, ### `duplicate key: "one"`
|
||||
"three": 3,
|
||||
}
|
||||
|
||||
---
|
||||
# Verify position of an "unhashable key" error in a dict comprehension.
|
||||
|
||||
_ = {
|
||||
k: v ### "unhashable type: list"
|
||||
for k, v in [
|
||||
("one", 1),
|
||||
(["two"], 2),
|
||||
("three", 3),
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
---
|
||||
# dict | dict (union)
|
||||
|
||||
load("assert.star", "assert", "freeze")
|
||||
|
||||
empty_dict = dict()
|
||||
dict_with_a_b = dict(a=1, b=[1, 2])
|
||||
dict_with_b = dict(b=[1, 2])
|
||||
dict_with_other_b = dict(b=[3, 4])
|
||||
|
||||
assert.eq(empty_dict | dict_with_a_b, dict_with_a_b)
|
||||
# Verify iteration order.
|
||||
assert.eq((empty_dict | dict_with_a_b).items(), dict_with_a_b.items())
|
||||
assert.eq(dict_with_a_b | empty_dict, dict_with_a_b)
|
||||
assert.eq((dict_with_a_b | empty_dict).items(), dict_with_a_b.items())
|
||||
assert.eq(dict_with_b | dict_with_a_b, dict_with_a_b)
|
||||
assert.eq((dict_with_b | dict_with_a_b).items(), dict(b=[1, 2], a=1).items())
|
||||
assert.eq(dict_with_a_b | dict_with_b, dict_with_a_b)
|
||||
assert.eq((dict_with_a_b | dict_with_b).items(), dict_with_a_b.items())
|
||||
assert.eq(dict_with_b | dict_with_other_b, dict_with_other_b)
|
||||
assert.eq((dict_with_b | dict_with_other_b).items(), dict_with_other_b.items())
|
||||
assert.eq(dict_with_other_b | dict_with_b, dict_with_b)
|
||||
assert.eq((dict_with_other_b | dict_with_b).items(), dict_with_b.items())
|
||||
|
||||
assert.eq(empty_dict, dict())
|
||||
assert.eq(dict_with_b, dict(b=[1,2]))
|
||||
|
||||
assert.fails(lambda: dict() | [], "unknown binary op: dict [|] list")
|
||||
|
||||
# dict |= dict (in-place union)
|
||||
|
||||
def test_dict_union_assignment():
|
||||
x = dict()
|
||||
saved = x
|
||||
x |= {"a": 1}
|
||||
x |= {"b": 2}
|
||||
x |= {"c": "3", 7: 4}
|
||||
x |= {"b": "5", "e": 6}
|
||||
want = {"a": 1, "b": "5", "c": "3", 7: 4, "e": 6}
|
||||
assert.eq(x, want)
|
||||
assert.eq(x.items(), want.items())
|
||||
assert.eq(saved, x) # they are aliases
|
||||
|
||||
a = {8: 1, "b": 2}
|
||||
b = {"b": 1, "c": 6}
|
||||
c = {"d": 7}
|
||||
d = {(5, "a"): ("c", 8)}
|
||||
orig_a, orig_c = a, c
|
||||
a |= b
|
||||
c |= a
|
||||
c |= d
|
||||
expected_2 = {"d": 7, 8: 1, "b": 1, "c": 6, (5, "a"): ("c", 8)}
|
||||
assert.eq(c, expected_2)
|
||||
assert.eq(c.items(), expected_2.items())
|
||||
assert.eq(b, {"b": 1, "c": 6})
|
||||
|
||||
# aliasing:
|
||||
assert.eq(a, orig_a)
|
||||
assert.eq(c, orig_c)
|
||||
a.clear()
|
||||
c.clear()
|
||||
assert.eq(a, orig_a)
|
||||
assert.eq(c, orig_c)
|
||||
|
||||
test_dict_union_assignment()
|
||||
|
||||
def dict_union_assignment_type_mismatch():
|
||||
some_dict = dict()
|
||||
some_dict |= []
|
||||
|
||||
assert.fails(dict_union_assignment_type_mismatch, "unknown binary op: dict [|] list")
|
||||
Reference in New Issue
Block a user