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