timer_spec.lua 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  1. local t = require('test.testutil')
  2. local n = require('test.functional.testnvim')()
  3. local Screen = require('test.functional.ui.screen')
  4. local feed, eq, eval, ok = n.feed, t.eq, n.eval, t.ok
  5. local source, async_meths, run = n.source, n.async_meths, n.run
  6. local clear, command, fn = n.clear, n.command, n.fn
  7. local exc_exec = n.exc_exec
  8. local api = n.api
  9. local load_adjust = n.load_adjust
  10. local retry = t.retry
  11. describe('timers', function()
  12. before_each(function()
  13. clear()
  14. source([[
  15. let g:val = 0
  16. func MyHandler(timer)
  17. let g:val += 1
  18. endfunc
  19. ]])
  20. end)
  21. it('works one-shot', function()
  22. eq(0, eval("[timer_start(10, 'MyHandler'), g:val][1]"))
  23. run(nil, nil, nil, load_adjust(100))
  24. eq(1, eval('g:val'))
  25. end)
  26. it('works one-shot when repeat=0', function()
  27. eq(0, eval("[timer_start(10, 'MyHandler', {'repeat': 0}), g:val][1]"))
  28. run(nil, nil, nil, load_adjust(100))
  29. eq(1, eval('g:val'))
  30. end)
  31. it('works with repeat two', function()
  32. eq(0, eval("[timer_start(10, 'MyHandler', {'repeat': 2}), g:val][1]"))
  33. run(nil, nil, nil, load_adjust(20))
  34. retry(nil, load_adjust(300), function()
  35. eq(2, eval('g:val'))
  36. end)
  37. end)
  38. it('are triggered during sleep', function()
  39. source([[
  40. let g:val = -1
  41. func! MyHandler(timer)
  42. if g:val >= 0
  43. let g:val += 1
  44. if g:val == 2
  45. call timer_stop(a:timer)
  46. endif
  47. endif
  48. endfunc
  49. ]])
  50. eval("timer_start(10, 'MyHandler', {'repeat': -1})")
  51. async_meths.nvim_command('sleep 10')
  52. eq(-1, eval('g:val')) -- timer did nothing yet.
  53. async_meths.nvim_command('let g:val = 0')
  54. run(nil, nil, nil, load_adjust(20))
  55. retry(nil, nil, function()
  56. eq(2, eval('g:val'))
  57. end)
  58. end)
  59. it('works with zero timeout', function()
  60. -- timer_start does still not invoke the callback immediately
  61. eq(0, eval("[timer_start(0, 'MyHandler', {'repeat': 1000}), g:val][1]"))
  62. retry(nil, nil, function()
  63. eq(1000, eval('g:val'))
  64. end)
  65. end)
  66. it('can be started during sleep', function()
  67. async_meths.nvim_command('sleep 10')
  68. -- this also tests that remote requests works during sleep
  69. eq(0, eval("[timer_start(10, 'MyHandler', {'repeat': 2}), g:val][1]"))
  70. run(nil, nil, nil, load_adjust(20))
  71. retry(nil, load_adjust(300), function()
  72. eq(2, eval('g:val'))
  73. end)
  74. end)
  75. it('are paused when event processing is disabled', function()
  76. command("call timer_start(5, 'MyHandler', {'repeat': -1})")
  77. run(nil, nil, nil, load_adjust(10))
  78. local count = eval('g:val')
  79. -- shows two line error message and thus invokes the return prompt.
  80. -- if we start to allow event processing here, we need to change this test.
  81. feed(':throw "fatal error"<CR>')
  82. run(nil, nil, nil, load_adjust(30))
  83. feed('<cr>')
  84. local diff = eval('g:val') - count
  85. assert(0 <= diff and diff <= 4, 'expected (0 <= diff <= 4), got: ' .. tostring(diff))
  86. end)
  87. it('are triggered in inputlist() call #7857', function()
  88. async_meths.nvim_exec2(
  89. [[
  90. call timer_start(5, 'MyHandler', {'repeat': -1})
  91. let g:val = 0
  92. let g:n = inputlist(['input0', 'input1'])
  93. ]],
  94. {}
  95. )
  96. retry(nil, nil, function()
  97. local val = eval('g:val')
  98. ok(val >= 2, '>= 2', tostring(val))
  99. eq(0, eval("exists('g:n')"))
  100. end)
  101. feed('42<CR>')
  102. eq(42, eval('g:n'))
  103. end)
  104. it('are triggered in confirm() call', function()
  105. api.nvim_ui_attach(80, 24, {}) -- needed for confirm() to work
  106. async_meths.nvim_exec2(
  107. [[
  108. call timer_start(5, 'MyHandler', {'repeat': -1})
  109. let g:val = 0
  110. let g:n = confirm('Are you sure?', "&Yes\n&No\n&Cancel")
  111. ]],
  112. {}
  113. )
  114. retry(nil, nil, function()
  115. local val = eval('g:val')
  116. ok(val >= 2, '>= 2', tostring(val))
  117. eq(0, eval("exists('g:n')"))
  118. end)
  119. feed('c')
  120. eq(3, eval('g:n'))
  121. end)
  122. it('are triggered in blocking getchar() call', function()
  123. async_meths.nvim_exec2(
  124. [[
  125. call timer_start(5, 'MyHandler', {'repeat': -1})
  126. let g:val = 0
  127. let g:c = getchar()
  128. ]],
  129. {}
  130. )
  131. retry(nil, nil, function()
  132. local val = eval('g:val')
  133. ok(val >= 2, '>= 2', tostring(val))
  134. eq(0, eval("exists('g:c')"))
  135. eq(0, eval('getchar(1)'))
  136. end)
  137. feed('c')
  138. eq(99, eval('g:c'))
  139. end)
  140. it('can invoke redraw in blocking getchar() call', function()
  141. local screen = Screen.new(40, 6)
  142. api.nvim_buf_set_lines(0, 0, -1, true, { 'ITEM 1', 'ITEM 2' })
  143. source([[
  144. let g:cont = 0
  145. func! AddItem(timer)
  146. if !g:cont
  147. return
  148. endif
  149. call timer_stop(a:timer)
  150. call nvim_buf_set_lines(0, 2, 2, v:true, ['ITEM 3'])
  151. " Meant to test for what Vim tests in Test_peek_and_get_char.
  152. call getchar(1)
  153. redraw
  154. endfunc
  155. ]])
  156. async_meths.nvim_command("let g:c2 = getchar(-1, {'cursor': 'msg'})")
  157. async_meths.nvim_command(
  158. 'call timer_start(' .. load_adjust(100) .. ", 'AddItem', {'repeat': -1})"
  159. )
  160. screen:expect([[
  161. ITEM 1 |
  162. ITEM 2 |
  163. {1:~ }|*3
  164. ^ |
  165. ]])
  166. async_meths.nvim_command('let g:cont = 1')
  167. screen:expect([[
  168. ITEM 1 |
  169. ITEM 2 |
  170. ITEM 3 |
  171. {1:~ }|*2
  172. ^ |
  173. ]])
  174. feed('3')
  175. eq(51, eval('g:c2'))
  176. screen:expect([[
  177. ^ITEM 1 |
  178. ITEM 2 |
  179. ITEM 3 |
  180. {1:~ }|*2
  181. |
  182. ]])
  183. end)
  184. it('can be stopped', function()
  185. local t_init_val = eval("[timer_start(5, 'MyHandler', {'repeat': -1}), g:val]")
  186. eq(0, t_init_val[2])
  187. run(nil, nil, nil, load_adjust(30))
  188. fn.timer_stop(t_init_val[1])
  189. local count = eval('g:val')
  190. run(nil, load_adjust(300), nil, load_adjust(30))
  191. local count2 = eval('g:val')
  192. -- when count is eval:ed after timer_stop this should be non-racy
  193. eq(count, count2)
  194. end)
  195. it('can be stopped from the handler', function()
  196. source([[
  197. func! MyHandler(timer)
  198. let g:val += 1
  199. if g:val == 3
  200. call timer_stop(a:timer)
  201. " check double stop is ignored
  202. call timer_stop(a:timer)
  203. endif
  204. endfunc
  205. ]])
  206. eq(0, eval('g:val'))
  207. command("call timer_start(10, 'MyHandler', {'repeat': -1})")
  208. retry(nil, nil, function()
  209. eq(3, eval('g:val'))
  210. end)
  211. end)
  212. it('can have two timers', function()
  213. source([[
  214. let g:val2 = 0
  215. func! MyHandler2(timer)
  216. let g:val2 += 1
  217. endfunc
  218. ]])
  219. command("call timer_start(2, 'MyHandler', {'repeat': 3})")
  220. command("call timer_start(4, 'MyHandler2', {'repeat': 2})")
  221. retry(nil, nil, function()
  222. eq(3, eval('g:val'))
  223. eq(2, eval('g:val2'))
  224. end)
  225. end)
  226. it('do not crash when processing events in the handler', function()
  227. source([[
  228. let g:val = 0
  229. func! MyHandler(timer)
  230. call timer_stop(a:timer)
  231. sleep 10m
  232. let g:val += 1
  233. endfunc
  234. ]])
  235. command("call timer_start(5, 'MyHandler', {'repeat': 1})")
  236. run(nil, nil, nil, load_adjust(20))
  237. retry(nil, load_adjust(150), function()
  238. eq(1, eval('g:val'))
  239. end)
  240. end)
  241. it("doesn't mess up the cmdline", function()
  242. local screen = Screen.new(40, 6)
  243. source([[
  244. let g:val = 0
  245. func! MyHandler(timer)
  246. while !g:val
  247. return
  248. endwhile
  249. call timer_stop(a:timer)
  250. echo "evil"
  251. redraw
  252. let g:val = 2
  253. endfunc
  254. ]])
  255. command("call timer_start(100, 'MyHandler', {'repeat': -1})")
  256. feed(':good')
  257. screen:expect([[
  258. |
  259. {1:~ }|*4
  260. :good^ |
  261. ]])
  262. command('let g:val = 1')
  263. screen:expect_unchanged(true, load_adjust(200))
  264. eq(2, eval('g:val'))
  265. end)
  266. it("timer_start can't be used in the sandbox", function()
  267. source [[
  268. function! Scary(timer) abort
  269. call execute('echo ''execute() should be disallowed''', '')
  270. endfunction
  271. ]]
  272. eq('Vim(call):E48: Not allowed in sandbox', exc_exec("sandbox call timer_start(0, 'Scary')"))
  273. end)
  274. it('can be triggered after an empty string <expr> mapping #17257', function()
  275. local screen = Screen.new(40, 6)
  276. command([=[imap <expr> <F2> [timer_start(0, { _ -> execute("throw 'x'", "") }), ''][-1]]=])
  277. feed('i<F2>')
  278. screen:expect({ any = 'E605: Exception not caught: x' })
  279. end)
  280. end)