diff options
Diffstat (limited to 'test/functional/plugin/lsp_spec.lua')
-rw-r--r-- | test/functional/plugin/lsp_spec.lua | 295 |
1 files changed, 160 insertions, 135 deletions
diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua index 6ad37110c7..ce50abb50d 100644 --- a/test/functional/plugin/lsp_spec.lua +++ b/test/functional/plugin/lsp_spec.lua @@ -132,37 +132,38 @@ local function test_rpc_server(config) end describe('LSP', function() - describe('server_name specified', function() - before_each(function() - clear_notrace() - -- Run an instance of nvim on the file which contains our "scripts". - -- Pass TEST_NAME to pick the script. - local test_name = "basic_init" - exec_lua([=[ - lsp = require('vim.lsp') - local test_name, fixture_filename, logfile = ... - function test__start_client() - return lsp.start_client { - cmd_env = { - NVIM_LOG_FILE = logfile; - }; - cmd = { - vim.v.progpath, '-Es', '-u', 'NONE', '--headless', - "-c", string.format("lua TEST_NAME = %q", test_name), - "-c", "luafile "..fixture_filename; - }; - root_dir = vim.loop.cwd(); - } - end - TEST_CLIENT1 = test__start_client() - ]=], test_name, fake_lsp_code, fake_lsp_logfile) - end) + before_each(function() + clear_notrace() - after_each(function() - exec_lua("lsp._vim_exit_handler()") - -- exec_lua("lsp.stop_all_clients(true)") - end) + -- Run an instance of nvim on the file which contains our "scripts". + -- Pass TEST_NAME to pick the script. + local test_name = "basic_init" + exec_lua([=[ + lsp = require('vim.lsp') + local test_name, fixture_filename, logfile = ... + function test__start_client() + return lsp.start_client { + cmd_env = { + NVIM_LOG_FILE = logfile; + }; + cmd = { + vim.v.progpath, '-Es', '-u', 'NONE', '--headless', + "-c", string.format("lua TEST_NAME = %q", test_name), + "-c", "luafile "..fixture_filename; + }; + root_dir = vim.loop.cwd(); + } + end + TEST_CLIENT1 = test__start_client() + ]=], test_name, fake_lsp_code, fake_lsp_logfile) + end) + after_each(function() + exec_lua("lsp._vim_exit_handler()") + -- exec_lua("lsp.stop_all_clients(true)") + end) + + describe('server_name specified', function() it('start_client(), stop_client()', function() retry(nil, 4000, function() eq(1, exec_lua('return #lsp.get_active_clients()')) @@ -334,7 +335,6 @@ describe('LSP', function() } end) it('workspace/configuration returns NIL per section if client was started without config.settings', function() - clear_notrace() fake_lsp_server_setup('workspace/configuration no settings') eq({ NIL, NIL, }, exec_lua [[ local result = { @@ -405,7 +405,7 @@ describe('LSP', function() } end) - it('should call unsupported_method when trying to call an unsupported method', function() + it('should not call unsupported_method when trying to call an unsupported method', function() local expected_handlers = { {NIL, {}, {method="shutdown", client_id=1}}; } @@ -415,24 +415,12 @@ describe('LSP', function() exec_lua([=[ BUFFER = vim.api.nvim_get_current_buf() lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID) - vim.lsp.handlers['textDocument/typeDefinition'] = function(err, result, ctx) - local method = ctx.method - vim.lsp._last_lsp_handler = { err = err; method = method } - end - vim.lsp._unsupported_method = function(method) - vim.lsp._last_unsupported_method = method - return 'fake-error' - end - vim.lsp.buf.type_definition() + vim.lsp.handlers['textDocument/typeDefinition'] = function() end ]=]) end; on_init = function(client) client.stop() - local method = exec_lua("return vim.lsp._last_unsupported_method") - eq("textDocument/typeDefinition", method) - local lsp_cb_call = exec_lua("return vim.lsp._last_lsp_handler") - eq("fake-error", lsp_cb_call.err) - eq("textDocument/typeDefinition", lsp_cb_call.method) + exec_lua("vim.lsp.buf.type_definition()") exec_lua [[ vim.api.nvim_command(BUFFER.."bwipeout") ]] @@ -447,7 +435,7 @@ describe('LSP', function() } end) - it('shouldn\'t call unsupported_method when no client and trying to call an unsupported method', function() + it('should not call unsupported_method when no client and trying to call an unsupported method', function() local expected_handlers = { {NIL, {}, {method="shutdown", client_id=1}}; } @@ -455,20 +443,12 @@ describe('LSP', function() test_name = "capabilities_for_client_supports_method"; on_setup = function() exec_lua([=[ - vim.lsp.handlers['textDocument/typeDefinition'] = function(err, method) - vim.lsp._last_lsp_handler = { err = err; method = method } - end - vim.lsp._unsupported_method = function(method) - vim.lsp._last_unsupported_method = method - return 'fake-error' - end - vim.lsp.buf.type_definition() + vim.lsp.handlers['textDocument/typeDefinition'] = function() end ]=]) end; on_init = function(client) client.stop() - eq(NIL, exec_lua("return vim.lsp._last_unsupported_method")) - eq(NIL, exec_lua("return vim.lsp._last_lsp_handler")) + exec_lua("vim.lsp.buf.type_definition()") end; on_exit = function(code, signal) eq(0, code, "exit code", fake_lsp_logfile) @@ -480,6 +460,55 @@ describe('LSP', function() } end) + it('should not forward RequestCancelled to callback', function() + local expected_handlers = { + {NIL, {}, {method="finish", client_id=1}}; + } + local client + test_rpc_server { + test_name = "check_forward_request_cancelled"; + on_init = function(_client) + _client.request("error_code_test") + client = _client + end; + on_exit = function(code, signal) + eq(0, code, "exit code", fake_lsp_logfile) + eq(0, signal, "exit signal", fake_lsp_logfile) + eq(0, #expected_handlers, "did not call expected handler") + end; + on_handler = function(err, _, ctx) + eq(table.remove(expected_handlers), {err, {}, ctx}, "expected handler") + if ctx.method == 'finish' then client.stop() end + end; + } + end) + + it('should forward ContentModified to callback', function() + local expected_handlers = { + {NIL, {}, {method="finish", client_id=1}}; + {{code = -32801}, NIL, {method = "error_code_test", client_id=1}}; + } + local client + test_rpc_server { + test_name = "check_forward_content_modified"; + on_init = function(_client) + _client.request("error_code_test") + client = _client + end; + on_exit = function(code, signal) + eq(0, code, "exit code", fake_lsp_logfile) + eq(0, signal, "exit signal", fake_lsp_logfile) + eq(0, #expected_handlers, "did not call expected handler") + end; + on_handler = function(err, _, ctx) + eq(table.remove(expected_handlers), {err, _, ctx}, "expected handler") + -- if ctx.method == 'error_code_test' then client.notify("finish") end + if ctx.method ~= 'finish' then client.notify('finish') end + if ctx.method == 'finish' then client.stop() end + end; + } + end) + it('should not send didOpen if the buffer closes before init', function() local expected_handlers = { {NIL, {}, {method="shutdown", client_id=1}}; @@ -1135,10 +1164,11 @@ describe('LSP', function() eq({ 2, 6 }, funcs.nvim_win_get_cursor(0)) end) - it('fix the cursor to the valid column if the content was removed', function() + it('fix the cursor to the valid col if the content was removed', function() funcs.nvim_win_set_cursor(0, { 2, 6 }) local edits = { - make_edit(1, 0, 1, 19, '') + make_edit(1, 0, 1, 6, ''), + make_edit(1, 6, 1, 19, '') } exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1) eq({ @@ -1151,6 +1181,19 @@ describe('LSP', function() eq({ 2, 0 }, funcs.nvim_win_get_cursor(0)) end) + it('fix the cursor to the valid row if the content was removed', function() + funcs.nvim_win_set_cursor(0, { 2, 6 }) + local edits = { + make_edit(1, 0, 1, 6, ''), + make_edit(0, 18, 5, 0, '') + } + exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1) + eq({ + 'First line of text'; + }, buf_lines(1)) + eq({ 1, 6 }, funcs.nvim_win_get_cursor(0)) + end) + it('fix the cursor row', function() funcs.nvim_win_set_cursor(0, { 3, 0 }) local edits = { @@ -2022,83 +2065,6 @@ describe('LSP', function() end) end) - describe('lsp.util.make_floating_popup_options', function() - before_each(function() - exec_lua [[ - local bufnr = vim.uri_to_bufnr("file:///fake/uri") - local winheight = vim.fn.winheight(0) - for i = 1, winheight do - vim.api.nvim_buf_set_lines(bufnr, 0, 0, false, {''}) - end - vim.api.nvim_win_set_buf(0, bufnr) - vim.api.nvim_win_set_cursor(0, {winheight, 0}) - ]] - end) - - local function popup_row(opts) - return exec_lua([[ - return vim.lsp.util.make_floating_popup_options(...).row - ]], 2, 2, opts) - end - - local err_pattern = "^Error executing lua: %.%.%./util%.lua:0: invalid floating preview border: .*%. :help vim%.api%.nvim_open_win%(%)$" - - it('calculates default border height correctly', function() - eq(0, popup_row()) - end) - - it('calculates string border height correctly', function() - eq(0, popup_row({border = 'none'})) - eq(-2, popup_row({border = 'single'})) - eq(-2, popup_row({border = 'double'})) - eq(-2, popup_row({border = 'rounded'})) - eq(-2, popup_row({border = 'solid'})) - eq(-1, popup_row({border = 'shadow'})) - end) - - it('error on invalid string border', function() - matches(err_pattern, pcall_err(popup_row, {border = ''})) - matches(err_pattern, pcall_err(popup_row, {border = 'invalid'})) - end) - - it('error on invalid array border length', function() - matches(err_pattern, pcall_err(popup_row, {border = {}})) - matches(err_pattern, pcall_err(popup_row, {border = {'', '', ''}})) - matches(err_pattern, pcall_err(popup_row, {border = {'', '', '', '', ''}})) - end) - - it('error on invalid array border member type', function() - matches(err_pattern, pcall_err(popup_row, {border = {0}})) - end) - - it('calculates 8-array border height correctly', function() - eq(0, popup_row({border = {'', '', '', '', '', '', '', ''}})) - eq(-2, popup_row({border = {'', '~', '', '~', '', '~', '', '~'}})) - eq(-1, popup_row({border = {'', '', '', '~', '', '~', '', ''}})) - eq(0, popup_row({border = {'', '', '', {'~', 'NormalFloat'}, '', '', '', {'~', 'NormalFloat'}}})) - eq(-2, popup_row({border = {'', {'~', 'NormalFloat'}, '', '', '', {'~', 'NormalFloat'}, '', ''}})) - end) - - it('calculates 4-array border height correctly', function() - eq(0, popup_row({border = {'', '', '', ''}})) - eq(-2, popup_row({border = {'', '~', '', '~'}})) - eq(0, popup_row({border = {'', '', '', {'~', 'NormalFloat'}}})) - eq(-2, popup_row({border = {'', {'~', 'NormalFloat'}, '', ''}})) - end) - - it('calculates 2-array border height correctly', function() - eq(0, popup_row({border = {'', ''}})) - eq(-2, popup_row({border = {'', '~'}})) - eq(-2, popup_row({border = {'', {'~', 'NormalFloat'}}})) - end) - - it('calculates 1-array border height correctly', function() - eq(0, popup_row({border = {''}})) - eq(-2, popup_row({border = {'~'}})) - eq(-2, popup_row({border = {{'~', 'NormalFloat'}}})) - end) - end) - describe('lsp.util._make_floating_popup_size', function() before_each(function() exec_lua [[ contents = @@ -2353,6 +2319,10 @@ describe('LSP', function() eq(0, signal, "exit signal", fake_lsp_logfile) end; on_handler = function(err, result, ctx) + -- Don't compare & assert params, they're not relevant for the testcase + -- This allows us to be lazy and avoid declaring them + ctx.params = nil + eq(table.remove(test.expected_handlers), {err, result, ctx}, "expected handler") if ctx.method == 'start' then exec_lua("vim.lsp.buf.rename()") @@ -2370,4 +2340,59 @@ describe('LSP', function() end end) + describe('vim.lsp.buf.code_action', function() + it('Calls client side command if available', function() + local client + local expected_handlers = { + {NIL, {}, {method="shutdown", client_id=1}}; + {NIL, {}, {method="start", client_id=1}}; + } + test_rpc_server { + test_name = 'code_action_with_resolve', + on_init = function(client_) + client = client_ + end, + on_setup = function() + 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}) + if ctx.method == 'start' then + exec_lua([[ + vim.lsp.commands['dummy1'] = function(cmd) + vim.lsp.commands['dummy2'] = function() + end + end + local bufnr = vim.api.nvim_get_current_buf() + vim.lsp.buf_attach_client(bufnr, TEST_RPC_CLIENT_ID) + vim.fn.inputlist = function() + return 1 + end + vim.lsp.buf.code_action() + ]]) + elseif ctx.method == 'shutdown' then + eq('function', exec_lua[[return type(vim.lsp.commands['dummy2'])]]) + client.stop() + end + end + } + end) + end) + describe('vim.lsp.commands', function() + it('Accepts only string keys', function() + matches( + '.*The key for commands in `vim.lsp.commands` must be a string', + pcall_err(exec_lua, 'vim.lsp.commands[1] = function() end') + ) + end) + it('Accepts only function values', function() + matches( + '.*Command added to `vim.lsp.commands` must be a function', + pcall_err(exec_lua, 'vim.lsp.commands.dummy = 10') + ) + end) + end) end) |