mirror of
https://github.com/neovim/neovim.git
synced 2025-12-10 00:22:41 +00:00
test: Improve test environment setup and error handling/reporting
During test setup, we used to call a vimscript function(BeforeEachTest) that attempted to restore Nvim to it's initial state as much as possible in order to provide a clean environment for running new tests. This approach has proven to be unreliable, as some tests leave state that can affect other tests, eventually causing failures that are difficult to debug. This commit changes the 'clear' function so it will restart Nvim every time it is called, which is a slower, but more reliable solution that will simplify spotting bugs in the future. Some other improvements/fixes were also performed: - Whenever an error is detected in a handler passed to "run()", the event loop will be stopped and the error will be propagated to the main thread. - Errors and the "cleanup()" function will always send a quit command to the current Nvim instance. This should prevent memory starvation when running tests under valgrind(where each Nvim instance can consume a lot of memory). - Fixed a wrong assertion in server_requests_spec.lua. Previously the failure was undetected in a notification handler. - Fixed some tests to expect fully clean registers. The deleted cleanup function used to put an empty string in every register, but that resulted in a extra line being added.
This commit is contained in:
@@ -4,7 +4,6 @@
|
||||
local helpers = require('test.functional.helpers')
|
||||
local clear, nvim, eval = helpers.clear, helpers.nvim, helpers.eval
|
||||
local eq, run, stop = helpers.eq, helpers.run, helpers.stop
|
||||
local restart = helpers.restart
|
||||
|
||||
|
||||
|
||||
@@ -15,7 +14,6 @@ describe('server -> client', function()
|
||||
clear()
|
||||
cid = nvim('get_api_info')[1]
|
||||
end)
|
||||
teardown(restart)
|
||||
|
||||
describe('simple call', function()
|
||||
it('works', function()
|
||||
@@ -110,7 +108,7 @@ describe('server -> client', function()
|
||||
return
|
||||
end
|
||||
notified = notified + 1
|
||||
eq('notified', eval('rpcrequest('..cid..', "notify")'))
|
||||
eq('notified!', eval('rpcrequest('..cid..', "notify")'))
|
||||
end
|
||||
|
||||
run(on_request, on_notification, on_setup)
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
require('coxpcall')
|
||||
local Loop = require('nvim.loop')
|
||||
local MsgpackStream = require('nvim.msgpack_stream')
|
||||
local AsyncSession = require('nvim.async_session')
|
||||
local Session = require('nvim.session')
|
||||
|
||||
local nvim_prog = os.getenv('NVIM_PROG') or 'build/bin/nvim'
|
||||
local nvim_argv = {nvim_prog, '-u', 'NONE', '-N', '--embed'}
|
||||
local nvim_argv = {nvim_prog, '-u', 'NONE', '-i', 'NONE', '-N', '--embed'}
|
||||
|
||||
if os.getenv('VALGRIND') then
|
||||
local log_file = os.getenv('VALGRIND_LOG') or 'valgrind-%p.log'
|
||||
@@ -23,74 +24,7 @@ if os.getenv('VALGRIND') then
|
||||
nvim_argv = valgrind_argv
|
||||
end
|
||||
|
||||
local session
|
||||
|
||||
local rawfeed
|
||||
local function restart()
|
||||
local loop = Loop.new()
|
||||
local msgpack_stream = MsgpackStream.new(loop)
|
||||
local async_session = AsyncSession.new(msgpack_stream)
|
||||
session = Session.new(async_session)
|
||||
loop:spawn(nvim_argv)
|
||||
rawfeed([[:function BeforeEachTest()
|
||||
set all&
|
||||
redir => groups
|
||||
silent augroup
|
||||
redir END
|
||||
for group in split(groups)
|
||||
exe 'augroup '.group
|
||||
autocmd!
|
||||
augroup END
|
||||
endfor
|
||||
autocmd!
|
||||
tabnew
|
||||
let curbufnum = eval(bufnr('%'))
|
||||
redir => buflist
|
||||
silent ls!
|
||||
redir END
|
||||
let bufnums = []
|
||||
for buf in split(buflist, '\n')
|
||||
let bufnum = eval(split(buf, '[ u]')[0])
|
||||
if bufnum != curbufnum
|
||||
call add(bufnums, bufnum)
|
||||
endif
|
||||
endfor
|
||||
if len(bufnums) > 0
|
||||
exe 'silent bwipeout! '.join(bufnums, ' ')
|
||||
endif
|
||||
silent tabonly
|
||||
for k in keys(g:)
|
||||
exe 'unlet g:'.k
|
||||
endfor
|
||||
filetype plugin indent off
|
||||
mapclear
|
||||
mapclear!
|
||||
abclear
|
||||
comclear
|
||||
let regs = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789/-"'
|
||||
let i = 0
|
||||
while i < strlen(regs)
|
||||
call setreg(regs[i], '')
|
||||
let i = i+1
|
||||
endwhile
|
||||
redir => funcs
|
||||
silent! function
|
||||
redir END
|
||||
for fname in split(funcs, '\n')
|
||||
let matches = matchlist(fname, '\v^function ([^()<>]+)')
|
||||
if type([]) == type(matches) && matches[1] !~ 'BeforeEachTest'
|
||||
exe 'silent! delfunc '.matches[1]
|
||||
endif
|
||||
endfor
|
||||
let options = ['shell', 'fileignorecase']
|
||||
for option in options
|
||||
exe 'set '.option.'&'
|
||||
endfor
|
||||
endfunction
|
||||
]])
|
||||
end
|
||||
|
||||
local loop_running, last_error
|
||||
local session, loop_running, last_error
|
||||
|
||||
local function request(method, ...)
|
||||
local status, rv = session:request(method, ...)
|
||||
@@ -112,9 +46,32 @@ local function next_message()
|
||||
return session:next_message()
|
||||
end
|
||||
|
||||
local function call_and_stop_on_error(...)
|
||||
local status, result = copcall(...)
|
||||
if not status then
|
||||
session:stop()
|
||||
last_error = result
|
||||
return ''
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
local function run(request_cb, notification_cb, setup_cb)
|
||||
|
||||
local function on_request(method, args)
|
||||
return call_and_stop_on_error(request_cb, method, args)
|
||||
end
|
||||
|
||||
local function on_notification(method, args)
|
||||
call_and_stop_on_error(notification_cb, method, args)
|
||||
end
|
||||
|
||||
local function on_setup()
|
||||
call_and_stop_on_error(setup_cb)
|
||||
end
|
||||
|
||||
loop_running = true
|
||||
session:run(request_cb, notification_cb, setup_cb)
|
||||
session:run(on_request, on_notification, on_setup)
|
||||
loop_running = false
|
||||
if last_error then
|
||||
local err = last_error
|
||||
@@ -153,7 +110,7 @@ local function buffer_slice(start, stop, buffer_idx)
|
||||
end
|
||||
|
||||
local function nvim_replace_termcodes(input)
|
||||
return request('vim_replace_termcodes', input, false, true, true )
|
||||
return request('vim_replace_termcodes', input, false, true, true)
|
||||
end
|
||||
|
||||
local function dedent(str)
|
||||
@@ -178,22 +135,29 @@ local function dedent(str)
|
||||
return str
|
||||
end
|
||||
|
||||
local function clear()
|
||||
nvim_command('call BeforeEachTest()')
|
||||
end
|
||||
|
||||
local function feed(...)
|
||||
for _, v in ipairs({...}) do
|
||||
nvim_feed(nvim_replace_termcodes(dedent(v)))
|
||||
end
|
||||
end
|
||||
|
||||
function rawfeed(...)
|
||||
local function rawfeed(...)
|
||||
for _, v in ipairs({...}) do
|
||||
nvim_feed(dedent(v), 'nt')
|
||||
end
|
||||
end
|
||||
|
||||
local function clear()
|
||||
if session then
|
||||
session:request('vim_command', 'qa!')
|
||||
end
|
||||
local loop = Loop.new()
|
||||
local msgpack_stream = MsgpackStream.new(loop)
|
||||
local async_session = AsyncSession.new(msgpack_stream)
|
||||
session = Session.new(async_session)
|
||||
loop:spawn(nvim_argv)
|
||||
end
|
||||
|
||||
local function insert(...)
|
||||
nvim_feed('i', 'nt')
|
||||
rawfeed(...)
|
||||
@@ -271,12 +235,11 @@ local function curtab(method, ...)
|
||||
return tabpage(method, tab, ...)
|
||||
end
|
||||
|
||||
restart()
|
||||
clear()
|
||||
|
||||
return {
|
||||
clear = clear,
|
||||
dedent = dedent,
|
||||
restart = restart,
|
||||
rawfeed = rawfeed,
|
||||
insert = insert,
|
||||
feed = feed,
|
||||
|
||||
@@ -50,7 +50,7 @@ describe('argument list', function()
|
||||
|
||||
execute('%d')
|
||||
execute('0put=@a')
|
||||
execute('1d | $d')
|
||||
execute('$d')
|
||||
|
||||
eq(dedent([[
|
||||
start of test file Xxx1
|
||||
|
||||
@@ -51,7 +51,7 @@ describe(':ball', function()
|
||||
execute('bf')
|
||||
execute('%d')
|
||||
execute('0put=@a')
|
||||
execute('1d | $d')
|
||||
execute('$d')
|
||||
|
||||
expect([[
|
||||
start of test file Xxx4
|
||||
|
||||
@@ -31,7 +31,7 @@ describe('CTRL-W CTRL-I', function()
|
||||
|
||||
-- Clean buffer and put register
|
||||
feed('ggdG"ap')
|
||||
execute('1,2d')
|
||||
execute('1d')
|
||||
|
||||
-- The buffer should now contain:
|
||||
expect([[
|
||||
|
||||
@@ -35,8 +35,8 @@ describe(':edit', function()
|
||||
execute('%d')
|
||||
execute('0put a')
|
||||
|
||||
-- Remove empty lines
|
||||
execute('1d | $d')
|
||||
-- Remove empty line
|
||||
execute('$d')
|
||||
|
||||
-- The buffer should now contain
|
||||
expect([[
|
||||
|
||||
@@ -25,7 +25,7 @@ describe('writing and reading a file of over 100 Kbyte', function()
|
||||
execute('6005yank A')
|
||||
execute('%d')
|
||||
execute('0put a')
|
||||
execute('1d | $d')
|
||||
execute('$d')
|
||||
execute('w!')
|
||||
|
||||
expect([[
|
||||
|
||||
@@ -2,11 +2,10 @@
|
||||
-- other tests, so restart nvim in the teardown hook
|
||||
|
||||
local helpers = require('test.functional.helpers')
|
||||
local restart, command, clear = helpers.restart, helpers.command, helpers.clear
|
||||
local command, clear = helpers.command, helpers.clear
|
||||
|
||||
describe('options', function()
|
||||
setup(clear)
|
||||
teardown(restart)
|
||||
|
||||
it('is working', function()
|
||||
command('options')
|
||||
|
||||
Reference in New Issue
Block a user