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