From 4ea5e63aa8c866b4fcc9d10f1a26078d2517f96a Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Sun, 9 Jun 2019 13:26:48 +0200 Subject: tree-sitter: add basic testing on ci build tree-sitter c parser on ci for testing purposes --- test/functional/lua/tree_sitter_spec.lua | 67 ++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 test/functional/lua/tree_sitter_spec.lua (limited to 'test/functional/lua') diff --git a/test/functional/lua/tree_sitter_spec.lua b/test/functional/lua/tree_sitter_spec.lua new file mode 100644 index 0000000000..e25eb47a60 --- /dev/null +++ b/test/functional/lua/tree_sitter_spec.lua @@ -0,0 +1,67 @@ +-- Test suite for testing interactions with API bindings +local helpers = require('test.functional.helpers')(after_each) + +local meths = helpers.meths +local clear = helpers.clear +local eq = helpers.eq +local insert = helpers.insert +local meth_pcall = helpers.meth_pcall +local exec_lua = helpers.exec_lua +local iswin = helpers.iswin + +before_each(clear) + +describe('tree-sitter API', function() + -- error tests not requiring a parser library + it('handles basic errors', function() + --eq({false, 'Error executing lua: vim.schedule: expected function'}, + -- meth_pcall(meths.execute_lua, "parser = vim.tree_sitter.create_parser(0, 'nosuchlang')", {})) + + + + end) + + local ts_path = os.getenv("TREE_SITTER_DIR") + + describe('with C parser', function() + if ts_path == nil then + it("works", function() pending("TREE_SITTER_PATH not set, skipping tree-sitter parser tests") end) + return + end + + before_each(function() + -- TODO the .so/.dylib/.dll thingie + local path = ts_path .. '/bin/c'..(iswin() and '.dll' or '.so') + exec_lua([[ + local path = ... + vim.tree_sitter.add_language(path,'c') + + ]], path) + end) + + it('parses buffer', function() + insert([[ + int main() { + int x = 3; + }]]) + + exec_lua([[ + parser = vim.tree_sitter.create_parser(0, "c") + tree = parser:parse_tree() + root = tree:root() + ]]) + + --eq("", exec_lua("return tostring(parser)")) + eq("", exec_lua("return tostring(tree)")) + eq("", exec_lua("return tostring(root)")) + eq({0,0,3,0}, exec_lua("return {root:range()}")) + + eq(1, exec_lua("return root:child_count()")) + exec_lua("child = root:child(0)") + eq("", exec_lua("return tostring(child)")) + eq({0,0,2,1}, exec_lua("return {child:range()}")) + end) + + end) +end) + -- cgit From c8f861b739b4703b1198dc1f88b09edbeb0d9f2e Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Sat, 15 Jun 2019 12:10:12 +0200 Subject: tree-sitter: rename tree_sitter => treesitter for consistency --- test/functional/lua/tree_sitter_spec.lua | 67 -------------------------------- test/functional/lua/treesitter_spec.lua | 67 ++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+), 67 deletions(-) delete mode 100644 test/functional/lua/tree_sitter_spec.lua create mode 100644 test/functional/lua/treesitter_spec.lua (limited to 'test/functional/lua') diff --git a/test/functional/lua/tree_sitter_spec.lua b/test/functional/lua/tree_sitter_spec.lua deleted file mode 100644 index e25eb47a60..0000000000 --- a/test/functional/lua/tree_sitter_spec.lua +++ /dev/null @@ -1,67 +0,0 @@ --- Test suite for testing interactions with API bindings -local helpers = require('test.functional.helpers')(after_each) - -local meths = helpers.meths -local clear = helpers.clear -local eq = helpers.eq -local insert = helpers.insert -local meth_pcall = helpers.meth_pcall -local exec_lua = helpers.exec_lua -local iswin = helpers.iswin - -before_each(clear) - -describe('tree-sitter API', function() - -- error tests not requiring a parser library - it('handles basic errors', function() - --eq({false, 'Error executing lua: vim.schedule: expected function'}, - -- meth_pcall(meths.execute_lua, "parser = vim.tree_sitter.create_parser(0, 'nosuchlang')", {})) - - - - end) - - local ts_path = os.getenv("TREE_SITTER_DIR") - - describe('with C parser', function() - if ts_path == nil then - it("works", function() pending("TREE_SITTER_PATH not set, skipping tree-sitter parser tests") end) - return - end - - before_each(function() - -- TODO the .so/.dylib/.dll thingie - local path = ts_path .. '/bin/c'..(iswin() and '.dll' or '.so') - exec_lua([[ - local path = ... - vim.tree_sitter.add_language(path,'c') - - ]], path) - end) - - it('parses buffer', function() - insert([[ - int main() { - int x = 3; - }]]) - - exec_lua([[ - parser = vim.tree_sitter.create_parser(0, "c") - tree = parser:parse_tree() - root = tree:root() - ]]) - - --eq("", exec_lua("return tostring(parser)")) - eq("", exec_lua("return tostring(tree)")) - eq("", exec_lua("return tostring(root)")) - eq({0,0,3,0}, exec_lua("return {root:range()}")) - - eq(1, exec_lua("return root:child_count()")) - exec_lua("child = root:child(0)") - eq("", exec_lua("return tostring(child)")) - eq({0,0,2,1}, exec_lua("return {child:range()}")) - end) - - end) -end) - diff --git a/test/functional/lua/treesitter_spec.lua b/test/functional/lua/treesitter_spec.lua new file mode 100644 index 0000000000..8916e59563 --- /dev/null +++ b/test/functional/lua/treesitter_spec.lua @@ -0,0 +1,67 @@ +-- Test suite for testing interactions with API bindings +local helpers = require('test.functional.helpers')(after_each) + +local meths = helpers.meths +local clear = helpers.clear +local eq = helpers.eq +local insert = helpers.insert +local meth_pcall = helpers.meth_pcall +local exec_lua = helpers.exec_lua +local iswin = helpers.iswin + +before_each(clear) + +describe('tree-sitter API', function() + -- error tests not requiring a parser library + it('handles basic errors', function() + --eq({false, 'Error executing lua: vim.schedule: expected function'}, + -- meth_pcall(meths.execute_lua, "parser = vim.treesitter.create_parser(0, 'nosuchlang')", {})) + + + + end) + + local ts_path = os.getenv("TREE_SITTER_DIR") + + describe('with C parser', function() + if ts_path == nil then + it("works", function() pending("TREE_SITTER_PATH not set, skipping tree-sitter parser tests") end) + return + end + + before_each(function() + -- TODO the .so/.dylib/.dll thingie + local path = ts_path .. '/bin/c'..(iswin() and '.dll' or '.so') + exec_lua([[ + local path = ... + vim.treesitter.add_language(path,'c') + + ]], path) + end) + + it('parses buffer', function() + insert([[ + int main() { + int x = 3; + }]]) + + exec_lua([[ + parser = vim.treesitter.create_parser(0, "c") + tree = parser:parse_tree() + root = tree:root() + ]]) + + --eq("", exec_lua("return tostring(parser)")) + eq("", exec_lua("return tostring(tree)")) + eq("", exec_lua("return tostring(root)")) + eq({0,0,3,0}, exec_lua("return {root:range()}")) + + eq(1, exec_lua("return root:child_count()")) + exec_lua("child = root:child(0)") + eq("", exec_lua("return tostring(child)")) + eq({0,0,2,1}, exec_lua("return {child:range()}")) + end) + + end) +end) + -- cgit From 167a1cfdef0c4b3526830ad0356f06bf480df6af Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Mon, 17 Jun 2019 21:46:31 +0200 Subject: tree-sitter: improve parser API (shared parser between plugins) --- test/functional/lua/treesitter_spec.lua | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/treesitter_spec.lua b/test/functional/lua/treesitter_spec.lua index 8916e59563..f3f7f4fd0a 100644 --- a/test/functional/lua/treesitter_spec.lua +++ b/test/functional/lua/treesitter_spec.lua @@ -8,6 +8,7 @@ local insert = helpers.insert local meth_pcall = helpers.meth_pcall local exec_lua = helpers.exec_lua local iswin = helpers.iswin +local feed = helpers.feed before_each(clear) @@ -46,12 +47,11 @@ describe('tree-sitter API', function() }]]) exec_lua([[ - parser = vim.treesitter.create_parser(0, "c") - tree = parser:parse_tree() + parser = vim.treesitter.get_parser(0, "c") + tree = parser:parse() root = tree:root() ]]) - --eq("", exec_lua("return tostring(parser)")) eq("", exec_lua("return tostring(tree)")) eq("", exec_lua("return tostring(root)")) eq({0,0,3,0}, exec_lua("return {root:range()}")) @@ -60,6 +60,27 @@ describe('tree-sitter API', function() exec_lua("child = root:child(0)") eq("", exec_lua("return tostring(child)")) eq({0,0,2,1}, exec_lua("return {child:range()}")) + + exec_lua("descendant = root:descendant_for_point_range(1,2,1,12)") + eq("", exec_lua("return tostring(descendant)")) + eq({1,2,1,12}, exec_lua("return {descendant:range()}")) + eq("(declaration (primitive_type) (init_declarator (identifier) (number_literal)))", exec_lua("return descendant:sexpr()")) + + feed("2G7|ay") + exec_lua([[ + tree2 = parser:parse() + root2 = tree2:root() + descendant2 = root2:descendant_for_point_range(1,2,1,13) + ]]) + eq(false, exec_lua("return tree2 == tree1")) + eq("", exec_lua("return tostring(descendant2)")) + eq({1,2,1,13}, exec_lua("return {descendant2:range()}")) + + -- orginal tree did not change + eq({1,2,1,12}, exec_lua("return {descendant:range()}")) + + -- unchanged buffer: return the same tree + eq(true, exec_lua("return parser:parse() == tree2")) end) end) -- cgit From 06ee45b9b1c14c7ce6cb23403cdbe2852d495cad Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Fri, 21 Jun 2019 14:14:51 +0200 Subject: tree-sitter: fix lint, delete "demo" plugin (replaced by functional tests) --- test/functional/lua/treesitter_spec.lua | 2 -- 1 file changed, 2 deletions(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/treesitter_spec.lua b/test/functional/lua/treesitter_spec.lua index f3f7f4fd0a..5aaaa80868 100644 --- a/test/functional/lua/treesitter_spec.lua +++ b/test/functional/lua/treesitter_spec.lua @@ -1,11 +1,9 @@ -- Test suite for testing interactions with API bindings local helpers = require('test.functional.helpers')(after_each) -local meths = helpers.meths local clear = helpers.clear local eq = helpers.eq local insert = helpers.insert -local meth_pcall = helpers.meth_pcall local exec_lua = helpers.exec_lua local iswin = helpers.iswin local feed = helpers.feed -- cgit From e0d6228978dd1389f75a3e0351f6e6d5625643ae Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Sat, 21 Sep 2019 10:10:47 +0200 Subject: tree-sitter: use "range" instead of "point_range" consistently in lua API --- test/functional/lua/treesitter_spec.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/treesitter_spec.lua b/test/functional/lua/treesitter_spec.lua index 5aaaa80868..d566f15649 100644 --- a/test/functional/lua/treesitter_spec.lua +++ b/test/functional/lua/treesitter_spec.lua @@ -59,7 +59,7 @@ describe('tree-sitter API', function() eq("", exec_lua("return tostring(child)")) eq({0,0,2,1}, exec_lua("return {child:range()}")) - exec_lua("descendant = root:descendant_for_point_range(1,2,1,12)") + exec_lua("descendant = root:descendant_for_range(1,2,1,12)") eq("", exec_lua("return tostring(descendant)")) eq({1,2,1,12}, exec_lua("return {descendant:range()}")) eq("(declaration (primitive_type) (init_declarator (identifier) (number_literal)))", exec_lua("return descendant:sexpr()")) @@ -68,7 +68,7 @@ describe('tree-sitter API', function() exec_lua([[ tree2 = parser:parse() root2 = tree2:root() - descendant2 = root2:descendant_for_point_range(1,2,1,13) + descendant2 = root2:descendant_for_range(1,2,1,13) ]]) eq(false, exec_lua("return tree2 == tree1")) eq("", exec_lua("return tostring(descendant2)")) -- cgit From d5a69eb07648a515d03aa5c9e268aef852015ea9 Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Sun, 22 Sep 2019 11:33:55 +0200 Subject: tree-sitter: handle node equality --- test/functional/lua/treesitter_spec.lua | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'test/functional/lua') diff --git a/test/functional/lua/treesitter_spec.lua b/test/functional/lua/treesitter_spec.lua index d566f15649..8e21faca12 100644 --- a/test/functional/lua/treesitter_spec.lua +++ b/test/functional/lua/treesitter_spec.lua @@ -64,6 +64,13 @@ describe('tree-sitter API', function() eq({1,2,1,12}, exec_lua("return {descendant:range()}")) eq("(declaration (primitive_type) (init_declarator (identifier) (number_literal)))", exec_lua("return descendant:sexpr()")) + eq(true, exec_lua("return child == child")) + -- separate lua object, but represents same node + eq(true, exec_lua("return child == root:child(0)")) + eq(false, exec_lua("return child == descendant2")) + eq(false, exec_lua("return child == nil")) + eq(false, exec_lua("return child == tree")) + feed("2G7|ay") exec_lua([[ tree2 = parser:parse() @@ -71,6 +78,7 @@ describe('tree-sitter API', function() descendant2 = root2:descendant_for_range(1,2,1,13) ]]) eq(false, exec_lua("return tree2 == tree1")) + eq(false, exec_lua("return root2 == root")) eq("", exec_lua("return tostring(descendant2)")) eq({1,2,1,13}, exec_lua("return {descendant2:range()}")) -- cgit From 9fa850991dbe8984996afdc149b5b32dc248197e Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Sat, 28 Sep 2019 09:32:55 +0200 Subject: tree-sitter: improve and cleanup tests --- test/functional/lua/treesitter_spec.lua | 73 +++++++++++++++++++++++++++++---- 1 file changed, 64 insertions(+), 9 deletions(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/treesitter_spec.lua b/test/functional/lua/treesitter_spec.lua index 8e21faca12..700e4599f2 100644 --- a/test/functional/lua/treesitter_spec.lua +++ b/test/functional/lua/treesitter_spec.lua @@ -7,34 +7,40 @@ local insert = helpers.insert local exec_lua = helpers.exec_lua local iswin = helpers.iswin local feed = helpers.feed +local pcall_err = helpers.pcall_err +local matches = helpers.matches before_each(clear) -describe('tree-sitter API', function() +describe('treesitter API', function() -- error tests not requiring a parser library - it('handles basic errors', function() - --eq({false, 'Error executing lua: vim.schedule: expected function'}, - -- meth_pcall(meths.execute_lua, "parser = vim.treesitter.create_parser(0, 'nosuchlang')", {})) + it('handles missing language', function() + local path_pat = 'Error executing lua: '..(iswin() and '.+\\vim\\' or '.+/vim/') + matches(path_pat..'treesitter.lua:39: no such language: borklang', + pcall_err(exec_lua, "parser = vim.treesitter.create_parser(0, 'borklang')")) + -- actual message depends on platform + matches('Error executing lua: Failed to load parser: uv_dlopen: .+', + pcall_err(exec_lua, "parser = vim.treesitter.add_language('borkbork.so', 'borklang')")) + eq('Error executing lua: [string ""]:1: no such language: borklang', + pcall_err(exec_lua, "parser = vim.treesitter.inspect_language('borklang')")) end) local ts_path = os.getenv("TREE_SITTER_DIR") describe('with C parser', function() if ts_path == nil then - it("works", function() pending("TREE_SITTER_PATH not set, skipping tree-sitter parser tests") end) + it("works", function() pending("TREE_SITTER_PATH not set, skipping treesitter parser tests") end) return end before_each(function() - -- TODO the .so/.dylib/.dll thingie local path = ts_path .. '/bin/c'..(iswin() and '.dll' or '.so') exec_lua([[ local path = ... vim.treesitter.add_language(path,'c') - ]], path) end) @@ -48,6 +54,7 @@ describe('tree-sitter API', function() parser = vim.treesitter.get_parser(0, "c") tree = parser:parse() root = tree:root() + lang = vim.treesitter.inspect_language('c') ]]) eq("", exec_lua("return tostring(tree)")) @@ -59,10 +66,21 @@ describe('tree-sitter API', function() eq("", exec_lua("return tostring(child)")) eq({0,0,2,1}, exec_lua("return {child:range()}")) + eq("function_definition", exec_lua("return child:type()")) + eq(true, exec_lua("return child:named()")) + eq("number", type(exec_lua("return child:symbol()"))) + eq({'function_definition', true}, exec_lua("return lang.symbols[child:symbol()]")) + + exec_lua("anon = root:descendant_for_range(0,8,0,9)") + eq("(", exec_lua("return anon:type()")) + eq(false, exec_lua("return anon:named()")) + eq("number", type(exec_lua("return anon:symbol()"))) + eq({'(', false}, exec_lua("return lang.symbols[anon:symbol()]")) + exec_lua("descendant = root:descendant_for_range(1,2,1,12)") eq("", exec_lua("return tostring(descendant)")) eq({1,2,1,12}, exec_lua("return {descendant:range()}")) - eq("(declaration (primitive_type) (init_declarator (identifier) (number_literal)))", exec_lua("return descendant:sexpr()")) + eq("(declaration type: (primitive_type) declarator: (init_declarator declarator: (identifier) value: (number_literal)))", exec_lua("return descendant:sexpr()")) eq(true, exec_lua("return child == child")) -- separate lua object, but represents same node @@ -89,6 +107,43 @@ describe('tree-sitter API', function() eq(true, exec_lua("return parser:parse() == tree2")) end) + it('inspects language', function() + local keys, fields, symbols = unpack(exec_lua([[ + local lang = vim.treesitter.inspect_language('c') + local keys, symbols = {}, {} + for k,_ in pairs(lang) do + keys[k] = true + end + + -- symbols array can have "holes" and is thus not a valid msgpack array + -- but we don't care about the numbers here (checked in the parser test) + for _, v in pairs(lang.symbols) do + table.insert(symbols, v) + end + return {keys, lang.fields, symbols} + ]])) + + eq({fields=true, symbols=true}, keys) + + local fset = {} + for _,f in pairs(fields) do + eq("string", type(f)) + fset[f] = true + end + eq(true, fset["directive"]) + eq(true, fset["initializer"]) + + local has_named, has_anonymous + for _,s in pairs(symbols) do + eq("string", type(s[1])) + eq("boolean", type(s[2])) + if s[1] == "for_statement" and s[2] == true then + has_named = true + elseif s[1] == "|=" and s[2] == false then + has_anonymous = true + end + end + eq({true,true}, {has_named,has_anonymous}) + end) end) end) - -- cgit From 996a057fb9b4b7d791adad19f07b2f9c53a88ab5 Mon Sep 17 00:00:00 2001 From: Hirokazu Hata Date: Mon, 21 Oct 2019 23:46:28 +0900 Subject: lua/stdlib: adjust some validation messages #11271 close #11271 --- test/functional/lua/utility_functions_spec.lua | 42 +++++++++++++++++--------- 1 file changed, 27 insertions(+), 15 deletions(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/utility_functions_spec.lua b/test/functional/lua/utility_functions_spec.lua index ea2b1fc8a9..dfcbcf06eb 100644 --- a/test/functional/lua/utility_functions_spec.lua +++ b/test/functional/lua/utility_functions_spec.lua @@ -9,6 +9,8 @@ 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 iswin = helpers.iswin before_each(clear) @@ -147,11 +149,8 @@ describe('lua stdlib', function() eq({"yy","xx"}, exec_lua("return test_table")) -- type checked 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()")) + 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() @@ -195,8 +194,8 @@ describe('lua stdlib', function() end) it("vim.split", function() - local split = function(str, sep) - return exec_lua('return vim.split(...)', str, sep) + local split = function(str, sep, plain) + return exec_lua('return vim.split(...)', str, sep, plain) end local tests = { @@ -221,10 +220,15 @@ describe('lua stdlib', function() } for _, t in ipairs(loops) do - local status, err = pcall(split, t[1], t[2]) - eq(false, status) - assert(string.match(err, "Infinite loop detected")) + matches(".*Infinite loop detected", pcall_err(split, t[1], t[2])) end + + -- type checked args + eq(true, pcall(split, 'string', 'string', nil)) + local path_pattern = iswin() and '[a-zA-Z]:[^:]+:%d+:' or '[^:]+:%d+:' + matches("Error executing lua: "..path_pattern.." Expected string, got number", pcall_err(split, 1, 'string', nil)) + matches("Error executing lua: "..path_pattern.." Expected string, got number", pcall_err(split, 'string', 1, nil)) + matches("Error executing lua: "..path_pattern.." Expected boolean or nil, got number", pcall_err(split, 'string', 'string', 1)) end) it('vim.trim', function() @@ -243,9 +247,9 @@ describe('lua stdlib', function() assert(t[2], trim(t[1])) end - local status, err = pcall(trim, 2) - eq(false, status) - assert(string.match(err, "Only strings can be trimmed")) + -- type checked args + local path_pattern = iswin() and '[a-zA-Z]:[^:]+:%d+:' or '[^:]+:%d+:' + matches("Error executing lua: "..path_pattern.." Expected string, got number", pcall_err(trim, 2)) end) it('vim.inspect', function() @@ -285,7 +289,15 @@ describe('lua stdlib', function() 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'))]])) + local pesc = function(s) + return exec_lua('return vim.pesc(...)', s) + end + + eq('foo%-bar', pesc('foo-bar')) + eq('foo%%%-bar', pesc(pesc('foo-bar'))) + + -- type checked args + local path_pattern = iswin() and '[a-zA-Z]:[^:]+:%d+:' or '[^:]+:%d+:' + matches("Error executing lua: "..path_pattern.." Expected string, got number", pcall_err(pesc, 2)) end) end) -- cgit From 316c29bbf36d3d36c459b7c955d921b29ca659d0 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sat, 26 Oct 2019 01:30:58 -0700 Subject: test/pcall_err(): truncate full paths, omit linenr ref #11271 --- test/functional/lua/treesitter_spec.lua | 4 +-- test/functional/lua/utility_functions_spec.lua | 41 +++++++++++++------------- 2 files changed, 21 insertions(+), 24 deletions(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/treesitter_spec.lua b/test/functional/lua/treesitter_spec.lua index 700e4599f2..5a53ca1425 100644 --- a/test/functional/lua/treesitter_spec.lua +++ b/test/functional/lua/treesitter_spec.lua @@ -15,9 +15,7 @@ before_each(clear) describe('treesitter API', function() -- error tests not requiring a parser library it('handles missing language', function() - local path_pat = 'Error executing lua: '..(iswin() and '.+\\vim\\' or '.+/vim/') - - matches(path_pat..'treesitter.lua:39: no such language: borklang', + eq('Error executing lua: .../treesitter.lua: no such language: borklang', pcall_err(exec_lua, "parser = vim.treesitter.create_parser(0, 'borklang')")) -- actual message depends on platform diff --git a/test/functional/lua/utility_functions_spec.lua b/test/functional/lua/utility_functions_spec.lua index dfcbcf06eb..a51334398c 100644 --- a/test/functional/lua/utility_functions_spec.lua +++ b/test/functional/lua/utility_functions_spec.lua @@ -10,7 +10,6 @@ local feed = helpers.feed local pcall_err = helpers.pcall_err local exec_lua = helpers.exec_lua local matches = helpers.matches -local iswin = helpers.iswin before_each(clear) @@ -148,9 +147,11 @@ describe('lua stdlib', function() ]]) eq({"yy","xx"}, exec_lua("return test_table")) - -- type checked 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()")) + -- 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() @@ -223,12 +224,14 @@ describe('lua stdlib', function() matches(".*Infinite loop detected", pcall_err(split, t[1], t[2])) end - -- type checked args + -- Validates args. eq(true, pcall(split, 'string', 'string', nil)) - local path_pattern = iswin() and '[a-zA-Z]:[^:]+:%d+:' or '[^:]+:%d+:' - matches("Error executing lua: "..path_pattern.." Expected string, got number", pcall_err(split, 1, 'string', nil)) - matches("Error executing lua: "..path_pattern.." Expected string, got number", pcall_err(split, 'string', 1, nil)) - matches("Error executing lua: "..path_pattern.." Expected boolean or nil, got number", pcall_err(split, 'string', 'string', 1)) + 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() @@ -247,9 +250,9 @@ describe('lua stdlib', function() assert(t[2], trim(t[1])) end - -- type checked args - local path_pattern = iswin() and '[a-zA-Z]:[^:]+:%d+:' or '[^:]+:%d+:' - matches("Error executing lua: "..path_pattern.." Expected string, got number", pcall_err(trim, 2)) + -- Validates args. + eq('Error executing lua: .../shared.lua: Expected string, got number', + pcall_err(trim, 2)) end) it('vim.inspect', function() @@ -289,15 +292,11 @@ describe('lua stdlib', function() end) it('vim.pesc', function() - local pesc = function(s) - return exec_lua('return vim.pesc(...)', s) - end - - eq('foo%-bar', pesc('foo-bar')) - eq('foo%%%-bar', pesc(pesc('foo-bar'))) + eq('foo%-bar', exec_lua([[return vim.pesc('foo-bar')]])) + eq('foo%%%-bar', exec_lua([[return vim.pesc(vim.pesc('foo-bar'))]])) - -- type checked args - local path_pattern = iswin() and '[a-zA-Z]:[^:]+:%d+:' or '[^:]+:%d+:' - matches("Error executing lua: "..path_pattern.." Expected string, got number", pcall_err(pesc, 2)) + -- Validates args. + eq("Error executing lua: .../shared.lua: Expected string, got number", + pcall_err(exec_lua, [[return vim.pesc(2)]])) end) end) -- cgit From 8ee7c94a92598d46b488b7fe3b1a5cff6b1bf94a Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Sun, 25 Aug 2019 22:01:35 +0200 Subject: lua: add vim.fn.{func} for direct access to vimL function compared to vim.api.|nvim_call_function|, this fixes some typing issues due to the indirect conversion via the API. float values are preserved as such (fixes #9389) as well as empty dicts/arrays. Ref https://github.com/norcalli/nvim.lua for the call syntax --- test/functional/lua/utility_functions_spec.lua | 28 ++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) (limited to 'test/functional/lua') diff --git a/test/functional/lua/utility_functions_spec.lua b/test/functional/lua/utility_functions_spec.lua index a51334398c..0b789e84b0 100644 --- a/test/functional/lua/utility_functions_spec.lua +++ b/test/functional/lua/utility_functions_spec.lua @@ -10,6 +10,7 @@ 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) @@ -299,4 +300,31 @@ describe('lua stdlib', function() eq("Error executing lua: .../shared.lua: Expected string, got number", pcall_err(exec_lua, [[return vim.pesc(2)]])) end) + + it('vim.call and 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) -- cgit From 9ef16a1628722958b6e14fe9274006e50ed6682d Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sun, 27 Oct 2019 15:05:59 -0700 Subject: doc: vim.fn, vim.call(), vim.api [ci skip] --- test/functional/lua/utility_functions_spec.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/utility_functions_spec.lua b/test/functional/lua/utility_functions_spec.lua index 0b789e84b0..6aeea5fc4f 100644 --- a/test/functional/lua/utility_functions_spec.lua +++ b/test/functional/lua/utility_functions_spec.lua @@ -301,7 +301,7 @@ describe('lua stdlib', function() pcall_err(exec_lua, [[return vim.pesc(2)]])) end) - it('vim.call and vim.fn', function() + 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 -- cgit From 474d0bcbf724c7eed740f60391a0ed35d651e1d3 Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Sun, 27 Oct 2019 20:49:03 +0100 Subject: lua: vim.rpcrequest, vim.rpcnotify, vim.NIL --- test/functional/lua/utility_functions_spec.lua | 72 ++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) (limited to 'test/functional/lua') diff --git a/test/functional/lua/utility_functions_spec.lua b/test/functional/lua/utility_functions_spec.lua index 6aeea5fc4f..6631aa8e4c 100644 --- a/test/functional/lua/utility_functions_spec.lua +++ b/test/functional/lua/utility_functions_spec.lua @@ -3,6 +3,8 @@ 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 @@ -11,6 +13,7 @@ local pcall_err = helpers.pcall_err local exec_lua = helpers.exec_lua local matches = helpers.matches local source = helpers.source +local NIL = helpers.NIL before_each(clear) @@ -315,6 +318,9 @@ describe('lua stdlib', function() 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")) @@ -324,7 +330,73 @@ describe('lua stdlib', function() 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() + ]])) + eq('foo', meths.get_current_line()) + + 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 ""]:6: E5560: rpcrequest must not be}| + {3: called in a lua loop callback} | + {4:Press ENTER or type command to continue}^ | + ]]} + feed('') + eq({3, NIL}, meths.get_var('yy')) + end) end) -- cgit From d200a818a71bba0f2b3d4f7f173b4d799eb3c7f0 Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Sun, 10 Nov 2019 17:12:41 +0100 Subject: tests: vim.rpcnotify test is flaky --- test/functional/lua/utility_functions_spec.lua | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/utility_functions_spec.lua b/test/functional/lua/utility_functions_spec.lua index 6631aa8e4c..7dc97ee5af 100644 --- a/test/functional/lua/utility_functions_spec.lua +++ b/test/functional/lua/utility_functions_spec.lua @@ -14,6 +14,7 @@ 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) @@ -368,7 +369,9 @@ describe('lua stdlib', function() vim.rpcnotify(chan, 'nvim_set_current_line', 'foo') return vim.api.nvim_get_current_line() ]])) - eq('foo', meths.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({ -- cgit From 678a51b1da0c0535299341e7a598c080adcf8553 Mon Sep 17 00:00:00 2001 From: Hirokazu Hata Date: Mon, 28 Oct 2019 20:52:18 +0900 Subject: Lua: vim.validate() We often want to do type checking of public function arguments. - test: Rename utility_function_spec.lua to vim_spec.lua - .luacov: Map lua module names --- test/functional/lua/utility_functions_spec.lua | 405 ---------------------- test/functional/lua/vim_spec.lua | 458 +++++++++++++++++++++++++ 2 files changed, 458 insertions(+), 405 deletions(-) delete mode 100644 test/functional/lua/utility_functions_spec.lua create mode 100644 test/functional/lua/vim_spec.lua (limited to 'test/functional/lua') diff --git a/test/functional/lua/utility_functions_spec.lua b/test/functional/lua/utility_functions_spec.lua deleted file mode 100644 index 7dc97ee5af..0000000000 --- a/test/functional/lua/utility_functions_spec.lua +++ /dev/null @@ -1,405 +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 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.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("") - eq('Error executing vim.schedule lua callback: [string ""]: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 ""]}| - {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 - 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 ""]:6: E5560: rpcrequest must not be}| - {3: called in a lua loop callback} | - {4:Press ENTER or type command to continue}^ | - ]]} - feed('') - eq({3, NIL}, meths.get_var('yy')) - end) -end) diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua new file mode 100644 index 0000000000..cb1f027623 --- /dev/null +++ b/test/functional/lua/vim_spec.lua @@ -0,0 +1,458 @@ +-- 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.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("") + eq('Error executing vim.schedule lua callback: [string ""]: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 ""]}| + {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 + 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 ""]:6: E5560: rpcrequest must not be}| + {3: called in a lua loop callback} | + {4:Press ENTER or type command to continue}^ | + ]]} + feed('') + eq({3, NIL}, meths.get_var('yy')) + end) + + it('vim.validate', function() + eq(NIL, exec_lua("vim.validate({ arg1={ {}, 'table' }})")) + eq(NIL, exec_lua("vim.validate({ arg1={ {}, 't' }})")) + eq(NIL, exec_lua("vim.validate({ arg1={ nil, 't', true }})")) + eq(NIL, exec_lua("vim.validate({ arg1={ { foo='foo' }, 't' }})")) + eq(NIL, exec_lua("vim.validate({ arg1={ { 'foo' }, 't' }})")) + eq(NIL, exec_lua("vim.validate({ arg1={ 'foo', 'string' }})")) + eq(NIL, exec_lua("vim.validate({ arg1={ 'foo', 's' }})")) + eq(NIL, exec_lua("vim.validate({ arg1={ '', 's' }})")) + eq(NIL, exec_lua("vim.validate({ arg1={ nil, 's', true }})")) + eq(NIL, exec_lua("vim.validate({ arg1={ 1, 'number' }})")) + eq(NIL, exec_lua("vim.validate({ arg1={ 1, 'n' }})")) + eq(NIL, exec_lua("vim.validate({ arg1={ 0, 'n' }})")) + eq(NIL, exec_lua("vim.validate({ arg1={ 0.1, 'n' }})")) + eq(NIL, exec_lua("vim.validate({ arg1={ nil, 'n', true }})")) + eq(NIL, exec_lua("vim.validate({ arg1={ true, 'boolean' }})")) + eq(NIL, exec_lua("vim.validate({ arg1={ true, 'b' }})")) + eq(NIL, exec_lua("vim.validate({ arg1={ false, 'b' }})")) + eq(NIL, exec_lua("vim.validate({ arg1={ nil, 'b', true }})")) + eq(NIL, exec_lua("vim.validate({ arg1={ function()end, 'function' }})")) + eq(NIL, exec_lua("vim.validate({ arg1={ function()end, 'f' }})")) + eq(NIL, exec_lua("vim.validate({ arg1={ nil, 'f', true }})")) + eq(NIL, exec_lua("vim.validate({ arg1={ nil, 'nil' }})")) + eq(NIL, exec_lua("vim.validate({ arg1={ nil, 'nil', true }})")) + eq(NIL, exec_lua("vim.validate({ arg1={ coroutine.create(function()end), 'thread' }})")) + eq(NIL, exec_lua("vim.validate({ arg1={ nil, 'thread', true }})")) + eq(NIL, exec_lua("vim.validate({ arg1={ {}, 't' } }, { arg2={ 'foo', 's' }})")) + eq(NIL, exec_lua("vim.validate({ arg1={ {}, 't' }, arg2={ 'foo', 's' }})")) + eq(NIL, exec_lua("vim.validate({ arg1={ 2, function(a) return (a % 2) == 0 end, 'even number' }})")) + + 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' }})")) + 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) +end) -- cgit From 7aa4042d3bddf2f39d048b9ba1dd7adf2193d4eb Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sun, 10 Nov 2019 19:58:14 -0800 Subject: Lua: vim.validate() --- test/functional/lua/vim_spec.lua | 81 +++++++++++++++++++++++----------------- 1 file changed, 47 insertions(+), 34 deletions(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index cb1f027623..a9c52bfcd9 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -404,40 +404,53 @@ describe('lua stdlib', function() end) it('vim.validate', function() - eq(NIL, exec_lua("vim.validate({ arg1={ {}, 'table' }})")) - eq(NIL, exec_lua("vim.validate({ arg1={ {}, 't' }})")) - eq(NIL, exec_lua("vim.validate({ arg1={ nil, 't', true }})")) - eq(NIL, exec_lua("vim.validate({ arg1={ { foo='foo' }, 't' }})")) - eq(NIL, exec_lua("vim.validate({ arg1={ { 'foo' }, 't' }})")) - eq(NIL, exec_lua("vim.validate({ arg1={ 'foo', 'string' }})")) - eq(NIL, exec_lua("vim.validate({ arg1={ 'foo', 's' }})")) - eq(NIL, exec_lua("vim.validate({ arg1={ '', 's' }})")) - eq(NIL, exec_lua("vim.validate({ arg1={ nil, 's', true }})")) - eq(NIL, exec_lua("vim.validate({ arg1={ 1, 'number' }})")) - eq(NIL, exec_lua("vim.validate({ arg1={ 1, 'n' }})")) - eq(NIL, exec_lua("vim.validate({ arg1={ 0, 'n' }})")) - eq(NIL, exec_lua("vim.validate({ arg1={ 0.1, 'n' }})")) - eq(NIL, exec_lua("vim.validate({ arg1={ nil, 'n', true }})")) - eq(NIL, exec_lua("vim.validate({ arg1={ true, 'boolean' }})")) - eq(NIL, exec_lua("vim.validate({ arg1={ true, 'b' }})")) - eq(NIL, exec_lua("vim.validate({ arg1={ false, 'b' }})")) - eq(NIL, exec_lua("vim.validate({ arg1={ nil, 'b', true }})")) - eq(NIL, exec_lua("vim.validate({ arg1={ function()end, 'function' }})")) - eq(NIL, exec_lua("vim.validate({ arg1={ function()end, 'f' }})")) - eq(NIL, exec_lua("vim.validate({ arg1={ nil, 'f', true }})")) - eq(NIL, exec_lua("vim.validate({ arg1={ nil, 'nil' }})")) - eq(NIL, exec_lua("vim.validate({ arg1={ nil, 'nil', true }})")) - eq(NIL, exec_lua("vim.validate({ arg1={ coroutine.create(function()end), 'thread' }})")) - eq(NIL, exec_lua("vim.validate({ arg1={ nil, 'thread', true }})")) - eq(NIL, exec_lua("vim.validate({ arg1={ {}, 't' } }, { arg2={ 'foo', 's' }})")) - eq(NIL, exec_lua("vim.validate({ arg1={ {}, 't' }, arg2={ 'foo', 's' }})")) - eq(NIL, exec_lua("vim.validate({ arg1={ 2, function(a) return (a % 2) == 0 end, 'even number' }})")) - - 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' }})")) + 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 }}")) + + 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'}}")) end) it('vim.is_callable', function() -- cgit From a0d992785feeefaea2810dcf08564fd8bea8cab9 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sun, 10 Nov 2019 22:18:59 -0800 Subject: Lua: Use vim.validate() instead of assert() --- test/functional/lua/vim_spec.lua | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index a9c52bfcd9..a25ae1d2c0 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -230,12 +230,12 @@ describe('lua stdlib', function() 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', + 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) @@ -256,7 +256,7 @@ describe('lua stdlib', function() end -- Validates args. - eq('Error executing lua: .../shared.lua: Expected string, got number', + eq('Error executing lua: .../shared.lua: s: expected string, got number', pcall_err(trim, 2)) end) @@ -301,7 +301,7 @@ describe('lua stdlib', function() eq('foo%%%-bar', exec_lua([[return vim.pesc(vim.pesc('foo-bar'))]])) -- Validates args. - eq("Error executing lua: .../shared.lua: Expected string, got number", + eq('Error executing lua: .../shared.lua: s: expected string, got number', pcall_err(exec_lua, [[return vim.pesc(2)]])) end) @@ -441,16 +441,25 @@ describe('lua stdlib', function() 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'}}")) + 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'}}")) + 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() -- cgit From 00dc12c5d8454a2d3c6806710f63bbb446076e96 Mon Sep 17 00:00:00 2001 From: Ashkan Kiani Date: Wed, 13 Nov 2019 12:55:26 -0800 Subject: lua LSP client: initial implementation (#11336) Mainly configuration and RPC infrastructure can be considered "done". Specific requests and their callbacks will be improved later (and also served by plugins). There are also some TODO:s for the client itself, like incremental updates. Co-authored by at-tjdevries and at-h-michael, with many review/suggestion contributions. --- test/functional/lua/uri_spec.lua | 107 +++++++++++++++++++++++++++++++++++++++ test/functional/lua/vim_spec.lua | 72 ++++++++++++++++++++++++++ 2 files changed, 179 insertions(+) create mode 100644 test/functional/lua/uri_spec.lua (limited to 'test/functional/lua') 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/vim_spec.lua b/test/functional/lua/vim_spec.lua index a25ae1d2c0..028f2dcd52 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -305,6 +305,78 @@ describe('lua stdlib', function() 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 must be a table', + 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 ]]) + 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 ]])) -- cgit From dab40f43b18d35b283804ecb033310198cbf7548 Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Wed, 30 Oct 2019 20:53:09 +0100 Subject: Add v:lua.func() vimL syntax for calling lua Also simplify error messages when calling lua from vimL. --- test/functional/lua/api_spec.lua | 30 +++++------ test/functional/lua/commands_spec.lua | 99 +++++++++++++++++----------------- test/functional/lua/luaeval_spec.lua | 96 ++++++++++++++++++++++++++++++--- test/functional/lua/overrides_spec.lua | 27 +++++----- 4 files changed, 169 insertions(+), 83 deletions(-) (limited to 'test/functional/lua') 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 ""]: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 ""]: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 ""]: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 ""]: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 ""]: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 ""]: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 ""]: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 ""]: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 ""]: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 ""]: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 ""]: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 ""]: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 ""]: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 ""]: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 ""]: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 ""]:1: unexpected symbol near ')']], - exc_exec('lua ()')) - eq([[Vim(lua):E5105: Error while calling lua chunk: [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 ""]: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 ""]:1: unfinished string near \'\'', 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 \'\'', 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")') - screen:expect([[ - | - {1:~ }| - {1:~ }| - {1:~ }| - {2: }| - {3:E5105: Error while calling lua chunk: [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('') - screen:expect([[ - ^ | - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - | - ]]) - eq('E5105: Error while calling lua chunk: [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 ""]: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') - screen:expect([[ - | - {1:~ }| - {1:~ }| - {1:~ }| - {2: }| - {3:E5105: Error while calling lua chunk: [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 ""]: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 ""]: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 ""]:1: unfinished string near \'\'', redir_exec(('luado return "%s'):format(s))) + eq('\nE5109: Error loading lua: [string ":luado"]:1: unfinished string near \'\'', 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 ""]: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 ""]: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 ""]: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 \"\"]: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 \"\"]: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') + 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..8c260632d9 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: ', + eq('\nE5108: Error executing lua E5114: Error while converting print argument #2: ', 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('') - 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 ""]: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(':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 ""]: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() -- cgit From b984f613c1e8dadbe59bf0d7093a6ed12af61b37 Mon Sep 17 00:00:00 2001 From: Ashkan Kiani Date: Wed, 20 Nov 2019 17:09:21 -0800 Subject: Extend list_extend to take start/finish. --- test/functional/lua/vim_spec.lua | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index 028f2dcd52..c8a4c1364f 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -353,10 +353,14 @@ describe('lua stdlib', function() 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 must be a table', + 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() -- cgit From d0d38fc36e0c1602186aa540417070fa6c1e2746 Mon Sep 17 00:00:00 2001 From: Ashkan Kiani Date: Sun, 24 Nov 2019 02:28:48 -0800 Subject: Lua: vim.env, vim.{g,v,w,bo,wo} #11442 - Add vim variable meta accessors: vim.env, vim.{g,v,w,bo,wo} - Redo gen_char_blob to generate multiple blobs instead of just one so that multiple Lua modules can be inlined. - Reorder vim.lua inclusion so that it can use previously defined C functions and utility functions like vim.shared and vim.inspect things. - Inline shared.lua into nvim, but also keep it available in runtime. --- test/functional/lua/vim_spec.lua | 57 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) (limited to 'test/functional/lua') diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index 028f2dcd52..446bbafc3c 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -549,4 +549,61 @@ describe('lua stdlib', function() 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(NIL, funcs.luaeval "vim.env.B") + 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") + end) + + it('vim.wo', function() + eq('', funcs.luaeval "vim.bo.filetype") + exec_lua [[ + vim.api.nvim_win_set_option(0, "cole", 2) + BUF = vim.api.nvim_create_buf(false, true) + vim.api.nvim_buf_set_option(BUF, "modifiable", false) + ]] + eq(2, funcs.luaeval "vim.wo.cole") + exec_lua [[ + vim.wo.conceallevel = 0 + vim.bo(BUF).modifiable = true + ]] + eq(0, funcs.luaeval "vim.wo.cole") + end) end) -- cgit From a76a669ac24ec91144153b65e0a0dc5598802653 Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Tue, 26 Nov 2019 17:57:53 +0100 Subject: lua: make vim.wo and vim.bo used nested indexing for specified handle Also missing option should be an error. Options are functionality, not arbitrary variable names (as for vim.g) --- test/functional/lua/vim_spec.lua | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index ebe394f164..720a33d430 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -587,13 +587,17 @@ describe('lua stdlib', function() ]] eq(false, funcs.luaeval "vim.bo.modified") eq('markdown', funcs.luaeval "vim.bo.filetype") - eq(false, funcs.luaeval "vim.bo(BUF).modifiable") + eq(false, funcs.luaeval "vim.bo[BUF].modifiable") exec_lua [[ vim.bo.filetype = '' - vim.bo(BUF).modifiable = true + vim.bo[BUF].modifiable = true ]] eq('', funcs.luaeval "vim.bo.filetype") - eq(true, funcs.luaeval "vim.bo(BUF).modifiable") + 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() @@ -606,8 +610,12 @@ describe('lua stdlib', function() eq(2, funcs.luaeval "vim.wo.cole") exec_lua [[ vim.wo.conceallevel = 0 - vim.bo(BUF).modifiable = true + vim.bo[BUF].modifiable = true ]] eq(0, funcs.luaeval "vim.wo.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')) end) end) -- cgit From edca84cfc91e637e97fcadd484a57911b20cfe75 Mon Sep 17 00:00:00 2001 From: Ashkan Kiani Date: Sun, 1 Dec 2019 05:04:57 -0800 Subject: Return nil instead of NIL for vim.env (#11486) --- test/functional/lua/vim_spec.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index 720a33d430..877d14f7e7 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -569,7 +569,7 @@ describe('lua stdlib', function() vim.fn.setenv("A", 123) ]] eq('123', funcs.luaeval "vim.env.A") - eq(NIL, funcs.luaeval "vim.env.B") + eq(true, funcs.luaeval "vim.env.B == nil") end) it('vim.v', function() -- cgit From e6da21d12895e2f34c6ce41bb16400d5eef3ea12 Mon Sep 17 00:00:00 2001 From: Ashkan Kiani Date: Sun, 1 Dec 2019 05:28:53 -0800 Subject: Add vim.cmd as an alias for nvim_command (#11446) --- test/functional/lua/vim_spec.lua | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'test/functional/lua') diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index 877d14f7e7..45818d2a99 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -618,4 +618,13 @@ describe('lua stdlib', function() matches("^Error executing lua: .*: Expected lua string$", pcall_err(exec_lua, 'return vim.wo[0][0].list')) end) + + it('vim.cmd', function() + exec_lua [[ + vim.cmd "autocmd BufNew * ++once lua BUF = vim.fn.expand('')" + vim.cmd "new" + ]] + eq('2', funcs.luaeval "BUF") + eq(2, funcs.luaeval "#vim.api.nvim_list_bufs()") + end) end) -- cgit From 70b606166640d043fc7b78a52b89ff1bba798b6a Mon Sep 17 00:00:00 2001 From: Ashkan Kiani Date: Sun, 1 Dec 2019 05:32:55 -0800 Subject: Add vim.startswith and vim.endswith (#11248) --- test/functional/lua/vim_spec.lua | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) (limited to 'test/functional/lua') diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index 45818d2a99..22c975147f 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -117,6 +117,34 @@ describe('lua stdlib', function() 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} -- cgit From a3b6c2a3dc5576db45fe4e893cfb8482af591c92 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Mon, 2 Dec 2019 00:46:46 -0800 Subject: API: rename nvim_execute_lua => nvim_exec_lua - We already find ourselves renaming nvim_execute_lua in tests and scripts, which suggests "exec" is the verb we actually want. - Add "exec" verb to `:help dev-api`. --- test/functional/lua/overrides_spec.lua | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/overrides_spec.lua b/test/functional/lua/overrides_spec.lua index 8c260632d9..1bccc02847 100644 --- a/test/functional/lua/overrides_spec.lua +++ b/test/functional/lua/overrides_spec.lua @@ -299,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() -- cgit From 0e6c6261e1b5a518995f53ca3898a68b9bb02012 Mon Sep 17 00:00:00 2001 From: Ashkan Kiani Date: Sat, 7 Dec 2019 03:34:02 -0800 Subject: Fix access on vim.wo (#11517) * Add more tests for vim.wo --- test/functional/lua/vim_spec.lua | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index 22c975147f..17ffcd8d86 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -629,22 +629,27 @@ describe('lua stdlib', function() end) it('vim.wo', function() - eq('', funcs.luaeval "vim.bo.filetype") exec_lua [[ vim.api.nvim_win_set_option(0, "cole", 2) - BUF = vim.api.nvim_create_buf(false, true) - vim.api.nvim_buf_set_option(BUF, "modifiable", false) + 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 - vim.bo[BUF].modifiable = true ]] 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() -- cgit