Files
neovim/test/functional/vimscript/timer_spec.lua
T

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

275 lines
8.0 KiB
Lua
Raw Normal View History

2024-04-20 17:44:13 +02:00
local t = require('test.testutil')
local n = require('test.functional.testnvim')()
local Screen = require('test.functional.ui.screen')
2024-04-20 17:44:13 +02:00
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
2024-04-08 11:03:20 +02:00
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})")
2024-01-15 16:10:51 +00:00
async_meths.nvim_command('sleep 10')
eq(-1, eval('g:val')) -- timer did nothing yet.
2024-01-15 16:10:51 +00:00
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)
2016-06-05 10:49:33 +02:00
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)
2016-06-05 10:49:33 +02:00
end)
it('can be started during sleep', function()
2024-01-15 16:10:51 +00:00
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')
2016-09-25 09:47:23 +02:00
-- 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))
2016-09-25 09:47:23 +02:00
feed('<cr>')
local diff = eval('g:val') - count
2018-10-08 08:56:13 +02:00
assert(0 <= diff and diff <= 4, 'expected (0 <= diff <= 4), got: ' .. tostring(diff))
2016-09-25 09:47:23 +02:00
end)
it('are triggered in blocking getchar() call', function()
command("call timer_start(5, 'MyHandler', {'repeat': -1})")
2024-01-15 16:10:51 +00:00
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)
2016-09-25 09:47:23 +02:00
it('can invoke redraw in blocking getchar() call', function()
local screen = Screen.new(40, 6)
screen:attach()
screen:set_default_attr_ids({
[1] = { bold = true, foreground = Screen.colors.Blue },
})
2024-01-12 17:59:57 +00:00
api.nvim_buf_set_lines(0, 0, -1, true, { 'ITEM 1', 'ITEM 2' })
2016-09-25 09:47:23 +02:00
source([[
2019-09-24 08:55:27 +02:00
let g:cont = 0
2016-09-25 09:47:23 +02:00
func! AddItem(timer)
2019-09-24 08:55:27 +02:00
if !g:cont
return
endif
call timer_stop(a:timer)
2016-09-25 09:47:23 +02:00
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.
2018-09-04 09:59:27 -04:00
call getchar(1)
2016-09-25 09:47:23 +02:00
redraw
endfunc
]])
2024-01-15 16:10:51 +00:00
async_meths.nvim_command('let g:c2 = getchar()')
async_meths.nvim_command(
'call timer_start(' .. load_adjust(100) .. ", 'AddItem', {'repeat': -1})"
)
2016-09-25 09:47:23 +02:00
screen:expect([[
^ITEM 1 |
2016-09-25 09:47:23 +02:00
ITEM 2 |
{1:~ }|*3
|
2016-09-25 09:47:23 +02:00
]])
2024-01-15 16:10:51 +00:00
async_meths.nvim_command('let g:cont = 1')
2016-09-25 09:47:23 +02:00
screen:expect([[
^ITEM 1 |
2016-09-25 09:47:23 +02:00
ITEM 2 |
ITEM 3 |
{1:~ }|*2
|
2016-09-25 09:47:23 +02:00
]])
feed('3')
eq(51, eval('g:c2'))
screen:expect {
grid = [[
2016-09-25 09:47:23 +02:00
^ITEM 1 |
ITEM 2 |
ITEM 3 |
{1:~ }|*2
2016-09-25 09:47:23 +02:00
|
]],
unchanged = true,
}
2016-09-25 09:47:23 +02:00
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))
2024-01-12 17:59:57 +00:00
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})")
2019-09-01 15:37:38 -07:00
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})")
2020-12-01 01:59:28 -05:00
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)
screen:attach()
screen:set_default_attr_ids({ [0] = { bold = true, foreground = 255 } })
source([[
let g:val = 0
func! MyHandler(timer)
2019-09-24 08:55:27 +02:00
while !g:val
return
endwhile
call timer_stop(a:timer)
echo "evil"
redraw
2019-09-24 08:55:27 +02:00
let g:val = 2
endfunc
]])
2019-09-24 08:55:27 +02:00
command("call timer_start(100, 'MyHandler', {'repeat': -1})")
feed(':good')
screen:expect([[
|
{0:~ }|*4
:good^ |
]])
2019-09-24 08:55:27 +02:00
command('let g:val = 1')
screen:expect_unchanged(true, load_adjust(200))
2019-09-24 08:55:27 +02:00
eq(2, eval('g:val'))
end)
2021-11-01 16:21:16 +00:00
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)
screen:attach()
command([=[imap <expr> <F2> [timer_start(0, { _ -> execute("throw 'x'", "") }), ''][-1]]=])
feed('i<F2>')
screen:expect({ any = 'E605: Exception not caught: x' })
end)
end)