1" Tests for the List and Dict types
2
3func TearDown()
4  " Run garbage collection after every test
5  call test_garbagecollect_now()
6endfunc
7
8" Tests for List type
9
10" List creation
11func Test_list_create()
12  " Creating List directly with different types
13  let l = [1, 'as''d', [1, 2, function("strlen")], {'a': 1},]
14  call assert_equal("[1, 'as''d', [1, 2, function('strlen')], {'a': 1}]", string(l))
15  call assert_equal({'a' : 1}, l[-1])
16  call assert_equal(1, l[-4])
17  let x = 10
18  try
19    let x = l[-5]
20  catch
21    call assert_match('E684:', v:exception)
22  endtry
23  call assert_equal(10, x)
24endfunc
25
26" List slices
27func Test_list_slice()
28  let l = [1, 'as''d', [1, 2, function("strlen")], {'a': 1},]
29  call assert_equal([1, 'as''d', [1, 2, function('strlen')], {'a': 1}], l[:])
30  call assert_equal(['as''d', [1, 2, function('strlen')], {'a': 1}], l[1:])
31  call assert_equal([1, 'as''d', [1, 2, function('strlen')]], l[:-2])
32  call assert_equal([1, 'as''d', [1, 2, function('strlen')], {'a': 1}], l[0:8])
33  call assert_equal([], l[8:-1])
34endfunc
35
36" List identity
37func Test_list_identity()
38  let l = [1, 'as''d', [1, 2, function("strlen")], {'a': 1},]
39  let ll = l
40  let lx = copy(l)
41  call assert_true(l == ll)
42  call assert_false(l isnot ll)
43  call assert_true(l is ll)
44  call assert_true(l == lx)
45  call assert_false(l is lx)
46  call assert_true(l isnot lx)
47endfunc
48
49" removing items with :unlet
50func Test_list_unlet()
51  let l = [1, 'as''d', [1, 2, function("strlen")], {'a': 1},]
52  unlet l[2]
53  call assert_equal([1, 'as''d', {'a': 1}], l)
54  let l = range(8)
55  unlet l[:3]
56  unlet l[1:]
57  call assert_equal([4], l)
58
59  " removing items out of range: silently skip items that don't exist
60  let l = [0, 1, 2, 3]
61  call assert_fails('unlet l[2:1]', 'E684')
62  let l = [0, 1, 2, 3]
63  unlet l[2:2]
64  call assert_equal([0, 1, 3], l)
65  let l = [0, 1, 2, 3]
66  unlet l[2:3]
67  call assert_equal([0, 1], l)
68  let l = [0, 1, 2, 3]
69  unlet l[2:4]
70  call assert_equal([0, 1], l)
71  let l = [0, 1, 2, 3]
72  unlet l[2:5]
73  call assert_equal([0, 1], l)
74  let l = [0, 1, 2, 3]
75  call assert_fails('unlet l[-1:2]', 'E684')
76  let l = [0, 1, 2, 3]
77  unlet l[-2:2]
78  call assert_equal([0, 1, 3], l)
79  let l = [0, 1, 2, 3]
80  unlet l[-3:2]
81  call assert_equal([0, 3], l)
82  let l = [0, 1, 2, 3]
83  unlet l[-4:2]
84  call assert_equal([3], l)
85  let l = [0, 1, 2, 3]
86  unlet l[-5:2]
87  call assert_equal([3], l)
88  let l = [0, 1, 2, 3]
89  unlet l[-6:2]
90  call assert_equal([3], l)
91endfunc
92
93" assignment to a list
94func Test_list_assign()
95  let l = [0, 1, 2, 3]
96  let [va, vb] = l[2:3]
97  call assert_equal([2, 3], [va, vb])
98  call assert_fails('let [va, vb] = l', 'E687')
99  call assert_fails('let [va, vb] = l[1:1]', 'E688')
100endfunc
101
102" test for range assign
103func Test_list_range_assign()
104  let l = [0]
105  let l[:] = [1, 2]
106  call assert_equal([1, 2], l)
107endfunc
108
109" Tests for Dictionary type
110
111func Test_dict()
112  " Creating Dictionary directly with different types
113  let d = {001: 'asd', 'b': [1, 2, function('strlen')], -1: {'a': 1},}
114  call assert_equal("{'1': 'asd', 'b': [1, 2, function('strlen')], '-1': {'a': 1}}", string(d))
115  call assert_equal('asd', d.1)
116  call assert_equal(['-1', '1', 'b'], sort(keys(d)))
117  call assert_equal(['asd', [1, 2, function('strlen')], {'a': 1}], values(d))
118  let v = []
119  for [key, val] in items(d)
120    call extend(v, [key, val])
121    unlet key val
122  endfor
123  call assert_equal(['1','asd','b',[1, 2, function('strlen')],'-1',{'a': 1}], v)
124
125  call extend(d, {3:33, 1:99})
126  call extend(d, {'b':'bbb', 'c':'ccc'}, "keep")
127  call assert_fails("call extend(d, {3:333,4:444}, 'error')", 'E737')
128  call assert_equal({'c': 'ccc', '1': 99, 'b': [1, 2, function('strlen')], '3': 33, '-1': {'a': 1}}, d)
129  call filter(d, 'v:key =~ ''[ac391]''')
130  call assert_equal({'c': 'ccc', '1': 99, '3': 33, '-1': {'a': 1}}, d)
131endfunc
132
133" Dictionary identity
134func Test_dict_identity()
135  let d = {001: 'asd', 'b': [1, 2, function('strlen')], -1: {'a': 1},}
136  let dd = d
137  let dx = copy(d)
138  call assert_true(d == dd)
139  call assert_false(d isnot dd)
140  call assert_true(d is dd)
141  call assert_true(d == dx)
142  call assert_false(d is dx)
143  call assert_true(d isnot dx)
144endfunc
145
146" removing items with :unlet
147func Test_dict_unlet()
148  let d = {'b':'bbb', '1': 99, '3': 33, '-1': {'a': 1}}
149  unlet d.b
150  unlet d[-1]
151  call assert_equal({'1': 99, '3': 33}, d)
152endfunc
153
154" manipulating a big Dictionary (hashtable.c has a border of 1000 entries)
155func Test_dict_big()
156  let d = {}
157  for i in range(1500)
158    let d[i] = 3000 - i
159  endfor
160  call assert_equal([3000, 2900, 2001, 1600, 1501], [d[0], d[100], d[999], d[1400], d[1499]])
161  let str = ''
162  try
163    let n = d[1500]
164  catch
165    let str=substitute(v:exception, '\v(.{14}).*( \d{4}).*', '\1\2', '')
166  endtry
167  call assert_equal('Vim(let):E716: 1500', str)
168
169  " lookup each items
170  for i in range(1500)
171    call assert_equal(3000 - i, d[i])
172  endfor
173  let i += 1
174
175  " delete even items
176  while i >= 2
177    let i -= 2
178    unlet d[i]
179  endwhile
180  call assert_equal('NONE', get(d, 1500 - 100, 'NONE'))
181  call assert_equal(2999, d[1])
182
183  " delete odd items, checking value, one intentionally wrong
184  let d[33] = 999
185  let i = 1
186  while i < 1500
187   if i != 33
188     call assert_equal(3000 - i, d[i])
189   else
190     call assert_equal(999, d[i])
191   endif
192   unlet d[i]
193   let i += 2
194  endwhile
195  call assert_equal({}, d)
196  unlet d
197endfunc
198
199" Dictionary function
200func Test_dict_func()
201  let d = {}
202  func d.func(a) dict
203    return a:a . len(self.data)
204  endfunc
205  let d.data = [1,2,3]
206  call assert_equal('len: 3', d.func('len: '))
207  let x = d.func('again: ')
208  call assert_equal('again: 3', x)
209  let Fn = d.func
210  call assert_equal('xxx3', Fn('xxx'))
211endfunc
212
213" Function in script-local List or Dict
214func Test_script_local_dict_func()
215  let g:dict = {}
216  function g:dict.func() dict
217    return 'g:dict.func' . self.foo[1] . self.foo[0]('asdf')
218  endfunc
219  let g:dict.foo = ['-', 2, 3]
220  call insert(g:dict.foo, function('strlen'))
221  call assert_equal('g:dict.func-4', g:dict.func())
222  unlet g:dict
223endfunc
224
225" Nasty: remove func from Dict that's being called (works)
226func Test_dict_func_remove_in_use()
227  let d = {1:1}
228  func d.func(a)
229    return "a:" . a:a
230  endfunc
231  let expected = 'a:' . string(get(d, 'func'))
232  call assert_equal(expected, d.func(string(remove(d, 'func'))))
233endfunc
234
235" Nasty: deepcopy() dict that refers to itself (fails when noref used)
236func Test_dict_deepcopy()
237  let d = {1:1, 2:2}
238  let l = [4, d, 6]
239  let d[3] = l
240  let dc = deepcopy(d)
241  call assert_fails('call deepcopy(d, 1)', 'E698')
242  let l2 = [0, l, l, 3]
243  let l[1] = l2
244  let l3 = deepcopy(l2)
245  call assert_true(l3[1] is l3[2])
246endfunc
247
248" Locked variables
249func Test_list_locked_var()
250  let expected = [
251	      \ [['0000-000', 'ppppppp'],
252	      \  ['0000-000', 'ppppppp'],
253	      \  ['0000-000', 'ppppppp']],
254	      \ [['1000-000', 'ppppppF'],
255	      \  ['0000-000', 'ppppppp'],
256	      \  ['0000-000', 'ppppppp']],
257	      \ [['1100-100', 'ppFppFF'],
258	      \  ['0000-000', 'ppppppp'],
259	      \  ['0000-000', 'ppppppp']],
260	      \ [['1110-110', 'pFFpFFF'],
261	      \  ['0010-010', 'pFppFpp'],
262	      \  ['0000-000', 'ppppppp']],
263	      \ [['1111-111', 'FFFFFFF'],
264	      \  ['0011-011', 'FFpFFpp'],
265	      \  ['0000-000', 'ppppppp']]
266	      \ ]
267  for depth in range(5)
268    for u in range(3)
269      unlet! l
270      let l = [0, [1, [2, 3]], {4: 5, 6: {7: 8}}]
271      exe "lockvar " . depth . " l"
272      if u == 1
273        exe "unlockvar l"
274      elseif u == 2
275        exe "unlockvar " . depth . " l"
276      endif
277      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]")
278      call assert_equal(expected[depth][u][0], ps)
279      let ps = ''
280      try
281        let l[1][1][0] = 99
282        let ps .= 'p'
283      catch
284        let ps .= 'F'
285      endtry
286      try
287        let l[1][1] = [99]
288        let ps .= 'p'
289      catch
290        let ps .= 'F'
291      endtry
292      try
293        let l[1] = [99]
294        let ps .= 'p'
295      catch
296        let ps .= 'F'
297      endtry
298      try
299        let l[2]['6'][7] = 99
300        let ps .= 'p'
301      catch
302        let ps .= 'F'
303      endtry
304      try
305        let l[2][6] = {99: 99}
306        let ps .= 'p'
307      catch
308        let ps .= 'F'
309      endtry
310      try
311        let l[2] = {99: 99}
312        let ps .= 'p'
313      catch
314        let ps .= 'F'
315      endtry
316      try
317        let l = [99]
318        let ps .= 'p'
319      catch
320        let ps .= 'F'
321      endtry
322      call assert_equal(expected[depth][u][1], ps)
323    endfor
324  endfor
325endfunc
326
327" Unletting locked variables
328func Test_list_locked_var_unlet()
329  let expected = [
330	      \ [['0000-000', 'ppppppp'],
331	      \  ['0000-000', 'ppppppp'],
332	      \  ['0000-000', 'ppppppp']],
333	      \ [['1000-000', 'ppFppFp'],
334	      \  ['0000-000', 'ppppppp'],
335	      \  ['0000-000', 'ppppppp']],
336	      \ [['1100-100', 'pFFpFFp'],
337	      \  ['0000-000', 'ppppppp'],
338	      \  ['0000-000', 'ppppppp']],
339	      \ [['1110-110', 'FFFFFFp'],
340	      \  ['0010-010', 'FppFppp'],
341	      \  ['0000-000', 'ppppppp']],
342	      \ [['1111-111', 'FFFFFFp'],
343	      \  ['0011-011', 'FppFppp'],
344	      \  ['0000-000', 'ppppppp']]
345	      \ ]
346
347  for depth in range(5)
348    for u in range(3)
349      unlet! l
350      let l = [0, [1, [2, 3]], {4: 5, 6: {7: 8}}]
351      exe "lockvar " . depth . " l"
352      if u == 1
353        exe "unlockvar l"
354      elseif u == 2
355        exe "unlockvar " . depth . " l"
356      endif
357      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]")
358      call assert_equal(expected[depth][u][0], ps)
359      let ps = ''
360      try
361        unlet l[2]['6'][7]
362        let ps .= 'p'
363      catch
364        let ps .= 'F'
365      endtry
366      try
367        unlet l[2][6]
368        let ps .= 'p'
369      catch
370        let ps .= 'F'
371      endtry
372      try
373        unlet l[2]
374        let ps .= 'p'
375      catch
376        let ps .= 'F'
377      endtry
378      try
379        unlet l[1][1][0]
380        let ps .= 'p'
381      catch
382        let ps .= 'F'
383      endtry
384      try
385        unlet l[1][1]
386        let ps .= 'p'
387      catch
388        let ps .= 'F'
389      endtry
390      try
391        unlet l[1]
392        let ps .= 'p'
393      catch
394        let ps .= 'F'
395      endtry
396      try
397        unlet l
398        let ps .= 'p'
399      catch
400        let ps .= 'F'
401      endtry
402      call assert_equal(expected[depth][u][1], ps)
403    endfor
404  endfor
405endfunc
406
407" Locked variables and :unlet or list / dict functions
408
409" No :unlet after lock on dict:
410func Test_dict_lock_unlet()
411  unlet! d
412  let d = {'a': 99, 'b': 100}
413  lockvar 1 d
414  call assert_fails('unlet d.a', 'E741')
415endfunc
416
417" unlet after lock on dict item
418func Test_dict_item_lock_unlet()
419  unlet! d
420  let d = {'a': 99, 'b': 100}
421  lockvar d.a
422  unlet d.a
423  call assert_equal({'b' : 100}, d)
424endfunc
425
426" filter() after lock on dict item
427func Test_dict_lock_filter()
428  unlet! d
429  let d = {'a': 99, 'b': 100}
430  lockvar d.a
431  call filter(d, 'v:key != "a"')
432  call assert_equal({'b' : 100}, d)
433endfunc
434
435" map() after lock on dict
436func Test_dict_lock_map()
437  unlet! d
438  let d = {'a': 99, 'b': 100}
439  lockvar 1 d
440  call map(d, 'v:val + 200')
441  call assert_equal({'a' : 299, 'b' : 300}, d)
442endfunc
443
444" No extend() after lock on dict item
445func Test_dict_lock_extend()
446  unlet! d
447  let d = {'a': 99, 'b': 100}
448  lockvar d.a
449  call assert_fails("call extend(d, {'a' : 123})", 'E741')
450  call assert_equal({'a': 99, 'b': 100}, d)
451endfunc
452
453" No remove() of write-protected scope-level variable
454func! Tfunc(this_is_a_long_parameter_name)
455  call assert_fails("call remove(a:, 'this_is_a_long_parameter_name')", 'E795')
456endfun
457func Test_dict_scope_var_remove()
458  call Tfunc('testval')
459endfunc
460
461" No extend() of write-protected scope-level variable
462func! Tfunc(this_is_a_long_parameter_name)
463  call assert_fails("call extend(a:, {'this_is_a_long_parameter_name': 1234})", 'E742')
464endfunc
465func Test_dict_scope_var_extend()
466  call Tfunc('testval')
467endfunc
468
469" No :unlet of variable in locked scope
470func Test_lock_var_unlet()
471  let b:testvar = 123
472  lockvar 1 b:
473  call assert_fails('unlet b:testvar', 'E741:')
474  unlockvar 1 b:
475  unlet! b:testvar
476endfunc
477
478" No :let += of locked list variable
479func Test_let_lock_list()
480  let l = ['a', 'b', 3]
481  lockvar 1 l
482  call assert_fails("let l += ['x']", 'E741:')
483  call assert_equal(['a', 'b', 3], l)
484
485  unlet l
486  let l = [1, 2, 3, 4]
487  lockvar! l
488  call assert_equal([1, 2, 3, 4], l)
489  unlockvar l[1]
490  call assert_fails('unlet l[0:1]', 'E741:')
491  call assert_equal([1, 2, 3, 4], l)
492  call assert_fails('unlet l[1:2]', 'E741:')
493  call assert_equal([1, 2, 3, 4], l)
494  unlockvar l[1]
495  call assert_fails('let l[0:1] = [0, 1]', 'E741:')
496  call assert_equal([1, 2, 3, 4], l)
497  call assert_fails('let l[1:2] = [0, 1]', 'E741:')
498  call assert_equal([1, 2, 3, 4], l)
499  unlet l
500endfunc
501
502" lockvar/islocked() triggering script autoloading
503func Test_lockvar_script_autoload()
504  let old_rtp = &rtp
505  set rtp+=./sautest
506  lockvar g:footest#x
507  unlockvar g:footest#x
508  call assert_equal(-1, islocked('g:footest#x'))
509  call assert_equal(0, exists('g:footest#x'))
510  call assert_equal(1, g:footest#x)
511  let &rtp = old_rtp
512endfunc
513
514" a:000 function argument test
515func s:arg_list_test(...)
516  call assert_fails('let a:000 = [1, 2]', 'E46:')
517  call assert_fails('let a:000[0] = 9', 'E742:')
518  call assert_fails('let a:000[2] = [9, 10]', 'E742:')
519  call assert_fails('let a:000[3] = {9 : 10}', 'E742:')
520
521  " now the tests that should pass
522  let a:000[2][1] = 9
523  call extend(a:000[2], [5, 6])
524  let a:000[3][5] = 8
525  let a:000[3]['a'] = 12
526  call assert_equal([1, 2, [3, 9, 5, 6], {'a': 12, '5': 8}], a:000)
527endfunc
528
529func Test_func_arg_list()
530  call s:arg_list_test(1, 2, [3, 4], {5: 6})
531endfunc
532
533" Tests for reverse(), sort(), uniq()
534func Test_reverse_sort_uniq()
535  let l = ['-0', 'A11', 2, 2, 'xaaa', 4, 'foo', 'foo6', 'foo', [0, 1, 2], 'x8', [0, 1, 2], 1.5]
536  call assert_equal(['-0', 'A11', 2, 'xaaa', 4, 'foo', 'foo6', 'foo', [0, 1, 2], 'x8', [0, 1, 2], 1.5], uniq(copy(l)))
537  call assert_equal([1.5, [0, 1, 2], 'x8', [0, 1, 2], 'foo', 'foo6', 'foo', 4, 'xaaa', 2, 2, 'A11', '-0'], reverse(l))
538  call assert_equal([1.5, [0, 1, 2], 'x8', [0, 1, 2], 'foo', 'foo6', 'foo', 4, 'xaaa', 2, 2, 'A11', '-0'], reverse(reverse(l)))
539  call assert_equal(['-0', 'A11', 'foo', 'foo', 'foo6', 'x8', 'xaaa', 1.5, 2, 2, 4, [0, 1, 2], [0, 1, 2]], sort(l))
540  call assert_equal([[0, 1, 2], [0, 1, 2], 4, 2, 2, 1.5, 'xaaa', 'x8', 'foo6', 'foo', 'foo', 'A11', '-0'], reverse(sort(l)))
541  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))))
542  call assert_equal(['-0', 'A11', 'foo', 'foo6', 'x8', 'xaaa', 1.5, 2, 4, [0, 1, 2]], uniq(sort(l)))
543
544  let l=[7, 9, 'one', 18, 12, 22, 'two', 10.0e-16, -1, 'three', 0xff, 0.22, 'four']
545  call assert_equal([-1, 'one', 'two', 'three', 'four', 1.0e-15, 0.22, 7, 9, 12, 18, 22, 255], sort(copy(l), 'n'))
546
547  let l=[7, 9, 18, 12, 22, 10.0e-16, -1, 0xff, 0, -0, 0.22, 'bar', 'BAR', 'Bar', 'Foo', 'FOO', 'foo', 'FOOBAR', {}, []]
548  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), 1))
549  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'))
550  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)))
551endfunc
552
553" splitting a string to a List
554func Test_str_split()
555  call assert_equal(['aa', 'bb'], split('  aa  bb '))
556  call assert_equal(['aa', 'bb'], split('  aa  bb  ', '\W\+', 0))
557  call assert_equal(['', 'aa', 'bb', ''], split('  aa  bb  ', '\W\+', 1))
558  call assert_equal(['', '', 'aa', '', 'bb', '', ''], split('  aa  bb  ', '\W', 1))
559  call assert_equal(['aa', '', 'bb'], split(':aa::bb:', ':', 0))
560  call assert_equal(['', 'aa', '', 'bb', ''], split(':aa::bb:', ':', 1))
561  call assert_equal(['aa', '', 'bb', 'cc', ''], split('aa,,bb, cc,', ',\s*', 1))
562  call assert_equal(['a', 'b', 'c'], split('abc', '\zs'))
563  call assert_equal(['', 'a', '', 'b', '', 'c', ''], split('abc', '\zs', 1))
564endfunc
565
566" compare recursively linked list and dict
567func Test_listdict_compare()
568  let l = [1, 2, 3, 4]
569  let d = {'1': 1, '2': l, '3': 3}
570  let l[1] = d
571  call assert_true(l == l)
572  call assert_true(d == d)
573  call assert_false(l != deepcopy(l))
574  call assert_false(d != deepcopy(d))
575endfunc
576
577  " compare complex recursively linked list and dict
578func Test_listdict_compare_complex()
579  let l = []
580  call add(l, l)
581  let dict4 = {"l": l}
582  call add(dict4.l, dict4)
583  let lcopy = deepcopy(l)
584  let dict4copy = deepcopy(dict4)
585  call assert_true(l == lcopy)
586  call assert_true(dict4 == dict4copy)
587endfunc
588
589func Test_listdict_extend()
590  " Pass the same List to extend()
591  let l = [1, 2, 3, 4, 5]
592  call extend(l, l)
593  call assert_equal([1, 2, 3, 4, 5, 1, 2, 3, 4, 5], l)
594
595  " Pass the same Dict to extend()
596  let d = { 'a': {'b': 'B'}}
597  call extend(d, d)
598  call assert_equal({'a': {'b': 'B'}}, d)
599
600  " Pass the same Dict to extend() with "error"
601  call assert_fails("call extend(d, d, 'error')", 'E737:')
602  call assert_equal({'a': {'b': 'B'}}, d)
603endfunc
604