mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
tests: improve robustness of immediate successes in screen tests
This commit is contained in:
parent
8fd092f3ff
commit
c8810a51a3
@ -20,15 +20,15 @@ describe("update_menu notification", function()
|
||||
end)
|
||||
|
||||
local function expect_sent(expected)
|
||||
screen:wait(function()
|
||||
screen:expect{condition=function()
|
||||
if screen.update_menu ~= expected then
|
||||
if expected then
|
||||
return 'update_menu was expected but not sent'
|
||||
error('update_menu was expected but not sent')
|
||||
else
|
||||
return 'update_menu was sent unexpectedly'
|
||||
error('update_menu was sent unexpectedly')
|
||||
end
|
||||
end
|
||||
end)
|
||||
end, unchanged=(not expected)}
|
||||
end
|
||||
|
||||
it("should be sent when adding a menu", function()
|
||||
|
@ -161,13 +161,13 @@ describe('execute()', function()
|
||||
eq('42', eval('g:mes'))
|
||||
|
||||
command('let g:mes = execute("echon 13", "silent")')
|
||||
screen:expect([[
|
||||
screen:expect{grid=[[
|
||||
^ |
|
||||
~ |
|
||||
~ |
|
||||
~ |
|
||||
|
|
||||
]])
|
||||
]], unchanged=true}
|
||||
eq('13', eval('g:mes'))
|
||||
end)
|
||||
|
||||
|
@ -150,13 +150,13 @@ describe('input()', function()
|
||||
{T:Foo>}Bar^ |
|
||||
]])
|
||||
command('redraw!')
|
||||
screen:expect([[
|
||||
screen:expect{grid=[[
|
||||
|
|
||||
{EOB:~ }|
|
||||
{EOB:~ }|
|
||||
{EOB:~ }|
|
||||
{T:Foo>}Bar^ |
|
||||
]])
|
||||
]], reset=true}
|
||||
feed('<BS>')
|
||||
screen:expect([[
|
||||
|
|
||||
@ -166,13 +166,13 @@ describe('input()', function()
|
||||
{T:Foo>}Ba^ |
|
||||
]])
|
||||
command('redraw!')
|
||||
screen:expect([[
|
||||
screen:expect{grid=[[
|
||||
|
|
||||
{EOB:~ }|
|
||||
{EOB:~ }|
|
||||
{EOB:~ }|
|
||||
{T:Foo>}Ba^ |
|
||||
]])
|
||||
]], reset=true}
|
||||
end)
|
||||
it('allows omitting everything with dictionary argument', function()
|
||||
command('echohl Test')
|
||||
@ -348,13 +348,13 @@ describe('inputdialog()', function()
|
||||
{T:Foo>}Bar^ |
|
||||
]])
|
||||
command('redraw!')
|
||||
screen:expect([[
|
||||
screen:expect{grid=[[
|
||||
|
|
||||
{EOB:~ }|
|
||||
{EOB:~ }|
|
||||
{EOB:~ }|
|
||||
{T:Foo>}Bar^ |
|
||||
]])
|
||||
]], reset=true}
|
||||
feed('<BS>')
|
||||
screen:expect([[
|
||||
|
|
||||
@ -364,13 +364,13 @@ describe('inputdialog()', function()
|
||||
{T:Foo>}Ba^ |
|
||||
]])
|
||||
command('redraw!')
|
||||
screen:expect([[
|
||||
screen:expect{grid=[[
|
||||
|
|
||||
{EOB:~ }|
|
||||
{EOB:~ }|
|
||||
{EOB:~ }|
|
||||
{T:Foo>}Ba^ |
|
||||
]])
|
||||
]], reset=true}
|
||||
end)
|
||||
it('allows omitting everything with dictionary argument', function()
|
||||
command('echohl Test')
|
||||
|
@ -113,7 +113,6 @@ describe('timers', function()
|
||||
^ |
|
||||
]])
|
||||
|
||||
screen:sleep(200)
|
||||
screen:expect([[
|
||||
ITEM 1 |
|
||||
ITEM 2 |
|
||||
@ -200,13 +199,14 @@ describe('timers', function()
|
||||
screen:attach()
|
||||
screen:set_default_attr_ids( {[0] = {bold=true, foreground=255}} )
|
||||
source([[
|
||||
let g:val = 0
|
||||
func! MyHandler(timer)
|
||||
echo "evil"
|
||||
let g:val = 1
|
||||
endfunc
|
||||
]])
|
||||
command("call timer_start(100, 'MyHandler', {'repeat': 1})")
|
||||
feed(":good")
|
||||
screen:sleep(200)
|
||||
screen:expect([[
|
||||
|
|
||||
{0:~ }|
|
||||
@ -215,6 +215,17 @@ describe('timers', function()
|
||||
{0:~ }|
|
||||
:good^ |
|
||||
]])
|
||||
|
||||
screen:expect{grid=[[
|
||||
|
|
||||
{0:~ }|
|
||||
{0:~ }|
|
||||
{0:~ }|
|
||||
{0:~ }|
|
||||
:good^ |
|
||||
]], intermediate=true, timeout=200}
|
||||
|
||||
eq(1, eval('g:val'))
|
||||
end)
|
||||
|
||||
end)
|
||||
|
@ -92,6 +92,7 @@ describe('search cmdline', function()
|
||||
9 {inc:the}se |
|
||||
/the^ |
|
||||
]])
|
||||
screen.bell = false
|
||||
feed('<C-G>')
|
||||
if wrapscan == 'wrapscan' then
|
||||
screen:expect([[
|
||||
@ -100,11 +101,13 @@ describe('search cmdline', function()
|
||||
/the^ |
|
||||
]])
|
||||
else
|
||||
screen:expect([[
|
||||
screen:expect{grid=[[
|
||||
8 them |
|
||||
9 {inc:the}se |
|
||||
/the^ |
|
||||
]])
|
||||
]], condition=function()
|
||||
eq(true, screen.bell)
|
||||
end}
|
||||
feed('<CR>')
|
||||
eq({0, 0, 0, 0}, funcs.getpos('"'))
|
||||
end
|
||||
@ -120,6 +123,7 @@ describe('search cmdline', function()
|
||||
10 foobar |
|
||||
?the^ |
|
||||
]])
|
||||
screen.bell = false
|
||||
if wrapscan == 'wrapscan' then
|
||||
feed('<C-G>')
|
||||
screen:expect([[
|
||||
@ -135,11 +139,13 @@ describe('search cmdline', function()
|
||||
]])
|
||||
else
|
||||
feed('<C-G>')
|
||||
screen:expect([[
|
||||
screen:expect{grid=[[
|
||||
9 {inc:the}se |
|
||||
10 foobar |
|
||||
?the^ |
|
||||
]])
|
||||
]], condition=function()
|
||||
eq(true, screen.bell)
|
||||
end}
|
||||
feed('<CR>')
|
||||
screen:expect([[
|
||||
9 ^these |
|
||||
@ -173,6 +179,7 @@ describe('search cmdline', function()
|
||||
3 the |
|
||||
?the^ |
|
||||
]])
|
||||
screen.bell = false
|
||||
feed('<C-T>')
|
||||
if wrapscan == 'wrapscan' then
|
||||
screen:expect([[
|
||||
@ -181,11 +188,13 @@ describe('search cmdline', function()
|
||||
?the^ |
|
||||
]])
|
||||
else
|
||||
screen:expect([[
|
||||
screen:expect{grid=[[
|
||||
2 {inc:the}se |
|
||||
3 the |
|
||||
?the^ |
|
||||
]])
|
||||
]], condition=function()
|
||||
eq(true, screen.bell)
|
||||
end}
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -874,20 +874,23 @@ describe('put command', function()
|
||||
local function bell_test(actions, should_ring)
|
||||
local screen = Screen.new()
|
||||
screen:attach()
|
||||
if should_ring then
|
||||
-- check bell is not set by nvim before the action
|
||||
screen:sleep(50)
|
||||
end
|
||||
helpers.ok(not screen.bell and not screen.visualbell)
|
||||
actions()
|
||||
helpers.wait()
|
||||
screen:wait(function()
|
||||
screen:expect{condition=function()
|
||||
if should_ring then
|
||||
if not screen.bell and not screen.visualbell then
|
||||
return 'Bell was not rung after action'
|
||||
error('Bell was not rung after action')
|
||||
end
|
||||
else
|
||||
if screen.bell or screen.visualbell then
|
||||
return 'Bell was rung after action'
|
||||
error('Bell was rung after action')
|
||||
end
|
||||
end
|
||||
end)
|
||||
end, unchanged=(not should_ring)}
|
||||
screen:detach()
|
||||
end
|
||||
|
||||
|
@ -36,6 +36,13 @@ describe("'fillchars'", function()
|
||||
]])
|
||||
end)
|
||||
it('supports whitespace', function()
|
||||
screen:expect([[
|
||||
^ |
|
||||
~ |
|
||||
~ |
|
||||
~ |
|
||||
|
|
||||
]])
|
||||
command('set fillchars=eob:\\ ')
|
||||
screen:expect([[
|
||||
^ |
|
||||
|
@ -426,9 +426,8 @@ describe("'scrollback' option", function()
|
||||
curbufmeths.set_option('scrollback', 200)
|
||||
|
||||
-- Wait for prompt.
|
||||
screen:expect{any='$'}
|
||||
screen:expect{any='%$'}
|
||||
|
||||
wait()
|
||||
if iswin() then
|
||||
feed_data('for($i=1;$i -le 30;$i++){Write-Host \"line$i\"}\r')
|
||||
else
|
||||
|
@ -370,7 +370,7 @@ describe('tui FocusGained/FocusLost', function()
|
||||
{3:-- TERMINAL --} |
|
||||
]])
|
||||
feed_data('\027[O')
|
||||
screen:expect([[
|
||||
screen:expect{grid=[[
|
||||
|
|
||||
{4:~ }|
|
||||
{4:~ }|
|
||||
@ -378,7 +378,7 @@ describe('tui FocusGained/FocusLost', function()
|
||||
{5:[No Name] }|
|
||||
:{1: } |
|
||||
{3:-- TERMINAL --} |
|
||||
]])
|
||||
]], unchanged=true}
|
||||
end)
|
||||
|
||||
it('in cmdline-mode', function()
|
||||
|
@ -267,7 +267,7 @@ describe('Command-line coloring', function()
|
||||
:echo {RBP1:(}{RBP2:(}42{RBP2:)}^ |
|
||||
]])
|
||||
redraw_input()
|
||||
screen:expect([[
|
||||
screen:expect{grid=[[
|
||||
|
|
||||
{EOB:~ }|
|
||||
{EOB:~ }|
|
||||
@ -276,7 +276,7 @@ describe('Command-line coloring', function()
|
||||
{EOB:~ }|
|
||||
{EOB:~ }|
|
||||
:echo {RBP1:(}{RBP2:(}42{RBP2:)}^ |
|
||||
]])
|
||||
]], reset=true}
|
||||
end)
|
||||
for _, func_part in ipairs({'', 'n', 'msg'}) do
|
||||
it('disables :echo' .. func_part .. ' messages', function()
|
||||
@ -855,17 +855,6 @@ describe('Ex commands coloring support', function()
|
||||
{EOB:~ }|
|
||||
|
|
||||
]])
|
||||
feed('<CR>')
|
||||
screen:expect([[
|
||||
^ |
|
||||
{EOB:~ }|
|
||||
{EOB:~ }|
|
||||
{EOB:~ }|
|
||||
{EOB:~ }|
|
||||
{EOB:~ }|
|
||||
{EOB:~ }|
|
||||
|
|
||||
]])
|
||||
eq('Error detected while processing :\nE605: Exception not caught: 42',
|
||||
meths.command_output('messages'))
|
||||
end)
|
||||
|
@ -253,9 +253,6 @@ local function test_cmdline(linegrid)
|
||||
]], cmdline=expectation}
|
||||
|
||||
-- erase information, so we check if it is retransmitted
|
||||
-- TODO(bfredl): when we add a flag to screen:expect{}
|
||||
-- to explicitly check redraw!, it should also do this
|
||||
screen.cmdline = {}
|
||||
command("redraw!")
|
||||
screen:expect{grid=[[
|
||||
^ |
|
||||
@ -263,7 +260,7 @@ local function test_cmdline(linegrid)
|
||||
{1:~ }|
|
||||
{1:~ }|
|
||||
|
|
||||
]], cmdline=expectation}
|
||||
]], cmdline=expectation, reset=true}
|
||||
|
||||
|
||||
feed('<cr>')
|
||||
@ -323,7 +320,6 @@ local function test_cmdline(linegrid)
|
||||
{{' line1'}},
|
||||
}}
|
||||
|
||||
screen.cmdline_block = {}
|
||||
command("redraw!")
|
||||
screen:expect{grid=[[
|
||||
^ |
|
||||
@ -339,7 +335,7 @@ local function test_cmdline(linegrid)
|
||||
}}, cmdline_block = {
|
||||
{{'function Foo()'}},
|
||||
{{' line1'}},
|
||||
}}
|
||||
}, reset=true}
|
||||
|
||||
feed('endfunction<cr>')
|
||||
screen:expect{grid=[[
|
||||
@ -415,7 +411,6 @@ local function test_cmdline(linegrid)
|
||||
pos = 4,
|
||||
}}}
|
||||
|
||||
screen.cmdline = {}
|
||||
command("redraw!")
|
||||
screen:expect{grid=[[
|
||||
|
|
||||
@ -427,7 +422,7 @@ local function test_cmdline(linegrid)
|
||||
firstc = ":",
|
||||
content = {{"yank"}},
|
||||
pos = 4,
|
||||
}}}
|
||||
}}, reset=true}
|
||||
|
||||
feed("<c-c>")
|
||||
screen:expect{grid=[[
|
||||
|
@ -870,7 +870,7 @@ describe("'winhighlight' highlight", function()
|
||||
eq('Vim(set):E474: Invalid argument: winhl=xxx:yyy',
|
||||
exc_exec("set winhl=xxx:yyy"))
|
||||
eq('Normal:Background1', eval('&winhl'))
|
||||
screen:expect([[
|
||||
screen:expect{grid=[[
|
||||
{1:^ }|
|
||||
{2:~ }|
|
||||
{2:~ }|
|
||||
@ -879,7 +879,7 @@ describe("'winhighlight' highlight", function()
|
||||
{2:~ }|
|
||||
{2:~ }|
|
||||
|
|
||||
]])
|
||||
]], unchanged=true}
|
||||
end)
|
||||
|
||||
|
||||
|
@ -495,6 +495,18 @@ describe(":substitute, 'inccommand' preserves undo", function()
|
||||
for _, case in pairs(cases) do
|
||||
clear()
|
||||
common_setup(screen, case, default_text)
|
||||
screen:expect([[
|
||||
Inc substitution on |
|
||||
two lines |
|
||||
^ |
|
||||
{15:~ }|
|
||||
{15:~ }|
|
||||
{15:~ }|
|
||||
{15:~ }|
|
||||
{15:~ }|
|
||||
{15:~ }|
|
||||
|
|
||||
]])
|
||||
feed_command("set undolevels=1")
|
||||
|
||||
feed("1G0")
|
||||
@ -757,8 +769,23 @@ describe(":substitute, inccommand=split", function()
|
||||
|
||||
-- non-modifier prefix
|
||||
feed(':silent tabedit %s/tw/to')
|
||||
screen:expect{any=[[two lines]]}
|
||||
feed('<Esc>')
|
||||
screen:expect([[
|
||||
Inc substitution on |
|
||||
two lines |
|
||||
Inc substitution on |
|
||||
two lines |
|
||||
|
|
||||
{15:~ }|
|
||||
{15:~ }|
|
||||
{15:~ }|
|
||||
{15:~ }|
|
||||
{15:~ }|
|
||||
{15:~ }|
|
||||
{15:~ }|
|
||||
{15:~ }|
|
||||
{15:~ }|
|
||||
:silent tabedit %s/tw/to^ |
|
||||
]])
|
||||
end)
|
||||
|
||||
it('shows split window when typing the pattern', function()
|
||||
@ -866,7 +893,6 @@ describe(":substitute, inccommand=split", function()
|
||||
it('does not show split window for :s/', function()
|
||||
feed("2gg")
|
||||
feed(":s/tw")
|
||||
screen:sleep(1)
|
||||
screen:expect([[
|
||||
Inc substitution on |
|
||||
{12:tw}o lines |
|
||||
@ -1234,8 +1260,18 @@ describe("inccommand=nosplit", function()
|
||||
|
||||
-- non-modifier prefix
|
||||
feed(':silent tabedit %s/tw/to')
|
||||
screen:expect{any=[[two lines]]}
|
||||
feed('<Esc>')
|
||||
screen:expect([[
|
||||
two lines |
|
||||
Inc substitution on |
|
||||
two lines |
|
||||
|
|
||||
{15:~ }|
|
||||
{15:~ }|
|
||||
{15:~ }|
|
||||
{15:~ }|
|
||||
:silent tabedit %s/t|
|
||||
w/to^ |
|
||||
]])
|
||||
end)
|
||||
|
||||
it("does not show window after toggling :set inccommand", function()
|
||||
|
@ -168,13 +168,13 @@ describe('ui/mouse/input', function()
|
||||
|
|
||||
]])
|
||||
feed('<LeftMouse><11,0>')
|
||||
screen:expect([[
|
||||
screen:expect{grid=[[
|
||||
{tab: + foo }{sel: + bar }{fill: }{tab:X}|
|
||||
this is ba^r |
|
||||
{0:~ }|
|
||||
{0:~ }|
|
||||
|
|
||||
]])
|
||||
]], unchanged=true}
|
||||
feed('<LeftDrag><6,0>')
|
||||
screen:expect([[
|
||||
{sel: + bar }{tab: + foo }{fill: }{tab:X}|
|
||||
@ -236,13 +236,13 @@ describe('ui/mouse/input', function()
|
||||
|
|
||||
]])
|
||||
feed('<LeftDrag><4,1>')
|
||||
screen:expect([[
|
||||
screen:expect{grid=[[
|
||||
{sel: + foo }{tab: + bar }{fill: }{tab:X}|
|
||||
this is fo^o |
|
||||
{0:~ }|
|
||||
{0:~ }|
|
||||
|
|
||||
]])
|
||||
]], unchanged=true}
|
||||
feed('<LeftDrag><14,1>')
|
||||
screen:expect([[
|
||||
{tab: + bar }{sel: + foo }{fill: }{tab:X}|
|
||||
@ -254,13 +254,6 @@ describe('ui/mouse/input', function()
|
||||
end)
|
||||
|
||||
it('out of tabline to the left moves tab left', function()
|
||||
if helpers.skip_fragile(pending,
|
||||
os.getenv("TRAVIS") and (helpers.os_name() == "osx"
|
||||
or os.getenv("CLANG_SANITIZER") == "ASAN_UBSAN")) -- #4874
|
||||
then
|
||||
return
|
||||
end
|
||||
|
||||
feed_command('%delete')
|
||||
insert('this is foo')
|
||||
feed_command('silent file foo | tabnew | file bar')
|
||||
@ -273,21 +266,21 @@ describe('ui/mouse/input', function()
|
||||
|
|
||||
]])
|
||||
feed('<LeftMouse><11,0>')
|
||||
screen:expect([[
|
||||
screen:expect{grid=[[
|
||||
{tab: + foo }{sel: + bar }{fill: }{tab:X}|
|
||||
this is ba^r |
|
||||
{0:~ }|
|
||||
{0:~ }|
|
||||
|
|
||||
]])
|
||||
]], unchanged=true}
|
||||
feed('<LeftDrag><11,1>')
|
||||
screen:expect([[
|
||||
screen:expect{grid=[[
|
||||
{tab: + foo }{sel: + bar }{fill: }{tab:X}|
|
||||
this is ba^r |
|
||||
{0:~ }|
|
||||
{0:~ }|
|
||||
|
|
||||
]])
|
||||
]], unchanged=true}
|
||||
feed('<LeftDrag><6,1>')
|
||||
screen:expect([[
|
||||
{sel: + bar }{tab: + foo }{fill: }{tab:X}|
|
||||
@ -319,13 +312,13 @@ describe('ui/mouse/input', function()
|
||||
|
|
||||
]])
|
||||
feed('<LeftDrag><4,1>')
|
||||
screen:expect([[
|
||||
screen:expect{grid=[[
|
||||
{sel: + foo }{tab: + bar }{fill: }{tab:X}|
|
||||
this is fo^o |
|
||||
{0:~ }|
|
||||
{0:~ }|
|
||||
|
|
||||
]])
|
||||
]], unchanged=true}
|
||||
feed('<LeftDrag><7,1>')
|
||||
screen:expect([[
|
||||
{tab: + bar }{sel: + foo }{fill: }{tab:X}|
|
||||
|
@ -51,25 +51,20 @@ describe("shell command :!", function()
|
||||
end)
|
||||
|
||||
it("throttles shell-command output greater than ~10KB", function()
|
||||
if os.getenv("TRAVIS") and helpers.os_name() == "osx" then
|
||||
pending("[Unreliable on Travis macOS.]", function() end)
|
||||
return
|
||||
end
|
||||
|
||||
screen.timeout = 20000 -- Avoid false failure on slow systems.
|
||||
child_session.feed_data(
|
||||
":!for i in $(seq 2 3000); do echo XXXXXXXXXX $i; done\n")
|
||||
":!for i in $(seq 2 30000); do echo XXXXXXXXXX $i; done\n")
|
||||
|
||||
-- If we observe any line starting with a dot, then throttling occurred.
|
||||
screen:expect{any="\n."}
|
||||
-- Avoid false failure on slow systems.
|
||||
screen:expect{any="\n%.", timeout=20000}
|
||||
|
||||
-- Final chunk of output should always be displayed, never skipped.
|
||||
-- (Throttling is non-deterministic, this test is merely a sanity check.)
|
||||
screen:expect([[
|
||||
XXXXXXXXXX 2997 |
|
||||
XXXXXXXXXX 2998 |
|
||||
XXXXXXXXXX 2999 |
|
||||
XXXXXXXXXX 3000 |
|
||||
XXXXXXXXXX 29997 |
|
||||
XXXXXXXXXX 29998 |
|
||||
XXXXXXXXXX 29999 |
|
||||
XXXXXXXXXX 30000 |
|
||||
|
|
||||
{10:Press ENTER or type command to continue}{1: } |
|
||||
{3:-- TERMINAL --} |
|
||||
|
@ -89,15 +89,17 @@ Screen.__index = Screen
|
||||
|
||||
local debug_screen
|
||||
|
||||
local default_screen_timeout = 3500
|
||||
local default_timeout_factor = 1
|
||||
if os.getenv('VALGRIND') then
|
||||
default_screen_timeout = default_screen_timeout * 3
|
||||
default_timeout_factor = default_timeout_factor * 3
|
||||
end
|
||||
|
||||
if os.getenv('CI') then
|
||||
default_screen_timeout = default_screen_timeout * 3
|
||||
default_timeout_factor = default_timeout_factor * 3
|
||||
end
|
||||
|
||||
local default_screen_timeout = default_timeout_factor * 3500
|
||||
|
||||
do
|
||||
local spawn, nvim_prog = helpers.spawn, helpers.nvim_prog
|
||||
local session = spawn({nvim_prog, '-u', 'NONE', '-i', 'NONE', '-N', '--embed'})
|
||||
@ -160,12 +162,13 @@ function Screen.new(width, height)
|
||||
_attr_table = {[0]={{},{}}},
|
||||
_clear_attrs = {},
|
||||
_new_attrs = false,
|
||||
_width = width,
|
||||
_height = height,
|
||||
_cursor = {
|
||||
row = 1, col = 1
|
||||
},
|
||||
_busy = false
|
||||
}, Screen)
|
||||
self:_handle_resize(width, height)
|
||||
return self
|
||||
end
|
||||
|
||||
@ -190,6 +193,7 @@ function Screen:attach(options)
|
||||
end
|
||||
self._options = options
|
||||
self._clear_attrs = (options.ext_linegrid and {{},{}}) or {}
|
||||
self:_handle_resize(self._width, self._height)
|
||||
uimeths.attach(self._width, self._height, options)
|
||||
if self._options.rgb == nil then
|
||||
-- nvim defaults to rgb=true internally,
|
||||
@ -243,8 +247,27 @@ local ext_keys = {
|
||||
-- nothing is ignored.
|
||||
-- condition: Function asserting some arbitrary condition. Return value is
|
||||
-- ignored, throw an error (use eq() or similar) to signal failure.
|
||||
-- any: Lua pattern string expected to match a screen line.
|
||||
-- any: Lua pattern string expected to match a screen line. NB: the
|
||||
-- following chars are magic characters
|
||||
-- ( ) . % + - * ? [ ^ $
|
||||
-- and must be escaped with a preceding % for a literal match.
|
||||
-- mode: Expected mode as signaled by "mode_change" event
|
||||
-- unchanged: Test that the screen state is unchanged since the previous
|
||||
-- expect(...). Any flush event resulting in a different state is
|
||||
-- considered an error. Not observing any events until timeout
|
||||
-- is acceptable.
|
||||
-- intermediate:Test that the final state is the same as the previous expect,
|
||||
-- but expect an intermediate state that is different. If possible
|
||||
-- it is better to use an explicit screen:expect(...) for this
|
||||
-- intermediate state.
|
||||
-- reset: Reset the state internal to the test Screen before starting to
|
||||
-- receive updates. This should be used after command("redraw!")
|
||||
-- or some other mechanism that will invoke "redraw!", to check
|
||||
-- that all screen state is transmitted again. This includes
|
||||
-- state related to ext_ features as mentioned below.
|
||||
-- timeout: maximum time that will be waited until the expected state is
|
||||
-- seen (or maximum time to observe an incorrect change when
|
||||
-- `unchanged` flag is used)
|
||||
--
|
||||
-- The following keys should be used to expect the state of various ext_
|
||||
-- features. Note that an absent key will assert that the item is currently
|
||||
@ -262,7 +285,8 @@ function Screen:expect(expected, attr_ids, attr_ignore)
|
||||
if type(expected) == "table" then
|
||||
assert(not (attr_ids ~= nil or attr_ignore ~= nil))
|
||||
local is_key = {grid=true, attr_ids=true, attr_ignore=true, condition=true,
|
||||
any=true, mode=true}
|
||||
any=true, mode=true, unchanged=true, intermediate=true,
|
||||
reset=true, timeout=true}
|
||||
for _, v in ipairs(ext_keys) do
|
||||
is_key[v] = true
|
||||
end
|
||||
@ -304,7 +328,7 @@ function Screen:expect(expected, attr_ids, attr_ignore)
|
||||
attr_state.id_to_index = self:hlstate_check_attrs(attr_state.ids or {})
|
||||
end
|
||||
self._new_attrs = false
|
||||
self:wait(function()
|
||||
self:_wait(function()
|
||||
if condition ~= nil then
|
||||
local status, res = pcall(condition)
|
||||
if not status then
|
||||
@ -361,7 +385,7 @@ screen:redraw_debug() to show all intermediate screen states. ]])
|
||||
-- Extension features. The default expectations should cover the case of
|
||||
-- the ext_ feature being disabled, or the feature currently not activated
|
||||
-- (for instance no external cmdline visible). Some extensions require
|
||||
-- preprocessing to prepresent highlights in a reproducible way.
|
||||
-- preprocessing to represent highlights in a reproducible way.
|
||||
local extstate = self:_extstate_repr(attr_state)
|
||||
|
||||
-- convert assertion errors into invalid screen state descriptions
|
||||
@ -379,14 +403,48 @@ screen:redraw_debug() to show all intermediate screen states. ]])
|
||||
if not status then
|
||||
return tostring(res)
|
||||
end
|
||||
end)
|
||||
end, expected)
|
||||
end
|
||||
|
||||
function Screen:wait(check, timeout)
|
||||
local err, checked = false
|
||||
function Screen:_wait(check, flags)
|
||||
local err, checked = false, false
|
||||
local success_seen = false
|
||||
local failure_after_success = false
|
||||
local did_flush = true
|
||||
local warn_immediate = not (flags.unchanged or flags.intermediate)
|
||||
|
||||
if flags.intermediate and flags.unchanged then
|
||||
error("Choose only one of 'intermediate' and 'unchanged', not both")
|
||||
end
|
||||
|
||||
if flags.reset then
|
||||
-- throw away all state, we expect it to be retransmitted
|
||||
self:_reset()
|
||||
end
|
||||
|
||||
-- Maximum timeout, after which a incorrect state will be regarded as a
|
||||
-- failure
|
||||
local timeout = flags.timeout or self.timeout
|
||||
|
||||
-- Minimal timeout before the loop is allowed to be stopped so we
|
||||
-- always do some check for failure after success.
|
||||
local minimal_timeout = default_timeout_factor * 2
|
||||
|
||||
local immediate_seen, intermediate_seen = false, false
|
||||
if not check() then
|
||||
minimal_timeout = default_timeout_factor * 20
|
||||
immediate_seen = true
|
||||
end
|
||||
|
||||
-- for an unchanged test, flags.timeout means the time during the state is
|
||||
-- expected to be unchanged, so always wait this full time.
|
||||
if (flags.unchanged or flags.intermediate) and flags.timeout ~= nil then
|
||||
minimal_timeout = timeout
|
||||
end
|
||||
|
||||
assert(timeout >= minimal_timeout)
|
||||
local did_miminal_timeout = false
|
||||
|
||||
local function notification_cb(method, args)
|
||||
assert(method == 'redraw')
|
||||
did_flush = self:_redraw(args)
|
||||
@ -395,9 +453,15 @@ function Screen:wait(check, timeout)
|
||||
end
|
||||
err = check()
|
||||
checked = true
|
||||
if err and immediate_seen then
|
||||
intermediate_seen = true
|
||||
end
|
||||
|
||||
if not err then
|
||||
success_seen = true
|
||||
if did_miminal_timeout then
|
||||
helpers.stop()
|
||||
end
|
||||
elseif success_seen and #args > 0 then
|
||||
failure_after_success = true
|
||||
--print(require('inspect')(args))
|
||||
@ -405,35 +469,83 @@ function Screen:wait(check, timeout)
|
||||
|
||||
return true
|
||||
end
|
||||
run(nil, notification_cb, nil, timeout or self.timeout)
|
||||
run(nil, notification_cb, nil, minimal_timeout)
|
||||
if not did_flush then
|
||||
err = "no flush received"
|
||||
elseif not checked then
|
||||
err = check()
|
||||
if not err and flags.unchanged then
|
||||
-- expecting NO screen change: use a shorter timout
|
||||
success_seen = true
|
||||
end
|
||||
end
|
||||
|
||||
if not success_seen then
|
||||
did_miminal_timeout = true
|
||||
run(nil, notification_cb, nil, timeout-minimal_timeout)
|
||||
end
|
||||
|
||||
local did_warn = false
|
||||
if warn_immediate and immediate_seen then
|
||||
print([[
|
||||
|
||||
Warning: A screen test has immediate success. Try to avoid this unless the
|
||||
purpose of the test really requires it.]])
|
||||
if intermediate_seen then
|
||||
print([[
|
||||
There are intermediate states between the two identical expects.
|
||||
Use screen:snapshot_util() or screen:redraw_debug() to find them, and add them
|
||||
to the test if they make sense.
|
||||
]])
|
||||
else
|
||||
print([[If necessary, silence this warning by
|
||||
supplying the 'unchanged' argument to screen:expect.]])
|
||||
end
|
||||
did_warn = true
|
||||
end
|
||||
|
||||
if failure_after_success then
|
||||
print([[
|
||||
|
||||
Warning: Screen changes were received after the expected state. This indicates
|
||||
indeterminism in the test. Try adding wait() (or screen:expect(...)) between
|
||||
indeterminism in the test. Try adding screen:expect(...) (or wait()) between
|
||||
asynchronous (feed(), nvim_input()) and synchronous API calls.
|
||||
- Use Screen:redraw_debug() to investigate the problem.
|
||||
- Use Screen:redraw_debug() to investigate the problem. It might find
|
||||
relevant intermediate states that should be added to the test to make it
|
||||
more robust.
|
||||
- If the point of the test is to assert the state after some user input
|
||||
sent with feed(...), also adding an screen:expect(...) before the feed(...)
|
||||
will help ensure the input is sent to nvim when nvim is in a predictable
|
||||
state. This is preferable to using wait(), as it is more closely emulates
|
||||
real user interaction.
|
||||
- wait() can trigger redraws and consequently generate more indeterminism.
|
||||
In that case try removing every wait().
|
||||
]])
|
||||
did_warn = true
|
||||
end
|
||||
|
||||
|
||||
if err then
|
||||
assert(false, err)
|
||||
elseif did_warn then
|
||||
local tb = debug.traceback()
|
||||
local index = string.find(tb, '\n%s*%[C]')
|
||||
print(string.sub(tb,1,index))
|
||||
end
|
||||
|
||||
if err then
|
||||
assert(false, err)
|
||||
if flags.intermediate then
|
||||
assert(intermediate_seen, "expected intermediate screen state before final screen state")
|
||||
elseif flags.unchanged then
|
||||
assert(not intermediate_seen, "expected screen state to be unchanged")
|
||||
end
|
||||
end
|
||||
|
||||
function Screen:sleep(ms)
|
||||
pcall(function() self:wait(function() return "error" end, ms) end)
|
||||
local function notification_cb(method, args)
|
||||
assert(method == 'redraw')
|
||||
self:_redraw(args)
|
||||
end
|
||||
run(nil, notification_cb, nil, ms)
|
||||
end
|
||||
|
||||
function Screen:_redraw(updates)
|
||||
@ -486,12 +598,23 @@ end
|
||||
function Screen:_handle_flush()
|
||||
end
|
||||
|
||||
|
||||
function Screen:_handle_grid_resize(grid, width, height)
|
||||
assert(grid == 1)
|
||||
self:_handle_resize(width, height)
|
||||
end
|
||||
|
||||
function Screen:_reset()
|
||||
-- TODO: generalize to multigrid later
|
||||
self:_handle_grid_clear(1)
|
||||
|
||||
-- TODO: share with initialization, so it generalizes?
|
||||
self.popupmenu = nil
|
||||
self.cmdline = {}
|
||||
self.cmdline_block = {}
|
||||
self.wildmenu_items = nil
|
||||
self.wildmenu_pos = nil
|
||||
end
|
||||
|
||||
|
||||
function Screen:_handle_mode_info_set(cursor_style_enabled, mode_info)
|
||||
self._cursor_style_enabled = cursor_style_enabled
|
||||
|
@ -394,7 +394,7 @@ local function screen_tests(linegrid)
|
||||
end)
|
||||
|
||||
it('redraws properly with :tab split right after scroll', function()
|
||||
feed('30Ofoo<esc>gg')
|
||||
feed('15Ofoo<esc>15Obar<esc>gg')
|
||||
|
||||
command('vsplit')
|
||||
screen:expect([[
|
||||
@ -420,18 +420,17 @@ local function screen_tests(linegrid)
|
||||
foo {3:│}foo |
|
||||
foo {3:│}foo |
|
||||
foo {3:│}foo |
|
||||
foo {3:│}foo |
|
||||
foo {3:│}foo |
|
||||
foo {3:│}foo |
|
||||
foo {3:│}foo |
|
||||
foo {3:│}foo |
|
||||
foo {3:│}foo |
|
||||
foo {3:│}foo |
|
||||
foo {3:│}foo |
|
||||
bar {3:│}foo |
|
||||
bar {3:│}foo |
|
||||
bar {3:│}foo |
|
||||
bar {3:│}foo |
|
||||
bar {3:│}foo |
|
||||
bar {3:│}foo |
|
||||
bar {3:│}foo |
|
||||
bar {3:│}foo |
|
||||
{1:[No Name] [+] }{3:[No Name] [+] }|
|
||||
|
|
||||
]])
|
||||
|
||||
command('tab split')
|
||||
screen:expect([[
|
||||
{4: }{5:2}{4:+ [No Name] }{2: + [No Name] }{3: }{4:X}|
|
||||
@ -439,14 +438,14 @@ local function screen_tests(linegrid)
|
||||
foo |
|
||||
foo |
|
||||
foo |
|
||||
foo |
|
||||
foo |
|
||||
foo |
|
||||
foo |
|
||||
foo |
|
||||
foo |
|
||||
foo |
|
||||
foo |
|
||||
bar |
|
||||
bar |
|
||||
bar |
|
||||
bar |
|
||||
bar |
|
||||
bar |
|
||||
bar |
|
||||
bar |
|
||||
|
|
||||
]])
|
||||
end)
|
||||
|
@ -324,7 +324,17 @@ describe('search highlighting', function()
|
||||
]])
|
||||
|
||||
-- same, for C-t
|
||||
feed('<ESC>/<C-t>')
|
||||
feed('<ESC>')
|
||||
screen:expect([[
|
||||
the first line |
|
||||
in a ^little file |
|
||||
|
|
||||
{1:~ }|
|
||||
{1:~ }|
|
||||
{1:~ }|
|
||||
|
|
||||
]])
|
||||
feed('/<C-t>')
|
||||
screen:expect([[
|
||||
the first line |
|
||||
in a little file |
|
||||
|
@ -1,3 +1,5 @@
|
||||
local global_helpers = require('test.helpers')
|
||||
local shallowcopy = global_helpers.shallowcopy
|
||||
local helpers = require('test.functional.helpers')(after_each)
|
||||
local Screen = require('test.functional.ui.screen')
|
||||
local clear, feed, command = helpers.clear, helpers.feed, helpers.command
|
||||
@ -18,6 +20,14 @@ describe("'wildmenu'", function()
|
||||
screen:detach()
|
||||
end)
|
||||
|
||||
-- expect the screen stayed unchanged some time after first seen success
|
||||
local function expect_stay_unchanged(args)
|
||||
screen:expect(args)
|
||||
args = shallowcopy(args)
|
||||
args.unchanged = true
|
||||
screen:expect(args)
|
||||
end
|
||||
|
||||
it(':sign <tab> shows wildmenu completions', function()
|
||||
command('set wildmode=full')
|
||||
command('set wildmenu')
|
||||
@ -76,10 +86,6 @@ describe("'wildmenu'", function()
|
||||
end)
|
||||
|
||||
it('is preserved during :terminal activity', function()
|
||||
-- Because this test verifies a _lack_ of activity after screen:sleep(), we
|
||||
-- must wait the full timeout. So make it reasonable.
|
||||
screen.timeout = 1000
|
||||
|
||||
command('set wildmenu wildmode=full')
|
||||
command('set scrollback=4')
|
||||
if iswin() then
|
||||
@ -90,26 +96,24 @@ describe("'wildmenu'", function()
|
||||
|
||||
feed([[<C-\><C-N>gg]])
|
||||
feed([[:sign <Tab>]]) -- Invoke wildmenu.
|
||||
screen:sleep(50) -- Allow some terminal output.
|
||||
screen:expect([[
|
||||
expect_stay_unchanged{grid=[[
|
||||
foo |
|
||||
foo |
|
||||
foo |
|
||||
define jump list > |
|
||||
:sign define^ |
|
||||
]])
|
||||
]]}
|
||||
|
||||
-- cmdline CTRL-D display should also be preserved.
|
||||
feed([[<C-\><C-N>]])
|
||||
feed([[:sign <C-D>]]) -- Invoke cmdline CTRL-D.
|
||||
screen:sleep(50) -- Allow some terminal output.
|
||||
screen:expect([[
|
||||
expect_stay_unchanged{grid=[[
|
||||
:sign |
|
||||
define place |
|
||||
jump undefine |
|
||||
list unplace |
|
||||
:sign ^ |
|
||||
]])
|
||||
]]}
|
||||
|
||||
-- Exiting cmdline should show the buffer.
|
||||
feed([[<C-\><C-N>]])
|
||||
@ -123,22 +127,17 @@ describe("'wildmenu'", function()
|
||||
end)
|
||||
|
||||
it('ignores :redrawstatus called from a timer #7108', function()
|
||||
-- Because this test verifies a _lack_ of activity after screen:sleep(), we
|
||||
-- must wait the full timeout. So make it reasonable.
|
||||
screen.timeout = 1000
|
||||
|
||||
command('set wildmenu wildmode=full')
|
||||
command([[call timer_start(10, {->execute('redrawstatus')}, {'repeat':-1})]])
|
||||
feed([[<C-\><C-N>]])
|
||||
feed([[:sign <Tab>]]) -- Invoke wildmenu.
|
||||
screen:sleep(30) -- Allow some timer activity.
|
||||
screen:expect([[
|
||||
expect_stay_unchanged{grid=[[
|
||||
|
|
||||
~ |
|
||||
~ |
|
||||
define jump list > |
|
||||
:sign define^ |
|
||||
]])
|
||||
]]}
|
||||
end)
|
||||
|
||||
it('with laststatus=0, :vsplit, :term #2255', function()
|
||||
@ -164,10 +163,9 @@ describe("'wildmenu'", function()
|
||||
|
||||
feed([[<C-\><C-N>]])
|
||||
feed([[:<Tab>]]) -- Invoke wildmenu.
|
||||
screen:sleep(10) -- Flush
|
||||
-- Check only the last 2 lines, because the shell output is
|
||||
-- system-dependent.
|
||||
screen:expect{any='! # & < = > @ > \n:!^'}
|
||||
expect_stay_unchanged{any='! # & < = > @ > \n:!^'}
|
||||
end)
|
||||
end)
|
||||
|
||||
|
@ -757,7 +757,7 @@ describe('completion', function()
|
||||
|
||||
eval('1 + 1')
|
||||
-- popupmenu still visible
|
||||
screen:expect([[
|
||||
screen:expect{grid=[[
|
||||
foobar fooegg |
|
||||
fooegg^ |
|
||||
{1:foobar }{0: }|
|
||||
@ -766,7 +766,7 @@ describe('completion', function()
|
||||
{0:~ }|
|
||||
{0:~ }|
|
||||
{3:-- Keyword completion (^N^P) }{4:match 1 of 2} |
|
||||
]])
|
||||
]], unchanged=true}
|
||||
|
||||
feed('<c-p>')
|
||||
-- Didn't restart completion: old matches still used
|
||||
|
Loading…
Reference in New Issue
Block a user