helpers.lua 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773
  1. require('vim.compat')
  2. require('coxpcall')
  3. local luv = require('luv')
  4. local lfs = require('lfs')
  5. local global_helpers = require('test.helpers')
  6. -- nvim client: Found in .deps/usr/share/lua/<version>/nvim/ if "bundled".
  7. local Session = require('nvim.session')
  8. local TcpStream = require('nvim.tcp_stream')
  9. local SocketStream = require('nvim.socket_stream')
  10. local ChildProcessStream = require('nvim.child_process_stream')
  11. local Paths = require('test.config.paths')
  12. local check_cores = global_helpers.check_cores
  13. local check_logs = global_helpers.check_logs
  14. local dedent = global_helpers.dedent
  15. local eq = global_helpers.eq
  16. local expect_err = global_helpers.expect_err
  17. local filter = global_helpers.filter
  18. local map = global_helpers.map
  19. local matches = global_helpers.matches
  20. local near = global_helpers.near
  21. local neq = global_helpers.neq
  22. local ok = global_helpers.ok
  23. local read_file = global_helpers.read_file
  24. local sleep = global_helpers.sleep
  25. local table_flatten = global_helpers.table_flatten
  26. local write_file = global_helpers.write_file
  27. local start_dir = lfs.currentdir()
  28. -- XXX: NVIM_PROG takes precedence, QuickBuild sets it.
  29. local nvim_prog = (
  30. os.getenv('NVIM_PROG')
  31. or os.getenv('NVIM_PRG')
  32. or Paths.test_build_dir .. '/bin/nvim'
  33. )
  34. -- Default settings for the test session.
  35. local nvim_set = 'set shortmess+=I background=light noswapfile noautoindent'
  36. ..' laststatus=1 undodir=. directory=. viewdir=. backupdir=.'
  37. ..' belloff= noshowcmd noruler nomore'
  38. local nvim_argv = {nvim_prog, '-u', 'NONE', '-i', 'NONE', '-N',
  39. '--cmd', nvim_set, '--embed'}
  40. -- Directory containing nvim.
  41. local nvim_dir = nvim_prog:gsub("[/\\][^/\\]+$", "")
  42. if nvim_dir == nvim_prog then
  43. nvim_dir = "."
  44. end
  45. local mpack = require('mpack')
  46. local tmpname = global_helpers.tmpname
  47. local uname = global_helpers.uname
  48. local prepend_argv
  49. if os.getenv('VALGRIND') then
  50. local log_file = os.getenv('VALGRIND_LOG') or 'valgrind-%p.log'
  51. prepend_argv = {'valgrind', '-q', '--tool=memcheck',
  52. '--leak-check=yes', '--track-origins=yes',
  53. '--show-possibly-lost=no',
  54. '--suppressions=src/.valgrind.supp',
  55. '--log-file='..log_file}
  56. if os.getenv('GDB') then
  57. table.insert(prepend_argv, '--vgdb=yes')
  58. table.insert(prepend_argv, '--vgdb-error=0')
  59. end
  60. elseif os.getenv('GDB') then
  61. local gdbserver_port = '7777'
  62. if os.getenv('GDBSERVER_PORT') then
  63. gdbserver_port = os.getenv('GDBSERVER_PORT')
  64. end
  65. prepend_argv = {'gdbserver', 'localhost:'..gdbserver_port}
  66. end
  67. if prepend_argv then
  68. local new_nvim_argv = {}
  69. local len = #prepend_argv
  70. for i = 1, len do
  71. new_nvim_argv[i] = prepend_argv[i]
  72. end
  73. for i = 1, #nvim_argv do
  74. new_nvim_argv[i + len] = nvim_argv[i]
  75. end
  76. nvim_argv = new_nvim_argv
  77. end
  78. local session, loop_running, last_error
  79. local function set_session(s, keep)
  80. if session and not keep then
  81. session:close()
  82. end
  83. session = s
  84. end
  85. local function request(method, ...)
  86. local status, rv = session:request(method, ...)
  87. if not status then
  88. if loop_running then
  89. last_error = rv[2]
  90. session:stop()
  91. else
  92. error(rv[2])
  93. end
  94. end
  95. return rv
  96. end
  97. local function next_msg(timeout)
  98. return session:next_message(timeout and timeout or 10000)
  99. end
  100. local function expect_twostreams(msgs1, msgs2)
  101. local pos1, pos2 = 1, 1
  102. while pos1 <= #msgs1 or pos2 <= #msgs2 do
  103. local msg = next_msg()
  104. if pos1 <= #msgs1 and pcall(eq, msgs1[pos1], msg) then
  105. pos1 = pos1 + 1
  106. elseif pos2 <= #msgs2 then
  107. eq(msgs2[pos2], msg)
  108. pos2 = pos2 + 1
  109. else
  110. -- already failed, but show the right error message
  111. eq(msgs1[pos1], msg)
  112. end
  113. end
  114. end
  115. -- Expects a sequence of next_msg() results. If multiple sequences are
  116. -- passed they are tried until one succeeds, in order of shortest to longest.
  117. local function expect_msg_seq(...)
  118. if select('#', ...) < 1 then
  119. error('need at least 1 argument')
  120. end
  121. local seqs = {...}
  122. table.sort(seqs, function(a, b) -- Sort ascending, by (shallow) length.
  123. return #a < #b
  124. end)
  125. local actual_seq = {}
  126. local final_error = ''
  127. local function cat_err(err1, err2)
  128. if err1 == nil then
  129. return err2
  130. end
  131. return string.format('%s\n%s\n%s', err1, string.rep('=', 78), err2)
  132. end
  133. for anum = 1, #seqs do
  134. local expected_seq = seqs[anum]
  135. -- Collect enough messages to compare the next expected sequence.
  136. while #actual_seq < #expected_seq do
  137. local msg = next_msg(10000) -- Big timeout for ASAN/valgrind.
  138. if msg == nil then
  139. error(cat_err(final_error,
  140. string.format('got %d messages, expected %d',
  141. #actual_seq, #expected_seq)))
  142. end
  143. table.insert(actual_seq, msg)
  144. end
  145. local status, result = pcall(eq, expected_seq, actual_seq)
  146. if status then
  147. return result
  148. end
  149. final_error = cat_err(final_error, result)
  150. end
  151. error(final_error)
  152. end
  153. local function call_and_stop_on_error(...)
  154. local status, result = copcall(...) -- luacheck: ignore
  155. if not status then
  156. session:stop()
  157. last_error = result
  158. return ''
  159. end
  160. return result
  161. end
  162. local function run(request_cb, notification_cb, setup_cb, timeout)
  163. local on_request, on_notification, on_setup
  164. if request_cb then
  165. function on_request(method, args)
  166. return call_and_stop_on_error(request_cb, method, args)
  167. end
  168. end
  169. if notification_cb then
  170. function on_notification(method, args)
  171. call_and_stop_on_error(notification_cb, method, args)
  172. end
  173. end
  174. if setup_cb then
  175. function on_setup()
  176. call_and_stop_on_error(setup_cb)
  177. end
  178. end
  179. loop_running = true
  180. session:run(on_request, on_notification, on_setup, timeout)
  181. loop_running = false
  182. if last_error then
  183. local err = last_error
  184. last_error = nil
  185. error(err)
  186. end
  187. end
  188. local function stop()
  189. session:stop()
  190. end
  191. -- Executes an ex-command. VimL errors manifest as client (lua) errors, but
  192. -- v:errmsg will not be updated.
  193. local function nvim_command(cmd)
  194. request('nvim_command', cmd)
  195. end
  196. -- Evaluates a VimL expression.
  197. -- Fails on VimL error, but does not update v:errmsg.
  198. local function nvim_eval(expr)
  199. return request('nvim_eval', expr)
  200. end
  201. local os_name = (function()
  202. local name = nil
  203. return (function()
  204. if not name then
  205. if nvim_eval('has("win32")') == 1 then
  206. name = 'windows'
  207. elseif nvim_eval('has("macunix")') == 1 then
  208. name = 'osx'
  209. else
  210. name = 'unix'
  211. end
  212. end
  213. return name
  214. end)
  215. end)()
  216. local function iswin()
  217. return package.config:sub(1,1) == '\\'
  218. end
  219. -- Executes a VimL function.
  220. -- Fails on VimL error, but does not update v:errmsg.
  221. local function nvim_call(name, ...)
  222. return request('nvim_call_function', name, {...})
  223. end
  224. -- Sends user input to Nvim.
  225. -- Does not fail on VimL error, but v:errmsg will be updated.
  226. local function nvim_feed(input)
  227. while #input > 0 do
  228. local written = request('nvim_input', input)
  229. input = input:sub(written + 1)
  230. end
  231. end
  232. local function feed(...)
  233. for _, v in ipairs({...}) do
  234. nvim_feed(dedent(v))
  235. end
  236. end
  237. local function rawfeed(...)
  238. for _, v in ipairs({...}) do
  239. nvim_feed(dedent(v))
  240. end
  241. end
  242. local function merge_args(...)
  243. local i = 1
  244. local argv = {}
  245. for anum = 1,select('#', ...) do
  246. local args = select(anum, ...)
  247. if args then
  248. for _, arg in ipairs(args) do
  249. argv[i] = arg
  250. i = i + 1
  251. end
  252. end
  253. end
  254. return argv
  255. end
  256. local function spawn(argv, merge, env)
  257. local child_stream = ChildProcessStream.spawn(
  258. merge and merge_args(prepend_argv, argv) or argv,
  259. env)
  260. return Session.new(child_stream)
  261. end
  262. -- Creates a new Session connected by domain socket (named pipe) or TCP.
  263. local function connect(file_or_address)
  264. local addr, port = string.match(file_or_address, "(.*):(%d+)")
  265. local stream = (addr and port) and TcpStream.open(addr, port) or
  266. SocketStream.open(file_or_address)
  267. return Session.new(stream)
  268. end
  269. -- Calls fn() until it succeeds, up to `max` times or until `max_ms`
  270. -- milliseconds have passed.
  271. local function retry(max, max_ms, fn)
  272. assert(max == nil or max > 0)
  273. assert(max_ms == nil or max_ms > 0)
  274. local tries = 1
  275. local timeout = (max_ms and max_ms or 10000)
  276. local start_time = luv.now()
  277. while true do
  278. local status, result = pcall(fn)
  279. if status then
  280. return result
  281. end
  282. luv.update_time() -- Update cached value of luv.now() (libuv: uv_now()).
  283. if (max and tries >= max) or (luv.now() - start_time > timeout) then
  284. error("\nretry() attempts: "..tostring(tries).."\n"..tostring(result))
  285. end
  286. tries = tries + 1
  287. luv.sleep(20) -- Avoid hot loop...
  288. end
  289. end
  290. -- Starts a new global Nvim session.
  291. -- Parameters are interpreted as startup args, OR a map with these keys:
  292. -- args: Merged with the default `nvim_argv` set.
  293. -- env : Defines the environment of the new session.
  294. --
  295. -- Example:
  296. -- clear('-e')
  297. -- clear({args={'-e'}, env={TERM=term}})
  298. local function clear(...)
  299. local args = {unpack(nvim_argv)}
  300. local new_args
  301. local env = nil
  302. local opts = select(1, ...)
  303. local headless = true
  304. if type(opts) == 'table' then
  305. if opts.env then
  306. local env_tbl = {}
  307. for k, v in pairs(opts.env) do
  308. assert(type(k) == 'string')
  309. assert(type(v) == 'string')
  310. env_tbl[k] = v
  311. end
  312. for _, k in ipairs({
  313. 'HOME',
  314. 'ASAN_OPTIONS',
  315. 'LD_LIBRARY_PATH', 'PATH',
  316. 'NVIM_LOG_FILE',
  317. 'NVIM_RPLUGIN_MANIFEST',
  318. }) do
  319. if not env_tbl[k] then
  320. env_tbl[k] = os.getenv(k)
  321. end
  322. end
  323. env = {}
  324. for k, v in pairs(env_tbl) do
  325. env[#env + 1] = k .. '=' .. v
  326. end
  327. end
  328. new_args = opts.args or {}
  329. if opts.headless == false then
  330. headless = false
  331. end
  332. else
  333. new_args = {...}
  334. end
  335. if headless then
  336. table.insert(args, '--headless')
  337. end
  338. for _, arg in ipairs(new_args) do
  339. table.insert(args, arg)
  340. end
  341. set_session(spawn(args, nil, env))
  342. end
  343. local function insert(...)
  344. nvim_feed('i')
  345. for _, v in ipairs({...}) do
  346. local escaped = v:gsub('<', '<lt>')
  347. rawfeed(escaped)
  348. end
  349. nvim_feed('<ESC>')
  350. end
  351. -- Executes an ex-command by user input. Because nvim_input() is used, VimL
  352. -- errors will not manifest as client (lua) errors. Use command() for that.
  353. local function feed_command(...)
  354. for _, v in ipairs({...}) do
  355. if v:sub(1, 1) ~= '/' then
  356. -- not a search command, prefix with colon
  357. nvim_feed(':')
  358. end
  359. nvim_feed(v:gsub('<', '<lt>'))
  360. nvim_feed('<CR>')
  361. end
  362. end
  363. local sourced_fnames = {}
  364. local function source(code)
  365. local fname = tmpname()
  366. write_file(fname, code)
  367. nvim_command('source '..fname)
  368. -- DO NOT REMOVE FILE HERE.
  369. -- do_source() has a habit of checking whether files are “same” by using inode
  370. -- and device IDs. If you run two source() calls in quick succession there is
  371. -- a good chance that underlying filesystem will reuse the inode, making files
  372. -- appear as “symlinks” to do_source when it checks FileIDs. With current
  373. -- setup linux machines (both QB, travis and mine(ZyX-I) with XFS) do reuse
  374. -- inodes, Mac OS machines (again, both QB and travis) do not.
  375. --
  376. -- Files appearing as “symlinks” mean that both the first and the second
  377. -- source() calls will use same SID, which may fail some tests which check for
  378. -- exact numbers after `<SNR>` in e.g. function names.
  379. sourced_fnames[#sourced_fnames + 1] = fname
  380. return fname
  381. end
  382. local function set_shell_powershell()
  383. source([[
  384. set shell=powershell shellquote=( shellpipe=\| shellredir=> shellxquote=
  385. let &shellcmdflag = '-NoLogo -NoProfile -ExecutionPolicy RemoteSigned -Command Remove-Item -Force alias:sleep;'
  386. ]])
  387. end
  388. local function nvim(method, ...)
  389. return request('nvim_'..method, ...)
  390. end
  391. local function ui(method, ...)
  392. return request('nvim_ui_'..method, ...)
  393. end
  394. local function nvim_async(method, ...)
  395. session:notify('nvim_'..method, ...)
  396. end
  397. local function buffer(method, ...)
  398. return request('nvim_buf_'..method, ...)
  399. end
  400. local function window(method, ...)
  401. return request('nvim_win_'..method, ...)
  402. end
  403. local function tabpage(method, ...)
  404. return request('nvim_tabpage_'..method, ...)
  405. end
  406. local function curbuf(method, ...)
  407. if not method then
  408. return nvim('get_current_buf')
  409. end
  410. return buffer(method, 0, ...)
  411. end
  412. local function wait()
  413. -- Execute 'nvim_eval' (a deferred function) to block
  414. -- until all pending input is processed.
  415. session:request('nvim_eval', '1')
  416. end
  417. local function curbuf_contents()
  418. wait() -- Before inspecting the buffer, process all input.
  419. return table.concat(curbuf('get_lines', 0, -1, true), '\n')
  420. end
  421. local function curwin(method, ...)
  422. if not method then
  423. return nvim('get_current_win')
  424. end
  425. return window(method, 0, ...)
  426. end
  427. local function curtab(method, ...)
  428. if not method then
  429. return nvim('get_current_tabpage')
  430. end
  431. return tabpage(method, 0, ...)
  432. end
  433. local function expect(contents)
  434. return eq(dedent(contents), curbuf_contents())
  435. end
  436. local function expect_any(contents)
  437. contents = dedent(contents)
  438. return ok(nil ~= string.find(curbuf_contents(), contents, 1, true))
  439. end
  440. local function do_rmdir(path)
  441. if lfs.attributes(path, 'mode') ~= 'directory' then
  442. return -- Don't complain.
  443. end
  444. for file in lfs.dir(path) do
  445. if file ~= '.' and file ~= '..' then
  446. local abspath = path..'/'..file
  447. if lfs.attributes(abspath, 'mode') == 'directory' then
  448. do_rmdir(abspath) -- recurse
  449. else
  450. local ret, err = os.remove(abspath)
  451. if not ret then
  452. if not session then
  453. error('os.remove: '..err)
  454. else
  455. -- Try Nvim delete(): it handles `readonly` attribute on Windows,
  456. -- and avoids Lua cross-version/platform incompatibilities.
  457. if -1 == nvim_call('delete', abspath) then
  458. local hint = (os_name() == 'windows'
  459. and ' (hint: try :%bwipeout! before rmdir())' or '')
  460. error('delete() failed'..hint..': '..abspath)
  461. end
  462. end
  463. end
  464. end
  465. end
  466. end
  467. local ret, err = lfs.rmdir(path)
  468. if not ret then
  469. error('lfs.rmdir('..path..'): '..err)
  470. end
  471. end
  472. local function rmdir(path)
  473. local ret, _ = pcall(do_rmdir, path)
  474. if not ret and os_name() == "windows" then
  475. -- Maybe "Permission denied"; try again after changing the nvim
  476. -- process to the top-level directory.
  477. nvim_command([[exe 'cd '.fnameescape(']]..start_dir.."')")
  478. ret, _ = pcall(do_rmdir, path)
  479. end
  480. -- During teardown, the nvim process may not exit quickly enough, then rmdir()
  481. -- will fail (on Windows).
  482. if not ret then -- Try again.
  483. sleep(1000)
  484. do_rmdir(path)
  485. end
  486. end
  487. local exc_exec = function(cmd)
  488. nvim_command(([[
  489. try
  490. execute "%s"
  491. catch
  492. let g:__exception = v:exception
  493. endtry
  494. ]]):format(cmd:gsub('\n', '\\n'):gsub('[\\"]', '\\%0')))
  495. local ret = nvim_eval('get(g:, "__exception", 0)')
  496. nvim_command('unlet! g:__exception')
  497. return ret
  498. end
  499. local function create_callindex(func)
  500. local table = {}
  501. setmetatable(table, {
  502. __index = function(tbl, arg1)
  503. local ret = function(...) return func(arg1, ...) end
  504. tbl[arg1] = ret
  505. return ret
  506. end,
  507. })
  508. return table
  509. end
  510. -- Helper to skip tests. Returns true in Windows systems.
  511. -- pending_fn is pending() from busted
  512. local function pending_win32(pending_fn)
  513. if uname() == 'Windows' then
  514. if pending_fn ~= nil then
  515. pending_fn('FIXME: Windows', function() end)
  516. end
  517. return true
  518. else
  519. return false
  520. end
  521. end
  522. -- Calls pending() and returns `true` if the system is too slow to
  523. -- run fragile or expensive tests. Else returns `false`.
  524. local function skip_fragile(pending_fn, cond)
  525. if pending_fn == nil or type(pending_fn) ~= type(function()end) then
  526. error("invalid pending_fn")
  527. end
  528. if cond then
  529. pending_fn("skipped (test is fragile on this system)", function() end)
  530. return true
  531. elseif os.getenv("TEST_SKIP_FRAGILE") then
  532. pending_fn("skipped (TEST_SKIP_FRAGILE)", function() end)
  533. return true
  534. end
  535. return false
  536. end
  537. local function meth_pcall(...)
  538. local ret = {pcall(...)}
  539. if type(ret[2]) == 'string' then
  540. ret[2] = ret[2]:gsub('^[^:]+:%d+: ', '')
  541. end
  542. return ret
  543. end
  544. local funcs = create_callindex(nvim_call)
  545. local meths = create_callindex(nvim)
  546. local uimeths = create_callindex(ui)
  547. local bufmeths = create_callindex(buffer)
  548. local winmeths = create_callindex(window)
  549. local tabmeths = create_callindex(tabpage)
  550. local curbufmeths = create_callindex(curbuf)
  551. local curwinmeths = create_callindex(curwin)
  552. local curtabmeths = create_callindex(curtab)
  553. local function redir_exec(cmd)
  554. meths.set_var('__redir_exec_cmd', cmd)
  555. nvim_command([[
  556. redir => g:__redir_exec_output
  557. silent! execute g:__redir_exec_cmd
  558. redir END
  559. ]])
  560. local ret = meths.get_var('__redir_exec_output')
  561. meths.del_var('__redir_exec_output')
  562. meths.del_var('__redir_exec_cmd')
  563. return ret
  564. end
  565. local function get_pathsep()
  566. return iswin() and '\\' or '/'
  567. end
  568. local function pathroot()
  569. local pathsep = package.config:sub(1,1)
  570. return iswin() and (nvim_dir:sub(1,2)..pathsep) or '/'
  571. end
  572. -- Returns a valid, platform-independent $NVIM_LISTEN_ADDRESS.
  573. -- Useful for communicating with child instances.
  574. local function new_pipename()
  575. -- HACK: Start a server temporarily, get the name, then stop it.
  576. local pipename = nvim_eval('serverstart()')
  577. funcs.serverstop(pipename)
  578. return pipename
  579. end
  580. local function missing_provider(provider)
  581. if provider == 'ruby' or provider == 'node' then
  582. local prog = funcs['provider#' .. provider .. '#Detect']()
  583. return prog == '' and (provider .. ' not detected') or false
  584. elseif provider == 'python' or provider == 'python3' then
  585. local py_major_version = (provider == 'python3' and 3 or 2)
  586. local errors = funcs['provider#pythonx#Detect'](py_major_version)[2]
  587. return errors ~= '' and errors or false
  588. else
  589. assert(false, 'Unknown provider: ' .. provider)
  590. end
  591. end
  592. local function alter_slashes(obj)
  593. if not iswin() then
  594. return obj
  595. end
  596. if type(obj) == 'string' then
  597. local ret = obj:gsub('/', '\\')
  598. return ret
  599. elseif type(obj) == 'table' then
  600. local ret = {}
  601. for k, v in pairs(obj) do
  602. ret[k] = alter_slashes(v)
  603. end
  604. return ret
  605. else
  606. assert(false, 'Could only alter slashes for tables of strings and strings')
  607. end
  608. end
  609. local module = {
  610. NIL = mpack.NIL,
  611. alter_slashes = alter_slashes,
  612. buffer = buffer,
  613. bufmeths = bufmeths,
  614. call = nvim_call,
  615. clear = clear,
  616. command = nvim_command,
  617. connect = connect,
  618. curbuf = curbuf,
  619. curbuf_contents = curbuf_contents,
  620. curbufmeths = curbufmeths,
  621. curtab = curtab,
  622. curtabmeths = curtabmeths,
  623. curwin = curwin,
  624. curwinmeths = curwinmeths,
  625. dedent = dedent,
  626. eq = eq,
  627. eval = nvim_eval,
  628. exc_exec = exc_exec,
  629. expect = expect,
  630. expect_any = expect_any,
  631. expect_err = expect_err,
  632. expect_msg_seq = expect_msg_seq,
  633. expect_twostreams = expect_twostreams,
  634. feed = feed,
  635. feed_command = feed_command,
  636. filter = filter,
  637. funcs = funcs,
  638. get_pathsep = get_pathsep,
  639. insert = insert,
  640. iswin = iswin,
  641. map = map,
  642. matches = matches,
  643. merge_args = merge_args,
  644. meth_pcall = meth_pcall,
  645. meths = meths,
  646. missing_provider = missing_provider,
  647. mkdir = lfs.mkdir,
  648. near = near,
  649. neq = neq,
  650. new_pipename = new_pipename,
  651. next_msg = next_msg,
  652. nvim = nvim,
  653. nvim_argv = nvim_argv,
  654. nvim_async = nvim_async,
  655. nvim_dir = nvim_dir,
  656. nvim_prog = nvim_prog,
  657. nvim_set = nvim_set,
  658. ok = ok,
  659. os_name = os_name,
  660. pathroot = pathroot,
  661. pending_win32 = pending_win32,
  662. prepend_argv = prepend_argv,
  663. rawfeed = rawfeed,
  664. read_file = read_file,
  665. redir_exec = redir_exec,
  666. request = request,
  667. retry = retry,
  668. rmdir = rmdir,
  669. run = run,
  670. set_session = set_session,
  671. set_shell_powershell = set_shell_powershell,
  672. skip_fragile = skip_fragile,
  673. sleep = sleep,
  674. source = source,
  675. spawn = spawn,
  676. stop = stop,
  677. table_flatten = table_flatten,
  678. tabmeths = tabmeths,
  679. tabpage = tabpage,
  680. tmpname = tmpname,
  681. uimeths = uimeths,
  682. wait = wait,
  683. window = window,
  684. winmeths = winmeths,
  685. write_file = write_file,
  686. }
  687. return function(after_each)
  688. if after_each then
  689. after_each(function()
  690. for _, fname in ipairs(sourced_fnames) do
  691. os.remove(fname)
  692. end
  693. check_logs()
  694. check_cores('build/bin/nvim')
  695. if session then
  696. local msg = session:next_message(0)
  697. if msg then
  698. if msg[1] == "notification" and msg[2] == "nvim_error_event" then
  699. error(msg[3][2])
  700. end
  701. end
  702. end
  703. end)
  704. end
  705. return module
  706. end