diff options
| author | Josh Rahm <joshuarahm@gmail.com> | 2023-01-25 18:31:31 +0000 |
|---|---|---|
| committer | Josh Rahm <joshuarahm@gmail.com> | 2023-01-25 18:31:31 +0000 |
| commit | 9243becbedbb6a1592208051f8fa2b090dcc5e7d (patch) | |
| tree | 607c2a862ec3f4399b8766383f6f8e04c4aa43b4 /test/functional/plugin | |
| parent | 9e40b6e9e1bc67f2d856adb837ee64dd0e25b717 (diff) | |
| parent | 3c48d3c83fc21dbc0841f9210f04bdb073d73cd1 (diff) | |
| download | rneovim-usermarks.tar.gz rneovim-usermarks.tar.bz2 rneovim-usermarks.zip | |
Merge remote-tracking branch 'upstream/master' into usermarksusermarks
Diffstat (limited to 'test/functional/plugin')
| -rw-r--r-- | test/functional/plugin/ccomplete_spec.lua | 61 | ||||
| -rw-r--r-- | test/functional/plugin/cfilter_spec.lua | 106 | ||||
| -rw-r--r-- | test/functional/plugin/editorconfig_spec.lua | 210 | ||||
| -rw-r--r-- | test/functional/plugin/health_spec.lua | 178 | ||||
| -rw-r--r-- | test/functional/plugin/lsp/codelens_spec.lua | 35 | ||||
| -rw-r--r-- | test/functional/plugin/lsp/helpers.lua | 176 | ||||
| -rw-r--r-- | test/functional/plugin/lsp/semantic_tokens_spec.lua | 1219 | ||||
| -rw-r--r-- | test/functional/plugin/lsp_spec.lua | 626 | ||||
| -rw-r--r-- | test/functional/plugin/man_spec.lua | 38 | ||||
| -rw-r--r-- | test/functional/plugin/shada_spec.lua | 73 |
10 files changed, 2500 insertions, 222 deletions
diff --git a/test/functional/plugin/ccomplete_spec.lua b/test/functional/plugin/ccomplete_spec.lua new file mode 100644 index 0000000000..903f16fc73 --- /dev/null +++ b/test/functional/plugin/ccomplete_spec.lua @@ -0,0 +1,61 @@ +local helpers = require('test.functional.helpers')(after_each) +local clear = helpers.clear +local command = helpers.command +local eq = helpers.eq +local eval = helpers.eval +local feed = helpers.feed +local write_file = helpers.write_file + +describe('ccomplete#Complete', function() + setup(function() + -- Realistic tags generated from neovim source tree using `ctags -R *` + write_file( + 'Xtags', + [[ +augroup_del src/nvim/autocmd.c /^void augroup_del(char *name, bool stupid_legacy_mode)$/;" f typeref:typename:void +augroup_exists src/nvim/autocmd.c /^bool augroup_exists(const char *name)$/;" f typeref:typename:bool +augroup_find src/nvim/autocmd.c /^int augroup_find(const char *name)$/;" f typeref:typename:int +aupat_get_buflocal_nr src/nvim/autocmd.c /^int aupat_get_buflocal_nr(char *pat, int patlen)$/;" f typeref:typename:int +aupat_is_buflocal src/nvim/autocmd.c /^bool aupat_is_buflocal(char *pat, int patlen)$/;" f typeref:typename:bool +expand_get_augroup_name src/nvim/autocmd.c /^char *expand_get_augroup_name(expand_T *xp, int idx)$/;" f typeref:typename:char * +expand_get_event_name src/nvim/autocmd.c /^char *expand_get_event_name(expand_T *xp, int idx)$/;" f typeref:typename:char * +]] + ) + end) + + before_each(function() + clear() + command('set tags=Xtags') + end) + + teardown(function() + os.remove('Xtags') + end) + + it('can complete from Xtags', function() + local completed = eval('ccomplete#Complete(0, "a")') + eq(5, #completed) + eq('augroup_del(', completed[1].word) + eq('f', completed[1].kind) + + local aupat = eval('ccomplete#Complete(0, "aupat")') + eq(2, #aupat) + eq('aupat_get_buflocal_nr(', aupat[1].word) + eq('f', aupat[1].kind) + end) + + it('does not error when returning no matches', function() + local completed = eval('ccomplete#Complete(0, "doesnotmatch")') + eq({}, completed) + end) + + it('can find the beginning of a word for C', function() + command('set filetype=c') + feed('i int something = augroup') + local result = eval('ccomplete#Complete(1, "")') + eq(#' int something = ', result) + + local completed = eval('ccomplete#Complete(0, "augroup")') + eq(3, #completed) + end) +end) diff --git a/test/functional/plugin/cfilter_spec.lua b/test/functional/plugin/cfilter_spec.lua new file mode 100644 index 0000000000..8b1e75b495 --- /dev/null +++ b/test/functional/plugin/cfilter_spec.lua @@ -0,0 +1,106 @@ +local helpers = require('test.functional.helpers')(after_each) +local clear = helpers.clear +local command = helpers.command +local eq = helpers.eq +local funcs = helpers.funcs + +describe('cfilter.lua', function() + before_each(function() + clear() + command('packadd cfilter') + end) + + for _, list in ipairs({ + { + name = 'Cfilter', + get = funcs.getqflist, + set = funcs.setqflist, + }, + { + name = 'Lfilter', + get = function() + return funcs.getloclist(0) + end, + set = function(items) + return funcs.setloclist(0, items) + end, + }, + }) do + local filter = function(s, bang) + if not bang then + bang = '' + else + bang = '!' + end + + command(string.format('%s%s %s', list.name, bang, s)) + end + + describe((':%s'):format(list.name), function() + it('does not error on empty list', function() + filter('nothing') + eq({}, funcs.getqflist()) + end) + + it('requires an argument', function() + local ok = pcall(filter, '') + eq(false, ok) + end) + + local test = function(name, s, res, map, bang) + it(('%s (%s)'):format(name, s), function() + list.set({ + { filename = 'foo', lnum = 1, text = 'bar' }, + { filename = 'foo', lnum = 2, text = 'baz' }, + { filename = 'foo', lnum = 3, text = 'zed' }, + }) + + filter(s, bang) + + local got = list.get() + if map then + got = map(got) + end + eq(res, got) + end) + end + + local toname = function(qflist) + return funcs.map(qflist, 'v:val.text') + end + + test('filters with no matches', 'does not match', {}) + + test('filters with matches', 'ba', { 'bar', 'baz' }, toname) + test('filters with matches', 'z', { 'baz', 'zed' }, toname) + test('filters with matches', '^z', { 'zed' }, toname) + test('filters with not matches', '^z', { 'bar', 'baz' }, toname, true) + + it('also supports using the / register', function() + list.set({ + { filename = 'foo', lnum = 1, text = 'bar' }, + { filename = 'foo', lnum = 2, text = 'baz' }, + { filename = 'foo', lnum = 3, text = 'zed' }, + }) + + funcs.setreg('/', 'ba') + filter('/') + + eq({ 'bar', 'baz' }, toname(list.get())) + end) + + it('also supports using the / register with bang', function() + list.set({ + { filename = 'foo', lnum = 1, text = 'bar' }, + { filename = 'foo', lnum = 2, text = 'baz' }, + { filename = 'foo', lnum = 3, text = 'zed' }, + }) + + funcs.setreg('/', 'ba') + filter('/', true) + + eq({ 'zed' }, toname(list.get())) + end) + end) + end +end) diff --git a/test/functional/plugin/editorconfig_spec.lua b/test/functional/plugin/editorconfig_spec.lua new file mode 100644 index 0000000000..e6a2550aba --- /dev/null +++ b/test/functional/plugin/editorconfig_spec.lua @@ -0,0 +1,210 @@ +local helpers = require('test.functional.helpers')(after_each) +local clear = helpers.clear +local command = helpers.command +local eq = helpers.eq +local pathsep = helpers.get_pathsep() +local curbufmeths = helpers.curbufmeths +local funcs = helpers.funcs +local meths = helpers.meths + +local testdir = 'Xtest-editorconfig' + +local function test_case(name, expected) + local filename = testdir .. pathsep .. name + command('edit ' .. filename) + for opt, val in pairs(expected) do + eq(val, curbufmeths.get_option(opt), name) + end +end + +setup(function() + helpers.mkdir_p(testdir) + helpers.write_file( + testdir .. pathsep .. '.editorconfig', + [[ + root = true + + [3_space.txt] + indent_style = space + indent_size = 3 + tab_width = 3 + + [4_space.py] + indent_style = space + indent_size = 4 + tab_width = 8 + + [space.txt] + indent_style = space + indent_size = tab + + [tab.txt] + indent_style = tab + + [4_tab.txt] + indent_style = tab + indent_size = 4 + tab_width = 4 + + [4_tab_width_of_8.txt] + indent_style = tab + indent_size = 4 + tab_width = 8 + + [lf.txt] + end_of_line = lf + + [crlf.txt] + end_of_line = crlf + + [cr.txt] + end_of_line = cr + + [utf-8.txt] + charset = utf-8 + + [utf-8-bom.txt] + charset = utf-8-bom + + [utf-16be.txt] + charset = utf-16be + + [utf-16le.txt] + charset = utf-16le + + [latin1.txt] + charset = latin1 + + [with_newline.txt] + insert_final_newline = true + + [without_newline.txt] + insert_final_newline = false + + [trim.txt] + trim_trailing_whitespace = true + + [no_trim.txt] + trim_trailing_whitespace = false + + [max_line_length.txt] + max_line_length = 42 + ]] + ) +end) + +teardown(function() + helpers.rmdir(testdir) +end) + +describe('editorconfig', function() + before_each(function() + -- Remove -u NONE so that plugins (i.e. editorconfig.lua) are loaded + clear({ args_rm = { '-u' } }) + end) + + it('sets indent options', function() + test_case('3_space.txt', { + expandtab = true, + shiftwidth = 3, + softtabstop = -1, + tabstop = 3, + }) + + test_case('4_space.py', { + expandtab = true, + shiftwidth = 4, + softtabstop = -1, + tabstop = 8, + }) + + test_case('space.txt', { + expandtab = true, + shiftwidth = 0, + softtabstop = 0, + }) + + test_case('tab.txt', { + expandtab = false, + shiftwidth = 0, + softtabstop = 0, + }) + + test_case('4_tab.txt', { + expandtab = false, + shiftwidth = 4, + softtabstop = -1, + tabstop = 4, + }) + + test_case('4_tab_width_of_8.txt', { + expandtab = false, + shiftwidth = 4, + softtabstop = -1, + tabstop = 8, + }) + end) + + it('sets end-of-line options', function() + test_case('lf.txt', { fileformat = 'unix' }) + test_case('crlf.txt', { fileformat = 'dos' }) + test_case('cr.txt', { fileformat = 'mac' }) + end) + + it('sets encoding options', function() + test_case('utf-8.txt', { fileencoding = 'utf-8', bomb = false }) + test_case('utf-8-bom.txt', { fileencoding = 'utf-8', bomb = true }) + test_case('utf-16be.txt', { fileencoding = 'utf-16', bomb = false }) + test_case('utf-16le.txt', { fileencoding = 'utf-16le', bomb = false }) + test_case('latin1.txt', { fileencoding = 'latin1', bomb = false }) + end) + + it('sets newline options', function() + test_case('with_newline.txt', { fixendofline = true, endofline = true }) + test_case('without_newline.txt', { fixendofline = false, endofline = false }) + end) + + it('respects trim_trailing_whitespace', function() + local filename = testdir .. pathsep .. 'trim.txt' + -- luacheck: push ignore 613 + local untrimmed = [[ +This line ends in whitespace +So does this one +And this one +But not this one +]] + -- luacheck: pop + local trimmed = untrimmed:gsub('%s+\n', '\n') + + helpers.write_file(filename, untrimmed) + command('edit ' .. filename) + command('write') + command('bdelete') + eq(trimmed, helpers.read_file(filename)) + + filename = testdir .. pathsep .. 'no_trim.txt' + helpers.write_file(filename, untrimmed) + command('edit ' .. filename) + command('write') + command('bdelete') + eq(untrimmed, helpers.read_file(filename)) + end) + + it('sets textwidth', function() + test_case('max_line_length.txt', { textwidth = 42 }) + end) + + it('can be disabled globally', function() + meths.set_var('editorconfig', false) + meths.set_option_value('shiftwidth', 42, {}) + test_case('3_space.txt', { shiftwidth = 42 }) + end) + + it('can be disabled per-buffer', function() + meths.set_option_value('shiftwidth', 42, {}) + local bufnr = funcs.bufadd(testdir .. pathsep .. '3_space.txt') + meths.buf_set_var(bufnr, 'editorconfig', false) + test_case('3_space.txt', { shiftwidth = 42 }) + test_case('4_space.py', { shiftwidth = 4 }) + end) +end) diff --git a/test/functional/plugin/health_spec.lua b/test/functional/plugin/health_spec.lua index ba66117fb1..97d32313e5 100644 --- a/test/functional/plugin/health_spec.lua +++ b/test/functional/plugin/health_spec.lua @@ -5,7 +5,7 @@ local Screen = require('test.functional.ui.screen') local clear = helpers.clear local curbuf_contents = helpers.curbuf_contents local command = helpers.command -local eq, neq = helpers.eq, helpers.neq +local eq, neq, matches = helpers.eq, helpers.neq, helpers.matches local getcompletion = helpers.funcs.getcompletion describe(':checkhealth', function() @@ -29,8 +29,7 @@ describe(':checkhealth', function() -- Do this after startup, otherwise it just breaks $VIMRUNTIME. command("let $VIM='zub'") command("checkhealth nvim") - eq("ERROR: $VIM is invalid: zub", - string.match(curbuf_contents(), "ERROR: $VIM .* zub")) + matches('ERROR $VIM .* zub', curbuf_contents()) end) it('completions can be listed via getcompletion()', function() clear() @@ -56,21 +55,22 @@ describe('health.vim', function() command("checkhealth full_render") helpers.expect([[ + ============================================================================== full_render: health#full_render#check - ======================================================================== - ## report 1 - - OK: life is fine - - WARNING: no what installed - - ADVICE: - - pip what - - make what - - ## report 2 - - INFO: stuff is stable - - ERROR: why no hardcopy - - ADVICE: - - :help |:hardcopy| - - :help |:TOhtml| + + report 1 ~ + - OK life is fine + - WARNING no what installed + - ADVICE: + - pip what + - make what + + report 2 ~ + - stuff is stable + - ERROR why no hardcopy + - ADVICE: + - :help |:hardcopy| + - :help |:TOhtml| ]]) end) @@ -78,26 +78,29 @@ describe('health.vim', function() command("checkhealth success1 success2 test_plug") helpers.expect([[ + ============================================================================== success1: health#success1#check - ======================================================================== - ## report 1 - - OK: everything is fine - ## report 2 - - OK: nothing to see here + report 1 ~ + - OK everything is fine + + report 2 ~ + - OK nothing to see here + ============================================================================== success2: health#success2#check - ======================================================================== - ## another 1 - - OK: ok + another 1 ~ + - OK ok + + ============================================================================== test_plug: require("test_plug.health").check() - ======================================================================== - ## report 1 - - OK: everything is fine - ## report 2 - - OK: nothing to see here + report 1 ~ + - OK everything is fine + + report 2 ~ + - OK nothing to see here ]]) end) @@ -107,13 +110,14 @@ describe('health.vim', function() -- 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 + report 1 ~ + - OK everything is fine + + report 2 ~ + - OK nothing to see here ]]) end) @@ -121,13 +125,14 @@ describe('health.vim', 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 + report 1 ~ + - OK everything is fine + + report 2 ~ + - OK nothing to see here ]]) end) @@ -138,30 +143,34 @@ describe('health.vim', function() local received = table.concat(buf_lines, '\n', 1, #buf_lines - 5) local expected = helpers.dedent([[ + ============================================================================== test_plug: require("test_plug.health").check() - ======================================================================== - ## report 1 - - OK: everything is fine - ## report 2 - - OK: nothing to see here + 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 + report 1 ~ + - OK everything is fine + report 2 ~ + - OK nothing to see here + + ============================================================================== test_plug.submodule_empty: require("test_plug.submodule_empty.health").check() - ======================================================================== - - ERROR: The healthcheck report for "test_plug.submodule_empty" plugin is empty. + - ERROR The healthcheck report for "test_plug.submodule_empty" plugin is empty. + + ============================================================================== 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 20]]) + + - ERROR Failed to run healthcheck for "test_plug.submodule_failed" plugin. Exception: + function health#check, line 25]]) eq(expected, received) end) @@ -169,11 +178,12 @@ describe('health.vim', function() command("checkhealth broken") helpers.expect([[ + ============================================================================== broken: health#broken#check - ======================================================================== - - ERROR: Failed to run healthcheck for "broken" plugin. Exception: - function health#check[20]..health#broken#check, line 1 - caused an error + + - ERROR Failed to run healthcheck for "broken" plugin. Exception: + function health#check[25]..health#broken#check, line 1 + caused an error ]]) end) @@ -181,9 +191,10 @@ describe('health.vim', function() command("checkhealth test_plug.submodule_empty") helpers.expect([[ + ============================================================================== test_plug.submodule_empty: require("test_plug.submodule_empty.health").check() - ======================================================================== - - ERROR: The healthcheck report for "test_plug.submodule_empty" plugin is empty. + + - ERROR The healthcheck report for "test_plug.submodule_empty" plugin is empty. ]]) end) @@ -198,38 +209,38 @@ describe('health.vim', function() 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 20]]) + + - ERROR Failed to run healthcheck for "test_plug.submodule_failed" plugin. Exception: + function health#check, line 25]]) eq(expected, received) end) it("highlights OK, ERROR", function() - local screen = Screen.new(72, 10) + local screen = Screen.new(50, 12) screen:attach() screen:set_default_attr_ids({ Ok = { foreground = Screen.colors.Grey3, background = 6291200 }, Error = { foreground = Screen.colors.Grey100, background = Screen.colors.Red }, - Heading = { bold=true, foreground=Screen.colors.Magenta }, - Heading2 = { foreground = Screen.colors.SlateBlue }, - Bar = { foreground = 0x6a0dad }, - Bullet = { bold=true, foreground=Screen.colors.Brown }, + Heading = { foreground = tonumber('0x6a0dad') }, + Bar = { foreground = Screen.colors.LightGrey, background = Screen.colors.DarkGrey }, }) command("checkhealth foo success1") - command("1tabclose") - command("set laststatus=0") + command("set nowrap laststatus=0") screen:expect{grid=[[ - ^ | - {Heading:foo: } | - {Bar:========================================================================}| - {Bullet: -} {Error:ERROR}: No healthcheck found for "foo" plugin. | - | - {Heading:success1: health#success1#check} | - {Bar:========================================================================}| - {Heading2:##}{Heading: report 1} | - {Bullet: -} {Ok:OK}: everything is fine | - | + ^ | + {Bar:──────────────────────────────────────────────────}| + {Heading:foo: } | + | + - {Error:ERROR} No healthcheck found for "foo" plugin. | + | + {Bar:──────────────────────────────────────────────────}| + {Heading:success1: health#success1#check} | + | + {Heading:report 1} | + - {Ok:OK} everything is fine | + | ]]} end) @@ -238,9 +249,10 @@ describe('health.vim', function() -- luacheck: ignore 613 helpers.expect([[ + ============================================================================== non_existent_healthcheck: - ======================================================================== - - ERROR: No healthcheck found for "non_existent_healthcheck" plugin. + + - ERROR No healthcheck found for "non_existent_healthcheck" plugin. ]]) end) diff --git a/test/functional/plugin/lsp/codelens_spec.lua b/test/functional/plugin/lsp/codelens_spec.lua index ecc2f579b8..3d7a15a191 100644 --- a/test/functional/plugin/lsp/codelens_spec.lua +++ b/test/functional/plugin/lsp/codelens_spec.lua @@ -58,6 +58,41 @@ describe('vim.lsp.codelens', function() ]], bufnr) eq({[1] = {'Lens1', 'LspCodeLens'}}, virtual_text_chunks) + end) + + it('can clear all lens', function() + local fake_uri = "file:///fake/uri" + local bufnr = exec_lua([[ + fake_uri = ... + local bufnr = vim.uri_to_bufnr(fake_uri) + local lines = {'So', 'many', 'lines'} + vim.fn.bufload(bufnr) + vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, lines) + return bufnr + ]], fake_uri) + + exec_lua([[ + local bufnr = ... + local lenses = { + { + range = { + start = { line = 0, character = 0, }, + ['end'] = { line = 0, character = 0 } + }, + command = { title = 'Lens1', command = 'Dummy' } + }, + } + vim.lsp.codelens.on_codelens(nil, lenses, {method='textDocument/codeLens', client_id=1, bufnr=bufnr}) + ]], bufnr) + + local stored_lenses = exec_lua('return vim.lsp.codelens.get(...)', bufnr) + eq(1, #stored_lenses) + + exec_lua([[ + vim.lsp.codelens.clear() + ]]) + stored_lenses = exec_lua('return vim.lsp.codelens.get(...)', bufnr) + eq(0, #stored_lenses) end) end) diff --git a/test/functional/plugin/lsp/helpers.lua b/test/functional/plugin/lsp/helpers.lua new file mode 100644 index 0000000000..028ccb9e2c --- /dev/null +++ b/test/functional/plugin/lsp/helpers.lua @@ -0,0 +1,176 @@ +local helpers = require('test.functional.helpers')(nil) + +local clear = helpers.clear +local exec_lua = helpers.exec_lua +local run = helpers.run +local stop = helpers.stop +local NIL = helpers.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"; + 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, fixture_filename, logfile, timeout, options, settings = ... + TEST_RPC_CLIENT_ID = lsp.start_client { + cmd_env = { + NVIM_LOG_FILE = logfile; + NVIM_LUA_NOTRACK = "1"; + }; + cmd = { + vim.v.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, + }; + handlers = setmetatable({}, { + __index = function(t, method) + return function(...) + return vim.rpcrequest(1, 'handler', ...) + end + end; + }); + workspace_folders = {{ + uri = 'file://' .. vim.loop.cwd(), + name = 'test_folder', + }}; + 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 + +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; + }) + 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 == '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, 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("vim.api.nvim_exec_autocmds('VimLeavePre', { modeline = false })") + end +end + +return M diff --git a/test/functional/plugin/lsp/semantic_tokens_spec.lua b/test/functional/plugin/lsp/semantic_tokens_spec.lua new file mode 100644 index 0000000000..9c1ba86fe1 --- /dev/null +++ b/test/functional/plugin/lsp/semantic_tokens_spec.lua @@ -0,0 +1,1219 @@ +local helpers = require('test.functional.helpers')(after_each) +local lsp_helpers = require('test.functional.plugin.lsp.helpers') +local Screen = require('test.functional.ui.screen') + +local command = helpers.command +local dedent = helpers.dedent +local eq = helpers.eq +local exec_lua = helpers.exec_lua +local feed = helpers.feed +local feed_command = helpers.feed_command +local insert = helpers.insert +local matches = helpers.matches + +local clear_notrace = lsp_helpers.clear_notrace +local create_server_definition = lsp_helpers.create_server_definition + +before_each(function() + clear_notrace() +end) + +after_each(function() + exec_lua("vim.api.nvim_exec_autocmds('VimLeavePre', { modeline = false })") +end) + +describe('semantic token highlighting', function() + + describe('general', function() + local text = dedent([[ + #include <iostream> + + int main() + { + int x; + #ifdef __cplusplus + std::cout << x << "\n"; + #else + printf("%d\n", x); + #endif + } + }]]) + + local legend = [[{ + "tokenTypes": [ + "variable", "variable", "parameter", "function", "method", "function", "property", "variable", "class", "interface", "enum", "enumMember", "type", "type", "unknown", "namespace", "typeParameter", "concept", "type", "macro", "comment" + ], + "tokenModifiers": [ + "declaration", "deprecated", "deduced", "readonly", "static", "abstract", "virtual", "dependentName", "defaultLibrary", "usedAsMutableReference", "functionScope", "classScope", "fileScope", "globalScope" + ] + }]] + + local response = [[{ + "data": [ 2, 4, 4, 3, 8193, 2, 8, 1, 1, 1025, 1, 7, 11, 19, 8192, 1, 4, 3, 15, 8448, 0, 5, 4, 0, 8448, 0, 8, 1, 1, 1024, 1, 0, 5, 20, 0, 1, 0, 22, 20, 0, 1, 0, 6, 20, 0 ], + "resultId": 1 + }]] + + local edit_response = [[{ + |