mirror of
https://github.com/neovim/neovim
synced 2025-07-15 16:51:49 +00:00
fix(tests): use uv.spawn instead of io.popen for unittest helpers
The old implementation of repeated_read_cmd would attempt to run the command multiple times to handle racyness of async output. Code like this should not be written. Instead, use the libuv event loop to read until the process has exited and the pipe has been closed. This causes some previous discarded errors to be propagated. Fix these as well.
This commit is contained in:
@ -5,17 +5,6 @@ local Paths = require('test.cmakeconfig.paths')
|
|||||||
|
|
||||||
luaassert:set_parameter('TableFormatLevel', 100)
|
luaassert:set_parameter('TableFormatLevel', 100)
|
||||||
|
|
||||||
local quote_me = '[^.%w%+%-%@%_%/]' -- complement (needn't quote)
|
|
||||||
|
|
||||||
--- @param str string
|
|
||||||
--- @return string
|
|
||||||
local function shell_quote(str)
|
|
||||||
if string.find(str, quote_me) or str == '' then
|
|
||||||
return '"' .. str:gsub('[$%%"\\]', '\\%0') .. '"'
|
|
||||||
end
|
|
||||||
return str
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Functions executing in the context of the test runner (not the current nvim test session).
|
--- Functions executing in the context of the test runner (not the current nvim test session).
|
||||||
--- @class test.testutil
|
--- @class test.testutil
|
||||||
local M = {
|
local M = {
|
||||||
@ -66,19 +55,15 @@ function M.argss_to_cmd(...)
|
|||||||
for i = 1, select('#', ...) do
|
for i = 1, select('#', ...) do
|
||||||
local arg = select(i, ...)
|
local arg = select(i, ...)
|
||||||
if type(arg) == 'string' then
|
if type(arg) == 'string' then
|
||||||
cmd[#cmd + 1] = shell_quote(arg)
|
cmd[#cmd + 1] = arg
|
||||||
else
|
else
|
||||||
--- @cast arg string[]
|
--- @cast arg string[]
|
||||||
for _, subarg in ipairs(arg) do
|
for _, subarg in ipairs(arg) do
|
||||||
cmd[#cmd + 1] = shell_quote(subarg)
|
cmd[#cmd + 1] = subarg
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return table.concat(cmd, ' ')
|
return cmd
|
||||||
end
|
|
||||||
|
|
||||||
function M.popen_r(...)
|
|
||||||
return io.popen(M.argss_to_cmd(...), 'r')
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Calls fn() until it succeeds, up to `max` times or until `max_ms`
|
--- Calls fn() until it succeeds, up to `max` times or until `max_ms`
|
||||||
@ -356,7 +341,7 @@ function M.check_logs()
|
|||||||
local status, f
|
local status, f
|
||||||
local out = io.stdout
|
local out = io.stdout
|
||||||
if os.getenv('SYMBOLIZER') then
|
if os.getenv('SYMBOLIZER') then
|
||||||
status, f = pcall(M.popen_r, os.getenv('SYMBOLIZER'), '-l', file)
|
status, f = pcall(M.repeated_read_cmd, os.getenv('SYMBOLIZER'), '-l', file)
|
||||||
end
|
end
|
||||||
out:write(start_msg .. '\n')
|
out:write(start_msg .. '\n')
|
||||||
if status then
|
if status then
|
||||||
@ -539,16 +524,37 @@ end
|
|||||||
|
|
||||||
--- @return string?
|
--- @return string?
|
||||||
function M.repeated_read_cmd(...)
|
function M.repeated_read_cmd(...)
|
||||||
for _ = 1, 10 do
|
local cmd = M.argss_to_cmd(...)
|
||||||
local stream = M.popen_r(...)
|
local data = {}
|
||||||
local ret = stream:read('*a')
|
local got_code = nil
|
||||||
stream:close()
|
local stdout = assert(vim.uv.new_pipe(false))
|
||||||
if ret then
|
local handle = assert(
|
||||||
return ret
|
vim.uv.spawn(
|
||||||
|
cmd[1],
|
||||||
|
{ args = vim.list_slice(cmd, 2), stdio = { nil, stdout, 2 }, hide = true },
|
||||||
|
function(code, _signal)
|
||||||
|
got_code = code
|
||||||
|
end
|
||||||
|
)
|
||||||
|
)
|
||||||
|
stdout:read_start(function(err, chunk)
|
||||||
|
if err or chunk == nil then
|
||||||
|
stdout:read_stop()
|
||||||
|
stdout:close()
|
||||||
|
else
|
||||||
|
table.insert(data, chunk)
|
||||||
end
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
while not stdout:is_closing() or got_code == nil do
|
||||||
|
vim.uv.run('once')
|
||||||
end
|
end
|
||||||
print('ERROR: Failed to execute ' .. M.argss_to_cmd(...) .. ': nil return after 10 attempts')
|
|
||||||
return nil
|
if got_code ~= 0 then
|
||||||
|
error('command ' .. vim.inspect(cmd) .. 'unexpectedly exited with status ' .. got_code)
|
||||||
|
end
|
||||||
|
handle:close()
|
||||||
|
return table.concat(data)
|
||||||
end
|
end
|
||||||
|
|
||||||
--- @generic T
|
--- @generic T
|
||||||
|
@ -18,7 +18,7 @@ local type_key = api_t.type_key
|
|||||||
local obj2lua = api_t.obj2lua
|
local obj2lua = api_t.obj2lua
|
||||||
local func_type = api_t.func_type
|
local func_type = api_t.func_type
|
||||||
|
|
||||||
local api = cimport('./src/nvim/api/private/t.h', './src/nvim/api/private/converter.h')
|
local api = cimport('./src/nvim/api/private/helpers.h', './src/nvim/api/private/converter.h')
|
||||||
|
|
||||||
describe('vim_to_object', function()
|
describe('vim_to_object', function()
|
||||||
local vim_to_object = function(l)
|
local vim_to_object = function(l)
|
||||||
|
@ -13,8 +13,11 @@ local int_type = t_eval.int_type
|
|||||||
local flt_type = t_eval.flt_type
|
local flt_type = t_eval.flt_type
|
||||||
local type_key = t_eval.type_key
|
local type_key = t_eval.type_key
|
||||||
|
|
||||||
local api =
|
local api = cimport(
|
||||||
cimport('./src/nvim/api/private/defs.h', './src/nvim/api/private/t.h', './src/nvim/memory.h')
|
'./src/nvim/api/private/defs.h',
|
||||||
|
'./src/nvim/api/private/helpers.h',
|
||||||
|
'./src/nvim/memory.h'
|
||||||
|
)
|
||||||
|
|
||||||
local obj2lua
|
local obj2lua
|
||||||
|
|
||||||
|
@ -94,7 +94,7 @@ local vterm = t.cimport(
|
|||||||
'./src/nvim/vterm/screen.h',
|
'./src/nvim/vterm/screen.h',
|
||||||
'./src/nvim/vterm/state.h',
|
'./src/nvim/vterm/state.h',
|
||||||
'./src/nvim/vterm/vterm.h',
|
'./src/nvim/vterm/vterm.h',
|
||||||
'./src/nvim/vterm/vterm_internal.h',
|
'./src/nvim/vterm/vterm_internal_defs.h',
|
||||||
'./test/unit/fixtures/vterm_test.h'
|
'./test/unit/fixtures/vterm_test.h'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user