neovim

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

test_lambda.vim (7335B)


      1 " Test for lambda and closure
      2 
      3 func Test_lambda_feature()
      4  call assert_equal(1, has('lambda'))
      5 endfunc
      6 
      7 func Test_lambda_with_filter()
      8  let s:x = 2
      9  call assert_equal([2, 3], filter([1, 2, 3], {i, v -> v >= s:x}))
     10 endfunc
     11 
     12 func Test_lambda_with_map()
     13  let s:x = 1
     14  call assert_equal([2, 3, 4], map([1, 2, 3], {i, v -> v + s:x}))
     15 endfunc
     16 
     17 func Test_lambda_with_sort()
     18  call assert_equal([1, 2, 3, 4, 7], sort([3,7,2,1,4], {a, b -> a - b}))
     19 endfunc
     20 
     21 func Test_lambda_with_timer()
     22  if !has('timers')
     23    return
     24  endif
     25 
     26  let s:n = 0
     27  let s:timer_id = 0
     28  func! s:Foo()
     29    let s:timer_id = timer_start(10, {-> execute("let s:n += 1 | echo s:n", "")}, {"repeat": -1})
     30  endfunc
     31 
     32  call s:Foo()
     33  " check timer works
     34  for i in range(0, 10)
     35    if s:n > 0
     36      break
     37    endif
     38    sleep 10m
     39  endfor
     40 
     41  " do not collect lambda
     42  call test_garbagecollect_now()
     43 
     44  " check timer still works
     45  let m = s:n
     46  for i in range(0, 10)
     47    if s:n > m
     48      break
     49    endif
     50    sleep 10m
     51  endfor
     52 
     53  call timer_stop(s:timer_id)
     54  call assert_true(s:n > m)
     55 endfunc
     56 
     57 func Test_lambda_with_partial()
     58  let l:Cb = function({... -> ['zero', a:1, a:2, a:3]}, ['one', 'two'])
     59  call assert_equal(['zero', 'one', 'two', 'three'], l:Cb('three'))
     60 endfunc
     61 
     62 function Test_lambda_fails()
     63  call assert_equal(3, {a, b -> a + b}(1, 2))
     64  call assert_fails('echo {a, a -> a + a}(1, 2)', 'E853:')
     65  call assert_fails('echo {a, b -> a + b)}(1, 2)', 'E451:')
     66  echo assert_fails('echo 10->{a -> a + 2}', 'E107:')
     67 endfunc
     68 
     69 func Test_not_lambda()
     70  let x = {'>' : 'foo'}
     71  call assert_equal('foo', x['>'])
     72 endfunc
     73 
     74 func Test_lambda_capture_by_reference()
     75  let v = 1
     76  let l:F = {x -> x + v}
     77  let v = 2
     78  call assert_equal(12, l:F(10))
     79 endfunc
     80 
     81 func Test_lambda_side_effect()
     82  func! s:update_and_return(arr)
     83    let a:arr[1] = 5
     84    return a:arr
     85  endfunc
     86 
     87  func! s:foo(arr)
     88    return {-> s:update_and_return(a:arr)}
     89  endfunc
     90 
     91  let arr = [3,2,1]
     92  call assert_equal([3, 5, 1], s:foo(arr)())
     93 endfunc
     94 
     95 func Test_lambda_refer_local_variable_from_other_scope()
     96  func! s:foo(X)
     97    return a:X() " refer l:x in s:bar()
     98  endfunc
     99 
    100  func! s:bar()
    101    let x = 123
    102    return s:foo({-> x})
    103  endfunc
    104 
    105  call assert_equal(123, s:bar())
    106 endfunc
    107 
    108 func Test_lambda_do_not_share_local_variable()
    109  func! s:define_funcs()
    110    let l:One = {-> split(execute("let a = 'abc' | echo a"))[0]}
    111    let l:Two = {-> exists("a") ? a : "no"}
    112    return [l:One, l:Two]
    113  endfunc
    114 
    115  let l:F = s:define_funcs()
    116 
    117  call assert_equal('no', l:F[1]())
    118  call assert_equal('abc', l:F[0]())
    119  call assert_equal('no', l:F[1]())
    120 endfunc
    121 
    122 func Test_lambda_closure_counter()
    123  func! s:foo()
    124    let x = 0
    125    return {-> [execute("let x += 1"), x][-1]}
    126  endfunc
    127 
    128  let l:F = s:foo()
    129  call test_garbagecollect_now()
    130  call assert_equal(1, l:F())
    131  call assert_equal(2, l:F())
    132  call assert_equal(3, l:F())
    133  call assert_equal(4, l:F())
    134 endfunc
    135 
    136 func Test_lambda_with_a_var()
    137  func! s:foo()
    138    let x = 2
    139    return {... -> a:000 + [x]}
    140  endfunc
    141  func! s:bar()
    142    return s:foo()(1)
    143  endfunc
    144 
    145  call assert_equal([1, 2], s:bar())
    146 endfunc
    147 
    148 func Test_lambda_call_lambda_from_lambda()
    149  func! s:foo(x)
    150    let l:F1 = {-> {-> a:x}}
    151    return {-> l:F1()}
    152  endfunc
    153 
    154  let l:F = s:foo(1)
    155  call assert_equal(1, l:F()())
    156 endfunc
    157 
    158 func Test_lambda_delfunc()
    159  func! s:gen()
    160    let pl = l:
    161    let l:Foo = {-> get(pl, "Foo", get(pl, "Bar", {-> 0}))}
    162    let l:Bar = l:Foo
    163    delfunction l:Foo
    164    return l:Bar
    165  endfunc
    166 
    167  let l:F = s:gen()
    168  call assert_fails(':call l:F()', 'E933:')
    169 endfunc
    170 
    171 func Test_lambda_scope()
    172  func! s:NewCounter()
    173    let c = 0
    174    return {-> [execute('let c += 1'), c][-1]}
    175  endfunc
    176 
    177  func! s:NewCounter2()
    178    return {-> [execute('let c += 100'), c][-1]}
    179  endfunc
    180 
    181  let l:C = s:NewCounter()
    182  let l:D = s:NewCounter2()
    183 
    184  call assert_equal(1, l:C())
    185  call assert_fails(':call l:D()', 'E121:')
    186  call assert_equal(2, l:C())
    187 endfunc
    188 
    189 func Test_lambda_share_scope()
    190  func! s:New()
    191    let c = 0
    192    let l:Inc0 = {-> [execute('let c += 1'), c][-1]}
    193    let l:Dec0 = {-> [execute('let c -= 1'), c][-1]}
    194    return [l:Inc0, l:Dec0]
    195  endfunc
    196 
    197  let [l:Inc, l:Dec] = s:New()
    198 
    199  call assert_equal(1, l:Inc())
    200  call assert_equal(2, l:Inc())
    201  call assert_equal(1, l:Dec())
    202 endfunc
    203 
    204 func Test_lambda_circular_reference()
    205  func! s:Foo()
    206    let d = {}
    207    let d.f = {-> d}
    208    return d.f
    209  endfunc
    210 
    211  call s:Foo()
    212  call test_garbagecollect_now()
    213  let i = 0 | while i < 10000 | call s:Foo() | let i+= 1 | endwhile
    214  call test_garbagecollect_now()
    215 endfunc
    216 
    217 func Test_lambda_combination()
    218  call assert_equal(2, {x -> {x -> x}}(1)(2))
    219  call assert_equal(10, {y -> {x -> x(y)(10)}({y -> y})}({z -> z}))
    220  if has('float')
    221    call assert_equal(5.0, {x -> {y -> x / y}}(10)(2.0))
    222  endif
    223  call assert_equal(6, {x -> {y -> {z -> x + y + z}}}(1)(2)(3))
    224 
    225  call assert_equal(6, {x -> {f -> f(x)}}(3)({x -> x * 2}))
    226  call assert_equal(6, {f -> {x -> f(x)}}({x -> x * 2})(3))
    227 
    228  " Z combinator
    229  let Z = {f -> {x -> f({y -> x(x)(y)})}({x -> f({y -> x(x)(y)})})}
    230  let Fact = {f -> {x -> x == 0 ? 1 : x * f(x - 1)}}
    231  call assert_equal(120, Z(Fact)(5))
    232 endfunc
    233 
    234 func Test_closure_counter()
    235  func! s:foo()
    236    let x = 0
    237    func! s:bar() closure
    238      let x += 1
    239      return x
    240    endfunc
    241    return function('s:bar')
    242  endfunc
    243 
    244  let l:F = s:foo()
    245  call test_garbagecollect_now()
    246  call assert_equal(1, l:F())
    247  call assert_equal(2, l:F())
    248  call assert_equal(3, l:F())
    249  call assert_equal(4, l:F())
    250 
    251  call assert_match("^\n   function <SNR>\\d\\+_bar() closure"
    252  \              .. "\n1        let x += 1"
    253  \              .. "\n2        return x"
    254  \              .. "\n   endfunction$", execute('func s:bar'))
    255 endfunc
    256 
    257 func Test_closure_unlet()
    258  func! s:foo()
    259    let x = 1
    260    func! s:bar() closure
    261      unlet x
    262    endfunc
    263    call s:bar()
    264    return l:
    265  endfunc
    266 
    267  call assert_false(has_key(s:foo(), 'x'))
    268  call test_garbagecollect_now()
    269 endfunc
    270 
    271 func LambdaFoo()
    272  let x = 0
    273  func! LambdaBar() closure
    274    let x += 1
    275    return x
    276  endfunc
    277  return function('LambdaBar')
    278 endfunc
    279 
    280 func Test_closure_refcount()
    281  let g:Count = LambdaFoo()
    282  call test_garbagecollect_now()
    283  call assert_equal(1, g:Count())
    284  let g:Count2 = LambdaFoo()
    285  call test_garbagecollect_now()
    286  call assert_equal(1, g:Count2())
    287  call assert_equal(2, g:Count())
    288  call assert_equal(3, g:Count2())
    289 
    290  delfunc LambdaFoo
    291  delfunc LambdaBar
    292 endfunc
    293 
    294 " This test is causing a use-after-free on shutdown.
    295 func Test_named_function_closure()
    296  func! Afoo()
    297    let x = 14
    298    func! s:Abar() closure
    299      return x
    300    endfunc
    301    call assert_equal(14, s:Abar())
    302  endfunc
    303  call Afoo()
    304  call assert_equal(14, s:Abar())
    305  call test_garbagecollect_now()
    306  call assert_equal(14, s:Abar())
    307 endfunc
    308 
    309 func Test_lambda_with_index()
    310  let List = {x -> [x]}
    311  let Extract = {-> function(List, ['foobar'])()[0]}
    312  call assert_equal('foobar', Extract())
    313 endfunc
    314 
    315 func Test_lambda_error()
    316  " This was causing a crash
    317  call assert_fails('ec{@{->{d->()()', 'E15')
    318 endfunc
    319 
    320 func Test_closure_error()
    321  let l =<< trim END
    322    func F1() closure
    323      return 1
    324    endfunc
    325  END
    326  call writefile(l, 'Xscript')
    327  let caught_932 = 0
    328  try
    329    source Xscript
    330  catch /E932:/
    331    let caught_932 = 1
    332  endtry
    333  call assert_equal(1, caught_932)
    334  call delete('Xscript')
    335 endfunc
    336 
    337 " vim: shiftwidth=2 sts=2 expandtab