From a330129a280a34963e42d498f7cb1f53e6723e85 Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Sat, 12 Oct 2019 13:29:51 +0200 Subject: tests/ui: cleanup illegitimate usages of "attr_ignore" "attr_ignore" is an anti-pattern, with snapshot_util() just include all the highlights already. --- test/functional/plugin/health_spec.lua | 20 ++++++-------- test/functional/plugin/man_spec.lua | 50 ++++++++++++++++------------------ 2 files changed, 33 insertions(+), 37 deletions(-) (limited to 'test/functional/plugin') diff --git a/test/functional/plugin/health_spec.lua b/test/functional/plugin/health_spec.lua index 3525e235de..a78ed07876 100644 --- a/test/functional/plugin/health_spec.lua +++ b/test/functional/plugin/health_spec.lua @@ -116,8 +116,6 @@ describe('health.vim', function() screen:set_default_attr_ids({ Ok = { foreground = Screen.colors.Grey3, background = 6291200 }, Error = { foreground = Screen.colors.Grey100, background = Screen.colors.Red }, - }) - screen:set_default_attr_ignore({ Heading = { bold=true, foreground=Screen.colors.Magenta }, Heading2 = { foreground = Screen.colors.SlateBlue }, Bar = { foreground=Screen.colors.Purple }, @@ -126,18 +124,18 @@ describe('health.vim', function() command("checkhealth foo success1") command("1tabclose") command("set laststatus=0") - screen:expect([[ + screen:expect{grid=[[ ^ | - health#foo#check | - ========================================================================| - - {Error:ERROR:} No healthcheck found for "foo" plugin. | + {Heading:health#foo#check} | + {Bar:========================================================================}| + {Bullet: -} {Error:ERROR:} No healthcheck found for "foo" plugin. | | - health#success1#check | - ========================================================================| - ## report 1 | - - {Ok:OK:} everything is fine | + {Heading:health#success1#check} | + {Bar:========================================================================}| + {Heading2:##}{Heading: report 1} | + {Bullet: -} {Ok:OK:} everything is fine | | - ]]) + ]]} end) it("gracefully handles invalid healthcheck", function() diff --git a/test/functional/plugin/man_spec.lua b/test/functional/plugin/man_spec.lua index d95995797e..e06e4b874e 100644 --- a/test/functional/plugin/man_spec.lua +++ b/test/functional/plugin/man_spec.lua @@ -19,10 +19,8 @@ describe(':Man', function() u = { underline = true }, bi = { bold = true, italic = true }, biu = { bold = true, italic = true, underline = true }, - }) - screen:set_default_attr_ignore({ - { foreground = Screen.colors.Blue }, -- control chars - { bold = true, foreground = Screen.colors.Blue } -- empty line '~'s + c = { foreground = Screen.colors.Blue }, -- control chars + eob = { bold = true, foreground = Screen.colors.Blue } -- empty line '~'s }) screen:attach() end) @@ -36,21 +34,21 @@ describe(':Man', function() ithis iiss aa test with _o_v_e_r_s_t_r_u_c_k text]]) - screen:expect([[ - this i^His^Hs a^Ha test | - with _^Ho_^Hv_^He_^Hr_^Hs_^Ht_^Hr_^Hu_^Hc_^Hk tex^t | - ~ | - ~ | - | - ]]) + screen:expect{grid=[[ + this i{c:^H}is{c:^H}s a{c:^H}a test | + with _{c:^H}o_{c:^H}v_{c:^H}e_{c:^H}r_{c:^H}s_{c:^H}t_{c:^H}r_{c:^H}u_{c:^H}c_{c:^H}k tex^t | + {eob:~ }| + {eob:~ }| + | + ]]} eval('man#init_pager()') screen:expect([[ ^this {b:is} {b:a} test | with {u:overstruck} text | - ~ | - ~ | + {eob:~ }| + {eob:~ }| | ]]) end) @@ -60,21 +58,21 @@ describe(':Man', function() ithis [1mis [3ma [4mtest[0m [4mwith[24m [4mescaped[24m [4mtext[24m]]) - screen:expect([=[ - this ^[[1mis ^[[3ma ^[[4mtest^[[0m | - ^[[4mwith^[[24m ^[[4mescaped^[[24m ^[[4mtext^[[24^m | - ~ | - ~ | - | - ]=]) + screen:expect{grid=[=[ + this {c:^[}[1mis {c:^[}[3ma {c:^[}[4mtest{c:^[}[0m | + {c:^[}[4mwith{c:^[}[24m {c:^[}[4mescaped{c:^[}[24m {c:^[}[4mtext{c:^[}[24^m | + {eob:~ }| + {eob:~ }| + | + ]=]} eval('man#init_pager()') screen:expect([[ ^this {b:is }{bi:a }{biu:test} | {u:with} {u:escaped} {u:text} | - ~ | - ~ | + {eob:~ }| + {eob:~ }| | ]]) end) @@ -88,8 +86,8 @@ describe(':Man', function() screen:expect([[ ^this {b:is} {b:あ} test | with {u:överstrũck} te{i:xt¶} | - ~ | - ~ | + {eob:~ }| + {eob:~ }| | ]]) end) @@ -105,7 +103,7 @@ describe(':Man', function() {b:^_begins} | {b:mid_dle} | {u:mid_dle} | - ~ | + {eob:~ }| | ]]) end) @@ -121,7 +119,7 @@ describe(':Man', function() ^· {b:·} | {b:·} | {b:·} double | - ~ | + {eob:~ }| | ]]) end) -- cgit From 4987311fb5b8f4a11d26995f71f5f402a9e2ace4 Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Sun, 13 Oct 2019 20:18:22 +0200 Subject: tests/ui: remove unnecessary screen:detach() It is perfectly fine and expected to detach from the screen just by the UI disconnecting from nvim or exiting nvim. Just keep detach() in screen_basic_spec, to get some coverage of the detach method itself. This avoids hang on failure in many situations (though one could argue that detach() should be "fast", or at least "as fast as resize", which works in press-return already). Never use detach() just to change the size of the screen, try_resize() method exists for that specifically. --- test/functional/plugin/man_spec.lua | 4 ---- 1 file changed, 4 deletions(-) (limited to 'test/functional/plugin') diff --git a/test/functional/plugin/man_spec.lua b/test/functional/plugin/man_spec.lua index e06e4b874e..e5b2e7dc1f 100644 --- a/test/functional/plugin/man_spec.lua +++ b/test/functional/plugin/man_spec.lua @@ -25,10 +25,6 @@ describe(':Man', function() screen:attach() end) - after_each(function() - screen:detach() - end) - it('clears backspaces from text and adds highlights', function() rawfeed([[ ithis iiss aa test -- cgit From 00dc12c5d8454a2d3c6806710f63bbb446076e96 Mon Sep 17 00:00:00 2001 From: Ashkan Kiani Date: Wed, 13 Nov 2019 12:55:26 -0800 Subject: lua LSP client: initial implementation (#11336) Mainly configuration and RPC infrastructure can be considered "done". Specific requests and their callbacks will be improved later (and also served by plugins). There are also some TODO:s for the client itself, like incremental updates. Co-authored by at-tjdevries and at-h-michael, with many review/suggestion contributions. --- test/functional/plugin/lsp/lsp_spec.lua | 634 ++++++++++++++++++++++++++++++++ 1 file changed, 634 insertions(+) create mode 100644 test/functional/plugin/lsp/lsp_spec.lua (limited to 'test/functional/plugin') diff --git a/test/functional/plugin/lsp/lsp_spec.lua b/test/functional/plugin/lsp/lsp_spec.lua new file mode 100644 index 0000000000..cd0974b81c --- /dev/null +++ b/test/functional/plugin/lsp/lsp_spec.lua @@ -0,0 +1,634 @@ +local helpers = require('test.functional.helpers')(after_each) + +local clear = helpers.clear +local exec_lua = helpers.exec_lua +local eq = helpers.eq +local NIL = helpers.NIL + +-- Use these to get access to a coroutine so that I can run async tests and use +-- yield. +local run, stop = helpers.run, helpers.stop + +if helpers.pending_win32(pending) then return end + +local is_windows = require'luv'.os_uname().sysname == "Windows" +local lsp_test_rpc_server_file = "test/functional/fixtures/lsp-test-rpc-server.lua" +if is_windows then + lsp_test_rpc_server_file = lsp_test_rpc_server_file:gsub("/", "\\") +end + +local function test_rpc_server_setup(test_name, timeout_ms) + exec_lua([=[ + lsp = require('vim.lsp') + local test_name, fixture_filename, timeout = ... + TEST_RPC_CLIENT_ID = lsp.start_client { + cmd = { + vim.api.nvim_get_vvar("progpath"), '-Es', '-u', 'NONE', '--headless', + "-c", string.format("lua TEST_NAME = %q", test_name), + "-c", string.format("lua TIMEOUT = %d", timeout), + "-c", "luafile "..fixture_filename, + }; + callbacks = setmetatable({}, { + __index = function(t, method) + return function(...) + return vim.rpcrequest(1, 'callback', ...) + end + end; + }); + root_dir = vim.loop.cwd(); + on_init = function(client, result) + TEST_RPC_CLIENT = client + vim.rpcrequest(1, "init", result) + end; + on_exit = function(...) + vim.rpcnotify(1, "exit", ...) + end; + } + ]=], test_name, lsp_test_rpc_server_file, timeout_ms or 1e3) +end + +local function test_rpc_server(config) + if config.test_name then + clear() + test_rpc_server_setup(config.test_name, config.timeout_ms or 1e3) + end + local client = setmetatable({}, { + __index = function(_, name) + -- Workaround for not being able to yield() inside __index for Lua 5.1 :( + -- Otherwise I would just return the value here. + return function(...) + return exec_lua([=[ + local name = ... + if type(TEST_RPC_CLIENT[name]) == 'function' then + return TEST_RPC_CLIENT[name](select(2, ...)) + else + return TEST_RPC_CLIENT[name] + end + ]=], name, ...) + end + end; + }) + local code, signal + local function on_request(method, args) + if method == "init" then + if config.on_init then + config.on_init(client, unpack(args)) + end + return NIL + end + if method == 'callback' then + if config.on_callback then + config.on_callback(unpack(args)) + end + end + return NIL + end + local function on_notify(method, args) + if method == 'exit' then + code, signal = unpack(args) + return stop() + end + end + -- TODO specify timeout? + -- run(on_request, on_notify, config.on_setup, 1000) + run(on_request, on_notify, config.on_setup) + if config.on_exit then + config.on_exit(code, signal) + end + stop() + if config.test_name then + exec_lua("lsp._vim_exit_handler()") + end +end + +describe('Language Client API', function() + describe('server_name is specified', function() + before_each(function() + clear() + -- 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 = ... + TEST_RPC_CLIENT_ID = lsp.start_client { + cmd = { + vim.api.nvim_get_vvar("progpath"), '-Es', '-u', 'NONE', '--headless', + "-c", string.format("lua TEST_NAME = %q", test_name), + "-c", "luafile "..fixture_filename; + }; + root_dir = vim.loop.cwd(); + } + ]=], test_name, lsp_test_rpc_server_file) + end) + + after_each(function() + exec_lua("lsp._vim_exit_handler()") + -- exec_lua("lsp.stop_all_clients(true)") + end) + + describe('start_client and stop_client', function() + it('should return true', function() + for _ = 1, 20 do + helpers.sleep(10) + if exec_lua("return #lsp.get_active_clients()") > 0 then + break + end + end + eq(1, exec_lua("return #lsp.get_active_clients()")) + eq(false, exec_lua("return lsp.get_client_by_id(TEST_RPC_CLIENT_ID) == nil")) + eq(false, exec_lua("return lsp.get_client_by_id(TEST_RPC_CLIENT_ID).is_stopped()")) + exec_lua("return lsp.get_client_by_id(TEST_RPC_CLIENT_ID).stop()") + eq(false, exec_lua("return lsp.get_client_by_id(TEST_RPC_CLIENT_ID).is_stopped()")) + for _ = 1, 20 do + helpers.sleep(10) + if exec_lua("return #lsp.get_active_clients()") == 0 then + break + end + end + eq(true, exec_lua("return lsp.get_client_by_id(TEST_RPC_CLIENT_ID) == nil")) + end) + end) + end) + + describe('basic_init test', function() + it('should run correctly', function() + local expected_callbacks = { + {NIL, "test", {}, 1}; + } + test_rpc_server { + test_name = "basic_init"; + on_init = function(client, _init_result) + -- client is a dummy object which will queue up commands to be run + -- once the server initializes. It can't accept lua callbacks or + -- other types that may be unserializable for now. + client.stop() + end; + -- If the program timed out, then code will be nil. + on_exit = function(code, signal) + eq(0, code, "exit code") eq(0, signal, "exit signal") + end; + -- Note that NIL must be used here. + -- on_callback(err, method, result, client_id) + on_callback = function(...) + eq(table.remove(expected_callbacks), {...}) + end; + } + end) + + it('should fail', function() + local expected_callbacks = { + {NIL, "test", {}, 1}; + } + test_rpc_server { + test_name = "basic_init"; + on_init = function(client) + client.notify('test') + client.stop() + end; + on_exit = function(code, signal) + eq(1, code, "exit code") eq(0, signal, "exit signal") + end; + on_callback = function(...) + eq(table.remove(expected_callbacks), {...}, "expected callback") + end; + } + end) + + it('should succeed with manual shutdown', function() + local expected_callbacks = { + {NIL, "shutdown", {}, 1}; + {NIL, "test", {}, 1}; + } + test_rpc_server { + test_name = "basic_init"; + on_init = function(client) + eq(0, client.resolved_capabilities().text_document_did_change) + client.request('shutdown') + client.notify('exit') + end; + on_exit = function(code, signal) + eq(0, code, "exit code") eq(0, signal, "exit signal") + end; + on_callback = function(...) + eq(table.remove(expected_callbacks), {...}, "expected callback") + end; + } + end) + + it('should verify capabilities sent', function() + local expected_callbacks = { + {NIL, "shutdown", {}, 1}; + } + test_rpc_server { + test_name = "basic_check_capabilities"; + on_init = function(client) + client.stop() + end; + on_exit = function(code, signal) + eq(0, code, "exit code") eq(0, signal, "exit signal") + end; + on_callback = function(...) + eq(table.remove(expected_callbacks), {...}, "expected callback") + end; + } + end) + + it('should not send didOpen if the buffer closes before init', function() + local expected_callbacks = { + {NIL, "shutdown", {}, 1}; + {NIL, "finish", {}, 1}; + } + local client + test_rpc_server { + test_name = "basic_finish"; + 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"; + }) + ]] + eq(1, exec_lua("return TEST_RPC_CLIENT_ID")) + 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 + local full_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Full") + eq(full_kind, client.resolved_capabilities().text_document_did_change) + eq(true, client.resolved_capabilities().text_document_open_close) + client.notify('finish') + end; + on_exit = function(code, signal) + eq(0, code, "exit code") eq(0, signal, "exit signal") + end; + on_callback = function(err, method, params, client_id) + eq(table.remove(expected_callbacks), {err, method, params, client_id}, "expected callback") + if method == 'finish' then + client.stop() + end + end; + } + end) + + it('should check the body sent attaching before init', function() + local expected_callbacks = { + {NIL, "shutdown", {}, 1}; + {NIL, "finish", {}, 1}; + {NIL, "start", {}, 1}; + } + local client + test_rpc_server { + test_name = "basic_check_buffer_open"; + 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"; + }) + ]] + exec_lua [[ + assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)) + ]] + end; + on_init = function(_client) + client = _client + local full_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Full") + eq(full_kind, client.resolved_capabilities().text_document_did_change) + eq(true, client.resolved_capabilities().text_document_open_close) + exec_lua [[ + assert(not lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID), "Shouldn't attach twice") + ]] + end; + on_exit = function(code, signal) + eq(0, code, "exit code") eq(0, signal, "exit signal") + end; + on_callback = function(err, method, params, client_id) + if method == 'start' then + client.notify('finish') + end + eq(table.remove(expected_callbacks), {err, method, params, client_id}, "expected callback") + if method == 'finish' then + client.stop() + end + end; + } + end) + + it('should check the body sent attaching after init', function() + local expected_callbacks = { + {NIL, "shutdown", {}, 1}; + {NIL, "finish", {}, 1}; + {NIL, "start", {}, 1}; + } + local client + test_rpc_server { + test_name = "basic_check_buffer_open"; + 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 full_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Full") + eq(full_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") eq(0, signal, "exit signal") + end; + on_callback = function(err, method, params, client_id) + if method == 'start' then + client.notify('finish') + end + eq(table.remove(expected_callbacks), {err, method, params, client_id}, "expected callback") + if method == 'finish' then + client.stop() + end + end; + } + end) + + it('should check the body and didChange full', function() + local expected_callbacks = { + {NIL, "shutdown", {}, 1}; + {NIL, "finish", {}, 1}; + {NIL, "start", {}, 1}; + } + local client + test_rpc_server { + test_name = "basic_check_buffer_open_and_change"; + 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 full_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Full") + eq(full_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") eq(0, signal, "exit signal") + end; + on_callback = function(err, method, params, client_id) + if method == 'start' then + exec_lua [[ + vim.api.nvim_buf_set_lines(BUFFER, 1, 2, false, { + "boop"; + }) + ]] + client.notify('finish') + end + eq(table.remove(expected_callbacks), {err, method, params, client_id}, "expected callback") + if method == 'finish' then + client.stop() + end + end; + } + end) + + -- TODO(askhan) we don't support full for now, so we can disable these tests. + pending('should check the body and didChange incremental', function() + local expected_callbacks = { + {NIL, "shutdown", {}, 1}; + {NIL, "finish", {}, 1}; + {NIL, "start", {}, 1}; + } + local client + test_rpc_server { + test_name = "basic_check_buffer_open_and_change_incremental"; + 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") eq(0, signal, "exit signal") + end; + on_callback = function(err, method, params, client_id) + if method == 'start' then + exec_lua [[ + vim.api.nvim_buf_set_lines(BUFFER, 1, 2, false, { + "boop"; + }) + ]] + client.notify('finish') + end + eq(table.remove(expected_callbacks), {err, method, params, client_id}, "expected callback") + if method == 'finish' then + client.stop() + end + end; + } + end) + + -- TODO(askhan) we don't support full for now, so we can disable these tests. + pending('should check the body and didChange incremental normal mode editting', function() + local expected_callbacks = { + {NIL, "shutdown", {}, 1}; + {NIL, "finish", {}, 1}; + {NIL, "start", {}, 1}; + } + local client + test_rpc_server { + test_name = "basic_check_buffer_open_and_change_incremental_editting"; + 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") eq(0, signal, "exit signal") + end; + on_callback = function(err, method, params, client_id) + if method == 'start' then + helpers.command("normal! 1Go") + client.notify('finish') + end + eq(table.remove(expected_callbacks), {err, method, params, client_id}, "expected callback") + if method == 'finish' then + client.stop() + end + end; + } + end) + + it('should check the body and didChange full with 2 changes', function() + local expected_callbacks = { + {NIL, "shutdown", {}, 1}; + {NIL, "finish", {}, 1}; + {NIL, "start", {}, 1}; + } + local client + test_rpc_server { + test_name = "basic_check_buffer_open_and_change_multi"; + 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.Full") + 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") eq(0, signal, "exit signal") + end; + on_callback = function(err, method, params, client_id) + if method == 'start' then + exec_lua [[ + vim.api.nvim_buf_set_lines(BUFFER, 1, 2, false, { + "321"; + }) + vim.api.nvim_buf_set_lines(BUFFER, 1, 2, false, { + "boop"; + }) + ]] + client.notify('finish') + end + eq(table.remove(expected_callbacks), {err, method, params, client_id}, "expected callback") + if method == 'finish' then + client.stop() + end + end; + } + end) + + it('should check the body and didChange full lifecycle', function() + local expected_callbacks = { + {NIL, "shutdown", {}, 1}; + {NIL, "finish", {}, 1}; + {NIL, "start", {}, 1}; + } + local client + test_rpc_server { + test_name = "basic_check_buffer_open_and_change_multi_and_close"; + 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.Full") + 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") eq(0, signal, "exit signal") + end; + on_callback = function(err, method, params, client_id) + if method == 'start' then + exec_lua [[ + vim.api.nvim_buf_set_lines(BUFFER, 1, 2, false, { + "321"; + }) + vim.api.nvim_buf_set_lines(BUFFER, 1, 2, false, { + "boop"; + }) + vim.api.nvim_command(BUFFER.."bwipeout") + ]] + client.notify('finish') + end + eq(table.remove(expected_callbacks), {err, method, params, client_id}, "expected callback") + if method == 'finish' then + client.stop() + end + end; + } + end) + + end) + + describe("parsing tests", function() + it('should handle invalid content-length correctly', function() + local expected_callbacks = { + {NIL, "shutdown", {}, 1}; + {NIL, "finish", {}, 1}; + {NIL, "start", {}, 1}; + } + local client + test_rpc_server { + test_name = "invalid_header"; + on_setup = function() + end; + on_init = function(_client) + client = _client + client.stop(true) + end; + on_exit = function(code, signal) + eq(0, code, "exit code") eq(0, signal, "exit signal") + end; + on_callback = function(err, method, params, client_id) + eq(table.remove(expected_callbacks), {err, method, params, client_id}, "expected callback") + end; + } + end) + + end) +end) -- cgit From 76e0a8bd935b27270f8f6a594c3025bc494f4422 Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Thu, 21 Nov 2019 10:29:54 +0100 Subject: lsp: transmit "\n" after last line when 'eol' is set Otherwise some servers like clangd will emit spurious "no newline at end of file" warnings. --- test/functional/plugin/lsp/lsp_spec.lua | 48 +++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) (limited to 'test/functional/plugin') diff --git a/test/functional/plugin/lsp/lsp_spec.lua b/test/functional/plugin/lsp/lsp_spec.lua index cd0974b81c..c38c9b72ce 100644 --- a/test/functional/plugin/lsp/lsp_spec.lua +++ b/test/functional/plugin/lsp/lsp_spec.lua @@ -410,6 +410,54 @@ describe('Language Client API', function() } end) + it('should check the body and didChange full with noeol', function() + local expected_callbacks = { + {NIL, "shutdown", {}, 1}; + {NIL, "finish", {}, 1}; + {NIL, "start", {}, 1}; + } + local client + test_rpc_server { + test_name = "basic_check_buffer_open_and_change_noeol"; + 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"; + }) + vim.api.nvim_buf_set_option(BUFFER, 'eol', false) + ]] + end; + on_init = function(_client) + client = _client + local full_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Full") + eq(full_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") eq(0, signal, "exit signal") + end; + on_callback = function(err, method, params, client_id) + if method == 'start' then + exec_lua [[ + vim.api.nvim_buf_set_lines(BUFFER, 1, 2, false, { + "boop"; + }) + ]] + client.notify('finish') + end + eq(table.remove(expected_callbacks), {err, method, params, client_id}, "expected callback") + if method == 'finish' then + client.stop() + end + end; + } + end) + -- TODO(askhan) we don't support full for now, so we can disable these tests. pending('should check the body and didChange incremental', function() local expected_callbacks = { -- cgit From bcae04f6c62b23104e85bb08c54a16d0cdc33852 Mon Sep 17 00:00:00 2001 From: Ashkan Kiani Date: Thu, 21 Nov 2019 15:19:06 -0800 Subject: Updates - Use correct implementation of text_edits. - Send indent options to rangeFormatting and formatting. - Remove references to vim bindings and filetype from lsp.txt - Add more examples to docs. - Add before_init to allow changing initialize_params. --- test/functional/plugin/lsp/util_spec.lua | 78 ++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 test/functional/plugin/lsp/util_spec.lua (limited to 'test/functional/plugin') diff --git a/test/functional/plugin/lsp/util_spec.lua b/test/functional/plugin/lsp/util_spec.lua new file mode 100644 index 0000000000..6516fa8a08 --- /dev/null +++ b/test/functional/plugin/lsp/util_spec.lua @@ -0,0 +1,78 @@ +local helpers = require('test.functional.helpers')(after_each) +local eq = helpers.eq +local exec_lua = helpers.exec_lua +local dedent = helpers.dedent +local insert = helpers.insert +local clear = helpers.clear +local command = helpers.command +local NIL = helpers.NIL + +describe('LSP util', function() + local test_text = dedent([[ + First line of text + Second line of text + Third line of text + Fourth line of text]]) + + local function reset() + clear() + insert(test_text) + end + + before_each(reset) + + local function make_edit(y_0, x_0, y_1, x_1, text) + return { + range = { + start = { line = y_0, character = x_0 }; + ["end"] = { line = y_1, character = x_1 }; + }; + newText = type(text) == 'table' and table.concat(text, '\n') or (text or ""); + } + end + + local function buf_lines(bufnr) + return exec_lua("return vim.api.nvim_buf_get_lines((...), 0, -1, false)", bufnr) + end + + describe('apply_edits', function() + it('should apply simple edits', function() + local edits = { + make_edit(0, 0, 0, 0, {"123"}); + make_edit(1, 0, 1, 1, {"2"}); + make_edit(2, 0, 2, 2, {"3"}); + } + exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1) + eq({ + '123First line of text'; + '2econd line of text'; + '3ird line of text'; + 'Fourth line of text'; + }, buf_lines(1)) + end) + + it('should apply complex edits', function() + local edits = { + make_edit(0, 0, 0, 0, {"", "12"}); + make_edit(0, 0, 0, 0, {"3", "foo"}); + make_edit(0, 1, 0, 1, {"bar", "123"}); + make_edit(0, #"First ", 0, #"First line of text", {"guy"}); + make_edit(1, 0, 1, #'Second', {"baz"}); + make_edit(2, #'Th', 2, #"Third", {"e next"}); + 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) + eq({ + ''; + '123'; + 'fooFbar'; + '123irst guy'; + 'baz line of text'; + 'The next line of text'; + 'another line of text'; + 'before this!'; + }, buf_lines(1)) + end) + end) +end) -- cgit From b4ca07896cbf29ac4ca2373f681930be3ac3b882 Mon Sep 17 00:00:00 2001 From: Ashkan Kiani Date: Thu, 21 Nov 2019 15:23:43 -0800 Subject: lualint --- test/functional/plugin/lsp/util_spec.lua | 2 -- 1 file changed, 2 deletions(-) (limited to 'test/functional/plugin') diff --git a/test/functional/plugin/lsp/util_spec.lua b/test/functional/plugin/lsp/util_spec.lua index 6516fa8a08..1cf0e48be4 100644 --- a/test/functional/plugin/lsp/util_spec.lua +++ b/test/functional/plugin/lsp/util_spec.lua @@ -4,8 +4,6 @@ local exec_lua = helpers.exec_lua local dedent = helpers.dedent local insert = helpers.insert local clear = helpers.clear -local command = helpers.command -local NIL = helpers.NIL describe('LSP util', function() local test_text = dedent([[ -- cgit