diff options
Diffstat (limited to 'test')
-rw-r--r-- | test/functional/api/keymap_spec.lua | 4 | ||||
-rw-r--r-- | test/functional/api/vim_spec.lua | 13 | ||||
-rw-r--r-- | test/functional/autocmd/textyankpost_spec.lua | 48 | ||||
-rw-r--r-- | test/functional/core/startup_spec.lua | 26 | ||||
-rw-r--r-- | test/functional/eval/buf_functions_spec.lua | 6 | ||||
-rw-r--r-- | test/functional/eval/map_functions_spec.lua | 2 | ||||
-rw-r--r-- | test/functional/eval/sort_spec.lua | 3 | ||||
-rw-r--r-- | test/functional/eval/uniq_spec.lua | 2 | ||||
-rw-r--r-- | test/functional/legacy/075_maparg_spec.lua | 6 | ||||
-rw-r--r-- | test/functional/legacy/memory_usage_spec.lua | 161 | ||||
-rw-r--r-- | test/functional/lua/treesitter_spec.lua | 8 | ||||
-rw-r--r-- | test/functional/lua/uri_spec.lua | 23 | ||||
-rw-r--r-- | test/functional/lua/vim_spec.lua | 180 | ||||
-rw-r--r-- | test/functional/plugin/lsp_spec.lua | 148 | ||||
-rw-r--r-- | test/functional/provider/define_spec.lua | 15 | ||||
-rw-r--r-- | test/unit/eval/helpers.lua | 12 | ||||
-rw-r--r-- | test/unit/eval/typval_spec.lua | 48 |
17 files changed, 633 insertions, 72 deletions
diff --git a/test/functional/api/keymap_spec.lua b/test/functional/api/keymap_spec.lua index 210394c83f..5da2c6b531 100644 --- a/test/functional/api/keymap_spec.lua +++ b/test/functional/api/keymap_spec.lua @@ -21,6 +21,7 @@ describe('nvim_get_keymap', function() local foo_bar_string = 'nnoremap foo bar' local foo_bar_map_table = { lhs='foo', + script=0, silent=0, rhs='bar', expr=0, @@ -245,6 +246,7 @@ describe('nvim_get_keymap', function() it('works correctly despite various &cpo settings', function() local cpo_table = { + script=0, silent=0, expr=0, sid=0, @@ -302,6 +304,7 @@ describe('nvim_get_keymap', function() lhs='| |', rhs='| |', mode='n', + script=0, silent=0, expr=0, sid=0, @@ -343,6 +346,7 @@ describe('nvim_set_keymap, nvim_del_keymap', function() to_return.noremap = not opts.noremap and 0 or 1 to_return.lhs = lhs to_return.rhs = rhs + to_return.script = 0 to_return.silent = not opts.silent and 0 or 1 to_return.nowait = not opts.nowait and 0 or 1 to_return.expr = not opts.expr and 0 or 1 diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index 2e9d0f57ac..72e810e3e4 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -482,6 +482,11 @@ describe('API', function() eq(true, status) -- nvim_input() did not fail. eq("E117:", v_errnum) -- v:errmsg was updated. end) + + it('does not crash even if trans_special result is largest #11788, #12287', function() + command("call nvim_input('<M-'.nr2char(0x40000000).'>')") + eq(1, eval('1')) + end) end) describe('nvim_paste', function() @@ -1808,7 +1813,7 @@ describe('API', function() eq({id=1}, meths.get_current_buf()) end) - it("doesn't cause BufEnter or BufWinEnter autocmds", function() + it("does not trigger BufEnter, BufWinEnter", function() command("let g:fired = v:false") command("au BufEnter,BufWinEnter * let g:fired = v:true") @@ -1818,7 +1823,7 @@ describe('API', function() eq(false, eval('g:fired')) end) - it('|scratch-buffer|', function() + it('scratch-buffer', function() eq({id=2}, meths.create_buf(false, true)) eq({id=3}, meths.create_buf(true, true)) eq({id=4}, meths.create_buf(true, true)) @@ -1845,6 +1850,7 @@ describe('API', function() eq('nofile', meths.buf_get_option(b, 'buftype')) eq('hide', meths.buf_get_option(b, 'bufhidden')) eq(false, meths.buf_get_option(b, 'swapfile')) + eq(false, meths.buf_get_option(b, 'modeline')) end -- @@ -1860,8 +1866,9 @@ describe('API', function() eq('nofile', meths.buf_get_option(edited_buf, 'buftype')) eq('hide', meths.buf_get_option(edited_buf, 'bufhidden')) eq(false, meths.buf_get_option(edited_buf, 'swapfile')) + eq(false, meths.buf_get_option(edited_buf, 'modeline')) - -- scratch buffer can be wiped without error + -- Scratch buffer can be wiped without error. command('bwipe') screen:expect([[ ^ | diff --git a/test/functional/autocmd/textyankpost_spec.lua b/test/functional/autocmd/textyankpost_spec.lua index 8c23b72cff..3898d59e58 100644 --- a/test/functional/autocmd/textyankpost_spec.lua +++ b/test/functional/autocmd/textyankpost_spec.lua @@ -27,7 +27,8 @@ describe('TextYankPost', function() operator = 'y', regcontents = { 'foo\nbar' }, regname = '', - regtype = 'V' + regtype = 'V', + visual = false }, eval('g:event')) eq(1, eval('g:count')) @@ -40,7 +41,8 @@ describe('TextYankPost', function() operator = 'y', regcontents = { 'baz ' }, regname = '', - regtype = 'v' + regtype = 'v', + visual = false }, eval('g:event')) eq(2, eval('g:count')) @@ -50,7 +52,8 @@ describe('TextYankPost', function() operator = 'y', regcontents = { 'foo', 'baz' }, regname = '', - regtype = "\0223" -- ^V + block width + regtype = "\0223", -- ^V + block width + visual = true }, eval('g:event')) eq(3, eval('g:count')) end) @@ -62,7 +65,8 @@ describe('TextYankPost', function() operator = 'y', regcontents = { 'foo\nbar' }, regname = '', - regtype = 'V' + regtype = 'V', + visual = false }, eval('g:event')) command('set debug=msg') @@ -92,7 +96,8 @@ describe('TextYankPost', function() operator = 'y', regcontents = { 'foo\nbar' }, regname = '', - regtype = 'V' + regtype = 'V', + visual = false }, eval('g:event')) eq(1, eval('g:count')) eq({ 'foo\nbar' }, funcs.getreg('+',1,1)) @@ -105,7 +110,8 @@ describe('TextYankPost', function() operator = 'd', regcontents = { 'foo' }, regname = '', - regtype = 'v' + regtype = 'v', + visual = false }, eval('g:event')) eq(1, eval('g:count')) @@ -115,7 +121,8 @@ describe('TextYankPost', function() operator = 'd', regcontents = { '\nbar' }, regname = '', - regtype = 'V' + regtype = 'V', + visual = false }, eval('g:event')) eq(2, eval('g:count')) @@ -125,7 +132,8 @@ describe('TextYankPost', function() operator = 'c', regcontents = { 'baz' }, regname = '', - regtype = 'v' + regtype = 'v', + visual = false }, eval('g:event')) eq(3, eval('g:count')) end) @@ -153,7 +161,8 @@ describe('TextYankPost', function() operator = 'y', regcontents = { 'bar' }, regname = 'b', - regtype = 'v' + regtype = 'v', + visual = false }, eval('g:event')) feed('"*yy') @@ -162,7 +171,8 @@ describe('TextYankPost', function() operator = 'y', regcontents = { 'foo\nbar' }, regname = '*', - regtype = 'V' + regtype = 'V', + visual = false }, eval('g:event')) command("set clipboard=unnamed") @@ -174,7 +184,8 @@ describe('TextYankPost', function() operator = 'y', regcontents = { 'foo\nbar' }, regname = '', - regtype = 'V' + regtype = 'V', + visual = false }, eval('g:event')) feed('"*yy') @@ -183,7 +194,8 @@ describe('TextYankPost', function() operator = 'y', regcontents = { 'foo\nbar' }, regname = '*', - regtype = 'V' + regtype = 'V', + visual = false }, eval('g:event')) end) @@ -194,7 +206,8 @@ describe('TextYankPost', function() operator = 'd', regcontents = { 'foo\nbar' }, regname = '+', - regtype = 'V' + regtype = 'V', + visual = false }, eval('g:event')) eq(1, eval('g:count')) @@ -204,7 +217,8 @@ describe('TextYankPost', function() operator = 'y', regcontents = { 'baz text' }, regname = '', - regtype = 'V' + regtype = 'V', + visual = false }, eval('g:event')) eq(2, eval('g:count')) @@ -214,7 +228,8 @@ describe('TextYankPost', function() operator = 'y', regcontents = { 'baz ' }, regname = '', - regtype = 'v' + regtype = 'v', + visual = false }, eval('g:event')) eq(3, eval('g:count')) @@ -224,7 +239,8 @@ describe('TextYankPost', function() operator = 'd', regcontents = { 'baz text' }, regname = '', - regtype = 'V' + regtype = 'V', + visual = false }, eval('g:event')) eq(4, eval('g:count')) end) diff --git a/test/functional/core/startup_spec.lua b/test/functional/core/startup_spec.lua index cc10d36a10..3269fbc68d 100644 --- a/test/functional/core/startup_spec.lua +++ b/test/functional/core/startup_spec.lua @@ -277,6 +277,32 @@ describe('startup', function() [4] = {bold = true, foreground = Screen.colors.Blue1}, }}) end) + + it('fixed hang issue with --headless (#11386)', function() + local expected = '' + local period = 100 + for i = 1, period - 1 do + expected = expected .. i .. '\r\n' + end + expected = expected .. period + eq( + expected, + -- FIXME(codehex): We should really set a timeout for the system function. + -- If this test fails, there will be a waiting input state. + funcs.system({nvim_prog, '-u', 'NONE', '-c', + 'for i in range(1, 100) | echo i | endfor | quit', + '--headless' + }) + ) + end) + + it("get command line arguments from v:argv", function() + local out = funcs.system({ nvim_prog, '-u', 'NONE', '-i', 'NONE', '--headless', + '--cmd', nvim_set, + '-c', [[echo v:argv[-1:] len(v:argv) > 1]], + '+q' }) + eq('[\'+q\'] 1', out) + end) end) describe('sysinit', function() diff --git a/test/functional/eval/buf_functions_spec.lua b/test/functional/eval/buf_functions_spec.lua index 37f4c89bfd..06841a4521 100644 --- a/test/functional/eval/buf_functions_spec.lua +++ b/test/functional/eval/buf_functions_spec.lua @@ -31,10 +31,12 @@ for _, func in ipairs({'bufname(%s)', 'bufnr(%s)', 'bufwinnr(%s)', it('errors out when receives v:true/v:false/v:null', function() -- Not compatible with Vim: in Vim it always results in buffer not found -- without any error messages. - for _, var in ipairs({'v:true', 'v:false', 'v:null'}) do - eq('Vim(call):E5300: Expected a Number or a String', + for _, var in ipairs({'v:true', 'v:false'}) do + eq('Vim(call):E5299: Expected a Number or a String, Boolean found', exc_exec('call ' .. func:format(var))) end + eq('Vim(call):E5300: Expected a Number or a String', + exc_exec('call ' .. func:format('v:null'))) end) it('errors out when receives invalid argument', function() eq('Vim(call):E745: Expected a Number or a String, List found', diff --git a/test/functional/eval/map_functions_spec.lua b/test/functional/eval/map_functions_spec.lua index 2747a94570..275c72d212 100644 --- a/test/functional/eval/map_functions_spec.lua +++ b/test/functional/eval/map_functions_spec.lua @@ -13,6 +13,7 @@ describe('maparg()', function() local foo_bar_map_table = { lhs='foo', + script=0, silent=0, rhs='bar', expr=0, @@ -147,6 +148,7 @@ describe('maparg()', function() mode = 'n', noremap = 1, nowait = 0, + script=0, sid = 0, silent = 0, lnum = 0, diff --git a/test/functional/eval/sort_spec.lua b/test/functional/eval/sort_spec.lua index 82557575ce..e1cc2c2924 100644 --- a/test/functional/eval/sort_spec.lua +++ b/test/functional/eval/sort_spec.lua @@ -14,7 +14,7 @@ before_each(clear) describe('sort()', function() it('errors out when sorting special values', function() - eq('Vim(call):E907: Using a special value as a Float', + eq('Vim(call):E362: Using a boolean value as a Float', exc_exec('call sort([v:true, v:false], "f")')) end) @@ -30,6 +30,7 @@ describe('sort()', function() errors[err] = true end eq({ + ['E362: Using a boolean value as a Float']=true, ['E891: Using a Funcref as a Float']=true, ['E892: Using a String as a Float']=true, ['E893: Using a List as a Float']=true, diff --git a/test/functional/eval/uniq_spec.lua b/test/functional/eval/uniq_spec.lua index 0e7a013e32..5cdba0a0f6 100644 --- a/test/functional/eval/uniq_spec.lua +++ b/test/functional/eval/uniq_spec.lua @@ -11,7 +11,7 @@ before_each(clear) describe('uniq()', function() it('errors out when processing special values', function() - eq('Vim(call):E907: Using a special value as a Float', + eq('Vim(call):E362: Using a boolean value as a Float', exc_exec('call uniq([v:true, v:false], "f")')) end) diff --git a/test/functional/legacy/075_maparg_spec.lua b/test/functional/legacy/075_maparg_spec.lua index 0164f5077a..ee2b041b51 100644 --- a/test/functional/legacy/075_maparg_spec.lua +++ b/test/functional/legacy/075_maparg_spec.lua @@ -49,9 +49,9 @@ describe('maparg()', function() -- Assert buffer contents. expect([[ is<F4>foo - {'lnum': 0, 'silent': 0, 'noremap': 0, 'lhs': 'foo<C-V>', 'mode': ' ', 'nowait': 0, 'expr': 0, 'sid': 0, 'rhs': 'is<F4>foo', 'buffer': 0} - {'lnum': 0, 'silent': 1, 'noremap': 1, 'lhs': 'bar', 'mode': 'v', 'nowait': 0, 'expr': 1, 'sid': 0, 'rhs': 'isbar', 'buffer': 1} - {'lnum': 0, 'silent': 0, 'noremap': 0, 'lhs': 'foo', 'mode': ' ', 'nowait': 1, 'expr': 0, 'sid': 0, 'rhs': 'bar', 'buffer': 1} + {'lnum': 0, 'script': 0, 'silent': 0, 'noremap': 0, 'lhs': 'foo<C-V>', 'mode': ' ', 'nowait': 0, 'expr': 0, 'sid': 0, 'rhs': 'is<F4>foo', 'buffer': 0} + {'lnum': 0, 'script': 1, 'silent': 1, 'noremap': 1, 'lhs': 'bar', 'mode': 'v', 'nowait': 0, 'expr': 1, 'sid': 0, 'rhs': 'isbar', 'buffer': 1} + {'lnum': 0, 'script': 0, 'silent': 0, 'noremap': 0, 'lhs': 'foo', 'mode': ' ', 'nowait': 1, 'expr': 0, 'sid': 0, 'rhs': 'bar', 'buffer': 1} xrx yRy abcd]]) diff --git a/test/functional/legacy/memory_usage_spec.lua b/test/functional/legacy/memory_usage_spec.lua new file mode 100644 index 0000000000..28ca749749 --- /dev/null +++ b/test/functional/legacy/memory_usage_spec.lua @@ -0,0 +1,161 @@ +local helpers = require('test.functional.helpers')(after_each) +local clear = helpers.clear +local eval = helpers.eval +local eq = helpers.eq +local feed_command = helpers.feed_command +local iswin = helpers.iswin +local retry = helpers.retry +local ok = helpers.ok +local source = helpers.source + +local monitor_memory_usage = { + memory_usage = function(self) + local handle + if iswin() then + handle = io.popen('wmic process where processid=' ..self.pid..' get WorkingSetSize') + else + handle = io.popen('ps -o rss= -p '..self.pid) + end + return tonumber(handle:read('*a'):match('%d+')) + end, + op = function(self) + retry(nil, 10000, function() + local val = self.memory_usage(self) + if self.max < val then + self.max = val + end + table.insert(self.hist, val) + ok(#self.hist > 20) + local result = {} + for key,value in ipairs(self.hist) do + if value ~= self.hist[key + 1] then + table.insert(result, value) + end + end + table.remove(self.hist, 1) + self.last = self.hist[#self.hist] + eq(#result, 1) + end) + end, + dump = function(self) + return 'max: '..self.max ..', last: '..self.last + end, + monitor_memory_usage = function(self, pid) + local obj = { + pid = pid, + max = 0, + last = 0, + hist = {}, + } + setmetatable(obj, { __index = self }) + obj:op() + return obj + end +} +setmetatable(monitor_memory_usage, +{__call = function(self, pid) + return monitor_memory_usage.monitor_memory_usage(self, pid) +end}) + +describe('memory usage', function() + local function check_result(tbl, status, result) + if not status then + print('') + for key, val in pairs(tbl) do + print(key, val:dump()) + end + error(result) + end + end + + local function isasan() + local version = eval('execute("version")') + return version:match('-fsanitize=[a-z,]*address') + end + + before_each(clear) + + --[[ + Case: if a local variable captures a:000, funccall object will be free + just after it finishes. + ]]-- + it('function capture vargs', function() + if isasan() then + pending('ASAN build is difficult to estimate memory usage') + end + if iswin() and eval("executable('wmic')") == 0 then + pending('missing "wmic" command') + elseif eval("executable('ps')") == 0 then + pending('missing "ps" command') + end + + local pid = eval('getpid()') + local before = monitor_memory_usage(pid) + source([[ + func s:f(...) + let x = a:000 + endfunc + for _ in range(10000) + call s:f(0) + endfor + ]]) + local after = monitor_memory_usage(pid) + -- Estimate the limit of max usage as 2x initial usage. + -- The lower limit can fluctuate a bit, use 97%. + check_result({before=before, after=after}, + pcall(ok, before.last * 97 / 100 < after.max)) + check_result({before=before, after=after}, + pcall(ok, before.last * 2 > after.max)) + -- In this case, garbage collecting is not needed. + -- The value might fluctuate a bit, allow for 3% tolerance below and 5% above. + -- Based on various test runs. + local lower = after.last * 97 / 100 + local upper = after.last * 105 / 100 + check_result({before=before, after=after}, pcall(ok, lower < after.max)) + check_result({before=before, after=after}, pcall(ok, after.max < upper)) + end) + + --[[ + Case: if a local variable captures l: dict, funccall object will not be + free until garbage collector runs, but after that memory usage doesn't + increase so much even when rerun Xtest.vim since system memory caches. + ]]-- + it('function capture lvars', function() + if isasan() then + pending('ASAN build is difficult to estimate memory usage') + end + if iswin() and eval("executable('wmic')") == 0 then + pending('missing "wmic" command') + elseif eval("executable('ps')") == 0 then + pending('missing "ps" command') + end + + local pid = eval('getpid()') + local before = monitor_memory_usage(pid) + local fname = source([[ + if !exists('s:defined_func') + func s:f() + let x = l: + endfunc + endif + let s:defined_func = 1 + for _ in range(10000) + call s:f() + endfor + ]]) + local after = monitor_memory_usage(pid) + for _ = 1, 3 do + feed_command('so '..fname) + end + local last = monitor_memory_usage(pid) + -- The usage may be a bit less than the last value, use 80%. + -- Allow for 20% tolerance at the upper limit. That's very permissive, but + -- otherwise the test fails sometimes. + local lower = before.last * 8 / 10 + local upper = (after.max + (after.last - before.last)) * 12 / 10 + check_result({before=before, after=after, last=last}, + pcall(ok, lower < last.last)) + check_result({before=before, after=after, last=last}, + pcall(ok, last.last < upper)) + end) +end) diff --git a/test/functional/lua/treesitter_spec.lua b/test/functional/lua/treesitter_spec.lua index f93185d1f6..ecee471386 100644 --- a/test/functional/lua/treesitter_spec.lua +++ b/test/functional/lua/treesitter_spec.lua @@ -240,17 +240,17 @@ static int nlua_schedule(lua_State *const lstate) ; TODO(bfredl): overlapping matches are unreliable, ; we need a proper priority mechanism ;(type_identifier) @type -((type_identifier) @Special (eq? @Special "LuaRef")) +((type_identifier) @Special (#eq? @Special "LuaRef")) (primitive_type) @type (sized_type_specifier) @type ; defaults to very magic syntax, for best compatibility -((identifier) @Identifier (match? @Identifier "^l(u)a_")) +((identifier) @Identifier (#match? @Identifier "^l(u)a_")) ; still support \M etc prefixes -((identifier) @Constant (match? @Constant "\M^\[A-Z_]\+$")) +((identifier) @Constant (#match? @Constant "\M^\[A-Z_]\+$")) -((binary_expression left: (identifier) @WarningMsg.left right: (identifier) @WarningMsg.right) (eq? @WarningMsg.left @WarningMsg.right)) +((binary_expression left: (identifier) @WarningMsg.left right: (identifier) @WarningMsg.right) (#eq? @WarningMsg.left @WarningMsg.right)) (comment) @comment ]] diff --git a/test/functional/lua/uri_spec.lua b/test/functional/lua/uri_spec.lua index a3b8e685e1..f782769935 100644 --- a/test/functional/lua/uri_spec.lua +++ b/test/functional/lua/uri_spec.lua @@ -112,6 +112,29 @@ describe('URI methods', function() eq('C:\\xy\\åäö\\ɧ\\汉语\\↥\\🤦\\🦄\\å\\بِيَّ.txt', exec_lua(test_case)) end) end) + + describe('decode non-file URI', function() + it('uri_to_fname returns non-file URI unchanged', function() + eq('jdt1.23+x-z://content/%5C/', exec_lua [[ + return vim.uri_to_fname('jdt1.23+x-z://content/%5C/') + ]]) + end) + + it('uri_to_fname returns non-file upper-case scheme URI unchanged', function() + eq('JDT://content/%5C/', exec_lua [[ + return vim.uri_to_fname('JDT://content/%5C/') + ]]) + end) + end) + + describe('decode URI without scheme', function() + it('fails because URI must have a scheme', function() + eq(false, exec_lua [[ + return pcall(vim.uri_to_fname, 'not_an_uri.txt') + ]]) + end) + end) + end) describe('uri to bufnr', function() diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index c68c05dffa..9b2697b3c2 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -243,6 +243,8 @@ describe('lua stdlib', function() { "here be dragons", " ", false, { "here", "be", "dragons"} }, { "axaby", "ab?", false, { '', 'x', 'y' } }, { "f v2v v3v w2w ", "([vw])2%1", false, { 'f ', ' v3v ', ' ' } }, + { "", "", false, {} }, + { "", "a", false, { '' } }, { "x*yz*oo*l", "*", true, { 'x', 'yz', 'oo', 'l' } }, } @@ -1048,13 +1050,13 @@ describe('lua stdlib', function() end) it('vim.defer_fn', function() - exec_lua [[ - vim.g.test = 0 - vim.defer_fn(function() vim.g.test = 1 end, 50) - ]] - eq(0, exec_lua[[return vim.g.test]]) - exec_lua [[vim.cmd("sleep 1000m")]] - eq(1, exec_lua[[return vim.g.test]]) + eq(false, exec_lua [[ + vim.g.test = false + vim.defer_fn(function() vim.g.test = true end, 150) + return vim.g.test + ]]) + exec_lua [[vim.wait(1000, function() return vim.g.test end)]] + eq(true, exec_lua[[return vim.g.test]]) end) it('vim.region', function() @@ -1066,4 +1068,168 @@ describe('lua stdlib', function() eq({5,15}, exec_lua[[ return vim.region(0,{1,5},{1,14},'v',true)[1] ]]) end) + describe('vim.wait', function() + before_each(function() + exec_lua[[ + -- high precision timer + get_time = function() + return vim.fn.reltimefloat(vim.fn.reltime()) + end + ]] + end) + + it('should run from lua', function() + exec_lua[[vim.wait(100, function() return true end)]] + end) + + it('should wait the expected time if false', function() + eq({time = true, wait_result = {false, -1}}, exec_lua[[ + start_time = get_time() + wait_succeed, wait_fail_val = vim.wait(200, function() return false end) + + return { + -- 150ms waiting or more results in true. Flaky tests are bad. + time = (start_time + 0.15) < get_time(), + wait_result = {wait_succeed, wait_fail_val} + } + ]]) + end) + + + it('should not block other events', function() + eq({time = true, wait_result = true}, exec_lua[[ + start_time = get_time() + + vim.g.timer_result = false + timer = vim.loop.new_timer() + timer:start(100, 0, vim.schedule_wrap(function() + vim.g.timer_result = true + end)) + + -- Would wait ten seconds if results blocked. + wait_result = vim.wait(10000, function() return vim.g.timer_result end) + + return { + time = (start_time + 5) > get_time(), + wait_result = wait_result, + } + ]]) + end) + + it('should work with vim.defer_fn', function() + eq({time = true, wait_result = true}, exec_lua[[ + start_time = get_time() + + vim.defer_fn(function() vim.g.timer_result = true end, 100) + wait_result = vim.wait(10000, function() return vim.g.timer_result end) + + return { + time = (start_time + 5) > get_time(), + wait_result = wait_result, + } + ]]) + end) + + it('should require functions to be passed', function() + local pcall_result = exec_lua [[ + return {pcall(function() vim.wait(1000, 13) end)} + ]] + + eq(pcall_result[1], false) + matches('condition must be a function', pcall_result[2]) + end) + + it('should not crash when callback errors', function() + local pcall_result = exec_lua [[ + return {pcall(function() vim.wait(1000, function() error("As Expected") end) end)} + ]] + + eq(pcall_result[1], false) + matches('As Expected', pcall_result[2]) + end) + + it('should call callbacks exactly once if they return true immediately', function() + eq(true, exec_lua [[ + vim.g.wait_count = 0 + vim.wait(1000, function() + vim.g.wait_count = vim.g.wait_count + 1 + return true + end, 20) + return vim.g.wait_count == 1 + ]]) + end) + + it('should call callbacks few times with large `interval`', function() + eq(true, exec_lua [[ + vim.g.wait_count = 0 + vim.wait(50, function() vim.g.wait_count = vim.g.wait_count + 1 end, 200) + return vim.g.wait_count < 5 + ]]) + end) + + it('should play nice with `not` when fails', function() + eq(true, exec_lua [[ + if not vim.wait(50, function() end) then + return true + end + + return false + ]]) + end) + + it('should play nice with `if` when success', function() + eq(true, exec_lua [[ + if vim.wait(50, function() return true end) then + return true + end + + return false + ]]) + end) + + it('should return immediately with false if timeout is 0', function() + eq({false, -1}, exec_lua [[ + return { + vim.wait(0, function() return false end) + } + ]]) + end) + + it('should work with tables with __call', function() + eq(true, exec_lua [[ + local t = setmetatable({}, {__call = function(...) return true end}) + return vim.wait(100, t, 10) + ]]) + end) + + it('should work with tables with __call that change', function() + eq(true, exec_lua [[ + local t = {count = 0} + setmetatable(t, { + __call = function() + t.count = t.count + 1 + return t.count > 3 + end + }) + + return vim.wait(1000, t, 10) + ]]) + end) + + it('should not work with negative intervals', function() + local pcall_result = exec_lua [[ + return pcall(function() vim.wait(1000, function() return false end, -1) end) + ]] + + eq(false, pcall_result) + end) + + it('should not work with weird intervals', function() + local pcall_result = exec_lua [[ + return pcall(function() vim.wait(1000, function() return false end, 'a string value') end) + ]] + + eq(false, pcall_result) + end) end) +end) diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua index f41a5323a8..1ab81a0ef8 100644 --- a/test/functional/plugin/lsp_spec.lua +++ b/test/functional/plugin/lsp_spec.lua @@ -6,6 +6,7 @@ local buf_lines = helpers.buf_lines local dedent = helpers.dedent local exec_lua = helpers.exec_lua local eq = helpers.eq +local pcall_err = helpers.pcall_err local pesc = helpers.pesc local insert = helpers.insert local retry = helpers.retry @@ -705,7 +706,6 @@ describe('LSP', function() end; } end) - end) describe("parsing tests", function() @@ -733,7 +733,23 @@ describe('LSP', function() end; } end) + end) + describe('lsp._cmd_parts test', function() + local function _cmd_parts(input) + return exec_lua([[ + lsp = require('vim.lsp') + return lsp._cmd_parts(...) + ]], input) + end + it('should valid cmd argument', function() + eq(true, pcall(_cmd_parts, {"nvim"})) + eq(true, pcall(_cmd_parts, {"nvim", "--head"})) + end) + it('should invalid cmd argument', function() + eq('Error executing lua: .../shared.lua: cmd: expected list, got nvim', pcall_err(_cmd_parts, "nvim")) + eq('Error executing lua: .../shared.lua: cmd argument: expected string, got number', pcall_err(_cmd_parts, {"nvim", 1})) + end) end) end) @@ -784,20 +800,44 @@ describe('LSP', function() make_edit(0, 0, 0, 0, {"123"}); make_edit(1, 0, 1, 1, {"2"}); make_edit(2, 0, 2, 2, {"3"}); + make_edit(3, 2, 3, 4, {""}); } 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'; + 'Foth line of text'; + 'å å ɧ 汉语 ↥ 🤦 🦄'; + }, buf_lines(1)) + end) + it('handles edits with the same start position, applying changes in the order in the array', function() + local edits = { + make_edit(0, 6, 0, 10, {""}); + make_edit(0, 6, 0, 6, {"REPLACE"}); + make_edit(1, 0, 1, 3, {""}); + make_edit(1, 0, 1, 0, {"123"}); + make_edit(2, 16, 2, 18, {""}); + make_edit(2, 16, 2, 16, {"XYZ"}); + make_edit(3, 7, 3, 11, {"this"}); + make_edit(3, 7, 3, 11, {"will"}); + make_edit(3, 7, 3, 11, {"not "}); + make_edit(3, 7, 3, 11, {"show"}); + make_edit(3, 7, 3, 11, {"(but this will)"}); + } + exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1) + eq({ + 'First REPLACE of text'; + '123ond line of text'; + 'Third line of teXYZ'; + 'Fourth (but this will) of text'; 'å å ɧ 汉语 ↥ 🤦 🦄'; }, buf_lines(1)) end) it('applies complex edits', function() local edits = { - make_edit(0, 0, 0, 0, {"", "12"}); make_edit(0, 0, 0, 0, {"3", "foo"}); + make_edit(0, 0, 0, 0, {"", "12"}); 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"}); @@ -957,7 +997,14 @@ describe('LSP', function() { label='foocar', insertText='foobar', textEdit={} }, -- resolves into textEdit.newText { label='foocar', insertText='foodar', textEdit={newText='foobar'} }, - { label='foocar', textEdit={newText='foobar'} } + { label='foocar', textEdit={newText='foobar'} }, + -- real-world snippet text + { label='foocar', insertText='foodar', textEdit={newText='foobar(${1:place holder}, ${2:more ...holder{\\}})'} }, + { label='foocar', insertText='foodar(${1:var1} typ1, ${2:var2} *typ2) {$0\\}', textEdit={} }, + -- nested snippet tokens + { label='foocar', insertText='foodar(${1:var1 ${2|typ2,typ3|} ${3:tail}}) {$0\\}', textEdit={} }, + -- plain text + { label='foocar', insertText='foodar(${1:var1})', insertTextFormat=1, textEdit={} }, } local completion_list_items = {items=completion_list} local expected = { @@ -967,6 +1014,10 @@ describe('LSP', function() { abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = 'Unknown', menu = '', word = 'foobar', user_data = { nvim = { lsp = { completion_item = { label='foocar', insertText='foobar', textEdit={} } } } } }, { abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = 'Unknown', menu = '', word = 'foobar', user_data = { nvim = { lsp = { completion_item = { label='foocar', insertText='foodar', textEdit={newText='foobar'} } } } } }, { abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = 'Unknown', menu = '', word = 'foobar', user_data = { nvim = { lsp = { completion_item = { label='foocar', textEdit={newText='foobar'} } } } } }, + { abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = 'Unknown', menu = '', word = 'foobar(place holder, more ...holder{})', user_data = { nvim = { lsp = { completion_item = { label='foocar', insertText='foodar', textEdit={newText='foobar(${1:place holder}, ${2:more ...holder{\\}})'} } } } } }, + { abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = 'Unknown', menu = '', word = 'foodar(var1 typ1, var2 *typ2) {}', user_data = { nvim = { lsp = { completion_item = { label='foocar', insertText='foodar(${1:var1} typ1, ${2:var2} *typ2) {$0\\}', textEdit={} } } } } }, + { abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = 'Unknown', menu = '', word = 'foodar(var1 typ2,typ3 tail) {}', user_data = { nvim = { lsp = { completion_item = { label='foocar', insertText='foodar(${1:var1 ${2|typ2,typ3|} ${3:tail}}) {$0\\}', textEdit={} } } } } }, + { abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = 'Unknown', menu = '', word = 'foodar(${1:var1})', user_data = { nvim = { lsp = { completion_item = { label='foocar', insertText='foodar(${1:var1})', insertTextFormat=1, textEdit={} } } } } }, } eq(expected, exec_lua([[return vim.lsp.util.text_document_completion_list_to_complete_items(...)]], completion_list, prefix)) @@ -1204,7 +1255,7 @@ describe('LSP', function() ]]) end) end) - describe('convert SymbolInformation[] to items', function() + it('convert SymbolInformation[] to items', function() local expected = { { col = 1, @@ -1268,11 +1319,11 @@ describe('LSP', function() end) describe('lsp.util._get_completion_item_kind_name', function() - describe('returns the name specified by protocol', function() + it('returns the name specified by protocol', function() eq("Text", exec_lua("return vim.lsp.util._get_completion_item_kind_name(1)")) eq("TypeParameter", exec_lua("return vim.lsp.util._get_completion_item_kind_name(25)")) end) - describe('returns the name not specified by protocol', function() + it('returns the name not specified by protocol', function() eq("Unknown", exec_lua("return vim.lsp.util._get_completion_item_kind_name(nil)")) eq("Unknown", exec_lua("return vim.lsp.util._get_completion_item_kind_name(vim.NIL)")) eq("Unknown", exec_lua("return vim.lsp.util._get_completion_item_kind_name(1000)")) @@ -1280,14 +1331,93 @@ describe('LSP', function() end) describe('lsp.util._get_symbol_kind_name', function() - describe('returns the name specified by protocol', function() + it('returns the name specified by protocol', function() eq("File", exec_lua("return vim.lsp.util._get_symbol_kind_name(1)")) eq("TypeParameter", exec_lua("return vim.lsp.util._get_symbol_kind_name(26)")) end) - describe('returns the name not specified by protocol', function() + it('returns the name not specified by protocol', function() eq("Unknown", exec_lua("return vim.lsp.util._get_symbol_kind_name(nil)")) eq("Unknown", exec_lua("return vim.lsp.util._get_symbol_kind_name(vim.NIL)")) eq("Unknown", exec_lua("return vim.lsp.util._get_symbol_kind_name(1000)")) end) end) + + describe('lsp.util.jump_to_location', function() + local target_bufnr + + before_each(function() + target_bufnr = exec_lua [[ + local bufnr = vim.uri_to_bufnr("file://fake/uri") + local lines = {"1st line of text", "å å ɧ 汉语 ↥ 🤦 🦄"} + vim.api.nvim_buf_set_lines(bufnr, 0, 1, false, lines) + return bufnr + ]] + end) + + local location = function(start_line, start_char, end_line, end_char) + return { + uri = "file://fake/uri", + range = { + start = { line = start_line, character = start_char }, + ["end"] = { line = end_line, character = end_char }, + }, + } + end + + local jump = function(msg) + eq(true, exec_lua('return vim.lsp.util.jump_to_location(...)', msg)) + eq(target_bufnr, exec_lua[[return vim.fn.bufnr('%')]]) + return { + line = exec_lua[[return vim.fn.line('.')]], + col = exec_lua[[return vim.fn.col('.')]], + } + end + + it('jumps to a Location', function() + local pos = jump(location(0, 9, 0, 9)) + eq(1, pos.line) + eq(10, pos.col) + end) + + it('jumps to a LocationLink', function() + local pos = jump({ + targetUri = "file://fake/uri", + targetSelectionRange = { + start = { line = 0, character = 4 }, + ["end"] = { line = 0, character = 4 }, + }, + targetRange = { + start = { line = 1, character = 5 }, + ["end"] = { line = 1, character = 5 }, + }, + }) + eq(1, pos.line) + eq(5, pos.col) + end) + + it('jumps to the correct multibyte column', function() + local pos = jump(location(1, 2, 1, 2)) + eq(2, pos.line) + eq(4, pos.col) + eq('å', exec_lua[[return vim.fn.expand('<cword>')]]) + end) + end) + + describe('lsp.util._make_floating_popup_size', function() + before_each(function() + exec_lua [[ contents = + {"text tαxt txtα tex", + "text tααt tααt text", + "text tαxt tαxt"} + ]] + end) + + it('calculates size correctly', function() + eq({19,3}, exec_lua[[ return {vim.lsp.util._make_floating_popup_size(contents)} ]]) + end) + + it('calculates size correctly with wrapping', function() + eq({15,5}, exec_lua[[ return {vim.lsp.util._make_floating_popup_size(contents,{width = 15, wrap_at = 14})} ]]) + end) + end) end) diff --git a/test/functional/provider/define_spec.lua b/test/functional/provider/define_spec.lua index 51a8831274..1d50ce0a56 100644 --- a/test/functional/provider/define_spec.lua +++ b/test/functional/provider/define_spec.lua @@ -89,6 +89,21 @@ local function command_specs_for(fn, sync, first_arg_factory, init) runx(sync, handler, on_setup) end) + it('with nargs/double-quote', function() + call(fn, args..', {"nargs": "*"}') + local function on_setup() + command('RpcCommand "arg1" "arg2" "arg3"') + end + + local function handler(method, arguments) + eq('test-handler', method) + eq({'"arg1"', '"arg2"', '"arg3"'}, arguments[1]) + return '' + end + + runx(sync, handler, on_setup) + end) + it('with range', function() call(fn,args..', {"range": ""}') local function on_setup() diff --git a/test/unit/eval/helpers.lua b/test/unit/eval/helpers.lua index bcd7c750c5..b600f01ab2 100644 --- a/test/unit/eval/helpers.lua +++ b/test/unit/eval/helpers.lua @@ -136,11 +136,15 @@ local function typvalt2lua_tab_init() return end typvalt2lua_tab = { + [tonumber(eval.VAR_BOOL)] = function(t) + return ({ + [tonumber(eval.kBoolVarFalse)] = false, + [tonumber(eval.kBoolVarTrue)] = true, + })[tonumber(t.vval.v_bool)] + end, [tonumber(eval.VAR_SPECIAL)] = function(t) return ({ - [tonumber(eval.kSpecialVarFalse)] = false, [tonumber(eval.kSpecialVarNull)] = nil_value, - [tonumber(eval.kSpecialVarTrue)] = true, })[tonumber(t.vval.v_special)] end, [tonumber(eval.VAR_NUMBER)] = function(t) @@ -349,8 +353,8 @@ lua2typvalt = function(l, processed) [null_list] = {'VAR_LIST', {v_list=ffi.cast('list_T*', nil)}}, [null_dict] = {'VAR_DICT', {v_dict=ffi.cast('dict_T*', nil)}}, [nil_value] = {'VAR_SPECIAL', {v_special=eval.kSpecialVarNull}}, - [true] = {'VAR_SPECIAL', {v_special=eval.kSpecialVarTrue}}, - [false] = {'VAR_SPECIAL', {v_special=eval.kSpecialVarFalse}}, + [true] = {'VAR_BOOL', {v_bool=eval.kBoolVarTrue}}, + [false] = {'VAR_BOOL', {v_bool=eval.kBoolVarFalse}}, } for k, v in pairs(special_vals) do diff --git a/test/unit/eval/typval_spec.lua b/test/unit/eval/typval_spec.lua index ea86ccbf1c..06465071c5 100644 --- a/test/unit/eval/typval_spec.lua +++ b/test/unit/eval/typval_spec.lua @@ -48,8 +48,7 @@ local lib = cimport('./src/nvim/eval/typval.h', './src/nvim/memory.h', local function vimconv_alloc() return ffi.gc( - ffi.cast('vimconv_T*', lib.xcalloc(1, ffi.sizeof('vimconv_T'))), - function(vc) + ffi.cast('vimconv_T*', lib.xcalloc(1, ffi.sizeof('vimconv_T'))), function(vc) lib.convert_setup(vc, nil, nil) lib.xfree(vc) end) @@ -2838,6 +2837,7 @@ describe('typval.c', function() {lib.VAR_FUNC, 'E729: using Funcref as a String'}, {lib.VAR_LIST, 'E730: using List as a String'}, {lib.VAR_DICT, 'E731: using Dictionary as a String'}, + {lib.VAR_BOOL, nil}, {lib.VAR_SPECIAL, nil}, {lib.VAR_UNKNOWN, 'E908: using an invalid value as a String'}, }) do @@ -2868,8 +2868,8 @@ describe('typval.c', function() {lib.VAR_LIST, {v_list=NULL}, 'E745: Using a List as a Number', 0}, {lib.VAR_DICT, {v_dict=NULL}, 'E728: Using a Dictionary as a Number', 0}, {lib.VAR_SPECIAL, {v_special=lib.kSpecialVarNull}, nil, 0}, - {lib.VAR_SPECIAL, {v_special=lib.kSpecialVarTrue}, nil, 1}, - {lib.VAR_SPECIAL, {v_special=lib.kSpecialVarFalse}, nil, 0}, + {lib.VAR_BOOL, {v_bool=lib.kBoolVarTrue}, nil, 1}, + {lib.VAR_BOOL, {v_bool=lib.kBoolVarFalse}, nil, 0}, {lib.VAR_UNKNOWN, nil, 'E685: Internal error: tv_get_number(UNKNOWN)', 0}, }) do -- Using to_cstr, cannot free with tv_clear @@ -2897,8 +2897,8 @@ describe('typval.c', function() {lib.VAR_LIST, {v_list=NULL}, 'E745: Using a List as a Number', 0}, {lib.VAR_DICT, {v_dict=NULL}, 'E728: Using a Dictionary as a Number', 0}, {lib.VAR_SPECIAL, {v_special=lib.kSpecialVarNull}, nil, 0}, - {lib.VAR_SPECIAL, {v_special=lib.kSpecialVarTrue}, nil, 1}, - {lib.VAR_SPECIAL, {v_special=lib.kSpecialVarFalse}, nil, 0}, + {lib.VAR_BOOL, {v_bool=lib.kBoolVarTrue}, nil, 1}, + {lib.VAR_BOOL, {v_bool=lib.kBoolVarFalse}, nil, 0}, {lib.VAR_UNKNOWN, nil, 'E685: Internal error: tv_get_number(UNKNOWN)', 0}, }) do -- Using to_cstr, cannot free with tv_clear @@ -2931,8 +2931,8 @@ describe('typval.c', function() {lib.VAR_LIST, {v_list=NULL}, 'E745: Using a List as a Number', -1}, {lib.VAR_DICT, {v_dict=NULL}, 'E728: Using a Dictionary as a Number', -1}, {lib.VAR_SPECIAL, {v_special=lib.kSpecialVarNull}, nil, 0}, - {lib.VAR_SPECIAL, {v_special=lib.kSpecialVarTrue}, nil, 1}, - {lib.VAR_SPECIAL, {v_special=lib.kSpecialVarFalse}, nil, 0}, + {lib.VAR_BOOL, {v_bool=lib.kBoolVarTrue}, nil, 1}, + {lib.VAR_BOOL, {v_bool=lib.kBoolVarFalse}, nil, 0}, {lib.VAR_UNKNOWN, nil, 'E685: Internal error: tv_get_number(UNKNOWN)', -1}, }) do lib.curwin.w_cursor.lnum = 46 @@ -2961,8 +2961,8 @@ describe('typval.c', function() {lib.VAR_LIST, {v_list=NULL}, 'E893: Using a List as a Float', 0}, {lib.VAR_DICT, {v_dict=NULL}, 'E894: Using a Dictionary as a Float', 0}, {lib.VAR_SPECIAL, {v_special=lib.kSpecialVarNull}, 'E907: Using a special value as a Float', 0}, - {lib.VAR_SPECIAL, {v_special=lib.kSpecialVarTrue}, 'E907: Using a special value as a Float', 0}, - {lib.VAR_SPECIAL, {v_special=lib.kSpecialVarFalse}, 'E907: Using a special value as a Float', 0}, + {lib.VAR_BOOL, {v_bool=lib.kBoolVarTrue}, 'E362: Using a boolean value as a Float', 0}, + {lib.VAR_BOOL, {v_bool=lib.kBoolVarFalse}, 'E362: Using a boolean value as a Float', 0}, {lib.VAR_UNKNOWN, nil, 'E685: Internal error: tv_get_float(UNKNOWN)', 0}, }) do -- Using to_cstr, cannot free with tv_clear @@ -2993,8 +2993,8 @@ describe('typval.c', function() {lib.VAR_LIST, {v_list=NULL}, 'E730: using List as a String', ''}, {lib.VAR_DICT, {v_dict=NULL}, 'E731: using Dictionary as a String', ''}, {lib.VAR_SPECIAL, {v_special=lib.kSpecialVarNull}, nil, 'null'}, - {lib.VAR_SPECIAL, {v_special=lib.kSpecialVarTrue}, nil, 'true'}, - {lib.VAR_SPECIAL, {v_special=lib.kSpecialVarFalse}, nil, 'false'}, + {lib.VAR_BOOL, {v_bool=lib.kBoolVarTrue}, nil, 'true'}, + {lib.VAR_BOOL, {v_bool=lib.kBoolVarFalse}, nil, 'false'}, {lib.VAR_UNKNOWN, nil, 'E908: using an invalid value as a String', ''}, }) do -- Using to_cstr in place of Neovim allocated string, cannot @@ -3005,7 +3005,8 @@ describe('typval.c', function() local ret = v[4] eq(ret, check_emsg(function() local res = lib.tv_get_string(tv) - if tv.v_type == lib.VAR_NUMBER or tv.v_type == lib.VAR_SPECIAL then + if tv.v_type == lib.VAR_NUMBER or tv.v_type == lib.VAR_SPECIAL + or tv.v_type == lib.VAR_BOOL then eq(buf, res) else neq(buf, res) @@ -3036,8 +3037,8 @@ describe('typval.c', function() {lib.VAR_LIST, {v_list=NULL}, 'E730: using List as a String', nil}, {lib.VAR_DICT, {v_dict=NULL}, 'E731: using Dictionary as a String', nil}, {lib.VAR_SPECIAL, {v_special=lib.kSpecialVarNull}, nil, 'null'}, - {lib.VAR_SPECIAL, {v_special=lib.kSpecialVarTrue}, nil, 'true'}, - {lib.VAR_SPECIAL, {v_special=lib.kSpecialVarFalse}, nil, 'false'}, + {lib.VAR_BOOL, {v_bool=lib.kBoolVarTrue}, nil, 'true'}, + {lib.VAR_BOOL, {v_bool=lib.kBoolVarFalse}, nil, 'false'}, {lib.VAR_UNKNOWN, nil, 'E908: using an invalid value as a String', nil}, }) do -- Using to_cstr, cannot free with tv_clear @@ -3047,7 +3048,8 @@ describe('typval.c', function() local ret = v[4] eq(ret, check_emsg(function() local res = lib.tv_get_string_chk(tv) - if tv.v_type == lib.VAR_NUMBER or tv.v_type == lib.VAR_SPECIAL then + if tv.v_type == lib.VAR_NUMBER or tv.v_type == lib.VAR_SPECIAL + or tv.v_type == lib.VAR_BOOL then eq(buf, res) else neq(buf, res) @@ -3077,8 +3079,8 @@ describe('typval.c', function() {lib.VAR_LIST, {v_list=NULL}, 'E730: using List as a String', ''}, {lib.VAR_DICT, {v_dict=NULL}, 'E731: using Dictionary as a String', ''}, {lib.VAR_SPECIAL, {v_special=lib.kSpecialVarNull}, nil, 'null'}, - {lib.VAR_SPECIAL, {v_special=lib.kSpecialVarTrue}, nil, 'true'}, - {lib.VAR_SPECIAL, {v_special=lib.kSpecialVarFalse}, nil, 'false'}, + {lib.VAR_BOOL, {v_bool=lib.kBoolVarTrue}, nil, 'true'}, + {lib.VAR_BOOL, {v_bool=lib.kBoolVarFalse}, nil, 'false'}, {lib.VAR_UNKNOWN, nil, 'E908: using an invalid value as a String', ''}, }) do -- Using to_cstr, cannot free with tv_clear @@ -3089,7 +3091,8 @@ describe('typval.c', function() eq(ret, check_emsg(function() local buf = ffi.new('char[?]', lib.NUMBUFLEN, {0}) local res = lib.tv_get_string_buf(tv, buf) - if tv.v_type == lib.VAR_NUMBER or tv.v_type == lib.VAR_SPECIAL then + if tv.v_type == lib.VAR_NUMBER or tv.v_type == lib.VAR_SPECIAL + or tv.v_type == lib.VAR_BOOL then eq(buf, res) else neq(buf, res) @@ -3119,8 +3122,8 @@ describe('typval.c', function() {lib.VAR_LIST, {v_list=NULL}, 'E730: using List as a String', nil}, {lib.VAR_DICT, {v_dict=NULL}, 'E731: using Dictionary as a String', nil}, {lib.VAR_SPECIAL, {v_special=lib.kSpecialVarNull}, nil, 'null'}, - {lib.VAR_SPECIAL, {v_special=lib.kSpecialVarTrue}, nil, 'true'}, - {lib.VAR_SPECIAL, {v_special=lib.kSpecialVarFalse}, nil, 'false'}, + {lib.VAR_BOOL, {v_bool=lib.kBoolVarTrue}, nil, 'true'}, + {lib.VAR_BOOL, {v_bool=lib.kBoolVarFalse}, nil, 'false'}, {lib.VAR_UNKNOWN, nil, 'E908: using an invalid value as a String', nil}, }) do -- Using to_cstr, cannot free with tv_clear @@ -3131,7 +3134,8 @@ describe('typval.c', function() eq(ret, check_emsg(function() local buf = ffi.new('char[?]', lib.NUMBUFLEN, {0}) local res = lib.tv_get_string_buf_chk(tv, buf) - if tv.v_type == lib.VAR_NUMBER or tv.v_type == lib.VAR_SPECIAL then + if tv.v_type == lib.VAR_NUMBER or tv.v_type == lib.VAR_SPECIAL + or tv.v_type == lib.VAR_BOOL then eq(buf, res) else neq(buf, res) |