timer_spec.lua 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  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 blocking getchar() call', function()
  88. command("call timer_start(5, 'MyHandler', {'repeat': -1})")
  89. async_meths.nvim_command('let g:val = 0 | let g:c = getchar()')
  90. retry(nil, nil, function()
  91. local val = eval('g:val')
  92. ok(val >= 2, '>= 2', tostring(val))
  93. eq(0, eval('getchar(1)'))
  94. end)
  95. feed('c')
  96. eq(99, eval('g:c'))
  97. end)
  98. it('can invoke redraw in blocking getchar() call', function()
  99. local screen = Screen.new(40, 6)
  100. screen:attach()
  101. screen:set_default_attr_ids({
  102. [1] = { bold = true, foreground = Screen.colors.Blue },
  103. })
  104. api.nvim_buf_set_lines(0, 0, -1, true, { 'ITEM 1', 'ITEM 2' })
  105. source([[
  106. let g:cont = 0
  107. func! AddItem(timer)
  108. if !g:cont
  109. return
  110. endif
  111. call timer_stop(a:timer)
  112. call nvim_buf_set_lines(0, 2, 2, v:true, ['ITEM 3'])
  113. " Meant to test for what Vim tests in Test_peek_and_get_char.
  114. call getchar(1)
  115. redraw
  116. endfunc
  117. ]])
  118. async_meths.nvim_command('let g:c2 = getchar()')
  119. async_meths.nvim_command(
  120. 'call timer_start(' .. load_adjust(100) .. ", 'AddItem', {'repeat': -1})"
  121. )
  122. screen:expect([[
  123. ^ITEM 1 |
  124. ITEM 2 |
  125. {1:~ }|*3
  126. |
  127. ]])
  128. async_meths.nvim_command('let g:cont = 1')
  129. screen:expect([[
  130. ^ITEM 1 |
  131. ITEM 2 |
  132. ITEM 3 |
  133. {1:~ }|*2
  134. |
  135. ]])
  136. feed('3')
  137. eq(51, eval('g:c2'))
  138. screen:expect {
  139. grid = [[
  140. ^ITEM 1 |
  141. ITEM 2 |
  142. ITEM 3 |
  143. {1:~ }|*2
  144. |
  145. ]],
  146. unchanged = true,
  147. }
  148. end)
  149. it('can be stopped', function()
  150. local t_init_val = eval("[timer_start(5, 'MyHandler', {'repeat': -1}), g:val]")
  151. eq(0, t_init_val[2])
  152. run(nil, nil, nil, load_adjust(30))
  153. fn.timer_stop(t_init_val[1])
  154. local count = eval('g:val')
  155. run(nil, load_adjust(300), nil, load_adjust(30))
  156. local count2 = eval('g:val')
  157. -- when count is eval:ed after timer_stop this should be non-racy
  158. eq(count, count2)
  159. end)
  160. it('can be stopped from the handler', function()
  161. source([[
  162. func! MyHandler(timer)
  163. let g:val += 1
  164. if g:val == 3
  165. call timer_stop(a:timer)
  166. " check double stop is ignored
  167. call timer_stop(a:timer)
  168. endif
  169. endfunc
  170. ]])
  171. eq(0, eval('g:val'))
  172. command("call timer_start(10, 'MyHandler', {'repeat': -1})")
  173. retry(nil, nil, function()
  174. eq(3, eval('g:val'))
  175. end)
  176. end)
  177. it('can have two timers', function()
  178. source([[
  179. let g:val2 = 0
  180. func! MyHandler2(timer)
  181. let g:val2 += 1
  182. endfunc
  183. ]])
  184. command("call timer_start(2, 'MyHandler', {'repeat': 3})")
  185. command("call timer_start(4, 'MyHandler2', {'repeat': 2})")
  186. retry(nil, nil, function()
  187. eq(3, eval('g:val'))
  188. eq(2, eval('g:val2'))
  189. end)
  190. end)
  191. it('do not crash when processing events in the handler', function()
  192. source([[
  193. let g:val = 0
  194. func! MyHandler(timer)
  195. call timer_stop(a:timer)
  196. sleep 10m
  197. let g:val += 1
  198. endfunc
  199. ]])
  200. command("call timer_start(5, 'MyHandler', {'repeat': 1})")
  201. run(nil, nil, nil, load_adjust(20))
  202. retry(nil, load_adjust(150), function()
  203. eq(1, eval('g:val'))
  204. end)
  205. end)
  206. it("doesn't mess up the cmdline", function()
  207. local screen = Screen.new(40, 6)
  208. screen:attach()
  209. screen:set_default_attr_ids({ [0] = { bold = true, foreground = 255 } })
  210. source([[
  211. let g:val = 0
  212. func! MyHandler(timer)
  213. while !g:val
  214. return
  215. endwhile
  216. call timer_stop(a:timer)
  217. echo "evil"
  218. redraw
  219. let g:val = 2
  220. endfunc
  221. ]])
  222. command("call timer_start(100, 'MyHandler', {'repeat': -1})")
  223. feed(':good')
  224. screen:expect([[
  225. |
  226. {0:~ }|*4
  227. :good^ |
  228. ]])
  229. command('let g:val = 1')
  230. screen:expect_unchanged(true, load_adjust(200))
  231. eq(2, eval('g:val'))
  232. end)
  233. it("timer_start can't be used in the sandbox", function()
  234. source [[
  235. function! Scary(timer) abort
  236. call execute('echo ''execute() should be disallowed''', '')
  237. endfunction
  238. ]]
  239. eq('Vim(call):E48: Not allowed in sandbox', exc_exec("sandbox call timer_start(0, 'Scary')"))
  240. end)
  241. it('can be triggered after an empty string <expr> mapping #17257', function()
  242. local screen = Screen.new(40, 6)
  243. screen:attach()
  244. command([=[imap <expr> <F2> [timer_start(0, { _ -> execute("throw 'x'", "") }), ''][-1]]=])
  245. feed('i<F2>')
  246. screen:expect({ any = 'E605: Exception not caught: x' })
  247. end)
  248. end)