diff options
author | Björn Linse <bjorn.linse@gmail.com> | 2017-06-26 14:49:15 +0200 |
---|---|---|
committer | Björn Linse <bjorn.linse@gmail.com> | 2018-10-15 20:13:11 +0200 |
commit | c8810a51a3a7ef1185b45c07d93f7e6769c5ab55 (patch) | |
tree | 55e62aa6c09a729c9c34bd5d4d4d40321f982376 | |
parent | 8fd092f3ff15bf70f84ec0d716c5aaa2c7379fa1 (diff) | |
download | rneovim-c8810a51a3a7ef1185b45c07d93f7e6769c5ab55.tar.gz rneovim-c8810a51a3a7ef1185b45c07d93f7e6769c5ab55.tar.bz2 rneovim-c8810a51a3a7ef1185b45c07d93f7e6769c5ab55.zip |
tests: improve robustness of immediate successes in screen tests
-rw-r--r-- | test/functional/api/menu_spec.lua | 8 | ||||
-rw-r--r-- | test/functional/eval/execute_spec.lua | 4 | ||||
-rw-r--r-- | test/functional/eval/input_spec.lua | 16 | ||||
-rw-r--r-- | test/functional/eval/timer_spec.lua | 15 | ||||
-rw-r--r-- | test/functional/legacy/search_spec.lua | 21 | ||||
-rw-r--r-- | test/functional/normal/put_spec.lua | 13 | ||||
-rw-r--r-- | test/functional/options/fillchars_spec.lua | 7 | ||||
-rw-r--r-- | test/functional/terminal/scrollback_spec.lua | 3 | ||||
-rw-r--r-- | test/functional/terminal/tui_spec.lua | 4 | ||||
-rw-r--r-- | test/functional/ui/cmdline_highlight_spec.lua | 15 | ||||
-rw-r--r-- | test/functional/ui/cmdline_spec.lua | 11 | ||||
-rw-r--r-- | test/functional/ui/highlight_spec.lua | 4 | ||||
-rw-r--r-- | test/functional/ui/inccommand_spec.lua | 46 | ||||
-rw-r--r-- | test/functional/ui/mouse_spec.lua | 27 | ||||
-rw-r--r-- | test/functional/ui/output_spec.lua | 19 | ||||
-rw-r--r-- | test/functional/ui/screen.lua | 161 | ||||
-rw-r--r-- | test/functional/ui/screen_basic_spec.lua | 35 | ||||
-rw-r--r-- | test/functional/ui/searchhl_spec.lua | 12 | ||||
-rw-r--r-- | test/functional/ui/wildmode_spec.lua | 36 | ||||
-rw-r--r-- | test/functional/viml/completion_spec.lua | 4 |
20 files changed, 314 insertions, 147 deletions
diff --git a/test/functional/api/menu_spec.lua b/test/functional/api/menu_spec.lua index d55b7b118a..2cfa0e3e47 100644 --- a/test/functional/api/menu_spec.lua +++ b/test/functional/api/menu_spec.lua @@ -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() diff --git a/test/functional/eval/execute_spec.lua b/test/functional/eval/execute_spec.lua index 925e311c7d..af37ab8d55 100644 --- a/test/functional/eval/execute_spec.lua +++ b/test/functional/eval/execute_spec.lua @@ -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) diff --git a/test/functional/eval/input_spec.lua b/test/functional/eval/input_spec.lua index 777f49462d..82e75d7a8e 100644 --- a/test/functional/eval/input_spec.lua +++ b/test/functional/eval/input_spec.lua @@ -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') diff --git a/test/functional/eval/timer_spec.lua b/test/functional/eval/timer_spec.lua index 040ab30522..c945f12e0e 100644 --- a/test/functional/eval/timer_spec.lua +++ b/test/functional/eval/timer_spec.lua @@ -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) diff --git a/test/functional/legacy/search_spec.lua b/test/functional/legacy/search_spec.lua index 277d8d6c7f..3ed06a22e7 100644 --- a/test/functional/legacy/search_spec.lua +++ b/test/functional/legacy/search_spec.lua @@ -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 diff --git a/test/functional/normal/put_spec.lua b/test/functional/normal/put_spec.lua index 148a35ec6b..29cef13e39 100644 --- a/test/functional/normal/put_spec.lua +++ b/test/functional/normal/put_spec.lua @@ -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 diff --git a/test/functional/options/fillchars_spec.lua b/test/functional/options/fillchars_spec.lua index ab61935d4c..99177a11b4 100644 --- a/test/functional/options/fillchars_spec.lua +++ b/test/functional/options/fillchars_spec.lua @@ -36,6 +36,13 @@ describe("'fillchars'", function() ]]) end) it('supports whitespace', function() + screen:expect([[ + ^ | + ~ | + ~ | + ~ | + | + ]]) command('set fillchars=eob:\\ ') screen:expect([[ ^ | diff --git a/test/functional/terminal/scrollback_spec.lua b/test/functional/terminal/scrollback_spec.lua index 5e36fea474..2e236327c8 100644 --- a/test/functional/terminal/scrollback_spec.lua +++ b/test/functional/terminal/scrollback_spec.lua @@ -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 diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua index 834720edc6..365bd2a0be 100644 --- a/test/functional/terminal/tui_spec.lua +++ b/test/functional/terminal/tui_spec.lua @@ -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() diff --git a/test/functional/ui/cmdline_highlight_spec.lua b/test/functional/ui/cmdline_highlight_spec.lua index 5d9fffdf23..768b24dd81 100644 --- a/test/functional/ui/cmdline_highlight_spec.lua +++ b/test/functional/ui/cmdline_highlight_spec.lua @@ -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) diff --git a/test/functional/ui/cmdline_spec.lua b/test/functional/ui/cmdline_spec.lua index af26a6d88f..e86414fe5f 100644 --- a/test/functional/ui/cmdline_spec.lua +++ b/test/functional/ui/cmdline_spec.lua @@ -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=[[ diff --git a/test/functional/ui/highlight_spec.lua b/test/functional/ui/highlight_spec.lua index 7f3bf3e97b..521b1e0b8a 100644 --- a/test/functional/ui/highlight_spec.lua +++ b/test/functional/ui/highlight_spec.lua @@ -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) diff --git a/test/functional/ui/inccommand_spec.lua b/test/functional/ui/inccommand_spec.lua index 6a17448582..0983f6f399 100644 --- a/test/functional/ui/inccommand_spec.lua +++ b/test/functional/ui/inccommand_spec.lua @@ -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() diff --git a/test/functional/ui/mouse_spec.lua b/test/functional/ui/mouse_spec.lua index debd324977..ff395adeb9 100644 --- a/test/functional/ui/mouse_spec.lua +++ b/test/functional/ui/mouse_spec.lua @@ -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}| diff --git a/test/functional/ui/output_spec.lua b/test/functional/ui/output_spec.lua index 0f076eac26..1850d436ac 100644 --- a/test/functional/ui/output_spec.lua +++ b/test/functional/ui/output_spec.lua @@ -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 --} | diff --git a/test/functional/ui/screen.lua b/test/functional/ui/screen.lua index 691bf9f64c..af036913d8 100644 --- a/test/functional/ui/screen.lua +++ b/test/functional/ui/screen.lua @@ -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 - helpers.stop() + 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 diff --git a/test/functional/ui/screen_basic_spec.lua b/test/functional/ui/screen_basic_spec.lua index 31825bdbf4..3e930b0ae7 100644 --- a/test/functional/ui/screen_basic_spec.lua +++ b/test/functional/ui/screen_basic_spec.lua @@ -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) diff --git a/test/functional/ui/searchhl_spec.lua b/test/functional/ui/searchhl_spec.lua index b535092ab9..a46670d8a2 100644 --- a/test/functional/ui/searchhl_spec.lua +++ b/test/functional/ui/searchhl_spec.lua @@ -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 | diff --git a/test/functional/ui/wildmode_spec.lua b/test/functional/ui/wildmode_spec.lua index 72dbef9538..8931d9245b 100644 --- a/test/functional/ui/wildmode_spec.lua +++ b/test/functional/ui/wildmode_spec.lua @@ -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) diff --git a/test/functional/viml/completion_spec.lua b/test/functional/viml/completion_spec.lua index 3222e5783d..70b4717c32 100644 --- a/test/functional/viml/completion_spec.lua +++ b/test/functional/viml/completion_spec.lua @@ -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 |