github.com/lab47/exprcore@v0.0.0-20210525052339-fb7d6bd9331e/exprcore/testdata/list.star (about)

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