aboutsummaryrefslogtreecommitdiff
path: root/test/functional/plugin/lsp/testutil.lua
diff options
context:
space:
mode:
authordundargoc <gocdundar@gmail.com>2024-04-08 11:03:20 +0200
committerdundargoc <33953936+dundargoc@users.noreply.github.com>2024-04-08 22:51:00 +0200
commit7035125b2b26aa68fcfb7cda39377ac79926a0f9 (patch)
treed194a3556a367b42505f9e7d26637e7cb3674928 /test/functional/plugin/lsp/testutil.lua
parent978962f9a00ce75216d2c36b79397ef3d2b54096 (diff)
downloadrneovim-7035125b2b26aa68fcfb7cda39377ac79926a0f9.tar.gz
rneovim-7035125b2b26aa68fcfb7cda39377ac79926a0f9.tar.bz2
rneovim-7035125b2b26aa68fcfb7cda39377ac79926a0f9.zip
test: improve test conventions
Work on https://github.com/neovim/neovim/issues/27004.
Diffstat (limited to 'test/functional/plugin/lsp/testutil.lua')
-rw-r--r--test/functional/plugin/lsp/testutil.lua219
1 files changed, 219 insertions, 0 deletions
diff --git a/test/functional/plugin/lsp/testutil.lua b/test/functional/plugin/lsp/testutil.lua
new file mode 100644
index 0000000000..7dc7bd9925
--- /dev/null
+++ b/test/functional/plugin/lsp/testutil.lua
@@ -0,0 +1,219 @@
+local t = require('test.functional.testutil')(nil)
+
+local clear = t.clear
+local exec_lua = t.exec_lua
+local run = t.run
+local stop = t.stop
+local api = t.api
+local NIL = vim.NIL
+
+local M = {}
+
+function M.clear_notrace()
+ -- problem: here be dragons
+ -- solution: don't look too closely for dragons
+ clear {
+ env = {
+ NVIM_LUA_NOTRACK = '1',
+ NVIM_APPNAME = 'nvim_lsp_test',
+ VIMRUNTIME = os.getenv 'VIMRUNTIME',
+ },
+ }
+end
+
+M.create_server_definition = [[
+ function _create_server(opts)
+ opts = opts or {}
+ local server = {}
+ server.messages = {}
+
+ function server.cmd(dispatchers)
+ local closing = false
+ local handlers = opts.handlers or {}
+ local srv = {}
+
+ function srv.request(method, params, callback)
+ table.insert(server.messages, {
+ method = method,
+ params = params,
+ })
+ local handler = handlers[method]
+ if handler then
+ local response, err = handler(method, params)
+ callback(err, response)
+ elseif method == 'initialize' then
+ callback(nil, {
+ capabilities = opts.capabilities or {}
+ })
+ elseif method == 'shutdown' then
+ callback(nil, nil)
+ end
+ local request_id = #server.messages
+ return true, request_id
+ end
+
+ function srv.notify(method, params)
+ table.insert(server.messages, {
+ method = method,
+ params = params
+ })
+ if method == 'exit' then
+ dispatchers.on_exit(0, 15)
+ end
+ end
+
+ function srv.is_closing()
+ return closing
+ end
+
+ function srv.terminate()
+ closing = true
+ end
+
+ return srv
+ end
+
+ return server
+ end
+]]
+
+-- Fake LSP server.
+M.fake_lsp_code = 'test/functional/fixtures/fake-lsp-server.lua'
+M.fake_lsp_logfile = 'Xtest-fake-lsp.log'
+
+local function fake_lsp_server_setup(test_name, timeout_ms, options, settings)
+ exec_lua(
+ [=[
+ lsp = require('vim.lsp')
+ local test_name, fake_lsp_code, fake_lsp_logfile, timeout, options, settings = ...
+ TEST_RPC_CLIENT_ID = lsp.start_client {
+ cmd_env = {
+ NVIM_LOG_FILE = fake_lsp_logfile;
+ NVIM_LUA_NOTRACK = "1";
+ NVIM_APPNAME = "nvim_lsp_test";
+ };
+ cmd = {
+ vim.v.progpath, '-l', fake_lsp_code, test_name, tostring(timeout),
+ };
+ handlers = setmetatable({}, {
+ __index = function(t, method)
+ return function(...)
+ return vim.rpcrequest(1, 'handler', ...)
+ end
+ end;
+ });
+ workspace_folders = {{
+ uri = 'file://' .. vim.uv.cwd(),
+ name = 'test_folder',
+ }};
+ before_init = function(params, config)
+ vim.schedule(function()
+ vim.rpcrequest(1, "setup")
+ end)
+ end,
+ on_init = function(client, result)
+ TEST_RPC_CLIENT = client
+ vim.rpcrequest(1, "init", result)
+ end;
+ flags = {
+ allow_incremental_sync = options.allow_incremental_sync or false;
+ debounce_text_changes = options.debounce_text_changes or 0;
+ };
+ settings = settings;
+ on_exit = function(...)
+ vim.rpcnotify(1, "exit", ...)
+ end;
+ }
+ ]=],
+ test_name,
+ M.fake_lsp_code,
+ M.fake_lsp_logfile,
+ timeout_ms or 1e3,
+ options or {},
+ settings or {}
+ )
+end
+
+--- @class test.lsp.Config
+--- @field test_name string
+--- @field timeout_ms? integer
+--- @field options? table
+--- @field settings? table
+---
+--- @field on_setup? fun()
+--- @field on_init? fun(client: vim.lsp.Client, ...)
+--- @field on_handler? fun(...)
+--- @field on_exit? fun(code: integer, signal: integer)
+
+--- @param config test.lsp.Config
+function M.test_rpc_server(config)
+ if config.test_name then
+ M.clear_notrace()
+ fake_lsp_server_setup(
+ config.test_name,
+ config.timeout_ms or 1e3,
+ config.options,
+ config.settings
+ )
+ 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,
+ })
+ --- @type integer, integer
+ local code, signal
+ local function on_request(method, args)
+ if method == 'setup' then
+ if config.on_setup then
+ config.on_setup()
+ end
+ return NIL
+ end
+ if method == 'init' then
+ if config.on_init then
+ config.on_init(client, unpack(args))
+ end
+ return NIL
+ end
+ if method == 'handler' then
+ if config.on_handler then
+ config.on_handler(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, nil, 1000)
+ run(on_request, on_notify, nil)
+ if config.on_exit then
+ config.on_exit(code, signal)
+ end
+ stop()
+ if config.test_name then
+ api.nvim_exec_autocmds('VimLeavePre', { modeline = false })
+ end
+end
+
+return M