diff options
Diffstat (limited to 'test/functional/lua')
-rw-r--r-- | test/functional/lua/api_spec.lua | 30 | ||||
-rw-r--r-- | test/functional/lua/commands_spec.lua | 99 | ||||
-rw-r--r-- | test/functional/lua/luaeval_spec.lua | 96 | ||||
-rw-r--r-- | test/functional/lua/overrides_spec.lua | 34 | ||||
-rw-r--r-- | test/functional/lua/uri_spec.lua | 107 | ||||
-rw-r--r-- | test/functional/lua/utility_functions_spec.lua | 330 | ||||
-rw-r--r-- | test/functional/lua/vim_spec.lua | 663 |
7 files changed, 941 insertions, 418 deletions
diff --git a/test/functional/lua/api_spec.lua b/test/functional/lua/api_spec.lua index b1dc5c07fd..23167d3ed9 100644 --- a/test/functional/lua/api_spec.lua +++ b/test/functional/lua/api_spec.lua @@ -155,41 +155,41 @@ describe('luaeval(vim.api.…)', function() it('errors out correctly when working with API', function() -- Conversion errors - eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [string "<VimL compiled string>"]:1: Cannot convert given lua type', + eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Cannot convert given lua type', exc_exec([[call luaeval("vim.api.nvim__id(vim.api.nvim__id)")]])) - eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [string "<VimL compiled string>"]:1: Cannot convert given lua table', + eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Cannot convert given lua table', exc_exec([[call luaeval("vim.api.nvim__id({1, foo=42})")]])) - eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [string "<VimL compiled string>"]:1: Cannot convert given lua type', + eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Cannot convert given lua type', exc_exec([[call luaeval("vim.api.nvim__id({42, vim.api.nvim__id})")]])) -- Errors in number of arguments - eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [string "<VimL compiled string>"]:1: Expected 1 argument', + eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Expected 1 argument', exc_exec([[call luaeval("vim.api.nvim__id()")]])) - eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [string "<VimL compiled string>"]:1: Expected 1 argument', + eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Expected 1 argument', exc_exec([[call luaeval("vim.api.nvim__id(1, 2)")]])) - eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [string "<VimL compiled string>"]:1: Expected 2 arguments', + eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Expected 2 arguments', exc_exec([[call luaeval("vim.api.nvim_set_var(1, 2, 3)")]])) -- Error in argument types - eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [string "<VimL compiled string>"]:1: Expected lua string', + eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Expected lua string', exc_exec([[call luaeval("vim.api.nvim_set_var(1, 2)")]])) - eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [string "<VimL compiled string>"]:1: Expected lua number', + eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Expected lua number', exc_exec([[call luaeval("vim.api.nvim_buf_get_lines(0, 'test', 1, false)")]])) - eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [string "<VimL compiled string>"]:1: Number is not integral', + eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Number is not integral', exc_exec([[call luaeval("vim.api.nvim_buf_get_lines(0, 1.5, 1, false)")]])) - eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [string "<VimL compiled string>"]:1: Expected lua table', + eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Expected lua table', exc_exec([[call luaeval("vim.api.nvim__id_float('test')")]])) - eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [string "<VimL compiled string>"]:1: Unexpected type', + eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Unexpected type', exc_exec([[call luaeval("vim.api.nvim__id_float({[vim.type_idx]=vim.types.dictionary})")]])) - eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [string "<VimL compiled string>"]:1: Expected lua table', + eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Expected lua table', exc_exec([[call luaeval("vim.api.nvim__id_array(1)")]])) - eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [string "<VimL compiled string>"]:1: Unexpected type', + eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Unexpected type', exc_exec([[call luaeval("vim.api.nvim__id_array({[vim.type_idx]=vim.types.dictionary})")]])) - eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [string "<VimL compiled string>"]:1: Expected lua table', + eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Expected lua table', exc_exec([[call luaeval("vim.api.nvim__id_dictionary(1)")]])) - eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [string "<VimL compiled string>"]:1: Unexpected type', + eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Unexpected type', exc_exec([[call luaeval("vim.api.nvim__id_dictionary({[vim.type_idx]=vim.types.array})")]])) -- TODO: check for errors with Tabpage argument -- TODO: check for errors with Window argument diff --git a/test/functional/lua/commands_spec.lua b/test/functional/lua/commands_spec.lua index 26dcbe0534..96eaa7991b 100644 --- a/test/functional/lua/commands_spec.lua +++ b/test/functional/lua/commands_spec.lua @@ -13,6 +13,7 @@ local source = helpers.source local dedent = helpers.dedent local command = helpers.command local exc_exec = helpers.exc_exec +local pcall_err = helpers.pcall_err local write_file = helpers.write_file local redir_exec = helpers.redir_exec local curbufmeths = helpers.curbufmeths @@ -42,16 +43,16 @@ describe(':lua command', function() eq({'', 'ETTS', 'TTSE', 'STTE'}, curbufmeths.get_lines(0, 100, false)) end) it('throws catchable errors', function() - eq([[Vim(lua):E5104: Error while creating lua chunk: [string "<VimL compiled string>"]:1: unexpected symbol near ')']], - exc_exec('lua ()')) - eq([[Vim(lua):E5105: Error while calling lua chunk: [string "<VimL compiled string>"]:1: TEST]], + eq([[Vim(lua):E5107: Error loading lua [string ":lua"]:1: unexpected symbol near ')']], + pcall_err(command, 'lua ()')) + eq([[Vim(lua):E5108: Error executing lua [string ":lua"]:1: TEST]], exc_exec('lua error("TEST")')) - eq([[Vim(lua):E5105: Error while calling lua chunk: [string "<VimL compiled string>"]:1: Invalid buffer id]], + eq([[Vim(lua):E5108: Error executing lua [string ":lua"]:1: Invalid buffer id]], exc_exec('lua vim.api.nvim_buf_set_lines(-10, 1, 1, false, {"TEST"})')) eq({''}, curbufmeths.get_lines(0, 100, false)) end) it('works with NULL errors', function() - eq([=[Vim(lua):E5105: Error while calling lua chunk: [NULL]]=], + eq([=[Vim(lua):E5108: Error executing lua [NULL]]=], exc_exec('lua error(nil)')) end) it('accepts embedded NLs without heredoc', function() @@ -74,7 +75,7 @@ describe(':lua command', function() it('works with long strings', function() local s = ('x'):rep(100500) - eq('\nE5104: Error while creating lua chunk: [string "<VimL compiled string>"]:1: unfinished string near \'<eof>\'', redir_exec(('lua vim.api.nvim_buf_set_lines(1, 1, 2, false, {"%s})'):format(s))) + eq('\nE5107: Error loading lua [string ":lua"]:1: unfinished string near \'<eof>\'', redir_exec(('lua vim.api.nvim_buf_set_lines(1, 1, 2, false, {"%s})'):format(s))) eq({''}, curbufmeths.get_lines(0, -1, false)) eq('', redir_exec(('lua vim.api.nvim_buf_set_lines(1, 1, 2, false, {"%s"})'):format(s))) @@ -82,7 +83,7 @@ describe(':lua command', function() end) it('can show multiline error messages', function() - local screen = Screen.new(50,10) + local screen = Screen.new(40,10) screen:attach() screen:set_default_attr_ids({ [1] = {bold = true, foreground = Screen.colors.Blue1}, @@ -92,51 +93,51 @@ describe(':lua command', function() }) feed(':lua error("fail\\nmuch error\\nsuch details")<cr>') - screen:expect([[ - | - {1:~ }| - {1:~ }| - {1:~ }| - {2: }| - {3:E5105: Error while calling lua chunk: [string "<Vi}| - {3:mL compiled string>"]:1: fail} | - {3:much error} | - {3:such details} | - {4:Press ENTER or type command to continue}^ | - ]]) + screen:expect{grid=[[ + | + {1:~ }| + {1:~ }| + {1:~ }| + {2: }| + {3:E5108: Error executing lua [string ":lua}| + {3:"]:1: fail} | + {3:much error} | + {3:such details} | + {4:Press ENTER or type command to continue}^ | + ]]} feed('<cr>') - screen:expect([[ - ^ | - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - | - ]]) - eq('E5105: Error while calling lua chunk: [string "<VimL compiled string>"]:1: fail\nmuch error\nsuch details', eval('v:errmsg')) + screen:expect{grid=[[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]} + eq('E5108: Error executing lua [string ":lua"]:1: fail\nmuch error\nsuch details', eval('v:errmsg')) local status, err = pcall(command,'lua error("some error\\nin a\\nAPI command")') - local expected = 'Vim(lua):E5105: Error while calling lua chunk: [string "<VimL compiled string>"]:1: some error\nin a\nAPI command' + local expected = 'Vim(lua):E5108: Error executing lua [string ":lua"]:1: some error\nin a\nAPI command' eq(false, status) eq(expected, string.sub(err, -string.len(expected))) feed(':messages<cr>') - screen:expect([[ - | - {1:~ }| - {1:~ }| - {1:~ }| - {2: }| - {3:E5105: Error while calling lua chunk: [string "<Vi}| - {3:mL compiled string>"]:1: fail} | - {3:much error} | - {3:such details} | - {4:Press ENTER or type command to continue}^ | - ]]) + screen:expect{grid=[[ + | + {1:~ }| + {1:~ }| + {1:~ }| + {2: }| + {3:E5108: Error executing lua [string ":lua}| + {3:"]:1: fail} | + {3:much error} | + {3:such details} | + {4:Press ENTER or type command to continue}^ | + ]]} end) end) @@ -167,13 +168,13 @@ describe(':luado command', function() eq({''}, curbufmeths.get_lines(0, -1, false)) end) it('fails on errors', function() - eq([[Vim(luado):E5109: Error while creating lua chunk: [string "<VimL compiled string>"]:1: unexpected symbol near ')']], + eq([[Vim(luado):E5109: Error loading lua: [string ":luado"]:1: unexpected symbol near ')']], exc_exec('luado ()')) - eq([[Vim(luado):E5111: Error while calling lua function: [string "<VimL compiled string>"]:1: attempt to perform arithmetic on global 'liness' (a nil value)]], + eq([[Vim(luado):E5111: Error calling lua: [string ":luado"]:1: attempt to perform arithmetic on global 'liness' (a nil value)]], exc_exec('luado return liness + 1')) end) it('works with NULL errors', function() - eq([=[Vim(luado):E5111: Error while calling lua function: [NULL]]=], + eq([=[Vim(luado):E5111: Error calling lua: [NULL]]=], exc_exec('luado error(nil)')) end) it('fails in sandbox when needed', function() @@ -185,7 +186,7 @@ describe(':luado command', function() it('works with long strings', function() local s = ('x'):rep(100500) - eq('\nE5109: Error while creating lua chunk: [string "<VimL compiled string>"]:1: unfinished string near \'<eof>\'', redir_exec(('luado return "%s'):format(s))) + eq('\nE5109: Error loading lua: [string ":luado"]:1: unfinished string near \'<eof>\'', redir_exec(('luado return "%s'):format(s))) eq({''}, curbufmeths.get_lines(0, -1, false)) eq('', redir_exec(('luado return "%s"'):format(s))) diff --git a/test/functional/lua/luaeval_spec.lua b/test/functional/lua/luaeval_spec.lua index 760105df6b..61c8e5c02e 100644 --- a/test/functional/lua/luaeval_spec.lua +++ b/test/functional/lua/luaeval_spec.lua @@ -1,13 +1,17 @@ -- Test suite for testing luaeval() function local helpers = require('test.functional.helpers')(after_each) +local Screen = require('test.functional.ui.screen') local redir_exec = helpers.redir_exec +local pcall_err = helpers.pcall_err local exc_exec = helpers.exc_exec +local exec_lua = helpers.exec_lua local command = helpers.command local meths = helpers.meths local funcs = helpers.funcs local clear = helpers.clear local eval = helpers.eval +local feed = helpers.feed local NIL = helpers.NIL local eq = helpers.eq @@ -186,9 +190,9 @@ describe('luaeval()', function() exc_exec('call luaeval("{1, foo=2}")')) eq("Vim(call):E5101: Cannot convert given lua type", exc_exec('call luaeval("vim.api.nvim_buf_get_lines")')) - startswith("Vim(call):E5107: Error while creating lua chunk for luaeval(): ", + startswith("Vim(call):E5107: Error loading lua [string \"luaeval()\"]:", exc_exec('call luaeval("1, 2, 3")')) - startswith("Vim(call):E5108: Error while calling lua chunk for luaeval(): ", + startswith("Vim(call):E5108: Error executing lua [string \"luaeval()\"]:", exc_exec('call luaeval("(nil)()")')) eq("Vim(call):E5101: Cannot convert given lua type", exc_exec('call luaeval("{42, vim.api}")')) @@ -237,19 +241,99 @@ describe('luaeval()', function() it('errors out correctly when doing incorrect things in lua', function() -- Conversion errors - eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [string "<VimL compiled string>"]:1: attempt to call field \'xxx_nonexistent_key_xxx\' (a nil value)', + eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: attempt to call field \'xxx_nonexistent_key_xxx\' (a nil value)', exc_exec([[call luaeval("vim.xxx_nonexistent_key_xxx()")]])) - eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [string "<VimL compiled string>"]:1: ERROR', + eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: ERROR', exc_exec([[call luaeval("error('ERROR')")]])) - eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [NULL]', + eq('Vim(call):E5108: Error executing lua [NULL]', exc_exec([[call luaeval("error(nil)")]])) end) it('does not leak memory when called with too long line', function() local s = ('x'):rep(65536) - eq('Vim(call):E5107: Error while creating lua chunk for luaeval(): [string "<VimL compiled string>"]:1: unexpected symbol near \')\'', + eq('Vim(call):E5107: Error loading lua [string "luaeval()"]:1: unexpected symbol near \')\'', exc_exec([[call luaeval("(']] .. s ..[[' + )")]])) eq(s, funcs.luaeval('"' .. s .. '"')) end) end) + +describe('v:lua', function() + before_each(function() + exec_lua([[ + function _G.foo(a,b,n) + _G.val = n + return a+b + end + mymod = {} + function mymod.noisy(name) + vim.api.nvim_set_current_line("hey "..name) + end + function mymod.crashy() + nonexistent() + end + function mymod.omni(findstart, base) + if findstart == 1 then + return 5 + else + if base == 'st' then + return {'stuff', 'steam', 'strange things'} + end + end + end + vim.api.nvim_buf_set_option(0, 'omnifunc', 'v:lua.mymod.omni') + ]]) + end) + + it('works in expressions', function() + eq(7, eval('v:lua.foo(3,4,v:null)')) + eq(true, exec_lua([[return _G.val == vim.NIL]])) + eq(NIL, eval('v:lua.mymod.noisy("eval")')) + eq("hey eval", meths.get_current_line()) + + eq("Vim:E5108: Error executing lua [string \"<nvim>\"]:10: attempt to call global 'nonexistent' (a nil value)", + pcall_err(eval, 'v:lua.mymod.crashy()')) + end) + + it('works in :call', function() + command(":call v:lua.mymod.noisy('command')") + eq("hey command", meths.get_current_line()) + eq("Vim(call):E5108: Error executing lua [string \"<nvim>\"]:10: attempt to call global 'nonexistent' (a nil value)", + pcall_err(command, 'call v:lua.mymod.crashy()')) + end) + + it('works in func options', function() + local screen = Screen.new(60, 8) + screen:set_default_attr_ids({ + [1] = {bold = true, foreground = Screen.colors.Blue1}, + [2] = {background = Screen.colors.WebGray}, + [3] = {background = Screen.colors.LightMagenta}, + [4] = {bold = true}, + [5] = {bold = true, foreground = Screen.colors.SeaGreen4}, + }) + screen:attach() + feed('isome st<c-x><c-o>') + screen:expect{grid=[[ + some stuff^ | + {1:~ }{2: stuff }{1: }| + {1:~ }{3: steam }{1: }| + {1:~ }{3: strange things }{1: }| + {1:~ }| + {1:~ }| + {1:~ }| + {4:-- Omni completion (^O^N^P) }{5:match 1 of 3} | + ]]} + end) + + it('throw errors for invalid use', function() + eq('Vim(let):E15: Invalid expression: v:lua.func', pcall_err(command, "let g:Func = v:lua.func")) + eq('Vim(let):E15: Invalid expression: v:lua', pcall_err(command, "let g:Func = v:lua")) + eq("Vim(let):E15: Invalid expression: v:['lua']", pcall_err(command, "let g:Func = v:['lua']")) + + eq("Vim:E15: Invalid expression: v:['lua'].foo()", pcall_err(eval, "v:['lua'].foo()")) + eq("Vim(call):E461: Illegal variable name: v:['lua']", pcall_err(command, "call v:['lua'].baar()")) + + eq("Vim(let):E46: Cannot change read-only variable \"v:['lua']\"", pcall_err(command, "let v:['lua'] = 'xx'")) + eq("Vim(let):E46: Cannot change read-only variable \"v:lua\"", pcall_err(command, "let v:lua = 'xx'")) + end) +end) diff --git a/test/functional/lua/overrides_spec.lua b/test/functional/lua/overrides_spec.lua index f6439001ac..1bccc02847 100644 --- a/test/functional/lua/overrides_spec.lua +++ b/test/functional/lua/overrides_spec.lua @@ -54,11 +54,12 @@ describe('print', function() v_tblout = setmetatable({}, meta_tblout) ]]) eq('', redir_exec('luafile ' .. fname)) - eq('\nE5105: Error while calling lua chunk: E5114: Error while converting print argument #2: [NULL]', + -- TODO(bfredl): these look weird, print() should not use "E5114:" style errors.. + eq('\nE5108: Error executing lua E5114: Error while converting print argument #2: [NULL]', redir_exec('lua print("foo", v_nilerr, "bar")')) - eq('\nE5105: Error while calling lua chunk: E5114: Error while converting print argument #2: Xtest-functional-lua-overrides-luafile:2: abc', + eq('\nE5108: Error executing lua E5114: Error while converting print argument #2: Xtest-functional-lua-overrides-luafile:2: abc', redir_exec('lua print("foo", v_abcerr, "bar")')) - eq('\nE5105: Error while calling lua chunk: E5114: Error while converting print argument #2: <Unknown error: lua_tolstring returned NULL for tostring result>', + eq('\nE5108: Error executing lua E5114: Error while converting print argument #2: <Unknown error: lua_tolstring returned NULL for tostring result>', redir_exec('lua print("foo", v_tblout, "bar")')) end) it('prints strings with NULs and NLs correctly', function() @@ -156,7 +157,8 @@ describe('debug.debug', function() lua_debug> ^ | ]]) feed('<C-c>') - screen:expect([[ + screen:expect{grid=[[ + {0:~ }| {0:~ }| {0:~ }| {0:~ }| @@ -167,11 +169,10 @@ describe('debug.debug', function() lua_debug> print("TEST") | TEST | | - {E:E5105: Error while calling lua chunk: [string "<VimL }| - {E:compiled string>"]:5: attempt to perform arithmetic o}| - {E:n local 'a' (a nil value)} | + {E:E5108: Error executing lua [string ":lua"]:5: attempt}| + {E: to perform arithmetic on local 'a' (a nil value)} | Interrupt: {cr:Press ENTER or type command to continue}^ | - ]]) + ]]} feed('<C-l>:lua Test()\n') screen:expect([[ {0:~ }| @@ -190,7 +191,8 @@ describe('debug.debug', function() lua_debug> ^ | ]]) feed('\n') - screen:expect([[ + screen:expect{grid=[[ + {0:~ }| {0:~ }| {0:~ }| {0:~ }| @@ -201,11 +203,10 @@ describe('debug.debug', function() {0:~ }| nil | lua_debug> | - {E:E5105: Error while calling lua chunk: [string "<VimL }| - {E:compiled string>"]:5: attempt to perform arithmetic o}| - {E:n local 'a' (a nil value)} | + {E:E5108: Error executing lua [string ":lua"]:5: attempt}| + {E: to perform arithmetic on local 'a' (a nil value)} | {cr:Press ENTER or type command to continue}^ | - ]]) + ]]} end) it("can be safely exited with 'cont'", function() @@ -298,14 +299,11 @@ describe('package.path/package.cpath', function() end return new_paths end - local function execute_lua(cmd, ...) - return meths.execute_lua(cmd, {...}) - end local function eval_lua(expr, ...) - return meths.execute_lua('return ' .. expr, {...}) + return meths.exec_lua('return '..expr, {...}) end local function set_path(which, value) - return execute_lua('package[select(1, ...)] = select(2, ...)', which, value) + return exec_lua('package[select(1, ...)] = select(2, ...)', which, value) end it('contains directories from &runtimepath on first invocation', function() diff --git a/test/functional/lua/uri_spec.lua b/test/functional/lua/uri_spec.lua new file mode 100644 index 0000000000..19b1eb1f61 --- /dev/null +++ b/test/functional/lua/uri_spec.lua @@ -0,0 +1,107 @@ +local helpers = require('test.functional.helpers')(after_each) +local clear = helpers.clear +local exec_lua = helpers.exec_lua +local eq = helpers.eq + +describe('URI methods', function() + before_each(function() + clear() + end) + + describe('file path to uri', function() + describe('encode Unix file path', function() + it('file path includes only ascii charactors', function() + exec_lua("filepath = '/Foo/Bar/Baz.txt'") + + eq('file:///Foo/Bar/Baz.txt', exec_lua("return vim.uri_from_fname(filepath)")) + end) + + it('file path including white space', function() + exec_lua("filepath = '/Foo /Bar/Baz.txt'") + + eq('file:///Foo%20/Bar/Baz.txt', exec_lua("return vim.uri_from_fname(filepath)")) + end) + + it('file path including Unicode charactors', function() + exec_lua("filepath = '/xy/åäö/ɧ/汉语/↥/🤦/🦄/å/بِيَّ.txt'") + + -- The URI encoding should be case-insensitive + eq('file:///xy/%c3%a5%c3%a4%c3%b6/%c9%a7/%e6%b1%89%e8%af%ad/%e2%86%a5/%f0%9f%a4%a6/%f0%9f%a6%84/a%cc%8a/%d8%a8%d9%90%d9%8a%d9%8e%d9%91.txt', exec_lua("return vim.uri_from_fname(filepath)")) + end) + end) + + describe('encode Windows filepath', function() + it('file path includes only ascii charactors', function() + exec_lua([[filepath = 'C:\\Foo\\Bar\\Baz.txt']]) + + eq('file:///C:/Foo/Bar/Baz.txt', exec_lua("return vim.uri_from_fname(filepath)")) + end) + + it('file path including white space', function() + exec_lua([[filepath = 'C:\\Foo \\Bar\\Baz.txt']]) + + eq('file:///C:/Foo%20/Bar/Baz.txt', exec_lua("return vim.uri_from_fname(filepath)")) + end) + + it('file path including Unicode charactors', function() + exec_lua([[filepath = 'C:\\xy\\åäö\\ɧ\\汉语\\↥\\🤦\\🦄\\å\\بِيَّ.txt']]) + + eq('file:///C:/xy/%c3%a5%c3%a4%c3%b6/%c9%a7/%e6%b1%89%e8%af%ad/%e2%86%a5/%f0%9f%a4%a6/%f0%9f%a6%84/a%cc%8a/%d8%a8%d9%90%d9%8a%d9%8e%d9%91.txt', exec_lua("return vim.uri_from_fname(filepath)")) + end) + end) + end) + + describe('uri to filepath', function() + describe('decode Unix file path', function() + it('file path includes only ascii charactors', function() + exec_lua("uri = 'file:///Foo/Bar/Baz.txt'") + + eq('/Foo/Bar/Baz.txt', exec_lua("return vim.uri_to_fname(uri)")) + end) + + it('file path including white space', function() + exec_lua("uri = 'file:///Foo%20/Bar/Baz.txt'") + + eq('/Foo /Bar/Baz.txt', exec_lua("return vim.uri_to_fname(uri)")) + end) + + it('file path including Unicode charactors', function() + local test_case = [[ + local uri = 'file:///xy/%C3%A5%C3%A4%C3%B6/%C9%A7/%E6%B1%89%E8%AF%AD/%E2%86%A5/%F0%9F%A4%A6/%F0%9F%A6%84/a%CC%8A/%D8%A8%D9%90%D9%8A%D9%8E%D9%91.txt' + return vim.uri_to_fname(uri) + ]] + + eq('/xy/åäö/ɧ/汉语/↥/🤦/🦄/å/بِيَّ.txt', exec_lua(test_case)) + end) + end) + + describe('decode Windows filepath', function() + it('file path includes only ascii charactors', function() + local test_case = [[ + local uri = 'file:///C:/Foo/Bar/Baz.txt' + return vim.uri_to_fname(uri) + ]] + + eq('C:\\Foo\\Bar\\Baz.txt', exec_lua(test_case)) + end) + + it('file path including white space', function() + local test_case = [[ + local uri = 'file:///C:/Foo%20/Bar/Baz.txt' + return vim.uri_to_fname(uri) + ]] + + eq('C:\\Foo \\Bar\\Baz.txt', exec_lua(test_case)) + end) + + it('file path including Unicode charactors', function() + local test_case = [[ + local uri = 'file:///C:/xy/%C3%A5%C3%A4%C3%B6/%C9%A7/%E6%B1%89%E8%AF%AD/%E2%86%A5/%F0%9F%A4%A6/%F0%9F%A6%84/a%CC%8A/%D8%A8%D9%90%D9%8A%D9%8E%D9%91.txt' + return vim.uri_to_fname(uri) + ]] + + eq('C:\\xy\\åäö\\ɧ\\汉语\\↥\\🤦\\🦄\\å\\بِيَّ.txt', exec_lua(test_case)) + end) + end) + end) +end) diff --git a/test/functional/lua/utility_functions_spec.lua b/test/functional/lua/utility_functions_spec.lua deleted file mode 100644 index 6aeea5fc4f..0000000000 --- a/test/functional/lua/utility_functions_spec.lua +++ /dev/null @@ -1,330 +0,0 @@ --- Test suite for testing interactions with API bindings -local helpers = require('test.functional.helpers')(after_each) -local Screen = require('test.functional.ui.screen') - -local funcs = helpers.funcs -local clear = helpers.clear -local eq = helpers.eq -local eval = helpers.eval -local feed = helpers.feed -local pcall_err = helpers.pcall_err -local exec_lua = helpers.exec_lua -local matches = helpers.matches -local source = helpers.source - -before_each(clear) - -describe('lua stdlib', function() - -- İ: `tolower("İ")` is `i` which has length 1 while `İ` itself has - -- length 2 (in bytes). - -- Ⱥ: `tolower("Ⱥ")` is `ⱥ` which has length 2 while `Ⱥ` itself has - -- length 3 (in bytes). - -- - -- Note: 'i' !=? 'İ' and 'ⱥ' !=? 'Ⱥ' on some systems. - -- Note: Built-in Nvim comparison (on systems lacking `strcasecmp`) works - -- only on ASCII characters. - it('vim.stricmp', function() - eq(0, funcs.luaeval('vim.stricmp("a", "A")')) - eq(0, funcs.luaeval('vim.stricmp("A", "a")')) - eq(0, funcs.luaeval('vim.stricmp("a", "a")')) - eq(0, funcs.luaeval('vim.stricmp("A", "A")')) - - eq(0, funcs.luaeval('vim.stricmp("", "")')) - eq(0, funcs.luaeval('vim.stricmp("\\0", "\\0")')) - eq(0, funcs.luaeval('vim.stricmp("\\0\\0", "\\0\\0")')) - eq(0, funcs.luaeval('vim.stricmp("\\0\\0\\0", "\\0\\0\\0")')) - eq(0, funcs.luaeval('vim.stricmp("\\0\\0\\0A", "\\0\\0\\0a")')) - eq(0, funcs.luaeval('vim.stricmp("\\0\\0\\0a", "\\0\\0\\0A")')) - eq(0, funcs.luaeval('vim.stricmp("\\0\\0\\0a", "\\0\\0\\0a")')) - - eq(0, funcs.luaeval('vim.stricmp("a\\0", "A\\0")')) - eq(0, funcs.luaeval('vim.stricmp("A\\0", "a\\0")')) - eq(0, funcs.luaeval('vim.stricmp("a\\0", "a\\0")')) - eq(0, funcs.luaeval('vim.stricmp("A\\0", "A\\0")')) - - eq(0, funcs.luaeval('vim.stricmp("\\0a", "\\0A")')) - eq(0, funcs.luaeval('vim.stricmp("\\0A", "\\0a")')) - eq(0, funcs.luaeval('vim.stricmp("\\0a", "\\0a")')) - eq(0, funcs.luaeval('vim.stricmp("\\0A", "\\0A")')) - - eq(0, funcs.luaeval('vim.stricmp("\\0a\\0", "\\0A\\0")')) - eq(0, funcs.luaeval('vim.stricmp("\\0A\\0", "\\0a\\0")')) - eq(0, funcs.luaeval('vim.stricmp("\\0a\\0", "\\0a\\0")')) - eq(0, funcs.luaeval('vim.stricmp("\\0A\\0", "\\0A\\0")')) - - eq(-1, funcs.luaeval('vim.stricmp("a", "B")')) - eq(-1, funcs.luaeval('vim.stricmp("A", "b")')) - eq(-1, funcs.luaeval('vim.stricmp("a", "b")')) - eq(-1, funcs.luaeval('vim.stricmp("A", "B")')) - - eq(-1, funcs.luaeval('vim.stricmp("", "\\0")')) - eq(-1, funcs.luaeval('vim.stricmp("\\0", "\\0\\0")')) - eq(-1, funcs.luaeval('vim.stricmp("\\0\\0", "\\0\\0\\0")')) - eq(-1, funcs.luaeval('vim.stricmp("\\0\\0\\0A", "\\0\\0\\0b")')) - eq(-1, funcs.luaeval('vim.stricmp("\\0\\0\\0a", "\\0\\0\\0B")')) - eq(-1, funcs.luaeval('vim.stricmp("\\0\\0\\0a", "\\0\\0\\0b")')) - - eq(-1, funcs.luaeval('vim.stricmp("a\\0", "B\\0")')) - eq(-1, funcs.luaeval('vim.stricmp("A\\0", "b\\0")')) - eq(-1, funcs.luaeval('vim.stricmp("a\\0", "b\\0")')) - eq(-1, funcs.luaeval('vim.stricmp("A\\0", "B\\0")')) - - eq(-1, funcs.luaeval('vim.stricmp("\\0a", "\\0B")')) - eq(-1, funcs.luaeval('vim.stricmp("\\0A", "\\0b")')) - eq(-1, funcs.luaeval('vim.stricmp("\\0a", "\\0b")')) - eq(-1, funcs.luaeval('vim.stricmp("\\0A", "\\0B")')) - - eq(-1, funcs.luaeval('vim.stricmp("\\0a\\0", "\\0B\\0")')) - eq(-1, funcs.luaeval('vim.stricmp("\\0A\\0", "\\0b\\0")')) - eq(-1, funcs.luaeval('vim.stricmp("\\0a\\0", "\\0b\\0")')) - eq(-1, funcs.luaeval('vim.stricmp("\\0A\\0", "\\0B\\0")')) - - eq(1, funcs.luaeval('vim.stricmp("c", "B")')) - eq(1, funcs.luaeval('vim.stricmp("C", "b")')) - eq(1, funcs.luaeval('vim.stricmp("c", "b")')) - eq(1, funcs.luaeval('vim.stricmp("C", "B")')) - - eq(1, funcs.luaeval('vim.stricmp("\\0", "")')) - eq(1, funcs.luaeval('vim.stricmp("\\0\\0", "\\0")')) - eq(1, funcs.luaeval('vim.stricmp("\\0\\0\\0", "\\0\\0")')) - eq(1, funcs.luaeval('vim.stricmp("\\0\\0\\0\\0", "\\0\\0\\0")')) - eq(1, funcs.luaeval('vim.stricmp("\\0\\0\\0C", "\\0\\0\\0b")')) - eq(1, funcs.luaeval('vim.stricmp("\\0\\0\\0c", "\\0\\0\\0B")')) - eq(1, funcs.luaeval('vim.stricmp("\\0\\0\\0c", "\\0\\0\\0b")')) - - eq(1, funcs.luaeval('vim.stricmp("c\\0", "B\\0")')) - eq(1, funcs.luaeval('vim.stricmp("C\\0", "b\\0")')) - eq(1, funcs.luaeval('vim.stricmp("c\\0", "b\\0")')) - eq(1, funcs.luaeval('vim.stricmp("C\\0", "B\\0")')) - - eq(1, funcs.luaeval('vim.stricmp("c\\0", "B")')) - eq(1, funcs.luaeval('vim.stricmp("C\\0", "b")')) - eq(1, funcs.luaeval('vim.stricmp("c\\0", "b")')) - eq(1, funcs.luaeval('vim.stricmp("C\\0", "B")')) - - eq(1, funcs.luaeval('vim.stricmp("\\0c", "\\0B")')) - eq(1, funcs.luaeval('vim.stricmp("\\0C", "\\0b")')) - eq(1, funcs.luaeval('vim.stricmp("\\0c", "\\0b")')) - eq(1, funcs.luaeval('vim.stricmp("\\0C", "\\0B")')) - - eq(1, funcs.luaeval('vim.stricmp("\\0c\\0", "\\0B\\0")')) - eq(1, funcs.luaeval('vim.stricmp("\\0C\\0", "\\0b\\0")')) - eq(1, funcs.luaeval('vim.stricmp("\\0c\\0", "\\0b\\0")')) - eq(1, funcs.luaeval('vim.stricmp("\\0C\\0", "\\0B\\0")')) - end) - - it("vim.str_utfindex/str_byteindex", function() - exec_lua([[_G.test_text = "xy åäö ɧ 汉语 ↥ 🤦x🦄 å بِيَّ"]]) - local indicies32 = {[0]=0,1,2,3,5,7,9,10,12,13,16,19,20,23,24,28,29,33,34,35,37,38,40,42,44,46,48} - local indicies16 = {[0]=0,1,2,3,5,7,9,10,12,13,16,19,20,23,24,28,28,29,33,33,34,35,37,38,40,42,44,46,48} - for i,k in pairs(indicies32) do - eq(k, exec_lua("return vim.str_byteindex(_G.test_text, ...)", i), i) - end - for i,k in pairs(indicies16) do - eq(k, exec_lua("return vim.str_byteindex(_G.test_text, ..., true)", i), i) - end - local i32, i16 = 0, 0 - for k = 0,48 do - if indicies32[i32] < k then - i32 = i32 + 1 - end - if indicies16[i16] < k then - i16 = i16 + 1 - if indicies16[i16+1] == indicies16[i16] then - i16 = i16 + 1 - end - end - eq({i32, i16}, exec_lua("return {vim.str_utfindex(_G.test_text, ...)}", k), k) - end - end) - - it("vim.schedule", function() - exec_lua([[ - test_table = {} - vim.schedule(function() - table.insert(test_table, "xx") - end) - table.insert(test_table, "yy") - ]]) - eq({"yy","xx"}, exec_lua("return test_table")) - - -- Validates args. - eq('Error executing lua: vim.schedule: expected function', - pcall_err(exec_lua, "vim.schedule('stringly')")) - eq('Error executing lua: vim.schedule: expected function', - pcall_err(exec_lua, "vim.schedule()")) - - exec_lua([[ - vim.schedule(function() - error("big failure\nvery async") - end) - ]]) - - feed("<cr>") - eq('Error executing vim.schedule lua callback: [string "<nvim>"]:2: big failure\nvery async', eval("v:errmsg")) - - local screen = Screen.new(60,5) - screen:set_default_attr_ids({ - [1] = {bold = true, foreground = Screen.colors.Blue1}, - [2] = {bold = true, reverse = true}, - [3] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red}, - [4] = {bold = true, foreground = Screen.colors.SeaGreen4}, - }) - screen:attach() - screen:expect{grid=[[ - ^ | - {1:~ }| - {1:~ }| - {1:~ }| - | - ]]} - - -- nvim_command causes a vimL exception, check that it is properly caught - -- and propagated as an error message in async contexts.. #10809 - exec_lua([[ - vim.schedule(function() - vim.api.nvim_command(":echo 'err") - end) - ]]) - screen:expect{grid=[[ - | - {2: }| - {3:Error executing vim.schedule lua callback: [string "<nvim>"]}| - {3::2: Vim(echo):E115: Missing quote: 'err} | - {4:Press ENTER or type command to continue}^ | - ]]} - end) - - it("vim.split", function() - local split = function(str, sep, plain) - return exec_lua('return vim.split(...)', str, sep, plain) - end - - local tests = { - { "a,b", ",", false, { 'a', 'b' } }, - { ":aa::bb:", ":", false, { '', 'aa', '', 'bb', '' } }, - { "::ee::ff:", ":", false, { '', '', 'ee', '', 'ff', '' } }, - { "ab", ".", false, { '', '', '' } }, - { "a1b2c", "[0-9]", false, { 'a', 'b', 'c' } }, - { "xy", "", false, { 'x', 'y' } }, - { "here be dragons", " ", false, { "here", "be", "dragons"} }, - { "axaby", "ab?", false, { '', 'x', 'y' } }, - { "f v2v v3v w2w ", "([vw])2%1", false, { 'f ', ' v3v ', ' ' } }, - { "x*yz*oo*l", "*", true, { 'x', 'yz', 'oo', 'l' } }, - } - - for _, t in ipairs(tests) do - eq(t[4], split(t[1], t[2], t[3])) - end - - local loops = { - { "abc", ".-" }, - } - - for _, t in ipairs(loops) do - matches(".*Infinite loop detected", pcall_err(split, t[1], t[2])) - end - - -- Validates args. - eq(true, pcall(split, 'string', 'string', nil)) - eq('Error executing lua: .../shared.lua: Expected string, got number', - pcall_err(split, 1, 'string', nil)) - eq('Error executing lua: .../shared.lua: Expected string, got number', - pcall_err(split, 'string', 1, nil)) - eq('Error executing lua: .../shared.lua: Expected boolean or nil, got number', - pcall_err(split, 'string', 'string', 1)) - end) - - it('vim.trim', function() - local trim = function(s) - return exec_lua('return vim.trim(...)', s) - end - - local trims = { - { " a", "a" }, - { " b ", "b" }, - { "\tc" , "c" }, - { "r\n", "r" }, - } - - for _, t in ipairs(trims) do - assert(t[2], trim(t[1])) - end - - -- Validates args. - eq('Error executing lua: .../shared.lua: Expected string, got number', - pcall_err(trim, 2)) - end) - - it('vim.inspect', function() - -- just make sure it basically works, it has its own test suite - local inspect = function(t, opts) - return exec_lua('return vim.inspect(...)', t, opts) - end - - eq('2', inspect(2)) - eq('{+a = {+b = 1+}+}', - inspect({ a = { b = 1 } }, { newline = '+', indent = '' })) - - -- special value vim.inspect.KEY works - eq('{ KEY_a = "x", KEY_b = "y"}', exec_lua([[ - return vim.inspect({a="x", b="y"}, {newline = '', process = function(item, path) - if path[#path] == vim.inspect.KEY then - return 'KEY_'..item - end - return item - end}) - ]])) - end) - - it("vim.deepcopy", function() - local is_dc = exec_lua([[ - local a = { x = { 1, 2 }, y = 5} - local b = vim.deepcopy(a) - - local count = 0 - for _ in pairs(b) do count = count + 1 end - - return b.x[1] == 1 and b.x[2] == 2 and b.y == 5 and count == 2 - and tostring(a) ~= tostring(b) - ]]) - - assert(is_dc) - end) - - it('vim.pesc', function() - eq('foo%-bar', exec_lua([[return vim.pesc('foo-bar')]])) - eq('foo%%%-bar', exec_lua([[return vim.pesc(vim.pesc('foo-bar'))]])) - - -- Validates args. - eq("Error executing lua: .../shared.lua: Expected string, got number", - pcall_err(exec_lua, [[return vim.pesc(2)]])) - end) - - it('vim.call, vim.fn', function() - eq(true, exec_lua([[return vim.call('sin', 0.0) == 0.0 ]])) - eq(true, exec_lua([[return vim.fn.sin(0.0) == 0.0 ]])) - -- compat: nvim_call_function uses "special" value for vimL float - eq(false, exec_lua([[return vim.api.nvim_call_function('sin', {0.0}) == 0.0 ]])) - - source([[ - func! FooFunc(test) - let g:test = a:test - return {} - endfunc - func! VarArg(...) - return a:000 - endfunc - ]]) - eq(true, exec_lua([[return next(vim.fn.FooFunc(3)) == nil ]])) - eq(3, eval("g:test")) - -- compat: nvim_call_function uses "special" value for empty dict - eq(true, exec_lua([[return next(vim.api.nvim_call_function("FooFunc", {5})) == true ]])) - eq(5, eval("g:test")) - - eq({2, "foo", true}, exec_lua([[return vim.fn.VarArg(2, "foo", true)]])) - - -- error handling - eq({false, 'Vim:E714: List required'}, exec_lua([[return {pcall(vim.fn.add, "aa", "bb")}]])) - end) -end) diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua new file mode 100644 index 0000000000..17ffcd8d86 --- /dev/null +++ b/test/functional/lua/vim_spec.lua @@ -0,0 +1,663 @@ +-- Test suite for testing interactions with API bindings +local helpers = require('test.functional.helpers')(after_each) +local Screen = require('test.functional.ui.screen') + +local funcs = helpers.funcs +local meths = helpers.meths +local command = helpers.command +local clear = helpers.clear +local eq = helpers.eq +local eval = helpers.eval +local feed = helpers.feed +local pcall_err = helpers.pcall_err +local exec_lua = helpers.exec_lua +local matches = helpers.matches +local source = helpers.source +local NIL = helpers.NIL +local retry = helpers.retry + +before_each(clear) + +describe('lua stdlib', function() + -- İ: `tolower("İ")` is `i` which has length 1 while `İ` itself has + -- length 2 (in bytes). + -- Ⱥ: `tolower("Ⱥ")` is `ⱥ` which has length 2 while `Ⱥ` itself has + -- length 3 (in bytes). + -- + -- Note: 'i' !=? 'İ' and 'ⱥ' !=? 'Ⱥ' on some systems. + -- Note: Built-in Nvim comparison (on systems lacking `strcasecmp`) works + -- only on ASCII characters. + it('vim.stricmp', function() + eq(0, funcs.luaeval('vim.stricmp("a", "A")')) + eq(0, funcs.luaeval('vim.stricmp("A", "a")')) + eq(0, funcs.luaeval('vim.stricmp("a", "a")')) + eq(0, funcs.luaeval('vim.stricmp("A", "A")')) + + eq(0, funcs.luaeval('vim.stricmp("", "")')) + eq(0, funcs.luaeval('vim.stricmp("\\0", "\\0")')) + eq(0, funcs.luaeval('vim.stricmp("\\0\\0", "\\0\\0")')) + eq(0, funcs.luaeval('vim.stricmp("\\0\\0\\0", "\\0\\0\\0")')) + eq(0, funcs.luaeval('vim.stricmp("\\0\\0\\0A", "\\0\\0\\0a")')) + eq(0, funcs.luaeval('vim.stricmp("\\0\\0\\0a", "\\0\\0\\0A")')) + eq(0, funcs.luaeval('vim.stricmp("\\0\\0\\0a", "\\0\\0\\0a")')) + + eq(0, funcs.luaeval('vim.stricmp("a\\0", "A\\0")')) + eq(0, funcs.luaeval('vim.stricmp("A\\0", "a\\0")')) + eq(0, funcs.luaeval('vim.stricmp("a\\0", "a\\0")')) + eq(0, funcs.luaeval('vim.stricmp("A\\0", "A\\0")')) + + eq(0, funcs.luaeval('vim.stricmp("\\0a", "\\0A")')) + eq(0, funcs.luaeval('vim.stricmp("\\0A", "\\0a")')) + eq(0, funcs.luaeval('vim.stricmp("\\0a", "\\0a")')) + eq(0, funcs.luaeval('vim.stricmp("\\0A", "\\0A")')) + + eq(0, funcs.luaeval('vim.stricmp("\\0a\\0", "\\0A\\0")')) + eq(0, funcs.luaeval('vim.stricmp("\\0A\\0", "\\0a\\0")')) + eq(0, funcs.luaeval('vim.stricmp("\\0a\\0", "\\0a\\0")')) + eq(0, funcs.luaeval('vim.stricmp("\\0A\\0", "\\0A\\0")')) + + eq(-1, funcs.luaeval('vim.stricmp("a", "B")')) + eq(-1, funcs.luaeval('vim.stricmp("A", "b")')) + eq(-1, funcs.luaeval('vim.stricmp("a", "b")')) + eq(-1, funcs.luaeval('vim.stricmp("A", "B")')) + + eq(-1, funcs.luaeval('vim.stricmp("", "\\0")')) + eq(-1, funcs.luaeval('vim.stricmp("\\0", "\\0\\0")')) + eq(-1, funcs.luaeval('vim.stricmp("\\0\\0", "\\0\\0\\0")')) + eq(-1, funcs.luaeval('vim.stricmp("\\0\\0\\0A", "\\0\\0\\0b")')) + eq(-1, funcs.luaeval('vim.stricmp("\\0\\0\\0a", "\\0\\0\\0B")')) + eq(-1, funcs.luaeval('vim.stricmp("\\0\\0\\0a", "\\0\\0\\0b")')) + + eq(-1, funcs.luaeval('vim.stricmp("a\\0", "B\\0")')) + eq(-1, funcs.luaeval('vim.stricmp("A\\0", "b\\0")')) + eq(-1, funcs.luaeval('vim.stricmp("a\\0", "b\\0")')) + eq(-1, funcs.luaeval('vim.stricmp("A\\0", "B\\0")')) + + eq(-1, funcs.luaeval('vim.stricmp("\\0a", "\\0B")')) + eq(-1, funcs.luaeval('vim.stricmp("\\0A", "\\0b")')) + eq(-1, funcs.luaeval('vim.stricmp("\\0a", "\\0b")')) + eq(-1, funcs.luaeval('vim.stricmp("\\0A", "\\0B")')) + + eq(-1, funcs.luaeval('vim.stricmp("\\0a\\0", "\\0B\\0")')) + eq(-1, funcs.luaeval('vim.stricmp("\\0A\\0", "\\0b\\0")')) + eq(-1, funcs.luaeval('vim.stricmp("\\0a\\0", "\\0b\\0")')) + eq(-1, funcs.luaeval('vim.stricmp("\\0A\\0", "\\0B\\0")')) + + eq(1, funcs.luaeval('vim.stricmp("c", "B")')) + eq(1, funcs.luaeval('vim.stricmp("C", "b")')) + eq(1, funcs.luaeval('vim.stricmp("c", "b")')) + eq(1, funcs.luaeval('vim.stricmp("C", "B")')) + + eq(1, funcs.luaeval('vim.stricmp("\\0", "")')) + eq(1, funcs.luaeval('vim.stricmp("\\0\\0", "\\0")')) + eq(1, funcs.luaeval('vim.stricmp("\\0\\0\\0", "\\0\\0")')) + eq(1, funcs.luaeval('vim.stricmp("\\0\\0\\0\\0", "\\0\\0\\0")')) + eq(1, funcs.luaeval('vim.stricmp("\\0\\0\\0C", "\\0\\0\\0b")')) + eq(1, funcs.luaeval('vim.stricmp("\\0\\0\\0c", "\\0\\0\\0B")')) + eq(1, funcs.luaeval('vim.stricmp("\\0\\0\\0c", "\\0\\0\\0b")')) + + eq(1, funcs.luaeval('vim.stricmp("c\\0", "B\\0")')) + eq(1, funcs.luaeval('vim.stricmp("C\\0", "b\\0")')) + eq(1, funcs.luaeval('vim.stricmp("c\\0", "b\\0")')) + eq(1, funcs.luaeval('vim.stricmp("C\\0", "B\\0")')) + + eq(1, funcs.luaeval('vim.stricmp("c\\0", "B")')) + eq(1, funcs.luaeval('vim.stricmp("C\\0", "b")')) + eq(1, funcs.luaeval('vim.stricmp("c\\0", "b")')) + eq(1, funcs.luaeval('vim.stricmp("C\\0", "B")')) + + eq(1, funcs.luaeval('vim.stricmp("\\0c", "\\0B")')) + eq(1, funcs.luaeval('vim.stricmp("\\0C", "\\0b")')) + eq(1, funcs.luaeval('vim.stricmp("\\0c", "\\0b")')) + eq(1, funcs.luaeval('vim.stricmp("\\0C", "\\0B")')) + + eq(1, funcs.luaeval('vim.stricmp("\\0c\\0", "\\0B\\0")')) + eq(1, funcs.luaeval('vim.stricmp("\\0C\\0", "\\0b\\0")')) + eq(1, funcs.luaeval('vim.stricmp("\\0c\\0", "\\0b\\0")')) + eq(1, funcs.luaeval('vim.stricmp("\\0C\\0", "\\0B\\0")')) + end) + + it('vim.startswith', function() + eq(true, funcs.luaeval('vim.startswith("123", "1")')) + eq(true, funcs.luaeval('vim.startswith("123", "")')) + eq(true, funcs.luaeval('vim.startswith("123", "123")')) + eq(true, funcs.luaeval('vim.startswith("", "")')) + + eq(false, funcs.luaeval('vim.startswith("123", " ")')) + eq(false, funcs.luaeval('vim.startswith("123", "2")')) + eq(false, funcs.luaeval('vim.startswith("123", "1234")')) + + eq("string", type(pcall_err(funcs.luaeval, 'vim.startswith("123", nil)'))) + eq("string", type(pcall_err(funcs.luaeval, 'vim.startswith(nil, "123")'))) + end) + + it('vim.endswith', function() + eq(true, funcs.luaeval('vim.endswith("123", "3")')) + eq(true, funcs.luaeval('vim.endswith("123", "")')) + eq(true, funcs.luaeval('vim.endswith("123", "123")')) + eq(true, funcs.luaeval('vim.endswith("", "")')) + + eq(false, funcs.luaeval('vim.endswith("123", " ")')) + eq(false, funcs.luaeval('vim.endswith("123", "2")')) + eq(false, funcs.luaeval('vim.endswith("123", "1234")')) + + eq("string", type(pcall_err(funcs.luaeval, 'vim.endswith("123", nil)'))) + eq("string", type(pcall_err(funcs.luaeval, 'vim.endswith(nil, "123")'))) + end) + + it("vim.str_utfindex/str_byteindex", function() + exec_lua([[_G.test_text = "xy åäö ɧ 汉语 ↥ 🤦x🦄 å بِيَّ"]]) + local indicies32 = {[0]=0,1,2,3,5,7,9,10,12,13,16,19,20,23,24,28,29,33,34,35,37,38,40,42,44,46,48} + local indicies16 = {[0]=0,1,2,3,5,7,9,10,12,13,16,19,20,23,24,28,28,29,33,33,34,35,37,38,40,42,44,46,48} + for i,k in pairs(indicies32) do + eq(k, exec_lua("return vim.str_byteindex(_G.test_text, ...)", i), i) + end + for i,k in pairs(indicies16) do + eq(k, exec_lua("return vim.str_byteindex(_G.test_text, ..., true)", i), i) + end + local i32, i16 = 0, 0 + for k = 0,48 do + if indicies32[i32] < k then + i32 = i32 + 1 + end + if indicies16[i16] < k then + i16 = i16 + 1 + if indicies16[i16+1] == indicies16[i16] then + i16 = i16 + 1 + end + end + eq({i32, i16}, exec_lua("return {vim.str_utfindex(_G.test_text, ...)}", k), k) + end + end) + + it("vim.schedule", function() + exec_lua([[ + test_table = {} + vim.schedule(function() + table.insert(test_table, "xx") + end) + table.insert(test_table, "yy") + ]]) + eq({"yy","xx"}, exec_lua("return test_table")) + + -- Validates args. + eq('Error executing lua: vim.schedule: expected function', + pcall_err(exec_lua, "vim.schedule('stringly')")) + eq('Error executing lua: vim.schedule: expected function', + pcall_err(exec_lua, "vim.schedule()")) + + exec_lua([[ + vim.schedule(function() + error("big failure\nvery async") + end) + ]]) + + feed("<cr>") + eq('Error executing vim.schedule lua callback: [string "<nvim>"]:2: big failure\nvery async', eval("v:errmsg")) + + local screen = Screen.new(60,5) + screen:set_default_attr_ids({ + [1] = {bold = true, foreground = Screen.colors.Blue1}, + [2] = {bold = true, reverse = true}, + [3] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red}, + [4] = {bold = true, foreground = Screen.colors.SeaGreen4}, + }) + screen:attach() + screen:expect{grid=[[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]} + + -- nvim_command causes a vimL exception, check that it is properly caught + -- and propagated as an error message in async contexts.. #10809 + exec_lua([[ + vim.schedule(function() + vim.api.nvim_command(":echo 'err") + end) + ]]) + screen:expect{grid=[[ + | + {2: }| + {3:Error executing vim.schedule lua callback: [string "<nvim>"]}| + {3::2: Vim(echo):E115: Missing quote: 'err} | + {4:Press ENTER or type command to continue}^ | + ]]} + end) + + it("vim.split", function() + local split = function(str, sep, plain) + return exec_lua('return vim.split(...)', str, sep, plain) + end + + local tests = { + { "a,b", ",", false, { 'a', 'b' } }, + { ":aa::bb:", ":", false, { '', 'aa', '', 'bb', '' } }, + { "::ee::ff:", ":", false, { '', '', 'ee', '', 'ff', '' } }, + { "ab", ".", false, { '', '', '' } }, + { "a1b2c", "[0-9]", false, { 'a', 'b', 'c' } }, + { "xy", "", false, { 'x', 'y' } }, + { "here be dragons", " ", false, { "here", "be", "dragons"} }, + { "axaby", "ab?", false, { '', 'x', 'y' } }, + { "f v2v v3v w2w ", "([vw])2%1", false, { 'f ', ' v3v ', ' ' } }, + { "x*yz*oo*l", "*", true, { 'x', 'yz', 'oo', 'l' } }, + } + + for _, t in ipairs(tests) do + eq(t[4], split(t[1], t[2], t[3])) + end + + local loops = { + { "abc", ".-" }, + } + + for _, t in ipairs(loops) do + matches(".*Infinite loop detected", pcall_err(split, t[1], t[2])) + end + + -- Validates args. + eq(true, pcall(split, 'string', 'string')) + eq('Error executing lua: .../shared.lua: s: expected string, got number', + pcall_err(split, 1, 'string')) + eq('Error executing lua: .../shared.lua: sep: expected string, got number', + pcall_err(split, 'string', 1)) + eq('Error executing lua: .../shared.lua: plain: expected boolean, got number', + pcall_err(split, 'string', 'string', 1)) + end) + + it('vim.trim', function() + local trim = function(s) + return exec_lua('return vim.trim(...)', s) + end + + local trims = { + { " a", "a" }, + { " b ", "b" }, + { "\tc" , "c" }, + { "r\n", "r" }, + } + + for _, t in ipairs(trims) do + assert(t[2], trim(t[1])) + end + + -- Validates args. + eq('Error executing lua: .../shared.lua: s: expected string, got number', + pcall_err(trim, 2)) + end) + + it('vim.inspect', function() + -- just make sure it basically works, it has its own test suite + local inspect = function(t, opts) + return exec_lua('return vim.inspect(...)', t, opts) + end + + eq('2', inspect(2)) + eq('{+a = {+b = 1+}+}', + inspect({ a = { b = 1 } }, { newline = '+', indent = '' })) + + -- special value vim.inspect.KEY works + eq('{ KEY_a = "x", KEY_b = "y"}', exec_lua([[ + return vim.inspect({a="x", b="y"}, {newline = '', process = function(item, path) + if path[#path] == vim.inspect.KEY then + return 'KEY_'..item + end + return item + end}) + ]])) + end) + + it("vim.deepcopy", function() + local is_dc = exec_lua([[ + local a = { x = { 1, 2 }, y = 5} + local b = vim.deepcopy(a) + + local count = 0 + for _ in pairs(b) do count = count + 1 end + + return b.x[1] == 1 and b.x[2] == 2 and b.y == 5 and count == 2 + and tostring(a) ~= tostring(b) + ]]) + + assert(is_dc) + end) + + it('vim.pesc', function() + eq('foo%-bar', exec_lua([[return vim.pesc('foo-bar')]])) + eq('foo%%%-bar', exec_lua([[return vim.pesc(vim.pesc('foo-bar'))]])) + + -- Validates args. + eq('Error executing lua: .../shared.lua: s: expected string, got number', + pcall_err(exec_lua, [[return vim.pesc(2)]])) + end) + + it('vim.tbl_keys', function() + eq({}, exec_lua("return vim.tbl_keys({})")) + for _, v in pairs(exec_lua("return vim.tbl_keys({'a', 'b', 'c'})")) do + eq(true, exec_lua("return vim.tbl_contains({ 1, 2, 3 }, ...)", v)) + end + for _, v in pairs(exec_lua("return vim.tbl_keys({a=1, b=2, c=3})")) do + eq(true, exec_lua("return vim.tbl_contains({ 'a', 'b', 'c' }, ...)", v)) + end + end) + + it('vim.tbl_values', function() + eq({}, exec_lua("return vim.tbl_values({})")) + for _, v in pairs(exec_lua("return vim.tbl_values({'a', 'b', 'c'})")) do + eq(true, exec_lua("return vim.tbl_contains({ 'a', 'b', 'c' }, ...)", v)) + end + for _, v in pairs(exec_lua("return vim.tbl_values({a=1, b=2, c=3})")) do + eq(true, exec_lua("return vim.tbl_contains({ 1, 2, 3 }, ...)", v)) + end + end) + + it('vim.tbl_islist', function() + eq(NIL, exec_lua("return vim.tbl_islist({})")) + eq(true, exec_lua("return vim.tbl_islist({'a', 'b', 'c'})")) + eq(false, exec_lua("return vim.tbl_islist({'a', '32', a='hello', b='baz'})")) + eq(false, exec_lua("return vim.tbl_islist({1, a='hello', b='baz'})")) + eq(false, exec_lua("return vim.tbl_islist({a='hello', b='baz', 1})")) + eq(false, exec_lua("return vim.tbl_islist({1, 2, nil, a='hello'})")) + end) + + it('vim.tbl_isempty', function() + eq(true, exec_lua("return vim.tbl_isempty({})")) + eq(false, exec_lua("return vim.tbl_isempty({ 1, 2, 3 })")) + eq(false, exec_lua("return vim.tbl_isempty({a=1, b=2, c=3})")) + end) + + it('vim.deep_equal', function() + eq(true, exec_lua [[ return vim.deep_equal({a=1}, {a=1}) ]]) + eq(true, exec_lua [[ return vim.deep_equal({a={b=1}}, {a={b=1}}) ]]) + eq(true, exec_lua [[ return vim.deep_equal({a={b={nil}}}, {a={b={}}}) ]]) + eq(true, exec_lua [[ return vim.deep_equal({a=1, [5]=5}, {nil,nil,nil,nil,5,a=1}) ]]) + eq(false, exec_lua [[ return vim.deep_equal(1, {nil,nil,nil,nil,5,a=1}) ]]) + eq(false, exec_lua [[ return vim.deep_equal(1, 3) ]]) + eq(false, exec_lua [[ return vim.deep_equal(nil, 3) ]]) + eq(false, exec_lua [[ return vim.deep_equal({a=1}, {a=2}) ]]) + end) + + it('vim.list_extend', function() + eq({1,2,3}, exec_lua [[ return vim.list_extend({1}, {2,3}) ]]) + eq('Error executing lua: .../shared.lua: src: expected table, got nil', + pcall_err(exec_lua, [[ return vim.list_extend({1}, nil) ]])) + eq({1,2}, exec_lua [[ return vim.list_extend({1}, {2;a=1}) ]]) + eq(true, exec_lua [[ local a = {1} return vim.list_extend(a, {2;a=1}) == a ]]) + eq({2}, exec_lua [[ return vim.list_extend({}, {2;a=1}, 1) ]]) + eq({}, exec_lua [[ return vim.list_extend({}, {2;a=1}, 2) ]]) + eq({}, exec_lua [[ return vim.list_extend({}, {2;a=1}, 1, -1) ]]) + eq({2}, exec_lua [[ return vim.list_extend({}, {2;a=1}, -1, 2) ]]) + end) + + it('vim.tbl_add_reverse_lookup', function() + eq(true, exec_lua [[ + local a = { A = 1 } + vim.tbl_add_reverse_lookup(a) + return vim.deep_equal(a, { A = 1; [1] = 'A'; }) + ]]) + -- Throw an error for trying to do it twice (run into an existing key) + local code = [[ + local res = {} + local a = { A = 1 } + vim.tbl_add_reverse_lookup(a) + assert(vim.deep_equal(a, { A = 1; [1] = 'A'; })) + vim.tbl_add_reverse_lookup(a) + ]] + matches('Error executing lua: .../shared.lua: The reverse lookup found an existing value for "[1A]" while processing key "[1A]"', + pcall_err(exec_lua, code)) + end) + + it('vim.call, vim.fn', function() + eq(true, exec_lua([[return vim.call('sin', 0.0) == 0.0 ]])) + eq(true, exec_lua([[return vim.fn.sin(0.0) == 0.0 ]])) + -- compat: nvim_call_function uses "special" value for vimL float + eq(false, exec_lua([[return vim.api.nvim_call_function('sin', {0.0}) == 0.0 ]])) + + source([[ + func! FooFunc(test) + let g:test = a:test + return {} + endfunc + func! VarArg(...) + return a:000 + endfunc + func! Nilly() + return [v:null, v:null] + endfunc + ]]) + eq(true, exec_lua([[return next(vim.fn.FooFunc(3)) == nil ]])) + eq(3, eval("g:test")) + -- compat: nvim_call_function uses "special" value for empty dict + eq(true, exec_lua([[return next(vim.api.nvim_call_function("FooFunc", {5})) == true ]])) + eq(5, eval("g:test")) + + eq({2, "foo", true}, exec_lua([[return vim.fn.VarArg(2, "foo", true)]])) + + eq(true, exec_lua([[ + local x = vim.fn.Nilly() + return #x == 2 and x[1] == vim.NIL and x[2] == vim.NIL + ]])) + eq({NIL, NIL}, exec_lua([[return vim.fn.Nilly()]])) + + -- error handling + eq({false, 'Vim:E714: List required'}, exec_lua([[return {pcall(vim.fn.add, "aa", "bb")}]])) + end) + + it('vim.rpcrequest and vim.rpcnotify', function() + exec_lua([[ + chan = vim.fn.jobstart({'cat'}, {rpc=true}) + vim.rpcrequest(chan, 'nvim_set_current_line', 'meow') + ]]) + eq('meow', meths.get_current_line()) + command("let x = [3, 'aa', v:true, v:null]") + eq(true, exec_lua([[ + ret = vim.rpcrequest(chan, 'nvim_get_var', 'x') + return #ret == 4 and ret[1] == 3 and ret[2] == 'aa' and ret[3] == true and ret[4] == vim.NIL + ]])) + eq({3, 'aa', true, NIL}, exec_lua([[return ret]])) + + -- error handling + eq({false, 'Invalid channel: 23'}, + exec_lua([[return {pcall(vim.rpcrequest, 23, 'foo')}]])) + eq({false, 'Invalid channel: 23'}, + exec_lua([[return {pcall(vim.rpcnotify, 23, 'foo')}]])) + + eq({false, 'Vim:E121: Undefined variable: foobar'}, + exec_lua([[return {pcall(vim.rpcrequest, chan, 'nvim_eval', "foobar")}]])) + + + -- rpcnotify doesn't wait on request + eq('meow', exec_lua([[ + vim.rpcnotify(chan, 'nvim_set_current_line', 'foo') + return vim.api.nvim_get_current_line() + ]])) + retry(10, nil, function() + eq('foo', meths.get_current_line()) + end) + + local screen = Screen.new(50,7) + screen:set_default_attr_ids({ + [1] = {bold = true, foreground = Screen.colors.Blue1}, + [2] = {bold = true, reverse = true}, + [3] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red}, + [4] = {bold = true, foreground = Screen.colors.SeaGreen4}, + }) + screen:attach() + exec_lua([[ + local timer = vim.loop.new_timer() + timer:start(20, 0, function () + -- notify ok (executed later when safe) + vim.rpcnotify(chan, 'nvim_set_var', 'yy', {3, vim.NIL}) + -- rpcrequest an error + vim.rpcrequest(chan, 'nvim_set_current_line', 'bork') + end) + ]]) + screen:expect{grid=[[ + foo | + {1:~ }| + {2: }| + {3:Error executing luv callback:} | + {3:[string "<nvim>"]:6: E5560: rpcrequest must not be}| + {3: called in a lua loop callback} | + {4:Press ENTER or type command to continue}^ | + ]]} + feed('<cr>') + eq({3, NIL}, meths.get_var('yy')) + end) + + it('vim.validate', function() + exec_lua("vim.validate{arg1={{}, 'table' }}") + exec_lua("vim.validate{arg1={{}, 't' }}") + exec_lua("vim.validate{arg1={nil, 't', true }}") + exec_lua("vim.validate{arg1={{ foo='foo' }, 't' }}") + exec_lua("vim.validate{arg1={{ 'foo' }, 't' }}") + exec_lua("vim.validate{arg1={'foo', 'string' }}") + exec_lua("vim.validate{arg1={'foo', 's' }}") + exec_lua("vim.validate{arg1={'', 's' }}") + exec_lua("vim.validate{arg1={nil, 's', true }}") + exec_lua("vim.validate{arg1={1, 'number' }}") + exec_lua("vim.validate{arg1={1, 'n' }}") + exec_lua("vim.validate{arg1={0, 'n' }}") + exec_lua("vim.validate{arg1={0.1, 'n' }}") + exec_lua("vim.validate{arg1={nil, 'n', true }}") + exec_lua("vim.validate{arg1={true, 'boolean' }}") + exec_lua("vim.validate{arg1={true, 'b' }}") + exec_lua("vim.validate{arg1={false, 'b' }}") + exec_lua("vim.validate{arg1={nil, 'b', true }}") + exec_lua("vim.validate{arg1={function()end, 'function' }}") + exec_lua("vim.validate{arg1={function()end, 'f' }}") + exec_lua("vim.validate{arg1={nil, 'f', true }}") + exec_lua("vim.validate{arg1={nil, 'nil' }}") + exec_lua("vim.validate{arg1={nil, 'nil', true }}") + exec_lua("vim.validate{arg1={coroutine.create(function()end), 'thread' }}") + exec_lua("vim.validate{arg1={nil, 'thread', true }}") + exec_lua("vim.validate{arg1={{}, 't' }, arg2={ 'foo', 's' }}") + exec_lua("vim.validate{arg1={2, function(a) return (a % 2) == 0 end, 'even number' }}") + + eq("Error executing lua: .../shared.lua: 1: expected table, got number", + pcall_err(exec_lua, "vim.validate{ 1, 'x' }")) + eq("Error executing lua: .../shared.lua: invalid type name: x", + pcall_err(exec_lua, "vim.validate{ arg1={ 1, 'x' }}")) + eq("Error executing lua: .../shared.lua: invalid type name: 1", + pcall_err(exec_lua, "vim.validate{ arg1={ 1, 1 }}")) + eq("Error executing lua: .../shared.lua: invalid type name: nil", + pcall_err(exec_lua, "vim.validate{ arg1={ 1 }}")) + + -- Validated parameters are required by default. + eq("Error executing lua: .../shared.lua: arg1: expected string, got nil", + pcall_err(exec_lua, "vim.validate{ arg1={ nil, 's' }}")) + -- Explicitly required. + eq("Error executing lua: .../shared.lua: arg1: expected string, got nil", + pcall_err(exec_lua, "vim.validate{ arg1={ nil, 's', false }}")) + + eq("Error executing lua: .../shared.lua: arg1: expected table, got number", + pcall_err(exec_lua, "vim.validate{arg1={1, 't'}}")) + eq("Error executing lua: .../shared.lua: arg2: expected string, got number", + pcall_err(exec_lua, "vim.validate{arg1={{}, 't'}, arg2={1, 's'}}")) + eq("Error executing lua: .../shared.lua: arg2: expected string, got nil", + pcall_err(exec_lua, "vim.validate{arg1={{}, 't'}, arg2={nil, 's'}}")) + eq("Error executing lua: .../shared.lua: arg2: expected string, got nil", + pcall_err(exec_lua, "vim.validate{arg1={{}, 't'}, arg2={nil, 's'}}")) + eq("Error executing lua: .../shared.lua: arg1: expected even number, got 3", + pcall_err(exec_lua, "vim.validate{arg1={3, function(a) return a == 1 end, 'even number'}}")) + eq("Error executing lua: .../shared.lua: arg1: expected ?, got 3", + pcall_err(exec_lua, "vim.validate{arg1={3, function(a) return a == 1 end}}")) + end) + + it('vim.is_callable', function() + eq(true, exec_lua("return vim.is_callable(function()end)")) + eq(true, exec_lua([[ + local meta = { __call = function()end } + local function new_callable() + return setmetatable({}, meta) + end + local callable = new_callable() + return vim.is_callable(callable) + ]])) + + eq(false, exec_lua("return vim.is_callable(1)")) + eq(false, exec_lua("return vim.is_callable('foo')")) + eq(false, exec_lua("return vim.is_callable({})")) + end) + + it('vim.g', function() + exec_lua [[ + vim.api.nvim_set_var("testing", "hi") + vim.api.nvim_set_var("other", 123) + ]] + eq('hi', funcs.luaeval "vim.g.testing") + eq(123, funcs.luaeval "vim.g.other") + eq(NIL, funcs.luaeval "vim.g.nonexistant") + end) + + it('vim.env', function() + exec_lua [[ + vim.fn.setenv("A", 123) + ]] + eq('123', funcs.luaeval "vim.env.A") + eq(true, funcs.luaeval "vim.env.B == nil") + end) + + it('vim.v', function() + eq(funcs.luaeval "vim.api.nvim_get_vvar('progpath')", funcs.luaeval "vim.v.progpath") + eq(false, funcs.luaeval "vim.v['false']") + eq(NIL, funcs.luaeval "vim.v.null") + end) + + it('vim.bo', function() + eq('', funcs.luaeval "vim.bo.filetype") + exec_lua [[ + vim.api.nvim_buf_set_option(0, "filetype", "markdown") + BUF = vim.api.nvim_create_buf(false, true) + vim.api.nvim_buf_set_option(BUF, "modifiable", false) + ]] + eq(false, funcs.luaeval "vim.bo.modified") + eq('markdown', funcs.luaeval "vim.bo.filetype") + eq(false, funcs.luaeval "vim.bo[BUF].modifiable") + exec_lua [[ + vim.bo.filetype = '' + vim.bo[BUF].modifiable = true + ]] + eq('', funcs.luaeval "vim.bo.filetype") + eq(true, funcs.luaeval "vim.bo[BUF].modifiable") + matches("^Error executing lua: .*: Invalid option name: 'nosuchopt'$", + pcall_err(exec_lua, 'return vim.bo.nosuchopt')) + matches("^Error executing lua: .*: Expected lua string$", + pcall_err(exec_lua, 'return vim.bo[0][0].autoread')) + end) + + it('vim.wo', function() + exec_lua [[ + vim.api.nvim_win_set_option(0, "cole", 2) + vim.cmd "split" + vim.api.nvim_win_set_option(0, "cole", 2) + ]] + eq(2, funcs.luaeval "vim.wo.cole") + exec_lua [[ + vim.wo.conceallevel = 0 + ]] + eq(0, funcs.luaeval "vim.wo.cole") + eq(0, funcs.luaeval "vim.wo[0].cole") + eq(0, funcs.luaeval "vim.wo[1001].cole") + matches("^Error executing lua: .*: Invalid option name: 'notanopt'$", + pcall_err(exec_lua, 'return vim.wo.notanopt')) + matches("^Error executing lua: .*: Expected lua string$", + pcall_err(exec_lua, 'return vim.wo[0][0].list')) + eq(2, funcs.luaeval "vim.wo[1000].cole") + exec_lua [[ + vim.wo[1000].cole = 0 + ]] + eq(0, funcs.luaeval "vim.wo[1000].cole") + end) + + it('vim.cmd', function() + exec_lua [[ + vim.cmd "autocmd BufNew * ++once lua BUF = vim.fn.expand('<abuf>')" + vim.cmd "new" + ]] + eq('2', funcs.luaeval "BUF") + eq(2, funcs.luaeval "#vim.api.nvim_list_bufs()") + end) +end) |