diff options
Diffstat (limited to 'test/functional/plugin')
-rw-r--r-- | test/functional/plugin/health_spec.lua | 6 | ||||
-rw-r--r-- | test/functional/plugin/lsp/incremental_sync_spec.lua | 269 | ||||
-rw-r--r-- | test/functional/plugin/lsp_spec.lua | 223 |
3 files changed, 457 insertions, 41 deletions
diff --git a/test/functional/plugin/health_spec.lua b/test/functional/plugin/health_spec.lua index b567b3e20c..37de5d0ce6 100644 --- a/test/functional/plugin/health_spec.lua +++ b/test/functional/plugin/health_spec.lua @@ -156,7 +156,7 @@ describe('health.vim', function() test_plug.submodule_failed: require("test_plug.submodule_failed.health").check() ======================================================================== - ERROR: Failed to run healthcheck for "test_plug.submodule_failed" plugin. Exception: - function health#check, line 24]]) + function health#check, line 20]]) eq(expected, received) end) @@ -167,7 +167,7 @@ describe('health.vim', function() broken: health#broken#check ======================================================================== - ERROR: Failed to run healthcheck for "broken" plugin. Exception: - function health#check[24]..health#broken#check, line 1 + function health#check[20]..health#broken#check, line 1 caused an error ]]) end) @@ -186,7 +186,7 @@ describe('health.vim', function() test_plug.submodule_failed: require("test_plug.submodule_failed.health").check() ======================================================================== - ERROR: Failed to run healthcheck for "test_plug.submodule_failed" plugin. Exception: - function health#check, line 24]]) + function health#check, line 20]]) eq(expected, received) end) diff --git a/test/functional/plugin/lsp/incremental_sync_spec.lua b/test/functional/plugin/lsp/incremental_sync_spec.lua index 5dd34e7665..4e3eddb960 100644 --- a/test/functional/plugin/lsp/incremental_sync_spec.lua +++ b/test/functional/plugin/lsp/incremental_sync_spec.lua @@ -164,6 +164,201 @@ describe('incremental synchronization', function() } test_edit({"a"}, {"rb"}, expected_text_changes, 'utf-16', '\n') end) + it('deleting a line', function() + local expected_text_changes = { + { + range = { + ['start'] = { + character = 0, + line = 0 + }, + ['end'] = { + character = 0, + line = 1 + } + }, + rangeLength = 12, + text = '' + } + } + test_edit({"hello world"}, {"dd"}, expected_text_changes, 'utf-16', '\n') + end) + it('deleting an empty line', function() + local expected_text_changes = { + { + range = { + ['start'] = { + character = 0, + line = 1 + }, + ['end'] = { + character = 0, + line = 2 + } + }, + rangeLength = 1, + text = '' + } + } + test_edit({"hello world", ""}, {"jdd"}, expected_text_changes, 'utf-16', '\n') + end) + it('adding a line', function() + local expected_text_changes = { + { + range = { + ['start'] = { + character = 0, + line = 1 + }, + ['end'] = { + character = 0, + line = 1 + } + }, + rangeLength = 0, + text = 'hello world\n' + } + } + test_edit({"hello world"}, {"yyp"}, expected_text_changes, 'utf-16', '\n') + end) + it('adding an empty line', function() + local expected_text_changes = { + { + range = { + ['start'] = { + character = 0, + line = 1 + }, + ['end'] = { + character = 0, + line = 1 + } + }, + rangeLength = 0, + text = '\n' + } + } + test_edit({"hello world"}, {"o"}, expected_text_changes, 'utf-16', '\n') + end) + end) + describe('multi line edit', function() + it('deletion and insertion', function() + local expected_text_changes = { + -- delete "_fsda" from end of line 1 + { + range = { + ['start'] = { + character = 4, + line = 1 + }, + ['end'] = { + character = 9, + line = 1 + } + }, + rangeLength = 5, + text = '' + }, + -- delete "hello world\n" from line 2 + { + range = { + ['start'] = { + character = 0, + line = 2 + }, + ['end'] = { + character = 0, + line = 3 + } + }, + rangeLength = 12, + text = '' + }, + -- delete "1234" from beginning of line 2 + { + range = { + ['start'] = { + character = 0, + line = 2 + }, + ['end'] = { + character = 4, + line = 2 + } + }, + rangeLength = 4, + text = '' + }, + -- add " asdf" to end of line 1 + { + range = { + ['start'] = { + character = 4, + line = 1 + }, + ['end'] = { + character = 4, + line = 1 + } + }, + rangeLength = 0, + text = ' asdf' + }, + -- delete " asdf\n" from line 2 + { + range = { + ['start'] = { + character = 0, + line = 2 + }, + ['end'] = { + character = 0, + line = 3 + } + }, + rangeLength = 6, + text = '' + }, + -- undo entire deletion + { + range = { + ['start'] = { + character = 4, + line = 1 + }, + ['end'] = { + character = 9, + line = 1 + } + }, + rangeLength = 5, + text = "_fdsa\nhello world\n1234 asdf" + }, + -- redo entire deletion + { + range = { + ['start'] = { + character = 4, + line = 1 + }, + ['end'] = { + character = 9, + line = 3 + } + }, + rangeLength = 27, + text = ' asdf' + }, + } + local original_lines = { + "\\begin{document}", + "test_fdsa", + "hello world", + "1234 asdf", + "\\end{document}" + } + test_edit(original_lines, {"jf_vejjbhhdu<C-R>"}, expected_text_changes, 'utf-16', '\n') + end) end) describe('multi-operation edits', function() @@ -297,6 +492,80 @@ describe('incremental synchronization', function() } test_edit({"🔥"}, {"x"}, expected_text_changes, 'utf-16', '\n') end) + it('replacing a multibyte character with matching prefix', function() + local expected_text_changes = { + { + range = { + ['start'] = { + character = 0, + line = 1 + }, + ['end'] = { + character = 1, + line = 1 + } + }, + rangeLength = 1, + text = '⟩' + } + } + -- ⟨ is e29fa8, ⟩ is e29fa9 + local original_lines = { + "\\begin{document}", + "⟨", + "\\end{document}", + } + test_edit(original_lines, {"jr⟩"}, expected_text_changes, 'utf-16', '\n') + end) + it('replacing a multibyte character with matching suffix', function() + local expected_text_changes = { + { + range = { + ['start'] = { + character = 0, + line = 1 + }, + ['end'] = { + character = 1, + line = 1 + } + }, + rangeLength = 1, + text = 'ḟ' + } + } + -- ฟ is e0b89f, ḟ is e1b89f + local original_lines = { + "\\begin{document}", + "ฟ", + "\\end{document}", + } + test_edit(original_lines, {"jrḟ"}, expected_text_changes, 'utf-16', '\n') + end) + it('inserting before a multibyte character', function() + local expected_text_changes = { + { + range = { + ['start'] = { + character = 0, + line = 1 + }, + ['end'] = { + character = 0, + line = 1 + } + }, + rangeLength = 0, + text = ' ' + } + } + local original_lines = { + "\\begin{document}", + "→", + "\\end{document}", + } + test_edit(original_lines, {"ji "}, expected_text_changes, 'utf-16', '\n') + end) it('deleting a multibyte character from a long line', function() local expected_text_changes = { { diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua index b12d4227d5..eab520948f 100644 --- a/test/functional/plugin/lsp_spec.lua +++ b/test/functional/plugin/lsp_spec.lua @@ -73,8 +73,11 @@ local function fake_lsp_server_setup(test_name, timeout_ms, options) on_init = function(client, result) TEST_RPC_CLIENT = client vim.rpcrequest(1, "init", result) - client.config.flags.allow_incremental_sync = options.allow_incremental_sync or false end; + flags = { + allow_incremental_sync = options.allow_incremental_sync or false; + debounce_text_changes = options.debounce_text_changes or 0; + }; on_exit = function(...) vim.rpcnotify(1, "exit", ...) end; @@ -301,6 +304,43 @@ describe('LSP', function() } end) + it('should detach buffer in response to nvim_buf_detach', function() + local expected_handlers = { + {NIL, {}, {method="shutdown", client_id=1}}; + {NIL, {}, {method="finish", client_id=1}}; + } + local client + test_rpc_server { + test_name = "basic_finish"; + on_setup = function() + exec_lua [[ + BUFFER = vim.api.nvim_create_buf(false, true) + ]] + eq(true, exec_lua("return lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)")) + eq(true, exec_lua("return lsp.buf_is_attached(BUFFER, TEST_RPC_CLIENT_ID)")) + exec_lua [[ + vim.api.nvim_command(BUFFER.."bwipeout") + ]] + end; + on_init = function(_client) + client = _client + client.notify('finish') + end; + on_exit = function(code, signal) + eq(0, code, "exit code", fake_lsp_logfile) + eq(0, signal, "exit signal", fake_lsp_logfile) + end; + on_handler = function(err, result, ctx) + eq(table.remove(expected_handlers), {err, result, ctx}, "expected handler") + if ctx.method == 'finish' then + exec_lua("return lsp.buf_detach_client(BUFFER, TEST_RPC_CLIENT_ID)") + eq(false, exec_lua("return lsp.buf_is_attached(BUFFER, TEST_RPC_CLIENT_ID)")) + client.stop() + end + end; + } + end) + it('client should return settings via workspace/configuration handler', function() local expected_handlers = { {NIL, {}, {method="shutdown", client_id=1}}; @@ -889,7 +929,60 @@ describe('LSP', function() local client test_rpc_server { test_name = "basic_check_buffer_open_and_change_incremental"; - options = { allow_incremental_sync = true }; + options = { + allow_incremental_sync = true, + }; + on_setup = function() + exec_lua [[ + BUFFER = vim.api.nvim_create_buf(false, true) + vim.api.nvim_buf_set_lines(BUFFER, 0, -1, false, { + "testing"; + "123"; + }) + ]] + end; + on_init = function(_client) + client = _client + local sync_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Incremental") + eq(sync_kind, client.resolved_capabilities().text_document_did_change) + eq(true, client.resolved_capabilities().text_document_open_close) + exec_lua [[ + assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)) + ]] + end; + on_exit = function(code, signal) + eq(0, code, "exit code", fake_lsp_logfile) + eq(0, signal, "exit signal", fake_lsp_logfile) + end; + on_handler = function(err, result, ctx) + if ctx.method == 'start' then + exec_lua [[ + vim.api.nvim_buf_set_lines(BUFFER, 1, 2, false, { + "123boop"; + }) + ]] + client.notify('finish') + end + eq(table.remove(expected_handlers), {err, result, ctx}, "expected handler") + if ctx.method == 'finish' then + client.stop() + end + end; + } + end) + it('should check the body and didChange incremental with debounce', function() + local expected_handlers = { + {NIL, {}, {method="shutdown", client_id=1}}; + {NIL, {}, {method="finish", client_id=1}}; + {NIL, {}, {method="start", client_id=1}}; + } + local client + test_rpc_server { + test_name = "basic_check_buffer_open_and_change_incremental"; + options = { + allow_incremental_sync = true, + debounce_text_changes = 5 + }; on_setup = function() exec_lua [[ BUFFER = vim.api.nvim_create_buf(false, true) @@ -1198,7 +1291,7 @@ describe('LSP', function() make_edit(2, 0, 2, 2, {"3"}); make_edit(3, 2, 3, 4, {""}); } - exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1) + exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, "utf-16") eq({ '123First line of text'; '2econd line of text'; @@ -1218,7 +1311,7 @@ describe('LSP', function() make_edit(3, #'', 3, #"Fourth", {"another line of text", "before this"}); make_edit(3, #'Fourth', 3, #"Fourth line of text", {"!"}); } - exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1) + exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, "utf-16") eq({ ''; '123'; @@ -1242,7 +1335,7 @@ describe('LSP', function() make_edit(3, #"Fourth", 3, #'', {"another line of text", "before this"}); make_edit(3, #"Fourth line of text", 3, #'Fourth', {"!"}); } - exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1) + exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, "utf-16") eq({ ''; '123'; @@ -1259,7 +1352,7 @@ describe('LSP', function() local edits = { make_edit(4, 3, 4, 4, {"ä"}); } - exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1) + exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, "utf-16") eq({ 'First line of text'; 'Second line of text'; @@ -1272,7 +1365,7 @@ describe('LSP', function() local edits = { make_edit(5, 0, 5, 0, "foobar"); } - exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1) + exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, "utf-16") eq({ 'First line of text'; 'Second line of text'; @@ -1282,6 +1375,20 @@ describe('LSP', function() 'foobar'; }, buf_lines(1)) end) + it('applies multiple text edits at the end of the document', function() + local edits = { + make_edit(4, 0, 5, 0, ""); + make_edit(5, 0, 5, 0, "foobar"); + } + exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, "utf-16") + eq({ + 'First line of text'; + 'Second line of text'; + 'Third line of text'; + 'Fourth line of text'; + 'foobar'; + }, buf_lines(1)) + end) describe('cursor position', function() it('don\'t fix the cursor if the range contains the cursor', function() @@ -1289,7 +1396,7 @@ describe('LSP', function() local edits = { make_edit(1, 0, 1, 19, 'Second line of text') } - exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1) + exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, "utf-16") eq({ 'First line of text'; 'Second line of text'; @@ -1306,7 +1413,7 @@ describe('LSP', function() make_edit(1, 0, 1, 6, ''), make_edit(1, 6, 1, 19, '') } - exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1) + exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, "utf-16") eq({ 'First line of text'; ''; @@ -1323,7 +1430,7 @@ describe('LSP', function() make_edit(1, 0, 1, 6, ''), make_edit(0, 18, 5, 0, '') } - exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1) + exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, "utf-16") eq({ 'First line of text'; }, buf_lines(1)) @@ -1335,7 +1442,7 @@ describe('LSP', function() local edits = { make_edit(1, 0, 2, 0, '') } - exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1) + exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, "utf-16") eq({ 'First line of text'; 'Third line of text'; @@ -1350,7 +1457,7 @@ describe('LSP', function() local edits = { make_edit(1, 7, 1, 11, '') } - exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1) + exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, "utf-16") eq({ 'First line of text'; 'Second of text'; @@ -1366,7 +1473,7 @@ describe('LSP', function() local edits = { make_edit(0, 11, 1, 12, '') } - exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1) + exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, "utf-16") eq({ 'First line of text'; 'Third line of text'; @@ -1382,21 +1489,21 @@ describe('LSP', function() local edits = { make_edit(0, 0, 5, 0, {"All replaced"}); } - exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1) + exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, "utf-16") eq({'All replaced'}, buf_lines(1)) end) it('applies edits when the end line is 2 larger than vim\'s', function() local edits = { make_edit(0, 0, 6, 0, {"All replaced"}); } - exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1) + exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, "utf-16") eq({'All replaced'}, buf_lines(1)) end) it('applies edits with a column offset', function() local edits = { make_edit(0, 0, 5, 2, {"All replaced"}); } - exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1) + exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, "utf-16") eq({'All replaced'}, buf_lines(1)) end) end) @@ -1424,7 +1531,7 @@ describe('LSP', function() ]] end) it('correctly goes ahead with the edit if all is normal', function() - exec_lua('vim.lsp.util.apply_text_document_edit(...)', text_document_edit(5)) + exec_lua("vim.lsp.util.apply_text_document_edit(..., nil, 'utf-16')", text_document_edit(5)) eq({ 'First ↥ 🤦 🦄 line of text'; '2nd line of è¯text'; @@ -1436,7 +1543,7 @@ describe('LSP', function() local bufnr = select(1, ...) local text_edit = select(2, ...) vim.lsp.util.buf_versions[bufnr] = 10 - vim.lsp.util.apply_text_document_edit(text_edit) + vim.lsp.util.apply_text_document_edit(text_edit, nil, 'utf-16') ]], target_bufnr, text_document_edit(0)) eq({ 'First ↥ 🤦 🦄 line of text'; @@ -1449,7 +1556,7 @@ describe('LSP', function() local args = {...} local versionedBuf = args[2] vim.lsp.util.buf_versions[versionedBuf.bufnr] = versionedBuf.currentVersion - vim.lsp.util.apply_text_document_edit(args[1]) + vim.lsp.util.apply_text_document_edit(args[1], nil, 'utf-16') ]], edit, versionedBuf) end @@ -1475,17 +1582,36 @@ describe('LSP', function() describe('workspace_apply_edit', function() it('workspace/applyEdit returns ApplyWorkspaceEditResponse', function() - local expected = { - applied = true; - failureReason = nil; + local expected_handlers = { + {NIL, {}, {method="test", client_id=1}}; + } + test_rpc_server { + test_name = "basic_init"; + on_init = function(client, _) + client.stop() + end; + -- If the program timed out, then code will be nil. + on_exit = function(code, signal) + eq(0, code, "exit code", fake_lsp_logfile) + eq(0, signal, "exit signal", fake_lsp_logfile) + end; + -- Note that NIL must be used here. + -- on_handler(err, method, result, client_id) + on_handler = function(...) + local expected = { + applied = true; + failureReason = nil; + } + eq(expected, exec_lua [[ + local apply_edit = { + label = nil; + edit = {}; + } + return vim.lsp.handlers['workspace/applyEdit'](nil, apply_edit, {client_id = TEST_RPC_CLIENT_ID}) + ]]) + eq(table.remove(expected_handlers), {...}) + end; } - eq(expected, exec_lua [[ - local apply_edit = { - label = nil; - edit = {}; - } - return vim.lsp.handlers['workspace/applyEdit'](nil, apply_edit) - ]]) end) end) @@ -1559,7 +1685,7 @@ describe('LSP', function() local workspace_edits = args[1] local target_bufnr = args[2] - vim.lsp.util.apply_workspace_edit(workspace_edits) + vim.lsp.util.apply_workspace_edit(workspace_edits, 'utf-16') return vim.api.nvim_buf_get_lines(target_bufnr, 0, -1, false) ]], make_workspace_edit(edits), target_bufnr)) @@ -1581,7 +1707,7 @@ describe('LSP', function() local workspace_edits = args[1] local target_bufnr = args[2] - vim.lsp.util.apply_workspace_edit(workspace_edits) + vim.lsp.util.apply_workspace_edit(workspace_edits, 'utf-16') return vim.api.nvim_buf_get_lines(target_bufnr, 0, -1, false) ]], make_workspace_edit(edits), target_bufnr)) @@ -1598,7 +1724,7 @@ describe('LSP', function() }, } } - exec_lua('vim.lsp.util.apply_workspace_edit(...)', edit) + exec_lua('vim.lsp.util.apply_workspace_edit(...)', edit, 'utf-16') eq(true, exec_lua('return vim.loop.fs_stat(...) ~= nil', tmpfile)) end) it('createFile does not touch file if it exists and ignoreIfExists is set', function() @@ -1616,7 +1742,7 @@ describe('LSP', function() }, } } - exec_lua('vim.lsp.util.apply_workspace_edit(...)', edit) + exec_lua('vim.lsp.util.apply_workspace_edit(...)', edit, 'utf-16') eq(true, exec_lua('return vim.loop.fs_stat(...) ~= nil', tmpfile)) eq('Dummy content', read_file(tmpfile)) end) @@ -1636,7 +1762,7 @@ describe('LSP', function() }, } } - exec_lua('vim.lsp.util.apply_workspace_edit(...)', edit) + exec_lua('vim.lsp.util.apply_workspace_edit(...)', edit, 'utf-16') eq(true, exec_lua('return vim.loop.fs_stat(...) ~= nil', tmpfile)) eq('', read_file(tmpfile)) end) @@ -1657,7 +1783,7 @@ describe('LSP', function() } } } - eq(true, pcall(exec_lua, 'vim.lsp.util.apply_workspace_edit(...)', edit)) + eq(true, pcall(exec_lua, 'vim.lsp.util.apply_workspace_edit(...)', edit, 'utf-16')) eq(false, exec_lua('return vim.loop.fs_stat(...) ~= nil', tmpfile)) eq(false, exec_lua('return vim.api.nvim_buf_is_loaded(vim.fn.bufadd(...))', tmpfile)) end) @@ -1818,7 +1944,7 @@ describe('LSP', function() } }, } - return vim.lsp.util.locations_to_items(locations) + return vim.lsp.util.locations_to_items(locations, 'utf-16') ]] eq(expected, actual) end) @@ -1848,7 +1974,7 @@ describe('LSP', function() } }, } - return vim.lsp.util.locations_to_items(locations) + return vim.lsp.util.locations_to_items(locations, 'utf-16') ]] eq(expected, actual) end) @@ -2152,7 +2278,7 @@ describe('LSP', function() end local jump = function(msg) - eq(true, exec_lua('return vim.lsp.util.jump_to_location(...)', msg)) + eq(true, exec_lua('return vim.lsp.util.jump_to_location(...)', msg, "utf-16")) eq(target_bufnr, exec_lua[[return vim.fn.bufnr('%')]]) return { line = exec_lua[[return vim.fn.line('.')]], @@ -2226,6 +2352,27 @@ describe('LSP', function() end) end) + describe('lsp.util.convert_signature_help_to_markdown_lines', function() + it('can handle negative activeSignature', function() + local result = exec_lua[[ + local signature_help = { + activeParameter = 0, + activeSignature = -1, + signatures = { + { + documentation = "", + label = "TestEntity.TestEntity()", + parameters = {} + }, + } + } + return vim.lsp.util.convert_signature_help_to_markdown_lines(signature_help, 'cs', {','}) + ]] + local expected = {'```cs', 'TestEntity.TestEntity()', '```', ''} + eq(expected, result) + end) + end) + describe('lsp.util.get_effective_tabstop', function() local function test_tabstop(tabsize, softtabstop) exec_lua(string.format([[ |