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  }