diff options
Diffstat (limited to 'test')
-rw-r--r-- | test/functional/api/extmark_spec.lua | 34 | ||||
-rw-r--r-- | test/functional/api/vim_spec.lua | 73 | ||||
-rw-r--r-- | test/functional/core/job_spec.lua | 21 | ||||
-rw-r--r-- | test/functional/eval/environ_spec.lua | 61 | ||||
-rw-r--r-- | test/functional/legacy/backspace_opt_spec.lua | 67 | ||||
-rw-r--r-- | test/functional/lua/buffer_updates_spec.lua | 130 | ||||
-rw-r--r-- | test/functional/lua/command_line_completion_spec.lua | 171 | ||||
-rw-r--r-- | test/functional/options/defaults_spec.lua | 26 | ||||
-rw-r--r-- | test/functional/plugin/lsp/diagnostic_spec.lua | 100 | ||||
-rw-r--r-- | test/functional/plugin/lsp_spec.lua | 124 | ||||
-rw-r--r-- | test/functional/treesitter/parser_spec.lua | 35 | ||||
-rw-r--r-- | test/functional/ui/sign_spec.lua | 105 | ||||
-rw-r--r-- | test/functional/viml/completion_spec.lua | 43 | ||||
-rw-r--r-- | test/symbolic/klee/nvim/charset.c | 4 | ||||
-rw-r--r-- | test/symbolic/klee/nvim/memory.c | 4 |
15 files changed, 806 insertions, 192 deletions
diff --git a/test/functional/api/extmark_spec.lua b/test/functional/api/extmark_spec.lua index ab913ba4a4..d2b555ee5b 100644 --- a/test/functional/api/extmark_spec.lua +++ b/test/functional/api/extmark_spec.lua @@ -1389,6 +1389,40 @@ describe('API/extmarks', function() undo]],false) eq(2, meths.eval('1+1')) -- did not crash end) + + it('works with left and right gravity', function() + -- right gravity should move with inserted text, while + -- left gravity should stay in place. + curbufmeths.set_extmark(ns, 0, 5, {right_gravity = false}) + curbufmeths.set_extmark(ns, 0, 5, {right_gravity = true}) + feed([[Aasdfasdf]]) + + eq({ {1, 0, 5}, {2, 0, 13} }, + curbufmeths.get_extmarks(ns, 0, -1, {})) + + -- but both move when text is inserted before + feed([[<esc>Iasdf<esc>]]) + -- eq({}, curbufmeths.get_lines(0, -1, true)) + eq({ {1, 0, 9}, {2, 0, 17} }, + curbufmeths.get_extmarks(ns, 0, -1, {})) + + -- clear text + curbufmeths.set_text(0, 0, 0, 17, {}) + + -- handles set_text correctly as well + eq({ {1, 0, 0}, {2, 0, 0} }, + meths.buf_get_extmarks(0, ns, 0, -1, {})) + curbufmeths.set_text(0, 0, 0, 0, {'asdfasdf'}) + eq({ {1, 0, 0}, {2, 0, 8} }, + curbufmeths.get_extmarks(ns, 0, -1, {})) + + feed('u') + -- handles pasting + meths.exec([[let @a='asdfasdf']], false) + feed([["ap]]) + eq({ {1, 0, 0}, {2, 0, 8} }, + meths.buf_get_extmarks(0, ns, 0, -1, {})) + end) end) describe('Extmarks buffer api with many marks', function() diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index 30128e9c40..3ff3efb8c9 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -2002,4 +2002,77 @@ describe('API', function() }, meths.get_option_info'showcmd') end) end) + + describe('nvim_echo', function() + local screen + + before_each(function() + clear() + screen = Screen.new(40, 8) + screen:attach() + screen:set_default_attr_ids({ + [0] = {bold=true, foreground=Screen.colors.Blue}, + [1] = {bold = true, foreground = Screen.colors.SeaGreen}, + [2] = {bold = true, reverse = true}, + [3] = {foreground = Screen.colors.Brown, bold = true}, -- Statement + [4] = {foreground = Screen.colors.SlateBlue}, -- Special + }) + command('highlight Statement gui=bold guifg=Brown') + command('highlight Special guifg=SlateBlue') + end) + + it('should clear cmdline message before echo', function() + feed(':call nvim_echo([["msg"]], v:false, {})<CR>') + screen:expect{grid=[[ + ^ | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + msg | + ]]} + end) + + it('can show highlighted line', function() + nvim_async("echo", {{"msg_a"}, {"msg_b", "Statement"}, {"msg_c", "Special"}}, true, {}) + screen:expect{grid=[[ + ^ | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + msg_a{3:msg_b}{4:msg_c} | + ]]} + end) + + it('can show highlighted multiline', function() + nvim_async("echo", {{"msg_a\nmsg_a", "Statement"}, {"msg_b", "Special"}}, true, {}) + screen:expect{grid=[[ + | + {0:~ }| + {0:~ }| + {0:~ }| + {2: }| + {3:msg_a} | + {3:msg_a}{4:msg_b} | + {1:Press ENTER or type command to continue}^ | + ]]} + end) + + it('can save message history', function() + nvim('command', 'set cmdheight=2') -- suppress Press ENTER + nvim("echo", {{"msg\nmsg"}, {"msg"}}, true, {}) + eq("msg\nmsgmsg", meths.exec('messages', true)) + end) + + it('can disable saving message history', function() + nvim('command', 'set cmdheight=2') -- suppress Press ENTER + nvim_async("echo", {{"msg\nmsg"}, {"msg"}}, false, {}) + eq("", meths.exec("messages", true)) + end) + end) end) diff --git a/test/functional/core/job_spec.lua b/test/functional/core/job_spec.lua index 6d1182478a..b59d87eb12 100644 --- a/test/functional/core/job_spec.lua +++ b/test/functional/core/job_spec.lua @@ -31,9 +31,9 @@ describe('jobs', function() nvim('set_var', 'channel', channel) source([[ function! Normalize(data) abort - " Windows: remove ^M + " Windows: remove ^M and term escape sequences return type([]) == type(a:data) - \ ? map(a:data, 'substitute(v:val, "\r", "", "g")') + \ ? map(a:data, 'substitute(substitute(v:val, "\r", "", "g"), "\x1b\\%(\\]\\d\\+;.\\{-}\x07\\|\\[.\\{-}[\x40-\x7E]\\)", "", "g")') \ : a:data endfunction function! OnEvent(id, data, event) dict @@ -63,6 +63,7 @@ describe('jobs', function() it('append environment #env', function() nvim('command', "let $VAR = 'abc'") + nvim('command', "let $TOTO = 'goodbye world'") nvim('command', "let g:job_opts.env = {'TOTO': 'hello world'}") if iswin() then nvim('command', [[call jobstart('echo %TOTO% %VAR%', g:job_opts)]]) @@ -75,8 +76,24 @@ describe('jobs', function() }) end) + it('append environment with pty #env', function() + nvim('command', "let $VAR = 'abc'") + nvim('command', "let $TOTO = 'goodbye world'") + nvim('command', "let g:job_opts.pty = v:true") + nvim('command', "let g:job_opts.env = {'TOTO': 'hello world'}") + if iswin() then + nvim('command', [[call jobstart('echo %TOTO% %VAR%', g:job_opts)]]) + else + nvim('command', [[call jobstart('echo $TOTO $VAR', g:job_opts)]]) + end + expect_msg_seq({ + {'notification', 'stdout', {0, {'hello world abc', ''}}}, + }) + end) + it('replace environment #env', function() nvim('command', "let $VAR = 'abc'") + nvim('command', "let $TOTO = 'goodbye world'") nvim('command', "let g:job_opts.env = {'TOTO': 'hello world'}") nvim('command', "let g:job_opts.clear_env = 1") diff --git a/test/functional/eval/environ_spec.lua b/test/functional/eval/environ_spec.lua index 54d2dc960b..9e19568249 100644 --- a/test/functional/eval/environ_spec.lua +++ b/test/functional/eval/environ_spec.lua @@ -3,6 +3,11 @@ local clear = helpers.clear local eq = helpers.eq local environ = helpers.funcs.environ local exists = helpers.funcs.exists +local system = helpers.funcs.system +local nvim_prog = helpers.nvim_prog +local command = helpers.command +local eval = helpers.eval +local setenv = helpers.funcs.setenv describe('environment variables', function() it('environ() handles empty env variable', function() @@ -17,3 +22,59 @@ describe('environment variables', function() eq(0, exists('$DOES_NOT_EXIST')) end) end) + +describe('empty $HOME', function() + local original_home = os.getenv('HOME') + + -- recover $HOME after each test + after_each(function() + if original_home ~= nil then + setenv('HOME', original_home) + end + os.remove('test_empty_home') + os.remove('./~') + end) + + local function tilde_in_cwd() + -- get files in cwd + command("let test_empty_home_cwd_files = split(globpath('.', '*'), '\n')") + -- get the index of the file named '~' + command('let test_empty_home_tilde_index = index(test_empty_home_cwd_files, "./~")') + return eval('test_empty_home_tilde_index') ~= -1 + end + + local function write_and_test_tilde() + system({nvim_prog, '-u', 'NONE', '-i', 'NONE', '--headless', + '-c', 'write test_empty_home', '+q'}) + eq(false, tilde_in_cwd()) + end + + it("'~' folder not created in cwd if $HOME and related env not defined", function() + command("unlet $HOME") + write_and_test_tilde() + + command("let $HOMEDRIVE='C:'") + command("let $USERPROFILE='C:\\'") + write_and_test_tilde() + + command("unlet $HOMEDRIVE") + write_and_test_tilde() + + command("unlet $USERPROFILE") + write_and_test_tilde() + + command("let $HOME='%USERPROFILE%'") + command("let $USERPROFILE='C:\\'") + write_and_test_tilde() + end) + + it("'~' folder not created in cwd if writing a file with invalid $HOME", function() + setenv('HOME', '/path/does/not/exist') + write_and_test_tilde() + end) + + it("'~' folder not created in cwd if writing a file with $HOME=''", function() + command("let $HOME=''") + write_and_test_tilde() + end) +end) diff --git a/test/functional/legacy/backspace_opt_spec.lua b/test/functional/legacy/backspace_opt_spec.lua deleted file mode 100644 index 90bc6f74f0..0000000000 --- a/test/functional/legacy/backspace_opt_spec.lua +++ /dev/null @@ -1,67 +0,0 @@ -local helpers = require('test.functional.helpers')(after_each) -local call, clear = helpers.call, helpers.clear -local source, eq, nvim = helpers.source, helpers.eq, helpers.meths - -describe("test 'backspace' settings", function() - before_each(function() - clear() - - source([[ - func Exec(expr) - let str='' - try - exec a:expr - catch /.*/ - let str=v:exception - endtry - return str - endfunc - - func Test_backspace_option() - set backspace= - call assert_equal('', &backspace) - set backspace=indent - call assert_equal('indent', &backspace) - set backspace=eol - call assert_equal('eol', &backspace) - set backspace=start - call assert_equal('start', &backspace) - " Add the value - set backspace= - set backspace=indent - call assert_equal('indent', &backspace) - set backspace+=eol - call assert_equal('indent,eol', &backspace) - set backspace+=start - call assert_equal('indent,eol,start', &backspace) - " Delete the value - set backspace-=indent - call assert_equal('eol,start', &backspace) - set backspace-=start - call assert_equal('eol', &backspace) - set backspace-=eol - call assert_equal('', &backspace) - " Check the error - call assert_equal(0, match(Exec('set backspace=ABC'), '.*E474')) - call assert_equal(0, match(Exec('set backspace+=def'), '.*E474')) - " NOTE: Vim doesn't check following error... - "call assert_equal(0, match(Exec('set backspace-=ghi'), '.*E474')) - - " Check backwards compatibility with version 5.4 and earlier - set backspace=0 - call assert_equal('0', &backspace) - set backspace=1 - call assert_equal('1', &backspace) - set backspace=2 - call assert_equal('2', &backspace) - call assert_false(match(Exec('set backspace=3'), '.*E474')) - call assert_false(match(Exec('set backspace=10'), '.*E474')) - endfunc - ]]) - end) - - it('works', function() - call('Test_backspace_option') - eq({}, nvim.get_vvar('errors')) - end) -end) diff --git a/test/functional/lua/buffer_updates_spec.lua b/test/functional/lua/buffer_updates_spec.lua index 67dc5f5a16..6087f9e7d6 100644 --- a/test/functional/lua/buffer_updates_spec.lua +++ b/test/functional/lua/buffer_updates_spec.lua @@ -20,12 +20,13 @@ local origlines = {"original line 1", "original line 6", " indented line"} -local function attach_buffer(evname) - exec_lua([[ +before_each(function () + clear() + exec_lua [[ local evname = ... local events = {} - function test_register(bufnr, id, changedtick, utf_sizes, preview) + function test_register(bufnr, evname, id, changedtick, utf_sizes, preview) local function callback(...) table.insert(events, {id, ...}) if test_unreg == id then @@ -44,41 +45,30 @@ local function attach_buffer(evname) events = {} return ret_events end - ]], evname) -end + ]] +end) describe('lua buffer event callbacks: on_lines', function() - before_each(function() - clear() - attach_buffer('on_lines') - end) - - - -- verifying the sizes with nvim_buf_get_offset is nice (checks we cannot - -- assert the wrong thing), but masks errors with unflushed lines (as - -- nvim_buf_get_offset forces a flush of the memline). To be safe run the - -- test both ways. - local function check(verify,utf_sizes) + local function setup_eventcheck(verify, utf_sizes, lines) local lastsize - meths.buf_set_lines(0, 0, -1, true, origlines) + meths.buf_set_lines(0, 0, -1, true, lines) if verify then lastsize = meths.buf_get_offset(0, meths.buf_line_count(0)) end - exec_lua("return test_register(...)", 0, "test1",false,utf_sizes) - local tick = meths.buf_get_changedtick(0) - + exec_lua("return test_register(...)", 0, "on_lines", "test1",false,utf_sizes) local verify_name = "test1" + local function check_events(expected) local events = exec_lua("return get_events(...)" ) if utf_sizes then -- this test case uses ASCII only, so sizes should be the same. -- Unicode is tested below. for _, event in ipairs(expected) do - event[9] = event[8] - event[10] = event[8] + event[9] = event[9] or event[8] + event[10] = event[10] or event[9] end end - eq(expected, events) + expect_events(expected, events, "line updates") if verify then for _, event in ipairs(events) do if event[1] == verify_name and event[2] == "lines" then @@ -92,25 +82,38 @@ describe('lua buffer event callbacks: on_lines', function() end end end + return check_events, function(new) verify_name = new end + end + + -- verifying the sizes with nvim_buf_get_offset is nice (checks we cannot + -- assert the wrong thing), but masks errors with unflushed lines (as + -- nvim_buf_get_offset forces a flush of the memline). To be safe run the + -- test both ways. + local function check(verify,utf_sizes) + local check_events, verify_name = setup_eventcheck(verify, utf_sizes, origlines) + + local tick = meths.buf_get_changedtick(0) command('set autoindent') command('normal! GyyggP') tick = tick + 1 - check_events({{ "test1", "lines", 1, tick, 0, 0, 1, 0}}) + check_events {{ "test1", "lines", 1, tick, 0, 0, 1, 0}} meths.buf_set_lines(0, 3, 5, true, {"changed line"}) tick = tick + 1 - check_events({{ "test1", "lines", 1, tick, 3, 5, 4, 32 }}) + check_events {{ "test1", "lines", 1, tick, 3, 5, 4, 32 }} - exec_lua("return test_register(...)", 0, "test2", true, utf_sizes) + exec_lua("return test_register(...)", 0, "on_lines", "test2", true, utf_sizes) tick = tick + 1 command('undo') -- plugins can opt in to receive changedtick events, or choose -- to only receive actual changes. - check_events({{ "test1", "lines", 1, tick, 3, 4, 5, 13 }, - { "test2", "lines", 1, tick, 3, 4, 5, 13 }, - { "test2", "changedtick", 1, tick+1 } }) + check_events { + { "test1", "lines", 1, tick, 3, 4, 5, 13 }; + { "test2", "lines", 1, tick, 3, 4, 5, 13 }; + { "test2", "changedtick", 1, tick+1 }; + } tick = tick + 1 -- simulate next callback returning true @@ -121,38 +124,40 @@ describe('lua buffer event callbacks: on_lines', function() -- plugins can opt in to receive changedtick events, or choose -- to only receive actual changes. - check_events({{ "test1", "lines", 1, tick, 6, 7, 9, 16 }, - { "test2", "lines", 1, tick, 6, 7, 9, 16 }}) + check_events { + { "test1", "lines", 1, tick, 6, 7, 9, 16 }; + { "test2", "lines", 1, tick, 6, 7, 9, 16 }; + } - verify_name = "test2" + verify_name "test2" meths.buf_set_lines(0, 1, 1, true, {"added"}) tick = tick + 1 - check_events({{ "test2", "lines", 1, tick, 1, 1, 2, 0 }}) + check_events {{ "test2", "lines", 1, tick, 1, 1, 2, 0 }} feed('wix') tick = tick + 1 - check_events({{ "test2", "lines", 1, tick, 4, 5, 5, 16 }}) + check_events {{ "test2", "lines", 1, tick, 4, 5, 5, 16 }} -- check hot path for multiple insert feed('yz') tick = tick + 1 - check_events({{ "test2", "lines", 1, tick, 4, 5, 5, 17 }}) + check_events {{ "test2", "lines", 1, tick, 4, 5, 5, 17 }} feed('<bs>') tick = tick + 1 - check_events({{ "test2", "lines", 1, tick, 4, 5, 5, 19 }}) + check_events {{ "test2", "lines", 1, tick, 4, 5, 5, 19 }} feed('<esc>Go') tick = tick + 1 - check_events({{ "test2", "lines", 1, tick, 11, 11, 12, 0 }}) + check_events {{ "test2", "lines", 1, tick, 11, 11, 12, 0 }} feed('x') tick = tick + 1 - check_events({{ "test2", "lines", 1, tick, 11, 12, 12, 5 }}) + check_events {{ "test2", "lines", 1, tick, 11, 12, 12, 5 }} command('bwipe!') - check_events({{ "test2", "detach", 1 }}) + check_events {{ "test2", "detach", 1 }} end it('works', function() @@ -167,51 +172,63 @@ describe('lua buffer event callbacks: on_lines', function() check(false,true) end) - it('works with utf_sizes and unicode text', function() + local function check_unicode(verify) local unicode_text = {"ascii text", "latin text åäö", "BMP text ɧ αλφά", "BMP text 汉语 ↥↧", "SMP 🤦 🦄🦃", "combining å بِيَّة"} - meths.buf_set_lines(0, 0, -1, true, unicode_text) - feed('gg') - exec_lua("return test_register(...)", 0, "test1", false, true) + local check_events, verify_name = setup_eventcheck(verify, true, unicode_text) + local tick = meths.buf_get_changedtick(0) - feed('dd') + feed('ggdd') tick = tick + 1 - eq({{ "test1", "lines", 1, tick, 0, 1, 0, 11, 11, 11 }}, exec_lua("return get_events(...)" )) + check_events {{ "test1", "lines", 1, tick, 0, 1, 0, 11, 11, 11 }} feed('A<bs>') tick = tick + 1 - eq({{ "test1", "lines", 1, tick, 0, 1, 1, 18, 15, 15 }}, exec_lua("return get_events(...)" )) + check_events {{ "test1", "lines", 1, tick, 0, 1, 1, 18, 15, 15 }} feed('<esc>jylp') tick = tick + 1 - eq({{ "test1", "lines", 1, tick, 1, 2, 2, 21, 16, 16 }}, exec_lua("return get_events(...)" )) + check_events {{ "test1", "lines", 1, tick, 1, 2, 2, 21, 16, 16 }} feed('+eea<cr>') tick = tick + 1 - eq({{ "test1", "lines", 1, tick, 2, 3, 4, 23, 15, 15 }}, exec_lua("return get_events(...)" )) + check_events {{ "test1", "lines", 1, tick, 2, 3, 4, 23, 15, 15 }} feed('<esc>jdw') tick = tick + 1 -- non-BMP chars count as 2 UTF-2 codeunits - eq({{ "test1", "lines", 1, tick, 4, 5, 5, 18, 9, 12 }}, exec_lua("return get_events(...)" )) + check_events {{ "test1", "lines", 1, tick, 4, 5, 5, 18, 9, 12 }} feed('+rx') tick = tick + 1 -- count the individual codepoints of a composed character. - eq({{ "test1", "lines", 1, tick, 5, 6, 6, 27, 20, 20 }}, exec_lua("return get_events(...)" )) + check_events {{ "test1", "lines", 1, tick, 5, 6, 6, 27, 20, 20 }} feed('kJ') tick = tick + 1 + -- verification fails with multiple line updates, sorry about that + verify_name "" -- NB: this is inefficient (but not really wrong). - eq({{ "test1", "lines", 1, tick, 4, 5, 5, 14, 5, 8 }, - { "test1", "lines", 1, tick+1, 5, 6, 5, 27, 20, 20 }}, exec_lua("return get_events(...)" )) + check_events { + { "test1", "lines", 1, tick, 4, 5, 5, 14, 5, 8 }; + { "test1", "lines", 1, tick+1, 5, 6, 5, 27, 20, 20 }; + } + end + + it('works with utf_sizes and unicode text', function() + check_unicode(false) + end) + + it('works with utf_sizes and unicode text with verify', function() + check_unicode(true) end) + it('has valid cursor position while shifting', function() meths.buf_set_lines(0, 0, -1, true, {'line1'}) exec_lua([[ @@ -272,11 +289,6 @@ describe('lua buffer event callbacks: on_lines', function() end) describe('lua: nvim_buf_attach on_bytes', function() - before_each(function() - clear() - attach_buffer('on_bytes') - end) - -- verifying the sizes with nvim_buf_get_offset is nice (checks we cannot -- assert the wrong thing), but masks errors with unflushed lines (as -- nvim_buf_get_offset forces a flush of the memline). To be safe run the @@ -291,7 +303,7 @@ describe('lua: nvim_buf_attach on_bytes', function() local len = meths.buf_get_offset(0, meths.buf_line_count(0)) eq(len == -1 and 1 or len, string.len(shadowbytes)) end - exec_lua("return test_register(...)", 0, "test1", false, false, true) + exec_lua("return test_register(...)", 0, "on_bytes", "test1", false, false, true) meths.buf_get_changedtick(0) local verify_name = "test1" @@ -504,11 +516,13 @@ describe('lua: nvim_buf_attach on_bytes', function() feed ':%s/bcd/' check_events { { "test1", "bytes", 1, 3, 0, 1, 1, 0, 3, 3, 0, 0, 0 }; + { "test1", "bytes", 1, 5, 0, 1, 1, 0, 0, 0, 0, 3, 3 }; } feed 'a' check_events { { "test1", "bytes", 1, 3, 0, 1, 1, 0, 3, 3, 0, 1, 1 }; + { "test1", "bytes", 1, 5, 0, 1, 1, 0, 1, 1, 0, 3, 3 }; } end) diff --git a/test/functional/lua/command_line_completion_spec.lua b/test/functional/lua/command_line_completion_spec.lua new file mode 100644 index 0000000000..3ba7e1589f --- /dev/null +++ b/test/functional/lua/command_line_completion_spec.lua @@ -0,0 +1,171 @@ +local helpers = require('test.functional.helpers')(after_each) + +local clear = helpers.clear +local eq = helpers.eq +local exec_lua = helpers.exec_lua + +local get_completions = function(input, env) + return exec_lua("return {vim._expand_pat(...)}", '^' .. input, env) +end + +local get_compl_parts = function(parts) + return exec_lua("return {vim._expand_pat_get_parts(...)}", parts) +end + +before_each(clear) + +describe('nlua_expand_pat', function() + it('should complete exact matches', function() + eq({{'exact'}, 0}, get_completions('exact', { exact = true })) + end) + + it('should return empty table when nothing matches', function() + eq({{}, 0}, get_completions('foo', { bar = true })) + end) + + it('should return nice completions with function call prefix', function() + eq({{'FOO'}, 6}, get_completions('print(F', { FOO = true, bawr = true })) + end) + + it('should return keys for nested dictionaries', function() + eq( + {{ + 'nvim_buf_set_lines', + 'nvim_buf_set_option' + }, 8 + }, + get_completions('vim.api.nvim_buf_', { + vim = { + api = { + nvim_buf_set_lines = true, + nvim_buf_set_option = true, + nvim_win_doesnt_match = true, + }, + other_key = true, + } + }) + ) + end) + + it('it should work with colons', function() + eq( + {{ + 'bawr', + 'baz', + }, 8 + }, + get_completions('MyClass:b', { + MyClass = { + baz = true, + bawr = true, + foo = false, + } + }) + ) + end) + + it('should return keys for string reffed dictionaries', function() + eq( + {{ + 'nvim_buf_set_lines', + 'nvim_buf_set_option' + }, 11 + }, + get_completions('vim["api"].nvim_buf_', { + vim = { + api = { + nvim_buf_set_lines = true, + nvim_buf_set_option = true, + nvim_win_doesnt_match = true, + }, + other_key = true, + } + }) + ) + end) + + it('should return keys for string reffed dictionaries', function() + eq( + {{ + 'nvim_buf_set_lines', + 'nvim_buf_set_option' + }, 21 + }, + get_completions('vim["nested"]["api"].nvim_buf_', { + vim = { + nested = { + api = { + nvim_buf_set_lines = true, + nvim_buf_set_option = true, + nvim_win_doesnt_match = true, + }, + }, + other_key = true, + } + }) + ) + end) + + it('should be able to interpolate globals', function() + eq( + {{ + 'nvim_buf_set_lines', + 'nvim_buf_set_option' + }, 12 + }, + get_completions('vim[MY_VAR].nvim_buf_', { + MY_VAR = "api", + vim = { + api = { + nvim_buf_set_lines = true, + nvim_buf_set_option = true, + nvim_win_doesnt_match = true, + }, + other_key = true, + } + }) + ) + end) + + it('should return everything if the input is of length 0', function() + eq({{"other", "vim"}, 0}, get_completions('', { vim = true, other = true })) + end) + + describe('get_parts', function() + it('should return an empty list for no separators', function() + eq({{}, 1}, get_compl_parts("vim")) + end) + + it('just the first item before a period', function() + eq({{"vim"}, 5}, get_compl_parts("vim.ap")) + end) + + it('should return multiple parts just for period', function() + eq({{"vim", "api"}, 9}, get_compl_parts("vim.api.nvim_buf")) + end) + + it('should be OK with colons', function() + eq({{"vim", "api"}, 9}, get_compl_parts("vim:api.nvim_buf")) + end) + + it('should work for just one string ref', function() + eq({{"vim", "api"}, 12}, get_compl_parts("vim['api'].nvim_buf")) + end) + + it('should work for just one string ref, with double quote', function() + eq({{"vim", "api"}, 12}, get_compl_parts('vim["api"].nvim_buf')) + end) + + it('should allows back-to-back string ref', function() + eq({{"vim", "nested", "api"}, 22}, get_compl_parts('vim["nested"]["api"].nvim_buf')) + end) + + it('should allows back-to-back string ref with spaces before and after', function() + eq({{"vim", "nested", "api"}, 25}, get_compl_parts('vim[ "nested" ]["api"].nvim_buf')) + end) + + it('should allow VAR style loolup', function() + eq({{"vim", {"NESTED"}, "api"}, 20}, get_compl_parts('vim[NESTED]["api"].nvim_buf')) + end) + end) +end) diff --git a/test/functional/options/defaults_spec.lua b/test/functional/options/defaults_spec.lua index 92d077ed14..eb5e284385 100644 --- a/test/functional/options/defaults_spec.lua +++ b/test/functional/options/defaults_spec.lua @@ -204,9 +204,8 @@ describe('startup defaults', function() end) describe('$NVIM_LOG_FILE', function() - local datasubdir = iswin() and 'nvim-data' or 'nvim' local xdgdir = 'Xtest-startup-xdg-logpath' - local xdgdatadir = xdgdir..'/'..datasubdir + local xdgcachedir = xdgdir..'/nvim' after_each(function() os.remove('Xtest-logpath') rmdir(xdgdir) @@ -218,28 +217,21 @@ describe('startup defaults', function() }}) eq('Xtest-logpath', eval('$NVIM_LOG_FILE')) end) - it('defaults to stdpath("data")/log if empty', function() - eq(true, mkdir(xdgdir) and mkdir(xdgdatadir)) + it('defaults to stdpath("cache")/log if empty', function() + eq(true, mkdir(xdgdir) and mkdir(xdgcachedir)) clear({env={ - XDG_DATA_HOME=xdgdir, + XDG_CACHE_HOME=xdgdir, NVIM_LOG_FILE='', -- Empty is invalid. }}) - eq(xdgdir..'/'..datasubdir..'/log', string.gsub(eval('$NVIM_LOG_FILE'), '\\', '/')) + eq(xdgcachedir..'/log', string.gsub(eval('$NVIM_LOG_FILE'), '\\', '/')) end) - it('defaults to stdpath("data")/log if invalid', function() - eq(true, mkdir(xdgdir) and mkdir(xdgdatadir)) + it('defaults to stdpath("cache")/log if invalid', function() + eq(true, mkdir(xdgdir) and mkdir(xdgcachedir)) clear({env={ - XDG_DATA_HOME=xdgdir, + XDG_CACHE_HOME=xdgdir, NVIM_LOG_FILE='.', -- Any directory is invalid. }}) - eq(xdgdir..'/'..datasubdir..'/log', string.gsub(eval('$NVIM_LOG_FILE'), '\\', '/')) - end) - it('defaults to .nvimlog if stdpath("data") is invalid', function() - clear({env={ - XDG_DATA_HOME='Xtest-missing-xdg-dir', - NVIM_LOG_FILE='.', -- Any directory is invalid. - }}) - eq('.nvimlog', eval('$NVIM_LOG_FILE')) + eq(xdgcachedir..'/log', string.gsub(eval('$NVIM_LOG_FILE'), '\\', '/')) end) end) end) diff --git a/test/functional/plugin/lsp/diagnostic_spec.lua b/test/functional/plugin/lsp/diagnostic_spec.lua index 3a676359ab..4705a76465 100644 --- a/test/functional/plugin/lsp/diagnostic_spec.lua +++ b/test/functional/plugin/lsp/diagnostic_spec.lua @@ -12,41 +12,41 @@ describe('vim.lsp.diagnostic', function() clear() exec_lua [[ - require('vim.lsp') - - make_range = function(x1, y1, x2, y2) - return { start = { line = x1, character = y1 }, ['end'] = { line = x2, character = y2 } } - end - - make_error = function(msg, x1, y1, x2, y2) - return { - range = make_range(x1, y1, x2, y2), - message = msg, - severity = 1, - } - end - - make_warning = function(msg, x1, y1, x2, y2) - return { - range = make_range(x1, y1, x2, y2), - message = msg, - severity = 2, - } - end - - make_information = function(msg, x1, y1, x2, y2) - return { - range = make_range(x1, y1, x2, y2), - message = msg, - severity = 3, - } - end - - count_of_extmarks_for_client = function(bufnr, client_id) - return #vim.api.nvim_buf_get_extmarks( - bufnr, vim.lsp.diagnostic._get_diagnostic_namespace(client_id), 0, -1, {} - ) - end + require('vim.lsp') + + make_range = function(x1, y1, x2, y2) + return { start = { line = x1, character = y1 }, ['end'] = { line = x2, character = y2 } } + end + + make_error = function(msg, x1, y1, x2, y2) + return { + range = make_range(x1, y1, x2, y2), + message = msg, + severity = 1, + } + end + + make_warning = function(msg, x1, y1, x2, y2) + return { + range = make_range(x1, y1, x2, y2), + message = msg, + severity = 2, + } + end + + make_information = function(msg, x1, y1, x2, y2) + return { + range = make_range(x1, y1, x2, y2), + message = msg, + severity = 3, + } + end + + count_of_extmarks_for_client = function(bufnr, client_id) + return #vim.api.nvim_buf_get_extmarks( + bufnr, vim.lsp.diagnostic._get_diagnostic_namespace(client_id), 0, -1, {} + ) + end ]] fake_uri = "file://fake/uri" @@ -640,6 +640,36 @@ describe('vim.lsp.diagnostic', function() eq(expected_spacing, #spacing) end) + + it('allows filtering via severity limit', function() + local get_extmark_count_with_severity = function(severity_limit) + return exec_lua([[ + PublishDiagnostics = vim.lsp.with(vim.lsp.diagnostic.on_publish_diagnostics, { + underline = false, + virtual_text = { + severity_limit = ... + }, + }) + + PublishDiagnostics(nil, nil, { + uri = fake_uri, + diagnostics = { + make_warning('Delayed Diagnostic', 4, 4, 4, 4), + } + }, 1 + ) + + return count_of_extmarks_for_client(diagnostic_bufnr, 1) + ]], severity_limit) + end + + -- No messages with Error or higher + eq(0, get_extmark_count_with_severity("Error")) + + -- But now we don't filter it + eq(1, get_extmark_count_with_severity("Warning")) + eq(1, get_extmark_count_with_severity("Hint")) + end) end) describe('lsp.util.show_line_diagnostics', function() diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua index ec06cb0639..981e2a96a8 100644 --- a/test/functional/plugin/lsp_spec.lua +++ b/test/functional/plugin/lsp_spec.lua @@ -193,6 +193,12 @@ describe('LSP', function() end) describe('basic_init test', function() + after_each(function() + stop() + exec_lua("lsp.stop_client(lsp.get_active_clients())") + exec_lua("lsp._vim_exit_handler()") + end) + it('should run correctly', function() local expected_callbacks = { {NIL, "test", {}, 1}; @@ -303,6 +309,19 @@ describe('LSP', function() end; } end) + it('workspace/configuration returns NIL per section if client was started without config.settings', function() + clear() + fake_lsp_server_setup('workspace/configuration no settings') + eq({ NIL, NIL, }, exec_lua [[ + local params = { + items = { + {section = 'foo'}, + {section = 'bar'}, + } + } + return vim.lsp.handlers['workspace/configuration'](nil, nil, params, TEST_RPC_CLIENT_ID) + ]]) + end) it('should verify capabilities sent', function() local expected_callbacks = { @@ -1045,7 +1064,7 @@ describe('LSP', function() return { edits = { make_edit(0, 0, 0, 3, "First ↥ 🤦 🦄") - }, + }, textDocument = { uri = "file://fake/uri"; version = editVersion @@ -1086,7 +1105,7 @@ describe('LSP', function() local args = {...} local versionedBuf = args[2] vim.lsp.util.buf_versions[versionedBuf.bufnr] = versionedBuf.currentVersion - vim.lsp.util.apply_text_document_edit(...) + vim.lsp.util.apply_text_document_edit(args[1]) ]], edit, versionedBuf) end @@ -1109,6 +1128,7 @@ describe('LSP', function() }, buf_lines(target_bufnr)) end) end) + describe('workspace_apply_edit', function() it('workspace/applyEdit returns ApplyWorkspaceEditResponse', function() local expected = { @@ -1124,6 +1144,106 @@ describe('LSP', function() ]]) end) end) + + describe('apply_workspace_edit', function() + local replace_line_edit = function(row, new_line, editVersion) + return { + edits = { + -- NOTE: This is a hack if you have a line longer than 1000 it won't replace it + make_edit(row, 0, row, 1000, new_line) + }, + textDocument = { + uri = "file://fake/uri"; + version = editVersion + } + } + end + + -- Some servers send all the edits separately, but with the same version. + -- We should not stop applying the edits + local make_workspace_edit = function(changes) + return { + documentChanges = changes + } + end + + local target_bufnr, changedtick = nil, nil + + before_each(function() + local ret = exec_lua [[ + local bufnr = vim.uri_to_bufnr("file://fake/uri") + local lines = { + "Original Line #1", + "Original Line #2" + } + + vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, lines) + + local update_changed_tick = function() + vim.lsp.util.buf_versions[bufnr] = vim.api.nvim_buf_get_var(bufnr, 'changedtick') + end + + update_changed_tick() + vim.api.nvim_buf_attach(bufnr, false, { + on_changedtick = function() + update_changed_tick() + end + }) + + return {bufnr, vim.api.nvim_buf_get_var(bufnr, 'changedtick')} + ]] + + target_bufnr = ret[1] + changedtick = ret[2] + end) + + it('apply_workspace_edit applies a single edit', function() + local new_lines = { + "First Line", + } + + local edits = {} + for row, line in ipairs(new_lines) do + table.insert(edits, replace_line_edit(row - 1, line, changedtick)) + end + + eq({ + "First Line", + "Original Line #2", + }, exec_lua([[ + local args = {...} + local workspace_edits = args[1] + local target_bufnr = args[2] + + vim.lsp.util.apply_workspace_edit(workspace_edits) + + return vim.api.nvim_buf_get_lines(target_bufnr, 0, -1, false) + ]], make_workspace_edit(edits), target_bufnr)) + end) + + it('apply_workspace_edit applies multiple edits', function() + local new_lines = { + "First Line", + "Second Line", + } + + local edits = {} + for row, line in ipairs(new_lines) do + table.insert(edits, replace_line_edit(row - 1, line, changedtick)) + end + + eq(new_lines, exec_lua([[ + local args = {...} + local workspace_edits = args[1] + local target_bufnr = args[2] + + vim.lsp.util.apply_workspace_edit(workspace_edits) + + return vim.api.nvim_buf_get_lines(target_bufnr, 0, -1, false) + ]], make_workspace_edit(edits), target_bufnr)) + end) + end) + describe('completion_list_to_complete_items', function() -- Completion option precedence: -- textEdit.newText > insertText > label diff --git a/test/functional/treesitter/parser_spec.lua b/test/functional/treesitter/parser_spec.lua index 520574c08a..f99362fbdf 100644 --- a/test/functional/treesitter/parser_spec.lua +++ b/test/functional/treesitter/parser_spec.lua @@ -245,7 +245,7 @@ void ui_refresh(void) parser = vim.treesitter.get_parser(0, "c") tree = parser:parse()[1] res = {} - for pattern, match in cquery:iter_matches(tree:root(), 0, 0, 1) do + for pattern, match in cquery:iter_matches(tree:root(), 0) do -- can't transmit node over RPC. just check the name and range local mrepr = {} for cid,node in pairs(match) do @@ -289,7 +289,7 @@ void ui_refresh(void) local query = query.parse_query("c", ...) local nodes = {} - for _, node in query:iter_captures(parser:parse()[1]:root(), 0, 0, 19) do + for _, node in query:iter_captures(parser:parse()[1]:root(), 0) do table.insert(nodes, {node:range()}) end @@ -365,7 +365,7 @@ void ui_refresh(void) query = vim.treesitter.parse_query("c", "(declaration) @decl") local nodes = {} - for _, node in query:iter_captures(parser:parse()[1]:root(), 0, 0, 19) do + for _, node in query:iter_captures(parser:parse()[1]:root(), 0) do table.insert(nodes, node) end @@ -412,7 +412,7 @@ void ui_refresh(void) local nodes = {} local query = vim.treesitter.parse_query("c", '((identifier) @id (eq? @id "foo"))') - for _, node in query:iter_captures(parser:parse()[1]:root(), str, 0, 2) do + for _, node in query:iter_captures(parser:parse()[1]:root(), str) do table.insert(nodes, { node:range() }) end @@ -421,6 +421,29 @@ void ui_refresh(void) eq({ {0, 10, 0, 13} }, ret) end) + it("should use node range when omitted", function() + local txt = [[ + int foo = 42; + int bar = 13; + ]] + + local ret = exec_lua([[ + local str = ... + local parser = vim.treesitter.get_string_parser(str, "c") + + local nodes = {} + local query = vim.treesitter.parse_query("c", '((identifier) @foo)') + local first_child = parser:parse()[1]:root():child(1) + + for _, node in query:iter_captures(first_child, str) do + table.insert(nodes, { node:range() }) + end + + return nodes]], txt) + + eq({ {1, 10, 1, 13} }, ret) + end) + describe("when creating a language tree", function() local function get_ranges() return exec_lua([[ @@ -539,7 +562,7 @@ int x = INT_MAX; query = vim.treesitter.parse_query("c", '((number_literal) @number (#set! "key" "value"))') parser = vim.treesitter.get_parser(0, "c") - for pattern, match, metadata in query:iter_matches(parser:parse()[1]:root(), 0, 0, 1) do + for pattern, match, metadata in query:iter_matches(parser:parse()[1]:root(), 0) do result = metadata.key end @@ -562,7 +585,7 @@ int x = INT_MAX; query = vim.treesitter.parse_query("c", '((number_literal) @number (#set! @number "key" "value"))') parser = vim.treesitter.get_parser(0, "c") - for pattern, match, metadata in query:iter_matches(parser:parse()[1]:root(), 0, 0, 1) do + for pattern, match, metadata in query:iter_matches(parser:parse()[1]:root(), 0) do result = metadata[pattern].key end diff --git a/test/functional/ui/sign_spec.lua b/test/functional/ui/sign_spec.lua index d1b8de5e4e..1937102782 100644 --- a/test/functional/ui/sign_spec.lua +++ b/test/functional/ui/sign_spec.lua @@ -266,6 +266,111 @@ describe('Signs', function() ]]} end) + it('auto-resize sign column with minimum size (#13783)', function() + feed('ia<cr>b<cr>c<cr><esc>') + command('set number') + -- sign column should always accommodate at the minimum size + command('set signcolumn=auto:1-3') + screen:expect([[ + {2: }{6: 1 }a | + {2: }{6: 2 }b | + {2: }{6: 3 }c | + {2: }{6: 4 }^ | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + | + ]]) + -- should support up to 8 signs at minimum + command('set signcolumn=auto:8-9') + screen:expect([[ + {2: }{6: 1 }a | + {2: }{6: 2 }b | + {2: }{6: 3 }c | + {2: }{6: 4 }^ | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + | + ]]) + -- should keep the same sign size when signs are not exceeding + -- the minimum + command('set signcolumn=auto:2-5') + command('sign define pietSearch text=>> texthl=Search') + command('sign place 1 line=1 name=pietSearch buffer=1') + screen:expect([[ + {1:>>}{2: }{6: 1 }a | + {2: }{6: 2 }b | + {2: }{6: 3 }c | + {2: }{6: 4 }^ | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + | + ]]) + -- should resize itself when signs are exceeding minimum but + -- not over the maximum + command('sign place 2 line=1 name=pietSearch buffer=1') + command('sign place 3 line=1 name=pietSearch buffer=1') + command('sign place 4 line=1 name=pietSearch buffer=1') + screen:expect([[ + {1:>>>>>>>>}{6: 1 }a | + {2: }{6: 2 }b | + {2: }{6: 3 }c | + {2: }{6:^ 4 } | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + | + ]]) + -- should keep the column at maximum size when signs are + -- exceeding the maximum + command('sign place 5 line=1 name=pietSearch buffer=1') + command('sign place 6 line=1 name=pietSearch buffer=1') + command('sign place 7 line=1 name=pietSearch buffer=1') + command('sign place 8 line=1 name=pietSearch buffer=1') + screen:expect([[ + {1:>>>>>>>>>>}{6: 1 }a | + {2: }{6: 2 }b | + {2: }{6: 3 }c | + {2: ^ }{6: 4 } | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + | + ]]) + end) + it('ignores signs with no icon and text when calculting the signcolumn width', function() feed('ia<cr>b<cr>c<cr><esc>') command('set number') diff --git a/test/functional/viml/completion_spec.lua b/test/functional/viml/completion_spec.lua index 01fc50289d..a4241fe5aa 100644 --- a/test/functional/viml/completion_spec.lua +++ b/test/functional/viml/completion_spec.lua @@ -3,6 +3,7 @@ local Screen = require('test.functional.ui.screen') local clear, feed = helpers.clear, helpers.feed local eval, eq, neq = helpers.eval, helpers.eq, helpers.neq local feed_command, source, expect = helpers.feed_command, helpers.source, helpers.expect +local funcs = helpers.funcs local curbufmeths = helpers.curbufmeths local command = helpers.command local meths = helpers.meths @@ -26,6 +27,7 @@ describe('completion', function() [7] = {foreground = Screen.colors.White, background = Screen.colors.Red}, [8] = {reverse = true}, [9] = {bold = true, reverse = true}, + [10] = {foreground = Screen.colors.Grey0, background = Screen.colors.Yellow}, }) end) @@ -895,8 +897,47 @@ describe('completion', function() ]]) end) - describe('from the commandline window', function() + describe('lua completion', function() + it('expands when there is only one match', function() + feed(':lua CURRENT_TESTING_VAR = 1<CR>') + feed(':lua CURRENT_TESTING_<TAB>') + screen:expect{grid=[[ + | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + :lua CURRENT_TESTING_VAR^ | + ]]} + end) + it('expands when there is only one match', function() + feed(':lua CURRENT_TESTING_FOO = 1<CR>') + feed(':lua CURRENT_TESTING_BAR = 1<CR>') + feed(':lua CURRENT_TESTING_<TAB>') + screen:expect{ grid = [[ + | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {10:CURRENT_TESTING_BAR}{9: CURRENT_TESTING_FOO }| + :lua CURRENT_TESTING_BAR^ | + ]], unchanged = true } + end) + + it('provides completion from `getcompletion()`', function() + eq({'vim'}, funcs.getcompletion('vi', 'lua')) + eq({'api'}, funcs.getcompletion('vim.ap', 'lua')) + eq({'tbl_filter'}, funcs.getcompletion('vim.tbl_fil', 'lua')) + eq({'vim'}, funcs.getcompletion('print(vi', 'lua')) + end) + end) + + describe('from the commandline window', function() it('is cleared after CTRL-C', function () feed('q:') feed('ifoo faa fee f') diff --git a/test/symbolic/klee/nvim/charset.c b/test/symbolic/klee/nvim/charset.c index f9bc3fabc4..fd1c5ee4b9 100644 --- a/test/symbolic/klee/nvim/charset.c +++ b/test/symbolic/klee/nvim/charset.c @@ -62,7 +62,7 @@ void vim_str2nr(const char_u *const start, int *const prep, int *const len, goto vim_str2nr_dec; } default: { - assert(false); + abort(); } } } else if ((what & (STR2NR_HEX|STR2NR_OCT|STR2NR_BIN)) @@ -102,7 +102,7 @@ void vim_str2nr(const char_u *const start, int *const prep, int *const len, } // Do the string-to-numeric conversion "manually" to avoid sscanf quirks. - assert(false); // Should’ve used goto earlier. + abort(); // Should’ve used goto earlier. #define PARSE_NUMBER(base, cond, conv) \ do { \ while (!STRING_ENDED(ptr) && (cond)) { \ diff --git a/test/symbolic/klee/nvim/memory.c b/test/symbolic/klee/nvim/memory.c index df422cea3e..1614f813d7 100644 --- a/test/symbolic/klee/nvim/memory.c +++ b/test/symbolic/klee/nvim/memory.c @@ -45,7 +45,7 @@ void xfree(void *const p) return; } } - assert(false); + abort(); } void *xrealloc(void *const p, size_t new_size) @@ -63,7 +63,7 @@ void *xrealloc(void *const p, size_t new_size) return ret; } } - assert(false); + abort(); return (void *)(intptr_t)1; } |