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