screen.lua: expect_unchanged(), get_snapshot()

Factor `get_snapshot()` out of `print_snapshot()`, so that callers can
get a table (for use with `expect()`) instead of the string form.

Try to use this to fix indeterminism in `searchhl_spec.lua`.
  - Since the screen state is collected by `screen:expect_unchanged()`,
    we don't need a deterministic initial state (which would then be
    hardcoded into the test). This allows us to check "did anything
    change in the last N ms?" rather than "did anything change compared
    to a hardcoded screen-state?"
  - This may end up fruitless, because `expect_unchanged()` depends on
    timing to wait for an initial "current state".
This commit is contained in:
Justin M. Keyes 2019-07-20 14:01:33 +02:00
parent 643ba06d4d
commit 6b45e12d67
2 changed files with 41 additions and 28 deletions

View File

@ -447,6 +447,18 @@ screen:redraw_debug() to show all intermediate screen states. ]])
end, expected) end, expected)
end end
function Screen:expect_unchanged(waittime_ms, ignore_attrs, request_cb)
waittime_ms = waittime_ms and waittime_ms or 100
-- Collect the current screen state.
self:sleep(waittime_ms, request_cb)
local kwargs = self:get_snapshot(nil, ignore_attrs)
-- Wait for potential changes.
self:sleep(waittime_ms, request_cb)
kwargs.unchanged = true
-- Check that screen state did not change.
self:expect(kwargs)
end
function Screen:_wait(check, flags) function Screen:_wait(check, flags)
local err, checked = false, false local err, checked = false, false
local success_seen = false local success_seen = false
@ -477,8 +489,8 @@ function Screen:_wait(check, flags)
immediate_seen = true immediate_seen = true
end end
-- for an unchanged test, flags.timeout means the time during the state is -- For an "unchanged" test, flags.timeout is the time during which the state
-- expected to be unchanged, so always wait this full time. -- must not change, so always wait this full time.
if (flags.unchanged or flags.intermediate) and flags.timeout ~= nil then if (flags.unchanged or flags.intermediate) and flags.timeout ~= nil then
minimal_timeout = timeout minimal_timeout = timeout
end end
@ -1214,7 +1226,9 @@ local remove_all_metatables = function(item, path)
if path[#path] ~= inspect.METATABLE then return item end if path[#path] ~= inspect.METATABLE then return item end
end end
function Screen:print_snapshot(attrs, ignore) -- Returns the current screen state in the form of a screen:expect()
-- keyword-args map.
function Screen:get_snapshot(attrs, ignore)
attrs = attrs or self._default_attr_ids attrs = attrs or self._default_attr_ids
if ignore == nil then if ignore == nil then
ignore = self._default_attr_ignore ignore = self._default_attr_ignore
@ -1246,6 +1260,26 @@ function Screen:print_snapshot(attrs, ignore)
end end
end end
-- Build keyword-args for screen:expect().
local kwargs = {}
if attr_state.modified then
kwargs['attr_ids'] = {}
for i, a in pairs(attr_state.ids) do
kwargs['attr_ids'][i] = a
end
end
kwargs['grid'] = table.concat(lines, '\n')
for _, k in ipairs(ext_keys) do
if ext_state[k] ~= nil then
kwargs[k] = ext_state[k]
end
end
return kwargs, ext_state, attr_state, keys
end
function Screen:print_snapshot(attrs, ignore)
local kwargs, ext_state, attr_state, keys = self:get_snapshot(attrs, ignore)
local attrstr = "" local attrstr = ""
if attr_state.modified then if attr_state.modified then
local attrstrs = {} local attrstrs = {}
@ -1263,7 +1297,7 @@ function Screen:print_snapshot(attrs, ignore)
.."{\n"..table.concat(attrstrs, "\n").."\n}") .."{\n"..table.concat(attrstrs, "\n").."\n}")
end end
print( "\nscreen:expect"..(keys and "{grid=" or "(").."[[") print( "\nscreen:expect"..(keys and "{grid=" or "(").."[[")
print( table.concat(lines, '\n')) print(kwargs.grid)
io.stdout:write( "]]"..attrstr) io.stdout:write( "]]"..attrstr)
for _, k in ipairs(ext_keys) do for _, k in ipairs(ext_keys) do
if ext_state[k] ~= nil then if ext_state[k] ~= nil then

View File

@ -5,8 +5,7 @@ local command = helpers.command
local feed_command = helpers.feed_command local feed_command = helpers.feed_command
local eq = helpers.eq local eq = helpers.eq
local eval = helpers.eval local eval = helpers.eval
local iswin = helpers.iswin local nvim_dir = helpers.nvim_dir
local sleep = helpers.sleep
describe('search highlighting', function() describe('search highlighting', function()
local screen local screen
@ -148,11 +147,7 @@ describe('search highlighting', function()
end) end)
it('is preserved during :terminal activity', function() it('is preserved during :terminal activity', function()
if iswin() then feed([[:terminal "]]..nvim_dir..[[/shell-test" REP 5000 foo<cr>]])
feed([[:terminal for /L \%I in (1,1,5000) do @(echo xxx & echo xxx & echo xxx)<cr>]])
else
feed([[:terminal for i in $(seq 1 5000); do printf 'xxx\nxxx\nxxx\n'; done<cr>]])
end
feed(':file term<CR>') feed(':file term<CR>')
feed(':vnew<CR>') feed(':vnew<CR>')
@ -162,23 +157,7 @@ describe('search highlighting', function()
bar foo baz bar foo baz
]]) ]])
feed('/foo') feed('/foo')
sleep(50) -- Allow some terminal activity. screen:expect_unchanged()
-- NB: in earlier versions terminal output was redrawn during cmdline mode.
-- For now just assert that the screens remain unchanged.
screen:expect([[
{3:foo} bar baz {3:} |
bar baz {2:foo} {3:} |
bar {2:foo} baz {3:} |
{3:} |
{1:~ }{3:} |
{5:[No Name] [+] }{3:term }|
/foo^ |
]], { [1] = {bold = true, foreground = Screen.colors.Blue1},
[2] = {background = Screen.colors.Yellow},
[3] = {reverse = true},
[4] = {foreground = Screen.colors.Red},
[5] = {bold = true, reverse = true},
})
end) end)
it('works with incsearch', function() it('works with incsearch', function()