diff options
Diffstat (limited to 'test/functional/lua')
34 files changed, 2077 insertions, 681 deletions
diff --git a/test/functional/lua/api_spec.lua b/test/functional/lua/api_spec.lua index acd56a0ddb..56969150bd 100644 --- a/test/functional/lua/api_spec.lua +++ b/test/functional/lua/api_spec.lua @@ -1,15 +1,16 @@ -- Test suite for testing interactions with API bindings -local helpers = require('test.functional.helpers')(after_each) - -local exc_exec = helpers.exc_exec -local remove_trace = helpers.remove_trace -local fn = helpers.fn -local clear = helpers.clear -local eval = helpers.eval +local t = require('test.testutil') +local n = require('test.functional.testnvim')() + +local exc_exec = n.exc_exec +local remove_trace = t.remove_trace +local fn = n.fn +local clear = n.clear +local eval = n.eval local NIL = vim.NIL -local eq = helpers.eq -local exec_lua = helpers.exec_lua -local pcall_err = helpers.pcall_err +local eq = t.eq +local exec_lua = n.exec_lua +local pcall_err = t.pcall_err before_each(clear) diff --git a/test/functional/lua/base64_spec.lua b/test/functional/lua/base64_spec.lua index 21fd536a98..529f5f56e8 100644 --- a/test/functional/lua/base64_spec.lua +++ b/test/functional/lua/base64_spec.lua @@ -1,9 +1,11 @@ -local helpers = require('test.functional.helpers')(after_each) -local clear = helpers.clear -local exec_lua = helpers.exec_lua -local eq = helpers.eq -local pcall_err = helpers.pcall_err -local matches = helpers.matches +local t = require('test.testutil') +local n = require('test.functional.testnvim')() + +local clear = n.clear +local exec_lua = n.exec_lua +local eq = t.eq +local pcall_err = t.pcall_err +local matches = t.matches describe('vim.base64', function() before_each(clear) @@ -42,6 +44,7 @@ describe('vim.base64', function() ̦H̬̤̗̤͝e͜ ̜̥̝̻͍̟́w̕h̖̯͓o̝͙̖͎̱̮ ҉̺̙̞̟͈W̷̼̭a̺̪͍į͈͕̭͙̯̜t̶̼̮s̘͙͖̕ ̠̫̠B̻͍͙͉̳ͅe̵h̵̬͇̫͙i̹͓̳̳̮͎̫̕n͟d̴̪̜̖ ̰͉̩͇͙̲͞ͅT͖̼͓̪͢h͏͓̮̻e̬̝̟ͅ ̤̹̝W͙̞̝͔͇͝ͅa͏͓͔̹̼̣l̴͔̰̤̟͔ḽ̫.͕ Z̮̞̠͙͔ͅḀ̗̞͈̻̗Ḷ͙͎̯̹̞͓G̻O̭̗̮ ]], + 'Hello\0world', } for _, v in ipairs(values) do diff --git a/test/functional/lua/buffer_updates_spec.lua b/test/functional/lua/buffer_updates_spec.lua index 714e1b951f..d4af7e4732 100644 --- a/test/functional/lua/buffer_updates_spec.lua +++ b/test/functional/lua/buffer_updates_spec.lua @@ -1,17 +1,19 @@ -- Test suite for testing interactions with API bindings -local helpers = require('test.functional.helpers')(after_each) - -local command = helpers.command -local api = helpers.api -local fn = helpers.fn -local clear = helpers.clear -local eq = helpers.eq -local fail = helpers.fail -local exec_lua = helpers.exec_lua -local feed = helpers.feed -local expect_events = helpers.expect_events -local write_file = helpers.write_file -local dedent = helpers.dedent +local t = require('test.testutil') +local n = require('test.functional.testnvim')() +local Screen = require('test.functional.ui.screen') + +local command = n.command +local api = n.api +local fn = n.fn +local clear = n.clear +local eq = t.eq +local fail = t.fail +local exec_lua = n.exec_lua +local feed = n.feed +local expect_events = t.expect_events +local write_file = t.write_file +local dedent = t.dedent local origlines = { 'original line 1', @@ -291,11 +293,11 @@ describe('lua buffer event callbacks: on_lines', function() exec_lua(code) command('q!') - helpers.assert_alive() + n.assert_alive() exec_lua(code) command('bd!') - helpers.assert_alive() + n.assert_alive() end) it('#12718 lnume', function() @@ -312,31 +314,71 @@ describe('lua buffer event callbacks: on_lines', function() feed('G0') feed('p') -- Is the last arg old_byte_size correct? Doesn't matter for this PR - eq(api.nvim_get_var('linesev'), { 'lines', 1, 4, 2, 3, 5, 4 }) + eq({ 'lines', 1, 4, 2, 3, 5, 4 }, api.nvim_get_var('linesev')) feed('2G0') feed('p') - eq(api.nvim_get_var('linesev'), { 'lines', 1, 5, 1, 4, 4, 8 }) + eq({ 'lines', 1, 5, 1, 4, 4, 8 }, api.nvim_get_var('linesev')) feed('1G0') feed('P') - eq(api.nvim_get_var('linesev'), { 'lines', 1, 6, 0, 3, 3, 9 }) + eq({ 'lines', 1, 6, 0, 3, 3, 9 }, api.nvim_get_var('linesev')) end) - it( - 'calling nvim_buf_call() from callback does not cause Normal mode CTRL-A to misbehave #16729', - function() - exec_lua([[ + it('nvim_buf_call() from callback does not cause wrong Normal mode CTRL-A #16729', function() + exec_lua([[ vim.api.nvim_buf_attach(0, false, { on_lines = function(...) vim.api.nvim_buf_call(0, function() end) end, }) ]]) - feed('itest123<Esc><C-A>') - eq('test124', api.nvim_get_current_line()) - end - ) + feed('itest123<Esc><C-A>') + eq('test124', api.nvim_get_current_line()) + end) + + it('setting extmark in on_lines callback works', function() + local screen = Screen.new(40, 6) + screen:attach() + + api.nvim_buf_set_lines(0, 0, -1, true, { 'aaa', 'bbb', 'ccc' }) + exec_lua([[ + local ns = vim.api.nvim_create_namespace('') + vim.api.nvim_buf_attach(0, false, { + on_lines = function(_, _, _, row, _, end_row) + vim.api.nvim_buf_clear_namespace(0, ns, row, end_row) + for i = row, end_row - 1 do + local id = vim.api.nvim_buf_set_extmark(0, ns, i, 0, { + virt_text = {{ 'NEW' .. tostring(i), 'WarningMsg' }}, + }) + end + end, + }) + ]]) + + feed('o') + screen:expect({ + grid = [[ + aaa | + ^ {19:NEW1} | + bbb | + ccc | + {1:~ }| + {5:-- INSERT --} | + ]], + }) + feed('<CR>') + screen:expect({ + grid = [[ + aaa | + {19:NEW1} | + ^ {19:NEW2} | + bbb | + ccc | + {5:-- INSERT --} | + ]], + }) + end) end) describe('lua: nvim_buf_attach on_bytes', function() @@ -426,14 +468,14 @@ describe('lua: nvim_buf_attach on_bytes', function() it('opening lines', function() local check_events = setup_eventcheck(verify, origlines) - -- api.nvim_set_option_value('autoindent', true, {}) + api.nvim_set_option_value('autoindent', false, {}) feed 'Go' check_events { { 'test1', 'bytes', 1, 3, 7, 0, 114, 0, 0, 0, 1, 0, 1 }, } feed '<cr>' check_events { - { 'test1', 'bytes', 1, 5, 7, 0, 114, 0, 0, 0, 1, 0, 1 }, + { 'test1', 'bytes', 1, 4, 7, 0, 114, 0, 0, 0, 1, 0, 1 }, } end) @@ -447,7 +489,7 @@ describe('lua: nvim_buf_attach on_bytes', function() feed '<cr>' check_events { { 'test1', 'bytes', 1, 4, 7, 0, 114, 0, 4, 4, 0, 0, 0 }, - { 'test1', 'bytes', 1, 5, 7, 0, 114, 0, 0, 0, 1, 4, 5 }, + { 'test1', 'bytes', 1, 4, 7, 0, 114, 0, 0, 0, 1, 4, 5 }, } end) @@ -477,7 +519,7 @@ describe('lua: nvim_buf_attach on_bytes', function() api.nvim_set_option_value('filetype', 'c', {}) feed 'A<CR>' check_events { - { 'test1', 'bytes', 1, 4, 0, 10, 10, 0, 0, 0, 1, 3, 4 }, + { 'test1', 'bytes', 1, 3, 0, 10, 10, 0, 0, 0, 1, 3, 4 }, } feed '<ESC>' @@ -493,7 +535,7 @@ describe('lua: nvim_buf_attach on_bytes', function() feed '<CR>' check_events { { 'test1', 'bytes', 1, 6, 1, 2, 13, 0, 1, 1, 0, 0, 0 }, - { 'test1', 'bytes', 1, 7, 1, 2, 13, 0, 0, 0, 1, 3, 4 }, + { 'test1', 'bytes', 1, 6, 1, 2, 13, 0, 0, 0, 1, 3, 4 }, } end) @@ -541,7 +583,7 @@ describe('lua: nvim_buf_attach on_bytes', function() feed 'cc' check_events { - { 'test1', 'bytes', 1, 4, 0, 0, 0, 0, 15, 15, 0, 0, 0 }, + { 'test1', 'bytes', 1, 3, 0, 0, 0, 0, 15, 15, 0, 0, 0 }, } feed '<ESC>' @@ -924,7 +966,7 @@ describe('lua: nvim_buf_attach on_bytes', function() command('e! Xtest-undofile') command('set undodir=. | set undofile') - local ns = helpers.request('nvim_create_namespace', 'ns1') + local ns = n.request('nvim_create_namespace', 'ns1') api.nvim_buf_set_extmark(0, ns, 0, 0, {}) eq({ '12345', 'hello world' }, api.nvim_buf_get_lines(0, 0, -1, true)) @@ -1225,6 +1267,25 @@ describe('lua: nvim_buf_attach on_bytes', function() } end) + it('prompt buffer', function() + local check_events = setup_eventcheck(verify, {}) + api.nvim_set_option_value('buftype', 'prompt', {}) + feed('i') + check_events { + { 'test1', 'bytes', 1, 3, 0, 0, 0, 0, 0, 0, 0, 2, 2 }, + } + feed('<CR>') + check_events { + { 'test1', 'bytes', 1, 4, 1, 0, 3, 0, 0, 0, 1, 0, 1 }, + { 'test1', 'bytes', 1, 5, 1, 0, 3, 0, 0, 0, 0, 2, 2 }, + } + feed('<CR>') + check_events { + { 'test1', 'bytes', 1, 6, 2, 0, 6, 0, 0, 0, 1, 0, 1 }, + { 'test1', 'bytes', 1, 7, 2, 0, 6, 0, 0, 0, 0, 2, 2 }, + } + end) + local function test_lockmarks(mode) local description = (mode ~= '') and mode or '(baseline)' it('test_lockmarks ' .. description .. ' %delete _', function() diff --git a/test/functional/lua/command_line_completion_spec.lua b/test/functional/lua/command_line_completion_spec.lua index b88a38082f..2ba432133b 100644 --- a/test/functional/lua/command_line_completion_spec.lua +++ b/test/functional/lua/command_line_completion_spec.lua @@ -1,8 +1,9 @@ -local helpers = require('test.functional.helpers')(after_each) +local t = require('test.testutil') +local n = require('test.functional.testnvim')() -local clear = helpers.clear -local eq = helpers.eq -local exec_lua = helpers.exec_lua +local clear = n.clear +local eq = t.eq +local exec_lua = n.exec_lua local get_completions = function(input, env) return exec_lua('return {vim._expand_pat(...)}', input, env) diff --git a/test/functional/lua/commands_spec.lua b/test/functional/lua/commands_spec.lua index b8d0638ce5..57b084d3d6 100644 --- a/test/functional/lua/commands_spec.lua +++ b/test/functional/lua/commands_spec.lua @@ -1,24 +1,25 @@ -- Test suite for checking :lua* commands -local helpers = require('test.functional.helpers')(after_each) +local t = require('test.testutil') +local n = require('test.functional.testnvim')() local Screen = require('test.functional.ui.screen') -local eq = helpers.eq +local eq = t.eq local NIL = vim.NIL -local eval = helpers.eval -local feed = helpers.feed -local clear = helpers.clear -local matches = helpers.matches -local api = helpers.api -local exec_lua = helpers.exec_lua -local exec_capture = helpers.exec_capture -local fn = helpers.fn -local source = helpers.source -local dedent = helpers.dedent -local command = helpers.command -local exc_exec = helpers.exc_exec -local pcall_err = helpers.pcall_err -local write_file = helpers.write_file -local remove_trace = helpers.remove_trace +local eval = n.eval +local feed = n.feed +local clear = n.clear +local matches = t.matches +local api = n.api +local exec_lua = n.exec_lua +local exec_capture = n.exec_capture +local fn = n.fn +local source = n.source +local dedent = t.dedent +local command = n.command +local exc_exec = n.exc_exec +local pcall_err = t.pcall_err +local write_file = t.write_file +local remove_trace = t.remove_trace before_each(clear) diff --git a/test/functional/lua/comment_spec.lua b/test/functional/lua/comment_spec.lua new file mode 100644 index 0000000000..bbf061a2ab --- /dev/null +++ b/test/functional/lua/comment_spec.lua @@ -0,0 +1,651 @@ +local t = require('test.testutil') +local n = require('test.functional.testnvim')() + +local api = n.api +local clear = n.clear +local eq = t.eq +local exec_capture = n.exec_capture +local exec_lua = n.exec_lua +local feed = n.feed + +-- Reference text +-- aa +-- aa +-- aa +-- +-- aa +-- aa +-- aa +local example_lines = { 'aa', ' aa', ' aa', '', ' aa', ' aa', 'aa' } + +local set_commentstring = function(commentstring) + api.nvim_set_option_value('commentstring', commentstring, { buf = 0 }) +end + +local get_lines = function(from, to) + from, to = from or 0, to or -1 + return api.nvim_buf_get_lines(0, from, to, false) +end + +local set_lines = function(lines, from, to) + from, to = from or 0, to or -1 + api.nvim_buf_set_lines(0, from, to, false, lines) +end + +local set_cursor = function(row, col) + api.nvim_win_set_cursor(0, { row, col }) +end + +local get_cursor = function() + return api.nvim_win_get_cursor(0) +end + +local setup_treesitter = function() + -- NOTE: This leverages bundled Vimscript and Lua tree-sitter parsers + api.nvim_set_option_value('filetype', 'vim', { buf = 0 }) + exec_lua('vim.treesitter.start()') +end + +before_each(function() + clear({ args_rm = { '--cmd' }, args = { '--clean' } }) +end) + +describe('commenting', function() + before_each(function() + set_lines(example_lines) + set_commentstring('# %s') + end) + + describe('toggle_lines()', function() + local toggle_lines = function(...) + exec_lua('require("vim._comment").toggle_lines(...)', ...) + end + + it('works', function() + toggle_lines(3, 5) + eq(get_lines(2, 5), { ' # aa', ' #', ' # aa' }) + + toggle_lines(3, 5) + eq(get_lines(2, 5), { ' aa', '', ' aa' }) + end) + + it("works with different 'commentstring' options", function() + local validate = function(lines_before, lines_after, lines_again) + set_lines(lines_before) + toggle_lines(1, #lines_before) + eq(get_lines(), lines_after) + toggle_lines(1, #lines_before) + eq(get_lines(), lines_again or lines_before) + end + + -- Single whitespace inside comment parts (main case) + set_commentstring('# %s #') + -- - General case + validate( + { 'aa', ' aa', 'aa ', ' aa ' }, + { '# aa #', '# aa #', '# aa #', '# aa #' } + ) + -- - Tabs + validate( + { 'aa', '\taa', 'aa\t', '\taa\t' }, + { '# aa #', '# \taa #', '# aa\t #', '# \taa\t #' } + ) + -- - With indent + validate({ ' aa', ' aa' }, { ' # aa #', ' # aa #' }) + -- - With blank/empty lines + validate( + { ' aa', '', ' ', '\t' }, + { ' # aa #', ' ##', ' ##', ' ##' }, + { ' aa', '', '', '' } + ) + + set_commentstring('# %s') + validate({ 'aa', ' aa', 'aa ', ' aa ' }, { '# aa', '# aa', '# aa ', '# aa ' }) + validate({ 'aa', '\taa', 'aa\t', '\taa\t' }, { '# aa', '# \taa', '# aa\t', '# \taa\t' }) + validate({ ' aa', ' aa' }, { ' # aa', ' # aa' }) + validate( + { ' aa', '', ' ', '\t' }, + { ' # aa', ' #', ' #', ' #' }, + { ' aa', '', '', '' } + ) + + set_commentstring('%s #') + validate({ 'aa', ' aa', 'aa ', ' aa ' }, { 'aa #', ' aa #', 'aa #', ' aa #' }) + validate({ 'aa', '\taa', 'aa\t', '\taa\t' }, { 'aa #', '\taa #', 'aa\t #', '\taa\t #' }) + validate({ ' aa', ' aa' }, { ' aa #', ' aa #' }) + validate( + { ' aa', '', ' ', '\t' }, + { ' aa #', ' #', ' #', ' #' }, + { ' aa', '', '', '' } + ) + + -- No whitespace in parts + set_commentstring('#%s#') + validate({ 'aa', ' aa', 'aa ', ' aa ' }, { '#aa#', '# aa#', '#aa #', '# aa #' }) + validate({ 'aa', '\taa', 'aa\t', '\taa\t' }, { '#aa#', '#\taa#', '#aa\t#', '#\taa\t#' }) + validate({ ' aa', ' aa' }, { ' #aa#', ' # aa#' }) + validate( + { ' aa', '', ' ', '\t' }, + { ' #aa#', ' ##', ' ##', ' ##' }, + { ' aa', '', '', '' } + ) + + set_commentstring('#%s') + validate({ 'aa', ' aa', 'aa ', ' aa ' }, { '#aa', '# aa', '#aa ', '# aa ' }) + validate({ 'aa', '\taa', 'aa\t', '\taa\t' }, { '#aa', '#\taa', '#aa\t', '#\taa\t' }) + validate({ ' aa', ' aa' }, { ' #aa', ' # aa' }) + validate({ ' aa', '', ' ', '\t' }, { ' #aa', ' #', ' #', ' #' }, { ' aa', '', '', '' }) + + set_commentstring('%s#') + validate({ 'aa', ' aa', 'aa ', ' aa ' }, { 'aa#', ' aa#', 'aa #', ' aa #' }) + validate({ 'aa', '\taa', 'aa\t', '\taa\t' }, { 'aa#', '\taa#', 'aa\t#', '\taa\t#' }) + validate({ ' aa', ' aa' }, { ' aa#', ' aa#' }) + validate({ ' aa', '', ' ', '\t' }, { ' aa#', ' #', ' #', ' #' }, { ' aa', '', '', '' }) + + -- Extra whitespace inside comment parts + set_commentstring('# %s #') + validate( + { 'aa', ' aa', 'aa ', ' aa ' }, + { '# aa #', '# aa #', '# aa #', '# aa #' } + ) + validate( + { 'aa', '\taa', 'aa\t', '\taa\t' }, + { '# aa #', '# \taa #', '# aa\t #', '# \taa\t #' } + ) + validate({ ' aa', ' aa' }, { ' # aa #', ' # aa #' }) + validate( + { ' aa', '', ' ', '\t' }, + { ' # aa #', ' ##', ' ##', ' ##' }, + { ' aa', '', '', '' } + ) + + set_commentstring('# %s') + validate({ 'aa', ' aa', 'aa ', ' aa ' }, { '# aa', '# aa', '# aa ', '# aa ' }) + validate({ 'aa', '\taa', 'aa\t', '\taa\t' }, { '# aa', '# \taa', '# aa\t', '# \taa\t' }) + validate({ ' aa', ' aa' }, { ' # aa', ' # aa' }) + validate( + { ' aa', '', ' ', '\t' }, + { ' # aa', ' #', ' #', ' #' }, + { ' aa', '', '', '' } + ) + + set_commentstring('%s #') + validate({ 'aa', ' aa', 'aa ', ' aa ' }, { 'aa #', ' aa #', 'aa #', ' aa #' }) + validate({ 'aa', '\taa', 'aa\t', '\taa\t' }, { 'aa #', '\taa #', 'aa\t #', '\taa\t #' }) + validate({ ' aa', ' aa' }, { ' aa #', ' aa #' }) + validate( + { ' aa', '', ' ', '\t' }, + { ' aa #', ' #', ' #', ' #' }, + { ' aa', '', '', '' } + ) + + -- Whitespace outside of comment parts + set_commentstring(' # %s # ') + validate( + { 'aa', ' aa', 'aa ', ' aa ' }, + { ' # aa # ', ' # aa # ', ' # aa # ', ' # aa # ' } + ) + validate( + { 'aa', '\taa', 'aa\t', '\taa\t' }, + { ' # aa # ', ' # \taa # ', ' # aa\t # ', ' # \taa\t # ' } + ) + validate({ ' aa', ' aa' }, { ' # aa # ', ' # aa # ' }) + validate( + { ' aa', '', ' ', '\t' }, + { ' # aa # ', ' ##', ' ##', ' ##' }, + { ' aa', '', '', '' } + ) + + set_commentstring(' # %s ') + validate( + { 'aa', ' aa', 'aa ', ' aa ' }, + { ' # aa ', ' # aa ', ' # aa ', ' # aa ' } + ) + validate( + { 'aa', '\taa', 'aa\t', '\taa\t' }, + { ' # aa ', ' # \taa ', ' # aa\t ', ' # \taa\t ' } + ) + validate({ ' aa', ' aa' }, { ' # aa ', ' # aa ' }) + validate( + { ' aa', '', ' ', '\t' }, + { ' # aa ', ' #', ' #', ' #' }, + { ' aa', '', '', '' } + ) + + set_commentstring(' %s # ') + validate( + { 'aa', ' aa', 'aa ', ' aa ' }, + { ' aa # ', ' aa # ', ' aa # ', ' aa # ' } + ) + validate( + { 'aa', '\taa', 'aa\t', '\taa\t' }, + { ' aa # ', ' \taa # ', ' aa\t # ', ' \taa\t # ' } + ) + validate({ ' aa', ' aa' }, { ' aa # ', ' aa # ' }) + validate( + { ' aa', '', ' ', '\t' }, + { ' aa # ', ' #', ' #', ' #' }, + { ' aa', '', '', '' } + ) + + -- LaTeX + set_commentstring('% %s') + validate({ 'aa', ' aa', 'aa ', ' aa ' }, { '% aa', '% aa', '% aa ', '% aa ' }) + validate({ 'aa', '\taa', 'aa\t', '\taa\t' }, { '% aa', '% \taa', '% aa\t', '% \taa\t' }) + validate({ ' aa', ' aa' }, { ' % aa', ' % aa' }) + validate( + { ' aa', '', ' ', '\t' }, + { ' % aa', ' %', ' %', ' %' }, + { ' aa', '', '', '' } + ) + end) + + it('respects tree-sitter injections', function() + setup_treesitter() + + local lines = { + 'set background=dark', + 'lua << EOF', + 'print(1)', + 'vim.api.nvim_exec2([[', + ' set background=light', + ']])', + 'EOF', + } + + -- Single line comments + local validate = function(line, ref_output) + set_lines(lines) + toggle_lines(line, line) + eq(get_lines(line - 1, line)[1], ref_output) + end + + validate(1, '"set background=dark') + validate(2, '"lua << EOF') + validate(3, '-- print(1)') + validate(4, '-- vim.api.nvim_exec2([[') + validate(5, ' "set background=light') + validate(6, '-- ]])') + validate(7, '"EOF') + + -- Multiline comments should be computed based on first line 'commentstring' + set_lines(lines) + toggle_lines(1, 3) + local out_lines = get_lines() + eq(out_lines[1], '"set background=dark') + eq(out_lines[2], '"lua << EOF') + eq(out_lines[3], '"print(1)') + end) + + it('correctly computes indent', function() + toggle_lines(2, 4) + eq(get_lines(1, 4), { ' # aa', ' # aa', ' #' }) + end) + + it('correctly detects comment/uncomment', function() + local validate = function(from, to, ref_lines) + set_lines({ '', 'aa', '# aa', '# aa', 'aa', '' }) + toggle_lines(from, to) + eq(get_lines(), ref_lines) + end + + -- It should uncomment only if all non-blank lines are comments + validate(3, 4, { '', 'aa', 'aa', 'aa', 'aa', '' }) + validate(2, 4, { '', '# aa', '# # aa', '# # aa', 'aa', '' }) + validate(3, 5, { '', 'aa', '# # aa', '# # aa', '# aa', '' }) + validate(1, 6, { '#', '# aa', '# # aa', '# # aa', '# aa', '#' }) + + -- Blank lines should be ignored when making a decision + set_lines({ '# aa', '', ' ', '\t', '# aa' }) + toggle_lines(1, 5) + eq(get_lines(), { 'aa', '', ' ', '\t', 'aa' }) + end) + + it('correctly matches comment parts during checking and uncommenting', function() + local validate = function(from, to, ref_lines) + set_lines({ '/*aa*/', '/* aa */', '/* aa */' }) + toggle_lines(from, to) + eq(get_lines(), ref_lines) + end + + -- Should first try to match 'commentstring' parts exactly with their + -- whitespace, with fallback on trimmed parts + set_commentstring('/*%s*/') + validate(1, 3, { 'aa', ' aa ', ' aa ' }) + validate(2, 3, { '/*aa*/', ' aa ', ' aa ' }) + validate(3, 3, { '/*aa*/', '/* aa */', ' aa ' }) + + set_commentstring('/* %s */') + validate(1, 3, { 'aa', 'aa', ' aa ' }) + validate(2, 3, { '/*aa*/', 'aa', ' aa ' }) + validate(3, 3, { '/*aa*/', '/* aa */', ' aa ' }) + + set_commentstring('/* %s */') + validate(1, 3, { 'aa', ' aa ', 'aa' }) + validate(2, 3, { '/*aa*/', ' aa ', 'aa' }) + validate(3, 3, { '/*aa*/', '/* aa */', 'aa' }) + + set_commentstring(' /*%s*/ ') + validate(1, 3, { 'aa', ' aa ', ' aa ' }) + validate(2, 3, { '/*aa*/', ' aa ', ' aa ' }) + validate(3, 3, { '/*aa*/', '/* aa */', ' aa ' }) + end) + + it('uncomments on inconsistent indent levels', function() + set_lines({ '# aa', ' # aa', ' # aa' }) + toggle_lines(1, 3) + eq(get_lines(), { 'aa', ' aa', ' aa' }) + end) + + it('respects tabs', function() + api.nvim_set_option_value('expandtab', false, { buf = 0 }) + set_lines({ '\t\taa', '\t\taa' }) + + toggle_lines(1, 2) + eq(get_lines(), { '\t\t# aa', '\t\t# aa' }) + + toggle_lines(1, 2) + eq(get_lines(), { '\t\taa', '\t\taa' }) + end) + + it('works with trailing whitespace', function() + -- Without right-hand side + set_commentstring('# %s') + set_lines({ ' aa', ' aa ', ' ' }) + toggle_lines(1, 3) + eq(get_lines(), { ' # aa', ' # aa ', ' #' }) + toggle_lines(1, 3) + eq(get_lines(), { ' aa', ' aa ', '' }) + + -- With right-hand side + set_commentstring('%s #') + set_lines({ ' aa', ' aa ', ' ' }) + toggle_lines(1, 3) + eq(get_lines(), { ' aa #', ' aa #', ' #' }) + toggle_lines(1, 3) + eq(get_lines(), { ' aa', ' aa ', '' }) + + -- Trailing whitespace after right side should be preserved for non-blanks + set_commentstring('%s #') + set_lines({ ' aa # ', ' aa #\t', ' # ', ' #\t' }) + toggle_lines(1, 4) + eq(get_lines(), { ' aa ', ' aa\t', '', '' }) + end) + end) + + describe('Operator', function() + it('works in Normal mode', function() + set_cursor(2, 2) + feed('gc', 'ap') + eq(get_lines(), { '# aa', '# aa', '# aa', '#', ' aa', ' aa', 'aa' }) + -- Cursor moves to start line + eq(get_cursor(), { 1, 0 }) + + -- Supports `v:count` + set_lines(example_lines) + set_cursor(2, 0) + feed('2gc', 'ap') + eq(get_lines(), { '# aa', '# aa', '# aa', '#', '# aa', '# aa', '# aa' }) + end) + + it('allows dot-repeat in Normal mode', function() + local doubly_commented = { '# # aa', '# # aa', '# # aa', '# #', '# aa', '# aa', '# aa' } + + set_lines(example_lines) + set_cursor(2, 2) + feed('gc', 'ap') + feed('.') + eq(get_lines(), doubly_commented) + + -- Not immediate dot-repeat + set_lines(example_lines) + set_cursor(2, 2) + feed('gc', 'ap') + set_cursor(7, 0) + feed('.') + eq(get_lines(), doubly_commented) + end) + + it('works in Visual mode', function() + set_cursor(2, 2) + feed('v', 'ap', 'gc') + eq(get_lines(), { '# aa', '# aa', '# aa', '#', ' aa', ' aa', 'aa' }) + + -- Cursor moves to start line + eq(get_cursor(), { 1, 0 }) + end) + + it('allows dot-repeat after initial Visual mode', function() + -- local example_lines = { 'aa', ' aa', ' aa', '', ' aa', ' aa', 'aa' } + + set_lines(example_lines) + set_cursor(2, 2) + feed('vip', 'gc') + eq(get_lines(), { '# aa', '# aa', '# aa', '', ' aa', ' aa', 'aa' }) + eq(get_cursor(), { 1, 0 }) + + -- Dot-repeat after first application in Visual mode should apply to the same + -- relative region + feed('.') + eq(get_lines(), example_lines) + + set_cursor(3, 0) + feed('.') + eq(get_lines(), { 'aa', ' aa', ' # aa', ' #', ' # aa', ' aa', 'aa' }) + end) + + it("respects 'commentstring'", function() + set_commentstring('/*%s*/') + set_cursor(2, 2) + feed('gc', 'ap') + eq(get_lines(), { '/*aa*/', '/* aa*/', '/* aa*/', '/**/', ' aa', ' aa', 'aa' }) + end) + + it("works with empty 'commentstring'", function() + set_commentstring('') + set_cursor(2, 2) + feed('gc', 'ap') + eq(get_lines(), example_lines) + eq(exec_capture('1messages'), [[Option 'commentstring' is empty.]]) + end) + + it('respects tree-sitter injections', function() + setup_treesitter() + + local lines = { + 'set background=dark', + 'lua << EOF', + 'print(1)', + 'vim.api.nvim_exec2([[', + ' set background=light', + ']])', + 'EOF', + } + + -- Single line comments + local validate = function(line, ref_output) + set_lines(lines) + set_cursor(line, 0) + feed('gc_') + eq(get_lines(line - 1, line)[1], ref_output) + end + + validate(1, '"set background=dark') + validate(2, '"lua << EOF') + validate(3, '-- print(1)') + validate(4, '-- vim.api.nvim_exec2([[') + validate(5, ' "set background=light') + validate(6, '-- ]])') + validate(7, '"EOF') + + -- Has proper dot-repeat which recomputes 'commentstring' + set_lines(lines) + + set_cursor(1, 0) + feed('gc_') + eq(get_lines()[1], '"set background=dark') + + set_cursor(3, 0) + feed('.') + eq(get_lines()[3], '-- print(1)') + + -- Multiline comments should be computed based on cursor position + -- which in case of Visual selection means its left part + set_lines(lines) + set_cursor(1, 0) + feed('v2j', 'gc') + local out_lines = get_lines() + eq(out_lines[1], '"set background=dark') + eq(out_lines[2], '"lua << EOF') + eq(out_lines[3], '"print(1)') + end) + + it("recomputes local 'commentstring' based on cursor position", function() + setup_treesitter() + local lines = { + ' print(1)', + 'lua << EOF', + ' print(1)', + 'EOF', + } + set_lines(lines) + + set_cursor(1, 1) + feed('gc_') + eq(get_lines()[1], ' "print(1)') + + set_lines(lines) + set_cursor(3, 2) + feed('.') + eq(get_lines()[3], ' -- print(1)') + end) + + it('preserves marks', function() + set_cursor(2, 0) + -- Set '`<' and '`>' marks + feed('VV') + feed('gc', 'ip') + eq(api.nvim_buf_get_mark(0, '<'), { 2, 0 }) + eq(api.nvim_buf_get_mark(0, '>'), { 2, 2147483647 }) + end) + end) + + describe('Current line', function() + it('works', function() + set_lines(example_lines) + set_cursor(1, 1) + feed('gcc') + eq(get_lines(0, 2), { '# aa', ' aa' }) + + -- Does not comment empty line + set_lines(example_lines) + set_cursor(4, 0) + feed('gcc') + eq(get_lines(2, 5), { ' aa', '', ' aa' }) + + -- Supports `v:count` + set_lines(example_lines) + set_cursor(2, 0) + feed('2gcc') + eq(get_lines(0, 3), { 'aa', ' # aa', ' # aa' }) + end) + + it('allows dot-repeat', function() + set_lines(example_lines) + set_cursor(1, 1) + feed('gcc') + feed('.') + eq(get_lines(), example_lines) + + -- Not immediate dot-repeat + set_lines(example_lines) + set_cursor(1, 1) + feed('gcc') + set_cursor(7, 0) + feed('.') + eq(get_lines(6, 7), { '# aa' }) + end) + + it('respects tree-sitter injections', function() + setup_treesitter() + + local lines = { + 'set background=dark', + 'lua << EOF', + 'print(1)', + 'EOF', + } + set_lines(lines) + + set_cursor(1, 0) + feed('gcc') + eq(get_lines(), { '"set background=dark', 'lua << EOF', 'print(1)', 'EOF' }) + + -- Should work with dot-repeat + set_cursor(3, 0) + feed('.') + eq(get_lines(), { '"set background=dark', 'lua << EOF', '-- print(1)', 'EOF' }) + end) + end) + + describe('Textobject', function() + it('works', function() + set_lines({ 'aa', '# aa', '# aa', 'aa' }) + set_cursor(2, 0) + feed('d', 'gc') + eq(get_lines(), { 'aa', 'aa' }) + end) + + it('allows dot-repeat', function() + set_lines({ 'aa', '# aa', '# aa', 'aa', '# aa' }) + set_cursor(2, 0) + feed('d', 'gc') + set_cursor(3, 0) + feed('.') + eq(get_lines(), { 'aa', 'aa' }) + end) + + it('does nothing when not inside textobject', function() + -- Builtin operators + feed('d', 'gc') + eq(get_lines(), example_lines) + + -- Comment operator + local validate_no_action = function(line, col) + set_lines(example_lines) + set_cursor(line, col) + feed('gc', 'gc') + eq(get_lines(), example_lines) + end + + validate_no_action(1, 1) + validate_no_action(2, 2) + + -- Doesn't work (but should) because both `[` and `]` are set to (1, 0) + -- (instead of more reasonable (1, -1) or (0, 2147483647)). + -- validate_no_action(1, 0) + end) + + it('respects tree-sitter injections', function() + setup_treesitter() + local lines = { + '"set background=dark', + '"set termguicolors', + 'lua << EOF', + '-- print(1)', + '-- print(2)', + 'EOF', + } + set_lines(lines) + + set_cursor(1, 0) + feed('dgc') + eq(get_lines(), { 'lua << EOF', '-- print(1)', '-- print(2)', 'EOF' }) + + -- Should work with dot-repeat + set_cursor(2, 0) + feed('.') + eq(get_lines(), { 'lua << EOF', 'EOF' }) + end) + end) +end) diff --git a/test/functional/lua/diagnostic_spec.lua b/test/functional/lua/diagnostic_spec.lua index 5802925339..05082bc132 100644 --- a/test/functional/lua/diagnostic_spec.lua +++ b/test/functional/lua/diagnostic_spec.lua @@ -1,13 +1,15 @@ -local helpers = require('test.functional.helpers')(after_each) +local t = require('test.testutil') +local n = require('test.functional.testnvim')() local NIL = vim.NIL -local command = helpers.command -local clear = helpers.clear -local exec_lua = helpers.exec_lua -local eq = helpers.eq -local matches = helpers.matches -local api = helpers.api -local pcall_err = helpers.pcall_err +local command = n.command +local clear = n.clear +local exec_lua = n.exec_lua +local eq = t.eq +local matches = t.matches +local api = n.api +local pcall_err = t.pcall_err +local fn = n.fn describe('vim.diagnostic', function() before_each(function() @@ -16,12 +18,12 @@ describe('vim.diagnostic', function() exec_lua [[ require('vim.diagnostic') - function make_diagnostic(msg, x1, y1, x2, y2, severity, source, code) + function make_diagnostic(msg, lnum, col, end_lnum, end_col, severity, source, code) return { - lnum = x1, - col = y1, - end_lnum = x2, - end_col = y2, + lnum = lnum, + col = col, + end_lnum = end_lnum, + end_col = end_col, message = msg, severity = severity, source = source, @@ -29,20 +31,20 @@ describe('vim.diagnostic', function() } end - function make_error(msg, x1, y1, x2, y2, source, code) - return make_diagnostic(msg, x1, y1, x2, y2, vim.diagnostic.severity.ERROR, source, code) + function make_error(msg, lnum, col, end_lnum, end_col, source, code) + return make_diagnostic(msg, lnum, col, end_lnum, end_col, vim.diagnostic.severity.ERROR, source, code) end - function make_warning(msg, x1, y1, x2, y2, source, code) - return make_diagnostic(msg, x1, y1, x2, y2, vim.diagnostic.severity.WARN, source, code) + function make_warning(msg, lnum, col, end_lnum, end_col, source, code) + return make_diagnostic(msg, lnum, col, end_lnum, end_col, vim.diagnostic.severity.WARN, source, code) end - function make_info(msg, x1, y1, x2, y2, source, code) - return make_diagnostic(msg, x1, y1, x2, y2, vim.diagnostic.severity.INFO, source, code) + function make_info(msg, lnum, col, end_lnum, end_col, source, code) + return make_diagnostic(msg, lnum, col, end_lnum, end_col, vim.diagnostic.severity.INFO, source, code) end - function make_hint(msg, x1, y1, x2, y2, source, code) - return make_diagnostic(msg, x1, y1, x2, y2, vim.diagnostic.severity.HINT, source, code) + function make_hint(msg, lnum, col, end_lnum, end_col, source, code) + return make_diagnostic(msg, lnum, col, end_lnum, end_col, vim.diagnostic.severity.HINT, source, code) end function count_diagnostics(bufnr, severity, namespace) @@ -109,7 +111,7 @@ describe('vim.diagnostic', function() 'DiagnosticVirtualTextOk', 'DiagnosticVirtualTextWarn', 'DiagnosticWarn', - }, exec_lua([[return vim.fn.getcompletion('Diagnostic', 'highlight')]])) + }, fn.getcompletion('Diagnostic', 'highlight')) end) it('retrieves diagnostics from all buffers and namespaces', function() @@ -205,7 +207,7 @@ describe('vim.diagnostic', function() diag[1].col = 10000 return vim.diagnostic.get()[1].col == 10000 ]] - eq(result, false) + eq(false, result) end) it('resolves buffer number 0 to the current buffer', function() @@ -328,7 +330,7 @@ describe('vim.diagnostic', function() eq( { 1, 1, 2, 0, 2 }, exec_lua [[ - vim.diagnostic.disable(diagnostic_bufnr, diagnostic_ns) + vim.diagnostic.enable(false, { bufnr = diagnostic_bufnr, ns_id = diagnostic_ns }) return { count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns), count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.WARN, other_ns), @@ -343,7 +345,7 @@ describe('vim.diagnostic', function() eq( all_highlights, exec_lua([[ - vim.diagnostic.enable(diagnostic_bufnr, diagnostic_ns) + vim.diagnostic.enable(true, { bufnr = diagnostic_bufnr, ns_id = diagnostic_ns }) return { count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns), count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.WARN, other_ns), @@ -370,7 +372,7 @@ describe('vim.diagnostic', function() vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, ns_1_diags) vim.diagnostic.set(other_ns, diagnostic_bufnr, ns_2_diags) - vim.diagnostic.disable(diagnostic_bufnr, diagnostic_ns) + vim.diagnostic.enable(false, { bufnr = diagnostic_bufnr, ns_id = diagnostic_ns }) return { count_extmarks(diagnostic_bufnr, diagnostic_ns), @@ -382,8 +384,8 @@ describe('vim.diagnostic', function() eq( { 4, 0 }, exec_lua [[ - vim.diagnostic.enable(diagnostic_bufnr, diagnostic_ns) - vim.diagnostic.disable(diagnostic_bufnr, other_ns) + vim.diagnostic.enable(true, { bufnr = diagnostic_bufnr, ns_id = diagnostic_ns }) + vim.diagnostic.enable(false, { bufnr = diagnostic_bufnr, ns_id = other_ns }) return { count_extmarks(diagnostic_bufnr, diagnostic_ns), @@ -477,7 +479,32 @@ describe('vim.diagnostic', function() end) describe('enable() and disable()', function() - it('works without arguments', function() + it('validation', function() + matches('expected boolean, got table', pcall_err(exec_lua, [[vim.diagnostic.enable({})]])) + matches( + 'filter: expected table, got string', + pcall_err(exec_lua, [[vim.diagnostic.enable(false, '')]]) + ) + matches( + 'Invalid buffer id: 42', + pcall_err(exec_lua, [[vim.diagnostic.enable(true, { bufnr = 42 })]]) + ) + matches( + 'expected boolean, got number', + pcall_err(exec_lua, [[vim.diagnostic.enable(42, {})]]) + ) + matches('expected boolean, got table', pcall_err(exec_lua, [[vim.diagnostic.enable({}, 42)]])) + + -- Deprecated signature. + matches('Invalid buffer id: 42', pcall_err(exec_lua, [[vim.diagnostic.enable(42)]])) + -- Deprecated signature. + matches( + 'namespace does not exist or is anonymous', + pcall_err(exec_lua, [[vim.diagnostic.enable(nil, 42)]]) + ) + end) + + it('without arguments', function() local result = exec_lua [[ vim.api.nvim_win_set_buf(0, diagnostic_bufnr) @@ -499,7 +526,7 @@ describe('vim.diagnostic', function() table.insert(result, count_extmarks(diagnostic_bufnr, diagnostic_ns) + count_extmarks(diagnostic_bufnr, other_ns)) - vim.diagnostic.disable() + vim.diagnostic.enable(false) table.insert(result, count_extmarks(diagnostic_bufnr, diagnostic_ns) + count_extmarks(diagnostic_bufnr, other_ns)) @@ -531,7 +558,7 @@ describe('vim.diagnostic', function() eq(4, result[4]) end) - it('works with only a buffer argument', function() + it('with buffer argument', function() local result = exec_lua [[ local other_bufnr = vim.api.nvim_create_buf(true, false) @@ -560,19 +587,19 @@ describe('vim.diagnostic', function() count_extmarks(diagnostic_bufnr, other_ns) + count_extmarks(other_bufnr, diagnostic_ns)) - vim.diagnostic.disable(diagnostic_bufnr) + vim.diagnostic.enable(false, { bufnr = diagnostic_bufnr }) table.insert(result, count_extmarks(diagnostic_bufnr, diagnostic_ns) + count_extmarks(diagnostic_bufnr, other_ns) + count_extmarks(other_bufnr, diagnostic_ns)) - vim.diagnostic.enable(diagnostic_bufnr) + vim.diagnostic.enable(true, { bufnr = diagnostic_bufnr }) table.insert(result, count_extmarks(diagnostic_bufnr, diagnostic_ns) + count_extmarks(diagnostic_bufnr, other_ns) + count_extmarks(other_bufnr, diagnostic_ns)) - vim.diagnostic.disable(other_bufnr) + vim.diagnostic.enable(false, { bufnr = other_bufnr }) table.insert(result, count_extmarks(diagnostic_bufnr, diagnostic_ns) + count_extmarks(diagnostic_bufnr, other_ns) + @@ -587,7 +614,7 @@ describe('vim.diagnostic', function() eq(3, result[4]) end) - it('works with only a namespace argument', function() + it('with a namespace argument', function() local result = exec_lua [[ vim.api.nvim_win_set_buf(0, diagnostic_bufnr) @@ -609,17 +636,17 @@ describe('vim.diagnostic', function() table.insert(result, count_extmarks(diagnostic_bufnr, diagnostic_ns) + count_extmarks(diagnostic_bufnr, other_ns)) - vim.diagnostic.disable(nil, diagnostic_ns) + vim.diagnostic.enable(false, { ns_id = diagnostic_ns }) table.insert(result, count_extmarks(diagnostic_bufnr, diagnostic_ns) + count_extmarks(diagnostic_bufnr, other_ns)) - vim.diagnostic.enable(nil, diagnostic_ns) + vim.diagnostic.enable(true, { ns_id = diagnostic_ns }) table.insert(result, count_extmarks(diagnostic_bufnr, diagnostic_ns) + count_extmarks(diagnostic_bufnr, other_ns)) - vim.diagnostic.disable(nil, other_ns) + vim.diagnostic.enable(false, { ns_id = other_ns }) table.insert(result, count_extmarks(diagnostic_bufnr, diagnostic_ns) + count_extmarks(diagnostic_bufnr, other_ns)) @@ -633,8 +660,11 @@ describe('vim.diagnostic', function() eq(2, result[4]) end) - it('works with both a buffer and a namespace argument', function() - local result = exec_lua [[ + --- @return table + local function test_enable(legacy) + local result = exec_lua( + [[ + local legacy = ... local other_bufnr = vim.api.nvim_create_buf(true, false) vim.api.nvim_win_set_buf(0, diagnostic_bufnr) @@ -662,34 +692,68 @@ describe('vim.diagnostic', function() count_extmarks(diagnostic_bufnr, other_ns) + count_extmarks(other_bufnr, diagnostic_ns)) - vim.diagnostic.disable(diagnostic_bufnr, diagnostic_ns) + if legacy then + vim.diagnostic.disable(diagnostic_bufnr, diagnostic_ns) + else + vim.diagnostic.enable(false, { bufnr = diagnostic_bufnr, ns_id = diagnostic_ns }) + end table.insert(result, count_extmarks(diagnostic_bufnr, diagnostic_ns) + count_extmarks(diagnostic_bufnr, other_ns) + count_extmarks(other_bufnr, diagnostic_ns)) - vim.diagnostic.disable(diagnostic_bufnr, other_ns) + if legacy then + vim.diagnostic.disable(diagnostic_bufnr, other_ns) + else + vim.diagnostic.enable(false, { bufnr = diagnostic_bufnr, ns_id = other_ns }) + end table.insert(result, count_extmarks(diagnostic_bufnr, diagnostic_ns) + count_extmarks(diagnostic_bufnr, other_ns) + count_extmarks(other_bufnr, diagnostic_ns)) - vim.diagnostic.enable(diagnostic_bufnr, diagnostic_ns) + if legacy then + vim.diagnostic.enable(diagnostic_bufnr, diagnostic_ns) + else + vim.diagnostic.enable(true, { bufnr = diagnostic_bufnr, ns_id = diagnostic_ns }) + end table.insert(result, count_extmarks(diagnostic_bufnr, diagnostic_ns) + count_extmarks(diagnostic_bufnr, other_ns) + count_extmarks(other_bufnr, diagnostic_ns)) - -- Should have no effect - vim.diagnostic.disable(other_bufnr, other_ns) + if legacy then + -- Should have no effect + vim.diagnostic.disable(other_bufnr, other_ns) + else + -- Should have no effect + vim.diagnostic.enable(false, { bufnr = other_bufnr, ns_id = other_ns }) + end table.insert(result, count_extmarks(diagnostic_bufnr, diagnostic_ns) + count_extmarks(diagnostic_bufnr, other_ns) + count_extmarks(other_bufnr, diagnostic_ns)) return result - ]] + ]], + legacy + ) + + return result + end + it('with both buffer and namespace arguments', function() + local result = test_enable(false) + eq(4, result[1]) + eq(2, result[2]) + eq(1, result[3]) + eq(3, result[4]) + eq(3, result[5]) + end) + + it('with both buffer and namespace arguments (deprecated signature)', function() + -- Exercise the legacy/deprecated signature. + local result = test_enable(true) eq(4, result[1]) eq(2, result[2]) eq(1, result[3]) @@ -870,15 +934,112 @@ describe('vim.diagnostic', function() eq( { 4, 0 }, exec_lua [[ - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error('Diagnostic #1', 3, 9001, 3, 9001), - make_error('Diagnostic #2', 4, -1, 4, -1), - }) - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - vim.api.nvim_win_set_cursor(0, {1, 1}) - vim.diagnostic.goto_next { float = false } - return vim.diagnostic.get_next_pos { namespace = diagnostic_ns } - ]] + vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { + make_error('Diagnostic #1', 3, 9001, 3, 9001), + make_error('Diagnostic #2', 4, -1, 4, -1), + }) + vim.api.nvim_win_set_buf(0, diagnostic_bufnr) + vim.api.nvim_win_set_cursor(0, {1, 1}) + vim.diagnostic.goto_next { float = false } + return vim.diagnostic.get_next_pos { namespace = diagnostic_ns } + ]] + ) + end) + + it('jumps to diagnostic with highest severity', function() + exec_lua([[ + vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { + make_info('Info', 1, 0, 1, 1), + make_error('Error', 2, 0, 2, 1), + make_warning('Warning', 3, 0, 3, 1), + make_error('Error', 4, 0, 4, 1), + }) + + vim.api.nvim_win_set_buf(0, diagnostic_bufnr) + vim.api.nvim_win_set_cursor(0, {1, 0}) + ]]) + + eq( + { 3, 0 }, + exec_lua([[ + vim.diagnostic.goto_next({_highest = true}) + return vim.api.nvim_win_get_cursor(0) + ]]) + ) + + eq( + { 5, 0 }, + exec_lua([[ + vim.diagnostic.goto_next({_highest = true}) + return vim.api.nvim_win_get_cursor(0) + ]]) + ) + + exec_lua([[ + vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { + make_info('Info', 1, 0, 1, 1), + make_hint('Hint', 2, 0, 2, 1), + make_warning('Warning', 3, 0, 3, 1), + make_hint('Hint', 4, 0, 4, 1), + make_warning('Warning', 5, 0, 5, 1), + }) + + vim.api.nvim_win_set_buf(0, diagnostic_bufnr) + vim.api.nvim_win_set_cursor(0, {1, 0}) + ]]) + + eq( + { 4, 0 }, + exec_lua([[ + vim.diagnostic.goto_next({_highest = true}) + return vim.api.nvim_win_get_cursor(0) + ]]) + ) + + eq( + { 6, 0 }, + exec_lua([[ + vim.diagnostic.goto_next({_highest = true}) + return vim.api.nvim_win_get_cursor(0) + ]]) + ) + end) + + it('jumps to next diagnostic if severity is non-nil', function() + exec_lua([[ + vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { + make_info('Info', 1, 0, 1, 1), + make_error('Error', 2, 0, 2, 1), + make_warning('Warning', 3, 0, 3, 1), + make_error('Error', 4, 0, 4, 1), + }) + + vim.api.nvim_win_set_buf(0, diagnostic_bufnr) + vim.api.nvim_win_set_cursor(0, {1, 0}) + ]]) + + eq( + { 2, 0 }, + exec_lua([[ + vim.diagnostic.goto_next() + return vim.api.nvim_win_get_cursor(0) + ]]) + ) + + eq( + { 3, 0 }, + exec_lua([[ + vim.diagnostic.goto_next() + return vim.api.nvim_win_get_cursor(0) + ]]) + ) + + eq( + { 4, 0 }, + exec_lua([[ + vim.diagnostic.goto_next() + return vim.api.nvim_win_get_cursor(0) + ]]) ) end) end) @@ -940,6 +1101,29 @@ describe('vim.diagnostic', function() ]] ) end) + + it('works on blank line #28397', function() + eq( + { 0, 2 }, + exec_lua [[ + local test_bufnr = vim.api.nvim_create_buf(true, false) + vim.api.nvim_buf_set_lines(test_bufnr, 0, -1, false, { + 'first line', + '', + '', + 'end line', + }) + vim.diagnostic.set(diagnostic_ns, test_bufnr, { + make_info('Diagnostic #1', 0, 2, 0, 2), + make_info('Diagnostic #2', 2, 0, 2, 0), + make_info('Diagnostic #3', 2, 0, 2, 0), + }) + vim.api.nvim_win_set_buf(0, test_bufnr) + vim.api.nvim_win_set_cursor(0, {3, 0}) + return vim.diagnostic.get_prev_pos { namespace = diagnostic_ns} + ]] + ) + end) end) describe('get()', function() @@ -1013,13 +1197,13 @@ describe('vim.diagnostic', function() it('allows filtering by line', function() eq( - 1, + 2, exec_lua [[ vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { make_error("Error 1", 1, 1, 1, 5), make_warning("Warning on Server 1", 1, 1, 2, 3), make_info("Ignored information", 1, 1, 2, 3), - make_error("Error On Other Line", 2, 1, 1, 5), + make_error("Error On Other Line", 3, 1, 3, 5), }) return #vim.diagnostic.get(diagnostic_bufnr, {lnum = 2}) @@ -1129,13 +1313,16 @@ describe('vim.diagnostic', function() it('allows filtering by line', function() eq( - exec_lua [[return { [vim.diagnostic.severity.ERROR] = 1 }]], + exec_lua [[return { + [vim.diagnostic.severity.WARN] = 1, + [vim.diagnostic.severity.INFO] = 1, + }]], exec_lua [[ vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { make_error("Error 1", 1, 1, 1, 5), make_warning("Warning on Server 1", 1, 1, 2, 3), make_info("Ignored information", 1, 1, 2, 3), - make_error("Error On Other Line", 2, 1, 1, 5), + make_error("Error On Other Line", 3, 1, 3, 5), }) return vim.diagnostic.count(diagnostic_bufnr, {lnum = 2}) @@ -1554,7 +1741,7 @@ describe('vim.diagnostic', function() end) describe('set()', function() - it('validates its arguments', function() + it('validation', function() matches( 'expected a list of diagnostics', pcall_err(exec_lua, [[vim.diagnostic.set(1, 0, {lnum = 1, col = 2})]]) @@ -1741,7 +1928,7 @@ describe('vim.diagnostic', function() eq( 0, exec_lua [[ - vim.diagnostic.disable(diagnostic_bufnr, diagnostic_ns) + vim.diagnostic.enable(false, { bufnr = diagnostic_bufnr, ns_id = diagnostic_ns }) vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { make_error('Diagnostic From Server 1:1', 1, 1, 1, 1), }) @@ -1752,7 +1939,7 @@ describe('vim.diagnostic', function() eq( 2, exec_lua [[ - vim.diagnostic.enable(diagnostic_bufnr, diagnostic_ns) + vim.diagnostic.enable(true, { bufnr = diagnostic_bufnr, ns_id = diagnostic_ns }) return count_extmarks(diagnostic_bufnr, diagnostic_ns) ]] ) @@ -1825,20 +2012,12 @@ describe('vim.diagnostic', function() it('respects legacy signs placed with :sign define or sign_define #26618', function() -- Legacy signs for diagnostics were deprecated in 0.10 and will be removed in 0.12 - eq(0, helpers.fn.has('nvim-0.12')) + eq(0, n.fn.has('nvim-0.12')) - helpers.command( - 'sign define DiagnosticSignError text= texthl= linehl=ErrorMsg numhl=ErrorMsg' - ) - helpers.command( - 'sign define DiagnosticSignWarn text= texthl= linehl=WarningMsg numhl=WarningMsg' - ) - helpers.command( - 'sign define DiagnosticSignInfo text= texthl= linehl=Underlined numhl=Underlined' - ) - helpers.command( - 'sign define DiagnosticSignHint text= texthl= linehl=Underlined numhl=Underlined' - ) + n.command('sign define DiagnosticSignError text= texthl= linehl=ErrorMsg numhl=ErrorMsg') + n.command('sign define DiagnosticSignWarn text= texthl= linehl=WarningMsg numhl=WarningMsg') + n.command('sign define DiagnosticSignInfo text= texthl= linehl=Underlined numhl=Underlined') + n.command('sign define DiagnosticSignHint text= texthl= linehl=Underlined numhl=Underlined') local result = exec_lua [[ vim.diagnostic.config({ @@ -2451,6 +2630,47 @@ describe('vim.diagnostic', function() ]] ) end) + + it('works for multi-line diagnostics #21949', function() + -- open float failed non diagnostic lnum + eq( + vim.NIL, + exec_lua [[ + local diagnostics = { + make_error("Error in two lines lnum is 1 and end_lnum is 2", 1, 1, 2, 3), + } + local winids = {} + vim.api.nvim_win_set_buf(0, diagnostic_bufnr) + vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics) + local _, winnr = vim.diagnostic.open_float(0, { header = false }) + return winnr + ]] + ) + + -- can open a float window on lnum 1 + eq( + { '1. Error in two lines lnum is 1 and end_lnum is 2' }, + exec_lua [[ + vim.api.nvim_win_set_cursor(0, {2, 0}) + local float_bufnr, winnr = vim.diagnostic.open_float(0, { header = false }) + local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) + vim.api.nvim_win_close(winnr, true) + return lines + ]] + ) + + -- can open a float window on end_lnum 2 + eq( + { '1. Error in two lines lnum is 1 and end_lnum is 2' }, + exec_lua [[ + vim.api.nvim_win_set_cursor(0, {3, 0}) + local float_bufnr, winnr = vim.diagnostic.open_float(0, { header = false }) + local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) + vim.api.nvim_win_close(winnr, true) + return lines + ]] + ) + end) end) describe('setloclist()', function() @@ -2718,7 +2938,41 @@ describe('vim.diagnostic', function() ) end) - it('checks if diagnostics are disabled in a buffer', function() + it('is_enabled', function() + eq( + { false, false, false, false, false }, + exec_lua [[ + vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { + make_error('Diagnostic #1', 1, 1, 1, 1), + }) + vim.api.nvim_set_current_buf(diagnostic_bufnr) + vim.diagnostic.enable(false) + return { + vim.diagnostic.is_enabled(), + vim.diagnostic.is_enabled{ bufnr = 0 }, + vim.diagnostic.is_enabled{ bufnr = diagnostic_bufnr }, + vim.diagnostic.is_enabled{ bufnr = diagnostic_bufnr, ns_id = diagnostic_ns }, + vim.diagnostic.is_enabled{ bufnr = 0, ns_id = diagnostic_ns }, + } + ]] + ) + + eq( + { true, true, true, true, true }, + exec_lua [[ + vim.diagnostic.enable() + return { + vim.diagnostic.is_enabled(), + vim.diagnostic.is_enabled{ bufnr = 0 }, + vim.diagnostic.is_enabled{ bufnr = diagnostic_bufnr }, + vim.diagnostic.is_enabled{ bufnr = diagnostic_bufnr, ns_id = diagnostic_ns }, + vim.diagnostic.is_enabled{ bufnr = 0, ns_id = diagnostic_ns }, + } + ]] + ) + end) + + it('is_disabled (deprecated)', function() eq( { true, true, true, true }, exec_lua [[ diff --git a/test/functional/lua/ffi_spec.lua b/test/functional/lua/ffi_spec.lua index c9e8e9d4ca..85ca264107 100644 --- a/test/functional/lua/ffi_spec.lua +++ b/test/functional/lua/ffi_spec.lua @@ -1,7 +1,9 @@ -local helpers = require('test.functional.helpers')(after_each) -local eq = helpers.eq -local exec_lua = helpers.exec_lua -local clear = helpers.clear +local t = require('test.testutil') +local n = require('test.functional.testnvim')() + +local eq = t.eq +local exec_lua = n.exec_lua +local clear = n.clear before_each(clear) @@ -13,15 +15,19 @@ describe('ffi.cdef', function() eq( 12, - exec_lua [[ + exec_lua [=[ local ffi = require('ffi') - ffi.cdef('int curwin_col_off(void);') + ffi.cdef [[ + typedef struct window_S win_T; + int win_col_off(win_T *wp); + extern win_T *curwin; + ]] vim.cmd('set number numberwidth=4 signcolumn=yes:4') - return ffi.C.curwin_col_off() - ]] + return ffi.C.win_col_off(ffi.C.curwin) + ]=] ) eq( @@ -30,7 +36,6 @@ describe('ffi.cdef', function() local ffi = require('ffi') ffi.cdef[[ - typedef struct window_S win_T; typedef struct {} stl_hlrec_t; typedef struct {} StlClickRecord; typedef struct {} statuscol_T; diff --git a/test/functional/lua/filetype_spec.lua b/test/functional/lua/filetype_spec.lua index 8b0e0a8beb..7db04e6f6b 100644 --- a/test/functional/lua/filetype_spec.lua +++ b/test/functional/lua/filetype_spec.lua @@ -1,10 +1,16 @@ -local helpers = require('test.functional.helpers')(after_each) -local exec_lua = helpers.exec_lua -local eq = helpers.eq -local api = helpers.api -local clear = helpers.clear -local pathroot = helpers.pathroot -local command = helpers.command +local t = require('test.testutil') +local n = require('test.functional.testnvim')() + +local exec_lua = n.exec_lua +local eq = t.eq +local api = n.api +local clear = n.clear +local pathroot = n.pathroot +local command = n.command +local mkdir = t.mkdir +local rmdir = n.rmdir +local write_file = t.write_file +local uv = vim.uv local root = pathroot() @@ -161,10 +167,30 @@ describe('vim.filetype', function() end) describe('filetype.lua', function() + before_each(function() + mkdir('Xfiletype') + end) + + after_each(function() + rmdir('Xfiletype') + end) + it('does not override user autocommands that set filetype #20333', function() clear({ args = { '--clean', '--cmd', 'autocmd BufRead *.md set filetype=notmarkdown', 'README.md' }, }) eq('notmarkdown', api.nvim_get_option_value('filetype', {})) end) + + it('uses unexpanded path for matching when editing a symlink #27914', function() + mkdir('Xfiletype/.config') + mkdir('Xfiletype/actual') + write_file('Xfiletype/actual/config', '') + uv.fs_symlink(assert(uv.fs_realpath('Xfiletype/actual')), 'Xfiletype/.config/git') + finally(function() + uv.fs_unlink('Xfiletype/.config/git') + end) + clear({ args = { '--clean', 'Xfiletype/.config/git/config' } }) + eq('gitconfig', api.nvim_get_option_value('filetype', {})) + end) end) diff --git a/test/functional/lua/fs_spec.lua b/test/functional/lua/fs_spec.lua index 6821fe3c5e..aba02ab01b 100644 --- a/test/functional/lua/fs_spec.lua +++ b/test/functional/lua/fs_spec.lua @@ -1,16 +1,19 @@ -local helpers = require('test.functional.helpers')(after_each) - -local clear = helpers.clear -local exec_lua = helpers.exec_lua -local eq = helpers.eq -local mkdir_p = helpers.mkdir_p -local rmdir = helpers.rmdir -local nvim_dir = helpers.nvim_dir -local test_build_dir = helpers.paths.test_build_dir -local test_source_path = helpers.paths.test_source_path -local nvim_prog = helpers.nvim_prog -local is_os = helpers.is_os -local mkdir = helpers.mkdir +local t = require('test.testutil') +local n = require('test.functional.testnvim')() + +local clear = n.clear +local exec_lua = n.exec_lua +local eq = t.eq +local mkdir_p = n.mkdir_p +local rmdir = n.rmdir +local nvim_dir = n.nvim_dir +local command = n.command +local api = n.api +local test_build_dir = t.paths.test_build_dir +local test_source_path = t.paths.test_source_path +local nvim_prog = n.nvim_prog +local is_os = t.is_os +local mkdir = t.mkdir local nvim_prog_basename = is_os('win') and 'nvim.exe' or 'nvim' @@ -36,6 +39,7 @@ local test_basename_dirname_eq = { 'c:/users/foo', 'c:/users/foo/bar.lua', 'c:/users/foo/bar/../', + '~/foo/bar\\baz', } local tests_windows_paths = { @@ -54,7 +58,7 @@ describe('vim.fs', function() it('works', function() local test_dir = nvim_dir .. '/test' mkdir_p(test_dir) - local dirs = {} + local dirs = {} --- @type string[] for dir in vim.fs.parents(test_dir .. '/foo.txt') do dirs[#dirs + 1] = dir if dir == test_build_dir then @@ -70,25 +74,26 @@ describe('vim.fs', function() it('works', function() eq(test_build_dir, vim.fs.dirname(nvim_dir)) - local function test_paths(paths) + ---@param paths string[] + ---@param is_win? boolean + local function test_paths(paths, is_win) + local gsub = is_win and [[:gsub('\\', '/')]] or '' + local code = string.format( + [[ + local path = ... + return vim.fn.fnamemodify(path,':h')%s + ]], + gsub + ) + for _, path in ipairs(paths) do - eq( - exec_lua( - [[ - local path = ... - return vim.fn.fnamemodify(path,':h'):gsub('\\', '/') - ]], - path - ), - vim.fs.dirname(path), - path - ) + eq(exec_lua(code, path), vim.fs.dirname(path), path) end end test_paths(test_basename_dirname_eq) if is_os('win') then - test_paths(tests_windows_paths) + test_paths(tests_windows_paths, true) end end) end) @@ -97,25 +102,26 @@ describe('vim.fs', function() it('works', function() eq(nvim_prog_basename, vim.fs.basename(nvim_prog)) - local function test_paths(paths) + ---@param paths string[] + ---@param is_win? boolean + local function test_paths(paths, is_win) + local gsub = is_win and [[:gsub('\\', '/')]] or '' + local code = string.format( + [[ + local path = ... + return vim.fn.fnamemodify(path,':t')%s + ]], + gsub + ) + for _, path in ipairs(paths) do - eq( - exec_lua( - [[ - local path = ... - return vim.fn.fnamemodify(path,':t'):gsub('\\', '/') - ]], - path - ), - vim.fs.basename(path), - path - ) + eq(exec_lua(code, path), vim.fs.basename(path), path) end end test_paths(test_basename_dirname_eq) if is_os('win') then - test_paths(tests_windows_paths) + test_paths(tests_windows_paths, true) end end) end) @@ -274,6 +280,57 @@ describe('vim.fs', function() end) end) + describe('root()', function() + before_each(function() + command('edit test/functional/fixtures/tty-test.c') + end) + + it('works with a single marker', function() + eq(test_source_path, exec_lua([[return vim.fs.root(0, '.git')]])) + end) + + it('works with multiple markers', function() + local bufnr = api.nvim_get_current_buf() + eq( + vim.fs.joinpath(test_source_path, 'test/functional/fixtures'), + exec_lua([[return vim.fs.root(..., {'CMakeLists.txt', '.git'})]], bufnr) + ) + end) + + it('works with a function', function() + ---@type string + local result = exec_lua([[ + return vim.fs.root(0, function(name, path) + return name:match('%.txt$') + end) + ]]) + eq(vim.fs.joinpath(test_source_path, 'test/functional/fixtures'), result) + end) + + it('works with a filename argument', function() + eq(test_source_path, exec_lua([[return vim.fs.root(..., '.git')]], nvim_prog)) + end) + + it('works with a relative path', function() + eq( + test_source_path, + exec_lua([[return vim.fs.root(..., '.git')]], vim.fs.basename(nvim_prog)) + ) + end) + + it('uses cwd for unnamed buffers', function() + command('new') + eq(test_source_path, exec_lua([[return vim.fs.root(0, '.git')]])) + end) + + it("uses cwd for buffers with non-empty 'buftype'", function() + command('new') + command('set buftype=nofile') + command('file lua://') + eq(test_source_path, exec_lua([[return vim.fs.root(0, '.git')]])) + end) + end) + describe('joinpath()', function() it('works', function() eq('foo/bar/baz', vim.fs.joinpath('foo', 'bar', 'baz')) @@ -282,9 +339,6 @@ describe('vim.fs', function() end) describe('normalize()', function() - it('works with backward slashes', function() - eq('C:/Users/jdoe', vim.fs.normalize('C:\\Users\\jdoe')) - end) it('removes trailing /', function() eq('/home/user', vim.fs.normalize('/home/user/')) end) @@ -292,7 +346,7 @@ describe('vim.fs', function() eq('/', vim.fs.normalize('/')) end) it('works with ~', function() - eq(vim.fs.normalize(vim.uv.os_homedir()) .. '/src/foo', vim.fs.normalize('~/src/foo')) + eq(vim.fs.normalize(assert(vim.uv.os_homedir())) .. '/src/foo', vim.fs.normalize('~/src/foo')) end) it('works with environment variables', function() local xdg_config_home = test_build_dir .. '/.config' @@ -307,10 +361,113 @@ describe('vim.fs', function() ) ) end) - if is_os('win') then - it('Last slash is not truncated from root drive', function() - eq('C:/', vim.fs.normalize('C:/')) + + -- Opts required for testing posix paths and win paths + local posix_opts = is_os('win') and { win = false } or {} + local win_opts = is_os('win') and {} or { win = true } + + it('preserves leading double slashes in POSIX paths', function() + eq('//foo', vim.fs.normalize('//foo', posix_opts)) + eq('//foo/bar', vim.fs.normalize('//foo//bar////', posix_opts)) + eq('/foo', vim.fs.normalize('///foo', posix_opts)) + eq('//', vim.fs.normalize('//', posix_opts)) + eq('/', vim.fs.normalize('///', posix_opts)) + eq('/foo/bar', vim.fs.normalize('/foo//bar////', posix_opts)) + end) + + it('allows backslashes on unix-based os', function() + eq('/home/user/hello\\world', vim.fs.normalize('/home/user/hello\\world', posix_opts)) + end) + + it('preserves / after drive letters', function() + eq('C:/', vim.fs.normalize([[C:\]], win_opts)) + end) + + it('works with UNC and DOS device paths', function() + eq('//server/share/foo/bar', vim.fs.normalize([[\\server\\share\\\foo\bar\\\]], win_opts)) + eq('//system07/C$/', vim.fs.normalize([[\\system07\C$\\\\]], win_opts)) + eq('//./C:/foo/bar', vim.fs.normalize([[\\.\\C:\foo\\\\bar]], win_opts)) + eq('//?/C:/foo/bar', vim.fs.normalize([[\\?\C:\\\foo\bar\\\\]], win_opts)) + eq( + '//?/UNC/server/share/foo/bar', + vim.fs.normalize([[\\?\UNC\server\\\share\\\\foo\\\bar]], win_opts) + ) + eq('//./BootPartition/foo/bar', vim.fs.normalize([[\\.\BootPartition\\foo\bar]], win_opts)) + eq( + '//./Volume{12345678-1234-1234-1234-1234567890AB}/foo/bar', + vim.fs.normalize([[\\.\Volume{12345678-1234-1234-1234-1234567890AB}\\\foo\bar\\]], win_opts) + ) + end) + + it('handles invalid UNC and DOS device paths', function() + eq('//server/share', vim.fs.normalize([[\\server\share]], win_opts)) + eq('//server/', vim.fs.normalize([[\\server\]], win_opts)) + eq('//./UNC/server/share', vim.fs.normalize([[\\.\UNC\server\share]], win_opts)) + eq('//?/UNC/server/', vim.fs.normalize([[\\?\UNC\server\]], win_opts)) + eq('//?/UNC/server/..', vim.fs.normalize([[\\?\UNC\server\..]], win_opts)) + eq('//./', vim.fs.normalize([[\\.\]], win_opts)) + eq('//./foo', vim.fs.normalize([[\\.\foo]], win_opts)) + eq('//./BootPartition', vim.fs.normalize([[\\.\BootPartition]], win_opts)) + end) + + it('converts backward slashes', function() + eq('C:/Users/jdoe', vim.fs.normalize([[C:\Users\jdoe]], win_opts)) + end) + + describe('. and .. component resolving', function() + it('works', function() + -- Windows paths + eq('C:/Users', vim.fs.normalize([[C:\Users\jdoe\Downloads\.\..\..\]], win_opts)) + eq('C:/Users/jdoe', vim.fs.normalize([[C:\Users\jdoe\Downloads\.\..\.\.\]], win_opts)) + eq('C:/', vim.fs.normalize('C:/Users/jdoe/Downloads/./../../../', win_opts)) + eq('C:foo', vim.fs.normalize([[C:foo\bar\.\..\.]], win_opts)) + -- POSIX paths + eq('/home', vim.fs.normalize('/home/jdoe/Downloads/./../..', posix_opts)) + eq('/home/jdoe', vim.fs.normalize('/home/jdoe/Downloads/./../././', posix_opts)) + eq('/', vim.fs.normalize('/home/jdoe/Downloads/./../../../', posix_opts)) + -- OS-agnostic relative paths + eq('foo/bar/baz', vim.fs.normalize('foo/bar/foobar/../baz/./')) + eq('foo/bar', vim.fs.normalize('foo/bar/foobar/../baz/./../../bar/./.')) end) - end + + it('works when relative path reaches current directory', function() + eq('C:', vim.fs.normalize('C:foo/bar/../../.', win_opts)) + + eq('.', vim.fs.normalize('.')) + eq('.', vim.fs.normalize('././././')) + eq('.', vim.fs.normalize('foo/bar/../../.')) + end) + + it('works when relative path goes outside current directory', function() + eq('../../foo/bar', vim.fs.normalize('../../foo/bar')) + eq('../foo', vim.fs.normalize('foo/bar/../../../foo')) + + eq('C:../foo', vim.fs.normalize('C:../foo', win_opts)) + eq('C:../../foo/bar', vim.fs.normalize('C:foo/../../../foo/bar', win_opts)) + end) + + it('.. in root directory resolves to itself', function() + eq('C:/', vim.fs.normalize('C:/../../', win_opts)) + eq('C:/foo', vim.fs.normalize('C:/foo/../../foo', win_opts)) + + eq('//server/share/', vim.fs.normalize([[\\server\share\..\..]], win_opts)) + eq('//server/share/foo', vim.fs.normalize([[\\server\\share\foo\..\..\foo]], win_opts)) + + eq('//./C:/', vim.fs.normalize([[\\.\C:\..\..]], win_opts)) + eq('//?/C:/foo', vim.fs.normalize([[\\?\C:\..\..\foo]], win_opts)) + + eq('//./UNC/server/share/', vim.fs.normalize([[\\.\UNC\\server\share\..\..\]], win_opts)) + eq( + '//?/UNC/server/share/foo', + vim.fs.normalize([[\\?\UNC\server\\share\..\..\foo]], win_opts) + ) + + eq('//?/BootPartition/', vim.fs.normalize([[\\?\BootPartition\..\..]], win_opts)) + eq('//./BootPartition/foo', vim.fs.normalize([[\\.\BootPartition\..\..\foo]], win_opts)) + + eq('/', vim.fs.normalize('/../../', posix_opts)) + eq('/foo', vim.fs.normalize('/foo/../../foo', posix_opts)) + end) + end) end) end) diff --git a/test/functional/lua/glob_spec.lua b/test/functional/lua/glob_spec.lua index 1eac037575..56cd4c9bb5 100644 --- a/test/functional/lua/glob_spec.lua +++ b/test/functional/lua/glob_spec.lua @@ -1,10 +1,12 @@ -local helpers = require('test.functional.helpers')(after_each) -local eq = helpers.eq -local exec_lua = helpers.exec_lua +local t = require('test.testutil') +local n = require('test.functional.testnvim')() + +local eq = t.eq +local exec_lua = n.exec_lua describe('glob', function() - before_each(helpers.clear) - after_each(helpers.clear) + before_each(n.clear) + after_each(n.clear) local match = function(...) return exec_lua( diff --git a/test/functional/lua/highlight_spec.lua b/test/functional/lua/highlight_spec.lua index 197f3139f3..c9f2d0a47f 100644 --- a/test/functional/lua/highlight_spec.lua +++ b/test/functional/lua/highlight_spec.lua @@ -1,11 +1,13 @@ -local helpers = require('test.functional.helpers')(after_each) -local exec_lua = helpers.exec_lua -local eq = helpers.eq -local neq = helpers.neq -local eval = helpers.eval -local command = helpers.command -local clear = helpers.clear -local api = helpers.api +local t = require('test.testutil') +local n = require('test.functional.testnvim')() + +local exec_lua = n.exec_lua +local eq = t.eq +local neq = t.neq +local eval = n.eval +local command = n.command +local clear = n.clear +local api = n.api describe('vim.highlight.on_yank', function() before_each(function() @@ -19,7 +21,7 @@ describe('vim.highlight.on_yank', function() vim.cmd('bwipeout!') ]]) vim.uv.sleep(10) - helpers.feed('<cr>') -- avoid hang if error message exists + n.feed('<cr>') -- avoid hang if error message exists eq('', eval('v:errmsg')) end) @@ -41,9 +43,9 @@ describe('vim.highlight.on_yank', function() vim.api.nvim_buf_set_mark(0,"]",1,1,{}) vim.highlight.on_yank({timeout = math.huge, on_macro = true, event = {operator = "y"}}) ]]) - neq({}, api.nvim_win_get_ns(0)) + neq({}, api.nvim__win_get_ns(0)) command('wincmd w') - eq({}, api.nvim_win_get_ns(0)) + eq({}, api.nvim__win_get_ns(0)) end) it('removes old highlight if new one is created before old one times out', function() @@ -53,7 +55,7 @@ describe('vim.highlight.on_yank', function() vim.api.nvim_buf_set_mark(0,"]",1,1,{}) vim.highlight.on_yank({timeout = math.huge, on_macro = true, event = {operator = "y"}}) ]]) - neq({}, api.nvim_win_get_ns(0)) + neq({}, api.nvim__win_get_ns(0)) command('wincmd w') exec_lua([[ vim.api.nvim_buf_set_mark(0,"[",1,1,{}) @@ -61,6 +63,6 @@ describe('vim.highlight.on_yank', function() vim.highlight.on_yank({timeout = math.huge, on_macro = true, event = {operator = "y"}}) ]]) command('wincmd w') - eq({}, api.nvim_win_get_ns(0)) + eq({}, api.nvim__win_get_ns(0)) end) end) diff --git a/test/functional/lua/inspector_spec.lua b/test/functional/lua/inspector_spec.lua index ad8b5a45a8..8fadba6ee8 100644 --- a/test/functional/lua/inspector_spec.lua +++ b/test/functional/lua/inspector_spec.lua @@ -1,8 +1,10 @@ -local helpers = require('test.functional.helpers')(after_each) -local exec_lua = helpers.exec_lua -local eq = helpers.eq -local eval = helpers.eval -local clear = helpers.clear +local t = require('test.testutil') +local n = require('test.functional.testnvim')() + +local exec_lua = n.exec_lua +local eq = t.eq +local eval = n.eval +local clear = n.clear describe('vim.inspect_pos', function() before_each(function() diff --git a/test/functional/lua/iter_spec.lua b/test/functional/lua/iter_spec.lua index 8d6cf1264b..79e92e6a7d 100644 --- a/test/functional/lua/iter_spec.lua +++ b/test/functional/lua/iter_spec.lua @@ -1,7 +1,8 @@ -local helpers = require('test.functional.helpers')(after_each) -local eq = helpers.eq -local matches = helpers.matches -local pcall_err = helpers.pcall_err +local t = require('test.testutil') + +local eq = t.eq +local matches = t.matches +local pcall_err = t.pcall_err describe('vim.iter', function() it('new() on iterable class instance', function() @@ -18,12 +19,12 @@ describe('vim.iter', function() return v % 2 ~= 0 end - local t = { 1, 2, 3, 4, 5 } - eq({ 1, 3, 5 }, vim.iter(t):filter(odd):totable()) + local q = { 1, 2, 3, 4, 5 } + eq({ 1, 3, 5 }, vim.iter(q):filter(odd):totable()) eq( { 2, 4 }, vim - .iter(t) + .iter(q) :filter(function(v) return not odd(v) end) @@ -32,7 +33,7 @@ describe('vim.iter', function() eq( {}, vim - .iter(t) + .iter(q) :filter(function(v) return v > 5 end) @@ -40,7 +41,7 @@ describe('vim.iter', function() ) do - local it = vim.iter(ipairs(t)) + local it = vim.iter(ipairs(q)) it:filter(function(i, v) return i > 1 and v < 5 end) @@ -60,11 +61,11 @@ describe('vim.iter', function() end) it('map()', function() - local t = { 1, 2, 3, 4, 5 } + local q = { 1, 2, 3, 4, 5 } eq( { 2, 4, 6, 8, 10 }, vim - .iter(t) + .iter(q) :map(function(v) return 2 * v end) @@ -96,10 +97,10 @@ describe('vim.iter', function() end) it('for loops', function() - local t = { 1, 2, 3, 4, 5 } + local q = { 1, 2, 3, 4, 5 } local acc = 0 for v in - vim.iter(t):map(function(v) + vim.iter(q):map(function(v) return v * 3 end) do @@ -116,6 +117,9 @@ describe('vim.iter', function() eq({ { 1, 1 }, { 2, 4 }, { 3, 9 } }, it:totable()) end + -- Holes in array-like tables are removed + eq({ 1, 2, 3 }, vim.iter({ 1, nil, 2, nil, 3 }):totable()) + do local it = vim.iter(string.gmatch('1,4,lol,17,blah,2,9,3', '%d+')):map(tonumber) eq({ 1, 4, 17, 2, 9, 3 }, it:totable()) @@ -141,18 +145,18 @@ describe('vim.iter', function() eq({ 3, 2, 1 }, vim.iter({ 1, 2, 3 }):rev():totable()) local it = vim.iter(string.gmatch('abc', '%w')) - matches('rev%(%) requires a list%-like table', pcall_err(it.rev, it)) + matches('rev%(%) requires an array%-like table', pcall_err(it.rev, it)) end) it('skip()', function() do - local t = { 4, 3, 2, 1 } - eq(t, vim.iter(t):skip(0):totable()) - eq({ 3, 2, 1 }, vim.iter(t):skip(1):totable()) - eq({ 2, 1 }, vim.iter(t):skip(2):totable()) - eq({ 1 }, vim.iter(t):skip(#t - 1):totable()) - eq({}, vim.iter(t):skip(#t):totable()) - eq({}, vim.iter(t):skip(#t + 1):totable()) + local q = { 4, 3, 2, 1 } + eq(q, vim.iter(q):skip(0):totable()) + eq({ 3, 2, 1 }, vim.iter(q):skip(1):totable()) + eq({ 2, 1 }, vim.iter(q):skip(2):totable()) + eq({ 1 }, vim.iter(q):skip(#q - 1):totable()) + eq({}, vim.iter(q):skip(#q):totable()) + eq({}, vim.iter(q):skip(#q + 1):totable()) end do @@ -168,44 +172,44 @@ describe('vim.iter', function() end end) - it('skipback()', function() + it('rskip()', function() do - local t = { 4, 3, 2, 1 } - eq(t, vim.iter(t):skipback(0):totable()) - eq({ 4, 3, 2 }, vim.iter(t):skipback(1):totable()) - eq({ 4, 3 }, vim.iter(t):skipback(2):totable()) - eq({ 4 }, vim.iter(t):skipback(#t - 1):totable()) - eq({}, vim.iter(t):skipback(#t):totable()) - eq({}, vim.iter(t):skipback(#t + 1):totable()) + local q = { 4, 3, 2, 1 } + eq(q, vim.iter(q):rskip(0):totable()) + eq({ 4, 3, 2 }, vim.iter(q):rskip(1):totable()) + eq({ 4, 3 }, vim.iter(q):rskip(2):totable()) + eq({ 4 }, vim.iter(q):rskip(#q - 1):totable()) + eq({}, vim.iter(q):rskip(#q):totable()) + eq({}, vim.iter(q):rskip(#q + 1):totable()) end local it = vim.iter(vim.gsplit('a|b|c|d', '|')) - matches('skipback%(%) requires a list%-like table', pcall_err(it.skipback, it, 0)) + matches('rskip%(%) requires an array%-like table', pcall_err(it.rskip, it, 0)) end) it('slice()', function() - local t = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 } - eq({ 3, 4, 5, 6, 7 }, vim.iter(t):slice(3, 7):totable()) - eq({}, vim.iter(t):slice(6, 5):totable()) - eq({}, vim.iter(t):slice(0, 0):totable()) - eq({ 1 }, vim.iter(t):slice(1, 1):totable()) - eq({ 1, 2 }, vim.iter(t):slice(1, 2):totable()) - eq({ 10 }, vim.iter(t):slice(10, 10):totable()) - eq({ 8, 9, 10 }, vim.iter(t):slice(8, 11):totable()) + local q = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 } + eq({ 3, 4, 5, 6, 7 }, vim.iter(q):slice(3, 7):totable()) + eq({}, vim.iter(q):slice(6, 5):totable()) + eq({}, vim.iter(q):slice(0, 0):totable()) + eq({ 1 }, vim.iter(q):slice(1, 1):totable()) + eq({ 1, 2 }, vim.iter(q):slice(1, 2):totable()) + eq({ 10 }, vim.iter(q):slice(10, 10):totable()) + eq({ 8, 9, 10 }, vim.iter(q):slice(8, 11):totable()) local it = vim.iter(vim.gsplit('a|b|c|d', '|')) - matches('slice%(%) requires a list%-like table', pcall_err(it.slice, it, 1, 3)) + matches('slice%(%) requires an array%-like table', pcall_err(it.slice, it, 1, 3)) end) it('nth()', function() do - local t = { 4, 3, 2, 1 } - eq(nil, vim.iter(t):nth(0)) - eq(4, vim.iter(t):nth(1)) - eq(3, vim.iter(t):nth(2)) - eq(2, vim.iter(t):nth(3)) - eq(1, vim.iter(t):nth(4)) - eq(nil, vim.iter(t):nth(5)) + local q = { 4, 3, 2, 1 } + eq(nil, vim.iter(q):nth(0)) + eq(4, vim.iter(q):nth(1)) + eq(3, vim.iter(q):nth(2)) + eq(2, vim.iter(q):nth(3)) + eq(1, vim.iter(q):nth(4)) + eq(nil, vim.iter(q):nth(5)) end do @@ -221,35 +225,41 @@ describe('vim.iter', function() end end) - it('nthback()', function() + it('nth(-x) advances in reverse order starting from end', function() do - local t = { 4, 3, 2, 1 } - eq(nil, vim.iter(t):nthback(0)) - eq(1, vim.iter(t):nthback(1)) - eq(2, vim.iter(t):nthback(2)) - eq(3, vim.iter(t):nthback(3)) - eq(4, vim.iter(t):nthback(4)) - eq(nil, vim.iter(t):nthback(5)) + local q = { 4, 3, 2, 1 } + eq(nil, vim.iter(q):nth(0)) + eq(1, vim.iter(q):nth(-1)) + eq(2, vim.iter(q):nth(-2)) + eq(3, vim.iter(q):nth(-3)) + eq(4, vim.iter(q):nth(-4)) + eq(nil, vim.iter(q):nth(-5)) end local it = vim.iter(vim.gsplit('a|b|c|d', '|')) - matches('skipback%(%) requires a list%-like table', pcall_err(it.nthback, it, 1)) + matches('rskip%(%) requires an array%-like table', pcall_err(it.nth, it, -1)) end) it('take()', function() do - local t = { 4, 3, 2, 1 } - eq({}, vim.iter(t):take(0):totable()) - eq({ 4 }, vim.iter(t):take(1):totable()) - eq({ 4, 3 }, vim.iter(t):take(2):totable()) - eq({ 4, 3, 2 }, vim.iter(t):take(3):totable()) - eq({ 4, 3, 2, 1 }, vim.iter(t):take(4):totable()) - eq({ 4, 3, 2, 1 }, vim.iter(t):take(5):totable()) + local q = { 4, 3, 2, 1 } + eq({}, vim.iter(q):take(0):totable()) + eq({ 4 }, vim.iter(q):take(1):totable()) + eq({ 4, 3 }, vim.iter(q):take(2):totable()) + eq({ 4, 3, 2 }, vim.iter(q):take(3):totable()) + eq({ 4, 3, 2, 1 }, vim.iter(q):take(4):totable()) + eq({ 4, 3, 2, 1 }, vim.iter(q):take(5):totable()) + end + + do + local q = { 4, 3, 2, 1 } + eq({ 1, 2, 3 }, vim.iter(q):rev():take(3):totable()) + eq({ 2, 3, 4 }, vim.iter(q):take(3):rev():totable()) end do - local t = { 4, 3, 2, 1 } - local it = vim.iter(t) + local q = { 4, 3, 2, 1 } + local it = vim.iter(q) eq({ 4, 3 }, it:take(2):totable()) -- tail is already set from the previous take() eq({ 4, 3 }, it:take(3):totable()) @@ -269,13 +279,13 @@ describe('vim.iter', function() end do - local t = { 4, 8, 9, 10 } - eq(true, vim.iter(t):any(odd)) + local q = { 4, 8, 9, 10 } + eq(true, vim.iter(q):any(odd)) end do - local t = { 4, 8, 10 } - eq(false, vim.iter(t):any(odd)) + local q = { 4, 8, 10 } + eq(false, vim.iter(q):any(odd)) end do @@ -300,13 +310,13 @@ describe('vim.iter', function() end do - local t = { 3, 5, 7, 9 } - eq(true, vim.iter(t):all(odd)) + local q = { 3, 5, 7, 9 } + eq(true, vim.iter(q):all(odd)) end do - local t = { 3, 5, 7, 10 } - eq(false, vim.iter(t):all(odd)) + local q = { 3, 5, 7, 10 } + eq(false, vim.iter(q):all(odd)) end do @@ -349,23 +359,23 @@ describe('vim.iter', function() do local it = vim.iter(vim.gsplit('hi', '')) - matches('peek%(%) requires a list%-like table', pcall_err(it.peek, it)) + matches('peek%(%) requires an array%-like table', pcall_err(it.peek, it)) end end) it('find()', function() - local t = { 3, 6, 9, 12 } - eq(12, vim.iter(t):find(12)) - eq(nil, vim.iter(t):find(15)) + local q = { 3, 6, 9, 12 } + eq(12, vim.iter(q):find(12)) + eq(nil, vim.iter(q):find(15)) eq( 12, - vim.iter(t):find(function(v) + vim.iter(q):find(function(v) return v % 4 == 0 end) ) do - local it = vim.iter(t) + local it = vim.iter(q) local pred = function(v) return v % 3 == 0 end @@ -389,16 +399,16 @@ describe('vim.iter', function() end) it('rfind()', function() - local t = { 1, 2, 3, 2, 1 } + local q = { 1, 2, 3, 2, 1 } do - local it = vim.iter(t) + local it = vim.iter(q) eq(1, it:rfind(1)) eq(1, it:rfind(1)) eq(nil, it:rfind(1)) end do - local it = vim.iter(t):enumerate() + local it = vim.iter(q):enumerate() local pred = function(i) return i % 2 ~= 0 end @@ -410,52 +420,52 @@ describe('vim.iter', function() do local it = vim.iter(vim.gsplit('AbCdE', '')) - matches('rfind%(%) requires a list%-like table', pcall_err(it.rfind, it, 'E')) + matches('rfind%(%) requires an array%-like table', pcall_err(it.rfind, it, 'E')) end end) - it('nextback()', function() + it('pop()', function() do local it = vim.iter({ 1, 2, 3, 4 }) - eq(4, it:nextback()) - eq(3, it:nextback()) - eq(2, it:nextback()) - eq(1, it:nextback()) - eq(nil, it:nextback()) - eq(nil, it:nextback()) + eq(4, it:pop()) + eq(3, it:pop()) + eq(2, it:pop()) + eq(1, it:pop()) + eq(nil, it:pop()) + eq(nil, it:pop()) end do local it = vim.iter(vim.gsplit('hi', '')) - matches('nextback%(%) requires a list%-like table', pcall_err(it.nextback, it)) + matches('pop%(%) requires an array%-like table', pcall_err(it.pop, it)) end end) - it('peekback()', function() + it('rpeek()', function() do local it = vim.iter({ 1, 2, 3, 4 }) - eq(4, it:peekback()) - eq(4, it:peekback()) - eq(4, it:nextback()) + eq(4, it:rpeek()) + eq(4, it:rpeek()) + eq(4, it:pop()) end do local it = vim.iter(vim.gsplit('hi', '')) - matches('peekback%(%) requires a list%-like table', pcall_err(it.peekback, it)) + matches('rpeek%(%) requires an array%-like table', pcall_err(it.rpeek, it)) end end) it('fold()', function() - local t = { 1, 2, 3, 4, 5 } + local q = { 1, 2, 3, 4, 5 } eq( 115, - vim.iter(t):fold(100, function(acc, v) + vim.iter(q):fold(100, function(acc, v) return acc + v end) ) eq( { 5, 4, 3, 2, 1 }, - vim.iter(t):fold({}, function(acc, v) + vim.iter(q):fold({}, function(acc, v) table.insert(acc, 1, v) return acc end) @@ -463,30 +473,32 @@ describe('vim.iter', function() end) it('flatten()', function() - local t = { { 1, { 2 } }, { { { { 3 } } }, { 4 } }, { 5 } } + local q = { { 1, { 2 } }, { { { { 3 } } }, { 4 } }, { 5 } } - eq(t, vim.iter(t):flatten(-1):totable()) - eq(t, vim.iter(t):flatten(0):totable()) - eq({ 1, { 2 }, { { { 3 } } }, { 4 }, 5 }, vim.iter(t):flatten():totable()) - eq({ 1, 2, { { 3 } }, 4, 5 }, vim.iter(t):flatten(2):totable()) - eq({ 1, 2, { 3 }, 4, 5 }, vim.iter(t):flatten(3):totable()) - eq({ 1, 2, 3, 4, 5 }, vim.iter(t):flatten(4):totable()) + eq(q, vim.iter(q):flatten(-1):totable()) + eq(q, vim.iter(q):flatten(0):totable()) + eq({ 1, { 2 }, { { { 3 } } }, { 4 }, 5 }, vim.iter(q):flatten():totable()) + eq({ 1, 2, { { 3 } }, 4, 5 }, vim.iter(q):flatten(2):totable()) + eq({ 1, 2, { 3 }, 4, 5 }, vim.iter(q):flatten(3):totable()) + eq({ 1, 2, 3, 4, 5 }, vim.iter(q):flatten(4):totable()) local m = { a = 1, b = { 2, 3 }, d = { 4 } } local it = vim.iter(m) - local flat_err = 'flatten%(%) requires a list%-like table' + local flat_err = 'flatten%(%) requires an array%-like table' matches(flat_err, pcall_err(it.flatten, it)) -- cases from the documentation local simple_example = { 1, { 2 }, { { 3 } } } eq({ 1, 2, { 3 } }, vim.iter(simple_example):flatten():totable()) - local not_list_like = vim.iter({ [2] = 2 }) - matches(flat_err, pcall_err(not_list_like.flatten, not_list_like)) + local not_list_like = { [2] = 2 } + eq({ 2 }, vim.iter(not_list_like):flatten():totable()) + + local also_not_list_like = { nil, 2 } + eq({ 2 }, vim.iter(also_not_list_like):flatten():totable()) - local also_not_list_like = vim.iter({ nil, 2 }) - matches(flat_err, pcall_err(not_list_like.flatten, also_not_list_like)) + eq({ 1, 2, 3 }, vim.iter({ nil, { 1, nil, 2 }, 3 }):flatten():totable()) local nested_non_lists = vim.iter({ 1, { { a = 2 } }, { { nil } }, { 3 } }) eq({ 1, { a = 2 }, { nil }, 3 }, nested_non_lists:flatten():totable()) @@ -501,11 +513,11 @@ describe('vim.iter', function() end end) - local t = it:fold({}, function(t, k, v) - t[k] = v - return t + local q = it:fold({}, function(q, k, v) + q[k] = v + return q end) - eq({ A = 2, C = 6 }, t) + eq({ A = 2, C = 6 }, q) end) it('handles table values mid-pipeline', function() diff --git a/test/functional/lua/json_spec.lua b/test/functional/lua/json_spec.lua index d348e2de3c..a6e814d739 100644 --- a/test/functional/lua/json_spec.lua +++ b/test/functional/lua/json_spec.lua @@ -1,8 +1,10 @@ -local helpers = require('test.functional.helpers')(after_each) -local clear = helpers.clear -local exec_lua = helpers.exec_lua -local eq = helpers.eq -local pcall_err = helpers.pcall_err +local t = require('test.testutil') +local n = require('test.functional.testnvim')() + +local clear = n.clear +local exec_lua = n.exec_lua +local eq = t.eq +local pcall_err = t.pcall_err describe('vim.json.decode()', function() before_each(function() @@ -30,6 +32,18 @@ describe('vim.json.decode()', function() baz = vim.NIL, foo = { a = 'b' }, }, exec_lua([[return vim.json.decode(..., {})]], jsonstr)) + eq( + { + arr = { 1, 2, vim.NIL }, + bar = { 3, 7 }, + baz = vim.NIL, + foo = { a = 'b' }, + }, + exec_lua( + [[return vim.json.decode(..., { luanil = { array = false, object = false } })]], + jsonstr + ) + ) eq({ arr = { 1, 2, vim.NIL }, bar = { 3, 7 }, diff --git a/test/functional/lua/loader_spec.lua b/test/functional/lua/loader_spec.lua index 4e42a18405..f13e6664c5 100644 --- a/test/functional/lua/loader_spec.lua +++ b/test/functional/lua/loader_spec.lua @@ -1,10 +1,11 @@ -- Test suite for testing interactions with API bindings -local helpers = require('test.functional.helpers')(after_each) +local t = require('test.testutil') +local n = require('test.functional.testnvim')() -local exec_lua = helpers.exec_lua -local command = helpers.command -local clear = helpers.clear -local eq = helpers.eq +local exec_lua = n.exec_lua +local command = n.command +local clear = n.clear +local eq = t.eq describe('vim.loader', function() before_each(clear) @@ -35,7 +36,7 @@ describe('vim.loader', function() vim.loader.enable() ]] - local tmp = helpers.tmpname() + local tmp = t.tmpname() command('edit ' .. tmp) eq( @@ -73,15 +74,15 @@ describe('vim.loader', function() vim.loader.enable() ]] - local tmp1, tmp2 = (function(t) - assert(os.remove(t)) - assert(helpers.mkdir(t)) - assert(helpers.mkdir(t .. '/%')) - return t .. '/%/x', t .. '/%%x' - end)(helpers.tmpname()) + local tmp = t.tmpname() + assert(os.remove(tmp)) + assert(t.mkdir(tmp)) + assert(t.mkdir(tmp .. '/%')) + local tmp1 = tmp .. '/%/x' + local tmp2 = tmp .. '/%%x' - helpers.write_file(tmp1, 'return 1', true) - helpers.write_file(tmp2, 'return 2', true) + t.write_file(tmp1, 'return 1', true) + t.write_file(tmp2, 'return 2', true) vim.uv.fs_utime(tmp1, 0, 0) vim.uv.fs_utime(tmp2, 0, 0) eq(1, exec_lua('return loadfile(...)()', tmp1)) diff --git a/test/functional/lua/loop_spec.lua b/test/functional/lua/loop_spec.lua index 71eaf29009..566a171a84 100644 --- a/test/functional/lua/loop_spec.lua +++ b/test/functional/lua/loop_spec.lua @@ -1,16 +1,18 @@ -- Test suite for testing interactions with API bindings -local helpers = require('test.functional.helpers')(after_each) +local t = require('test.testutil') +local n = require('test.functional.testnvim')() local Screen = require('test.functional.ui.screen') -local fn = helpers.fn -local api = helpers.api -local clear = helpers.clear + +local fn = n.fn +local api = n.api +local clear = n.clear local sleep = vim.uv.sleep -local feed = helpers.feed -local eq = helpers.eq -local eval = helpers.eval -local matches = helpers.matches -local exec_lua = helpers.exec_lua -local retry = helpers.retry +local feed = n.feed +local eq = t.eq +local eval = n.eval +local matches = t.matches +local exec_lua = n.exec_lua +local retry = t.retry before_each(clear) @@ -131,6 +133,20 @@ describe('vim.uv', function() {5:-- INSERT --} | ]]) eq({ blocking = false, mode = 'n' }, exec_lua('return _G.mode')) + + exec_lua([[ + local timer = vim.uv.new_timer() + timer:start(20, 0, function () + _G.is_fast = vim.in_fast_event() + timer:close() + _G.value = vim.fn.has("nvim-0.5") + _G.unvalue = vim.fn.has("python3") + end) + ]]) + + screen:expect({ any = [[{3:Vim:E5560: Vimscript function must not be called i}]] }) + feed('<cr>') + eq({ 1, nil }, exec_lua('return {_G.value, _G.unvalue}')) end) it("is equal to require('luv')", function() diff --git a/test/functional/lua/luaeval_spec.lua b/test/functional/lua/luaeval_spec.lua index b28cfa4dd2..3f62cd8325 100644 --- a/test/functional/lua/luaeval_spec.lua +++ b/test/functional/lua/luaeval_spec.lua @@ -1,19 +1,20 @@ -- Test suite for testing luaeval() function -local helpers = require('test.functional.helpers')(after_each) +local t = require('test.testutil') +local n = require('test.functional.testnvim')() local Screen = require('test.functional.ui.screen') -local pcall_err = helpers.pcall_err -local exc_exec = helpers.exc_exec -local remove_trace = helpers.remove_trace -local exec_lua = helpers.exec_lua -local command = helpers.command -local api = helpers.api -local fn = helpers.fn -local clear = helpers.clear -local eval = helpers.eval -local feed = helpers.feed +local pcall_err = t.pcall_err +local exc_exec = n.exc_exec +local remove_trace = t.remove_trace +local exec_lua = n.exec_lua +local command = n.command +local api = n.api +local fn = n.fn +local clear = n.clear +local eval = n.eval +local feed = n.feed local NIL = vim.NIL -local eq = helpers.eq +local eq = t.eq before_each(clear) @@ -38,8 +39,8 @@ describe('luaeval()', function() describe('second argument', function() it('is successfully received', function() - local t = {t=true, f=false, --[[n=NIL,]] d={l={'string', 42, 0.42}}} - eq(t, fn.luaeval("_A", t)) + local q = {t=true, f=false, --[[n=NIL,]] d={l={'string', 42, 0.42}}} + eq(q, fn.luaeval("_A", q)) -- Not tested: nil, funcrefs, returned object identity: behaviour will -- most likely change. end) diff --git a/test/functional/lua/mpack_spec.lua b/test/functional/lua/mpack_spec.lua index 0b6a6d60bd..efd69d4607 100644 --- a/test/functional/lua/mpack_spec.lua +++ b/test/functional/lua/mpack_spec.lua @@ -1,9 +1,10 @@ -- Test suite for testing interactions with API bindings -local helpers = require('test.functional.helpers')(after_each) +local t = require('test.testutil') +local n = require('test.functional.testnvim')() -local clear = helpers.clear -local eq = helpers.eq -local exec_lua = helpers.exec_lua +local clear = n.clear +local eq = t.eq +local exec_lua = n.exec_lua describe('lua vim.mpack', function() before_each(clear) @@ -22,7 +23,7 @@ describe('lua vim.mpack', function() { { {}, 'foo', {} }, true, false }, exec_lua [[ local var = vim.mpack.decode(vim.mpack.encode({{}, "foo", vim.empty_dict()})) - return {var, vim.tbl_islist(var[1]), vim.tbl_islist(var[3])} + return {var, vim.islist(var[1]), vim.islist(var[3])} ]] ) end) diff --git a/test/functional/lua/overrides_spec.lua b/test/functional/lua/overrides_spec.lua index ecbdde3bfd..849978f080 100644 --- a/test/functional/lua/overrides_spec.lua +++ b/test/functional/lua/overrides_spec.lua @@ -1,19 +1,20 @@ -- Test for Vim overrides of lua built-ins -local helpers = require('test.functional.helpers')(after_each) +local t = require('test.testutil') +local n = require('test.functional.testnvim')() local Screen = require('test.functional.ui.screen') -local eq = helpers.eq +local eq = t.eq local NIL = vim.NIL -local feed = helpers.feed -local clear = helpers.clear -local fn = helpers.fn -local api = helpers.api -local command = helpers.command -local write_file = helpers.write_file -local exec_capture = helpers.exec_capture -local exec_lua = helpers.exec_lua -local pcall_err = helpers.pcall_err -local is_os = helpers.is_os +local feed = n.feed +local clear = n.clear +local fn = n.fn +local api = n.api +local command = n.command +local write_file = t.write_file +local exec_capture = n.exec_capture +local exec_lua = n.exec_lua +local pcall_err = t.pcall_err +local is_os = t.is_os local fname = 'Xtest-functional-lua-overrides-luafile' @@ -195,7 +196,7 @@ describe('print', function() end) describe('debug.debug', function() - local screen + local screen --- @type test.functional.ui.screen before_each(function() screen = Screen.new() diff --git a/test/functional/lua/runtime_spec.lua b/test/functional/lua/runtime_spec.lua index 6f36ccfb9e..4adce42c3e 100644 --- a/test/functional/lua/runtime_spec.lua +++ b/test/functional/lua/runtime_spec.lua @@ -1,17 +1,18 @@ -local helpers = require('test.functional.helpers')(after_each) - -local clear = helpers.clear -local eq = helpers.eq -local eval = helpers.eval -local exec = helpers.exec -local fn = helpers.fn -local mkdir_p = helpers.mkdir_p -local rmdir = helpers.rmdir -local write_file = helpers.write_file +local t = require('test.testutil') +local n = require('test.functional.testnvim')() + +local clear = n.clear +local eq = t.eq +local eval = n.eval +local exec = n.exec +local fn = n.fn +local mkdir_p = n.mkdir_p +local rmdir = n.rmdir +local write_file = t.write_file describe('runtime:', function() local plug_dir = 'Test_Plugin' - local sep = helpers.get_pathsep() + local sep = n.get_pathsep() local init = 'dummy_init.lua' setup(function() diff --git a/test/functional/lua/secure_spec.lua b/test/functional/lua/secure_spec.lua index 7aed711b23..c58fd689b7 100644 --- a/test/functional/lua/secure_spec.lua +++ b/test/functional/lua/secure_spec.lua @@ -1,18 +1,21 @@ -local helpers = require('test.functional.helpers')(after_each) +local t = require('test.testutil') +local n = require('test.functional.testnvim')() local Screen = require('test.functional.ui.screen') -local eq = helpers.eq -local clear = helpers.clear -local command = helpers.command -local pathsep = helpers.get_pathsep() -local is_os = helpers.is_os -local api = helpers.api -local exec_lua = helpers.exec_lua -local feed_command = helpers.feed_command -local feed = helpers.feed -local fn = helpers.fn -local pcall_err = helpers.pcall_err -local matches = helpers.matches +local eq = t.eq +local clear = n.clear +local command = n.command +local pathsep = n.get_pathsep() +local is_os = t.is_os +local api = n.api +local exec_lua = n.exec_lua +local feed_command = n.feed_command +local feed = n.feed +local fn = n.fn +local stdpath = fn.stdpath +local pcall_err = t.pcall_err +local matches = t.matches +local read_file = t.read_file describe('vim.secure', function() describe('read()', function() @@ -20,8 +23,8 @@ describe('vim.secure', function() setup(function() clear { env = { XDG_STATE_HOME = xstate } } - helpers.mkdir_p(xstate .. pathsep .. (is_os('win') and 'nvim-data' or 'nvim')) - helpers.write_file( + n.mkdir_p(xstate .. pathsep .. (is_os('win') and 'nvim-data' or 'nvim')) + t.write_file( 'Xfile', [[ let g:foobar = 42 @@ -31,7 +34,7 @@ describe('vim.secure', function() teardown(function() os.remove('Xfile') - helpers.rmdir(xstate) + n.rmdir(xstate) end) it('works', function() @@ -71,11 +74,11 @@ describe('vim.secure', function() ]], } - local trust = helpers.read_file(fn.stdpath('state') .. pathsep .. 'trust') + local trust = read_file(stdpath('state') .. pathsep .. 'trust') eq(string.format('! %s', cwd .. pathsep .. 'Xfile'), vim.trim(trust)) eq(vim.NIL, exec_lua([[return vim.secure.read('Xfile')]])) - os.remove(fn.stdpath('state') .. pathsep .. 'trust') + os.remove(stdpath('state') .. pathsep .. 'trust') feed_command([[lua vim.secure.read('Xfile')]]) screen:expect { @@ -100,12 +103,12 @@ describe('vim.secure', function() ]], } - local hash = fn.sha256(helpers.read_file('Xfile')) - trust = helpers.read_file(fn.stdpath('state') .. pathsep .. 'trust') + local hash = fn.sha256(read_file('Xfile')) + trust = read_file(stdpath('state') .. pathsep .. 'trust') eq(string.format('%s %s', hash, cwd .. pathsep .. 'Xfile'), vim.trim(trust)) eq(vim.NIL, exec_lua([[vim.secure.read('Xfile')]])) - os.remove(fn.stdpath('state') .. pathsep .. 'trust') + os.remove(stdpath('state') .. pathsep .. 'trust') feed_command([[lua vim.secure.read('Xfile')]]) screen:expect { @@ -131,7 +134,7 @@ describe('vim.secure', function() } -- Trust database is not updated - trust = helpers.read_file(fn.stdpath('state') .. pathsep .. 'trust') + trust = read_file(stdpath('state') .. pathsep .. 'trust') eq(nil, trust) feed_command([[lua vim.secure.read('Xfile')]]) @@ -165,7 +168,7 @@ describe('vim.secure', function() } -- Trust database is not updated - trust = helpers.read_file(fn.stdpath('state') .. pathsep .. 'trust') + trust = read_file(stdpath('state') .. pathsep .. 'trust') eq(nil, trust) -- Cannot write file @@ -179,15 +182,15 @@ describe('vim.secure', function() setup(function() clear { env = { XDG_STATE_HOME = xstate } } - helpers.mkdir_p(xstate .. pathsep .. (is_os('win') and 'nvim-data' or 'nvim')) + n.mkdir_p(xstate .. pathsep .. (is_os('win') and 'nvim-data' or 'nvim')) end) teardown(function() - helpers.rmdir(xstate) + n.rmdir(xstate) end) before_each(function() - helpers.write_file('test_file', 'test') + t.write_file('test_file', 'test') end) after_each(function() @@ -210,70 +213,70 @@ describe('vim.secure', function() it('trust then deny then remove a file using bufnr', function() local cwd = fn.getcwd() - local hash = fn.sha256(helpers.read_file('test_file')) + local hash = fn.sha256(read_file('test_file')) local full_path = cwd .. pathsep .. 'test_file' command('edit test_file') eq({ true, full_path }, exec_lua([[return {vim.secure.trust({action='allow', bufnr=0})}]])) - local trust = helpers.read_file(fn.stdpath('state') .. pathsep .. 'trust') + local trust = read_file(stdpath('state') .. pathsep .. 'trust') eq(string.format('%s %s', hash, full_path), vim.trim(trust)) eq({ true, full_path }, exec_lua([[return {vim.secure.trust({action='deny', bufnr=0})}]])) - trust = helpers.read_file(fn.stdpath('state') .. pathsep .. 'trust') + trust = read_file(stdpath('state') .. pathsep .. 'trust') eq(string.format('! %s', full_path), vim.trim(trust)) eq({ true, full_path }, exec_lua([[return {vim.secure.trust({action='remove', bufnr=0})}]])) - trust = helpers.read_file(fn.stdpath('state') .. pathsep .. 'trust') + trust = read_file(stdpath('state') .. pathsep .. 'trust') eq('', vim.trim(trust)) end) it('deny then trust then remove a file using bufnr', function() local cwd = fn.getcwd() - local hash = fn.sha256(helpers.read_file('test_file')) + local hash = fn.sha256(read_file('test_file')) local full_path = cwd .. pathsep .. 'test_file' command('edit test_file') eq({ true, full_path }, exec_lua([[return {vim.secure.trust({action='deny', bufnr=0})}]])) - local trust = helpers.read_file(fn.stdpath('state') .. pathsep .. 'trust') + local trust = read_file(stdpath('state') .. pathsep .. 'trust') eq(string.format('! %s', full_path), vim.trim(trust)) eq({ true, full_path }, exec_lua([[return {vim.secure.trust({action='allow', bufnr=0})}]])) - trust = helpers.read_file(fn.stdpath('state') .. pathsep .. 'trust') + trust = read_file(stdpath('state') .. pathsep .. 'trust') eq(string.format('%s %s', hash, full_path), vim.trim(trust)) eq({ true, full_path }, exec_lua([[return {vim.secure.trust({action='remove', bufnr=0})}]])) - trust = helpers.read_file(fn.stdpath('state') .. pathsep .. 'trust') + trust = read_file(stdpath('state') .. pathsep .. 'trust') eq('', vim.trim(trust)) end) it('trust using bufnr then deny then remove a file using path', function() local cwd = fn.getcwd() - local hash = fn.sha256(helpers.read_file('test_file')) + local hash = fn.sha256(read_file('test_file')) local full_path = cwd .. pathsep .. 'test_file' command('edit test_file') eq({ true, full_path }, exec_lua([[return {vim.secure.trust({action='allow', bufnr=0})}]])) - local trust = helpers.read_file(fn.stdpath('state') .. pathsep .. 'trust') + local trust = read_file(stdpath('state') .. pathsep .. 'trust') eq(string.format('%s %s', hash, full_path), vim.trim(trust)) eq( { true, full_path }, exec_lua([[return {vim.secure.trust({action='deny', path='test_file'})}]]) ) - trust = helpers.read_file(fn.stdpath('state') .. pathsep .. 'trust') + trust = read_file(stdpath('state') .. pathsep .. 'trust') eq(string.format('! %s', full_path), vim.trim(trust)) eq( { true, full_path }, exec_lua([[return {vim.secure.trust({action='remove', path='test_file'})}]]) ) - trust = helpers.read_file(fn.stdpath('state') .. pathsep .. 'trust') + trust = read_file(stdpath('state') .. pathsep .. 'trust') eq('', vim.trim(trust)) end) it('deny then trust then remove a file using bufnr', function() local cwd = fn.getcwd() - local hash = fn.sha256(helpers.read_file('test_file')) + local hash = fn.sha256(read_file('test_file')) local full_path = cwd .. pathsep .. 'test_file' command('edit test_file') @@ -281,18 +284,18 @@ describe('vim.secure', function() { true, full_path }, exec_lua([[return {vim.secure.trust({action='deny', path='test_file'})}]]) ) - local trust = helpers.read_file(fn.stdpath('state') .. pathsep .. 'trust') + local trust = read_file(stdpath('state') .. pathsep .. 'trust') eq(string.format('! %s', full_path), vim.trim(trust)) eq({ true, full_path }, exec_lua([[return {vim.secure.trust({action='allow', bufnr=0})}]])) - trust = helpers.read_file(fn.stdpath('state') .. pathsep .. 'trust') + trust = read_file(stdpath('state') .. pathsep .. 'trust') eq(string.format('%s %s', hash, full_path), vim.trim(trust)) eq( { true, full_path }, exec_lua([[return {vim.secure.trust({action='remove', path='test_file'})}]]) ) - trust = helpers.read_file(fn.stdpath('state') .. pathsep .. 'trust') + trust = read_file(stdpath('state') .. pathsep .. 'trust') eq('', vim.trim(trust)) end) diff --git a/test/functional/lua/snippet_spec.lua b/test/functional/lua/snippet_spec.lua index e981bc6261..413aa93994 100644 --- a/test/functional/lua/snippet_spec.lua +++ b/test/functional/lua/snippet_spec.lua @@ -1,15 +1,17 @@ -local helpers = require('test.functional.helpers')(after_each) - -local buf_lines = helpers.buf_lines -local clear = helpers.clear -local eq = helpers.eq -local exec_lua = helpers.exec_lua -local feed = helpers.feed -local fn = helpers.fn -local matches = helpers.matches -local pcall_err = helpers.pcall_err -local poke_eventloop = helpers.poke_eventloop -local retry = helpers.retry +local t = require('test.testutil') +local n = require('test.functional.testnvim')() + +local buf_lines = n.buf_lines +local clear = n.clear +local eq = t.eq +local exec_lua = n.exec_lua +local feed = n.feed +local api = n.api +local fn = n.fn +local matches = t.matches +local pcall_err = t.pcall_err +local poke_eventloop = n.poke_eventloop +local retry = t.retry describe('vim.snippet', function() before_each(function() @@ -95,9 +97,9 @@ describe('vim.snippet', function() it('does not jump outside snippet range', function() test_expand_success({ 'function $1($2)', ' $0', 'end' }, { 'function ()', ' ', 'end' }) - eq(false, exec_lua('return vim.snippet.jumpable(-1)')) + eq(false, exec_lua('return vim.snippet.active({ direction = -1 })')) feed('<Tab><Tab>i') - eq(false, exec_lua('return vim.snippet.jumpable(1)')) + eq(false, exec_lua('return vim.snippet.active( { direction = 1 })')) end) it('navigates backwards', function() @@ -230,7 +232,7 @@ describe('vim.snippet', function() end) it('updates snippet state when built-in completion menu is visible', function() - test_expand_success({ '$1 = function($2)\n$3\nend' }, { ' = function()', '', 'end' }) + test_expand_success({ '$1 = function($2)\nend' }, { ' = function()', 'end' }) -- Show the completion menu. feed('<C-n>') -- Make sure no item is selected. @@ -238,6 +240,50 @@ describe('vim.snippet', function() -- Jump forward (the 2nd tabstop). exec_lua('vim.snippet.jump(1)') feed('foo') - eq({ ' = function(foo)', '', 'end' }, buf_lines(0)) + eq({ ' = function(foo)', 'end' }, buf_lines(0)) + end) + + it('correctly indents with newlines', function() + local curbuf = api.nvim_get_current_buf() + test_expand_success( + { 'function($2)\n\t$3\nend' }, + { 'function()', ' ', 'end' }, + [[ + vim.opt.sw = 2 + vim.opt.expandtab = true + ]] + ) + api.nvim_buf_set_lines(curbuf, 0, -1, false, {}) + test_expand_success( + { 'function($2)\n$3\nend' }, + { 'function()', '', 'end' }, + [[ + vim.opt.sw = 2 + vim.opt.expandtab = true + ]] + ) + api.nvim_buf_set_lines(curbuf, 0, -1, false, {}) + test_expand_success( + { 'func main() {\n\t$1\n}' }, + { 'func main() {', '\t', '}' }, + [[ + vim.opt.sw = 4 + vim.opt.ts = 4 + vim.opt.expandtab = false + ]] + ) + api.nvim_buf_set_lines(curbuf, 0, -1, false, {}) + test_expand_success( + { '${1:name} :: ${2}\n${1:name} ${3}= ${0:undefined}' }, + { + 'name :: ', + 'name = undefined', + }, + [[ + vim.opt.sw = 4 + vim.opt.ts = 4 + vim.opt.expandtab = false + ]] + ) end) end) diff --git a/test/functional/lua/spell_spec.lua b/test/functional/lua/spell_spec.lua index e82dd7b4a0..af7d08b390 100644 --- a/test/functional/lua/spell_spec.lua +++ b/test/functional/lua/spell_spec.lua @@ -1,8 +1,10 @@ -local helpers = require('test.functional.helpers')(after_each) -local clear = helpers.clear -local exec_lua = helpers.exec_lua -local eq = helpers.eq -local pcall_err = helpers.pcall_err +local t = require('test.testutil') +local n = require('test.functional.testnvim')() + +local clear = n.clear +local exec_lua = n.exec_lua +local eq = t.eq +local pcall_err = t.pcall_err describe('vim.spell', function() before_each(function() diff --git a/test/functional/lua/system_spec.lua b/test/functional/lua/system_spec.lua index cb561f0771..e72a009d2e 100644 --- a/test/functional/lua/system_spec.lua +++ b/test/functional/lua/system_spec.lua @@ -1,7 +1,9 @@ -local helpers = require('test.functional.helpers')(after_each) -local clear = helpers.clear -local exec_lua = helpers.exec_lua -local eq = helpers.eq +local t = require('test.testutil') +local n = require('test.functional.testnvim')() + +local clear = n.clear +local exec_lua = n.exec_lua +local eq = t.eq local function system_sync(cmd, opts) return exec_lua( diff --git a/test/functional/lua/text_spec.lua b/test/functional/lua/text_spec.lua index e31aa63768..9e77953c8c 100644 --- a/test/functional/lua/text_spec.lua +++ b/test/functional/lua/text_spec.lua @@ -1,6 +1,8 @@ -local helpers = require('test.functional.helpers')(after_each) -local clear = helpers.clear -local eq = helpers.eq +local t = require('test.testutil') +local n = require('test.functional.testnvim')() + +local clear = n.clear +local eq = t.eq describe('vim.text', function() before_each(clear) diff --git a/test/functional/lua/thread_spec.lua b/test/functional/lua/thread_spec.lua index c1981e19d4..780057b580 100644 --- a/test/functional/lua/thread_spec.lua +++ b/test/functional/lua/thread_spec.lua @@ -1,13 +1,15 @@ -local helpers = require('test.functional.helpers')(after_each) +local t = require('test.testutil') +local n = require('test.functional.testnvim')() local Screen = require('test.functional.ui.screen') -local assert_alive = helpers.assert_alive -local clear = helpers.clear -local feed = helpers.feed -local eq = helpers.eq -local exec_lua = helpers.exec_lua -local next_msg = helpers.next_msg + +local assert_alive = n.assert_alive +local clear = n.clear +local feed = n.feed +local eq = t.eq +local exec_lua = n.exec_lua +local next_msg = n.next_msg local NIL = vim.NIL -local pcall_err = helpers.pcall_err +local pcall_err = t.pcall_err describe('thread', function() local screen @@ -166,7 +168,7 @@ describe('thread', function() ]] local msg = next_msg() - eq(msg[1], 'notification') + eq('notification', msg[1]) assert(tonumber(msg[2]) >= 72961) end) @@ -327,7 +329,7 @@ describe('threadpool', function() ]] local msg = next_msg() - eq(msg[1], 'notification') + eq('notification', msg[1]) assert(tonumber(msg[2]) >= 72961) end) diff --git a/test/functional/lua/ui_event_spec.lua b/test/functional/lua/ui_event_spec.lua index 3e46018682..1e80c88403 100644 --- a/test/functional/lua/ui_event_spec.lua +++ b/test/functional/lua/ui_event_spec.lua @@ -1,10 +1,16 @@ -local helpers = require('test.functional.helpers')(after_each) +local t = require('test.testutil') +local n = require('test.functional.testnvim')() local Screen = require('test.functional.ui.screen') -local eq = helpers.eq -local exec_lua = helpers.exec_lua -local clear = helpers.clear -local feed = helpers.feed -local fn = helpers.fn + +local eq = t.eq +local exec_lua = n.exec_lua +local clear = n.clear +local feed = n.feed +local fn = n.fn +local assert_log = t.assert_log +local check_close = n.check_close + +local testlog = 'Xtest_lua_ui_event_log' describe('vim.ui_attach', function() local screen @@ -108,7 +114,7 @@ describe('vim.ui_attach', function() it('does not crash on exit', function() fn.system({ - helpers.nvim_prog, + n.nvim_prog, '-u', 'NONE', '-i', @@ -120,7 +126,7 @@ describe('vim.ui_attach', function() '--cmd', 'quitall!', }) - eq(0, helpers.eval('v:shell_error')) + eq(0, n.eval('v:shell_error')) end) it('can receive accurate message kinds even if they are history', function() @@ -149,4 +155,56 @@ describe('vim.ui_attach', function() }, }, actual, vim.inspect(actual)) end) + + it('ui_refresh() activates correct capabilities without remote UI', function() + screen:detach() + exec_lua('vim.ui_attach(ns, { ext_cmdline = true }, on_event)') + eq(1, n.api.nvim_get_option_value('cmdheight', {})) + exec_lua('vim.ui_detach(ns)') + exec_lua('vim.ui_attach(ns, { ext_messages = true }, on_event)') + n.api.nvim_set_option_value('cmdheight', 1, {}) + screen:attach() + eq(1, n.api.nvim_get_option_value('cmdheight', {})) + end) + + it("ui_refresh() sets 'cmdheight' for all open tabpages with ext_messages", function() + exec_lua('vim.cmd.tabnew()') + exec_lua('vim.ui_attach(ns, { ext_messages = true }, on_event)') + exec_lua('vim.cmd.tabnext()') + eq(0, n.api.nvim_get_option_value('cmdheight', {})) + end) + + it('avoids recursive flushing and invalid memory access with :redraw', function() + exec_lua([[ + _G.cmdline = 0 + vim.ui_attach(ns, { ext_messages = true }, function(ev) + vim.cmd.redraw() + _G.cmdline = _G.cmdline + (ev == 'cmdline_show' and 1 or 0) + end + )]]) + feed(':') + eq(1, exec_lua('return _G.cmdline')) + n.assert_alive() + feed('version<CR><CR>v<Esc>') + n.assert_alive() + end) +end) + +describe('vim.ui_attach', function() + after_each(function() + check_close() + os.remove(testlog) + end) + + it('error in callback is logged', function() + clear({ env = { NVIM_LOG_FILE = testlog } }) + local screen = Screen.new() + screen:attach() + exec_lua([[ + local ns = vim.api.nvim_create_namespace('testspace') + vim.ui_attach(ns, { ext_popupmenu = true }, function() error(42) end) + ]]) + feed('ifoo<CR>foobar<CR>fo<C-X><C-N>') + assert_log('Error executing UI event callback: Error executing lua: .*: 42', testlog, 100) + end) end) diff --git a/test/functional/lua/ui_spec.lua b/test/functional/lua/ui_spec.lua index e769843b19..d69e893c96 100644 --- a/test/functional/lua/ui_spec.lua +++ b/test/functional/lua/ui_spec.lua @@ -1,13 +1,15 @@ -local helpers = require('test.functional.helpers')(after_each) -local eq = helpers.eq -local matches = helpers.matches -local exec_lua = helpers.exec_lua -local clear = helpers.clear -local feed = helpers.feed -local eval = helpers.eval -local is_ci = helpers.is_ci -local is_os = helpers.is_os -local poke_eventloop = helpers.poke_eventloop +local t = require('test.testutil') +local n = require('test.functional.testnvim')() + +local eq = t.eq +local ok = t.ok +local exec_lua = n.exec_lua +local clear = n.clear +local feed = n.feed +local eval = n.eval +local is_ci = t.is_ci +local is_os = t.is_os +local poke_eventloop = n.poke_eventloop describe('vim.ui', function() before_each(function() @@ -138,13 +140,12 @@ describe('vim.ui', function() describe('open()', function() it('validation', function() if is_os('win') or not is_ci('github') then - exec_lua [[vim.system = function() return { wait=function() return { code=3} end } end]] + exec_lua [[vim.system = function() return { wait=function() return { code=3 } end } end]] end if not is_os('bsd') then - matches( - 'vim.ui.open: command failed %(%d%): { "[^"]+", .*"non%-existent%-file" }', - exec_lua [[local _, err = vim.ui.open('non-existent-file') ; return err]] - ) + local rv = + exec_lua [[local cmd = vim.ui.open('non-existent-file'); return cmd:wait(100).code]] + ok(type(rv) == 'number' and rv ~= 0, 'nonzero exit code', rv) end exec_lua [[ @@ -152,7 +153,7 @@ describe('vim.ui', function() vim.fn.executable = function() return 0 end ]] eq( - 'vim.ui.open: no handler found (tried: explorer.exe, xdg-open)', + 'vim.ui.open: no handler found (tried: wslview, explorer.exe, xdg-open)', exec_lua [[local _, err = vim.ui.open('foo') ; return err]] ) end) diff --git a/test/functional/lua/uri_spec.lua b/test/functional/lua/uri_spec.lua index dacaf95867..553afb35d3 100644 --- a/test/functional/lua/uri_spec.lua +++ b/test/functional/lua/uri_spec.lua @@ -1,10 +1,12 @@ -local helpers = require('test.functional.helpers')(after_each) -local clear = helpers.clear -local exec_lua = helpers.exec_lua -local eq = helpers.eq -local is_os = helpers.is_os -local skip = helpers.skip -local write_file = require('test.helpers').write_file +local t = require('test.testutil') +local n = require('test.functional.testnvim')() + +local clear = n.clear +local exec_lua = n.exec_lua +local eq = t.eq +local is_os = t.is_os +local skip = t.skip +local write_file = t.write_file describe('URI methods', function() before_each(function() @@ -206,7 +208,7 @@ describe('URI methods', function() it('Windows paths should not be treated as uris', function() skip(not is_os('win'), 'Not applicable on non-Windows') - local file = helpers.tmpname() + local file = t.tmpname() write_file(file, 'Test content') local test_case = string.format( [[ diff --git a/test/functional/lua/version_spec.lua b/test/functional/lua/version_spec.lua index 3bc9e26d41..4ce8fb8dfe 100644 --- a/test/functional/lua/version_spec.lua +++ b/test/functional/lua/version_spec.lua @@ -1,10 +1,13 @@ -local helpers = require('test.functional.helpers')(after_each) -local clear = helpers.clear -local eq = helpers.eq -local ok = helpers.ok -local exec_lua = helpers.exec_lua -local matches = helpers.matches -local pcall_err = helpers.pcall_err +local t = require('test.testutil') +local n = require('test.functional.testnvim')() + +local clear = n.clear +local eq = t.eq +local ok = t.ok +local exec_lua = n.exec_lua +local matches = t.matches +local pcall_err = t.pcall_err +local fn = n.fn local function v(ver) return vim.version._version(ver) @@ -17,7 +20,7 @@ describe('version', function() end) it('version() returns Nvim version', function() - local expected = exec_lua('return vim.fn.api_info().version') + local expected = fn.api_info().version local actual = exec_lua('return vim.version()') eq(expected.major, actual.major) eq(expected.minor, actual.minor) diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index a262d239e8..c8f94c6ffa 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -1,32 +1,33 @@ -- Test suite for testing interactions with API bindings -local helpers = require('test.functional.helpers')(after_each) +local t = require('test.testutil') +local n = require('test.functional.testnvim')() local Screen = require('test.functional.ui.screen') -local nvim_prog = helpers.nvim_prog -local fn = helpers.fn -local api = helpers.api -local command = helpers.command -local dedent = helpers.dedent -local insert = helpers.insert -local clear = helpers.clear -local eq = helpers.eq -local ok = helpers.ok +local nvim_prog = n.nvim_prog +local fn = n.fn +local api = n.api +local command = n.command +local dedent = t.dedent +local insert = n.insert +local clear = n.clear +local eq = t.eq +local ok = t.ok local pesc = vim.pesc -local eval = helpers.eval -local feed = helpers.feed -local pcall_err = helpers.pcall_err -local exec_lua = helpers.exec_lua -local matches = helpers.matches -local exec = helpers.exec +local eval = n.eval +local feed = n.feed +local pcall_err = t.pcall_err +local exec_lua = n.exec_lua +local matches = t.matches +local exec = n.exec local NIL = vim.NIL -local retry = helpers.retry -local next_msg = helpers.next_msg -local remove_trace = helpers.remove_trace -local mkdir_p = helpers.mkdir_p -local rmdir = helpers.rmdir -local write_file = helpers.write_file -local poke_eventloop = helpers.poke_eventloop -local assert_alive = helpers.assert_alive +local retry = t.retry +local next_msg = n.next_msg +local remove_trace = t.remove_trace +local mkdir_p = n.mkdir_p +local rmdir = n.rmdir +local write_file = t.write_file +local poke_eventloop = n.poke_eventloop +local assert_alive = n.assert_alive describe('lua stdlib', function() before_each(clear) @@ -128,63 +129,62 @@ describe('lua stdlib', function() eq(1, fn.luaeval('vim.stricmp("\\0C\\0", "\\0B\\0")')) end) - local function test_vim_deprecate(current_version) + --- @param prerel string | nil + local function test_vim_deprecate(prerel) -- vim.deprecate(name, alternative, version, plugin, backtrace) -- See MAINTAIN.md for the soft/hard deprecation policy - describe(('vim.deprecate [current_version = %s]'):format(current_version), function() - before_each(function() - -- mock vim.version() behavior, should be pinned for consistent testing - exec_lua( - [[ - local current_version_mock = vim.version.parse(...) - getmetatable(vim.version).__call = function() - return current_version_mock - end - ]], - current_version - ) - end) + describe(('vim.deprecate prerel=%s,'):format(prerel or 'nil'), function() + local curver = exec_lua('return vim.version()') --[[@as {major:number, minor:number}]] + -- "0.10" or "0.10-dev+xxx" + local curstr = ('%s.%s%s'):format(curver.major, curver.minor, prerel or '') + -- "0.10" or "0.11" + local nextver = ('%s.%s'):format(curver.major, curver.minor + (prerel and 0 or 1)) + local was_removed = prerel and 'was removed' or 'will be removed' - it('when plugin = nil', function() + it('plugin=nil, same message skipped', function() eq( - dedent [[ - foo.bar() is deprecated, use zub.wooo{ok=yay} instead. :help deprecated - This feature will be removed in Nvim version 0.10]], - exec_lua('return vim.deprecate(...)', 'foo.bar()', 'zub.wooo{ok=yay}', '0.10') + dedent( + [[ + foo.bar() is deprecated. Run ":checkhealth vim.deprecated" for more information]] + ):format(curstr), + exec_lua('return vim.deprecate(...)', 'foo.bar()', 'zub.wooo{ok=yay}', curstr) ) - -- Same message, skipped. - eq(vim.NIL, exec_lua('return vim.deprecate(...)', 'foo.bar()', 'zub.wooo{ok=yay}', '0.10')) + -- Same message as above; skipped this time. + eq(vim.NIL, exec_lua('return vim.deprecate(...)', 'foo.bar()', 'zub.wooo{ok=yay}', curstr)) + end) - -- Don't show error if not hard-deprecated (only soft-deprecated) + it('plugin=nil, no error if soft-deprecated', function() eq( vim.NIL, - exec_lua('return vim.deprecate(...)', 'foo.baz()', 'foo.better_baz()', '0.12.0') + exec_lua('return vim.deprecate(...)', 'foo.baz()', 'foo.better_baz()', '0.99.0') ) + end) - -- Show error if hard-deprecated + it('plugin=nil, show error if hard-deprecated', function() eq( - dedent [[ - foo.hard_dep() is deprecated, use vim.new_api() instead. :help deprecated - This feature will be removed in Nvim version 0.11]], - exec_lua('return vim.deprecate(...)', 'foo.hard_dep()', 'vim.new_api()', '0.11') + dedent( + [[ + foo.hard_dep() is deprecated. Run ":checkhealth vim.deprecated" for more information]] + ):format(was_removed, nextver), + exec_lua('return vim.deprecate(...)', 'foo.hard_dep()', 'vim.new_api()', nextver) ) + end) - -- To be deleted in the next major version (1.0) + it('plugin=nil, to be deleted in the next major version (1.0)', function() eq( dedent [[ - foo.baz() is deprecated. :help deprecated - This feature will be removed in Nvim version 1.0]], + foo.baz() is deprecated. Run ":checkhealth vim.deprecated" for more information]], exec_lua [[ return vim.deprecate('foo.baz()', nil, '1.0') ]] ) end) - it('when plugin is specified', function() + it('plugin specified', function() -- When `plugin` is specified, don't show ":help deprecated". #22235 eq( dedent [[ foo.bar() is deprecated, use zub.wooo{ok=yay} instead. - This feature will be removed in my-plugin.nvim version 0.3.0]], + Feature will be removed in my-plugin.nvim 0.3.0]], exec_lua( 'return vim.deprecate(...)', 'foo.bar()', @@ -199,7 +199,7 @@ describe('lua stdlib', function() eq( dedent [[ foo.bar() is deprecated, use zub.wooo{ok=yay} instead. - This feature will be removed in my-plugin.nvim version 0.11.0]], + Feature will be removed in my-plugin.nvim 0.11.0]], exec_lua( 'return vim.deprecate(...)', 'foo.bar()', @@ -213,8 +213,8 @@ describe('lua stdlib', function() end) end - test_vim_deprecate('0.10') - test_vim_deprecate('0.10-dev+g0000000') + test_vim_deprecate() + test_vim_deprecate('-dev+g0000000') it('vim.startswith', function() eq(true, fn.luaeval('vim.startswith("123", "1")')) @@ -592,8 +592,8 @@ describe('lua stdlib', function() { 'x*yz*oo*l', '*', true, false, { 'x', 'yz', 'oo', 'l' } }, } - for _, t in ipairs(tests) do - eq(t[5], vim.split(t[1], t[2], { plain = t[3], trimempty = t[4] }), t[1]) + for _, q in ipairs(tests) do + eq(q[5], vim.split(q[1], q[2], { plain = q[3], trimempty = q[4] }), q[1]) end -- Test old signature @@ -603,8 +603,8 @@ describe('lua stdlib', function() { 'abc', '.-' }, } - for _, t in ipairs(loops) do - matches('Infinite loop detected', pcall_err(vim.split, t[1], t[2])) + for _, q in ipairs(loops) do + matches('Infinite loop detected', pcall_err(vim.split, q[1], q[2])) end -- Validates args. @@ -626,8 +626,8 @@ describe('lua stdlib', function() { 'r\n', 'r' }, } - for _, t in ipairs(trims) do - assert(t[2], trim(t[1])) + for _, q in ipairs(trims) do + assert(q[2], trim(q[1])) end -- Validates args. @@ -636,8 +636,8 @@ describe('lua stdlib', function() it('vim.inspect', function() -- just make sure it basically works, it has its own test suite - local inspect = function(t, opts) - return exec_lua('return vim.inspect(...)', t, opts) + local inspect = function(q, opts) + return exec_lua('return vim.inspect(...)', q, opts) end eq('2', inspect(2)) @@ -670,21 +670,21 @@ describe('lua stdlib', function() local a = {} local b = vim.deepcopy(a) - return vim.tbl_islist(b) and vim.tbl_count(b) == 0 and tostring(a) ~= tostring(b) + return vim.islist(b) and vim.tbl_count(b) == 0 and tostring(a) ~= tostring(b) ]])) ok(exec_lua([[ local a = vim.empty_dict() local b = vim.deepcopy(a) - return not vim.tbl_islist(b) and vim.tbl_count(b) == 0 + return not vim.islist(b) and vim.tbl_count(b) == 0 ]])) ok(exec_lua([[ local a = {x = vim.empty_dict(), y = {}} local b = vim.deepcopy(a) - return not vim.tbl_islist(b.x) and vim.tbl_islist(b.y) + return not vim.islist(b.x) and vim.islist(b.y) and vim.tbl_count(b) == 2 and tostring(a) ~= tostring(b) ]])) @@ -822,30 +822,30 @@ describe('lua stdlib', function() ) end) - it('vim.tbl_isarray', function() - eq(true, exec_lua('return vim.tbl_isarray({})')) - eq(false, exec_lua('return vim.tbl_isarray(vim.empty_dict())')) - eq(true, exec_lua("return vim.tbl_isarray({'a', 'b', 'c'})")) - eq(false, exec_lua("return vim.tbl_isarray({'a', '32', a='hello', b='baz'})")) - eq(false, exec_lua("return vim.tbl_isarray({1, a='hello', b='baz'})")) - eq(false, exec_lua("return vim.tbl_isarray({a='hello', b='baz', 1})")) - eq(false, exec_lua("return vim.tbl_isarray({1, 2, nil, a='hello'})")) - eq(true, exec_lua('return vim.tbl_isarray({1, 2, nil, 4})')) - eq(true, exec_lua('return vim.tbl_isarray({nil, 2, 3, 4})')) - eq(false, exec_lua('return vim.tbl_isarray({1, [1.5]=2, [3]=3})')) + it('vim.isarray', function() + eq(true, exec_lua('return vim.isarray({})')) + eq(false, exec_lua('return vim.isarray(vim.empty_dict())')) + eq(true, exec_lua("return vim.isarray({'a', 'b', 'c'})")) + eq(false, exec_lua("return vim.isarray({'a', '32', a='hello', b='baz'})")) + eq(false, exec_lua("return vim.isarray({1, a='hello', b='baz'})")) + eq(false, exec_lua("return vim.isarray({a='hello', b='baz', 1})")) + eq(false, exec_lua("return vim.isarray({1, 2, nil, a='hello'})")) + eq(true, exec_lua('return vim.isarray({1, 2, nil, 4})')) + eq(true, exec_lua('return vim.isarray({nil, 2, 3, 4})')) + eq(false, exec_lua('return vim.isarray({1, [1.5]=2, [3]=3})')) end) - it('vim.tbl_islist', function() - eq(true, exec_lua('return vim.tbl_islist({})')) - eq(false, exec_lua('return vim.tbl_islist(vim.empty_dict())')) - eq(true, exec_lua("return vim.tbl_islist({'a', 'b', 'c'})")) - eq(false, exec_lua("return vim.tbl_islist({'a', '32', a='hello', b='baz'})")) - eq(false, exec_lua("return vim.tbl_islist({1, a='hello', b='baz'})")) - eq(false, exec_lua("return vim.tbl_islist({a='hello', b='baz', 1})")) - eq(false, exec_lua("return vim.tbl_islist({1, 2, nil, a='hello'})")) - eq(false, exec_lua('return vim.tbl_islist({1, 2, nil, 4})')) - eq(false, exec_lua('return vim.tbl_islist({nil, 2, 3, 4})')) - eq(false, exec_lua('return vim.tbl_islist({1, [1.5]=2, [3]=3})')) + it('vim.islist', function() + eq(true, exec_lua('return vim.islist({})')) + eq(false, exec_lua('return vim.islist(vim.empty_dict())')) + eq(true, exec_lua("return vim.islist({'a', 'b', 'c'})")) + eq(false, exec_lua("return vim.islist({'a', '32', a='hello', b='baz'})")) + eq(false, exec_lua("return vim.islist({1, a='hello', b='baz'})")) + eq(false, exec_lua("return vim.islist({a='hello', b='baz', 1})")) + eq(false, exec_lua("return vim.islist({1, 2, nil, a='hello'})")) + eq(false, exec_lua('return vim.islist({1, 2, nil, 4})')) + eq(false, exec_lua('return vim.islist({nil, 2, 3, 4})')) + eq(false, exec_lua('return vim.islist({1, [1.5]=2, [3]=3})')) end) it('vim.tbl_isempty', function() @@ -918,7 +918,7 @@ describe('lua stdlib', function() local b = {} local c = vim.tbl_extend("keep", a, b) - return not vim.tbl_islist(c) and vim.tbl_count(c) == 0 + return not vim.islist(c) and vim.tbl_count(c) == 0 ]])) ok(exec_lua([[ @@ -926,7 +926,7 @@ describe('lua stdlib', function() local b = vim.empty_dict() local c = vim.tbl_extend("keep", a, b) - return vim.tbl_islist(c) and vim.tbl_count(c) == 0 + return vim.islist(c) and vim.tbl_count(c) == 0 ]])) ok(exec_lua([[ @@ -1026,7 +1026,7 @@ describe('lua stdlib', function() local count = 0 for _ in pairs(c) do count = count + 1 end - return not vim.tbl_islist(c) and count == 0 + return not vim.islist(c) and count == 0 ]])) ok(exec_lua([[ @@ -1037,7 +1037,7 @@ describe('lua stdlib', function() local count = 0 for _ in pairs(c) do count = count + 1 end - return vim.tbl_islist(c) and count == 0 + return vim.islist(c) and count == 0 ]])) eq( @@ -1282,7 +1282,7 @@ describe('lua stdlib', function() vim.rpcrequest(chan, 'nvim_exec', 'let xx = {}\nlet yy = []', false) local dict = vim.rpcrequest(chan, 'nvim_eval', 'xx') local list = vim.rpcrequest(chan, 'nvim_eval', 'yy') - return {dict, list, vim.tbl_islist(dict), vim.tbl_islist(list)} + return {dict, list, vim.islist(dict), vim.islist(list)} ]]) ) @@ -1355,7 +1355,7 @@ describe('lua stdlib', function() vim.api.nvim_set_var('dicty', vim.empty_dict()) local listy = vim.fn.eval("listy") local dicty = vim.fn.eval("dicty") - return {vim.tbl_islist(listy), vim.tbl_islist(dicty), next(listy) == nil, next(dicty) == nil} + return {vim.islist(listy), vim.islist(dicty), next(listy) == nil, next(dicty) == nil} ]]) ) @@ -1569,7 +1569,7 @@ describe('lua stdlib', function() eq(NIL, exec_lua([[return vim.g.Unknown_script_func]])) -- Check if autoload works properly - local pathsep = helpers.get_pathsep() + local pathsep = n.get_pathsep() local xconfig = 'Xhome' .. pathsep .. 'Xconfig' local xdata = 'Xhome' .. pathsep .. 'Xdata' local autoload_folder = table.concat({ xconfig, 'nvim', 'autoload' }, pathsep) @@ -2016,7 +2016,7 @@ describe('lua stdlib', function() vim.opt.scrolloff = 10 return vim.o.scrolloff ]] - eq(scrolloff, 10) + eq(10, scrolloff) end) pending('should handle STUPID window things', function() @@ -2037,7 +2037,7 @@ describe('lua stdlib', function() vim.opt.wildignore = { 'hello', 'world' } return vim.o.wildignore ]] - eq(wildignore, 'hello,world') + eq('hello,world', wildignore) end) it('should allow setting tables with shortnames', function() @@ -2045,7 +2045,7 @@ describe('lua stdlib', function() vim.opt.wig = { 'hello', 'world' } return vim.o.wildignore ]] - eq(wildignore, 'hello,world') + eq('hello,world', wildignore) end) it('should error when you attempt to set string values to numeric options', function() @@ -2451,13 +2451,13 @@ describe('lua stdlib', function() vim.opt.wildignore = 'foo' return vim.o.wildignore ]] - eq(wildignore, 'foo') + eq('foo', wildignore) wildignore = exec_lua [[ vim.opt.wildignore = vim.opt.wildignore + { 'bar', 'baz' } return vim.o.wildignore ]] - eq(wildignore, 'foo,bar,baz') + eq('foo,bar,baz', wildignore) end) it('should handle adding duplicates', function() @@ -2465,19 +2465,19 @@ describe('lua stdlib', function() vim.opt.wildignore = 'foo' return vim.o.wildignore ]] - eq(wildignore, 'foo') + eq('foo', wildignore) wildignore = exec_lua [[ vim.opt.wildignore = vim.opt.wildignore + { 'bar', 'baz' } return vim.o.wildignore ]] - eq(wildignore, 'foo,bar,baz') + eq('foo,bar,baz', wildignore) wildignore = exec_lua [[ vim.opt.wildignore = vim.opt.wildignore + { 'bar', 'baz' } return vim.o.wildignore ]] - eq(wildignore, 'foo,bar,baz') + eq('foo,bar,baz', wildignore) end) it('should allow adding multiple times', function() @@ -2486,7 +2486,7 @@ describe('lua stdlib', function() vim.opt.wildignore = vim.opt.wildignore + 'bar' + 'baz' return vim.o.wildignore ]] - eq(wildignore, 'foo,bar,baz') + eq('foo,bar,baz', wildignore) end) it('should remove values when you use minus', function() @@ -2494,19 +2494,19 @@ describe('lua stdlib', function() vim.opt.wildignore = 'foo' return vim.o.wildignore ]] - eq(wildignore, 'foo') + eq('foo', wildignore) wildignore = exec_lua [[ vim.opt.wildignore = vim.opt.wildignore + { 'bar', 'baz' } return vim.o.wildignore ]] - eq(wildignore, 'foo,bar,baz') + eq('foo,bar,baz', wildignore) wildignore = exec_lua [[ vim.opt.wildignore = vim.opt.wildignore - 'bar' return vim.o.wildignore ]] - eq(wildignore, 'foo,baz') + eq('foo,baz', wildignore) end) it('should prepend values when using ^', function() @@ -2521,7 +2521,7 @@ describe('lua stdlib', function() vim.opt.wildignore = vim.opt.wildignore ^ 'super_first' return vim.o.wildignore ]] - eq(wildignore, 'super_first,first,foo') + eq('super_first,first,foo', wildignore) end) it('should not remove duplicates from wildmode: #14708', function() @@ -2530,7 +2530,7 @@ describe('lua stdlib', function() return vim.o.wildmode ]] - eq(wildmode, 'full,list,full') + eq('full,list,full', wildmode) end) describe('option types', function() @@ -2738,7 +2738,7 @@ describe('lua stdlib', function() return vim.go.whichwrap ]] - eq(ww, 'b,s') + eq('b,s', ww) eq( 'b,s,<,>,[,]', exec_lua [[ @@ -3007,25 +3007,65 @@ describe('lua stdlib', function() end) describe('vim.on_key', function() - it('tracks keystrokes', function() + it('tracks Unicode input', function() insert([[hello world ]]) exec_lua [[ keys = {} + typed = {} - vim.on_key(function(buf) + vim.on_key(function(buf, typed_buf) if buf:byte() == 27 then buf = "<ESC>" end + if typed_buf:byte() == 27 then + typed_buf = "<ESC>" + end table.insert(keys, buf) + table.insert(typed, typed_buf) end) ]] - insert([[next 🤦 lines å ]]) + insert([[next 🤦 lines å …]]) -- It has escape in the keys pressed - eq('inext 🤦 lines å <ESC>', exec_lua [[return table.concat(keys, '')]]) + eq('inext 🤦 lines å …<ESC>', exec_lua [[return table.concat(keys, '')]]) + eq('inext 🤦 lines å …<ESC>', exec_lua [[return table.concat(typed, '')]]) + end) + + it('tracks input with modifiers', function() + exec_lua [[ + keys = {} + typed = {} + + vim.on_key(function(buf, typed_buf) + table.insert(keys, vim.fn.keytrans(buf)) + table.insert(typed, vim.fn.keytrans(typed_buf)) + end) + ]] + + feed([[i<C-V><C-;><C-V><C-…><Esc>]]) + + eq('i<C-V><C-;><C-V><C-…><Esc>', exec_lua [[return table.concat(keys, '')]]) + eq('i<C-V><C-;><C-V><C-…><Esc>', exec_lua [[return table.concat(typed, '')]]) + end) + + it('works with character find and Select mode', function() + insert('12345') + + exec_lua [[ + typed = {} + + vim.cmd('snoremap # @') + + vim.on_key(function(buf, typed_buf) + table.insert(typed, vim.fn.keytrans(typed_buf)) + end) + ]] + + feed('F3gHβγδεζ<Esc>gH…<Esc>gH#$%^') + eq('F3gHβγδεζ<Esc>gH…<Esc>gH#$%^', exec_lua [[return table.concat(typed, '')]]) end) it('allows removing on_key listeners', function() @@ -3087,23 +3127,29 @@ describe('lua stdlib', function() eq('inext l', exec_lua [[ return table.concat(keys, '') ]]) end) - it('processes mapped keys, not unmapped keys', function() + it('argument 1 is keys after mapping, argument 2 is typed keys', function() exec_lua [[ keys = {} + typed = {} vim.cmd("inoremap hello world") - vim.on_key(function(buf) + vim.on_key(function(buf, typed_buf) if buf:byte() == 27 then buf = "<ESC>" end + if typed_buf:byte() == 27 then + typed_buf = "<ESC>" + end table.insert(keys, buf) + table.insert(typed, typed_buf) end) ]] insert('hello') eq('iworld<ESC>', exec_lua [[return table.concat(keys, '')]]) + eq('ihello<ESC>', exec_lua [[return table.concat(typed, '')]]) end) it('can call vim.fn functions on Ctrl-C #17273', function() @@ -3664,6 +3710,20 @@ describe('lua stdlib', function() ]] ) end) + + it('layout in current tabpage does not affect windows in others', function() + command('tab split') + local t2_move_win = api.nvim_get_current_win() + command('vsplit') + local t2_other_win = api.nvim_get_current_win() + command('tabprevious') + matches('E36: Not enough room$', pcall_err(command, 'execute "split|"->repeat(&lines)')) + command('vsplit') + + -- Without vim-patch:8.2.3862, this gives E36, despite just the 1st tabpage being full. + exec_lua('vim.api.nvim_win_call(..., function() vim.cmd.wincmd "J" end)', t2_move_win) + eq({ 'col', { { 'leaf', t2_other_win }, { 'leaf', t2_move_win } } }, fn.winlayout(2)) + end) end) describe('vim.iconv', function() @@ -4011,7 +4071,7 @@ describe('vim.keymap', function() feed('asdf\n') eq(1, exec_lua [[return GlobalCount]]) - eq('\nNo mapping found', helpers.exec_capture('nmap asdf')) + eq('\nNo mapping found', n.exec_capture('nmap asdf')) end) it('works with buffer-local mappings', function() @@ -4035,7 +4095,7 @@ describe('vim.keymap', function() feed('asdf\n') eq(1, exec_lua [[return GlobalCount]]) - eq('\nNo mapping found', helpers.exec_capture('nmap asdf')) + eq('\nNo mapping found', n.exec_capture('nmap asdf')) end) it('does not mutate the opts parameter', function() diff --git a/test/functional/lua/watch_spec.lua b/test/functional/lua/watch_spec.lua index 115fee8091..bd8faadf5b 100644 --- a/test/functional/lua/watch_spec.lua +++ b/test/functional/lua/watch_spec.lua @@ -1,15 +1,17 @@ -local helpers = require('test.functional.helpers')(after_each) -local eq = helpers.eq -local exec_lua = helpers.exec_lua -local clear = helpers.clear -local is_ci = helpers.is_ci -local is_os = helpers.is_os -local skip = helpers.skip +local t = require('test.testutil') +local n = require('test.functional.testnvim')() + +local eq = t.eq +local exec_lua = n.exec_lua +local clear = n.clear +local is_ci = t.is_ci +local is_os = t.is_os +local skip = t.skip -- Create a file via a rename to avoid multiple -- events which can happen with some backends on some platforms local function touch(path) - local tmp = helpers.tmpname() + local tmp = t.tmpname() io.open(tmp, 'w'):close() assert(vim.uv.fs_rename(tmp, path)) end @@ -22,15 +24,13 @@ describe('vim._watch', function() local function run(watchfunc) it('detects file changes (watchfunc=' .. watchfunc .. '())', function() if watchfunc == 'fswatch' then - skip(is_os('mac'), 'flaky test on mac') - skip( - not is_ci() and helpers.fn.executable('fswatch') == 0, - 'fswatch not installed and not on CI' - ) skip(is_os('win'), 'not supported on windows') + skip(is_os('mac'), 'flaky test on mac') + skip(not is_ci() and n.fn.executable('fswatch') == 0, 'fswatch not installed and not on CI') end if watchfunc == 'watch' then + skip(is_os('mac'), 'flaky test on mac') skip(is_os('bsd'), 'Stopped working on bsd after 3ca967387c49c754561c3b11a574797504d40f38') else skip( @@ -39,7 +39,7 @@ describe('vim._watch', function() ) end - local root_dir = vim.uv.fs_mkdtemp(vim.fs.dirname(helpers.tmpname()) .. '/nvim_XXXXXXXXXX') + local root_dir = vim.uv.fs_mkdtemp(vim.fs.dirname(t.tmpname()) .. '/nvim_XXXXXXXXXX') local expected_events = 0 diff --git a/test/functional/lua/xdiff_spec.lua b/test/functional/lua/xdiff_spec.lua index c21309c2e4..d5589c1f13 100644 --- a/test/functional/lua/xdiff_spec.lua +++ b/test/functional/lua/xdiff_spec.lua @@ -1,8 +1,10 @@ -local helpers = require('test.functional.helpers')(after_each) -local clear = helpers.clear -local exec_lua = helpers.exec_lua -local eq = helpers.eq -local pcall_err = helpers.pcall_err +local t = require('test.testutil') +local n = require('test.functional.testnvim')() + +local clear = n.clear +local exec_lua = n.exec_lua +local eq = t.eq +local pcall_err = t.pcall_err describe('xdiff bindings', function() before_each(function() |