123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269 |
- local t = require('test.testutil')
- local n = require('test.functional.testnvim')()
- local Screen = require('test.functional.ui.screen')
- local feed, eq, eval, ok = n.feed, t.eq, n.eval, t.ok
- local source, async_meths, run = n.source, n.async_meths, n.run
- local clear, command, fn = n.clear, n.command, n.fn
- local exc_exec = n.exc_exec
- local api = n.api
- local load_adjust = n.load_adjust
- local retry = t.retry
- describe('timers', function()
- before_each(function()
- clear()
- source([[
- let g:val = 0
- func MyHandler(timer)
- let g:val += 1
- endfunc
- ]])
- end)
- it('works one-shot', function()
- eq(0, eval("[timer_start(10, 'MyHandler'), g:val][1]"))
- run(nil, nil, nil, load_adjust(100))
- eq(1, eval('g:val'))
- end)
- it('works one-shot when repeat=0', function()
- eq(0, eval("[timer_start(10, 'MyHandler', {'repeat': 0}), g:val][1]"))
- run(nil, nil, nil, load_adjust(100))
- eq(1, eval('g:val'))
- end)
- it('works with repeat two', function()
- eq(0, eval("[timer_start(10, 'MyHandler', {'repeat': 2}), g:val][1]"))
- run(nil, nil, nil, load_adjust(20))
- retry(nil, load_adjust(300), function()
- eq(2, eval('g:val'))
- end)
- end)
- it('are triggered during sleep', function()
- source([[
- let g:val = -1
- func! MyHandler(timer)
- if g:val >= 0
- let g:val += 1
- if g:val == 2
- call timer_stop(a:timer)
- endif
- endif
- endfunc
- ]])
- eval("timer_start(10, 'MyHandler', {'repeat': -1})")
- async_meths.nvim_command('sleep 10')
- eq(-1, eval('g:val')) -- timer did nothing yet.
- async_meths.nvim_command('let g:val = 0')
- run(nil, nil, nil, load_adjust(20))
- retry(nil, nil, function()
- eq(2, eval('g:val'))
- end)
- end)
- it('works with zero timeout', function()
- -- timer_start does still not invoke the callback immediately
- eq(0, eval("[timer_start(0, 'MyHandler', {'repeat': 1000}), g:val][1]"))
- retry(nil, nil, function()
- eq(1000, eval('g:val'))
- end)
- end)
- it('can be started during sleep', function()
- async_meths.nvim_command('sleep 10')
- -- this also tests that remote requests works during sleep
- eq(0, eval("[timer_start(10, 'MyHandler', {'repeat': 2}), g:val][1]"))
- run(nil, nil, nil, load_adjust(20))
- retry(nil, load_adjust(300), function()
- eq(2, eval('g:val'))
- end)
- end)
- it('are paused when event processing is disabled', function()
- command("call timer_start(5, 'MyHandler', {'repeat': -1})")
- run(nil, nil, nil, load_adjust(10))
- local count = eval('g:val')
- -- shows two line error message and thus invokes the return prompt.
- -- if we start to allow event processing here, we need to change this test.
- feed(':throw "fatal error"<CR>')
- run(nil, nil, nil, load_adjust(30))
- feed('<cr>')
- local diff = eval('g:val') - count
- assert(0 <= diff and diff <= 4, 'expected (0 <= diff <= 4), got: ' .. tostring(diff))
- end)
- it('are triggered in blocking getchar() call', function()
- command("call timer_start(5, 'MyHandler', {'repeat': -1})")
- async_meths.nvim_command('let g:val = 0 | let g:c = getchar()')
- retry(nil, nil, function()
- local val = eval('g:val')
- ok(val >= 2, '>= 2', tostring(val))
- eq(0, eval('getchar(1)'))
- end)
- feed('c')
- eq(99, eval('g:c'))
- end)
- it('can invoke redraw in blocking getchar() call', function()
- local screen = Screen.new(40, 6)
- api.nvim_buf_set_lines(0, 0, -1, true, { 'ITEM 1', 'ITEM 2' })
- source([[
- let g:cont = 0
- func! AddItem(timer)
- if !g:cont
- return
- endif
- call timer_stop(a:timer)
- call nvim_buf_set_lines(0, 2, 2, v:true, ['ITEM 3'])
- " Meant to test for what Vim tests in Test_peek_and_get_char.
- call getchar(1)
- redraw
- endfunc
- ]])
- async_meths.nvim_command('let g:c2 = getchar()')
- async_meths.nvim_command(
- 'call timer_start(' .. load_adjust(100) .. ", 'AddItem', {'repeat': -1})"
- )
- screen:expect([[
- ^ITEM 1 |
- ITEM 2 |
- {1:~ }|*3
- |
- ]])
- async_meths.nvim_command('let g:cont = 1')
- screen:expect([[
- ^ITEM 1 |
- ITEM 2 |
- ITEM 3 |
- {1:~ }|*2
- |
- ]])
- feed('3')
- eq(51, eval('g:c2'))
- screen:expect {
- grid = [[
- ^ITEM 1 |
- ITEM 2 |
- ITEM 3 |
- {1:~ }|*2
- |
- ]],
- unchanged = true,
- }
- end)
- it('can be stopped', function()
- local t_init_val = eval("[timer_start(5, 'MyHandler', {'repeat': -1}), g:val]")
- eq(0, t_init_val[2])
- run(nil, nil, nil, load_adjust(30))
- fn.timer_stop(t_init_val[1])
- local count = eval('g:val')
- run(nil, load_adjust(300), nil, load_adjust(30))
- local count2 = eval('g:val')
- -- when count is eval:ed after timer_stop this should be non-racy
- eq(count, count2)
- end)
- it('can be stopped from the handler', function()
- source([[
- func! MyHandler(timer)
- let g:val += 1
- if g:val == 3
- call timer_stop(a:timer)
- " check double stop is ignored
- call timer_stop(a:timer)
- endif
- endfunc
- ]])
- eq(0, eval('g:val'))
- command("call timer_start(10, 'MyHandler', {'repeat': -1})")
- retry(nil, nil, function()
- eq(3, eval('g:val'))
- end)
- end)
- it('can have two timers', function()
- source([[
- let g:val2 = 0
- func! MyHandler2(timer)
- let g:val2 += 1
- endfunc
- ]])
- command("call timer_start(2, 'MyHandler', {'repeat': 3})")
- command("call timer_start(4, 'MyHandler2', {'repeat': 2})")
- retry(nil, nil, function()
- eq(3, eval('g:val'))
- eq(2, eval('g:val2'))
- end)
- end)
- it('do not crash when processing events in the handler', function()
- source([[
- let g:val = 0
- func! MyHandler(timer)
- call timer_stop(a:timer)
- sleep 10m
- let g:val += 1
- endfunc
- ]])
- command("call timer_start(5, 'MyHandler', {'repeat': 1})")
- run(nil, nil, nil, load_adjust(20))
- retry(nil, load_adjust(150), function()
- eq(1, eval('g:val'))
- end)
- end)
- it("doesn't mess up the cmdline", function()
- local screen = Screen.new(40, 6)
- source([[
- let g:val = 0
- func! MyHandler(timer)
- while !g:val
- return
- endwhile
- call timer_stop(a:timer)
- echo "evil"
- redraw
- let g:val = 2
- endfunc
- ]])
- command("call timer_start(100, 'MyHandler', {'repeat': -1})")
- feed(':good')
- screen:expect([[
- |
- {1:~ }|*4
- :good^ |
- ]])
- command('let g:val = 1')
- screen:expect_unchanged(true, load_adjust(200))
- eq(2, eval('g:val'))
- end)
- it("timer_start can't be used in the sandbox", function()
- source [[
- function! Scary(timer) abort
- call execute('echo ''execute() should be disallowed''', '')
- endfunction
- ]]
- eq('Vim(call):E48: Not allowed in sandbox', exc_exec("sandbox call timer_start(0, 'Scary')"))
- end)
- it('can be triggered after an empty string <expr> mapping #17257', function()
- local screen = Screen.new(40, 6)
- command([=[imap <expr> <F2> [timer_start(0, { _ -> execute("throw 'x'", "") }), ''][-1]]=])
- feed('i<F2>')
- screen:expect({ any = 'E605: Exception not caught: x' })
- end)
- end)
|