neovim/test/functional/terminal/ex_terminal_spec.lua
dundargoc 2d6735d8ce
ci: move BSD jobs from sourcehut to Cirrus CI #19616
dispatch.sr.ht is being deprecated, meaning that using sourcehut CI
won't be possible (see https://github.com/neovim/neovim/issues/19609).
Since Github Actions doesn't provide any BSD runners an external service
is required and Cirrus CI seems like a good replacement for sourcehut.

Initially experimented with using FreeBSD and OpenBSD virtual machines
in GitHub Actions, but Cirrus has been a much better fit with better
performance, logs and overall experience.

Failing tests are automatically skipped on FreeBSD regardless if it's on
CI or not. Ideally these tests should only be skipped in CI with the
help of `isCI` helper function. Unfortunately, the tests don't recognize
the environment variable CIRRUS_CI even if it's set manually. This
workaround is good enough for the time being, but we might want to only
skip tests when using the CI (or even better, fix the failing tests).

Closes: https://github.com/neovim/neovim/issues/19609
2022-09-08 15:12:42 -07:00

294 lines
10 KiB
Lua

local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen')
local assert_alive = helpers.assert_alive
local clear, poke_eventloop, nvim = helpers.clear, helpers.poke_eventloop, helpers.nvim
local testprg, source, eq = helpers.testprg, helpers.source, helpers.eq
local feed = helpers.feed
local feed_command, eval = helpers.feed_command, helpers.eval
local funcs = helpers.funcs
local retry = helpers.retry
local ok = helpers.ok
local iswin = helpers.iswin
local command = helpers.command
local uname = helpers.uname
describe(':terminal', function()
local screen
before_each(function()
clear()
screen = Screen.new(50, 4)
screen:attach({rgb=false})
end)
it("does not interrupt Press-ENTER prompt #2748", function()
-- Ensure that :messages shows Press-ENTER.
source([[
echomsg "msg1"
echomsg "msg2"
echomsg "msg3"
]])
-- Invoke a command that emits frequent terminal activity.
feed([[:terminal "]]..testprg('shell-test')..[[" REP 9999 !terminal_output!<cr>]])
feed([[<C-\><C-N>]])
poke_eventloop()
-- Wait for some terminal activity.
retry(nil, 4000, function()
ok(funcs.line('$') > 6)
end)
feed_command("messages")
screen:expect([[
msg1 |
msg2 |
msg3 |
Press ENTER or type command to continue^ |
]])
end)
it("reads output buffer on terminal reporting #4151", function()
if uname() == 'freebsd' then
pending('Failing FreeBSD test')
end
if helpers.pending_win32(pending) then return end
if iswin() then
feed_command([[terminal powershell -NoProfile -NoLogo -Command Write-Host -NoNewline "\"$([char]27)[6n\""; Start-Sleep -Milliseconds 500 ]])
else
feed_command([[terminal printf '\e[6n'; sleep 0.5 ]])
end
screen:expect{any='%^%[%[1;1R'}
end)
it("in normal-mode :split does not move cursor", function()
if iswin() then
feed_command([[terminal for /L \\%I in (1,0,2) do ( echo foo & ping -w 100 -n 1 127.0.0.1 > nul )]])
else
feed_command([[terminal while true; do echo foo; sleep .1; done]])
end
feed([[<C-\><C-N>M]]) -- move cursor away from last line
poke_eventloop()
eq(3, eval("line('$')")) -- window height
eq(2, eval("line('.')")) -- cursor is in the middle
feed_command('vsplit')
eq(2, eval("line('.')")) -- cursor stays where we put it
feed_command('split')
eq(2, eval("line('.')")) -- cursor stays where we put it
end)
it('Enter/Leave does not increment jumplist #3723', function()
feed_command('terminal')
local function enter_and_leave()
local lines_before = funcs.line('$')
-- Create a new line (in the shell). For a normal buffer this
-- increments the jumplist; for a terminal-buffer it should not. #3723
feed('i')
poke_eventloop()
feed('<CR><CR><CR><CR>')
poke_eventloop()
feed([[<C-\><C-N>]])
poke_eventloop()
-- Wait for >=1 lines to be created.
retry(nil, 4000, function()
ok(funcs.line('$') > lines_before)
end)
end
enter_and_leave()
enter_and_leave()
enter_and_leave()
ok(funcs.line('$') > 6) -- Verify assumption.
local jumps = funcs.split(funcs.execute('jumps'), '\n')
eq(' jump line col file/text', jumps[1])
eq(3, #jumps)
end)
it('nvim_get_mode() in :terminal', function()
command(':terminal')
eq({ blocking=false, mode='nt' }, nvim('get_mode'))
feed('i')
eq({ blocking=false, mode='t' }, nvim('get_mode'))
feed([[<C-\><C-N>]])
eq({ blocking=false, mode='nt' }, nvim('get_mode'))
end)
it(':stopinsert RPC request exits terminal-mode #7807', function()
command(':terminal')
feed('i[tui] insert-mode')
eq({ blocking=false, mode='t' }, nvim('get_mode'))
command('stopinsert')
eq({ blocking=false, mode='nt' }, nvim('get_mode'))
end)
it(':stopinsert in normal mode doesn\'t break insert mode #9889', function()
command(':terminal')
eq({ blocking=false, mode='nt' }, nvim('get_mode'))
command(':stopinsert')
eq({ blocking=false, mode='nt' }, nvim('get_mode'))
feed('a')
eq({ blocking=false, mode='t' }, nvim('get_mode'))
end)
end)
describe(':terminal (with fake shell)', function()
local screen
before_each(function()
clear()
screen = Screen.new(50, 4)
screen:attach({rgb=false})
-- shell-test.c is a fake shell that prints its arguments and exits.
nvim('set_option', 'shell', testprg('shell-test'))
nvim('set_option', 'shellcmdflag', 'EXE')
end)
-- Invokes `:terminal {cmd}` using a fake shell (shell-test.c) which prints
-- the {cmd} and exits immediately .
local function terminal_with_fake_shell(cmd)
feed_command("terminal "..(cmd and cmd or ""))
end
it('with no argument, acts like termopen()', function()
if helpers.pending_win32(pending) then return end
terminal_with_fake_shell()
retry(nil, 4 * screen.timeout, function()
screen:expect([[
^ready $ |
[Process exited 0] |
|
:terminal |
]])
end)
end)
it("with no argument, and 'shell' is set to empty string", function()
nvim('set_option', 'shell', '')
terminal_with_fake_shell()
screen:expect([[
^ |
~ |
~ |
E91: 'shell' option is empty |
]])
end)
it("with no argument, but 'shell' has arguments, acts like termopen()", function()
if helpers.pending_win32(pending) then return end
nvim('set_option', 'shell', testprg('shell-test')..' -t jeff')
terminal_with_fake_shell()
screen:expect([[
^jeff $ |
[Process exited 0] |
|
:terminal |
]])
end)
it('executes a given command through the shell', function()
if helpers.pending_win32(pending) then return end
command('set shellxquote=') -- win: avoid extra quotes
terminal_with_fake_shell('echo hi')
screen:expect([[
^ready $ echo hi |
|
[Process exited 0] |
:terminal echo hi |
]])
end)
it("executes a given command through the shell, when 'shell' has arguments", function()
if helpers.pending_win32(pending) then return end
nvim('set_option', 'shell', testprg('shell-test')..' -t jeff')
command('set shellxquote=') -- win: avoid extra quotes
terminal_with_fake_shell('echo hi')
screen:expect([[
^jeff $ echo hi |
|
[Process exited 0] |
:terminal echo hi |
]])
end)
it('allows quotes and slashes', function()
if helpers.pending_win32(pending) then return end
command('set shellxquote=') -- win: avoid extra quotes
terminal_with_fake_shell([[echo 'hello' \ "world"]])
screen:expect([[
^ready $ echo 'hello' \ "world" |
|
[Process exited 0] |
:terminal echo 'hello' \ "world" |
]])
end)
it('ex_terminal() double-free #4554', function()
source([[
autocmd BufNew * set shell=foo
terminal]])
-- Verify that BufNew actually fired (else the test is invalid).
eq('foo', eval('&shell'))
end)
it('ignores writes if the backing stream closes', function()
terminal_with_fake_shell()
feed('iiXXXXXXX')
poke_eventloop()
-- Race: Though the shell exited (and streams were closed by SIGCHLD
-- handler), :terminal cleanup is pending on the main-loop.
-- This write should be ignored (not crash, #5445).
feed('iiYYYYYYY')
assert_alive()
end)
it('works with findfile()', function()
feed_command('terminal')
eq('term://', string.match(eval('bufname("%")'), "^term://"))
eq('scripts/shadacat.py', eval('findfile("scripts/shadacat.py", ".")'))
end)
it('works with :find', function()
if helpers.pending_win32(pending) then return end
terminal_with_fake_shell()
screen:expect([[
^ready $ |
[Process exited 0] |
|
:terminal |
]])
eq('term://', string.match(eval('bufname("%")'), "^term://"))
feed([[<C-\><C-N>]])
feed_command([[find */shadacat.py]])
if iswin() then
eq('scripts\\shadacat.py', eval('bufname("%")'))
else
eq('scripts/shadacat.py', eval('bufname("%")'))
end
end)
it('works with gf', function()
if helpers.pending_win32(pending) then return end
command('set shellxquote=') -- win: avoid extra quotes
terminal_with_fake_shell([[echo "scripts/shadacat.py"]])
retry(nil, 4 * screen.timeout, function()
screen:expect([[
^ready $ echo "scripts/shadacat.py" |
|
[Process exited 0] |
:terminal echo "scripts/shadacat.py" |
]])
end)
feed([[<C-\><C-N>]])
eq('term://', string.match(eval('bufname("%")'), "^term://"))
feed([[ggf"lgf]])
eq('scripts/shadacat.py', eval('bufname("%")'))
end)
it('with bufhidden=delete #3958', function()
command('set hidden')
eq(1, eval('&hidden'))
command('autocmd BufNew * setlocal bufhidden=delete')
for _ = 1, 5 do
source([[
execute 'edit '.reltimestr(reltime())
terminal]])
end
end)
end)