mirror of
https://github.com/neovim/neovim.git
synced 2025-09-08 20:38:18 +00:00
Merge pull request #6844 from bfredl/channel
channels: support buffered output and bytes sockets/stdio
This commit is contained in:
@@ -262,6 +262,7 @@ describe('server -> client', function()
|
||||
eq("done!",funcs.rpcrequest(jobid, "write_stderr", "fluff\n"))
|
||||
eq({'notification', 'stderr', {0, {'fluff', ''}}}, next_message())
|
||||
funcs.rpcrequest(jobid, "exit")
|
||||
eq({'notification', 'stderr', {0, {''}}}, next_message())
|
||||
eq({'notification', 'exit', {0, 0}}, next_message())
|
||||
end)
|
||||
end)
|
||||
|
266
test/functional/core/channels_spec.lua
Normal file
266
test/functional/core/channels_spec.lua
Normal file
@@ -0,0 +1,266 @@
|
||||
|
||||
local helpers = require('test.functional.helpers')(after_each)
|
||||
local clear, eq, eval, next_msg, ok, source = helpers.clear, helpers.eq,
|
||||
helpers.eval, helpers.next_message, helpers.ok, helpers.source
|
||||
local command, funcs, meths = helpers.command, helpers.funcs, helpers.meths
|
||||
local sleep = helpers.sleep
|
||||
local spawn, nvim_argv = helpers.spawn, helpers.nvim_argv
|
||||
local set_session = helpers.set_session
|
||||
local nvim_prog = helpers.nvim_prog
|
||||
local retry = helpers.retry
|
||||
local expect_twostreams = helpers.expect_twostreams
|
||||
|
||||
describe('channels', function()
|
||||
local init = [[
|
||||
function! Normalize(data) abort
|
||||
" Windows: remove ^M
|
||||
return type([]) == type(a:data)
|
||||
\ ? map(a:data, 'substitute(v:val, "\r", "", "g")')
|
||||
\ : a:data
|
||||
endfunction
|
||||
function! OnEvent(id, data, event) dict
|
||||
call rpcnotify(1, a:event, a:id, a:data)
|
||||
endfunction
|
||||
]]
|
||||
before_each(function()
|
||||
clear()
|
||||
source(init)
|
||||
end)
|
||||
|
||||
it('can connect to socket', function()
|
||||
local server = spawn(nvim_argv)
|
||||
set_session(server)
|
||||
local address = funcs.serverlist()[1]
|
||||
local client = spawn(nvim_argv)
|
||||
set_session(client, true)
|
||||
source(init)
|
||||
|
||||
meths.set_var('address', address)
|
||||
command("let g:id = sockconnect('pipe', address, {'on_data':'OnEvent'})")
|
||||
local id = eval("g:id")
|
||||
ok(id > 0)
|
||||
|
||||
command("call chansend(g:id, msgpackdump([[2,'nvim_set_var',['code',23]]]))")
|
||||
set_session(server, true)
|
||||
retry(nil, 1000, function()
|
||||
eq(23, meths.get_var('code'))
|
||||
end)
|
||||
set_session(client, true)
|
||||
|
||||
command("call chansend(g:id, msgpackdump([[0,0,'nvim_eval',['2+3']]]))")
|
||||
|
||||
|
||||
local res = eval("msgpackdump([[1,0,v:null,5]])")
|
||||
eq({"\148\001\n\192\005"}, res)
|
||||
eq({'notification', 'data', {id, res}}, next_msg())
|
||||
command("call chansend(g:id, msgpackdump([[2,'nvim_command',['quit']]]))")
|
||||
eq({'notification', 'data', {id, {''}}}, next_msg())
|
||||
end)
|
||||
|
||||
it('can use stdio channel', function()
|
||||
source([[
|
||||
let g:job_opts = {
|
||||
\ 'on_stdout': function('OnEvent'),
|
||||
\ 'on_stderr': function('OnEvent'),
|
||||
\ 'on_exit': function('OnEvent'),
|
||||
\ }
|
||||
]])
|
||||
meths.set_var("nvim_prog", nvim_prog)
|
||||
meths.set_var("code", [[
|
||||
function! OnEvent(id, data, event) dict
|
||||
let text = string([a:id, a:data, a:event])
|
||||
call chansend(g:x, text)
|
||||
|
||||
if a:data == ['']
|
||||
call chansend(v:stderr, "*dies*")
|
||||
quit
|
||||
endif
|
||||
endfunction
|
||||
let g:x = stdioopen({'on_stdin':'OnEvent'})
|
||||
call chansend(x, "hello")
|
||||
]])
|
||||
command("let g:id = jobstart([ g:nvim_prog, '-u', 'NONE', '-i', 'NONE', '--cmd', 'set noswapfile', '--headless', '--cmd', g:code], g:job_opts)")
|
||||
local id = eval("g:id")
|
||||
ok(id > 0)
|
||||
|
||||
eq({ "notification", "stdout", {id, { "hello" } } }, next_msg())
|
||||
|
||||
command("call chansend(id, 'howdy')")
|
||||
eq({"notification", "stdout", {id, {"[1, ['howdy'], 'stdin']"}}}, next_msg())
|
||||
|
||||
command("call chanclose(id, 'stdin')")
|
||||
expect_twostreams({{"notification", "stdout", {id, {"[1, [''], 'stdin']"}}},
|
||||
{'notification', 'stdout', {id, {''}}}},
|
||||
{{"notification", "stderr", {id, {"*dies*"}}},
|
||||
{'notification', 'stderr', {id, {''}}}})
|
||||
eq({"notification", "exit", {3,0}}, next_msg())
|
||||
end)
|
||||
|
||||
local function expect_twoline(id, stream, line1, line2, nobr)
|
||||
local msg = next_msg()
|
||||
local joined = nobr and {line1..line2} or {line1, line2}
|
||||
if not pcall(eq, {"notification", stream, {id, joined}}, msg) then
|
||||
local sep = (not nobr) and "" or nil
|
||||
eq({"notification", stream, {id, {line1, sep}}}, msg)
|
||||
eq({"notification", stream, {id, {line2}}}, next_msg())
|
||||
end
|
||||
end
|
||||
|
||||
it('can use stdio channel with pty', function()
|
||||
if helpers.pending_win32(pending) then return end
|
||||
source([[
|
||||
let g:job_opts = {
|
||||
\ 'on_stdout': function('OnEvent'),
|
||||
\ 'on_exit': function('OnEvent'),
|
||||
\ 'pty': v:true,
|
||||
\ }
|
||||
]])
|
||||
meths.set_var("nvim_prog", nvim_prog)
|
||||
meths.set_var("code", [[
|
||||
function! OnEvent(id, data, event) dict
|
||||
let text = string([a:id, a:data, a:event])
|
||||
call chansend(g:x, text)
|
||||
endfunction
|
||||
let g:x = stdioopen({'on_stdin':'OnEvent'})
|
||||
]])
|
||||
command("let g:id = jobstart([ g:nvim_prog, '-u', 'NONE', '-i', 'NONE', '--cmd', 'set noswapfile', '--headless', '--cmd', g:code], g:job_opts)")
|
||||
local id = eval("g:id")
|
||||
ok(id > 0)
|
||||
|
||||
command("call chansend(id, 'TEXT\n')")
|
||||
expect_twoline(id, "stdout", "TEXT\r", "[1, ['TEXT', ''], 'stdin']")
|
||||
|
||||
|
||||
command("call chansend(id, 'neovan')")
|
||||
eq({"notification", "stdout", {id, {"neovan"}}}, next_msg())
|
||||
command("call chansend(id, '\127\127im\n')")
|
||||
expect_twoline(id, "stdout", "\b \b\b \bim\r", "[1, ['neovim', ''], 'stdin']")
|
||||
|
||||
command("call chansend(id, 'incomplet\004')")
|
||||
|
||||
local is_freebsd = eval("system('uname') =~? 'FreeBSD'") == 1
|
||||
local bsdlike = is_freebsd or (helpers.os_name() == "osx")
|
||||
print("bsdlike:", bsdlike)
|
||||
local extra = bsdlike and "^D\008\008" or ""
|
||||
expect_twoline(id, "stdout",
|
||||
"incomplet"..extra, "[1, ['incomplet'], 'stdin']", true)
|
||||
|
||||
|
||||
command("call chansend(id, '\004')")
|
||||
if bsdlike then
|
||||
expect_twoline(id, "stdout", extra, "[1, [''], 'stdin']", true)
|
||||
else
|
||||
eq({"notification", "stdout", {id, {"[1, [''], 'stdin']"}}}, next_msg())
|
||||
end
|
||||
|
||||
-- channel is still open
|
||||
command("call chansend(id, 'hi again!\n')")
|
||||
eq({"notification", "stdout", {id, {"hi again!\r", ""}}}, next_msg())
|
||||
end)
|
||||
|
||||
|
||||
it('stdio channel can use rpc and stderr simultaneously', function()
|
||||
if helpers.pending_win32(pending) then return end
|
||||
source([[
|
||||
let g:job_opts = {
|
||||
\ 'on_stderr': function('OnEvent'),
|
||||
\ 'on_exit': function('OnEvent'),
|
||||
\ 'rpc': v:true,
|
||||
\ }
|
||||
]])
|
||||
meths.set_var("nvim_prog", nvim_prog)
|
||||
meths.set_var("code", [[
|
||||
let id = stdioopen({'rpc':v:true})
|
||||
call rpcnotify(id,"nvim_call_function", "rpcnotify", [1, "message", "hi there!", id])
|
||||
call chansend(v:stderr, "trouble!")
|
||||
]])
|
||||
command("let id = jobstart([ g:nvim_prog, '-u', 'NONE', '-i', 'NONE', '--cmd', 'set noswapfile', '--headless', '--cmd', g:code], g:job_opts)")
|
||||
eq({"notification", "message", {"hi there!", 1}}, next_msg())
|
||||
eq({"notification", "stderr", {3, {"trouble!"}}}, next_msg())
|
||||
|
||||
eq(30, eval("rpcrequest(id, 'nvim_eval', '[chansend(v:stderr, \"math??\"), 5*6][1]')"))
|
||||
eq({"notification", "stderr", {3, {"math??"}}}, next_msg())
|
||||
|
||||
local _, err = pcall(command,"call rpcrequest(id, 'nvim_command', 'call chanclose(v:stderr, \"stdin\")')")
|
||||
ok(string.find(err,"E906: invalid stream for channel") ~= nil)
|
||||
|
||||
eq(1, eval("rpcrequest(id, 'nvim_eval', 'chanclose(v:stderr, \"stderr\")')"))
|
||||
eq({"notification", "stderr", {3, {""}}}, next_msg())
|
||||
|
||||
command("call rpcnotify(id, 'nvim_command', 'quit')")
|
||||
eq({"notification", "exit", {3, 0}}, next_msg())
|
||||
end)
|
||||
|
||||
it('can use buffered output mode', function()
|
||||
if helpers.pending_win32(pending) then return end
|
||||
source([[
|
||||
let g:job_opts = {
|
||||
\ 'on_stdout': function('OnEvent'),
|
||||
\ 'on_exit': function('OnEvent'),
|
||||
\ 'stdout_buffered': v:true,
|
||||
\ }
|
||||
]])
|
||||
command("let id = jobstart(['grep', '^[0-9]'], g:job_opts)")
|
||||
local id = eval("g:id")
|
||||
|
||||
command([[call chansend(id, "stuff\n10 PRINT \"NVIM\"\nxx")]])
|
||||
sleep(10)
|
||||
command([[call chansend(id, "xx\n20 GOTO 10\nzz\n")]])
|
||||
command("call chanclose(id, 'stdin')")
|
||||
|
||||
eq({"notification", "stdout", {id, {'10 PRINT "NVIM"',
|
||||
'20 GOTO 10', ''}}}, next_msg())
|
||||
eq({"notification", "exit", {id, 0}}, next_msg())
|
||||
|
||||
command("let id = jobstart(['grep', '^[0-9]'], g:job_opts)")
|
||||
id = eval("g:id")
|
||||
|
||||
command([[call chansend(id, "is no number\nnot at all")]])
|
||||
command("call chanclose(id, 'stdin')")
|
||||
|
||||
-- works correctly with no output
|
||||
eq({"notification", "stdout", {id, {''}}}, next_msg())
|
||||
eq({"notification", "exit", {id, 1}}, next_msg())
|
||||
|
||||
end)
|
||||
|
||||
it('can use buffered output mode with no stream callback', function()
|
||||
if helpers.pending_win32(pending) then return end
|
||||
source([[
|
||||
function! OnEvent(id, data, event) dict
|
||||
call rpcnotify(1, a:event, a:id, a:data, self.stdout)
|
||||
endfunction
|
||||
let g:job_opts = {
|
||||
\ 'on_exit': function('OnEvent'),
|
||||
\ 'stdout_buffered': v:true,
|
||||
\ }
|
||||
]])
|
||||
command("let id = jobstart(['grep', '^[0-9]'], g:job_opts)")
|
||||
local id = eval("g:id")
|
||||
|
||||
command([[call chansend(id, "stuff\n10 PRINT \"NVIM\"\nxx")]])
|
||||
sleep(10)
|
||||
command([[call chansend(id, "xx\n20 GOTO 10\nzz\n")]])
|
||||
command("call chanclose(id, 'stdin')")
|
||||
|
||||
eq({"notification", "exit", {id, 0, {'10 PRINT "NVIM"',
|
||||
'20 GOTO 10', ''}}}, next_msg())
|
||||
|
||||
-- reset dictionary
|
||||
source([[
|
||||
let g:job_opts = {
|
||||
\ 'on_exit': function('OnEvent'),
|
||||
\ 'stdout_buffered': v:true,
|
||||
\ }
|
||||
]])
|
||||
command("let id = jobstart(['grep', '^[0-9]'], g:job_opts)")
|
||||
id = eval("g:id")
|
||||
|
||||
command([[call chansend(id, "is no number\nnot at all")]])
|
||||
command("call chanclose(id, 'stdin')")
|
||||
|
||||
-- works correctly with no output
|
||||
eq({"notification", "exit", {id, 1, {''}}}, next_msg())
|
||||
|
||||
end)
|
||||
end)
|
@@ -10,6 +10,7 @@ local wait = helpers.wait
|
||||
local iswin = helpers.iswin
|
||||
local get_pathsep = helpers.get_pathsep
|
||||
local nvim_set = helpers.nvim_set
|
||||
local expect_twostreams = helpers.expect_twostreams
|
||||
local Screen = require('test.functional.ui.screen')
|
||||
|
||||
describe('jobs', function()
|
||||
@@ -29,15 +30,14 @@ describe('jobs', function()
|
||||
\ ? map(a:data, 'substitute(v:val, "\r", "", "g")')
|
||||
\ : a:data
|
||||
endfunction
|
||||
function! s:OnEvent(id, data, event) dict
|
||||
function! OnEvent(id, data, event) dict
|
||||
let userdata = get(self, 'user')
|
||||
let data = Normalize(a:data)
|
||||
call rpcnotify(g:channel, a:event, userdata, data)
|
||||
endfunction
|
||||
let g:job_opts = {
|
||||
\ 'on_stdout': function('s:OnEvent'),
|
||||
\ 'on_stderr': function('s:OnEvent'),
|
||||
\ 'on_exit': function('s:OnEvent'),
|
||||
\ 'on_stdout': function('OnEvent'),
|
||||
\ 'on_exit': function('OnEvent'),
|
||||
\ 'user': 0
|
||||
\ }
|
||||
]])
|
||||
@@ -51,6 +51,7 @@ describe('jobs', function()
|
||||
nvim('command', "let j = jobstart('echo $VAR', g:job_opts)")
|
||||
end
|
||||
eq({'notification', 'stdout', {0, {'abc', ''}}}, next_msg())
|
||||
eq({'notification', 'stdout', {0, {''}}}, next_msg())
|
||||
eq({'notification', 'exit', {0, 0}}, next_msg())
|
||||
end)
|
||||
|
||||
@@ -63,6 +64,7 @@ describe('jobs', function()
|
||||
end
|
||||
eq({'notification', 'stdout',
|
||||
{0, {(iswin() and [[C:\]] or '/'), ''}}}, next_msg())
|
||||
eq({'notification', 'stdout', {0, {''}}}, next_msg())
|
||||
eq({'notification', 'exit', {0, 0}}, next_msg())
|
||||
end)
|
||||
|
||||
@@ -76,6 +78,7 @@ describe('jobs', function()
|
||||
nvim('command', "let j = jobstart('pwd', g:job_opts)")
|
||||
end
|
||||
eq({'notification', 'stdout', {0, {dir, ''}}}, next_msg())
|
||||
eq({'notification', 'stdout', {0, {''}}}, next_msg())
|
||||
eq({'notification', 'exit', {0, 0}}, next_msg())
|
||||
rmdir(dir)
|
||||
end)
|
||||
@@ -118,8 +121,12 @@ describe('jobs', function()
|
||||
it('invokes callbacks when the job writes and exits', function()
|
||||
-- TODO: hangs on Windows
|
||||
if helpers.pending_win32(pending) then return end
|
||||
nvim('command', "let g:job_opts.on_stderr = function('OnEvent')")
|
||||
nvim('command', "call jobstart('echo', g:job_opts)")
|
||||
eq({'notification', 'stdout', {0, {'', ''}}}, next_msg())
|
||||
expect_twostreams({{'notification', 'stdout', {0, {'', ''}}},
|
||||
{'notification', 'stdout', {0, {''}}}},
|
||||
{{'notification', 'stderr', {0, {''}}}})
|
||||
|
||||
eq({'notification', 'exit', {0, 0}}, next_msg())
|
||||
end)
|
||||
|
||||
@@ -134,6 +141,7 @@ describe('jobs', function()
|
||||
nvim('command', 'call jobsend(j, [123, "xyz", ""])')
|
||||
eq({'notification', 'stdout', {0, {'123', 'xyz', ''}}}, next_msg())
|
||||
nvim('command', "call jobstop(j)")
|
||||
eq({'notification', 'stdout', {0, {''}}}, next_msg())
|
||||
eq({'notification', 'exit', {0, 0}}, next_msg())
|
||||
end)
|
||||
|
||||
@@ -145,6 +153,7 @@ describe('jobs', function()
|
||||
|
||||
nvim('command', "let j = jobstart(['cat', '"..filename.."'], g:job_opts)")
|
||||
eq({'notification', 'stdout', {0, {'abc\ndef', ''}}}, next_msg())
|
||||
eq({'notification', 'stdout', {0, {''}}}, next_msg())
|
||||
eq({'notification', 'exit', {0, 0}}, next_msg())
|
||||
os.remove(filename)
|
||||
|
||||
@@ -168,6 +177,7 @@ describe('jobs', function()
|
||||
nvim('command', 'call jobsend(j, "abc\\nxyz")')
|
||||
eq({'notification', 'stdout', {0, {'abc', 'xyz'}}}, next_msg())
|
||||
nvim('command', "call jobstop(j)")
|
||||
eq({'notification', 'stdout', {0, {''}}}, next_msg())
|
||||
eq({'notification', 'exit', {0, 0}}, next_msg())
|
||||
end)
|
||||
|
||||
@@ -186,6 +196,7 @@ describe('jobs', function()
|
||||
eq({'notification', 'stdout', {0, {'\n123\n', 'abc\nxyz\n', ''}}},
|
||||
next_msg())
|
||||
nvim('command', "call jobstop(j)")
|
||||
eq({'notification', 'stdout', {0, {''}}}, next_msg())
|
||||
eq({'notification', 'exit', {0, 0}}, next_msg())
|
||||
end)
|
||||
|
||||
@@ -196,6 +207,7 @@ describe('jobs', function()
|
||||
eq({'notification', 'stdout', {0, {'some data', 'without\nfinal nl'}}},
|
||||
next_msg())
|
||||
nvim('command', "call jobstop(j)")
|
||||
eq({'notification', 'stdout', {0, {''}}}, next_msg())
|
||||
eq({'notification', 'exit', {0, 0}}, next_msg())
|
||||
end)
|
||||
|
||||
@@ -203,6 +215,7 @@ describe('jobs', function()
|
||||
if helpers.pending_win32(pending) then return end -- TODO: Need `cat`.
|
||||
nvim('command', "let j = jobstart(['cat', '-'], g:job_opts)")
|
||||
nvim('command', 'call jobclose(j, "stdin")')
|
||||
eq({'notification', 'stdout', {0, {''}}}, next_msg())
|
||||
eq({'notification', 'exit', {0, 0}}, next_msg())
|
||||
end)
|
||||
|
||||
@@ -239,6 +252,7 @@ describe('jobs', function()
|
||||
local pid = eval('jobpid(j)')
|
||||
eq(0,os.execute('ps -p '..pid..' > /dev/null'))
|
||||
nvim('command', 'call jobstop(j)')
|
||||
eq({'notification', 'stdout', {0, {''}}}, next_msg())
|
||||
eq({'notification', 'exit', {0, 0}}, next_msg())
|
||||
neq(0,os.execute('ps -p '..pid..' > /dev/null'))
|
||||
end)
|
||||
@@ -270,6 +284,7 @@ describe('jobs', function()
|
||||
nvim('command', [[call jobstart('echo "foo"', g:job_opts)]])
|
||||
local data = {n = 5, s = 'str', l = {1}}
|
||||
eq({'notification', 'stdout', {data, {'foo', ''}}}, next_msg())
|
||||
eq({'notification', 'stdout', {data, {''}}}, next_msg())
|
||||
eq({'notification', 'exit', {data, 0}}, next_msg())
|
||||
end)
|
||||
|
||||
@@ -283,7 +298,6 @@ describe('jobs', function()
|
||||
|
||||
it('can omit data callbacks', function()
|
||||
nvim('command', 'unlet g:job_opts.on_stdout')
|
||||
nvim('command', 'unlet g:job_opts.on_stderr')
|
||||
nvim('command', 'let g:job_opts.user = 5')
|
||||
nvim('command', [[call jobstart('echo "foo"', g:job_opts)]])
|
||||
eq({'notification', 'exit', {5, 0}}, next_msg())
|
||||
@@ -294,11 +308,13 @@ describe('jobs', function()
|
||||
nvim('command', 'let g:job_opts.user = 5')
|
||||
nvim('command', [[call jobstart('echo "foo"', g:job_opts)]])
|
||||
eq({'notification', 'stdout', {5, {'foo', ''}}}, next_msg())
|
||||
eq({'notification', 'stdout', {5, {''}}}, next_msg())
|
||||
end)
|
||||
|
||||
it('will pass return code with the exit event', function()
|
||||
nvim('command', 'let g:job_opts.user = 5')
|
||||
nvim('command', "call jobstart('exit 55', g:job_opts)")
|
||||
eq({'notification', 'stdout', {5, {''}}}, next_msg())
|
||||
eq({'notification', 'exit', {5, 55}}, next_msg())
|
||||
end)
|
||||
|
||||
@@ -341,6 +357,14 @@ describe('jobs', function()
|
||||
end)
|
||||
|
||||
it('requires funcrefs for script-local (s:) functions', function()
|
||||
local screen = Screen.new(60, 5)
|
||||
screen:attach()
|
||||
screen:set_default_attr_ids({
|
||||
[1] = {bold = true, foreground = Screen.colors.Blue1},
|
||||
[2] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red},
|
||||
[3] = {bold = true, foreground = Screen.colors.SeaGreen4}
|
||||
})
|
||||
|
||||
-- Pass job callback names _without_ `function(...)`.
|
||||
source([[
|
||||
function! s:OnEvent(id, data, event) dict
|
||||
@@ -350,14 +374,10 @@ describe('jobs', function()
|
||||
\ 'on_stdout': 's:OnEvent',
|
||||
\ 'on_stderr': 's:OnEvent',
|
||||
\ 'on_exit': 's:OnEvent',
|
||||
\ 'user': 2349
|
||||
\ })
|
||||
]])
|
||||
|
||||
-- The behavior is asynchronous, retry until a time limit.
|
||||
helpers.retry(nil, 10000, function()
|
||||
eq("E120:", string.match(eval("v:errmsg"), "E%d*:"))
|
||||
end)
|
||||
screen:expect("{2:E120: Using <SID> not in a script context: s:OnEvent}",nil,nil,nil,true)
|
||||
end)
|
||||
|
||||
it('does not repeat output with slow output handlers', function()
|
||||
@@ -376,7 +396,7 @@ describe('jobs', function()
|
||||
call jobwait([jobstart(cmd, d)])
|
||||
call rpcnotify(g:channel, 'data', d.data)
|
||||
]])
|
||||
eq({'notification', 'data', {{{'1', ''}, {'2', ''}, {'3', ''}, {'4', ''}, {'5', ''}}}}, next_msg())
|
||||
eq({'notification', 'data', {{{'1', ''}, {'2', ''}, {'3', ''}, {'4', ''}, {'5', ''}, {''}}}}, next_msg())
|
||||
end)
|
||||
|
||||
it('jobstart() works with partial functions', function()
|
||||
@@ -497,7 +517,8 @@ describe('jobs', function()
|
||||
elseif self.state == 2
|
||||
let self.state = 3
|
||||
call jobsend(a:id, "line3\n")
|
||||
else
|
||||
elseif self.state == 3
|
||||
let self.state = 4
|
||||
call rpcnotify(g:channel, 'w', printf('job %d closed', self.counter))
|
||||
call jobclose(a:id, 'stdin')
|
||||
endif
|
||||
@@ -552,6 +573,7 @@ describe('jobs', function()
|
||||
|
||||
-- FIXME need to wait until jobsend succeeds before calling jobstop
|
||||
pending('will only emit the "exit" event after "stdout" and "stderr"', function()
|
||||
nvim('command', "let g:job_opts.on_stderr = function('s:OnEvent')")
|
||||
nvim('command', "let j = jobstart(['cat', '-'], g:job_opts)")
|
||||
local jobid = nvim('eval', 'j')
|
||||
nvim('eval', 'jobsend(j, "abcdef")')
|
||||
@@ -638,7 +660,7 @@ describe('jobs', function()
|
||||
-- there won't be any more messages, and the test would hang.
|
||||
helpers.sleep(100)
|
||||
local err = exc_exec('call jobpid(j)')
|
||||
eq('Vim(call):E900: Invalid job id', err)
|
||||
eq('Vim(call):E900: Invalid channel id', err)
|
||||
|
||||
-- cleanup
|
||||
eq(other_pid, eval('jobpid(' .. other_jobid .. ')'))
|
||||
|
@@ -100,6 +100,22 @@ local function next_message()
|
||||
return session:next_message()
|
||||
end
|
||||
|
||||
local function expect_twostreams(msgs1, msgs2)
|
||||
local pos1, pos2 = 1, 1
|
||||
while pos1 <= #msgs1 or pos2 <= #msgs2 do
|
||||
local msg = next_message()
|
||||
if pos1 <= #msgs1 and pcall(eq, msgs1[pos1], msg) then
|
||||
pos1 = pos1 + 1
|
||||
elseif pos2 <= #msgs2 then
|
||||
eq(msgs2[pos2], msg)
|
||||
pos2 = pos2 + 1
|
||||
else
|
||||
-- already failed, but show the right error message
|
||||
eq(msgs1[pos1], msg)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function call_and_stop_on_error(...)
|
||||
local status, result = copcall(...) -- luacheck: ignore
|
||||
if not status then
|
||||
@@ -618,6 +634,33 @@ local function alter_slashes(obj)
|
||||
end
|
||||
end
|
||||
|
||||
local function hexdump(str)
|
||||
local len = string.len( str )
|
||||
local dump = ""
|
||||
local hex = ""
|
||||
local asc = ""
|
||||
|
||||
for i = 1, len do
|
||||
if 1 == i % 8 then
|
||||
dump = dump .. hex .. asc .. "\n"
|
||||
hex = string.format( "%04x: ", i - 1 )
|
||||
asc = ""
|
||||
end
|
||||
|
||||
local ord = string.byte( str, i )
|
||||
hex = hex .. string.format( "%02x ", ord )
|
||||
if ord >= 32 and ord <= 126 then
|
||||
asc = asc .. string.char( ord )
|
||||
else
|
||||
asc = asc .. "."
|
||||
end
|
||||
end
|
||||
|
||||
return dump .. hex
|
||||
.. string.rep( " ", 8 - len % 8 ) .. asc
|
||||
|
||||
end
|
||||
|
||||
local module = {
|
||||
prepend_argv = prepend_argv,
|
||||
clear = clear,
|
||||
@@ -636,6 +679,7 @@ local module = {
|
||||
command = nvim_command,
|
||||
request = request,
|
||||
next_message = next_message,
|
||||
expect_twostreams = expect_twostreams,
|
||||
run = run,
|
||||
stop = stop,
|
||||
eq = eq,
|
||||
@@ -687,6 +731,7 @@ local module = {
|
||||
get_pathsep = get_pathsep,
|
||||
missing_provider = missing_provider,
|
||||
alter_slashes = alter_slashes,
|
||||
hexdump = hexdump,
|
||||
}
|
||||
|
||||
return function(after_each)
|
||||
|
@@ -225,21 +225,8 @@ local function check_cores(app, force)
|
||||
local esigns = ('='):rep(len / 2)
|
||||
out:write(('\n%s Core file %s %s\n'):format(esigns, core, esigns))
|
||||
out:flush()
|
||||
local pipe = io.popen(
|
||||
db_cmd:gsub('%$_NVIM_TEST_APP', app):gsub('%$_NVIM_TEST_CORE', core)
|
||||
.. ' 2>&1', 'r')
|
||||
if pipe then
|
||||
local bt = pipe:read('*a')
|
||||
if bt then
|
||||
out:write(bt)
|
||||
out:write('\n')
|
||||
else
|
||||
out:write('Failed to read from the pipe\n')
|
||||
end
|
||||
else
|
||||
out:write('Failed to create pipe\n')
|
||||
end
|
||||
out:flush()
|
||||
os.execute(db_cmd:gsub('%$_NVIM_TEST_APP', app):gsub('%$_NVIM_TEST_CORE', core) .. ' 2>&1')
|
||||
out:write('\n')
|
||||
found_cores = found_cores + 1
|
||||
os.remove(core)
|
||||
end
|
||||
|
Reference in New Issue
Block a user