go.starlark.net@v0.0.0-20231101134539-556fd59b42f6/starlark/testdata/list.star (about)

     1  # Tests of Starlark 'list'
     2  
     3  load("assert.star", "assert", "freeze")
     4  
     5  # literals
     6  assert.eq([], [])
     7  assert.eq([1], [1])
     8  assert.eq([1], [1])
     9  assert.eq([1, 2], [1, 2])
    10  assert.ne([1, 2, 3], [1, 2, 4])
    11  
    12  # truth
    13  assert.true([0])
    14  assert.true(not [])
    15  
    16  # indexing, x[i]
    17  abc = list("abc".elems())
    18  assert.fails(lambda: abc[-4], "list index -4 out of range \\[-3:2]")
    19  assert.eq(abc[-3], "a")
    20  assert.eq(abc[-2], "b")
    21  assert.eq(abc[-1], "c")
    22  assert.eq(abc[0], "a")
    23  assert.eq(abc[1], "b")
    24  assert.eq(abc[2], "c")
    25  assert.fails(lambda: abc[3], "list index 3 out of range \\[-3:2]")
    26  
    27  # x[i] = ...
    28  x3 = [0, 1, 2]
    29  x3[1] = 2
    30  x3[2] += 3
    31  assert.eq(x3, [0, 2, 5])
    32  
    33  def f2():
    34      x3[3] = 4
    35  
    36  assert.fails(f2, "out of range")
    37  freeze(x3)
    38  
    39  def f3():
    40      x3[0] = 0
    41  
    42  assert.fails(f3, "cannot assign to element of frozen list")
    43  assert.fails(x3.clear, "cannot clear frozen list")
    44  
    45  # list + list
    46  assert.eq([1, 2, 3] + [3, 4, 5], [1, 2, 3, 3, 4, 5])
    47  assert.fails(lambda: [1, 2] + (3, 4), "unknown.*list \\+ tuple")
    48  assert.fails(lambda: (1, 2) + [3, 4], "unknown.*tuple \\+ list")
    49  
    50  # list * int,  int * list
    51  assert.eq(abc * 0, [])
    52  assert.eq(abc * -1, [])
    53  assert.eq(abc * 1, abc)
    54  assert.eq(abc * 3, ["a", "b", "c", "a", "b", "c", "a", "b", "c"])
    55  assert.eq(0 * abc, [])
    56  assert.eq(-1 * abc, [])
    57  assert.eq(1 * abc, abc)
    58  assert.eq(3 * abc, ["a", "b", "c", "a", "b", "c", "a", "b", "c"])
    59  
    60  # list comprehensions
    61  assert.eq([2 * x for x in [1, 2, 3]], [2, 4, 6])
    62  assert.eq([2 * x for x in [1, 2, 3] if x > 1], [4, 6])
    63  assert.eq(
    64      [(x, y) for x in [1, 2] for y in [3, 4]],
    65      [(1, 3), (1, 4), (2, 3), (2, 4)],
    66  )
    67  assert.eq([(x, y) for x in [1, 2] if x == 2 for y in [3, 4]], [(2, 3), (2, 4)])
    68  assert.eq([2 * x for x in (1, 2, 3)], [2, 4, 6])
    69  assert.eq([x for x in "abc".elems()], ["a", "b", "c"])
    70  assert.eq([x for x in {"a": 1, "b": 2}], ["a", "b"])
    71  assert.eq([(y, x) for x, y in {1: 2, 3: 4}.items()], [(2, 1), (4, 3)])
    72  
    73  # corner cases of parsing:
    74  assert.eq([x for x in range(12) if x % 2 == 0 if x % 3 == 0], [0, 6])
    75  assert.eq([x for x in [1, 2] if lambda: None], [1, 2])
    76  assert.eq([x for x in [1, 2] if (lambda: 3 if True else 4)], [1, 2])
    77  
    78  # list function
    79  assert.eq(list(), [])
    80  assert.eq(list("ab".elems()), ["a", "b"])
    81  
    82  # A list comprehension defines a separate lexical block,
    83  # whether at top-level...
    84  a = [1, 2]
    85  b = [a for a in [3, 4]]
    86  assert.eq(a, [1, 2])
    87  assert.eq(b, [3, 4])
    88  
    89  # ...or local to a function.
    90  def listcompblock():
    91      c = [1, 2]
    92      d = [c for c in [3, 4]]
    93      assert.eq(c, [1, 2])
    94      assert.eq(d, [3, 4])
    95  
    96  listcompblock()
    97  
    98  # list.pop
    99  x4 = [1, 2, 3, 4, 5]
   100  assert.fails(lambda: x4.pop(-6), "index -6 out of range \\[-5:4]")
   101  assert.fails(lambda: x4.pop(6), "index 6 out of range \\[-5:4]")
   102  assert.eq(x4.pop(), 5)
   103  assert.eq(x4, [1, 2, 3, 4])
   104  assert.eq(x4.pop(1), 2)
   105  assert.eq(x4, [1, 3, 4])
   106  assert.eq(x4.pop(0), 1)
   107  assert.eq(x4, [3, 4])
   108  assert.eq(x4.pop(-2), 3)
   109  assert.eq(x4, [4])
   110  assert.eq(x4.pop(-1), 4)
   111  assert.eq(x4, [])
   112  
   113  # TODO(adonovan): test uses of list as sequence
   114  # (for loop, comprehension, library functions).
   115  
   116  # x += y for lists is equivalent to x.extend(y).
   117  # y may be a sequence.
   118  # TODO: Test that side-effects of 'x' occur only once.
   119  def list_extend():
   120      a = [1, 2, 3]
   121      b = a
   122      a = a + [4]  # creates a new list
   123      assert.eq(a, [1, 2, 3, 4])
   124      assert.eq(b, [1, 2, 3])  # b is unchanged
   125  
   126      a = [1, 2, 3]
   127      b = a
   128      a += [4]  # updates a (and thus b) in place
   129      assert.eq(a, [1, 2, 3, 4])
   130      assert.eq(b, [1, 2, 3, 4])  # alias observes the change
   131  
   132      a = [1, 2, 3]
   133      b = a
   134      a.extend([4])  # updates existing list
   135      assert.eq(a, [1, 2, 3, 4])
   136      assert.eq(b, [1, 2, 3, 4])  # alias observes the change
   137  
   138  list_extend()
   139  
   140  # Unlike list.extend(iterable), list += iterable makes its LHS name local.
   141  a_list = []
   142  
   143  def f4():
   144      a_list += [1]  # binding use => a_list is a local var
   145  
   146  assert.fails(f4, "local variable a_list referenced before assignment")
   147  
   148  # list += <not iterable>
   149  def f5():
   150      x = []
   151      x += 1
   152  
   153  assert.fails(f5, "unknown binary op: list \\+ int")
   154  
   155  # frozen list += iterable
   156  def f6():
   157      x = []
   158      freeze(x)
   159      x += [1]
   160  
   161  assert.fails(f6, "cannot apply \\+= to frozen list")
   162  
   163  # list += hasfields (hasfields is not iterable but defines list+hasfields)
   164  def f7():
   165      x = []
   166      x += hasfields()
   167      return x
   168  
   169  assert.eq(f7(), 42)  # weird, but exercises a corner case in list+=x.
   170  
   171  # append
   172  x5 = [1, 2, 3]
   173  x5.append(4)
   174  x5.append("abc")
   175  assert.eq(x5, [1, 2, 3, 4, "abc"])
   176  
   177  # extend
   178  x5a = [1, 2, 3]
   179  x5a.extend("abc".elems())  # string
   180  x5a.extend((True, False))  # tuple
   181  assert.eq(x5a, [1, 2, 3, "a", "b", "c", True, False])
   182  
   183  # list.insert
   184  def insert_at(index):
   185      x = list(range(3))
   186      x.insert(index, 42)
   187      return x
   188  
   189  assert.eq(insert_at(-99), [42, 0, 1, 2])
   190  assert.eq(insert_at(-2), [0, 42, 1, 2])
   191  assert.eq(insert_at(-1), [0, 1, 42, 2])
   192  assert.eq(insert_at(0), [42, 0, 1, 2])
   193  assert.eq(insert_at(1), [0, 42, 1, 2])
   194  assert.eq(insert_at(2), [0, 1, 42, 2])
   195  assert.eq(insert_at(3), [0, 1, 2, 42])
   196  assert.eq(insert_at(4), [0, 1, 2, 42])
   197  
   198  # list.remove
   199  def remove(v):
   200      x = [3, 1, 4, 1]
   201      x.remove(v)
   202      return x
   203  
   204  assert.eq(remove(3), [1, 4, 1])
   205  assert.eq(remove(1), [3, 4, 1])
   206  assert.eq(remove(4), [3, 1, 1])
   207  assert.fails(lambda: [3, 1, 4, 1].remove(42), "remove: element not found")
   208  
   209  # list.index
   210  bananas = list("bananas".elems())
   211  assert.eq(bananas.index("a"), 1)  # bAnanas
   212  assert.fails(lambda: bananas.index("d"), "value not in list")
   213  
   214  # start
   215  assert.eq(bananas.index("a", -1000), 1)  # bAnanas
   216  assert.eq(bananas.index("a", 0), 1)  # bAnanas
   217  assert.eq(bananas.index("a", 1), 1)  # bAnanas
   218  assert.eq(bananas.index("a", 2), 3)  # banAnas
   219  assert.eq(bananas.index("a", 3), 3)  # banAnas
   220  assert.eq(bananas.index("b", 0), 0)  # Bananas
   221  assert.eq(bananas.index("n", -3), 4)  # banaNas
   222  assert.fails(lambda: bananas.index("n", -2), "value not in list")
   223  assert.eq(bananas.index("s", -2), 6)  # bananaS
   224  assert.fails(lambda: bananas.index("b", 1), "value not in list")
   225  
   226  # start, end
   227  assert.eq(bananas.index("s", -1000, 7), 6)  # bananaS
   228  assert.fails(lambda: bananas.index("s", -1000, 6), "value not in list")
   229  assert.fails(lambda: bananas.index("d", -1000, 1000), "value not in list")
   230  
   231  # slicing, x[i:j:k]
   232  assert.eq(bananas[6::-2], list("snnb".elems()))
   233  assert.eq(bananas[5::-2], list("aaa".elems()))
   234  assert.eq(bananas[4::-2], list("nnb".elems()))
   235  assert.eq(bananas[99::-2], list("snnb".elems()))
   236  assert.eq(bananas[100::-2], list("snnb".elems()))
   237  # TODO(adonovan): many more tests
   238  
   239  # iterator invalidation
   240  def iterator1():
   241      list = [0, 1, 2]
   242      for x in list:
   243          list[x] = 2 * x
   244      return list
   245  
   246  assert.fails(iterator1, "assign to element.* during iteration")
   247  
   248  def iterator2():
   249      list = [0, 1, 2]
   250      for x in list:
   251          list.remove(x)
   252  
   253  assert.fails(iterator2, "remove.*during iteration")
   254  
   255  def iterator3():
   256      list = [0, 1, 2]
   257      for x in list:
   258          list.append(3)
   259  
   260  assert.fails(iterator3, "append.*during iteration")
   261  
   262  def iterator4():
   263      list = [0, 1, 2]
   264      for x in list:
   265          list.extend([3, 4])
   266  
   267  assert.fails(iterator4, "extend.*during iteration")
   268  
   269  def iterator5():
   270      def f(x):
   271          x.append(4)
   272  
   273      list = [1, 2, 3]
   274      _ = [f(list) for x in list]
   275  
   276  assert.fails(iterator5, "append.*during iteration")