diff options
Diffstat (limited to 'test')
| -rw-r--r-- | test/functional/cmdline/ctrl_r_spec.lua | 34 | ||||
| -rw-r--r-- | test/functional/cmdline/history_spec.lua (renamed from test/functional/ex_getln/history_spec.lua) | 0 | ||||
| -rw-r--r-- | test/functional/core/job_spec.lua | 21 | ||||
| -rw-r--r-- | test/functional/eval/has_spec.lua | 8 | ||||
| -rw-r--r-- | test/functional/eval/let_spec.lua | 22 | ||||
| -rw-r--r-- | test/functional/ex_cmds/dict_notifications_spec.lua | 26 | ||||
| -rw-r--r-- | test/functional/helpers.lua | 6 | ||||
| -rw-r--r-- | test/functional/legacy/arglist_spec.lua | 4 | ||||
| -rw-r--r-- | test/functional/terminal/edit_spec.lua | 36 | ||||
| -rw-r--r-- | test/functional/terminal/ex_terminal_spec.lua | 22 | ||||
| -rw-r--r-- | test/functional/terminal/helpers.lua | 51 | ||||
| -rw-r--r-- | test/functional/terminal/mouse_spec.lua | 2 | ||||
| -rw-r--r-- | test/functional/terminal/scrollback_spec.lua | 385 | ||||
| -rw-r--r-- | test/functional/terminal/window_split_tab_spec.lua | 14 | ||||
| -rw-r--r-- | test/helpers.lua | 106 | ||||
| -rw-r--r-- | test/unit/preprocess.lua | 25 |
16 files changed, 550 insertions, 212 deletions
diff --git a/test/functional/cmdline/ctrl_r_spec.lua b/test/functional/cmdline/ctrl_r_spec.lua new file mode 100644 index 0000000000..d2dad23e98 --- /dev/null +++ b/test/functional/cmdline/ctrl_r_spec.lua @@ -0,0 +1,34 @@ +local helpers = require('test.functional.helpers')(after_each) +local clear, insert, funcs, eq, feed = + helpers.clear, helpers.insert, helpers.funcs, helpers.eq, helpers.feed + +describe('cmdline CTRL-R', function() + before_each(clear) + + it('pasting non-special register inserts <CR> *between* lines', function() + insert([[ + line1abc + line2somemoretext + ]]) + -- Yank 2 lines linewise, then paste to cmdline. + feed([[<C-\><C-N>gg0yj:<C-R>0]]) + -- <CR> inserted between lines, NOT after the final line. + eq('line1abc\rline2somemoretext', funcs.getcmdline()) + + -- Yank 2 lines characterwise, then paste to cmdline. + feed([[<C-\><C-N>gg05lyvj:<C-R>0]]) + -- <CR> inserted between lines, NOT after the final line. + eq('abc\rline2', funcs.getcmdline()) + + -- Yank 1 line linewise, then paste to cmdline. + feed([[<C-\><C-N>ggyy:<C-R>0]]) + -- No <CR> inserted. + eq('line1abc', funcs.getcmdline()) + end) + + it('pasting special register inserts <CR>, <NL>', function() + feed([[:<C-R>="foo\nbar\rbaz"<CR>]]) + eq('foo\nbar\rbaz', funcs.getcmdline()) + end) +end) + diff --git a/test/functional/ex_getln/history_spec.lua b/test/functional/cmdline/history_spec.lua index 20f9cf06a2..20f9cf06a2 100644 --- a/test/functional/ex_getln/history_spec.lua +++ b/test/functional/cmdline/history_spec.lua diff --git a/test/functional/core/job_spec.lua b/test/functional/core/job_spec.lua index 6e9633465f..b551adb8db 100644 --- a/test/functional/core/job_spec.lua +++ b/test/functional/core/job_spec.lua @@ -391,6 +391,27 @@ describe('jobs', function() eq({'notification', '1', {'foo', 'bar', {'some text', ''}, 'stdout'}}, next_msg()) end) + it('jobstart() works with closures', function() + source([[ + fun! MkFun() + let a1 = 'foo' + let a2 = 'bar' + return {id, data, event -> rpcnotify(g:channel, '1', a1, a2, Normalize(data), event)} + endfun + let g:job_opts = {'on_stdout': MkFun()} + call jobstart('echo "some text"', g:job_opts) + ]]) + eq({'notification', '1', {'foo', 'bar', {'some text', ''}, 'stdout'}}, next_msg()) + end) + + it('jobstart() works when closure passed directly to `jobstart`', function() + source([[ + let g:job_opts = {'on_stdout': {id, data, event -> rpcnotify(g:channel, '1', 'foo', 'bar', Normalize(data), event)}} + call jobstart('echo "some text"', g:job_opts) + ]]) + eq({'notification', '1', {'foo', 'bar', {'some text', ''}, 'stdout'}}, next_msg()) + end) + describe('jobwait', function() it('returns a list of status codes', function() source([[ diff --git a/test/functional/eval/has_spec.lua b/test/functional/eval/has_spec.lua index 97b3b0e620..78c4e08fde 100644 --- a/test/functional/eval/has_spec.lua +++ b/test/functional/eval/has_spec.lua @@ -2,6 +2,7 @@ local helpers = require('test.functional.helpers')(after_each) local eq = helpers.eq local clear = helpers.clear local funcs = helpers.funcs +local iswin = helpers.iswin describe('has()', function() before_each(clear) @@ -49,4 +50,11 @@ describe('has()', function() eq(1, funcs.has("nvim-00.001.05")) end) + it('"unnamedplus"', function() + if (not iswin()) and funcs.has("clipboard") == 1 then + eq(1, funcs.has("unnamedplus")) + else + eq(0, funcs.has("unnamedplus")) + end + end) end) diff --git a/test/functional/eval/let_spec.lua b/test/functional/eval/let_spec.lua new file mode 100644 index 0000000000..c3ab3cc367 --- /dev/null +++ b/test/functional/eval/let_spec.lua @@ -0,0 +1,22 @@ +local helpers = require('test.functional.helpers')(after_each) + +local eq = helpers.eq +local clear = helpers.clear +local meths = helpers.meths +local redir_exec = helpers.redir_exec + +before_each(clear) + +describe(':let command', function() + it('correctly lists variables with curly-braces', function() + meths.set_var('v', {0}) + eq('\nv [0]', redir_exec('let {"v"}')) + end) + + it('correctly lists variables with subscript', function() + meths.set_var('v', {0}) + eq('\nv[0] #0', redir_exec('let v[0]')) + eq('\ng:["v"][0] #0', redir_exec('let g:["v"][0]')) + eq('\n{"g:"}["v"][0] #0', redir_exec('let {"g:"}["v"][0]')) + end) +end) diff --git a/test/functional/ex_cmds/dict_notifications_spec.lua b/test/functional/ex_cmds/dict_notifications_spec.lua index 5e89986c0f..30753c34ac 100644 --- a/test/functional/ex_cmds/dict_notifications_spec.lua +++ b/test/functional/ex_cmds/dict_notifications_spec.lua @@ -254,23 +254,33 @@ describe('dictionary change notifications', function() command('call g:ReplaceWatcher2()') command('let g:key = "value"') eq({'notification', '2b', {'key', {old = 'v2', new = 'value'}}}, next_msg()) - end) it('does not crash when freeing a watched dictionary', function() source([[ - function! Watcher(dict, key, value) - echo a:key string(a:value) - endfunction + function! Watcher(dict, key, value) + echo a:key string(a:value) + endfunction - function! MakeWatch() - let d = {'foo': 'bar'} - call dictwatcheradd(d, 'foo', function('Watcher')) - endfunction + function! MakeWatch() + let d = {'foo': 'bar'} + call dictwatcheradd(d, 'foo', function('Watcher')) + endfunction ]]) command('call MakeWatch()') eq(2, eval('1+1')) -- Still alive? end) end) + + describe('with lambdas', function() + it('works correctly', function() + source([[ + let d = {'foo': 'baz'} + call dictwatcheradd(d, 'foo', {dict, key, value -> rpcnotify(g:channel, '2', key, value)}) + let d.foo = 'bar' + ]]) + eq({'notification', '2', {'foo', {old = 'baz', new = 'bar'}}}, next_msg()) + end) + end) end) diff --git a/test/functional/helpers.lua b/test/functional/helpers.lua index eb6cc95f34..a894fa9328 100644 --- a/test/functional/helpers.lua +++ b/test/functional/helpers.lua @@ -9,6 +9,7 @@ local TcpStream = require('nvim.tcp_stream') local SocketStream = require('nvim.socket_stream') local ChildProcessStream = require('nvim.child_process_stream') +local check_cores = global_helpers.check_cores local check_logs = global_helpers.check_logs local neq = global_helpers.neq local eq = global_helpers.eq @@ -619,7 +620,10 @@ local M = { return function(after_each) if after_each then - after_each(check_logs) + after_each(function() + check_logs() + check_cores('build/bin/nvim') + end) end return M end diff --git a/test/functional/legacy/arglist_spec.lua b/test/functional/legacy/arglist_spec.lua index b86d3f0aea..f5e3522972 100644 --- a/test/functional/legacy/arglist_spec.lua +++ b/test/functional/legacy/arglist_spec.lua @@ -222,7 +222,6 @@ describe('argument list commands', function() execute('argedit a') eq({'a', 'b'}, eval('argv()')) eq('a', eval('expand("%:t")')) - assert_fails('argedit a b', 'E172:') execute('argedit c') eq({'a', 'c', 'b'}, eval('argv()')) execute('0argedit x') @@ -232,6 +231,9 @@ describe('argument list commands', function() execute('argedit! y') eq({'x', 'y', 'a', 'c', 'b'}, eval('argv()')) execute('%argd') + -- Nvim allows unescaped spaces in filename on all platforms. #6010 + execute('argedit a b') + eq({'a b'}, eval('argv()')) end) it('test for :argdelete command', function() diff --git a/test/functional/terminal/edit_spec.lua b/test/functional/terminal/edit_spec.lua index 8edcfa56b7..42a5c768bb 100644 --- a/test/functional/terminal/edit_spec.lua +++ b/test/functional/terminal/edit_spec.lua @@ -31,45 +31,41 @@ describe(':edit term://*', function() eq(termopen_runs[1], termopen_runs[1]:match('^term://.//%d+:$')) end) - it('runs TermOpen early enough to respect terminal_scrollback_buffer_size', function() + it("runs TermOpen early enough to set buffer-local 'scrollback'", function() local columns, lines = 20, 4 local scr = get_screen(columns, lines) local rep = 'a' meths.set_option('shellcmdflag', 'REP ' .. rep) - local rep_size = rep:byte() + local rep_size = rep:byte() -- 'a' => 97 local sb = 10 - local gsb = 20 - meths.set_var('terminal_scrollback_buffer_size', gsb) - command('autocmd TermOpen * :let b:terminal_scrollback_buffer_size = ' - .. tostring(sb)) + command('autocmd TermOpen * :setlocal scrollback='..tostring(sb) + ..'|call feedkeys("G", "n")') command('edit term://foobar') + local bufcontents = {} local winheight = curwinmeths.get_height() - -- I have no idea why there is + 4 needed. But otherwise it works fine with - -- different scrollbacks. - local shift = -4 - local buf_cont_start = rep_size - 1 - sb - winheight - shift - local bufline = function(i) return ('%d: foobar'):format(i) end + local buf_cont_start = rep_size - sb - winheight + 2 + local function bufline (i) + return ('%d: foobar'):format(i) + end for i = buf_cont_start,(rep_size - 1) do bufcontents[#bufcontents + 1] = bufline(i) end bufcontents[#bufcontents + 1] = '' bufcontents[#bufcontents + 1] = '[Process exited 0]' - -- Do not ask me why displayed screen is one line *before* buffer - -- contents: buffer starts with 87:, screen with 86:. + local exp_screen = '\n' - local did_cursor = false - for i = 0,(winheight - 1) do - local line = bufline(buf_cont_start + i - 1) + for i = 1,(winheight - 1) do + local line = bufcontents[#bufcontents - winheight + i] exp_screen = (exp_screen - .. (did_cursor and '' or '^') .. line .. (' '):rep(columns - #line) .. '|\n') - did_cursor = true end - exp_screen = exp_screen .. (' '):rep(columns) .. '|\n' + exp_screen = exp_screen..'^[Process exited 0] |\n' + + exp_screen = exp_screen..(' '):rep(columns)..'|\n' scr:expect(exp_screen) - eq(bufcontents, curbufmeths.get_lines(1, -1, true)) + eq(bufcontents, curbufmeths.get_lines(0, -1, true)) end) end) diff --git a/test/functional/terminal/ex_terminal_spec.lua b/test/functional/terminal/ex_terminal_spec.lua index 7c391db18c..7a9d2a9b36 100644 --- a/test/functional/terminal/ex_terminal_spec.lua +++ b/test/functional/terminal/ex_terminal_spec.lua @@ -20,26 +20,34 @@ describe(':terminal', function() source([[ echomsg "msg1" echomsg "msg2" + echomsg "msg3" ]]) -- Invoke a command that emits frequent terminal activity. execute([[terminal while true; do echo X; done]]) helpers.feed([[<C-\><C-N>]]) - screen:expect([[ - X | - X | - ^X | - | - ]]) + wait() helpers.sleep(10) -- Let some terminal activity happen. execute("messages") screen:expect([[ - X | msg1 | msg2 | + msg3 | Press ENTER or type command to continue^ | ]]) end) + it("in normal-mode :split does not move cursor", function() + execute([[terminal while true; do echo foo; sleep .1; done]]) + helpers.feed([[<C-\><C-N>M]]) -- move cursor away from last line + wait() + eq(3, eval("line('$')")) -- window height + eq(2, eval("line('.')")) -- cursor is in the middle + execute('vsplit') + eq(2, eval("line('.')")) -- cursor stays where we put it + execute('split') + eq(2, eval("line('.')")) -- cursor stays where we put it + end) + end) describe(':terminal (with fake shell)', function() diff --git a/test/functional/terminal/helpers.lua b/test/functional/terminal/helpers.lua index ae5e6d4b1f..934c01e3bf 100644 --- a/test/functional/terminal/helpers.lua +++ b/test/functional/terminal/helpers.lua @@ -1,7 +1,7 @@ local helpers = require('test.functional.helpers')(nil) local Screen = require('test.functional.ui.screen') local nvim_dir = helpers.nvim_dir -local execute, nvim, wait = helpers.execute, helpers.nvim, helpers.wait +local execute, nvim = helpers.execute, helpers.nvim local function feed_data(data) nvim('set_var', 'term_data', data) @@ -34,13 +34,15 @@ local function disable_mouse() feed_termcode('[?1002l') end local default_command = '["'..nvim_dir..'/tty-test'..'"]' -local function screen_setup(extra_height, command) +local function screen_setup(extra_rows, command, cols) + extra_rows = extra_rows and extra_rows or 0 + command = command and command or default_command + cols = cols and cols or 50 + nvim('command', 'highlight TermCursor cterm=reverse') nvim('command', 'highlight TermCursorNC ctermbg=11') - nvim('set_var', 'terminal_scrollback_buffer_size', 10) - if not extra_height then extra_height = 0 end - if not command then command = default_command end - local screen = Screen.new(50, 7 + extra_height) + + local screen = Screen.new(cols, 7 + extra_rows) screen:set_default_attr_ids({ [1] = {reverse = true}, -- focused cursor [2] = {background = 11}, -- unfocused cursor @@ -55,31 +57,42 @@ local function screen_setup(extra_height, command) }) screen:attach({rgb=false}) - -- tty-test puts the terminal into raw mode and echoes all input. tests are - -- done by feeding it with terminfo codes to control the display and - -- verifying output with screen:expect. - execute('enew | call termopen('..command..') | startinsert') + + execute('enew | call termopen('..command..')') + nvim('input', '<CR>') + local vim_errmsg = nvim('eval', 'v:errmsg') + if vim_errmsg and "" ~= vim_errmsg then + error(vim_errmsg) + end + + execute('setlocal scrollback=10') + execute('startinsert') + + -- tty-test puts the terminal into raw mode and echoes input. Tests work by + -- feeding termcodes to control the display and asserting by screen:expect. if command == default_command then - -- wait for "tty ready" to be printed before each test or the terminal may - -- still be in canonical mode(will echo characters for example) - -- - local empty_line = ' ' + -- Wait for "tty ready" to be printed before each test or the terminal may + -- still be in canonical mode (will echo characters for example). + local empty_line = (' '):rep(cols + 1) local expected = { - 'tty ready ', - '{1: } ', + 'tty ready'..(' '):rep(cols - 8), + '{1: }' ..(' '):rep(cols), empty_line, empty_line, empty_line, empty_line, } - for _ = 1, extra_height do + for _ = 1, extra_rows do table.insert(expected, empty_line) end - table.insert(expected, '{3:-- TERMINAL --} ') + table.insert(expected, '{3:-- TERMINAL --}' .. ((' '):rep(cols - 13))) screen:expect(table.concat(expected, '\n')) else - wait() + -- This eval also acts as a wait(). + if 0 == nvim('eval', "exists('b:terminal_job_id')") then + error("terminal job failed to start") + end end return screen end diff --git a/test/functional/terminal/mouse_spec.lua b/test/functional/terminal/mouse_spec.lua index ecb0b2beb0..da7e1c36db 100644 --- a/test/functional/terminal/mouse_spec.lua +++ b/test/functional/terminal/mouse_spec.lua @@ -117,7 +117,7 @@ describe('terminal mouse', function() rows: 5, cols: 25 |rows: 5, cols: 25 | {2:^ } |{2: } | ========== ========== | - | + :vsp | ]]) feed(':enew | set number<cr>') screen:expect([[ diff --git a/test/functional/terminal/scrollback_spec.lua b/test/functional/terminal/scrollback_spec.lua index d60819af65..930d0cf58b 100644 --- a/test/functional/terminal/scrollback_spec.lua +++ b/test/functional/terminal/scrollback_spec.lua @@ -3,7 +3,11 @@ local helpers = require('test.functional.helpers')(after_each) local thelpers = require('test.functional.terminal.helpers') local clear, eq, curbuf = helpers.clear, helpers.eq, helpers.curbuf local feed, nvim_dir, execute = helpers.feed, helpers.nvim_dir, helpers.execute +local eval = helpers.eval +local command = helpers.command local wait = helpers.wait +local retry = helpers.retry +local curbufmeths = helpers.curbufmeths local feed_data = thelpers.feed_data if helpers.pending_win32(pending) then return end @@ -13,14 +17,14 @@ describe('terminal scrollback', function() before_each(function() clear() - screen = thelpers.screen_setup() + screen = thelpers.screen_setup(nil, nil, 30) end) after_each(function() screen:detach() end) - describe('when the limit is crossed', function() + describe('when the limit is exceeded', function() before_each(function() local lines = {} for i = 1, 30 do @@ -29,26 +33,26 @@ describe('terminal scrollback', function() table.insert(lines, '') feed_data(lines) screen:expect([[ - line26 | - line27 | - line28 | - line29 | - line30 | - {1: } | - {3:-- TERMINAL --} | + line26 | + line27 | + line28 | + line29 | + line30 | + {1: } | + {3:-- TERMINAL --} | ]]) end) it('will delete extra lines at the top', function() feed('<c-\\><c-n>gg') screen:expect([[ - ^line16 | - line17 | - line18 | - line19 | - line20 | - line21 | - | + ^line16 | + line17 | + line18 | + line19 | + line20 | + line21 | + | ]]) end) end) @@ -57,13 +61,13 @@ describe('terminal scrollback', function() before_each(function() feed_data({'line1', 'line2', 'line3', 'line4', ''}) screen:expect([[ - tty ready | - line1 | - line2 | - line3 | - line4 | - {1: } | - {3:-- TERMINAL --} | + tty ready | + line1 | + line2 | + line3 | + line4 | + {1: } | + {3:-- TERMINAL --} | ]]) end) @@ -72,13 +76,13 @@ describe('terminal scrollback', function() it('will hide the top line', function() screen:expect([[ - line1 | - line2 | - line3 | - line4 | - line5 | - {1: } | - {3:-- TERMINAL --} | + line1 | + line2 | + line3 | + line4 | + line5 | + {1: } | + {3:-- TERMINAL --} | ]]) eq(7, curbuf('line_count')) end) @@ -88,46 +92,46 @@ describe('terminal scrollback', function() it('will hide the top 4 lines', function() screen:expect([[ - line3 | - line4 | - line5 | - line6 | - line7 | - line8{1: } | - {3:-- TERMINAL --} | + line3 | + line4 | + line5 | + line6 | + line7 | + line8{1: } | + {3:-- TERMINAL --} | ]]) feed('<c-\\><c-n>6k') screen:expect([[ - ^line2 | - line3 | - line4 | - line5 | - line6 | - line7 | - | + ^line2 | + line3 | + line4 | + line5 | + line6 | + line7 | + | ]]) feed('gg') screen:expect([[ - ^tty ready | - line1 | - line2 | - line3 | - line4 | - line5 | - | + ^tty ready | + line1 | + line2 | + line3 | + line4 | + line5 | + | ]]) feed('G') screen:expect([[ - line3 | - line4 | - line5 | - line6 | - line7 | - ^line8{2: } | - | + line3 | + line4 | + line5 | + line6 | + line7 | + ^line8{2: } | + | ]]) end) end) @@ -138,12 +142,12 @@ describe('terminal scrollback', function() local function will_hide_top_line() screen:try_resize(screen._width, screen._height - 1) screen:expect([[ - line2 | - line3 | - line4 | - rows: 5, cols: 50 | - {1: } | - {3:-- TERMINAL --} | + line2 | + line3 | + line4 | + rows: 5, cols: 30 | + {1: } | + {3:-- TERMINAL --} | ]]) end @@ -157,18 +161,18 @@ describe('terminal scrollback', function() it('will hide the top 3 lines', function() screen:expect([[ - rows: 5, cols: 50 | - rows: 3, cols: 50 | - {1: } | - {3:-- TERMINAL --} | + rows: 5, cols: 30 | + rows: 3, cols: 30 | + {1: } | + {3:-- TERMINAL --} | ]]) eq(8, curbuf('line_count')) feed('<c-\\><c-n>3k') screen:expect([[ - ^line4 | - rows: 5, cols: 50 | - rows: 3, cols: 50 | - | + ^line4 | + rows: 5, cols: 30 | + rows: 3, cols: 30 | + | ]]) end) end) @@ -183,11 +187,11 @@ describe('terminal scrollback', function() local function will_delete_last_two_lines() screen:expect([[ - tty ready | - rows: 4, cols: 50 | - {1: } | - | - {3:-- TERMINAL --} | + tty ready | + rows: 4, cols: 30 | + {1: } | + | + {3:-- TERMINAL --} | ]]) eq(4, curbuf('line_count')) end @@ -202,25 +206,25 @@ describe('terminal scrollback', function() it('will delete the last line and hide the first', function() screen:expect([[ - rows: 4, cols: 50 | - rows: 3, cols: 50 | - {1: } | - {3:-- TERMINAL --} | + rows: 4, cols: 30 | + rows: 3, cols: 30 | + {1: } | + {3:-- TERMINAL --} | ]]) eq(4, curbuf('line_count')) feed('<c-\\><c-n>gg') screen:expect([[ - ^tty ready | - rows: 4, cols: 50 | - rows: 3, cols: 50 | - | + ^tty ready | + rows: 4, cols: 30 | + rows: 3, cols: 30 | + | ]]) feed('a') screen:expect([[ - rows: 4, cols: 50 | - rows: 3, cols: 50 | - {1: } | - {3:-- TERMINAL --} | + rows: 4, cols: 30 | + rows: 3, cols: 30 | + {1: } | + {3:-- TERMINAL --} | ]]) end) end) @@ -231,20 +235,20 @@ describe('terminal scrollback', function() before_each(function() feed_data({'line1', 'line2', 'line3', 'line4', ''}) screen:expect([[ - tty ready | - line1 | - line2 | - line3 | - line4 | - {1: } | - {3:-- TERMINAL --} | + tty ready | + line1 | + line2 | + line3 | + line4 | + {1: } | + {3:-- TERMINAL --} | ]]) screen:try_resize(screen._width, screen._height - 3) screen:expect([[ - line4 | - rows: 3, cols: 50 | - {1: } | - {3:-- TERMINAL --} | + line4 | + rows: 3, cols: 30 | + {1: } | + {3:-- TERMINAL --} | ]]) eq(7, curbuf('line_count')) end) @@ -253,11 +257,11 @@ describe('terminal scrollback', function() local function pop_then_push() screen:try_resize(screen._width, screen._height + 1) screen:expect([[ - line4 | - rows: 3, cols: 50 | - rows: 4, cols: 50 | - {1: } | - {3:-- TERMINAL --} | + line4 | + rows: 3, cols: 30 | + rows: 4, cols: 30 | + {1: } | + {3:-- TERMINAL --} | ]]) end @@ -272,26 +276,26 @@ describe('terminal scrollback', function() local function pop3_then_push1() screen:expect([[ - line2 | - line3 | - line4 | - rows: 3, cols: 50 | - rows: 4, cols: 50 | - rows: 7, cols: 50 | - {1: } | - {3:-- TERMINAL --} | + line2 | + line3 | + line4 | + rows: 3, cols: 30 | + rows: 4, cols: 30 | + rows: 7, cols: 30 | + {1: } | + {3:-- TERMINAL --} | ]]) eq(9, curbuf('line_count')) feed('<c-\\><c-n>gg') screen:expect([[ - ^tty ready | - line1 | - line2 | - line3 | - line4 | - rows: 3, cols: 50 | - rows: 4, cols: 50 | - | + ^tty ready | + line1 | + line2 | + line3 | + line4 | + rows: 3, cols: 30 | + rows: 4, cols: 30 | + | ]]) end @@ -306,18 +310,18 @@ describe('terminal scrollback', function() it('will show all lines and leave a blank one at the end', function() screen:expect([[ - tty ready | - line1 | - line2 | - line3 | - line4 | - rows: 3, cols: 50 | - rows: 4, cols: 50 | - rows: 7, cols: 50 | - rows: 11, cols: 50 | - {1: } | - | - {3:-- TERMINAL --} | + tty ready | + line1 | + line2 | + line3 | + line4 | + rows: 3, cols: 30 | + rows: 4, cols: 30 | + rows: 7, cols: 30 | + rows: 11, cols: 30 | + {1: } | + | + {3:-- TERMINAL --} | ]]) -- since there's an empty line after the cursor, the buffer line -- count equals the terminal screen height @@ -332,30 +336,115 @@ end) describe('terminal prints more lines than the screen height and exits', function() it('will push extra lines to scrollback', function() clear() - local screen = Screen.new(50, 7) + local screen = Screen.new(30, 7) screen:attach({rgb=false}) execute('call termopen(["'..nvim_dir..'/tty-test", "10"]) | startinsert') wait() screen:expect([[ - line6 | - line7 | - line8 | - line9 | - | - [Process exited 0] | - -- TERMINAL -- | + line6 | + line7 | + line8 | + line9 | + | + [Process exited 0] | + -- TERMINAL -- | ]]) feed('<cr>') -- closes the buffer correctly after pressing a key screen:expect([[ - ^ | - ~ | - ~ | - ~ | - ~ | - ~ | - | + ^ | + ~ | + ~ | + ~ | + ~ | + ~ | + | ]]) end) end) +describe("'scrollback' option", function() + before_each(function() + clear() + end) + + local function expect_lines(expected) + local actual = eval("line('$')") + if expected ~= actual then + error('expected: '..expected..', actual: '..tostring(actual)) + end + end + + it('set to 0 behaves as 1', function() + local screen = thelpers.screen_setup(nil, "['sh']", 30) + + curbufmeths.set_option('scrollback', 0) + feed_data('for i in $(seq 1 30); do echo "line$i"; done\n') + screen:expect('line30 ', nil, nil, nil, true) + retry(nil, nil, function() expect_lines(7) end) + + screen:detach() + end) + + it('deletes lines (only) if necessary', function() + local screen = thelpers.screen_setup(nil, "['sh']", 30) + + curbufmeths.set_option('scrollback', 200) + + -- Wait for prompt. + screen:expect('$', nil, nil, nil, true) + + wait() + feed_data('for i in $(seq 1 30); do echo "line$i"; done\n') + + screen:expect('line30 ', nil, nil, nil, true) + + retry(nil, nil, function() expect_lines(33) end) + curbufmeths.set_option('scrollback', 10) + wait() + retry(nil, nil, function() expect_lines(16) end) + curbufmeths.set_option('scrollback', 10000) + eq(16, eval("line('$')")) + -- Terminal job data is received asynchronously, may happen before the + -- 'scrollback' option is synchronized with the internal sb_buffer. + command('sleep 100m') + feed_data('for i in $(seq 1 40); do echo "line$i"; done\n') + + screen:expect('line40 ', nil, nil, nil, true) + + retry(nil, nil, function() expect_lines(58) end) + -- Verify off-screen state + eq('line35', eval("getline(line('w0') - 1)")) + eq('line26', eval("getline(line('w0') - 10)")) + + screen:detach() + end) + + it('defaults to 1000', function() + execute('terminal') + eq(1000, curbufmeths.get_option('scrollback')) + end) + + it('error if set to invalid values', function() + local status, rv = pcall(command, 'set scrollback=-2') + eq(false, status) -- assert failure + eq('E474:', string.match(rv, "E%d*:")) + + status, rv = pcall(command, 'set scrollback=100001') + eq(false, status) -- assert failure + eq('E474:', string.match(rv, "E%d*:")) + end) + + it('defaults to -1 on normal buffers', function() + execute('new') + eq(-1, curbufmeths.get_option('scrollback')) + end) + + it('error if set on a normal buffer', function() + command('new') + execute('set scrollback=42') + feed('<CR>') + eq('E474:', string.match(eval("v:errmsg"), "E%d*:")) + end) + +end) diff --git a/test/functional/terminal/window_split_tab_spec.lua b/test/functional/terminal/window_split_tab_spec.lua index 6951b84a69..d3386a641e 100644 --- a/test/functional/terminal/window_split_tab_spec.lua +++ b/test/functional/terminal/window_split_tab_spec.lua @@ -28,16 +28,16 @@ describe('terminal', function() feed('<c-\\><c-n>') execute('2split') screen:expect([[ - tty ready | - ^rows: 2, cols: 50 | + rows: 2, cols: 50 | + {2:^ } | ========== | - tty ready | rows: 2, cols: 50 | {2: } | {4:~ }| {4:~ }| + {4:~ }| ========== | - | + :2split | ]]) execute('wincmd p') screen:expect([[ @@ -54,14 +54,14 @@ describe('terminal', function() ]]) execute('wincmd p') screen:expect([[ - rows: 5, cols: 50 | - ^rows: 2, cols: 50 | + rows: 2, cols: 50 | + {2:^ } | ========== | - rows: 5, cols: 50 | rows: 2, cols: 50 | {2: } | {4:~ }| {4:~ }| + {4:~ }| ========== | :wincmd p | ]]) diff --git a/test/helpers.lua b/test/helpers.lua index 3f7a9c2b74..25ab80bb50 100644 --- a/test/helpers.lua +++ b/test/helpers.lua @@ -17,6 +17,34 @@ local ok = function(res) return assert.is_true(res) end +local function glob(initial_path, re, exc_re) + local paths_to_check = {initial_path} + local ret = {} + local checked_files = {} + while #paths_to_check > 0 do + local cur_path = paths_to_check[#paths_to_check] + paths_to_check[#paths_to_check] = nil + for e in lfs.dir(cur_path) do + local full_path = cur_path .. '/' .. e + local checked_path = full_path:sub(#initial_path + 1) + if ((not exc_re or not checked_path:match(exc_re)) + and e:sub(1, 1) ~= '.') then + local attrs = lfs.attributes(full_path) + local check_key = attrs.dev .. ':' .. tostring(attrs.ino) + if not checked_files[check_key] then + checked_files[check_key] = true + if attrs.mode == 'directory' then + paths_to_check[#paths_to_check + 1] = full_path + elseif not re or checked_path:match(re) then + ret[#ret + 1] = full_path + end + end + end + end + end + return ret +end + local function check_logs() local log_dir = os.getenv('LOG_DIR') local runtime_errors = 0 @@ -109,6 +137,81 @@ local function filter(filter_func, tab) return rettab end +local function hasenv(name) + local env = os.getenv(name) + if env and env ~= '' then + return env + end + return nil +end + +local tests_skipped = 0 + +local function check_cores(app) + app = app or 'build/bin/nvim' + local initial_path, re, exc_re + local gdb_db_cmd = 'gdb -n -batch -ex "thread apply all bt full" "$_NVIM_TEST_APP" -c "$_NVIM_TEST_CORE"' + local lldb_db_cmd = 'lldb -Q -o "bt all" -f "$_NVIM_TEST_APP" -c "$_NVIM_TEST_CORE"' + local random_skip = false + local db_cmd + if hasenv('NVIM_TEST_CORE_GLOB_DIRECTORY') then + initial_path = os.getenv('NVIM_TEST_CORE_GLOB_DIRECTORY') + re = os.getenv('NVIM_TEST_CORE_GLOB_RE') + exc_re = os.getenv('NVIM_TEST_CORE_EXC_RE') + db_cmd = os.getenv('NVIM_TEST_CORE_DB_CMD') or gdb_db_cmd + random_skip = os.getenv('NVIM_TEST_CORE_RANDOM_SKIP') + elseif os.getenv('TRAVIS_OS_NAME') == 'osx' then + initial_path = '/cores' + re = nil + exc_re = nil + db_cmd = lldb_db_cmd + else + initial_path = '.' + re = '/core[^/]*$' + exc_re = '^/%.deps$' + db_cmd = gdb_db_cmd + random_skip = true + end + -- Finding cores takes too much time on linux + if random_skip and math.random() < 0.9 then + tests_skipped = tests_skipped + 1 + return + end + local cores = glob(initial_path, re, exc_re) + local found_cores = 0 + local out = io.stdout + for _, core in ipairs(cores) do + local len = 80 - #core - #('Core file ') - 2 + 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() + found_cores = found_cores + 1 + os.remove(core) + end + if found_cores ~= 0 then + out:write(('\nTests covered by this check: %u\n'):format(tests_skipped + 1)) + end + tests_skipped = 0 + if found_cores > 0 then + error("crash detected (see above)") + end +end + return { eq = eq, neq = neq, @@ -118,4 +221,7 @@ return { tmpname = tmpname, map = map, filter = filter, + glob = glob, + check_cores = check_cores, + hasenv = hasenv, } diff --git a/test/unit/preprocess.lua b/test/unit/preprocess.lua index 1c9b290462..4d819e5f23 100644 --- a/test/unit/preprocess.lua +++ b/test/unit/preprocess.lua @@ -185,6 +185,30 @@ local function repeated_call(...) return nil end +function Gcc:filter_standard_defines(defines) + if not self.standard_defines then + local pseudoheader_fname = 'tmp_empty_pseudoheader.h' + local pseudoheader_file = io.open(pseudoheader_fname, 'w') + pseudoheader_file:close() + local standard_defines = repeated_call(self.path, + self.preprocessor_extra_flags, + self.get_defines_extra_flags, + {pseudoheader_fname}) + os.remove(pseudoheader_fname) + self.standard_defines = {} + for line in standard_defines:gmatch('[^\n]+') do + self.standard_defines[line] = true + end + end + local ret = {} + for line in defines:gmatch('[^\n]+') do + if not self.standard_defines[line] then + ret[#ret + 1] = line + end + end + return table.concat(ret, "\n") +end + -- returns a stream representing a preprocessed form of the passed-in headers. -- Don't forget to close the stream by calling the close() method on it. function Gcc:preprocess(previous_defines, ...) @@ -201,6 +225,7 @@ function Gcc:preprocess(previous_defines, ...) local defines = repeated_call(self.path, self.preprocessor_extra_flags, self.get_defines_extra_flags, {pseudoheader_fname}) + defines = self:filter_standard_defines(defines) -- lfs = require("lfs") -- print("CWD: #{lfs.currentdir!}") |