diff options
Diffstat (limited to 'test/functional/plugin')
-rw-r--r-- | test/functional/plugin/health_spec.lua | 157 | ||||
-rw-r--r-- | test/functional/plugin/lsp/codelens_spec.lua | 28 | ||||
-rw-r--r-- | test/functional/plugin/lsp/diagnostic_spec.lua | 26 | ||||
-rw-r--r-- | test/functional/plugin/lsp_spec.lua | 295 |
4 files changed, 333 insertions, 173 deletions
diff --git a/test/functional/plugin/health_spec.lua b/test/functional/plugin/health_spec.lua index 85c67be8f9..b84e9d1533 100644 --- a/test/functional/plugin/health_spec.lua +++ b/test/functional/plugin/health_spec.lua @@ -1,4 +1,5 @@ local helpers = require('test.functional.helpers')(after_each) +local global_helpers = require('test.helpers') local Screen = require('test.functional.ui.screen') local clear = helpers.clear @@ -35,6 +36,7 @@ describe(':checkhealth', function() clear() eq('nvim', getcompletion('nvim', 'checkhealth')[1]) eq('provider', getcompletion('prov', 'checkhealth')[1]) + eq('vim.lsp', getcompletion('vim.ls', 'checkhealth')[1]) end) end) @@ -48,42 +50,34 @@ describe('health.vim', function() command("set runtimepath+=test/functional/fixtures") end) - it("health#report_*()", function() - helpers.source([[ - let g:health_report = execute([ - \ "call health#report_start('Check Bar')", - \ "call health#report_ok('Bar status')", - \ "call health#report_ok('Other Bar status')", - \ "call health#report_warn('Zub')", - \ "call health#report_start('Baz')", - \ "call health#report_warn('Zim', ['suggestion 1', 'suggestion 2'])" - \ ]) - ]]) - local result = helpers.eval("g:health_report") - - helpers.eq(helpers.dedent([[ - - - ## Check Bar - - OK: Bar status - - OK: Other Bar status - - WARNING: Zub - - ## Baz - - WARNING: Zim + describe(":checkhealth", function() + it("functions health#report_*() render correctly", function() + command("checkhealth full_render") + helpers.expect([[ + + full_render: health#full_render#check + ======================================================================== + ## report 1 + - OK: life is fine + - WARNING: no what installed - ADVICE: - - suggestion 1 - - suggestion 2]]), - result) - end) + - pip what + - make what + ## report 2 + - INFO: stuff is stable + - ERROR: why no hardcopy + - ADVICE: + - :help |:hardcopy| + - :help |:TOhtml| + ]]) + end) - describe(":checkhealth", function() it("concatenates multiple reports", function() - command("checkhealth success1 success2") + command("checkhealth success1 success2 test_plug") helpers.expect([[ - health#success1#check + success1: health#success1#check ======================================================================== ## report 1 - OK: everything is fine @@ -91,25 +85,111 @@ describe('health.vim', function() ## report 2 - OK: nothing to see here - health#success2#check + success2: health#success2#check ======================================================================== ## another 1 - OK: ok + + test_plug: require("test_plug.health").check() + ======================================================================== + ## report 1 + - OK: everything is fine + + ## report 2 + - OK: nothing to see here + ]]) + end) + + it("lua plugins, skips vimscript healthchecks with the same name", function() + command("checkhealth test_plug") + -- Existing file in test/functional/fixtures/lua/test_plug/autoload/health/test_plug.vim + -- and the Lua healthcheck is used instead. + helpers.expect([[ + + test_plug: require("test_plug.health").check() + ======================================================================== + ## report 1 + - OK: everything is fine + + ## report 2 + - OK: nothing to see here ]]) end) + it("lua plugins submodules", function() + command("checkhealth test_plug.submodule") + helpers.expect([[ + + test_plug.submodule: require("test_plug.submodule.health").check() + ======================================================================== + ## report 1 + - OK: everything is fine + + ## report 2 + - OK: nothing to see here + ]]) + end) + + it("lua plugins submodules with expression '*'", function() + command("checkhealth test_plug*") + local buf_lines = helpers.curbuf('get_lines', 0, -1, true) + -- avoid dealing with path separators + local received = table.concat(buf_lines, '\n', 1, #buf_lines - 2) + local expected = helpers.dedent([[ + + test_plug: require("test_plug.health").check() + ======================================================================== + ## report 1 + - OK: everything is fine + + ## report 2 + - OK: nothing to see here + + test_plug.submodule: require("test_plug.submodule.health").check() + ======================================================================== + ## report 1 + - OK: everything is fine + + ## report 2 + - OK: nothing to see here + + 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]]) + eq(expected, received) + end) + it("gracefully handles broken healthcheck", function() command("checkhealth broken") helpers.expect([[ - health#broken#check + broken: health#broken#check ======================================================================== - ERROR: Failed to run healthcheck for "broken" plugin. Exception: - function health#check[21]..health#broken#check, line 1 + function health#check[24]..health#broken#check, line 1 caused an error ]]) end) + it("gracefully handles broken lua healthcheck", function() + command("checkhealth test_plug.submodule_failed") + local buf_lines = helpers.curbuf('get_lines', 0, -1, true) + local received = table.concat(buf_lines, '\n', 1, #buf_lines - 2) + -- avoid dealing with path separators + local lua_err = "attempt to perform arithmetic on a nil value" + local last_line = buf_lines[#buf_lines - 1] + assert(string.find(last_line, lua_err) ~= nil, "Lua error not present") + + local expected = global_helpers.dedent([[ + + 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]]) + eq(expected, received) + end) + it("highlights OK, ERROR", function() local screen = Screen.new(72, 10) screen:attach() @@ -126,23 +206,24 @@ describe('health.vim', function() command("set laststatus=0") screen:expect{grid=[[ ^ | - {Heading:health#foo#check} | + {Heading:foo: } | {Bar:========================================================================}| - {Bullet: -} {Error:ERROR:} No healthcheck found for "foo" plugin. | + {Bullet: -} {Error:ERROR}: No healthcheck found for "foo" plugin. | | - {Heading:health#success1#check} | + {Heading:success1: health#success1#check} | {Bar:========================================================================}| {Heading2:##}{Heading: report 1} | - {Bullet: -} {Ok:OK:} everything is fine | + {Bullet: -} {Ok:OK}: everything is fine | | ]]} end) it("gracefully handles invalid healthcheck", function() command("checkhealth non_existent_healthcheck") + -- luacheck: ignore 613 helpers.expect([[ - health#non_existent_healthcheck#check + non_existent_healthcheck: ======================================================================== - ERROR: No healthcheck found for "non_existent_healthcheck" plugin. ]]) diff --git a/test/functional/plugin/lsp/codelens_spec.lua b/test/functional/plugin/lsp/codelens_spec.lua index e48a0ad260..c8b75e65fc 100644 --- a/test/functional/plugin/lsp/codelens_spec.lua +++ b/test/functional/plugin/lsp/codelens_spec.lua @@ -58,5 +58,33 @@ describe('vim.lsp.codelens', function() ]], bufnr) eq({[1] = {'Lens1', 'LspCodeLens'}}, virtual_text_chunks) + + end) + it('codelens uses client commands', function() + local fake_uri = "file:///fake/uri" + local cmd = exec_lua([[ + fake_uri = ... + local bufnr = vim.uri_to_bufnr(fake_uri) + vim.fn.bufload(bufnr) + vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, {'One line'}) + local lenses = { + { + range = { + start = { line = 0, character = 0, }, + ['end'] = { line = 0, character = 8 } + }, + command = { title = 'Lens1', command = 'Dummy' } + }, + } + vim.lsp.codelens.on_codelens(nil, lenses, {method='textDocument/codeLens', client_id=1, bufnr=bufnr}) + local cmd_called = nil + vim.lsp.commands['Dummy'] = function(command) + cmd_called = command + end + vim.api.nvim_set_current_buf(bufnr) + vim.lsp.codelens.run() + return cmd_called + ]], fake_uri) + eq({ command = 'Dummy', title = 'Lens1' }, cmd) end) end) diff --git a/test/functional/plugin/lsp/diagnostic_spec.lua b/test/functional/plugin/lsp/diagnostic_spec.lua index 353de667ea..243ad6bdb8 100644 --- a/test/functional/plugin/lsp/diagnostic_spec.lua +++ b/test/functional/plugin/lsp/diagnostic_spec.lua @@ -428,6 +428,32 @@ describe('vim.lsp.diagnostic', function() end) end) end) + + it('maintains LSP information when translating diagnostics', function() + local result = exec_lua [[ + local diagnostics = { + make_error("Error 1", 1, 1, 1, 5), + } + + diagnostics[1].code = 42 + diagnostics[1].tags = {"foo", "bar"} + diagnostics[1].data = "Hello world" + + vim.lsp.diagnostic.on_publish_diagnostics(nil, { + uri = fake_uri, + diagnostics = diagnostics, + }, {client_id=1}) + + return { + vim.diagnostic.get(diagnostic_bufnr, {lnum=1})[1], + vim.lsp.diagnostic.get_line_diagnostics(diagnostic_bufnr, 1)[1], + } + ]] + eq({code = 42, tags = {"foo", "bar"}, data = "Hello world"}, result[1].user_data.lsp) + eq(42, result[2].code) + eq({"foo", "bar"}, result[2].tags) + eq("Hello world", result[2].data) + end) end) describe("vim.lsp.diagnostic.get_line_diagnostics", function() 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) |