neovim

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

test_timers.vim (12188B)


      1 " Test for timers
      2 
      3 source check.vim
      4 CheckFeature timers
      5 
      6 source screendump.vim
      7 source shared.vim
      8 source term_util.vim
      9 source load.vim
     10 
     11 func SetUp()
     12  call timer_stopall()
     13 endfunc
     14 
     15 func MyHandler(timer)
     16  let g:val += 1
     17 endfunc
     18 
     19 func MyHandlerWithLists(lists, timer)
     20  let x = string(a:lists)
     21 endfunc
     22 
     23 func Test_timer_oneshot()
     24  let g:test_is_flaky = 1
     25  let g:val = 0
     26  let timer = timer_start(50, 'MyHandler')
     27  let slept = WaitFor('g:val == 1')
     28  call assert_equal(1, g:val)
     29  if has('reltime')
     30    call assert_inrange(40, LoadAdjust(120), slept)
     31  else
     32    call assert_inrange(20, 120, slept)
     33  endif
     34 endfunc
     35 
     36 func Test_timer_repeat_three()
     37  let g:test_is_flaky = 1
     38  let g:val = 0
     39  let timer = timer_start(50, 'MyHandler', {'repeat': 3})
     40  let slept = WaitFor('g:val == 3')
     41  call assert_equal(3, g:val)
     42  if has('reltime')
     43    call assert_inrange(120, LoadAdjust(250), slept)
     44  else
     45    call assert_inrange(80, 200, slept)
     46  endif
     47 endfunc
     48 
     49 func Test_timer_repeat_many()
     50  let g:test_is_flaky = 1
     51  let g:val = 0
     52  let timer = timer_start(50, 'MyHandler', {'repeat': -1})
     53  sleep 200m
     54  call timer_stop(timer)
     55  call assert_inrange((has('mac') ? 1 : 2), LoadAdjust(5), g:val)
     56 endfunc
     57 
     58 func Test_timer_with_partial_callback()
     59  let g:test_is_flaky = 1
     60  let g:val = 0
     61  let meow = {'one': 1}
     62  function meow.bite(...)
     63    let g:val += self.one
     64  endfunction
     65 
     66  call timer_start(50, meow.bite)
     67  let slept = WaitFor('g:val == 1')
     68  call assert_equal(1, g:val)
     69  if has('reltime')
     70    call assert_inrange(40, LoadAdjust(130), slept)
     71  else
     72    call assert_inrange(20, 100, slept)
     73  endif
     74 endfunc
     75 
     76 func Test_timer_retain_partial()
     77  call timer_start(50, function('MyHandlerWithLists', [['a']]))
     78  call test_garbagecollect_now()
     79  sleep 100m
     80 endfunc
     81 
     82 func Test_timer_info()
     83  let id = timer_start(1000, 'MyHandler')
     84  let info = id->timer_info()
     85  call assert_equal(id, info[0]['id'])
     86  call assert_equal(1000, info[0]['time'])
     87  call assert_equal("function('MyHandler')", string(info[0]['callback']))
     88 
     89  let found = 0
     90  for info in timer_info()
     91    if info['id'] == id
     92      let found += 1
     93    endif
     94  endfor
     95  call assert_equal(1, found)
     96 
     97  call timer_stop(id)
     98  call assert_equal([], timer_info(id))
     99 
    100  call assert_fails('call timer_info("abc")', 'E1210:')
    101 
    102  " check repeat count inside the callback
    103  let g:timer_repeat = []
    104  let tid = timer_start(10, {tid -> execute("call add(g:timer_repeat, timer_info(tid)[0].repeat)")}, #{repeat: 3})
    105  call WaitForAssert({-> assert_equal([2, 1, 0], g:timer_repeat)})
    106  unlet g:timer_repeat
    107 endfunc
    108 
    109 func Test_timer_stopall()
    110  let id1 = timer_start(1000, 'MyHandler')
    111  let id2 = timer_start(2000, 'MyHandler')
    112  let info = timer_info()
    113  call assert_equal(2, len(info))
    114 
    115  call timer_stopall()
    116  let info = timer_info()
    117  call assert_equal(0, len(info))
    118 endfunc
    119 
    120 func Test_timer_paused()
    121  let g:test_is_flaky = 1
    122  let g:val = 0
    123 
    124  let id = timer_start(50, 'MyHandler')
    125  let info = timer_info(id)
    126  call assert_equal(0, info[0]['paused'])
    127 
    128  eval id->timer_pause(1)
    129  let info = timer_info(id)
    130  call assert_equal(1, info[0]['paused'])
    131  sleep 200m
    132  call assert_equal(0, g:val)
    133 
    134  call timer_pause(id, 0)
    135  let info = timer_info(id)
    136  call assert_equal(0, info[0]['paused'])
    137 
    138  let slept = WaitFor('g:val == 1')
    139  call assert_equal(1, g:val)
    140  if has('reltime')
    141    call assert_inrange(0, LoadAdjust(140), slept)
    142  else
    143    call assert_inrange(0, 10, slept)
    144  endif
    145 
    146  call assert_fails('call timer_pause("abc", 1)', 'E39:')
    147 endfunc
    148 
    149 func StopMyself(timer)
    150  let g:called += 1
    151  if g:called == 2
    152    call timer_stop(a:timer)
    153  endif
    154 endfunc
    155 
    156 func Test_timer_delete_myself()
    157  let g:called = 0
    158  let t = timer_start(10, 'StopMyself', {'repeat': -1})
    159  call WaitForAssert({-> assert_equal(2, g:called)})
    160  call assert_equal(2, g:called)
    161  call assert_equal([], timer_info(t))
    162 endfunc
    163 
    164 func StopTimer1(timer)
    165  let g:timer2 = 10->timer_start('StopTimer2')
    166  " avoid maxfuncdepth error
    167  call timer_pause(g:timer1, 1)
    168  sleep 20m
    169 endfunc
    170 
    171 func StopTimer2(timer)
    172  call timer_stop(g:timer1)
    173 endfunc
    174 
    175 func Test_timer_stop_in_callback()
    176  let g:test_is_flaky = 1
    177  call assert_equal(0, len(timer_info()))
    178  let g:timer1 = timer_start(10, 'StopTimer1')
    179  let slept = 0
    180  for i in range(10)
    181    if len(timer_info()) == 0
    182      break
    183    endif
    184    sleep 10m
    185    let slept += 10
    186  endfor
    187  " This should take only 30 msec, but on Mac it's often longer
    188  call assert_inrange(0, 50, slept)
    189 endfunc
    190 
    191 func StopTimerAll(timer)
    192  call timer_stopall()
    193 endfunc
    194 
    195 func Test_timer_stop_all_in_callback()
    196  let g:test_is_flaky = 1
    197  call assert_equal(0, len(timer_info()))
    198  call timer_start(10, 'StopTimerAll')
    199  call assert_equal(1, len(timer_info()))
    200  let slept = 0
    201  for i in range(10)
    202    if len(timer_info()) == 0
    203      break
    204    endif
    205    sleep 10m
    206    let slept += 10
    207  endfor
    208  call assert_inrange(0, 30, slept)
    209 endfunc
    210 
    211 func FeedkeysCb(timer)
    212  call feedkeys("hello\<CR>", 'nt')
    213 endfunc
    214 
    215 func InputCb(timer)
    216  call timer_start(10, 'FeedkeysCb')
    217  let g:val = input('?')
    218  call Resume()
    219 endfunc
    220 
    221 func Test_timer_input_in_timer()
    222  let g:val = ''
    223  call timer_start(10, 'InputCb')
    224  call Standby(1000)
    225  call assert_equal('hello', g:val)
    226 endfunc
    227 
    228 func FuncWithError(timer)
    229  let g:call_count += 1
    230  if g:call_count == 4
    231    return
    232  endif
    233  doesnotexist
    234 endfunc
    235 
    236 func Test_timer_errors()
    237  let g:call_count = 0
    238  let timer = timer_start(10, 'FuncWithError', {'repeat': -1})
    239  " Timer will be stopped after failing 3 out of 3 times.
    240  call WaitForAssert({-> assert_equal(3, g:call_count)})
    241  sleep 50m
    242  call assert_equal(3, g:call_count)
    243 
    244  call assert_fails('call timer_start(100, "MyHandler", "abc")', 'E1206:')
    245  call assert_fails('call timer_start(100, [])', 'E921:')
    246  call assert_fails('call timer_stop("abc")', 'E1210:')
    247 endfunc
    248 
    249 func FuncWithCaughtError(timer)
    250  let g:call_count += 1
    251  try
    252    doesnotexist
    253  catch
    254    " nop
    255  endtry
    256 endfunc
    257 
    258 func Test_timer_catch_error()
    259  let g:call_count = 0
    260  let timer = timer_start(10, 'FuncWithCaughtError', {'repeat': 4})
    261  " Timer will not be stopped.
    262  call WaitForAssert({-> assert_equal(4, g:call_count)})
    263  sleep 50m
    264  call assert_equal(4, g:call_count)
    265 endfunc
    266 
    267 func FeedAndPeek(timer)
    268  " call test_feedinput('a')
    269  call nvim_input('a')
    270  call getchar(1)
    271 endfunc
    272 
    273 func Interrupt(timer)
    274  " eval "\<C-C>"->test_feedinput()
    275  call nvim_input("\<C-C>")
    276 endfunc
    277 
    278 func Test_timer_peek_and_get_char()
    279  if !has('unix') && !has('gui_running')
    280    throw 'Skipped: cannot feed low-level input'
    281  endif
    282 
    283  call timer_start(0, 'FeedAndPeek')
    284  let intr = timer_start(100, 'Interrupt')
    285  let c = getchar()
    286  call assert_equal(char2nr('a'), c)
    287  eval intr->timer_stop()
    288 endfunc
    289 
    290 func Test_timer_getchar_zero()
    291  if has('win32') && !has('gui_running')
    292    throw 'Skipped: cannot feed low-level input'
    293  endif
    294  CheckFunction reltimefloat
    295 
    296  " Measure the elapsed time to avoid a hang when it fails.
    297  let start = reltime()
    298  let id = timer_start(20, {-> feedkeys('x', 'L')})
    299  let c = 0
    300  while c == 0 && reltimefloat(reltime(start)) < 0.2
    301    let c = getchar(0)
    302    sleep 10m
    303  endwhile
    304  call assert_equal('x', nr2char(c))
    305  call timer_stop(id)
    306 endfunc
    307 
    308 func Test_timer_ex_mode()
    309  " Function with an empty line.
    310  func Foo(...)
    311 
    312  endfunc
    313  let timer = timer_start(40, function('g:Foo'), {'repeat':-1})
    314  " This used to throw error E749.
    315  exe "normal Qsleep 100m\rvi\r"
    316  call timer_stop(timer)
    317 endfunc
    318 
    319 func Test_timer_restore_count()
    320  CheckRunVimInTerminal
    321  " Check that v:count is saved and restored, not changed by a timer.
    322  call writefile([
    323        \ 'nnoremap <expr><silent> L v:count ? v:count . "l" : "l"',
    324        \ 'func Doit(id)',
    325        \ '  normal 3j',
    326        \ 'endfunc',
    327        \ 'call timer_start(100, "Doit")',
    328 \ ], 'Xtrcscript')
    329  call writefile([
    330        \ '1-1234',
    331        \ '2-1234',
    332        \ '3-1234',
    333 \ ], 'Xtrctext')
    334  let buf = RunVimInTerminal('-S Xtrcscript Xtrctext', {})
    335 
    336  " Wait for the timer to move the cursor to the third line.
    337  call WaitForAssert({-> assert_equal(3, term_getcursor(buf)[0])})
    338  call assert_equal(1, term_getcursor(buf)[1])
    339  " Now check that v:count has not been set to 3
    340  call term_sendkeys(buf, 'L')
    341  call WaitForAssert({-> assert_equal(2, term_getcursor(buf)[1])})
    342 
    343  call StopVimInTerminal(buf)
    344  call delete('Xtrcscript')
    345  call delete('Xtrctext')
    346 endfunc
    347 
    348 " Test that the garbage collector isn't triggered if a timer callback invokes
    349 " vgetc().
    350 func Test_nocatch_timer_garbage_collect()
    351  " FIXME: why does this fail only on MacOS M1?
    352  try
    353    CheckNotMacM1
    354    throw 'Skipped: Nvim does not support test_garbagecollect_soon(), test_override()'
    355  catch /Skipped/
    356    let g:skipped_reason = v:exception
    357    return
    358  endtry
    359 
    360  " 'uptimetime. must be bigger than the timer timeout
    361  set ut=200
    362  call test_garbagecollect_soon()
    363  call test_override('no_wait_return', 0)
    364  func CauseAnError(id)
    365    " This will show an error and wait for Enter.
    366    let a = {'foo', 'bar'}
    367  endfunc
    368  func FeedChar(id)
    369    call feedkeys(":\<CR>", 't')
    370  endfunc
    371  call timer_start(300, 'FeedChar')
    372  call timer_start(100, 'CauseAnError')
    373  let x = getchar()   " wait for error in timer
    374  let x = getchar(0)  " read any remaining chars
    375  let x = getchar(0)
    376 
    377  set ut&
    378  call test_override('no_wait_return', 1)
    379  delfunc CauseAnError
    380  delfunc FeedChar
    381 endfunc
    382 
    383 func Test_timer_error_in_timer_callback()
    384  if !has('terminal') || (has('win32') && has('gui_running'))
    385    throw 'Skipped: cannot run Vim in a terminal window'
    386  endif
    387 
    388  let lines =<< trim [CODE]
    389  func Func(timer)
    390    " fail to create list
    391    let x = [
    392  endfunc
    393  set updatetime=50
    394  call timer_start(1, 'Func')
    395  [CODE]
    396  call writefile(lines, 'Xtest.vim')
    397 
    398  let buf = term_start(GetVimCommandCleanTerm() .. ' -S Xtest.vim', {'term_rows': 8})
    399  let job = term_getjob(buf)
    400  call WaitForAssert({-> assert_notequal('', term_getline(buf, 8))})
    401 
    402  " GC must not run during timer callback, which can make Vim crash.
    403  call TermWait(buf, 50)
    404  call term_sendkeys(buf, "\<CR>")
    405  call TermWait(buf, 50)
    406  call assert_equal('run', job_status(job))
    407 
    408  call term_sendkeys(buf, ":qall!\<CR>")
    409  call WaitFor({-> job_status(job) ==# 'dead'})
    410  if has('unix')
    411    call assert_equal('', job_info(job).termsig)
    412  endif
    413 
    414  call delete('Xtest.vim')
    415  exe buf .. 'bwipe!'
    416 endfunc
    417 
    418 " Test for garbage collection when a timer is still running
    419 func Test_timer_garbage_collect()
    420  let timer = timer_start(1000, function('MyHandler'), {'repeat' : 10})
    421  call test_garbagecollect_now()
    422  let l = timer_info(timer)
    423  call assert_equal(function('MyHandler'), l[0].callback)
    424  call timer_stop(timer)
    425 endfunc
    426 
    427 func Test_timer_invalid_callback()
    428  call assert_fails('call timer_start(0, "0")', 'E921')
    429 endfunc
    430 
    431 func Test_timer_changing_function_list()
    432  CheckRunVimInTerminal
    433 
    434  " Create a large number of functions.  Should get the "more" prompt.
    435  " The typing "G" triggers the timer, which changes the function table.
    436  let lines =<< trim END
    437    for func in map(range(1,99), "'Func' .. v:val")
    438      exe "func " .. func .. "()"
    439      endfunc
    440    endfor
    441    au CmdlineLeave : call timer_start(0, {-> 0})
    442  END
    443  call writefile(lines, 'XTest_timerchange')
    444  let buf = RunVimInTerminal('-S XTest_timerchange', #{rows: 10})
    445  call term_sendkeys(buf, ":fu\<CR>")
    446  call WaitForAssert({-> assert_match('-- More --', term_getline(buf, 10))})
    447  call term_sendkeys(buf, "G")
    448  call WaitForAssert({-> assert_match('E454', term_getline(buf, 9))})
    449  call term_sendkeys(buf, "\<Esc>")
    450 
    451  call StopVimInTerminal(buf)
    452  call delete('XTest_timerchange')
    453 endfunc
    454 
    455 func Test_timer_using_win_execute_undo_sync()
    456  let bufnr1 = bufnr()
    457  new
    458  let g:bufnr2 = bufnr()
    459  let g:winid = win_getid()
    460  exe "buffer " .. bufnr1
    461  wincmd w
    462  call setline(1, ['test'])
    463  autocmd InsertEnter * call timer_start(100, { -> win_execute(g:winid, 'buffer ' .. g:bufnr2) })
    464  call timer_start(200, { -> feedkeys("\<CR>bbbb\<Esc>") })
    465  call feedkeys("Oaaaa", 'x!t')
    466  " will hang here until the second timer fires
    467  call assert_equal(['aaaa', 'bbbb', 'test'], getline(1, '$'))
    468  undo
    469  call assert_equal(['test'], getline(1, '$'))
    470 
    471  bwipe!
    472  bwipe!
    473  unlet g:winid
    474  unlet g:bufnr2
    475  au! InsertEnter
    476 endfunc
    477 
    478 " vim: shiftwidth=2 sts=2 expandtab