...

Text file src/go.starlark.net/starlark/testdata/dict.star

Documentation: go.starlark.net/starlark/testdata

     1# Tests of Starlark 'dict'
     2
     3load("assert.star", "assert", "freeze")
     4
     5# literals
     6assert.eq({}, {})
     7assert.eq({"a": 1}, {"a": 1})
     8assert.eq({"a": 1,}, {"a": 1})
     9
    10# truth
    11assert.true({False: False})
    12assert.true(not {})
    13
    14# dict + dict is no longer supported.
    15assert.fails(lambda: {"a": 1} + {"b": 2}, 'unknown binary op: dict \\+ dict')
    16
    17# dict comprehension
    18assert.eq({x: x*x for x in range(3)}, {0: 0, 1: 1, 2: 4})
    19
    20# dict.pop
    21x6 = {"a": 1, "b": 2}
    22assert.eq(x6.pop("a"), 1)
    23assert.eq(str(x6), '{"b": 2}')
    24assert.fails(lambda: x6.pop("c"), "pop: missing key")
    25assert.eq(x6.pop("c", 3), 3)
    26assert.eq(x6.pop("c", None), None) # default=None tests an edge case of UnpackArgs
    27assert.eq(x6.pop("b"), 2)
    28assert.eq(len(x6), 0)
    29
    30# dict.popitem
    31x7 = {"a": 1, "b": 2}
    32assert.eq([x7.popitem(), x7.popitem()], [("a", 1), ("b", 2)])
    33assert.fails(x7.popitem, "empty dict")
    34assert.eq(len(x7), 0)
    35
    36# dict.keys, dict.values
    37x8 = {"a": 1, "b": 2}
    38assert.eq(x8.keys(), ["a", "b"])
    39assert.eq(x8.values(), [1, 2])
    40
    41# equality
    42assert.eq({"a": 1, "b": 2}, {"a": 1, "b": 2})
    43assert.eq({"a": 1, "b": 2,}, {"a": 1, "b": 2})
    44assert.eq({"a": 1, "b": 2}, {"b": 2, "a": 1})
    45
    46# insertion order is preserved
    47assert.eq(dict([("a", 0), ("b", 1), ("c", 2), ("b", 3)]).keys(), ["a", "b", "c"])
    48assert.eq(dict([("b", 0), ("a", 1), ("b", 2), ("c", 3)]).keys(), ["b", "a", "c"])
    49assert.eq(dict([("b", 0), ("a", 1), ("b", 2), ("c", 3)])["b"], 2)
    50# ...even after rehashing (which currently occurs after key 'i'):
    51small = dict([("a", 0), ("b", 1), ("c", 2)])
    52small.update([("d", 4), ("e", 5), ("f", 6), ("g", 7), ("h", 8), ("i", 9), ("j", 10), ("k", 11)])
    53assert.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.)
    57assert.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.
    60assert.fails(lambda: dict({'b': 3}, a=4, **dict(a=5)), 'dict: duplicate keyword arg: "a"')
    61assert.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
    63assert.eq(dict((['a', 2], ), a=4), {'a': 4})
    64assert.eq(dict((['a', 2], ['a', 3]), a=4), {'a': 4})
    65
    66# index
    67def setIndex(d, k, v):
    68  d[k] = v
    69
    70x9 = {}
    71assert.fails(lambda: x9["a"], 'key "a" not in dict')
    72x9["a"] = 1
    73assert.eq(x9["a"], 1)
    74assert.eq(x9, {"a": 1})
    75assert.fails(lambda: setIndex(x9, [], 2), 'unhashable type: list')
    76freeze(x9)
    77assert.fails(lambda: setIndex(x9, "a", 3), 'cannot insert into frozen hash table')
    78
    79x9a = {}
    80x9a[1, 2] = 3  # unparenthesized tuple is allowed here
    81assert.eq(x9a.keys()[0], (1, 2))
    82
    83# dict.get
    84x10 = {"a": 1}
    85assert.eq(x10.get("a"), 1)
    86assert.eq(x10.get("b"), None)
    87assert.eq(x10.get("a", 2), 1)
    88assert.eq(x10.get("b", 2), 2)
    89
    90# dict.clear
    91x11 = {"a": 1}
    92assert.contains(x11, "a")
    93assert.eq(x11["a"], 1)
    94x11.clear()
    95assert.fails(lambda: x11["a"], 'key "a" not in dict')
    96assert.true("a" not in x11)
    97freeze(x11)
    98assert.fails(x11.clear, "cannot clear frozen hash table")
    99
   100# dict.setdefault
   101x12 = {"a": 1}
   102assert.eq(x12.setdefault("a"), 1)
   103assert.eq(x12["a"], 1)
   104assert.eq(x12.setdefault("b"), None)
   105assert.eq(x12["b"], None)
   106assert.eq(x12.setdefault("c", 2), 2)
   107assert.eq(x12["c"], 2)
   108assert.eq(x12.setdefault("c", 3), 2)
   109assert.eq(x12["c"], 2)
   110freeze(x12)
   111assert.eq(x12.setdefault("a", 1), 1) # no change, no error
   112assert.fails(lambda: x12.setdefault("d", 1), "cannot insert into frozen hash table")
   113
   114# dict.update
   115x13 = {"a": 1}
   116x13.update(a=2, b=3)
   117assert.eq(x13, {"a": 2, "b": 3})
   118x13.update([("b", 4), ("c", 5)])
   119assert.eq(x13, {"a": 2, "b": 4, "c": 5})
   120x13.update({"c": 6, "d": 7})
   121assert.eq(x13, {"a": 2, "b": 4, "c": 6, "d": 7})
   122freeze(x13)
   123assert.fails(lambda: x13.update({"a": 8}), "cannot insert into frozen hash table")
   124
   125# dict as a sequence
   126#
   127# for loop
   128x14 = {1:2, 3:4}
   129def keys(dict):
   130  keys = []
   131  for k in dict: keys.append(k)
   132  return keys
   133assert.eq(keys(x14), [1, 3])
   134#
   135# comprehension
   136assert.eq([x for x in x14], [1, 3])
   137#
   138# varargs
   139def varargs(*args): return args
   140x15 = {"one": 1}
   141assert.eq(varargs(*x15), ("one",))
   142
   143# kwargs parameter does not alias the **kwargs dict
   144def kwargs(**kwargs): return kwargs
   145x16 = kwargs(**x15)
   146assert.eq(x16, x15)
   147x15["two"] = 2 # mutate
   148assert.ne(x16, x15)
   149
   150# iterator invalidation
   151def iterator1():
   152  dict = {1:1, 2:1}
   153  for k in dict:
   154    dict[2*k] = dict[k]
   155assert.fails(iterator1, "insert.*during iteration")
   156
   157def iterator2():
   158  dict = {1:1, 2:1}
   159  for k in dict:
   160    dict.pop(k)
   161assert.fails(iterator2, "delete.*during iteration")
   162
   163def iterator3():
   164  def f(d):
   165    d[3] = 3
   166  dict = {1:1, 2:1}
   167  _ = [f(dict) for x in dict]
   168assert.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.
   173def 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})
   178f()
   179
   180# Regression test for a bug in hashtable.delete
   181def 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
   214test_delete()
   215
   216# Regression test for github.com/google/starlark-go/issues/128.
   217assert.fails(lambda: dict(None), 'got NoneType, want iterable')
   218assert.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
   254load("assert.star", "assert", "freeze")
   255
   256empty_dict = dict()
   257dict_with_a_b = dict(a=1, b=[1, 2])
   258dict_with_b = dict(b=[1, 2])
   259dict_with_other_b = dict(b=[3, 4])
   260
   261assert.eq(empty_dict | dict_with_a_b, dict_with_a_b)
   262# Verify iteration order.
   263assert.eq((empty_dict | dict_with_a_b).items(), dict_with_a_b.items())
   264assert.eq(dict_with_a_b | empty_dict, dict_with_a_b)
   265assert.eq((dict_with_a_b | empty_dict).items(), dict_with_a_b.items())
   266assert.eq(dict_with_b | dict_with_a_b, dict_with_a_b)
   267assert.eq((dict_with_b | dict_with_a_b).items(), dict(b=[1, 2], a=1).items())
   268assert.eq(dict_with_a_b | dict_with_b, dict_with_a_b)
   269assert.eq((dict_with_a_b | dict_with_b).items(), dict_with_a_b.items())
   270assert.eq(dict_with_b | dict_with_other_b, dict_with_other_b)
   271assert.eq((dict_with_b | dict_with_other_b).items(), dict_with_other_b.items())
   272assert.eq(dict_with_other_b | dict_with_b, dict_with_b)
   273assert.eq((dict_with_other_b | dict_with_b).items(), dict_with_b.items())
   274
   275assert.eq(empty_dict, dict())
   276assert.eq(dict_with_b, dict(b=[1,2]))
   277
   278assert.fails(lambda: dict() | [], "unknown binary op: dict [|] list")
   279
   280# dict |= dict (in-place union)
   281
   282def 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
   315test_dict_union_assignment()
   316
   317def dict_union_assignment_type_mismatch():
   318    some_dict = dict()
   319    some_dict |= []
   320
   321assert.fails(dict_union_assignment_type_mismatch, "unknown binary op: dict [|] list")

View as plain text