go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/starlark/typed/testdata/dict.star (about)

     1  # Copyright 2018 The LUCI Authors.
     2  #
     3  # Licensed under the Apache License, Version 2.0 (the "License");
     4  # you may not use this file except in compliance with the License.
     5  # You may obtain a copy of the License at
     6  #
     7  #      http://www.apache.org/licenses/LICENSE-2.0
     8  #
     9  # Unless required by applicable law or agreed to in writing, software
    10  # distributed under the License is distributed on an "AS IS" BASIS,
    11  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  # See the License for the specific language governing permissions and
    13  # limitations under the License.
    14  
    15  # Helpers.
    16  def key_conv(x):
    17    if type(x) == 'int' and x < 0:
    18      fail('nope')
    19    return str(x)
    20  def val_conv(x):
    21    if type(x) == 'int' and x < 0:
    22      fail('nope')
    23    return str(x)
    24  def typed(d):
    25    return typed_dict(key_conv, val_conv, d)
    26  
    27  
    28  # Typed dict implements same methods as a regular dict. If this test fails, it
    29  # means go.starlark.net added a new dict method that should be added to typed
    30  # dicts as well.
    31  def test_same_dir_as_dict():
    32    assert.eq(dir(typed({})), dir({}))
    33  test_same_dir_as_dict()
    34  
    35  
    36  # Value interface.
    37  def test_basic_value_interface():
    38    assert.eq(str(typed({1: 2})), 'dict<K,V>({"1": "2"})')
    39    assert.eq(type(typed({})), 'dict<K,V>')  # see starlark_test.go for K, V
    40    assert.eq(bool(typed({})), False)
    41    assert.eq(bool(typed({1: 2})), True)
    42  test_basic_value_interface()
    43  
    44  
    45  # Basic dict interface.
    46  def test_dict():
    47    a = typed({1: 2, 3: 4})
    48    assert.eq(dict(a), {'1': '2', '3': '4'})
    49  
    50    # Iteration works.
    51    keys = []
    52    for k in a:
    53      keys.append(k)
    54    assert.eq(keys, ['1', '3'])
    55  
    56    assert.eq(len(a), 2)
    57    assert.eq(bool(a), True)
    58    assert.eq(bool(typed({})), False)
    59  
    60    assert.eq(a['1'], '2')
    61    assert.eq('1' in a, True)
    62    assert.eq(1 in a, False)  # no type coercion
    63  
    64    a['1'] = 6
    65    assert.eq(a['1'], '6')
    66  
    67    def bad_key_type():
    68      a[-1] = '6'
    69    assert.fails(bad_key_type, 'bad key: fail: nope')
    70  
    71    def bad_val_type():
    72      a[1] = -1
    73    assert.fails(bad_val_type, 'bad value: fail: nope')
    74  test_dict()
    75  
    76  
    77  # '==' and '!=' operators.
    78  def test_equality_operators():
    79    assert.true(typed({}) == typed({}))
    80    assert.true(typed({0:1, 2:3}) == typed({0:1, 2:3}))
    81    assert.true(typed({0:1, 2:3}) != typed({0:1}))
    82    assert.true(typed({0:1, 2:3}) != typed({0:1, 9:3}))
    83    assert.true(typed({0:1, 2:3}) != typed({0:1, 2:9}))
    84    # Different key type.
    85    assert.true(typed({0:1}) != typed_dict(lambda x: str(x), val_conv, {0:1}))
    86    # Different value type.
    87    assert.true(typed({0:1}) != typed_dict(key_conv, lambda x: str(x), {0:1}))
    88  test_equality_operators()
    89  
    90  
    91  # 'setdefault' method.
    92  def test_setdefault():
    93    a = typed({1: 2, 3: 4})
    94    assert.eq(a.setdefault(1, 666), '2')
    95    assert.eq(a.setdefault(5, 666), '666')
    96    assert.eq(a['5'], '666')
    97    assert.eq(a.setdefault(6), 'None')
    98    def bad_key_type():
    99      a.setdefault(-1, '6')
   100    assert.fails(bad_key_type, 'bad key: fail: nope')
   101    def bad_val_type():
   102      a.setdefault(1, -1)
   103    assert.fails(bad_val_type, 'bad value: fail: nope')
   104  test_setdefault()
   105  
   106  
   107  # 'update' method.
   108  def test_update():
   109    # Fastest path.
   110    a = typed({1: 2})
   111    a.update(typed({3: 4, 5: 6}))
   112    assert.eq(dict(a), {'1': '2', '3': '4', '5': '6'})
   113  
   114    # Fast path.
   115    a = typed({1: 2})
   116    a.update({3: 4, 5: 6})
   117    assert.eq(dict(a), {'1': '2', '3': '4', '5': '6'})
   118  
   119    # Slow path.
   120    a = typed({1: 2})
   121    a.update([(3, 4), (5, 6)])
   122    assert.eq(dict(a), {'1': '2', '3': '4', '5': '6'})
   123  
   124    # Doesn't accept kwargs.
   125    assert.fails(lambda: a.update(a=1), 'update: got unexpected keyword argument')
   126  
   127    # Needs exactly one positional arg.
   128    assert.fails(lambda: a.update(), 'update: got 0 arguments, want exactly 1')
   129    assert.fails(lambda: a.update({}, {}), 'update: got 2 arguments, want exactly 1')
   130  
   131    # Need an iterable that returns pairs.
   132    assert.fails(lambda: a.update(1), 'update: got int, want iterable')
   133    assert.fails(lambda: a.update([1]), r'update: element #0 is not iterable \(int\)')
   134    assert.fails(lambda: a.update([(1,1,1)]), 'update: element #0 has length 3, want 2')
   135  
   136    # Bad conversion in fast path.
   137    assert.fails(lambda: a.update({-1: 0}), 'update: element #0: bad key: fail: nope')
   138    assert.fails(lambda: a.update({0: -1}), 'update: element #0: bad value: fail: nope')
   139  
   140    # Bad conversion in slow path.
   141    assert.fails(lambda: a.update([(-1, 0)]), 'update: element #0: bad key: fail: nope')
   142    assert.fails(lambda: a.update([(0, -1)]), 'update: element #0: bad value: fail: nope')
   143  test_update()
   144  
   145  
   146  # Other builtins we didn't touch.
   147  def test_builtins():
   148    a = typed({1: 2, 3: 4})
   149  
   150    assert.eq(a.get('1'), '2')
   151    assert.eq(a.get(1), None)  # no type coercion
   152  
   153    assert.eq(a.items(), [('1', '2'), ('3', '4')])
   154    assert.eq(a.keys(), ['1', '3'])
   155    assert.eq(a.values(), ['2', '4'])
   156  
   157    assert.eq(a.pop('1'), '2')
   158    assert.eq(a.pop(3, None), None)  # no type coercion
   159    assert.eq(a.popitem(), ('3', '4'))
   160  
   161    a = typed({1: 2, 3: 4})
   162    a.clear()
   163    assert.eq(len(a), 0)
   164  test_builtins()