neovim

Neovim text editor
git clone https://git.dasho.dev/neovim.git
Log | Files | Refs | README

test_listdict.vim (49567B)


      1 " Tests for the List and Dict types
      2 scriptencoding utf-8
      3 
      4 source vim9.vim
      5 
      6 func TearDown()
      7  " Run garbage collection after every test
      8  call test_garbagecollect_now()
      9 endfunc
     10 
     11 " Tests for List type
     12 
     13 " List creation
     14 func Test_list_create()
     15  " Creating List directly with different types
     16  let l = [1, 'as''d', [1, 2, function("strlen")], {'a': 1},]
     17  call assert_equal("[1, 'as''d', [1, 2, function('strlen')], {'a': 1}]", string(l))
     18  call assert_equal({'a' : 1}, l[-1])
     19  call assert_equal(1, l[-4])
     20  let x = 10
     21  try
     22    let x = l[-5]
     23  catch
     24    call assert_match('E684:', v:exception)
     25  endtry
     26  call assert_equal(10, x)
     27 endfunc
     28 
     29 " This was allowed in legacy Vim script
     30 let s:list_with_spaces = [1 , 2 , 3]
     31 
     32 " List slices
     33 func Test_list_slice()
     34  let l = [1, 'as''d', [1, 2, function("strlen")], {'a': 1},]
     35  call assert_equal([1, 'as''d', [1, 2, function('strlen')], {'a': 1}], l[:])
     36  call assert_equal(['as''d', [1, 2, function('strlen')], {'a': 1}], l[1:])
     37  call assert_equal([1, 'as''d', [1, 2, function('strlen')]], l[:-2])
     38  call assert_equal([1, 'as''d', [1, 2, function('strlen')], {'a': 1}], l[0:8])
     39  call assert_equal([], l[8:-1])
     40  call assert_equal([], l[0:-10])
     41  " perform an operation on a list slice
     42  let l = [1, 2, 3]
     43  let l[:1] += [1, 2]
     44  let l[2:] -= [1]
     45  call assert_equal([2, 4, 2], l)
     46 
     47  let lines =<< trim END
     48      VAR l = [1, 2]
     49      call assert_equal([1, 2], l[:])
     50      call assert_equal([2], l[-1 : -1])
     51      call assert_equal([1, 2], l[-2 : -1])
     52  END
     53  call CheckLegacyAndVim9Success(lines)
     54 
     55  let l = [1, 2]
     56  call assert_equal([], l[-3 : -1])
     57 
     58  let lines =<< trim END
     59      var l = [1, 2]
     60      assert_equal([1, 2], l[-3 : -1])
     61  END
     62  call CheckDefAndScriptSuccess(lines)
     63 
     64  call assert_fails('let l[[]] = 1', 'E730: Using a List as a String')
     65  call assert_fails('let l[1 : []] = [1]', 'E730: Using a List as a String')
     66 endfunc
     67 
     68 " List identity
     69 func Test_list_identity()
     70  let lines =<< trim END
     71      VAR l = [1, 'as''d', [1, 2, function("strlen")], {'a': 1},]
     72      VAR ll = l
     73      VAR lx = copy(l)
     74      call assert_true(l == ll)
     75      call assert_false(l isnot ll)
     76      call assert_true(l is ll)
     77      call assert_true(l == lx)
     78      call assert_false(l is lx)
     79      call assert_true(l isnot lx)
     80  END
     81  call CheckLegacyAndVim9Success(lines)
     82 endfunc
     83 
     84 " removing items with :unlet
     85 func Test_list_unlet()
     86  let lines =<< trim END
     87      VAR l = [1, 'as''d', [1, 2, function("strlen")], {'a': 1},]
     88      unlet l[2]
     89      call assert_equal([1, 'as''d', {'a': 1}], l)
     90      LET l = range(8)
     91      unlet l[: 3]
     92      unlet l[1 :]
     93      call assert_equal([4], l)
     94 
     95      #" removing items out of range: silently skip items that don't exist
     96      LET l = [0, 1, 2, 3]
     97      unlet l[2 : 2]
     98      call assert_equal([0, 1, 3], l)
     99      LET l = [0, 1, 2, 3]
    100      unlet l[2 : 3]
    101      call assert_equal([0, 1], l)
    102      LET l = [0, 1, 2, 3]
    103      unlet l[2 : 4]
    104      call assert_equal([0, 1], l)
    105      LET l = [0, 1, 2, 3]
    106      unlet l[2 : 5]
    107      call assert_equal([0, 1], l)
    108      LET l = [0, 1, 2, 3]
    109      unlet l[-2 : 2]
    110      call assert_equal([0, 1, 3], l)
    111      LET l = [0, 1, 2, 3]
    112      unlet l[-3 : 2]
    113      call assert_equal([0, 3], l)
    114      LET l = [0, 1, 2, 3]
    115      unlet l[-4 : 2]
    116      call assert_equal([3], l)
    117      LET l = [0, 1, 2, 3]
    118      unlet l[-5 : 2]
    119      call assert_equal([3], l)
    120      LET l = [0, 1, 2, 3]
    121      unlet l[-6 : 2]
    122      call assert_equal([3], l)
    123  END
    124  call CheckLegacyAndVim9Success(lines)
    125 
    126  let l = [0, 1, 2, 3]
    127  unlet l[2:2]
    128  call assert_equal([0, 1, 3], l)
    129  let l = [0, 1, 2, 3]
    130  unlet l[2:3]
    131  call assert_equal([0, 1], l)
    132 
    133  let lines =<< trim END
    134      VAR l = [0, 1, 2, 3]
    135      unlet l[2 : 1]
    136  END
    137  call CheckLegacyAndVim9Failure(lines, 'E684:')
    138 
    139  let lines =<< trim END
    140      VAR l = [0, 1, 2, 3]
    141      unlet l[-1 : 2]
    142  END
    143  call CheckLegacyAndVim9Failure(lines, 'E684:')
    144 endfunc
    145 
    146 " assignment to a list
    147 func Test_list_assign()
    148  let lines =<< trim END
    149      VAR l = [0, 1, 2, 3]
    150      VAR va = 0
    151      VAR vb = 0
    152      LET [va, vb] = l[2 : 3]
    153      call assert_equal([2, 3], [va, vb])
    154  END
    155  call CheckLegacyAndVim9Success(lines)
    156 
    157  let lines =<< trim END
    158      let l = [0, 1, 2, 3]
    159      let [va, vb] = l
    160  END
    161  call CheckScriptFailure(lines, 'E687:')
    162  let lines =<< trim END
    163      var l = [0, 1, 2, 3]
    164      var va = 0
    165      var vb = 0
    166      [va, vb] = l
    167  END
    168  call CheckScriptFailure(['vim9script'] + lines, 'E687:')
    169  call CheckDefExecFailure(lines, 'E1093: Expected 2 items but got 4')
    170 
    171  let lines =<< trim END
    172      let l = [0, 1, 2, 3]
    173      let [va, vb] = l[1:1]
    174  END
    175  call CheckScriptFailure(lines, 'E688:')
    176  let lines =<< trim END
    177      var l = [0, 1, 2, 3]
    178      var va = 0
    179      var vb = 0
    180      [va, vb] = l[1 : 1]
    181  END
    182  call CheckScriptFailure(['vim9script'] + lines, 'E688:')
    183  call CheckDefExecFailure(lines, 'E1093: Expected 2 items but got 1')
    184 
    185  let lines =<< trim END
    186    VAR l = [2]
    187    LET l += v:_null_list
    188    call assert_equal([2], l)
    189    LET l = v:_null_list
    190    LET l += [1]
    191    call assert_equal([1], l)
    192  END
    193  call CheckLegacyAndVim9Success(lines)
    194 
    195  let d = {'abc': [1, 2, 3]}
    196  call assert_fails('let d.abc[0:0z10] = [10, 20]', 'E976: Using a Blob as a String')
    197 endfunc
    198 
    199 " test for range assign
    200 func Test_list_range_assign()
    201  let lines =<< trim END
    202      VAR l = [0]
    203      LET l[:] = [1, 2]
    204      call assert_equal([1, 2], l)
    205      LET l[-4 : -1] = [5, 6]
    206      call assert_equal([5, 6], l)
    207  END
    208  call CheckLegacyAndVim9Success(lines)
    209 
    210  let lines =<< trim END
    211    var l = [7]
    212    l[:] = ['text']
    213  END
    214  call CheckDefAndScriptFailure(lines, 'E1012:', 2)
    215 endfunc
    216 
    217 func Test_list_items()
    218  let r = []
    219  let l = ['a', 'b', 'c']
    220  for [idx, val] in items(l)
    221    call extend(r, [[idx, val]])
    222  endfor
    223  call assert_equal([[0, 'a'], [1, 'b'], [2, 'c']], r)
    224 
    225  call assert_fails('call items(3)', 'E1225:')
    226 endfunc
    227 
    228 func Test_string_items()
    229  let r = []
    230  let s = 'ábツ'
    231  for [idx, val] in items(s)
    232    call extend(r, [[idx, val]])
    233  endfor
    234  call assert_equal([[0, 'á'], [1, 'b'], [2, 'ツ']], r)
    235 endfunc
    236 
    237 " Test removing items in list
    238 func Test_list_func_remove()
    239  let lines =<< trim END
    240      #" Test removing 1 element
    241      VAR l = [1, 2, 3, 4]
    242      call assert_equal(1, remove(l, 0))
    243      call assert_equal([2, 3, 4], l)
    244 
    245      LET l = [1, 2, 3, 4]
    246      call assert_equal(2, remove(l, 1))
    247      call assert_equal([1, 3, 4], l)
    248 
    249      LET l = [1, 2, 3, 4]
    250      call assert_equal(4, remove(l, -1))
    251      call assert_equal([1, 2, 3], l)
    252 
    253      #" Test removing range of element(s)
    254      LET l = [1, 2, 3, 4]
    255      call assert_equal([3], remove(l, 2, 2))
    256      call assert_equal([1, 2, 4], l)
    257 
    258      LET l = [1, 2, 3, 4]
    259      call assert_equal([2, 3], remove(l, 1, 2))
    260      call assert_equal([1, 4], l)
    261 
    262      LET l = [1, 2, 3, 4]
    263      call assert_equal([2, 3], remove(l, -3, -2))
    264      call assert_equal([1, 4], l)
    265  END
    266  call CheckLegacyAndVim9Success(lines)
    267 
    268  " Test invalid cases
    269  let l = [1, 2, 3, 4]
    270  call assert_fails("call remove(l, 5)", 'E684:')
    271  call assert_fails("call remove(l, 1, 5)", 'E684:')
    272  call assert_fails("call remove(l, 3, 2)", 'E16:')
    273  call assert_fails("call remove(1, 0)", 'E896:')
    274  call assert_fails("call remove(l, l)", 'E745:')
    275 endfunc
    276 
    277 " List add() function
    278 func Test_list_add()
    279  let lines =<< trim END
    280      VAR l = []
    281      call add(l, 1)
    282      call add(l, [2, 3])
    283      call add(l, [])
    284      call add(l, v:_null_list)
    285      call add(l, {'k': 3})
    286      call add(l, {})
    287      call add(l, v:_null_dict)
    288      call assert_equal([1, [2, 3], [], [], {'k': 3}, {}, {}], l)
    289  END
    290  call CheckLegacyAndVim9Success(lines)
    291 
    292  " weird legacy behavior
    293  " call assert_equal(1, add(v:_null_list, 4))
    294 endfunc
    295 
    296 " Tests for Dictionary type
    297 
    298 func Test_dict()
    299  " Creating Dictionary directly with different types
    300  let lines =<< trim END
    301      VAR d = {'1': 'asd', 'b': [1, 2, function('strlen')], '-1': {'a': 1}, }
    302      call assert_equal("{'1': 'asd', 'b': [1, 2, function('strlen')], '-1': {'a': 1}}", string(d))
    303      call assert_equal('asd', d.1)
    304      call assert_equal(['-1', '1', 'b'], sort(keys(d)))
    305      call assert_equal(['asd', [1, 2, function('strlen')], {'a': 1}], values(d))
    306      call extend(d, {3: 33, 1: 99})
    307      call extend(d, {'b': 'bbb', 'c': 'ccc'}, "keep")
    308      call assert_equal({'c': 'ccc', '1': 99, 'b': [1, 2, function('strlen')], '3': 33, '-1': {'a': 1}}, d)
    309  END
    310  call CheckLegacyAndVim9Success(lines)
    311 
    312  let d = {001: 'asd', 'b': [1, 2, function('strlen')], -1: {'a': 1},}
    313  call assert_equal("{'1': 'asd', 'b': [1, 2, function('strlen')], '-1': {'a': 1}}", string(d))
    314 
    315  let v = []
    316  for [key, val] in items(d)
    317    call extend(v, [key, val])
    318    unlet key val
    319  endfor
    320  call assert_equal(['1','asd','b',[1, 2, function('strlen')],'-1',{'a': 1}], v)
    321 
    322  call extend(d, {3: 33, 1: 99})
    323  call assert_fails("call extend(d, {3:333,4:444}, 'error')", 'E737:')
    324 
    325  " duplicate key
    326  call assert_fails("let d = {'k' : 10, 'k' : 20}", 'E721:')
    327  " missing comma
    328  call assert_fails("let d = {'k' : 10 'k' : 20}", 'E722:')
    329  " missing curly brace
    330  call assert_fails("let d = {'k' : 10,", 'E723:')
    331  " invalid key
    332  call assert_fails('let d = #{++ : 10}', 'E15:')
    333  " wrong type for key
    334  call assert_fails('let d={[] : 10}', 'E730:')
    335  " undefined variable as value
    336  call assert_fails("let d={'k' : i}", 'E121:')
    337 
    338  " allow key starting with number at the start, not a curly expression
    339  call assert_equal({'1foo': 77}, #{1foo: 77})
    340 
    341  " #{expr} is not a curly expression
    342  let x = 'x'
    343  call assert_equal(#{g: x}, #{g:x})
    344 endfunc
    345 
    346 " This was allowed in legacy Vim script
    347 let s:dict_with_spaces = {'one' : 1 , 'two' : 2 , 'three' : 3}
    348 let s:dict_with_spaces_lit = #{one : 1 , two : 2 , three : 3}
    349 
    350 " Dictionary identity
    351 func Test_dict_identity()
    352  let lines =<< trim END
    353      VAR d = {'1': 'asd', 'b': [1, 2, function('strlen')], -1: {'a': 1}, }
    354      VAR dd = d
    355      VAR dx = copy(d)
    356      call assert_true(d == dd)
    357      call assert_false(d isnot dd)
    358      call assert_true(d is dd)
    359      call assert_true(d == dx)
    360      call assert_false(d is dx)
    361      call assert_true(d isnot dx)
    362  END
    363  call CheckLegacyAndVim9Success(lines)
    364 endfunc
    365 
    366 " removing items with :unlet
    367 func Test_dict_unlet()
    368  let lines =<< trim END
    369      VAR d = {'b': 'bbb', '1': 99, '3': 33, '-1': {'a': 1}}
    370      unlet d.b
    371      unlet d[-1]
    372      call assert_equal({'1': 99, '3': 33}, d)
    373  END
    374  call CheckLegacyAndVim9Success(lines)
    375 endfunc
    376 
    377 " manipulating a big Dictionary (hashtable.c has a border of 1000 entries)
    378 func Test_dict_big()
    379  let d = {}
    380  for i in range(1500)
    381    let d[i] = 3000 - i
    382  endfor
    383  call assert_equal([3000, 2900, 2001, 1600, 1501], [d[0], d[100], d[999], d[1400], d[1499]])
    384  let str = ''
    385  try
    386    let n = d[1500]
    387  catch
    388    let str = substitute(v:exception, '\v(.{14}).*( "\d{4}").*', '\1\2', '')
    389  endtry
    390  call assert_equal('Vim(let):E716: "1500"', str)
    391 
    392  " lookup each item
    393  for i in range(1500)
    394    call assert_equal(3000 - i, d[i])
    395  endfor
    396  let i += 1
    397 
    398  " delete even items
    399  while i >= 2
    400    let i -= 2
    401    unlet d[i]
    402  endwhile
    403  call assert_equal('NONE', get(d, 1500 - 100, 'NONE'))
    404  call assert_equal(2999, d[1])
    405 
    406  " delete odd items, checking value, one intentionally wrong
    407  let d[33] = 999
    408  let i = 1
    409  while i < 1500
    410   if i != 33
    411     call assert_equal(3000 - i, d[i])
    412   else
    413     call assert_equal(999, d[i])
    414   endif
    415   unlet d[i]
    416   let i += 2
    417  endwhile
    418  call assert_equal({}, d)
    419  unlet d
    420 endfunc
    421 
    422 " Dictionary function
    423 func Test_dict_func()
    424  let d = {}
    425  func d.func(a) dict
    426    return a:a . len(self.data)
    427  endfunc
    428  let d.data = [1,2,3]
    429  call assert_equal('len: 3', d.func('len: '))
    430  let x = d.func('again: ')
    431  call assert_equal('again: 3', x)
    432  let Fn = d.func
    433  call assert_equal('xxx3', Fn('xxx'))
    434 endfunc
    435 
    436 func Test_dict_assign()
    437  let d = {}
    438  let d.1 = 1
    439  let d._ = 2
    440  call assert_equal({'1': 1, '_': 2}, d)
    441 
    442  let lines =<< trim END
    443      VAR d = {}
    444      LET d.a = 1
    445      LET d._ = 2
    446      call assert_equal({'a': 1, '_': 2}, d)
    447  END
    448  call CheckLegacyAndVim9Success(lines)
    449 
    450  let lines =<< trim END
    451    let n = 0
    452    let n.key = 3
    453  END
    454  call CheckScriptFailure(lines, 'E1203: Dot can only be used on a dictionary: n.key = 3')
    455  let lines =<< trim END
    456    vim9script
    457    var n = 0
    458    n.key = 3
    459  END
    460  call CheckScriptFailure(lines, 'E1203: Dot can only be used on a dictionary: n.key = 3')
    461  let lines =<< trim END
    462    var n = 0
    463    n.key = 3
    464  END
    465  call CheckDefFailure(lines, 'E1141:')
    466 
    467  let d = {'abc': {}}
    468  call assert_fails("let d.abc[0z10] = 10", 'E976: Using a Blob as a String')
    469 endfunc
    470 
    471 " Function in script-local List or Dict
    472 func Test_script_local_dict_func()
    473  let g:dict = {}
    474  function g:dict.func() dict
    475    return 'g:dict.func' . self.foo[1] . self.foo[0]('asdf')
    476  endfunc
    477  let g:dict.foo = ['-', 2, 3]
    478  call insert(g:dict.foo, function('strlen'))
    479  call assert_equal('g:dict.func-4', g:dict.func())
    480  unlet g:dict
    481 endfunc
    482 
    483 " Test removing items in a dictionary
    484 func Test_dict_func_remove()
    485  let lines =<< trim END
    486      VAR d = {1: 'a', 2: 'b', 3: 'c'}
    487      call assert_equal('b', remove(d, 2))
    488      call assert_equal({1: 'a', 3: 'c'}, d)
    489  END
    490  call CheckLegacyAndVim9Success(lines)
    491 
    492  let lines =<< trim END
    493      VAR d = {1: 'a', 3: 'c'}
    494      call remove(d, 1, 2)
    495  END
    496  call CheckLegacyAndVim9Failure(lines, 'E118:')
    497 
    498  let lines =<< trim END
    499      VAR d = {1: 'a', 3: 'c'}
    500      call remove(d, 'a')
    501  END
    502  call CheckLegacyAndVim9Failure(lines, 'E716:')
    503 
    504  let lines =<< trim END
    505      let d = {'a-b': 55}
    506      echo d.a-b
    507  END
    508  call CheckScriptFailure(lines, 'E716: Key not present in Dictionary: "a"')
    509 
    510  let lines =<< trim END
    511      vim9script
    512      var d = {'a-b': 55}
    513      echo d.a-b
    514  END
    515  call CheckScriptFailure(lines, 'E716: Key not present in Dictionary: "a"')
    516 
    517  let lines =<< trim END
    518      var d = {'a-b': 55}
    519      echo d.a-b
    520  END
    521  call CheckDefFailure(lines, 'E1004: White space required before and after ''-''')
    522 
    523  let lines =<< trim END
    524      let d = {1: 'a', 3: 'c'}
    525      call remove(d, [])
    526  END
    527  call CheckScriptFailure(lines, 'E730:')
    528  let lines =<< trim END
    529      vim9script
    530      var d = {1: 'a', 3: 'c'}
    531      call remove(d, [])
    532  END
    533  call CheckScriptFailure(lines, 'E1174: String required for argument 2')
    534  let lines =<< trim END
    535      var d = {1: 'a', 3: 'c'}
    536      call remove(d, [])
    537  END
    538  call CheckDefExecFailure(lines, 'E1013: Argument 2: type mismatch, expected string but got list<unknown>')
    539 endfunc
    540 
    541 " Nasty: remove func from Dict that's being called (works)
    542 func Test_dict_func_remove_in_use()
    543  let d = {1:1}
    544  func d.func(a)
    545    return "a:" . a:a
    546  endfunc
    547  let expected = 'a:' . string(get(d, 'func'))
    548  call assert_equal(expected, d.func(string(remove(d, 'func'))))
    549 
    550  " similar, in a way it also works in Vim9
    551  let lines =<< trim END
    552      VAR d = {1: 1, 2: 'x'}
    553      func GetArg(a)
    554        return "a:" .. a:a
    555      endfunc
    556      LET d.func = function('GetArg')
    557      VAR expected = 'a:' .. string(get(d, 'func'))
    558      call assert_equal(expected, d.func(string(remove(d, 'func'))))
    559  END
    560  call CheckTransLegacySuccess(lines)
    561  call CheckTransVim9Success(lines)
    562 endfunc
    563 
    564 func Test_dict_literal_keys()
    565  call assert_equal({'one': 1, 'two2': 2, '3three': 3, '44': 4}, #{one: 1, two2: 2, 3three: 3, 44: 4},)
    566 
    567  " why *{} cannot be used for a literal dictionary
    568  let blue = 'blue'
    569  call assert_equal('6', trim(execute('echo 2 *{blue: 3}.blue')))
    570 
    571  call assert_fails('eval 1 || #{a:', 'E15:') " used to leak
    572 endfunc
    573 
    574 " Nasty: deepcopy() dict that refers to itself (fails when noref used)
    575 func Test_dict_deepcopy()
    576  let lines =<< trim END
    577      VAR d = {1: 1, 2: '2'}
    578      VAR l = [4, d, 6]
    579      LET d[3] = l
    580      VAR dc = deepcopy(d)
    581      call deepcopy(d, 1)
    582  END
    583  call CheckLegacyAndVim9Failure(lines, 'E698:')
    584 
    585  let lines =<< trim END
    586      VAR d = {1: 1, 2: '2'}
    587      VAR l = [4, d, 6]
    588      LET d[3] = l
    589      VAR l2 = [0, l, l, 3]
    590      LET l[1] = l2
    591      VAR l3 = deepcopy(l2)
    592      call assert_true(l3[1] is l3[2])
    593  END
    594  call CheckLegacyAndVim9Success(lines)
    595 
    596  call assert_fails("call deepcopy([1, 2], 2)", 'E1212:')
    597 endfunc
    598 
    599 " Locked variables
    600 func Test_list_locked_var()
    601  " Not tested with :def function, local vars cannot be locked.
    602  let lines =<< trim END
    603      VAR expected = [
    604                  \ [['1000-000', 'ppppppF'],
    605                  \  ['0000-000', 'ppppppp'],
    606                  \  ['0000-000', 'ppppppp']],
    607                  \ [['1000-000', 'ppppppF'],
    608                  \  ['0000-000', 'ppppppp'],
    609                  \  ['0000-000', 'ppppppp']],
    610                  \ [['1100-100', 'ppFppFF'],
    611                  \  ['0000-000', 'ppppppp'],
    612                  \  ['0000-000', 'ppppppp']],
    613                  \ [['1110-110', 'pFFpFFF'],
    614                  \  ['0010-010', 'pFppFpp'],
    615                  \  ['0000-000', 'ppppppp']],
    616                  \ [['1111-111', 'FFFFFFF'],
    617                  \  ['0011-011', 'FFpFFpp'],
    618                  \  ['0000-000', 'ppppppp']]
    619                  \ ]
    620      for depth in range(5)
    621        for u in range(3)
    622          VAR l = [0, [1, [2, 3]], {4: 5, 6: {7: 8}}]
    623          exe "lockvar " .. depth .. " l"
    624          if u == 1
    625            exe "unlockvar l"
    626          elseif u == 2
    627            exe "unlockvar " .. depth .. " l"
    628          endif
    629          VAR ps = islocked("l") .. islocked("l[1]") .. islocked("l[1][1]") .. islocked("l[1][1][0]") .. '-' .. islocked("l[2]") .. islocked("l[2]['6']") .. islocked("l[2]['6'][7]")
    630          call assert_equal(expected[depth][u][0], ps, 'depth: ' .. depth)
    631          LET ps = ''
    632          try
    633            LET l[1][1][0] = 99
    634            LET ps ..= 'p'
    635          catch
    636            LET ps ..= 'F'
    637          endtry
    638          try
    639            LET l[1][1] = [99]
    640            LET ps ..= 'p'
    641          catch
    642            LET ps ..= 'F'
    643          endtry
    644          try
    645            LET l[1] = [99]
    646            LET ps ..= 'p'
    647          catch
    648            LET ps ..= 'F'
    649          endtry
    650          try
    651            LET l[2]['6'][7] = 99
    652            LET ps ..= 'p'
    653          catch
    654            LET ps ..= 'F'
    655          endtry
    656          try
    657            LET l[2][6] = {99: 99}
    658            LET ps ..= 'p'
    659          catch
    660            LET ps ..= 'F'
    661          endtry
    662          try
    663            LET l[2] = {99: 99}
    664            LET ps ..= 'p'
    665          catch
    666            LET ps ..= 'F'
    667          endtry
    668          try
    669            LET l = [99]
    670            LET ps ..= 'p'
    671          catch
    672            LET ps ..= 'F'
    673          endtry
    674          call assert_equal(expected[depth][u][1], ps, 'depth: ' .. depth)
    675          unlock! l
    676        endfor
    677      endfor
    678  END
    679  call CheckTransLegacySuccess(lines)
    680  call CheckTransVim9Success(lines)
    681 
    682  call assert_fails("let x=islocked('a b')", 'E488:')
    683  let mylist = [1, 2, 3]
    684  call assert_fails("let x = islocked('mylist[1:2]')", 'E786:')
    685  let mydict = {'k' : 'v'}
    686  call assert_fails("let x = islocked('mydict.a')", 'E716:')
    687 endfunc
    688 
    689 " Unletting locked variables
    690 func Test_list_locked_var_unlet()
    691  " Not tested with Vim9: script and local variables cannot be unlocked
    692  let expected = [
    693       \ [['1000-000', 'ppppppp'],
    694       \  ['0000-000', 'ppppppp'],
    695       \  ['0000-000', 'ppppppp']],
    696       \ [['1000-000', 'ppFppFp'],
    697       \  ['0000-000', 'ppppppp'],
    698       \  ['0000-000', 'ppppppp']],
    699       \ [['1100-100', 'pFFpFFp'],
    700       \  ['0000-000', 'ppppppp'],
    701       \  ['0000-000', 'ppppppp']],
    702       \ [['1110-110', 'FFFFFFp'],
    703       \  ['0010-010', 'FppFppp'],
    704       \  ['0000-000', 'ppppppp']],
    705       \ [['1111-111', 'FFFFFFp'],
    706       \  ['0011-011', 'FppFppp'],
    707       \  ['0000-000', 'ppppppp']]
    708       \ ]
    709 
    710  for depth in range(5)
    711    for u in range(3)
    712      unlet! l
    713      let l = [0, [1, [2, 3]], {4: 5, 6: {7: 8}}]
    714      exe "lockvar " . depth . " l"
    715      if u == 1
    716        exe "unlockvar l"
    717      elseif u == 2
    718        exe "unlockvar " . depth . " l"
    719      endif
    720      let ps = islocked("l").islocked("l[1]").islocked("l[1][1]").islocked("l[1][1][0]").'-'.islocked("l[2]").islocked("l[2]['6']").islocked("l[2]['6'][7]")
    721      call assert_equal(expected[depth][u][0], ps, 'depth: ' .. depth)
    722      let ps = ''
    723      try
    724        unlet l[2]['6'][7]
    725        let ps .= 'p'
    726      catch
    727        let ps .= 'F'
    728      endtry
    729      try
    730        unlet l[2][6]
    731        let ps .= 'p'
    732      catch
    733        let ps .= 'F'
    734      endtry
    735      try
    736        unlet l[2]
    737        let ps .= 'p'
    738      catch
    739        let ps .= 'F'
    740      endtry
    741      try
    742        unlet l[1][1][0]
    743        let ps .= 'p'
    744      catch
    745        let ps .= 'F'
    746      endtry
    747      try
    748        unlet l[1][1]
    749        let ps .= 'p'
    750      catch
    751        let ps .= 'F'
    752      endtry
    753      try
    754        unlet l[1]
    755        let ps .= 'p'
    756      catch
    757        let ps .= 'F'
    758      endtry
    759      try
    760        unlet l
    761        let ps .= 'p'
    762      catch
    763        let ps .= 'F'
    764      endtry
    765      call assert_equal(expected[depth][u][1], ps)
    766    endfor
    767  endfor
    768 
    769  " Deleting a list range with locked items works, but changing the items
    770  " fails.
    771  let l = [1, 2, 3, 4]
    772  lockvar l[1:2]
    773  call assert_fails('let l[1:2] = [8, 9]', 'E741:')
    774  unlet l[1:2]
    775  call assert_equal([1, 4], l)
    776  unlet l
    777 endfunc
    778 
    779 " Locked variables and :unlet or list / dict functions
    780 
    781 " No :unlet after lock on dict:
    782 func Test_dict_lock_unlet()
    783  let d = {'a': 99, 'b': 100}
    784  lockvar 1 d
    785  call assert_fails('unlet d.a', 'E741:')
    786 endfunc
    787 
    788 " unlet after lock on dict item
    789 func Test_dict_item_lock_unlet()
    790  let lines =<< trim END
    791      VAR d = {'a': 99, 'b': 100}
    792      lockvar d.a
    793      unlet d.a
    794      call assert_equal({'b': 100}, d)
    795  END
    796  call CheckLegacyAndVim9Success(lines)
    797 endfunc
    798 
    799 " filter() after lock on dict item
    800 func Test_dict_lock_filter()
    801  let lines =<< trim END
    802      VAR d = {'a': 99, 'b': 100}
    803      lockvar d.a
    804      call filter(d, 'v:key != "a"')
    805      call assert_equal({'b': 100}, d)
    806  END
    807  call CheckLegacyAndVim9Success(lines)
    808 endfunc
    809 
    810 " map() after lock on dict
    811 func Test_dict_lock_map()
    812  let lines =<< trim END
    813      VAR d = {'a': 99, 'b': 100}
    814      lockvar 1 d
    815      call map(d, 'v:val + 200')
    816      call assert_equal({'a': 299, 'b': 300}, d)
    817  END
    818  " This won't work in a :def function
    819  call CheckTransLegacySuccess(lines)
    820  call CheckTransVim9Success(lines)
    821 
    822  " For a :def function use a global dict.
    823  let lines =<< trim END
    824      let g:thedict = {'a': 77, 'b': 88}
    825      lockvar 1 g:thedict
    826      def Delkey()
    827        unlet g:thedict.a
    828      enddef
    829      call Delkey()
    830  END
    831  " call CheckScriptFailure(lines, 'E741:')
    832 endfunc
    833 
    834 " No extend() after lock on dict item
    835 func Test_dict_lock_extend()
    836  let d = {'a': 99, 'b': 100}
    837  lockvar d.a
    838  call assert_fails("call extend(d, {'a' : 123})", 'E741:')
    839  call assert_equal({'a': 99, 'b': 100}, d)
    840 endfunc
    841 
    842 " Cannot use += with a locked dict
    843 func Test_dict_lock_operator()
    844  let d = {}
    845  lockvar d
    846  call assert_fails("let d += {'k' : 10}", 'E741:')
    847  unlockvar d
    848 endfunc
    849 
    850 " No remove() of write-protected scope-level variable
    851 func Tfunc1(this_is_a_long_parameter_name)
    852  call assert_fails("call remove(a:, 'this_is_a_long_parameter_name')", 'E742:')
    853 endfunc
    854 func Test_dict_scope_var_remove()
    855  call Tfunc1('testval')
    856 endfunc
    857 
    858 " No extend() of write-protected scope-level variable
    859 func Test_dict_scope_var_extend()
    860  call assert_fails("call extend(a:, {'this_is_a_long_parameter_name': 1234})", 'E742:')
    861 endfunc
    862 func Tfunc2(this_is_a_long_parameter_name)
    863  call assert_fails("call extend(a:, {'this_is_a_long_parameter_name': 1234})", 'E742:')
    864 endfunc
    865 func Test_dict_scope_var_extend_overwrite()
    866  call Tfunc2('testval')
    867 endfunc
    868 
    869 " No :unlet of variable in locked scope
    870 func Test_lock_var_unlet()
    871  let b:testvar = 123
    872  lockvar 1 b:
    873  call assert_fails('unlet b:testvar', 'E741:')
    874  unlockvar 1 b:
    875  unlet! b:testvar
    876 endfunc
    877 
    878 " No :let += of locked list variable
    879 func Test_let_lock_list()
    880  let l = ['a', 'b', 3]
    881  lockvar 1 l
    882  call assert_fails("let l += ['x']", 'E741:')
    883  call assert_equal(['a', 'b', 3], l)
    884 
    885  unlet l
    886  let l = [1, 2, 3, 4]
    887  lockvar! l
    888  call assert_equal([1, 2, 3, 4], l)
    889  unlockvar l[1]
    890  call assert_fails('unlet l[0:1]', 'E741:')
    891  call assert_equal([1, 2, 3, 4], l)
    892  call assert_fails('unlet l[1:2]', 'E741:')
    893  call assert_equal([1, 2, 3, 4], l)
    894  unlockvar l[1]
    895  call assert_fails('let l[0:1] = [0, 1]', 'E741:')
    896  call assert_equal([1, 2, 3, 4], l)
    897  call assert_fails('let l[1:2] = [0, 1]', 'E741:')
    898  call assert_equal([1, 2, 3, 4], l)
    899  unlet l
    900 endfunc
    901 
    902 " Locking part of the list
    903 func Test_let_lock_list_items()
    904  let l = [1, 2, 3, 4]
    905  lockvar l[2:]
    906  call assert_equal(0, islocked('l[0]'))
    907  call assert_equal(1, islocked('l[2]'))
    908  call assert_equal(1, islocked('l[3]'))
    909  call assert_fails('let l[2] = 10', 'E741:')
    910  call assert_fails('let l[3] = 20', 'E741:')
    911  unlet l
    912 endfunc
    913 
    914 " lockvar/islocked() triggering script autoloading
    915 func Test_lockvar_script_autoload()
    916  let old_rtp = &rtp
    917  set rtp+=./sautest
    918  lockvar g:footest#x
    919  unlockvar g:footest#x
    920  call assert_equal(-1, 'g:footest#x'->islocked())
    921  call assert_equal(0, exists('g:footest#x'))
    922  call assert_equal(1, g:footest#x)
    923  let &rtp = old_rtp
    924 endfunc
    925 
    926 " a:000 function argument test
    927 func s:arg_list_test(...)
    928  call assert_fails('let a:000 = [1, 2]', 'E46:')
    929  call assert_fails('let a:000[0] = 9', 'E742:')
    930  call assert_fails('let a:000[2] = [9, 10]', 'E742:')
    931  call assert_fails('let a:000[3] = {9 : 10}', 'E742:')
    932 
    933  " now the tests that should pass
    934  let a:000[2][1] = 9
    935  call extend(a:000[2], [5, 6])
    936  let a:000[3][5] = 8
    937  let a:000[3]['a'] = 12
    938  call assert_equal([1, 2, [3, 9, 5, 6], {'a': 12, '5': 8}], a:000)
    939 endfunc
    940 
    941 func Test_func_arg_list()
    942  call s:arg_list_test(1, 2, [3, 4], {5: 6})
    943 endfunc
    944 
    945 " Tests for reverse(), sort(), uniq()
    946 func Test_reverse_sort_uniq()
    947  let lines =<< trim END
    948      VAR l = ['-0', 'A11', 2, 2, 'xaaa', 4, 'foo', 'foo6', 'foo', [0, 1, 2], 'x8', [0, 1, 2], 1.5]
    949      call assert_equal(['-0', 'A11', 2, 'xaaa', 4, 'foo', 'foo6', 'foo', [0, 1, 2], 'x8', [0, 1, 2], 1.5], uniq(copy(l)))
    950      call assert_equal([1.5, [0, 1, 2], 'x8', [0, 1, 2], 'foo', 'foo6', 'foo', 4, 'xaaa', 2, 2, 'A11', '-0'], reverse(l))
    951      call assert_equal([1.5, [0, 1, 2], 'x8', [0, 1, 2], 'foo', 'foo6', 'foo', 4, 'xaaa', 2, 2, 'A11', '-0'], reverse(reverse(l)))
    952      if has('float')
    953        call assert_equal(['-0', 'A11', 'foo', 'foo', 'foo6', 'x8', 'xaaa', 1.5, 2, 2, 4, [0, 1, 2], [0, 1, 2]], sort(l))
    954        call assert_equal([[0, 1, 2], [0, 1, 2], 4, 2, 2, 1.5, 'xaaa', 'x8', 'foo6', 'foo', 'foo', 'A11', '-0'], reverse(sort(l)))
    955        call assert_equal(['-0', 'A11', 'foo', 'foo', 'foo6', 'x8', 'xaaa', 1.5, 2, 2, 4, [0, 1, 2], [0, 1, 2]], sort(reverse(sort(l))))
    956        call assert_equal(['-0', 'A11', 'foo', 'foo6', 'x8', 'xaaa', 1.5, 2, 4, [0, 1, 2]], uniq(sort(l)))
    957 
    958        LET l = [7, 9, 'one', 18, 12, 22, 'two', 10.0e-16, -1, 'three', 0xff, 0.22, 'four']
    959        call assert_equal([-1, 'one', 'two', 'three', 'four', 1.0e-15, 0.22, 7, 9, 12, 18, 22, 255], sort(copy(l), 'n'))
    960 
    961        LET l = [7, 9, 18, 12, 22, 10.0e-16, -1, 0xff, 0, -0, 0.22, 'bar', 'BAR', 'Bar', 'Foo', 'FOO', 'foo', 'FOOBAR', {}, []]
    962        call assert_equal(['bar', 'BAR', 'Bar', 'Foo', 'FOO', 'foo', 'FOOBAR', -1, 0, 0, 0.22, 1.0e-15, 12, 18, 22, 255, 7, 9, [], {}], sort(copy(l), 'i'))
    963        call assert_equal(['bar', 'BAR', 'Bar', 'Foo', 'FOO', 'foo', 'FOOBAR', -1, 0, 0, 0.22, 1.0e-15, 12, 18, 22, 255, 7, 9, [], {}], sort(copy(l), 'i'))
    964        call assert_equal(['BAR', 'Bar', 'FOO', 'FOOBAR', 'Foo', 'bar', 'foo', -1, 0, 0, 0.22, 1.0e-15, 12, 18, 22, 255, 7, 9, [], {}], sort(copy(l)))
    965      endif
    966  END
    967  call CheckLegacyAndVim9Success(lines)
    968 
    969  call assert_fails('call reverse({})', 'E1252:')
    970  call assert_fails('call uniq([1, 2], {x, y -> []})', 'E745:')
    971  call assert_fails("call sort([1, 2], function('min'), 1)", "E1206:")
    972  call assert_fails("call sort([1, 2], function('invalid_func'))", "E700:")
    973  call assert_fails("call sort([1, 2], function('min'))", "E118:")
    974 
    975  let lines =<< trim END
    976    call sort(['a', 'b'], 0)
    977  END
    978  call CheckDefAndScriptFailure(lines, 'E1256: String or function required for argument 2')
    979 
    980  let lines =<< trim END
    981    call sort(['a', 'b'], 1)
    982  END
    983  call CheckDefAndScriptFailure(lines, 'E1256: String or function required for argument 2')
    984 endfunc
    985 
    986 " reduce a list, blob or string
    987 func Test_reduce()
    988  let lines =<< trim END
    989      call assert_equal(1, reduce([], LSTART acc, val LMIDDLE acc + val LEND, 1))
    990      call assert_equal(10, reduce([1, 3, 5], LSTART acc, val LMIDDLE acc + val LEND, 1))
    991      call assert_equal(2 * (2 * ((2 * 1) + 2) + 3) + 4, reduce([2, 3, 4], LSTART acc, val LMIDDLE 2 * acc + val LEND, 1))
    992      call assert_equal('a x y z', ['x', 'y', 'z']->reduce(LSTART acc, val LMIDDLE acc .. ' ' .. val LEND, 'a'))
    993      call assert_equal([0, 1, 2, 3], reduce([1, 2, 3], function('add'), [0]))
    994 
    995      VAR l = ['x', 'y', 'z']
    996      call assert_equal(42, reduce(l, function('get'), {'x': {'y': {'z': 42 } } }))
    997      call assert_equal(['x', 'y', 'z'], l)
    998 
    999      call assert_equal(1, reduce([1], LSTART acc, val LMIDDLE acc + val LEND))
   1000      call assert_equal('x y z', reduce(['x', 'y', 'z'], LSTART acc, val LMIDDLE acc .. ' ' .. val LEND))
   1001      call assert_equal(120, range(1, 5)->reduce(LSTART acc, val LMIDDLE acc * val LEND))
   1002 
   1003      call assert_equal(1, reduce(0z, LSTART acc, val LMIDDLE acc + val LEND, 1))
   1004      call assert_equal(1 + 0xaf + 0xbf + 0xcf, reduce(0zAFBFCF, LSTART acc, val LMIDDLE acc + val LEND, 1))
   1005      call assert_equal(2 * (2 * 1 + 0xaf) + 0xbf, 0zAFBF->reduce(LSTART acc, val LMIDDLE 2 * acc + val LEND, 1))
   1006 
   1007      call assert_equal(0xff, reduce(0zff, LSTART acc, val LMIDDLE acc + val LEND))
   1008      call assert_equal(2 * (2 * 0xaf + 0xbf) + 0xcf, reduce(0zAFBFCF, LSTART acc, val LMIDDLE 2 * acc + val LEND))
   1009 
   1010      call assert_equal('x,y,z', 'xyz'->reduce(LSTART acc, val LMIDDLE acc .. ',' .. val LEND))
   1011      call assert_equal('', ''->reduce(LSTART acc, val LMIDDLE acc .. ',' .. val LEND, ''))
   1012      call assert_equal('あ,い,う,え,お,😊,💕', 'あいうえお😊💕'->reduce(LSTART acc, val LMIDDLE acc .. ',' .. val LEND))
   1013      call assert_equal('😊,あ,い,う,え,お,💕', 'あいうえお💕'->reduce(LSTART acc, val LMIDDLE acc .. ',' .. val LEND, '😊'))
   1014      call assert_equal('ऊ,ॠ,ॡ', reduce('ऊॠॡ', LSTART acc, val LMIDDLE acc .. ',' .. val LEND))
   1015      call assert_equal('c,à,t', reduce('càt', LSTART acc, val LMIDDLE acc .. ',' .. val LEND))
   1016      call assert_equal('Å,s,t,r,ö,m', reduce('Åström', LSTART acc, val LMIDDLE acc .. ',' .. val LEND))
   1017      call assert_equal('Å,s,t,r,ö,m', reduce('Åström', LSTART acc, val LMIDDLE acc .. ',' .. val LEND))
   1018      call assert_equal(',a,b,c', reduce('abc', LSTART acc, val LMIDDLE acc .. ',' .. val LEND, v:_null_string))
   1019 
   1020      call assert_equal(0x7d, reduce([0x30, 0x25, 0x08, 0x61], 'or'))
   1021      call assert_equal(0x7d, reduce(0z30250861, 'or'))
   1022      call assert_equal('β', reduce('ββββ', 'matchstr'))
   1023  END
   1024  call CheckLegacyAndVim9Success(lines)
   1025 
   1026  call assert_equal({'x': 1, 'y': 1, 'z': 1 }, ['x', 'y', 'z']->reduce({ acc, val -> extend(acc, { val: 1 }) }, {}))
   1027  " vim9 assert_equal({'x': 1, 'y': 1, 'z': 1 }, ['x', 'y', 'z']->reduce((acc, val) => extend(acc, {[val]: 1 }), {}))
   1028 
   1029  call assert_fails("call reduce([], { acc, val -> acc + val })", 'E998: Reduce of an empty List with no initial value')
   1030  call assert_fails("call reduce(0z, { acc, val -> acc + val })", 'E998: Reduce of an empty Blob with no initial value')
   1031  call assert_fails("call reduce(v:_null_blob, { acc, val -> acc + val })", 'E998: Reduce of an empty Blob with no initial value')
   1032  call assert_fails("call reduce('', { acc, val -> acc + val })", 'E998: Reduce of an empty String with no initial value')
   1033  call assert_fails("call reduce(v:_null_string, { acc, val -> acc + val })", 'E998: Reduce of an empty String with no initial value')
   1034 
   1035  call assert_fails("call reduce({}, { acc, val -> acc + val }, 1)", 'E1098:')
   1036  call assert_fails("call reduce(0, { acc, val -> acc + val }, 1)", 'E1098:')
   1037  call assert_fails("call reduce([1, 2], 'Xdoes_not_exist')", 'E117:')
   1038  call assert_fails("echo reduce(0z01, { acc, val -> 2 * acc + val }, '')", 'E1210:')
   1039 
   1040  " call assert_fails("vim9 reduce(0, (acc, val) => (acc .. val), '')", 'E1252:')
   1041  " call assert_fails("vim9 reduce({}, (acc, val) => (acc .. val), '')", 'E1252:')
   1042  " call assert_fails("vim9 reduce(0.1, (acc, val) => (acc .. val), '')", 'E1252:')
   1043  " call assert_fails("vim9 reduce(function('tr'), (acc, val) => (acc .. val), '')", 'E1252:')
   1044  call assert_fails("call reduce('', { acc, val -> acc + val }, 1)", 'E1174:')
   1045  call assert_fails("call reduce('', { acc, val -> acc + val }, {})", 'E1174:')
   1046  call assert_fails("call reduce('', { acc, val -> acc + val }, 0.1)", 'E1174:')
   1047  call assert_fails("call reduce('', { acc, val -> acc + val }, function('tr'))", 'E1174:')
   1048  call assert_fails("call reduce('abc', { a, v -> a10}, '')", 'E121:')
   1049  call assert_fails("call reduce(0z0102, { a, v -> a10}, 1)", 'E121:')
   1050  call assert_fails("call reduce([1, 2], { a, v -> a10}, '')", 'E121:')
   1051 
   1052  let g:lut = [1, 2, 3, 4]
   1053  func EvilRemove()
   1054    call remove(g:lut, 1)
   1055    return 1
   1056  endfunc
   1057  call assert_fails("call reduce(g:lut, { acc, val -> EvilRemove() }, 1)", 'E742:')
   1058  unlet g:lut
   1059  delfunc EvilRemove
   1060 
   1061  call assert_equal(42, reduce(v:_null_list, function('add'), 42))
   1062  call assert_equal(42, reduce(v:_null_blob, function('add'), 42))
   1063 
   1064  " should not crash
   1065  " Nvim doesn't have null functions
   1066  " call assert_fails('echo reduce([1], test_null_function())', 'E1132:')
   1067  " Nvim doesn't have null partials
   1068  " call assert_fails('echo reduce([1], test_null_partial())', 'E1132:')
   1069 endfunc
   1070 
   1071 " splitting a string to a List using split()
   1072 func Test_str_split()
   1073  let lines =<< trim END
   1074      call assert_equal(['aa', 'bb'], split('  aa  bb '))
   1075      call assert_equal(['aa', 'bb'], split('  aa  bb  ', '\W\+', 0))
   1076      call assert_equal(['', 'aa', 'bb', ''], split('  aa  bb  ', '\W\+', 1))
   1077      call assert_equal(['', '', 'aa', '', 'bb', '', ''], split('  aa  bb  ', '\W', 1))
   1078      call assert_equal(['aa', '', 'bb'], split(':aa::bb:', ':', 0))
   1079      call assert_equal(['', 'aa', '', 'bb', ''], split(':aa::bb:', ':', 1))
   1080      call assert_equal(['aa', '', 'bb', 'cc', ''], split('aa,,bb, cc,', ',\s*', 1))
   1081      call assert_equal(['a', 'b', 'c'], split('abc', '\zs'))
   1082      call assert_equal(['', 'a', '', 'b', '', 'c', ''], split('abc', '\zs', 1))
   1083      call assert_equal(['abc'], split('abc', '\\%('))
   1084  END
   1085  call CheckLegacyAndVim9Success(lines)
   1086 
   1087  call assert_fails("call split('abc', [])", 'E730:')
   1088  call assert_fails("call split('abc', 'b', [])", 'E745:')
   1089 endfunc
   1090 
   1091 " compare recursively linked list and dict
   1092 func Test_listdict_compare()
   1093  let lines =<< trim END
   1094      VAR l = [1, 2, 3, '4']
   1095      VAR d = {'1': 1, '2': l, '3': 3}
   1096      LET l[1] = d
   1097      call assert_true(l == l)
   1098      call assert_true(d == d)
   1099      call assert_false(l != deepcopy(l))
   1100      call assert_false(d != deepcopy(d))
   1101  END
   1102  call CheckLegacyAndVim9Success(lines)
   1103 
   1104  " comparison errors
   1105  call assert_fails('echo [1, 2] =~ {}', 'E691:')
   1106  call assert_fails('echo [1, 2] =~ [1, 2]', 'E692:')
   1107  call assert_fails('echo {} =~ 5', 'E735:')
   1108  call assert_fails('echo {} =~ {}', 'E736:')
   1109 endfunc
   1110 
   1111 func Test_recursive_listdict_compare()
   1112  let l1 = [0, 1]
   1113  let l1[0] = l1
   1114  let l2 = [0, 1]
   1115  let l2[0] = l2
   1116  call assert_true(l1 == l2)
   1117  let d1 = {0: 0, 1: 1}
   1118  let d1[0] = d1
   1119  let d2 = {0: 0, 1: 1}
   1120  let d2[0] = d2
   1121  call assert_true(d1 == d2)
   1122 endfunc
   1123 
   1124  " compare complex recursively linked list and dict
   1125 func Test_listdict_compare_complex()
   1126  let lines =<< trim END
   1127      VAR l = []
   1128      call add(l, l)
   1129      VAR dict4 = {"l": l}
   1130      call add(dict4.l, dict4)
   1131      VAR lcopy = deepcopy(l)
   1132      VAR dict4copy = deepcopy(dict4)
   1133      call assert_true(l == lcopy)
   1134      call assert_true(dict4 == dict4copy)
   1135  END
   1136  call CheckLegacyAndVim9Success(lines)
   1137 endfunc
   1138 
   1139 " Test for extending lists and dictionaries
   1140 func Test_listdict_extend()
   1141  " Test extend() with lists
   1142 
   1143  " Pass the same List to extend()
   1144  let lines =<< trim END
   1145      VAR l = [1, 2, 3]
   1146      call assert_equal([1, 2, 3, 1, 2, 3], extend(l, l))
   1147      call assert_equal([1, 2, 3, 1, 2, 3], l)
   1148 
   1149      LET l = [1, 2, 3]
   1150      call assert_equal([1, 2, 3, 4, 5, 6], extend(l, [4, 5, 6]))
   1151      call assert_equal([1, 2, 3, 4, 5, 6], l)
   1152 
   1153      LET l = [1, 2, 3]
   1154      call extend(l, [4, 5, 6], 0)
   1155      call assert_equal([4, 5, 6, 1, 2, 3], l)
   1156 
   1157      LET l = [1, 2, 3]
   1158      call extend(l, [4, 5, 6], 1)
   1159      call assert_equal([1, 4, 5, 6, 2, 3], l)
   1160 
   1161      LET l = [1, 2, 3]
   1162      call extend(l, [4, 5, 6], 3)
   1163      call assert_equal([1, 2, 3, 4, 5, 6], l)
   1164 
   1165      LET l = [1, 2, 3]
   1166      call extend(l, [4, 5, 6], -1)
   1167      call assert_equal([1, 2, 4, 5, 6, 3], l)
   1168 
   1169      LET l = [1, 2, 3]
   1170      call extend(l, [4, 5, 6], -3)
   1171      call assert_equal([4, 5, 6, 1, 2,  3], l)
   1172  END
   1173  call CheckLegacyAndVim9Success(lines)
   1174 
   1175  let l = [1, 2, 3]
   1176  call assert_fails("call extend(l, [4, 5, 6], 4)", 'E684:')
   1177  call assert_fails("call extend(l, [4, 5, 6], -4)", 'E684:')
   1178  if has('float')
   1179    call assert_fails("call extend(l, [4, 5, 6], 1.2)", 'E805:')
   1180  endif
   1181 
   1182  " Test extend() with dictionaries.
   1183 
   1184  " Pass the same Dict to extend()
   1185  let lines =<< trim END
   1186      VAR d = {'a': {'b': 'B'}, 'x': 9}
   1187      call extend(d, d)
   1188      call assert_equal({'a': {'b': 'B'}, 'x': 9}, d)
   1189 
   1190      LET d = {'a': 'A', 'b': 9}
   1191      call assert_equal({'a': 'A', 'b': 0, 'c': 'C'}, extend(d, {'b': 0, 'c': 'C'}))
   1192      call assert_equal({'a': 'A', 'b': 0, 'c': 'C'}, d)
   1193 
   1194      LET d = {'a': 'A', 'b': 9}
   1195      call extend(d, {'a': 'A', 'b': 0, 'c': 'C'}, "force")
   1196      call assert_equal({'a': 'A', 'b': 0, 'c': 'C'}, d)
   1197 
   1198      LET d = {'a': 'A', 'b': 9}
   1199      call extend(d, {'b': 0, 'c': 'C'}, "keep")
   1200      call assert_equal({'a': 'A', 'b': 9, 'c': 'C'}, d)
   1201  END
   1202  call CheckLegacyAndVim9Success(lines)
   1203 
   1204  let d = {'a': 'A', 'b': 'B'}
   1205  call assert_fails("call extend(d, {'b': 0, 'c':'C'}, 'error')", 'E737:')
   1206  call assert_fails("call extend(d, {'b': 0}, [])", 'E730:')
   1207  call assert_fails("call extend(d, {'b': 0, 'c':'C'}, 'xxx')", 'E475:')
   1208  if has('float')
   1209    call assert_fails("call extend(d, {'b': 0, 'c':'C'}, 1.2)", 'E475:')
   1210  endif
   1211  call assert_equal({'a': 'A', 'b': 'B'}, d)
   1212 
   1213  call assert_fails("call extend([1, 2], 1)", 'E712:')
   1214  call assert_fails("call extend([1, 2], {})", 'E712:')
   1215 
   1216  " Extend g: dictionary with an invalid variable name
   1217  call assert_fails("call extend(g:, {'-!' : 10})", 'E461:')
   1218 
   1219  " Extend a list with itself.
   1220  let lines =<< trim END
   1221      VAR l = [1, 5, 7]
   1222      call extend(l, l, 0)
   1223      call assert_equal([1, 5, 7, 1, 5, 7], l)
   1224      LET l = [1, 5, 7]
   1225      call extend(l, l, 1)
   1226      call assert_equal([1, 1, 5, 7, 5, 7], l)
   1227      LET l = [1, 5, 7]
   1228      call extend(l, l, 2)
   1229      call assert_equal([1, 5, 1, 5, 7, 7], l)
   1230      LET l = [1, 5, 7]
   1231      call extend(l, l, 3)
   1232      call assert_equal([1, 5, 7, 1, 5, 7], l)
   1233  END
   1234  call CheckLegacyAndVim9Success(lines)
   1235 endfunc
   1236 
   1237 func Test_listdict_extendnew()
   1238  " Test extendnew() with lists
   1239  let l = [1, 2, 3]
   1240  call assert_equal([1, 2, 3, 4, 5], extendnew(l, [4, 5]))
   1241  call assert_equal([1, 2, 3], l)
   1242  lockvar l
   1243  call assert_equal([1, 2, 3, 4, 5], extendnew(l, [4, 5]))
   1244 
   1245  " Test extendnew() with dictionaries.
   1246  let d = {'a': {'b': 'B'}}
   1247  call assert_equal({'a': {'b': 'B'}, 'c': 'cc'}, extendnew(d, {'c': 'cc'}))
   1248  call assert_equal({'a': {'b': 'B'}}, d)
   1249  lockvar d
   1250  call assert_equal({'a': {'b': 'B'}, 'c': 'cc'}, extendnew(d, {'c': 'cc'}))
   1251 endfunc
   1252 
   1253 func s:check_scope_dict(x, fixed)
   1254  func s:gen_cmd(cmd, x)
   1255    return substitute(a:cmd, '\<x\ze:', a:x, 'g')
   1256  endfunc
   1257 
   1258  let cmd = s:gen_cmd('let x:foo = 1', a:x)
   1259  if a:fixed
   1260    call assert_fails(cmd, 'E461')
   1261  else
   1262    exe cmd
   1263    exe s:gen_cmd('call assert_equal(1, x:foo)', a:x)
   1264  endif
   1265 
   1266  let cmd = s:gen_cmd('let x:["bar"] = 2', a:x)
   1267  if a:fixed
   1268    call assert_fails(cmd, 'E461')
   1269  else
   1270    exe cmd
   1271    exe s:gen_cmd('call assert_equal(2, x:bar)', a:x)
   1272  endif
   1273 
   1274  let cmd = s:gen_cmd('call extend(x:, {"baz": 3})', a:x)
   1275  if a:fixed
   1276    call assert_fails(cmd, 'E742')
   1277  else
   1278    exe cmd
   1279    exe s:gen_cmd('call assert_equal(3, x:baz)', a:x)
   1280  endif
   1281 
   1282  if a:fixed
   1283    if a:x ==# 'a'
   1284      call assert_fails('unlet a:x', 'E795')
   1285      call assert_fails('call remove(a:, "x")', 'E742')
   1286    elseif a:x ==# 'v'
   1287      call assert_fails('unlet v:count', 'E795')
   1288      call assert_fails('call remove(v:, "count")', 'E742')
   1289    endif
   1290  else
   1291    exe s:gen_cmd('unlet x:foo', a:x)
   1292    exe s:gen_cmd('unlet x:bar', a:x)
   1293    exe s:gen_cmd('call remove(x:, "baz")', a:x)
   1294  endif
   1295 
   1296  delfunc s:gen_cmd
   1297 endfunc
   1298 
   1299 func Test_scope_dict()
   1300  " Test for g:
   1301  call s:check_scope_dict('g', v:false)
   1302 
   1303  " Test for s:
   1304  call s:check_scope_dict('s', v:false)
   1305 
   1306  " Test for l:
   1307  call s:check_scope_dict('l', v:false)
   1308 
   1309  " Test for a:
   1310  call s:check_scope_dict('a', v:true)
   1311 
   1312  " Test for b:
   1313  call s:check_scope_dict('b', v:false)
   1314 
   1315  " Test for w:
   1316  call s:check_scope_dict('w', v:false)
   1317 
   1318  " Test for t:
   1319  call s:check_scope_dict('t', v:false)
   1320 
   1321  " Test for v:
   1322  call s:check_scope_dict('v', v:true)
   1323 endfunc
   1324 
   1325 " Test for deep nesting of lists (> 100)
   1326 func Test_deep_nested_list()
   1327  let deep_list = []
   1328  let l = deep_list
   1329  for i in range(102)
   1330    let newlist = []
   1331    call add(l, newlist)
   1332    let l = newlist
   1333  endfor
   1334  call add(l, 102)
   1335 
   1336  call assert_fails('let m = deepcopy(deep_list)', 'E698:')
   1337  call assert_fails('lockvar 110 deep_list', 'E743:')
   1338  call assert_fails('unlockvar 110 deep_list', 'E743:')
   1339  " Nvim implements :echo very differently
   1340  " call assert_fails('let x = execute("echo deep_list")', 'E724:')
   1341  call test_garbagecollect_now()
   1342  unlet deep_list
   1343 endfunc
   1344 
   1345 " Test for deep nesting of dicts (> 100)
   1346 func Test_deep_nested_dict()
   1347  let deep_dict = {}
   1348  let d = deep_dict
   1349  for i in range(102)
   1350    let newdict = {}
   1351    let d.k = newdict
   1352    let d = newdict
   1353  endfor
   1354  let d.k = 'v'
   1355 
   1356  call assert_fails('let m = deepcopy(deep_dict)', 'E698:')
   1357  call assert_fails('lockvar 110 deep_dict', 'E743:')
   1358  call assert_fails('unlockvar 110 deep_dict', 'E743:')
   1359  " Nvim implements :echo very differently
   1360  " call assert_fails('let x = execute("echo deep_dict")', 'E724:')
   1361  call test_garbagecollect_now()
   1362  unlet deep_dict
   1363 endfunc
   1364 
   1365 " List and dict indexing tests
   1366 func Test_listdict_index()
   1367  call CheckLegacyAndVim9Failure(['echo function("min")[0]'], 'E695:')
   1368  call CheckLegacyAndVim9Failure(['echo v:true[0]'], 'E909:')
   1369  call CheckLegacyAndVim9Failure(['echo v:null[0]'], 'E909:')
   1370  call CheckLegacyAndVim9Failure(['VAR d = {"k": 10}', 'echo d.'], ['E15:', 'E1127:', 'E15:'])
   1371  call CheckLegacyAndVim9Failure(['VAR d = {"k": 10}', 'echo d[1 : 2]'], 'E719:')
   1372 
   1373  call assert_fails("let v = [4, 6][{-> 1}]", 'E729:')
   1374  call CheckDefAndScriptFailure(['var v = [4, 6][() => 1]'], ['E1012:', 'E703:'])
   1375 
   1376  call CheckLegacyAndVim9Failure(['VAR v = range(5)[2 : []]'], ['E730:', 'E1012:', 'E730:'])
   1377 
   1378  call assert_fails("let v = range(5)[2:{-> 2}(]", ['E15:', 'E116:'])
   1379  call CheckDefAndScriptFailure(['var v = range(5)[2 : () => 2(]'], 'E15:')
   1380 
   1381  call CheckLegacyAndVim9Failure(['VAR v = range(5)[2 : 3'], ['E111:', 'E1097:', 'E111:'])
   1382  call CheckLegacyAndVim9Failure(['VAR l = insert([1, 2, 3], 4, 10)'], 'E684:')
   1383  call CheckLegacyAndVim9Failure(['VAR l = insert([1, 2, 3], 4, -10)'], 'E684:')
   1384  call CheckLegacyAndVim9Failure(['VAR l = insert([1, 2, 3], 4, [])'], ['E745:', 'E1013:', 'E1210:'])
   1385 
   1386  call CheckLegacyAndVim9Failure(['VAR l = [1, 2, 3]', 'LET l[i] = 3'], ['E121:', 'E1001:', 'E121:'])
   1387  call CheckLegacyAndVim9Failure(['VAR l = [1, 2, 3]', 'LET l[1.1] = 4'], ['E805:', 'E1012:', 'E805:'])
   1388  call CheckLegacyAndVim9Failure(['VAR l = [1, 2, 3]', 'LET l[: i] = [4, 5]'], ['E121:', 'E1001:', 'E121:'])
   1389  call CheckLegacyAndVim9Failure(['VAR l = [1, 2, 3]', 'LET l[: 3.2] = [4, 5]'], ['E805:', 'E1012:', 'E805:'])
   1390  " call CheckLegacyAndVim9Failure(['VAR t = test_unknown()', 'echo t[0]'], ['E685:', 'E909:', 'E685:'])
   1391 endfunc
   1392 
   1393 " Test for a null list
   1394 func Test_null_list()
   1395  let l = v:_null_list
   1396  call assert_equal('', join(l))
   1397  call assert_equal(0, len(l))
   1398  call assert_equal(1, empty(l))
   1399  call assert_fails('let s = join([1, 2], [])', 'E730:')
   1400  call assert_equal([], split(v:_null_string))
   1401  call assert_equal([], l[:2])
   1402  call assert_true([] == l)
   1403  call assert_equal('[]', string(l))
   1404  " call assert_equal(0, sort(l))
   1405  " call assert_equal(0, sort(l))
   1406  " call assert_equal(0, uniq(l))
   1407  let k = [] + l
   1408  call assert_equal([], k)
   1409  let k = l + []
   1410  call assert_equal([], k)
   1411  call assert_equal(0, len(copy(l)))
   1412  call assert_equal(0, count(l, 5))
   1413  call assert_equal([], deepcopy(l))
   1414  call assert_equal(5, get(l, 2, 5))
   1415  call assert_equal(-1, index(l, 2, 5))
   1416  " call assert_equal(0, insert(l, 2, -1))
   1417  call assert_equal(0, min(l))
   1418  call assert_equal(0, max(l))
   1419  " call assert_equal(0, remove(l, 0, 2))
   1420  call assert_equal([], repeat(l, 2))
   1421  " call assert_equal(0, reverse(l))
   1422  " call assert_equal(0, sort(l))
   1423  call assert_equal('[]', string(l))
   1424  " call assert_equal(0, extend(l, l, 0))
   1425  lockvar l
   1426  call assert_equal(1, islocked('l'))
   1427  unlockvar l
   1428 endfunc
   1429 
   1430 " Test for a null dict
   1431 func Test_null_dict()
   1432  call assert_equal(v:_null_dict, v:_null_dict)
   1433  let d = v:_null_dict
   1434  call assert_equal({}, d)
   1435  call assert_equal(0, len(d))
   1436  call assert_equal(1, empty(d))
   1437  call assert_equal([], items(d))
   1438  call assert_equal([], keys(d))
   1439  call assert_equal([], values(d))
   1440  call assert_false(has_key(d, 'k'))
   1441  call assert_equal('{}', string(d))
   1442  call assert_fails('let x = d[10]')
   1443  call assert_equal({}, {})
   1444  call assert_equal(0, len(copy(d)))
   1445  call assert_equal(0, count(d, 'k'))
   1446  call assert_equal({}, deepcopy(d))
   1447  call assert_equal(20, get(d, 'k', 20))
   1448  call assert_equal(0, min(d))
   1449  call assert_equal(0, max(d))
   1450  call assert_equal(0, remove(d, 'k'))
   1451  call assert_equal('{}', string(d))
   1452  " call assert_equal(0, extend(d, d, 0))
   1453  lockvar d
   1454  call assert_equal(1, islocked('d'))
   1455  unlockvar d
   1456 endfunc
   1457 
   1458 " Test for the indexof() function
   1459 func Test_indexof()
   1460  let l = [#{color: 'red'}, #{color: 'blue'}, #{color: 'green'}]
   1461  call assert_equal(0, indexof(l, {i, v -> v.color == 'red'}))
   1462  call assert_equal(2, indexof(l, {i, v -> v.color == 'green'}))
   1463  call assert_equal(-1, indexof(l, {i, v -> v.color == 'grey'}))
   1464  call assert_equal(1, indexof(l, "v:val.color == 'blue'"))
   1465  call assert_equal(-1, indexof(l, "v:val.color == 'cyan'"))
   1466 
   1467  let l = [#{n: 10}, #{n: 10}, #{n: 20}]
   1468  call assert_equal(0, indexof(l, "v:val.n == 10", #{startidx: 0}))
   1469  call assert_equal(1, indexof(l, "v:val.n == 10", #{startidx: -2}))
   1470  call assert_equal(-1, indexof(l, "v:val.n == 10", #{startidx: 4}))
   1471  call assert_equal(-1, indexof(l, "v:val.n == 10", #{startidx: -4}))
   1472  call assert_equal(0, indexof(l, "v:val.n == 10", v:_null_dict))
   1473 
   1474  let s = ["a", "b", "c"]
   1475  call assert_equal(2, indexof(s, {_, v -> v == 'c'}))
   1476  call assert_equal(-1, indexof(s, {_, v -> v == 'd'}))
   1477  call assert_equal(-1, indexof(s, {_, v -> "v == 'd'"}))
   1478 
   1479  call assert_equal(-1, indexof([], {i, v -> v == 'a'}))
   1480  call assert_equal(-1, indexof([1, 2, 3], {_, v -> "v == 2"}))
   1481  call assert_equal(-1, indexof(v:_null_list, {i, v -> v == 'a'}))
   1482  call assert_equal(-1, indexof(l, v:_null_string))
   1483  " Nvim doesn't have null functions
   1484  " call assert_equal(-1, indexof(l, test_null_function()))
   1485  call assert_equal(-1, indexof(l, ""))
   1486  call assert_fails('let i = indexof(l, " ")', 'E15:')
   1487 
   1488  " failure cases
   1489  call assert_fails('let i = indexof(l, "v:val == ''cyan''")', 'E735:')
   1490  call assert_fails('let i = indexof(l, "color == ''cyan''")', 'E121:')
   1491  call assert_fails('let i = indexof(l, {})', 'E1256:')
   1492  call assert_fails('let i = indexof({}, "v:val == 2")', 'E1226:')
   1493  call assert_fails('let i = indexof([], "v:val == 2", [])', 'E1206:')
   1494 
   1495  func TestIdx(k, v)
   1496    return a:v.n == 20
   1497  endfunc
   1498  call assert_equal(2, indexof(l, function("TestIdx")))
   1499  delfunc TestIdx
   1500  func TestIdx(k, v)
   1501    return {}
   1502  endfunc
   1503  call assert_fails('let i = indexof(l, function("TestIdx"))', 'E728:')
   1504  delfunc TestIdx
   1505  func TestIdx(k, v)
   1506    throw "IdxError"
   1507  endfunc
   1508  call assert_fails('let i = indexof(l, function("TestIdx"))', 'E605:')
   1509  delfunc TestIdx
   1510 endfunc
   1511 
   1512 func Test_extendnew_leak()
   1513  " This used to leak memory
   1514  for i in range(100) | silent! call extendnew([], [], []) | endfor
   1515  for i in range(100) | silent! call extendnew({}, {}, {}) | endfor
   1516 endfunc
   1517 
   1518 " Test for comparing deeply nested List/Dict values
   1519 func Test_deep_nested_listdict_compare()
   1520  let lines =<< trim END
   1521    func GetNestedList(sz)
   1522      let l = []
   1523      let x = l
   1524      for i in range(a:sz)
   1525        let y = [1]
   1526        call add(x, y)
   1527        let x = y
   1528      endfor
   1529      return l
   1530    endfunc
   1531 
   1532    VAR l1 = GetNestedList(1000)
   1533    VAR l2 = GetNestedList(999)
   1534    call assert_false(l1 == l2)
   1535 
   1536    #" after 1000 nested items, the lists are considered to be equal
   1537    VAR l3 = GetNestedList(1001)
   1538    VAR l4 = GetNestedList(1002)
   1539    call assert_true(l3 == l4)
   1540  END
   1541  call CheckLegacyAndVim9Success(lines)
   1542 
   1543  let lines =<< trim END
   1544    func GetNestedDict(sz)
   1545      let d = {}
   1546      let x = d
   1547      for i in range(a:sz)
   1548        let y = {}
   1549        let x['a'] = y
   1550        let x = y
   1551      endfor
   1552      return d
   1553    endfunc
   1554 
   1555    VAR d1 = GetNestedDict(1000)
   1556    VAR d2 = GetNestedDict(999)
   1557    call assert_false(d1 == d2)
   1558 
   1559    #" after 1000 nested items, the Dicts are considered to be equal
   1560    VAR d3 = GetNestedDict(1001)
   1561    VAR d4 = GetNestedDict(1002)
   1562    call assert_true(d3 == d4)
   1563  END
   1564  call CheckLegacyAndVim9Success(lines)
   1565 endfunc
   1566 
   1567 " vim: shiftwidth=2 sts=2 expandtab