commit c81af9428c08d21d6e7ddc7ce7ac1761e9a20b9e
parent 272e04178060841e1bfda535de6f31825985ffef
Author: bfredl <bjorn.linse@gmail.com>
Date: Tue, 20 May 2025 12:10:37 +0200
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.
Diffstat:
4 files changed, 40 insertions(+), 31 deletions(-)
diff --git a/test/testutil.lua b/test/testutil.lua
@@ -5,17 +5,6 @@ local Paths = require('test.cmakeconfig.paths')
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).
--- @class test.testutil
local M = {
@@ -66,19 +55,15 @@ function M.argss_to_cmd(...)
for i = 1, select('#', ...) do
local arg = select(i, ...)
if type(arg) == 'string' then
- cmd[#cmd + 1] = shell_quote(arg)
+ cmd[#cmd + 1] = arg
else
--- @cast arg string[]
for _, subarg in ipairs(arg) do
- cmd[#cmd + 1] = shell_quote(subarg)
+ cmd[#cmd + 1] = subarg
end
end
end
- return table.concat(cmd, ' ')
-end
-
-function M.popen_r(...)
- return io.popen(M.argss_to_cmd(...), 'r')
+ return cmd
end
--- 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 out = io.stdout
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
out:write(start_msg .. '\n')
if status then
@@ -539,16 +524,37 @@ end
--- @return string?
function M.repeated_read_cmd(...)
- for _ = 1, 10 do
- local stream = M.popen_r(...)
- local ret = stream:read('*a')
- stream:close()
- if ret then
- return ret
+ local cmd = M.argss_to_cmd(...)
+ local data = {}
+ local got_code = nil
+ local stdout = assert(vim.uv.new_pipe(false))
+ local handle = assert(
+ 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)
+
+ while not stdout:is_closing() or got_code == nil do
+ vim.uv.run('once')
+ end
+
+ if got_code ~= 0 then
+ error('command ' .. vim.inspect(cmd) .. 'unexpectedly exited with status ' .. got_code)
end
- print('ERROR: Failed to execute ' .. M.argss_to_cmd(...) .. ': nil return after 10 attempts')
- return nil
+ handle:close()
+ return table.concat(data)
end
--- @generic T
diff --git a/test/unit/api/private_helpers_spec.lua b/test/unit/api/private_helpers_spec.lua
@@ -18,7 +18,7 @@ local type_key = api_t.type_key
local obj2lua = api_t.obj2lua
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()
local vim_to_object = function(l)
diff --git a/test/unit/api/testutil.lua b/test/unit/api/testutil.lua
@@ -13,8 +13,11 @@ local int_type = t_eval.int_type
local flt_type = t_eval.flt_type
local type_key = t_eval.type_key
-local api =
- cimport('./src/nvim/api/private/defs.h', './src/nvim/api/private/t.h', './src/nvim/memory.h')
+local api = cimport(
+ './src/nvim/api/private/defs.h',
+ './src/nvim/api/private/helpers.h',
+ './src/nvim/memory.h'
+)
local obj2lua
diff --git a/test/unit/vterm_spec.lua b/test/unit/vterm_spec.lua
@@ -94,7 +94,7 @@ local vterm = t.cimport(
'./src/nvim/vterm/screen.h',
'./src/nvim/vterm/state.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'
)