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 From 440695c29696f261337227e5c419aa1cf313c2dd Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Sat, 28 Sep 2019 14:27:20 +0200 Subject: tree-sitter: implement query functionality and highlighting prototype [skip.lint] --- test/functional/lua/treesitter_spec.lua | 476 ++++++++++++++++++++++++-------- 1 file changed, 363 insertions(+), 113 deletions(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/treesitter_spec.lua b/test/functional/lua/treesitter_spec.lua index 5a53ca1425..76e9899d34 100644 --- a/test/functional/lua/treesitter_spec.lua +++ b/test/functional/lua/treesitter_spec.lua @@ -1,5 +1,6 @@ -- Test suite for testing interactions with API bindings local helpers = require('test.functional.helpers')(after_each) +local Screen = require('test.functional.ui.screen') local clear = helpers.clear local eq = helpers.eq @@ -26,122 +27,371 @@ describe('treesitter API', function() pcall_err(exec_lua, "parser = vim.treesitter.inspect_language('borklang')")) end) +end) + +describe('treesitter API with C parser', function() 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 treesitter parser tests") end) - return - end - - before_each(function() - 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.get_parser(0, "c") - tree = parser:parse() - root = tree:root() - lang = vim.treesitter.inspect_language('c') - ]]) - - 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()}")) - - 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 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 - 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() - root2 = tree2:root() - 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()}")) - - -- 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) - - 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 + -- The tests after this requires an actual parser + if ts_path == nil then + it("works", function() pending("TREE_SITTER_PATH not set, skipping treesitter parser tests") end) + return + end + + before_each(function() + 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.get_parser(0, "c") + tree = parser:parse() + root = tree:root() + lang = vim.treesitter.inspect_language('c') + ]]) + + 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()}")) + + 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 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 + 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() + root2 = tree2:root() + 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()}")) + + -- 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) + + local test_text = [[ +void ui_refresh(void) +{ + int width = INT_MAX, height = INT_MAX; + bool ext_widgets[kUIExtCount]; + for (UIExtension i = 0; (int)i < kUIExtCount; i++) { + ext_widgets[i] = true; + } + + bool inclusive = ui_override(); + for (size_t i = 0; i < ui_count; i++) { + UI *ui = uis[i]; + width = MIN(ui->width, width); + height = MIN(ui->height, height); + foo = BAR(ui->bazaar, bazaar); + for (UIExtension j = 0; (int)j < kUIExtCount; j++) { + ext_widgets[j] &= (ui->ui_ext[j] || inclusive); + } + } +}]] + + local query = [[ + ((call_expression function: (identifier) @minfunc (argument_list (identifier) @min_id)) (eq? @minfunc "MIN")) + "for" @keyword + (primitive_type) @type + (field_expression argument: (identifier) @fieldarg) + ]] + + it('support query and iter by capture', function() + insert(test_text) + + local res = exec_lua([[ + cquery = vim.treesitter.parse_query("c", ...) + parser = vim.treesitter.get_parser(0, "c") + tree = parser:parse() + res = {} + for cid, node in cquery:iter_captures(tree:root(), 0, 7, 14) do + -- can't transmit node over RPC. just check the name and range + table.insert(res, {cquery.captures[cid], node:type(), node:range()}) + end + return res + ]], query) + + eq({ + { "type", "primitive_type", 8, 2, 8, 6 }, + { "keyword", "for", 9, 2, 9, 5 }, + { "type", "primitive_type", 9, 7, 9, 13 }, + { "minfunc", "identifier", 11, 12, 11, 15 }, + { "fieldarg", "identifier", 11, 16, 11, 18 }, + { "min_id", "identifier", 11, 27, 11, 32 }, + { "minfunc", "identifier", 12, 13, 12, 16 }, + { "fieldarg", "identifier", 12, 17, 12, 19 }, + { "min_id", "identifier", 12, 29, 12, 35 }, + { "fieldarg", "identifier", 13, 14, 13, 16 } + }, res) + end) + + it('support query and iter by match', function() + insert(test_text) + + local res = exec_lua([[ + cquery = vim.treesitter.parse_query("c", ...) + parser = vim.treesitter.get_parser(0, "c") + tree = parser:parse() + res = {} + for pattern, match in cquery:iter_matches(tree:root(), 0, 7, 14) do + -- can't transmit node over RPC. just check the name and range + local mrepr = {} + for cid,node in pairs(match) do + table.insert(mrepr, {cquery.captures[cid], node:type(), node:range()}) 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 + table.insert(res, {pattern, mrepr}) + end + return res + ]], query) + + eq({ + { 3, { { "type", "primitive_type", 8, 2, 8, 6 } } }, + { 2, { { "keyword", "for", 9, 2, 9, 5 } } }, + { 3, { { "type", "primitive_type", 9, 7, 9, 13 } } }, + { 4, { { "fieldarg", "identifier", 11, 16, 11, 18 } } }, + { 1, { { "minfunc", "identifier", 11, 12, 11, 15 }, { "min_id", "identifier", 11, 27, 11, 32 } } }, + { 4, { { "fieldarg", "identifier", 12, 17, 12, 19 } } }, + { 1, { { "minfunc", "identifier", 12, 13, 12, 16 }, { "min_id", "identifier", 12, 29, 12, 35 } } }, + { 4, { { "fieldarg", "identifier", 13, 14, 13, 16 } } } + }, res) + end) + + it('supports highlighting', function() + local hl_text = [[ +/// Schedule Lua callback on main loop's event queue +static int nlua_schedule(lua_State *const lstate) +{ + if (lua_type(lstate, 1) != LUA_TFUNCTION + || lstate != lstate) { + lua_pushliteral(lstate, "vim.schedule: expected function"); + return lua_error(lstate); + } + + LuaRef cb = nlua_ref(lstate, 1); + + multiqueue_put(main_loop.events, nlua_schedule_event, + 1, (void *)(ptrdiff_t)cb); + return 0; +}]] + + local hl_query = [[ +(ERROR) @ErrorMsg + +"if" @keyword +"else" @keyword +"for" @keyword +"return" @keyword + +"const" @type +"static" @type +"struct" @type +"enum" @type +"extern" @type + +(string_literal) @string + +(number_literal) @number +(char_literal) @string + +; TODO(bfredl): overlapping matches are unreliable, +; we need a proper priority mechanism +;(type_identifier) @type +((type_identifier) @Special (eq? @Special "LuaRef")) + +(primitive_type) @type +(sized_type_specifier) @type + +((binary_expression left: (identifier) @WarningMsg.left right: (identifier) @WarningMsg.right) (eq? @WarningMsg.left @WarningMsg.right)) + +(comment) @comment +]] + + local screen = Screen.new(65, 18) + screen:attach() + screen:set_default_attr_ids({ + [1] = {bold = true, foreground = Screen.colors.Blue1}, + [2] = {foreground = Screen.colors.Blue1}, + [3] = {bold = true, foreground = Screen.colors.SeaGreen4}, + [4] = {bold = true, foreground = Screen.colors.Brown}, + [5] = {foreground = Screen.colors.Magenta}, + [6] = {foreground = Screen.colors.Red}, + [7] = {foreground = Screen.colors.SlateBlue}, + [8] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red}, + [9] = {foreground = Screen.colors.Magenta, background = Screen.colors.Red}, + [10] = {foreground = Screen.colors.Red, background = Screen.colors.Red}, + + }) + + insert(hl_text) + screen:expect{grid=[[ + /// Schedule Lua callback on main loop's event queue | + static int nlua_schedule(lua_State *const lstate) | + { | + if (lua_type(lstate, 1) != LUA_TFUNCTION | + || lstate != lstate) { | + lua_pushliteral(lstate, "vim.schedule: expected function"); | + return lua_error(lstate); | + } | + | + LuaRef cb = nlua_ref(lstate, 1); | + | + multiqueue_put(main_loop.events, nlua_schedule_event, | + 1, (void *)(ptrdiff_t)cb); | + return 0; | + ^} | + {1:~ }| + {1:~ }| + | + ]]} + + exec_lua([[ + local TSHighlighter = vim.treesitter.TSHighlighter + local query = ... + test_hl = TSHighlighter.new(query, 0, "c") + ]], hl_query) + screen:expect{grid=[[ + {2:/// Schedule Lua callback on main loop's event queue} | + {3:static} {3:int} nlua_schedule(lua_State *{3:const} lstate) | + { | + {4:if} (lua_type(lstate, {5:1}) != LUA_TFUNCTION | + || {6:lstate} != {6:lstate}) { | + lua_pushliteral(lstate, {5:"vim.schedule: expected function"}); | + {4:return} lua_error(lstate); | + } | + | + {7:LuaRef} cb = nlua_ref(lstate, {5:1}); | + | + multiqueue_put(main_loop.events, nlua_schedule_event, | + {5:1}, ({3:void} *)(ptrdiff_t)cb); | + {4:return} {5:0}; | + ^} | + {1:~ }| + {1:~ }| + | + ]]} + + feed('7Go*/') + screen:expect{grid=[[ + {2:/// Schedule Lua callback on main loop's event queue} | + {3:static} {3:int} nlua_schedule(lua_State *{3:const} lstate) | + { | + {4:if} (lua_type(lstate, {5:1}) != LUA_TFUNCTION | + || {6:lstate} != {6:lstate}) { | + lua_pushliteral(lstate, {5:"vim.schedule: expected function"}); | + {4:return} lua_error(lstate); | + {8:*^/} | + } | + | + {7:LuaRef} cb = nlua_ref(lstate, {5:1}); | + | + multiqueue_put(main_loop.events, nlua_schedule_event, | + {5:1}, ({3:void} *)(ptrdiff_t)cb); | + {4:return} {5:0}; | + } | + {1:~ }| + | + ]]} + + feed('3Go/*') + screen:expect{grid=[[ + {2:/// Schedule Lua callback on main loop's event queue} | + {3:static} {3:int} nlua_schedule(lua_State *{3:const} lstate) | + { | + {2:/^*} | + {2: if (lua_type(lstate, 1) != LUA_TFUNCTION} | + {2: || lstate != lstate) {} | + {2: lua_pushliteral(lstate, "vim.schedule: expected function");} | + {2: return lua_error(lstate);} | + {2:*/} | + } | + | + {7:LuaRef} cb = nlua_ref(lstate, {5:1}); | + | + multiqueue_put(main_loop.events, nlua_schedule_event, | + {5:1}, ({3:void} *)(ptrdiff_t)cb); | + {4:return} {5:0}; | + {8:}} | + | + ]]} + 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 - eq({true,true}, {has_named,has_anonymous}) - end) + end + eq({true,true}, {has_named,has_anonymous}) end) end) -- cgit From ea4127e9a7a624484f51c21e17f37c766da15da0 Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Wed, 27 Nov 2019 20:45:41 +0100 Subject: lua: metatable for empty dict value --- test/functional/lua/vim_spec.lua | 44 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 2 deletions(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index 17ffcd8d86..e879f8b925 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -354,7 +354,8 @@ describe('lua stdlib', function() end) it('vim.tbl_islist', function() - eq(NIL, exec_lua("return vim.tbl_islist({})")) + eq(true, exec_lua("return vim.tbl_islist({})")) + eq(false, exec_lua("return vim.tbl_islist(vim.empty_dict())")) 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'})")) @@ -458,6 +459,19 @@ describe('lua stdlib', function() ]])) eq({3, 'aa', true, NIL}, exec_lua([[return ret]])) + eq({{}, {}, false, true}, exec_lua([[ + vim.rpcrequest(chan, 'nvim_exec', 'let xx = {}\nlet yy = []', false) + local dict = vim.rpcrequest(chan, 'nvim_eval', 'xx') + local list = vim.rpcrequest(chan, 'nvim_eval', 'yy') + return {dict, list, vim.tbl_islist(dict), vim.tbl_islist(list)} + ]])) + + exec_lua([[ + vim.rpcrequest(chan, 'nvim_set_var', 'aa', {}) + vim.rpcrequest(chan, 'nvim_set_var', 'bb', vim.empty_dict()) + ]]) + eq({1, 1}, eval('[type(g:aa) == type([]), type(g:bb) == type({})]')) + -- error handling eq({false, 'Invalid channel: 23'}, exec_lua([[return {pcall(vim.rpcrequest, 23, 'foo')}]])) @@ -486,7 +500,7 @@ describe('lua stdlib', function() }) screen:attach() exec_lua([[ - local timer = vim.loop.new_timer() + 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}) @@ -505,6 +519,32 @@ describe('lua stdlib', function() ]]} feed('') eq({3, NIL}, meths.get_var('yy')) + + exec_lua([[timer:close()]]) + end) + + it('vim.empty_dict()', function() + eq({true, false, true, true}, exec_lua([[ + vim.api.nvim_set_var('listy', {}) + vim.api.nvim_set_var('dicty', vim.empty_dict()) + local listy = vim.fn.eval("listy") + local dicty = vim.fn.eval("dicty") + return {vim.tbl_islist(listy), vim.tbl_islist(dicty), next(listy) == nil, next(dicty) == nil} + ]])) + + -- vim.empty_dict() gives new value each time + -- equality is not overriden (still by ref) + -- non-empty table uses the usual heuristics (ignores the tag) + eq({false, {"foo"}, {namey="bar"}}, exec_lua([[ + local aa = vim.empty_dict() + local bb = vim.empty_dict() + local equally = (aa == bb) + aa[1] = "foo" + bb["namey"] = "bar" + return {equally, aa, bb} + ]])) + + eq("{ {}, vim.empty_dict() }", exec_lua("return vim.inspect({{}, vim.empty_dict()})")) end) it('vim.validate', function() -- cgit From 3d1531aee5d92375b69098de8f8c788ea407b066 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Tue, 14 Jan 2020 09:21:10 +0100 Subject: API: include invalid buffer/window/tabpage in error message (#11712) --- test/functional/lua/api_spec.lua | 2 +- test/functional/lua/commands_spec.lua | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/api_spec.lua b/test/functional/lua/api_spec.lua index 23167d3ed9..896554f7a3 100644 --- a/test/functional/lua/api_spec.lua +++ b/test/functional/lua/api_spec.lua @@ -39,7 +39,7 @@ describe('luaeval(vim.api.…)', function() eq({false, 'Argument "pos" must be a [row, col] array'}, funcs.luaeval('{pcall(vim.api.nvim_win_set_cursor, 0, {1, 2, 3})}')) -- Used to produce a memory leak due to a bug in nvim_win_set_cursor - eq({false, 'Invalid window id'}, + eq({false, 'Invalid window id: -1'}, funcs.luaeval('{pcall(vim.api.nvim_win_set_cursor, -1, {1, 2, 3})}')) end) diff --git a/test/functional/lua/commands_spec.lua b/test/functional/lua/commands_spec.lua index 96eaa7991b..cbc3aee557 100644 --- a/test/functional/lua/commands_spec.lua +++ b/test/functional/lua/commands_spec.lua @@ -47,7 +47,7 @@ describe(':lua command', function() pcall_err(command, 'lua ()')) eq([[Vim(lua):E5108: Error executing lua [string ":lua"]:1: TEST]], exc_exec('lua error("TEST")')) - eq([[Vim(lua):E5108: Error executing lua [string ":lua"]:1: Invalid buffer id]], + eq([[Vim(lua):E5108: Error executing lua [string ":lua"]:1: Invalid buffer id: -10]], exc_exec('lua vim.api.nvim_buf_set_lines(-10, 1, 1, false, {"TEST"})')) eq({''}, curbufmeths.get_lines(0, 100, false)) end) -- cgit From 2538e615130c7f4baa1029d0be2bc2d7f66cdd7e Mon Sep 17 00:00:00 2001 From: Axel Forsman Date: Thu, 30 Jan 2020 07:34:34 +0100 Subject: Fix shift change callbacks reading bad cursor (#11782) Sloppy code inherited from Vim caused user scripts to be able to observe the cursor line in an invalid intermediary state, due to Neovim change callbacks being unbuffered unlike Vim listeners. Manifested in Vimscript executed from the callback possibly erroring when `:call`:ing any function, due to the implicit range `curwin->w_cursor.lnum,curwin->w_cursor.lnum` failing validation. Fixed by deferring the call to `changed_lines()` until after `curwin->w_cursor.lnum` gets its correct value. --- test/functional/lua/buffer_updates_spec.lua | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'test/functional/lua') diff --git a/test/functional/lua/buffer_updates_spec.lua b/test/functional/lua/buffer_updates_spec.lua index 990cb97fec..7d3ecbf912 100644 --- a/test/functional/lua/buffer_updates_spec.lua +++ b/test/functional/lua/buffer_updates_spec.lua @@ -203,4 +203,17 @@ describe('lua: buffer event callbacks', function() { "test1", "lines", 1, tick+1, 5, 6, 5, 27, 20, 20 }}, exec_lua("return get_events(...)" )) end) + it('has valid cursor position while shifting', function() + meths.buf_set_lines(0, 0, -1, true, {'line1'}) + exec_lua([[ + vim.api.nvim_buf_attach(0, false, { + on_lines = function() + vim.api.nvim_set_var('listener_cursor_line', vim.api.nvim_win_get_cursor(0)[1]) + end, + }) + ]]) + feed('>>') + eq(1, meths.get_var('listener_cursor_line')) + end) + end) -- cgit From 14a8b3b98c245087ef431070195f3a2fa3db16c0 Mon Sep 17 00:00:00 2001 From: Hye Sung Jung Date: Fri, 31 Jan 2020 00:56:34 -0600 Subject: doc: fix typos [ci skip] #11787 --- test/functional/lua/buffer_updates_spec.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/buffer_updates_spec.lua b/test/functional/lua/buffer_updates_spec.lua index 7d3ecbf912..77f8189bb9 100644 --- a/test/functional/lua/buffer_updates_spec.lua +++ b/test/functional/lua/buffer_updates_spec.lua @@ -98,7 +98,7 @@ describe('lua: buffer event callbacks', function() command('undo') -- plugins can opt in to receive changedtick events, or choose - -- to only recieve actual changes. + -- to only receive actual changes. check_events({{ "test1", "lines", 1, tick, 3, 4, 5, 13 }, { "test2", "lines", 1, tick, 3, 4, 5, 13 }, { "test2", "changedtick", 1, tick+1 } }) @@ -111,7 +111,7 @@ describe('lua: buffer event callbacks', function() tick = tick + 1 -- plugins can opt in to receive changedtick events, or choose - -- to only recieve actual changes. + -- to only receive actual changes. check_events({{ "test1", "lines", 1, tick, 6, 7, 9, 16 }, { "test2", "lines", 1, tick, 6, 7, 9, 16 }}) -- cgit From 00c57c98dfb2df58875a3d9ad8fc557ec9a24cba Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Sat, 25 Jan 2020 13:43:41 +0100 Subject: treesitter: add standard &rtp/parser/ search path for parsers --- test/functional/lua/treesitter_spec.lua | 107 +++++++++++++++++--------------- 1 file changed, 56 insertions(+), 51 deletions(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/treesitter_spec.lua b/test/functional/lua/treesitter_spec.lua index 76e9899d34..494d6c84bb 100644 --- a/test/functional/lua/treesitter_spec.lua +++ b/test/functional/lua/treesitter_spec.lua @@ -6,7 +6,6 @@ local clear = helpers.clear local eq = helpers.eq 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 @@ -16,37 +15,35 @@ before_each(clear) describe('treesitter API', function() -- error tests not requiring a parser library it('handles missing language', function() - eq('Error executing lua: .../treesitter.lua: no such language: borklang', + eq("Error executing lua: .../treesitter.lua: no parser for 'borklang' language", 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')")) + matches("Error executing lua: Failed to load parser: uv_dlopen: .+", + pcall_err(exec_lua, "parser = vim.treesitter.require_language('borklang', 'borkbork.so')")) - eq('Error executing lua: [string ""]:1: no such language: borklang', + eq("Error executing lua: .../treesitter.lua: no parser for 'borklang' language", pcall_err(exec_lua, "parser = vim.treesitter.inspect_language('borklang')")) end) end) describe('treesitter API with C parser', function() - local ts_path = os.getenv("TREE_SITTER_DIR") - - -- The tests after this requires an actual parser - if ts_path == nil then - it("works", function() pending("TREE_SITTER_PATH not set, skipping treesitter parser tests") end) - return + local function check_parser() + local status, msg = unpack(exec_lua([[ return {pcall(vim.treesitter.require_language, 'c')} ]])) + if not status then + if helpers.isCI() then + error("treesitter C parser not found, required on CI: " .. msg) + else + pending('no C parser, skipping') + end + end + return status end - before_each(function() - 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() + if not check_parser() then return end + insert([[ int main() { int x = 3; @@ -138,6 +135,8 @@ void ui_refresh(void) ]] it('support query and iter by capture', function() + if not check_parser() then return end + insert(test_text) local res = exec_lua([[ @@ -167,6 +166,8 @@ void ui_refresh(void) end) it('support query and iter by match', function() + if not check_parser() then return end + insert(test_text) local res = exec_lua([[ @@ -198,6 +199,8 @@ void ui_refresh(void) end) it('supports highlighting', function() + if not check_parser() then return end + local hl_text = [[ /// Schedule Lua callback on main loop's event queue static int nlua_schedule(lua_State *const lstate) @@ -357,41 +360,43 @@ static int nlua_schedule(lua_State *const lstate) 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 + if not check_parser() then return 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 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 - local fset = {} - for _,f in pairs(fields) do - eq("string", type(f)) - fset[f] = true + -- 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 - 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 + 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 - eq({true,true}, {has_named,has_anonymous}) + end + eq({true,true}, {has_named,has_anonymous}) end) end) -- cgit From 032ede02036cda1b0caebce46bc31ecf06a70dc2 Mon Sep 17 00:00:00 2001 From: Hirokazu Hata Date: Wed, 12 Feb 2020 20:51:15 +0900 Subject: test: add json_encode test for vim.empty_dict() --- test/functional/lua/vim_spec.lua | 2 ++ 1 file changed, 2 insertions(+) (limited to 'test/functional/lua') diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index e879f8b925..339fbd65a0 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -545,6 +545,8 @@ describe('lua stdlib', function() ]])) eq("{ {}, vim.empty_dict() }", exec_lua("return vim.inspect({{}, vim.empty_dict()})")) + eq('{}', exec_lua([[ return vim.fn.json_encode(vim.empty_dict()) ]])) + eq('{"a": {}, "b": []}', exec_lua([[ return vim.fn.json_encode({a=vim.empty_dict(), b={}}) ]])) end) it('vim.validate', function() -- cgit From 417fc6ccf78801aef79a8731c5a85db6b12cd407 Mon Sep 17 00:00:00 2001 From: Hirokazu Hata Date: Thu, 13 Feb 2020 11:55:43 +0900 Subject: lua: vim.deepcopy uses empty_dict() instead of {} for empty_dict() fix: https://github.com/neovim/nvim-lsp/issues/94 --- test/functional/lua/vim_spec.lua | 42 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) (limited to 'test/functional/lua') diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index e879f8b925..b8edd7b3e0 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -322,6 +322,48 @@ describe('lua stdlib', function() ]]) assert(is_dc) + + local is_empty_list = exec_lua([[ + local a = {} + local b = vim.deepcopy(a) + + local count = 0 + for _ in pairs(b) do count = count + 1 end + + return getmetatable(b) ~= vim._empty_dict_mt + and count == 0 + and tostring(a) ~= tostring(b) + ]]) + + assert(is_empty_list) + + local is_empty_dic = exec_lua([[ + local a = vim.empty_dict() + local b = vim.deepcopy(a) + + local count = 0 + for _ in pairs(b) do count = count + 1 end + + return getmetatable(b) == vim._empty_dict_mt + and count == 0 + ]]) + + assert(is_empty_dic) + + local include_empty_dic = exec_lua([[ + local a = {x = vim.empty_dict(), y = {}} + local b = vim.deepcopy(a) + + local count = 0 + for _ in pairs(b) do count = count + 1 end + + return getmetatable(b.x) == vim._empty_dict_mt + and getmetatable(b.y) ~= vim._empty_dict_mt + and count == 2 + and tostring(a) ~= tostring(b) + ]]) + + assert(include_empty_dic) end) it('vim.pesc', function() -- cgit From cdb729b7462cfef28a0264cb75bffe69182c5275 Mon Sep 17 00:00:00 2001 From: Hirokazu Hata Date: Fri, 14 Feb 2020 19:40:02 +0900 Subject: lua: add vim.tbl_extend and vim.deepcopy test --- test/functional/lua/vim_spec.lua | 122 +++++++++++++++++++++++++++++++-------- 1 file changed, 99 insertions(+), 23 deletions(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index b8edd7b3e0..f549ca2bd1 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -7,6 +7,7 @@ local meths = helpers.meths local command = helpers.command local clear = helpers.clear local eq = helpers.eq +local ok = helpers.ok local eval = helpers.eval local feed = helpers.feed local pcall_err = helpers.pcall_err @@ -310,7 +311,7 @@ describe('lua stdlib', function() end) it("vim.deepcopy", function() - local is_dc = exec_lua([[ + ok(exec_lua([[ local a = { x = { 1, 2 }, y = 5} local b = vim.deepcopy(a) @@ -319,51 +320,39 @@ describe('lua stdlib', function() 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) + ]])) - local is_empty_list = exec_lua([[ + ok(exec_lua([[ local a = {} local b = vim.deepcopy(a) local count = 0 for _ in pairs(b) do count = count + 1 end - return getmetatable(b) ~= vim._empty_dict_mt - and count == 0 - and tostring(a) ~= tostring(b) - ]]) - - assert(is_empty_list) + return vim.tbl_islist(b) and count == 0 and tostring(a) ~= tostring(b) + ]])) - local is_empty_dic = exec_lua([[ + ok(exec_lua([[ local a = vim.empty_dict() local b = vim.deepcopy(a) local count = 0 for _ in pairs(b) do count = count + 1 end - return getmetatable(b) == vim._empty_dict_mt - and count == 0 - ]]) - - assert(is_empty_dic) + return not vim.tbl_islist(b) and count == 0 + ]])) - local include_empty_dic = exec_lua([[ + ok(exec_lua([[ local a = {x = vim.empty_dict(), y = {}} local b = vim.deepcopy(a) local count = 0 for _ in pairs(b) do count = count + 1 end - return getmetatable(b.x) == vim._empty_dict_mt - and getmetatable(b.y) ~= vim._empty_dict_mt + return not vim.tbl_islist(b.x) and vim.tbl_islist(b.y) and count == 2 and tostring(a) ~= tostring(b) - ]]) - - assert(include_empty_dic) + ]])) end) it('vim.pesc', function() @@ -411,6 +400,93 @@ describe('lua stdlib', function() eq(false, exec_lua("return vim.tbl_isempty({a=1, b=2, c=3})")) end) + it('vim.tbl_extend', function() + ok(exec_lua([[ + local a = {x = 1} + local b = {y = 2} + local c = vim.tbl_extend("keep", a, b) + + local count = 0 + for _ in pairs(c) do count = count + 1 end + + return c.x == 1 and b.y == 2 and count == 2 + ]])) + + ok(exec_lua([[ + local a = {x = 1} + local b = {y = 2} + local c = {z = 3} + local d = vim.tbl_extend("keep", a, b, c) + + local count = 0 + for _ in pairs(d) do count = count + 1 end + + return d.x == 1 and d.y == 2 and d.z == 3 and count == 3 + ]])) + + ok(exec_lua([[ + local a = {x = 1} + local b = {x = 3} + local c = vim.tbl_extend("keep", a, b) + + local count = 0 + for _ in pairs(c) do count = count + 1 end + + return c.x == 1 and count == 1 + ]])) + + ok(exec_lua([[ + local a = {x = 1} + local b = {x = 3} + local c = vim.tbl_extend("force", a, b) + + local count = 0 + for _ in pairs(c) do count = count + 1 end + + return c.x == 3 and count == 1 + ]])) + + ok(exec_lua([[ + local a = vim.empty_dict() + local b = {} + local c = vim.tbl_extend("keep", a, b) + + local count = 0 + for _ in pairs(c) do count = count + 1 end + + return not vim.tbl_islist(c) and count == 0 + ]])) + + ok(exec_lua([[ + local a = {} + local b = vim.empty_dict() + local c = vim.tbl_extend("keep", a, b) + + local count = 0 + for _ in pairs(c) do count = count + 1 end + + return vim.tbl_islist(c) and count == 0 + ]])) + + eq('Error executing lua: .../shared.lua: invalid "behavior": nil', + pcall_err(exec_lua, [[ + return vim.tbl_extend() + ]]) + ) + + eq('Error executing lua: .../shared.lua: wrong number of arguments (given 1, expected at least 3)', + pcall_err(exec_lua, [[ + return vim.tbl_extend("keep") + ]]) + ) + + eq('Error executing lua: .../shared.lua: wrong number of arguments (given 2, expected at least 3)', + pcall_err(exec_lua, [[ + return vim.tbl_extend("keep", {}) + ]]) + ) + 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}}) ]]) -- cgit From e2ed8053bf722d4d111fac7dcdb07179fdea8752 Mon Sep 17 00:00:00 2001 From: Hirokazu Hata Date: Tue, 18 Feb 2020 17:41:29 +0900 Subject: lua: move test helper function, map and filter, to vim.shared module --- test/functional/lua/vim_spec.lua | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'test/functional/lua') diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index ca7c5301ed..2f459145f5 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -384,6 +384,30 @@ describe('lua stdlib', function() end end) + it('vim.tbl_map', function() + eq({}, exec_lua([[ + return vim.tbl_map(function(v) return v * 2 end, {}) + ]])) + eq({2, 4, 6}, exec_lua([[ + return vim.tbl_map(function(v) return v * 2 end, {1, 2, 3}) + ]])) + eq({{i=2}, {i=4}, {i=6}}, exec_lua([[ + return vim.tbl_map(function(v) return { i = v.i * 2 } end, {{i=1}, {i=2}, {i=3}}) + ]])) + end) + + it('vim.tbl_filter', function() + eq({}, exec_lua([[ + return vim.tbl_filter(function(v) return (v % 2) == 0 end, {}) + ]])) + eq({2}, exec_lua([[ + return vim.tbl_filter(function(v) return (v % 2) == 0 end, {1, 2, 3}) + ]])) + eq({{i=2}}, exec_lua([[ + return vim.tbl_filter(function(v) return (v.i % 2) == 0 end, {{i=1}, {i=2}, {i=3}}) + ]])) + end) + it('vim.tbl_islist', function() eq(true, exec_lua("return vim.tbl_islist({})")) eq(false, exec_lua("return vim.tbl_islist(vim.empty_dict())")) -- cgit From 9c00fea585ccab56a6044a174ce8d9a2c605c6cd Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Mon, 4 Nov 2019 20:40:30 +0100 Subject: lua: add regex support, and `@match` support in treesitter queries --- test/functional/lua/treesitter_spec.lua | 19 ++++++++++++------- test/functional/lua/vim_spec.lua | 18 ++++++++++++++++++ 2 files changed, 30 insertions(+), 7 deletions(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/treesitter_spec.lua b/test/functional/lua/treesitter_spec.lua index 494d6c84bb..f93185d1f6 100644 --- a/test/functional/lua/treesitter_spec.lua +++ b/test/functional/lua/treesitter_spec.lua @@ -245,6 +245,11 @@ static int nlua_schedule(lua_State *const lstate) (primitive_type) @type (sized_type_specifier) @type +; defaults to very magic syntax, for best compatibility +((identifier) @Identifier (match? @Identifier "^l(u)a_")) +; still support \M etc prefixes +((identifier) @Constant (match? @Constant "\M^\[A-Z_]\+$")) + ((binary_expression left: (identifier) @WarningMsg.left right: (identifier) @WarningMsg.right) (eq? @WarningMsg.left @WarningMsg.right)) (comment) @comment @@ -263,7 +268,7 @@ static int nlua_schedule(lua_State *const lstate) [8] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red}, [9] = {foreground = Screen.colors.Magenta, background = Screen.colors.Red}, [10] = {foreground = Screen.colors.Red, background = Screen.colors.Red}, - + [11] = {foreground = Screen.colors.Cyan4}, }) insert(hl_text) @@ -297,10 +302,10 @@ static int nlua_schedule(lua_State *const lstate) {2:/// Schedule Lua callback on main loop's event queue} | {3:static} {3:int} nlua_schedule(lua_State *{3:const} lstate) | { | - {4:if} (lua_type(lstate, {5:1}) != LUA_TFUNCTION | + {4:if} ({11:lua_type}(lstate, {5:1}) != {5:LUA_TFUNCTION} | || {6:lstate} != {6:lstate}) { | - lua_pushliteral(lstate, {5:"vim.schedule: expected function"}); | - {4:return} lua_error(lstate); | + {11:lua_pushliteral}(lstate, {5:"vim.schedule: expected function"}); | + {4:return} {11:lua_error}(lstate); | } | | {7:LuaRef} cb = nlua_ref(lstate, {5:1}); | @@ -319,10 +324,10 @@ static int nlua_schedule(lua_State *const lstate) {2:/// Schedule Lua callback on main loop's event queue} | {3:static} {3:int} nlua_schedule(lua_State *{3:const} lstate) | { | - {4:if} (lua_type(lstate, {5:1}) != LUA_TFUNCTION | + {4:if} ({11:lua_type}(lstate, {5:1}) != {5:LUA_TFUNCTION} | || {6:lstate} != {6:lstate}) { | - lua_pushliteral(lstate, {5:"vim.schedule: expected function"}); | - {4:return} lua_error(lstate); | + {11:lua_pushliteral}(lstate, {5:"vim.schedule: expected function"}); | + {4:return} {11:lua_error}(lstate); | {8:*^/} | } | | diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index 2f459145f5..532368c37c 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -844,4 +844,22 @@ describe('lua stdlib', function() eq('2', funcs.luaeval "BUF") eq(2, funcs.luaeval "#vim.api.nvim_list_bufs()") end) + + it('vim.regex', function() + exec_lua [[ + re1 = vim.regex"ab\\+c" + vim.cmd "set nomagic ignorecase" + re2 = vim.regex"xYz" + ]] + eq({}, exec_lua[[return {re1:match_str("x ac")}]]) + eq({3,7}, exec_lua[[return {re1:match_str("ac abbc")}]]) + + meths.buf_set_lines(0, 0, -1, true, {"yy", "abc abbc"}) + eq({}, exec_lua[[return {re1:match_line(0, 0)}]]) + eq({0,3}, exec_lua[[return {re1:match_line(0, 1)}]]) + eq({3,7}, exec_lua[[return {re1:match_line(0, 1, 1)}]]) + eq({3,7}, exec_lua[[return {re1:match_line(0, 1, 1, 8)}]]) + eq({}, exec_lua[[return {re1:match_line(0, 1, 1, 7)}]]) + eq({0,3}, exec_lua[[return {re1:match_line(0, 1, 0, 7)}]]) + end) end) -- cgit From e35ff7371f4a61621587744a7620200380abbbe9 Mon Sep 17 00:00:00 2001 From: Hirokazu Hata Date: Mon, 2 Mar 2020 16:38:43 +0900 Subject: lua: add vim.tbl_len() #11889 --- test/functional/lua/vim_spec.lua | 63 +++++++++++++++------------------------- 1 file changed, 23 insertions(+), 40 deletions(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index 532368c37c..5ce4bf2973 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -315,10 +315,7 @@ describe('lua stdlib', function() 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 + return b.x[1] == 1 and b.x[2] == 2 and b.y == 5 and vim.tbl_count(b) == 2 and tostring(a) ~= tostring(b) ]])) @@ -326,31 +323,22 @@ describe('lua stdlib', function() local a = {} local b = vim.deepcopy(a) - local count = 0 - for _ in pairs(b) do count = count + 1 end - - return vim.tbl_islist(b) and count == 0 and tostring(a) ~= tostring(b) + return vim.tbl_islist(b) and vim.tbl_count(b) == 0 and tostring(a) ~= tostring(b) ]])) ok(exec_lua([[ local a = vim.empty_dict() local b = vim.deepcopy(a) - local count = 0 - for _ in pairs(b) do count = count + 1 end - - return not vim.tbl_islist(b) and count == 0 + return not vim.tbl_islist(b) and vim.tbl_count(b) == 0 ]])) ok(exec_lua([[ local a = {x = vim.empty_dict(), y = {}} local b = vim.deepcopy(a) - local count = 0 - for _ in pairs(b) do count = count + 1 end - return not vim.tbl_islist(b.x) and vim.tbl_islist(b.y) - and count == 2 + and vim.tbl_count(b) == 2 and tostring(a) ~= tostring(b) ]])) end) @@ -430,10 +418,7 @@ describe('lua stdlib', function() local b = {y = 2} local c = vim.tbl_extend("keep", a, b) - local count = 0 - for _ in pairs(c) do count = count + 1 end - - return c.x == 1 and b.y == 2 and count == 2 + return c.x == 1 and b.y == 2 and vim.tbl_count(c) == 2 ]])) ok(exec_lua([[ @@ -442,10 +427,7 @@ describe('lua stdlib', function() local c = {z = 3} local d = vim.tbl_extend("keep", a, b, c) - local count = 0 - for _ in pairs(d) do count = count + 1 end - - return d.x == 1 and d.y == 2 and d.z == 3 and count == 3 + return d.x == 1 and d.y == 2 and d.z == 3 and vim.tbl_count(d) == 3 ]])) ok(exec_lua([[ @@ -453,10 +435,7 @@ describe('lua stdlib', function() local b = {x = 3} local c = vim.tbl_extend("keep", a, b) - local count = 0 - for _ in pairs(c) do count = count + 1 end - - return c.x == 1 and count == 1 + return c.x == 1 and vim.tbl_count(c) == 1 ]])) ok(exec_lua([[ @@ -464,10 +443,7 @@ describe('lua stdlib', function() local b = {x = 3} local c = vim.tbl_extend("force", a, b) - local count = 0 - for _ in pairs(c) do count = count + 1 end - - return c.x == 3 and count == 1 + return c.x == 3 and vim.tbl_count(c) == 1 ]])) ok(exec_lua([[ @@ -475,10 +451,7 @@ describe('lua stdlib', function() local b = {} local c = vim.tbl_extend("keep", a, b) - local count = 0 - for _ in pairs(c) do count = count + 1 end - - return not vim.tbl_islist(c) and count == 0 + return not vim.tbl_islist(c) and vim.tbl_count(c) == 0 ]])) ok(exec_lua([[ @@ -486,10 +459,7 @@ describe('lua stdlib', function() local b = vim.empty_dict() local c = vim.tbl_extend("keep", a, b) - local count = 0 - for _ in pairs(c) do count = count + 1 end - - return vim.tbl_islist(c) and count == 0 + return vim.tbl_islist(c) and vim.tbl_count(c) == 0 ]])) eq('Error executing lua: .../shared.lua: invalid "behavior": nil', @@ -511,6 +481,19 @@ describe('lua stdlib', function() ) end) + it('vim.tbl_count', function() + eq(0, exec_lua [[ return vim.tbl_count({}) ]]) + eq(0, exec_lua [[ return vim.tbl_count(vim.empty_dict()) ]]) + eq(0, exec_lua [[ return vim.tbl_count({nil}) ]]) + eq(0, exec_lua [[ return vim.tbl_count({a=nil}) ]]) + eq(1, exec_lua [[ return vim.tbl_count({1}) ]]) + eq(2, exec_lua [[ return vim.tbl_count({1, 2}) ]]) + eq(2, exec_lua [[ return vim.tbl_count({1, nil, 3}) ]]) + eq(1, exec_lua [[ return vim.tbl_count({a=1}) ]]) + eq(2, exec_lua [[ return vim.tbl_count({a=1, b=2}) ]]) + eq(2, exec_lua [[ return vim.tbl_count({a=1, b=nil, 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}}) ]]) -- cgit From 4139678f97ee556ab142031a1ed5c7580278b64f Mon Sep 17 00:00:00 2001 From: Hirokazu Hata Date: Mon, 30 Mar 2020 21:30:24 +0900 Subject: vim.uri: fix uri_to_fname (#12059) fix: #12056 If the colon of the drive letter of windows is URI encoded, it doesn't match the expected pattern, so decode it first. --- test/functional/lua/uri_spec.lua | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'test/functional/lua') diff --git a/test/functional/lua/uri_spec.lua b/test/functional/lua/uri_spec.lua index 19b1eb1f61..128c7c6137 100644 --- a/test/functional/lua/uri_spec.lua +++ b/test/functional/lua/uri_spec.lua @@ -85,6 +85,15 @@ describe('URI methods', function() eq('C:\\Foo\\Bar\\Baz.txt', exec_lua(test_case)) end) + it('file path includes only ascii charactors with encoded colon character', function() + local test_case = [[ + local uri = 'file:///C%3A/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' -- cgit From bf0f74586153dfa8d550e1cfefd83ca9e0354171 Mon Sep 17 00:00:00 2001 From: Tristan Konolige Date: Sat, 18 Apr 2020 17:04:37 -0600 Subject: lua: allow deepcopy of functions (#12136) --- test/functional/lua/vim_spec.lua | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'test/functional/lua') diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index 5ce4bf2973..ca74d185cd 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -341,6 +341,22 @@ describe('lua stdlib', function() and vim.tbl_count(b) == 2 and tostring(a) ~= tostring(b) ]])) + + ok(exec_lua([[ + local f1 = function() return 1 end + local f2 = function() return 2 end + local t1 = {f = f1} + local t2 = vim.deepcopy(t1) + t1.f = f2 + return t1.f() ~= t2.f() + ]])) + + eq('Error executing lua: .../shared.lua: Cannot deepcopy object of type thread', + pcall_err(exec_lua, [[ + local thread = coroutine.create(function () return 0 end) + local t = {thr = thread} + vim.deepcopy(t) + ]])) end) it('vim.pesc', function() -- cgit From 2c40a38b39a944a3e1a90302c1061b4e6e3ba6ac Mon Sep 17 00:00:00 2001 From: Mathias Fußenegger Date: Tue, 5 May 2020 05:06:40 +0200 Subject: LSP: Avoid URI-to-fname conversion for non-file URIs #12243 Fixes https://github.com/neovim/neovim/issues/12210 --- test/functional/lua/uri_spec.lua | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'test/functional/lua') diff --git a/test/functional/lua/uri_spec.lua b/test/functional/lua/uri_spec.lua index 128c7c6137..a3b8e685e1 100644 --- a/test/functional/lua/uri_spec.lua +++ b/test/functional/lua/uri_spec.lua @@ -113,4 +113,15 @@ describe('URI methods', function() end) end) end) + + describe('uri to bufnr', function() + it('uri_to_bufnr & uri_from_bufnr returns original uri for non-file uris', function() + local uri = 'jdt://contents/java.base/java.util/List.class?=sql/%5C/home%5C/user%5C/.jabba%5C/jdk%5C/openjdk%5C@1.14.0%5C/lib%5C/jrt-fs.jar%60java.base=/javadoc_location=/https:%5C/%5C/docs.oracle.com%5C/en%5C/java%5C/javase%5C/14%5C/docs%5C/api%5C/=/%3Cjava.util(List.class' + local test_case = string.format([[ + local uri = '%s' + return vim.uri_from_bufnr(vim.uri_to_bufnr(uri)) + ]], uri) + eq(uri, exec_lua(test_case)) + end) + end) end) -- cgit From 1407899c32018f1988936adfddc1dede73c559cb Mon Sep 17 00:00:00 2001 From: TJ DeVries Date: Thu, 7 May 2020 15:22:24 -0400 Subject: lua: Add buffer, window and tab accessors (#12268) * Add buffer, window and tab accessors * Fix deletion and add tests --- test/functional/lua/vim_spec.lua | 86 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) (limited to 'test/functional/lua') diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index ca74d185cd..79d523b5c6 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -769,10 +769,96 @@ describe('lua stdlib', function() exec_lua [[ vim.api.nvim_set_var("testing", "hi") vim.api.nvim_set_var("other", 123) + vim.api.nvim_set_var("to_delete", {hello="world"}) ]] + eq('hi', funcs.luaeval "vim.g.testing") eq(123, funcs.luaeval "vim.g.other") eq(NIL, funcs.luaeval "vim.g.nonexistant") + + eq({hello="world"}, funcs.luaeval "vim.g.to_delete") + exec_lua [[ + vim.g.to_delete = nil + ]] + eq(NIL, funcs.luaeval "vim.g.to_delete") + end) + + it('vim.b', function() + exec_lua [[ + vim.api.nvim_buf_set_var(0, "testing", "hi") + vim.api.nvim_buf_set_var(0, "other", 123) + vim.api.nvim_buf_set_var(0, "to_delete", {hello="world"}) + ]] + + eq('hi', funcs.luaeval "vim.b.testing") + eq(123, funcs.luaeval "vim.b.other") + eq(NIL, funcs.luaeval "vim.b.nonexistant") + + eq({hello="world"}, funcs.luaeval "vim.b.to_delete") + exec_lua [[ + vim.b.to_delete = nil + ]] + eq(NIL, funcs.luaeval "vim.b.to_delete") + + exec_lua [[ + vim.cmd "vnew" + ]] + + eq(NIL, funcs.luaeval "vim.b.testing") + eq(NIL, funcs.luaeval "vim.b.other") + eq(NIL, funcs.luaeval "vim.b.nonexistant") + end) + + it('vim.w', function() + exec_lua [[ + vim.api.nvim_win_set_var(0, "testing", "hi") + vim.api.nvim_win_set_var(0, "other", 123) + vim.api.nvim_win_set_var(0, "to_delete", {hello="world"}) + ]] + + eq('hi', funcs.luaeval "vim.w.testing") + eq(123, funcs.luaeval "vim.w.other") + eq(NIL, funcs.luaeval "vim.w.nonexistant") + + eq({hello="world"}, funcs.luaeval "vim.w.to_delete") + exec_lua [[ + vim.w.to_delete = nil + ]] + eq(NIL, funcs.luaeval "vim.w.to_delete") + + exec_lua [[ + vim.cmd "vnew" + ]] + + eq(NIL, funcs.luaeval "vim.w.testing") + eq(NIL, funcs.luaeval "vim.w.other") + eq(NIL, funcs.luaeval "vim.w.nonexistant") + end) + + it('vim.t', function() + exec_lua [[ + vim.api.nvim_tabpage_set_var(0, "testing", "hi") + vim.api.nvim_tabpage_set_var(0, "other", 123) + vim.api.nvim_tabpage_set_var(0, "to_delete", {hello="world"}) + ]] + + eq('hi', funcs.luaeval "vim.t.testing") + eq(123, funcs.luaeval "vim.t.other") + eq(NIL, funcs.luaeval "vim.t.nonexistant") + + eq({hello="world"}, funcs.luaeval "vim.t.to_delete") + exec_lua [[ + vim.t.to_delete = nil + ]] + eq(NIL, funcs.luaeval "vim.t.to_delete") + + exec_lua [[ + vim.cmd "tabnew" + ]] + + eq(NIL, funcs.luaeval "vim.t.testing") + eq(NIL, funcs.luaeval "vim.t.other") + eq(NIL, funcs.luaeval "vim.t.nonexistant") end) it('vim.env', function() -- cgit From ae5bd0454ee4ed3bdbf22e953a216449ca34dd46 Mon Sep 17 00:00:00 2001 From: Hirokazu Hata Date: Mon, 18 May 2020 02:24:34 +0900 Subject: lua: add tbl_deep_extend (#11969) --- test/functional/lua/vim_spec.lua | 99 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) (limited to 'test/functional/lua') diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index 79d523b5c6..46ae56955b 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -478,6 +478,17 @@ describe('lua stdlib', function() return vim.tbl_islist(c) and vim.tbl_count(c) == 0 ]])) + ok(exec_lua([[ + local a = {x = {a = 1, b = 2}} + local b = {x = {a = 2, c = {y = 3}}} + local c = vim.tbl_extend("keep", a, b) + + local count = 0 + for _ in pairs(c) do count = count + 1 end + + return c.x.a == 1 and c.x.b == 2 and c.x.c == nil and count == 1 + ]])) + eq('Error executing lua: .../shared.lua: invalid "behavior": nil', pcall_err(exec_lua, [[ return vim.tbl_extend() @@ -497,6 +508,94 @@ describe('lua stdlib', function() ) end) + it('vim.tbl_deep_extend', function() + ok(exec_lua([[ + local a = {x = {a = 1, b = 2}} + local b = {x = {a = 2, c = {y = 3}}} + local c = vim.tbl_deep_extend("keep", a, b) + + local count = 0 + for _ in pairs(c) do count = count + 1 end + + return c.x.a == 1 and c.x.b == 2 and c.x.c.y == 3 and count == 1 + ]])) + + ok(exec_lua([[ + local a = {x = {a = 1, b = 2}} + local b = {x = {a = 2, c = {y = 3}}} + local c = vim.tbl_deep_extend("force", a, b) + + local count = 0 + for _ in pairs(c) do count = count + 1 end + + return c.x.a == 2 and c.x.b == 2 and c.x.c.y == 3 and count == 1 + ]])) + + ok(exec_lua([[ + local a = {x = {a = 1, b = 2}} + local b = {x = {a = 2, c = {y = 3}}} + local c = {x = {c = 4, d = {y = 4}}} + local d = vim.tbl_deep_extend("keep", a, b, c) + + local count = 0 + for _ in pairs(c) do count = count + 1 end + + return d.x.a == 1 and d.x.b == 2 and d.x.c.y == 3 and d.x.d.y == 4 and count == 1 + ]])) + + ok(exec_lua([[ + local a = {x = {a = 1, b = 2}} + local b = {x = {a = 2, c = {y = 3}}} + local c = {x = {c = 4, d = {y = 4}}} + local d = vim.tbl_deep_extend("force", a, b, c) + + local count = 0 + for _ in pairs(c) do count = count + 1 end + + return d.x.a == 2 and d.x.b == 2 and d.x.c == 4 and d.x.d.y == 4 and count == 1 + ]])) + + ok(exec_lua([[ + local a = vim.empty_dict() + local b = {} + local c = vim.tbl_deep_extend("keep", a, b) + + local count = 0 + for _ in pairs(c) do count = count + 1 end + + return not vim.tbl_islist(c) and count == 0 + ]])) + + ok(exec_lua([[ + local a = {} + local b = vim.empty_dict() + local c = vim.tbl_deep_extend("keep", a, b) + + local count = 0 + for _ in pairs(c) do count = count + 1 end + + return vim.tbl_islist(c) and count == 0 + ]])) + + eq('Error executing lua: .../shared.lua: invalid "behavior": nil', + pcall_err(exec_lua, [[ + return vim.tbl_deep_extend() + ]]) + ) + + eq('Error executing lua: .../shared.lua: wrong number of arguments (given 1, expected at least 3)', + pcall_err(exec_lua, [[ + return vim.tbl_deep_extend("keep") + ]]) + ) + + eq('Error executing lua: .../shared.lua: wrong number of arguments (given 2, expected at least 3)', + pcall_err(exec_lua, [[ + return vim.tbl_deep_extend("keep", {}) + ]]) + ) + end) + it('vim.tbl_count', function() eq(0, exec_lua [[ return vim.tbl_count({}) ]]) eq(0, exec_lua [[ return vim.tbl_count(vim.empty_dict()) ]]) -- cgit From f2894bffb024b712e69158d7914e9d9d3d495f72 Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Mon, 18 May 2020 15:49:50 +0200 Subject: lua: Add highlight.on_yank (#12279) * add lua function to highlight yanked region * extract namespace, better naming, default values * add default for event argument * free timer * factor out mark to position calculation * d'oh * make sure timer stops before callback (cf. luv example) * factor out timer, more documentation * fixup * validate function argument for schedule * fix block selection past eol * correct handling of multibyte characters * move arguments around, some cleanup * move utility functions to vim.lua * use anonymous namespaces, avoid local api * rename function * add test for schedule_fn * fix indent * turn hl-yank into proper (hightlight) module * factor out position-to-region function mark extraction now part of highlight.on_yank * rename schedule_fn to defer_fn * add test for vim.region * todo: handle double-width characters * remove debug printout * do not shadow arguments * defer also callable table * whitespace change * move highlight to vim/highlight.lua * add documentation * add @return documentation * test: add check before vim.defer fires * doc: fixup --- test/functional/lua/vim_spec.lua | 22 +++++++++++++++++++++- 1 file changed, 21 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 46ae56955b..2ea51e7b0b 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -1046,4 +1046,24 @@ describe('lua stdlib', function() eq({}, exec_lua[[return {re1:match_line(0, 1, 1, 7)}]]) eq({0,3}, exec_lua[[return {re1:match_line(0, 1, 0, 7)}]]) end) -end) + + it('vim.defer_fn', function() + exec_lua [[ + vim.g.test = 0 + vim.defer_fn(function() vim.g.test = 1 end, 10) + ]] + eq(0, exec_lua[[return vim.g.test]]) + exec_lua [[vim.cmd("sleep 10m")]] + eq(1, exec_lua[[return vim.g.test]]) + end) + + it('vim.region', function() + helpers.insert(helpers.dedent( [[ + text tααt tααt text + text tαxt txtα tex + text tαxt tαxt + ]])) + eq({5,15}, exec_lua[[ return vim.region(0,{1,5},{1,14},'v',true)[1] ]]) + end) + + end) -- cgit From eabf1803cd9432ff85f9b8310e8d6262eff93ec9 Mon Sep 17 00:00:00 2001 From: Hirokazu Hata Date: Tue, 19 May 2020 00:02:14 +0900 Subject: test: fix flaky vim.defer_fn test --- test/functional/lua/vim_spec.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index 2ea51e7b0b..c68c05dffa 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -1050,10 +1050,10 @@ describe('lua stdlib', function() it('vim.defer_fn', function() exec_lua [[ vim.g.test = 0 - vim.defer_fn(function() vim.g.test = 1 end, 10) + vim.defer_fn(function() vim.g.test = 1 end, 50) ]] eq(0, exec_lua[[return vim.g.test]]) - exec_lua [[vim.cmd("sleep 10m")]] + exec_lua [[vim.cmd("sleep 1000m")]] eq(1, exec_lua[[return vim.g.test]]) end) -- cgit From 04a0486c66e2ae6d67cad990f95283863dbe28fd Mon Sep 17 00:00:00 2001 From: Mathias Fußenegger Date: Thu, 21 May 2020 18:17:21 +0200 Subject: Change uri_to_fname to not convert non-file URIs (#12351) * Change uri_to_fname to not convert non-file URIs A URI with a scheme other than file doesn't have a local file path. * fixup! Change uri_to_fname to not convert non-file URIs * fixup! fixup! Change uri_to_fname to not convert non-file URIs --- test/functional/lua/uri_spec.lua | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'test/functional/lua') diff --git a/test/functional/lua/uri_spec.lua b/test/functional/lua/uri_spec.lua index a3b8e685e1..f782769935 100644 --- a/test/functional/lua/uri_spec.lua +++ b/test/functional/lua/uri_spec.lua @@ -112,6 +112,29 @@ describe('URI methods', function() eq('C:\\xy\\åäö\\ɧ\\汉语\\↥\\🤦\\🦄\\å\\بِيَّ.txt', exec_lua(test_case)) end) end) + + describe('decode non-file URI', function() + it('uri_to_fname returns non-file URI unchanged', function() + eq('jdt1.23+x-z://content/%5C/', exec_lua [[ + return vim.uri_to_fname('jdt1.23+x-z://content/%5C/') + ]]) + end) + + it('uri_to_fname returns non-file upper-case scheme URI unchanged', function() + eq('JDT://content/%5C/', exec_lua [[ + return vim.uri_to_fname('JDT://content/%5C/') + ]]) + end) + end) + + describe('decode URI without scheme', function() + it('fails because URI must have a scheme', function() + eq(false, exec_lua [[ + return pcall(vim.uri_to_fname, 'not_an_uri.txt') + ]]) + end) + end) + end) describe('uri to bufnr', function() -- cgit From be662fe5c7d06ee63377dd7defb72aea88134305 Mon Sep 17 00:00:00 2001 From: TJ DeVries Date: Wed, 20 May 2020 11:08:19 -0400 Subject: lua: vim.wait implementation --- test/functional/lua/vim_spec.lua | 186 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 179 insertions(+), 7 deletions(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index c68c05dffa..596b960419 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -1048,13 +1048,13 @@ describe('lua stdlib', function() end) it('vim.defer_fn', function() - exec_lua [[ - vim.g.test = 0 - vim.defer_fn(function() vim.g.test = 1 end, 50) - ]] - eq(0, exec_lua[[return vim.g.test]]) - exec_lua [[vim.cmd("sleep 1000m")]] - eq(1, exec_lua[[return vim.g.test]]) + eq(false, exec_lua [[ + vim.g.test = false + vim.defer_fn(function() vim.g.test = true end, 150) + return vim.g.test + ]]) + exec_lua [[vim.wait(1000, function() return vim.g.test end)]] + eq(true, exec_lua[[return vim.g.test]]) end) it('vim.region', function() @@ -1066,4 +1066,176 @@ describe('lua stdlib', function() eq({5,15}, exec_lua[[ return vim.region(0,{1,5},{1,14},'v',true)[1] ]]) end) + describe('vim.wait', function() + before_each(function() + exec_lua[[ + -- high precision timer + get_time = function() + return vim.fn.reltimefloat(vim.fn.reltime()) + end + ]] + end) + + it('should run from lua', function() + exec_lua[[vim.wait(100, function() return true end)]] + end) + + it('should wait the expected time if false', function() + eq({time = true, wait_result = {false, -1}}, exec_lua[[ + start_time = get_time() + wait_succeed, wait_fail_val = vim.wait(200, function() return false end) + + return { + -- 150ms waiting or more results in true. Flaky tests are bad. + time = (start_time + 0.15) < get_time(), + wait_result = {wait_succeed, wait_fail_val} + } + ]]) + end) + + + it('should not block other events', function() + eq({time = true, wait_result = true}, exec_lua[[ + start_time = get_time() + + vim.g.timer_result = false + timer = vim.loop.new_timer() + timer:start(100, 0, vim.schedule_wrap(function() + vim.g.timer_result = true + end)) + + -- Would wait ten seconds if results blocked. + wait_result = vim.wait(10000, function() return vim.g.timer_result end) + + return { + time = (start_time + 5) > get_time(), + wait_result = wait_result, + } + ]]) + end) + + it('should work with vim.defer_fn', function() + eq({time = true, wait_result = true}, exec_lua[[ + start_time = get_time() + + vim.defer_fn(function() vim.g.timer_result = true end, 100) + wait_result = vim.wait(10000, function() return vim.g.timer_result end) + + return { + time = (start_time + 5) > get_time(), + wait_result = wait_result, + } + ]]) + end) + + it('should require functions to be passed', function() + local pcall_result = exec_lua [[ + return {pcall(function() vim.wait(1000, 13) end)} + ]] + + eq(pcall_result[1], false) + matches('condition must be a function', pcall_result[2]) + end) + + it('should not crash when callback errors', function() + local pcall_result = exec_lua [[ + return {pcall(function() vim.wait(1000, function() error("As Expected") end) end)} + ]] + + eq(pcall_result[1], false) + matches('As Expected', pcall_result[2]) + end) + + it('should call callbacks exactly once if they return true immediately', function() + eq(true, exec_lua [[ + vim.g.wait_count = 0 + vim.wait(1000, function() + vim.g.wait_count = vim.g.wait_count + 1 + return true + end, 20) + return vim.g.wait_count == 1 + ]]) + end) + + it('should call callbacks few times with large `interval`', function() + eq(true, exec_lua [[ + vim.g.wait_count = 0 + vim.wait(50, function() vim.g.wait_count = vim.g.wait_count + 1 end, 200) + return vim.g.wait_count < 5 + ]]) + end) + + it('should call callbacks more times with small `interval`', function() + eq(true, exec_lua [[ + vim.g.wait_count = 0 + vim.wait(50, function() vim.g.wait_count = vim.g.wait_count + 1 end, 5) + return vim.g.wait_count > 5 + ]]) + end) + + it('should play nice with `not` when fails', function() + eq(true, exec_lua [[ + if not vim.wait(50, function() end) then + return true + end + + return false + ]]) + end) + + it('should play nice with `if` when success', function() + eq(true, exec_lua [[ + if vim.wait(50, function() return true end) then + return true + end + + return false + ]]) + end) + + it('should return immediately with false if timeout is 0', function() + eq({false, -1}, exec_lua [[ + return { + vim.wait(0, function() return false end) + } + ]]) + end) + + it('should work with tables with __call', function() + eq(true, exec_lua [[ + local t = setmetatable({}, {__call = function(...) return true end}) + return vim.wait(100, t, 10) + ]]) + end) + + it('should work with tables with __call that change', function() + eq(true, exec_lua [[ + local t = {count = 0} + setmetatable(t, { + __call = function() + t.count = t.count + 1 + return t.count > 3 + end + }) + + return vim.wait(1000, t, 10) + ]]) + end) + + it('should not work with negative intervals', function() + local pcall_result = exec_lua [[ + return pcall(function() vim.wait(1000, function() return false end, -1) end) + ]] + + eq(false, pcall_result) + end) + + it('should not work with weird intervals', function() + local pcall_result = exec_lua [[ + return pcall(function() vim.wait(1000, function() return false end, 'a string value') end) + ]] + + eq(false, pcall_result) + end) end) +end) -- cgit From 8349192503450d645bad6a2b30a72c67fd97f7c8 Mon Sep 17 00:00:00 2001 From: Thomas Vigouroux Date: Fri, 15 May 2020 12:23:26 +0200 Subject: treesitter: update runtime Since tree-sitter PR 615, predicates are not parsed the same. "Old" way of writing predicates is still supported. --- test/functional/lua/treesitter_spec.lua | 6 +++--- 1 file changed, 3 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 f93185d1f6..cb0e46b9eb 100644 --- a/test/functional/lua/treesitter_spec.lua +++ b/test/functional/lua/treesitter_spec.lua @@ -240,15 +240,15 @@ static int nlua_schedule(lua_State *const lstate) ; TODO(bfredl): overlapping matches are unreliable, ; we need a proper priority mechanism ;(type_identifier) @type -((type_identifier) @Special (eq? @Special "LuaRef")) +((type_identifier) @Special (#eq? @Special "LuaRef")) (primitive_type) @type (sized_type_specifier) @type ; defaults to very magic syntax, for best compatibility -((identifier) @Identifier (match? @Identifier "^l(u)a_")) +((identifier) @Identifier (#match? @Identifier "^l(u)a_")) ; still support \M etc prefixes -((identifier) @Constant (match? @Constant "\M^\[A-Z_]\+$")) +((identifier) @Constant (#match? @Constant "\M^\[A-Z_]\+$")) ((binary_expression left: (identifier) @WarningMsg.left right: (identifier) @WarningMsg.right) (eq? @WarningMsg.left @WarningMsg.right)) -- cgit From 60c581b35db439dd6b32cdc2ebe1a5aed933b44c Mon Sep 17 00:00:00 2001 From: notomo Date: Wed, 3 Jun 2020 08:31:43 +0900 Subject: lua: fix infinite loop for vim.split on empty string (#12420) --- test/functional/lua/vim_spec.lua | 1 + 1 file changed, 1 insertion(+) (limited to 'test/functional/lua') diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index 596b960419..61bc3e1e3c 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -243,6 +243,7 @@ describe('lua stdlib', function() { "here be dragons", " ", false, { "here", "be", "dragons"} }, { "axaby", "ab?", false, { '', 'x', 'y' } }, { "f v2v v3v w2w ", "([vw])2%1", false, { 'f ', ' v3v ', ' ' } }, + { "", "", false, {} }, { "x*yz*oo*l", "*", true, { 'x', 'yz', 'oo', 'l' } }, } -- cgit From 6a93077475d298f46ac19c8030ed5b4a723685dc Mon Sep 17 00:00:00 2001 From: Thomas Vigouroux Date: Wed, 3 Jun 2020 19:58:02 +0200 Subject: treesitter: fix tests --- test/functional/lua/treesitter_spec.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/treesitter_spec.lua b/test/functional/lua/treesitter_spec.lua index cb0e46b9eb..ecee471386 100644 --- a/test/functional/lua/treesitter_spec.lua +++ b/test/functional/lua/treesitter_spec.lua @@ -250,7 +250,7 @@ static int nlua_schedule(lua_State *const lstate) ; still support \M etc prefixes ((identifier) @Constant (#match? @Constant "\M^\[A-Z_]\+$")) -((binary_expression left: (identifier) @WarningMsg.left right: (identifier) @WarningMsg.right) (eq? @WarningMsg.left @WarningMsg.right)) +((binary_expression left: (identifier) @WarningMsg.left right: (identifier) @WarningMsg.right) (#eq? @WarningMsg.left @WarningMsg.right)) (comment) @comment ]] -- cgit From ac5a3f2c56775040a1b7de438cfd592c0dc26400 Mon Sep 17 00:00:00 2001 From: notomo Date: Thu, 4 Jun 2020 21:48:48 +0900 Subject: lua: fix behavior when split empty string (#12429) * lua: fix behavior when split empty string * test: lsp.util.apply_text_edits with an empty edit --- test/functional/lua/vim_spec.lua | 1 + 1 file changed, 1 insertion(+) (limited to 'test/functional/lua') diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index 61bc3e1e3c..aa0b3d822b 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -244,6 +244,7 @@ describe('lua stdlib', function() { "axaby", "ab?", false, { '', 'x', 'y' } }, { "f v2v v3v w2w ", "([vw])2%1", false, { 'f ', ' v3v ', ' ' } }, { "", "", false, {} }, + { "", "a", false, { '' } }, { "x*yz*oo*l", "*", true, { 'x', 'yz', 'oo', 'l' } }, } -- cgit From d14298a1f076d9681ba35c2fbb53af812e4d15f6 Mon Sep 17 00:00:00 2001 From: TJ DeVries Date: Sun, 31 May 2020 20:37:43 -0400 Subject: test: remove flaky unhelpful test vim.wait( sthg) --- test/functional/lua/vim_spec.lua | 8 -------- 1 file changed, 8 deletions(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index aa0b3d822b..9b2697b3c2 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -1167,14 +1167,6 @@ describe('lua stdlib', function() ]]) end) - it('should call callbacks more times with small `interval`', function() - eq(true, exec_lua [[ - vim.g.wait_count = 0 - vim.wait(50, function() vim.g.wait_count = vim.g.wait_count + 1 end, 5) - return vim.g.wait_count > 5 - ]]) - end) - it('should play nice with `not` when fails', function() eq(true, exec_lua [[ if not vim.wait(50, function() end) then -- cgit From ac18403d6e58a08956f9465998f2223df4e19108 Mon Sep 17 00:00:00 2001 From: Thomas Vigouroux Date: Sun, 14 Jun 2020 18:50:22 +0200 Subject: treesitter: test newly added set_included_ranges --- test/functional/lua/treesitter_spec.lua | 40 +++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) (limited to 'test/functional/lua') diff --git a/test/functional/lua/treesitter_spec.lua b/test/functional/lua/treesitter_spec.lua index ecee471386..1fd93d5f56 100644 --- a/test/functional/lua/treesitter_spec.lua +++ b/test/functional/lua/treesitter_spec.lua @@ -404,4 +404,44 @@ static int nlua_schedule(lua_State *const lstate) end eq({true,true}, {has_named,has_anonymous}) end) + it('allows to set ranges', function() + if not check_parser() then return end + + insert(test_text) + + local res = exec_lua([[ + parser = vim.treesitter.get_parser(0, "c") + return { parser:parse():root():range() } + ]]) + + eq({0, 0, 19, 0}, res) + + local res = exec_lua([[ + parser:set_included_ranges({{0, 0, 1, 0}}) + parser.valid = false + return { parser:parse():root():range() } + ]]) + + eq({0, 0, 1, 0}, res) + + -- Pick random samples + local res = exec_lua([[ + parser:set_included_ranges({{8, 0, 9, 0}, {12, 0, 13 ,0}}) + local root = parser:parse():root() + return {{root:child(0):range()}, {root:child(1):range()}} + ]]) + + eq({{ + 8, + 2, + 8, + 33 + }, + { + 12, + 4, + 12, + 37 + }}, res) + end) end) -- cgit From b652f74ca3a6722ad0d185a0f4093907a6af65d7 Mon Sep 17 00:00:00 2001 From: Thomas Vigouroux Date: Tue, 16 Jun 2020 08:17:25 +0200 Subject: treesitter: use nodes to mark ranges --- test/functional/lua/treesitter_spec.lua | 45 +++++++++++++++++++++------------ 1 file changed, 29 insertions(+), 16 deletions(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/treesitter_spec.lua b/test/functional/lua/treesitter_spec.lua index 1fd93d5f56..539c2b5e7c 100644 --- a/test/functional/lua/treesitter_spec.lua +++ b/test/functional/lua/treesitter_spec.lua @@ -417,31 +417,44 @@ static int nlua_schedule(lua_State *const lstate) eq({0, 0, 19, 0}, res) local res = exec_lua([[ - parser:set_included_ranges({{0, 0, 1, 0}}) + local root = parser:parse():root() + parser:set_included_ranges({{root:child(0), root:child(0)}}) parser.valid = false return { parser:parse():root():range() } ]]) - eq({0, 0, 1, 0}, res) + eq({0, 0, 18, 1}, res) -- Pick random samples local res = exec_lua([[ - parser:set_included_ranges({{8, 0, 9, 0}, {12, 0, 13 ,0}}) + query = vim.treesitter.parse_query("c", "(declaration) @decl") + + local nodes = {} + for _, node in query:iter_captures(parser:parse():root(), 0, 0, 19) do + table.insert(nodes, { node, node }) + end + + parser:set_included_ranges(nodes) + local root = parser:parse():root() - return {{root:child(0):range()}, {root:child(1):range()}} + + local res = {} + for i=0,(root:named_child_count() - 1) do + table.insert(res, { root:named_child(i):range() }) + end + return res ]]) - eq({{ - 8, - 2, - 8, - 33 - }, - { - 12, - 4, - 12, - 37 - }}, res) + eq({ + { 2, 2, 2, 40 }, + { 3, 3, 3, 32 }, + { 4, 7, 4, 8 }, + { 4, 8, 4, 25 }, + { 8, 2, 8, 6 }, + { 8, 7, 8, 33 }, + { 9, 8, 9, 20 }, + { 10, 4, 10, 5 }, + { 10, 5, 10, 20 }, + { 14, 9, 14, 27 } }, res) end) end) -- cgit From 66af35fc85fb2e14fe8f91449289af06b9104dd4 Mon Sep 17 00:00:00 2001 From: Thomas Vigouroux Date: Fri, 26 Jun 2020 20:11:16 +0200 Subject: treesitter: separate tests into smaller pieces --- test/functional/lua/treesitter_spec.lua | 12 ++++++++++-- 1 file changed, 10 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 539c2b5e7c..16a7f365a8 100644 --- a/test/functional/lua/treesitter_spec.lua +++ b/test/functional/lua/treesitter_spec.lua @@ -404,7 +404,7 @@ static int nlua_schedule(lua_State *const lstate) end eq({true,true}, {has_named,has_anonymous}) end) - it('allows to set ranges', function() + it('allows to set simple ranges', function() if not check_parser() then return end insert(test_text) @@ -416,6 +416,8 @@ static int nlua_schedule(lua_State *const lstate) eq({0, 0, 19, 0}, res) + -- The following sets the included ranges for the current parser + -- As stated here, this only includes the function (thus the whole buffer, without the last line) local res = exec_lua([[ local root = parser:parse():root() parser:set_included_ranges({{root:child(0), root:child(0)}}) @@ -424,9 +426,15 @@ static int nlua_schedule(lua_State *const lstate) ]]) eq({0, 0, 18, 1}, res) + end) + it("allows to set complex ranges", function() + if not check_parser() then return end + + insert(test_text) + - -- Pick random samples local res = exec_lua([[ + parser = vim.treesitter.get_parser(0, "c") query = vim.treesitter.parse_query("c", "(declaration) @decl") local nodes = {} -- cgit From 69816f5e134f0e965352367b5928835794da1698 Mon Sep 17 00:00:00 2001 From: Thomas Vigouroux Date: Mon, 29 Jun 2020 23:02:30 +0200 Subject: treesitter: use single nodes in set_ranges fixup! treesitter: fix lint --- test/functional/lua/treesitter_spec.lua | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/treesitter_spec.lua b/test/functional/lua/treesitter_spec.lua index 16a7f365a8..ab0224a911 100644 --- a/test/functional/lua/treesitter_spec.lua +++ b/test/functional/lua/treesitter_spec.lua @@ -418,14 +418,14 @@ static int nlua_schedule(lua_State *const lstate) -- The following sets the included ranges for the current parser -- As stated here, this only includes the function (thus the whole buffer, without the last line) - local res = exec_lua([[ + local res2 = exec_lua([[ local root = parser:parse():root() - parser:set_included_ranges({{root:child(0), root:child(0)}}) + parser:set_included_ranges({root:child(0)}) parser.valid = false return { parser:parse():root():range() } ]]) - eq({0, 0, 18, 1}, res) + eq({0, 0, 18, 1}, res2) end) it("allows to set complex ranges", function() if not check_parser() then return end @@ -439,7 +439,7 @@ static int nlua_schedule(lua_State *const lstate) local nodes = {} for _, node in query:iter_captures(parser:parse():root(), 0, 0, 19) do - table.insert(nodes, { node, node }) + table.insert(nodes, node) end parser:set_included_ranges(nodes) -- cgit From d19132ffd1df21cd4dbd608435530ee6044d1829 Mon Sep 17 00:00:00 2001 From: Thomas Vigouroux Date: Mon, 6 Jul 2020 21:54:15 +0200 Subject: treesitter: update test to show overlapping works --- test/functional/lua/treesitter_spec.lua | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/treesitter_spec.lua b/test/functional/lua/treesitter_spec.lua index ab0224a911..6ba4220849 100644 --- a/test/functional/lua/treesitter_spec.lua +++ b/test/functional/lua/treesitter_spec.lua @@ -237,9 +237,7 @@ static int nlua_schedule(lua_State *const lstate) (number_literal) @number (char_literal) @string -; TODO(bfredl): overlapping matches are unreliable, -; we need a proper priority mechanism -;(type_identifier) @type +(type_identifier) @type ((type_identifier) @Special (#eq? @Special "LuaRef")) (primitive_type) @type @@ -264,7 +262,7 @@ static int nlua_schedule(lua_State *const lstate) [4] = {bold = true, foreground = Screen.colors.Brown}, [5] = {foreground = Screen.colors.Magenta}, [6] = {foreground = Screen.colors.Red}, - [7] = {foreground = Screen.colors.SlateBlue}, + [7] = {bold = true, foreground = Screen.colors.SlateBlue}, [8] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red}, [9] = {foreground = Screen.colors.Magenta, background = Screen.colors.Red}, [10] = {foreground = Screen.colors.Red, background = Screen.colors.Red}, @@ -300,7 +298,7 @@ static int nlua_schedule(lua_State *const lstate) ]], hl_query) screen:expect{grid=[[ {2:/// Schedule Lua callback on main loop's event queue} | - {3:static} {3:int} nlua_schedule(lua_State *{3:const} lstate) | + {3:static} {3:int} nlua_schedule({3:lua_State} *{3:const} lstate) | { | {4:if} ({11:lua_type}(lstate, {5:1}) != {5:LUA_TFUNCTION} | || {6:lstate} != {6:lstate}) { | @@ -311,7 +309,7 @@ static int nlua_schedule(lua_State *const lstate) {7:LuaRef} cb = nlua_ref(lstate, {5:1}); | | multiqueue_put(main_loop.events, nlua_schedule_event, | - {5:1}, ({3:void} *)(ptrdiff_t)cb); | + {5:1}, ({3:void} *)({3:ptrdiff_t})cb); | {4:return} {5:0}; | ^} | {1:~ }| @@ -322,7 +320,7 @@ static int nlua_schedule(lua_State *const lstate) feed('7Go*/') screen:expect{grid=[[ {2:/// Schedule Lua callback on main loop's event queue} | - {3:static} {3:int} nlua_schedule(lua_State *{3:const} lstate) | + {3:static} {3:int} nlua_schedule({3:lua_State} *{3:const} lstate) | { | {4:if} ({11:lua_type}(lstate, {5:1}) != {5:LUA_TFUNCTION} | || {6:lstate} != {6:lstate}) { | @@ -334,7 +332,7 @@ static int nlua_schedule(lua_State *const lstate) {7:LuaRef} cb = nlua_ref(lstate, {5:1}); | | multiqueue_put(main_loop.events, nlua_schedule_event, | - {5:1}, ({3:void} *)(ptrdiff_t)cb); | + {5:1}, ({3:void} *)({3:ptrdiff_t})cb); | {4:return} {5:0}; | } | {1:~ }| @@ -344,7 +342,7 @@ static int nlua_schedule(lua_State *const lstate) feed('3Go/*') screen:expect{grid=[[ {2:/// Schedule Lua callback on main loop's event queue} | - {3:static} {3:int} nlua_schedule(lua_State *{3:const} lstate) | + {3:static} {3:int} nlua_schedule({3:lua_State} *{3:const} lstate) | { | {2:/^*} | {2: if (lua_type(lstate, 1) != LUA_TFUNCTION} | @@ -357,7 +355,7 @@ static int nlua_schedule(lua_State *const lstate) {7:LuaRef} cb = nlua_ref(lstate, {5:1}); | | multiqueue_put(main_loop.events, nlua_schedule_event, | - {5:1}, ({3:void} *)(ptrdiff_t)cb); | + {5:1}, ({3:void} *)({3:ptrdiff_t})cb); | {4:return} {5:0}; | {8:}} | | -- cgit From 971a191c4d772493535d55524b994fe385fae546 Mon Sep 17 00:00:00 2001 From: TJ DeVries Date: Fri, 19 Jun 2020 00:23:30 -0400 Subject: lua: Add ability to pass lua functions directly to vimL --- test/functional/lua/luaeval_spec.lua | 136 +++++++++++++++++++++++++++++++---- 1 file changed, 122 insertions(+), 14 deletions(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/luaeval_spec.lua b/test/functional/lua/luaeval_spec.lua index 61c8e5c02e..4faacecd86 100644 --- a/test/functional/lua/luaeval_spec.lua +++ b/test/functional/lua/luaeval_spec.lua @@ -2,7 +2,6 @@ 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 @@ -188,23 +187,132 @@ describe('luaeval()', function() it('issues an error in some cases', function() eq("Vim(call):E5100: Cannot convert given lua table: table should either have a sequence of positive integer keys or contain only string keys", 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 loading lua [string \"luaeval()\"]:", exc_exec('call luaeval("1, 2, 3")')) 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}")')) - eq("Vim(call):E5101: Cannot convert given lua type", - exc_exec('call luaeval("{foo=42, baz=vim.api}")')) - - -- The following should not crash: conversion error happens inside - eq("Vim(call):E5101: Cannot convert given lua type", - exc_exec('call luaeval("vim.api")')) - -- The following should not show internal error - eq("\nE5101: Cannot convert given lua type\n0", - redir_exec('echo luaeval("vim.api")')) + + end) + + it('should handle sending lua functions to viml', function() + eq(true, exec_lua [[ + can_pass_lua_callback_to_vim_from_lua_result = nil + + vim.fn.call(function() + can_pass_lua_callback_to_vim_from_lua_result = true + end, {}) + + return can_pass_lua_callback_to_vim_from_lua_result + ]]) + end) + + it('run functions even in timers', function() + eq(true, exec_lua [[ + can_pass_lua_callback_to_vim_from_lua_result = nil + + vim.fn.timer_start(50, function() + can_pass_lua_callback_to_vim_from_lua_result = true + end) + + vim.wait(1000, function() + return can_pass_lua_callback_to_vim_from_lua_result + end) + + return can_pass_lua_callback_to_vim_from_lua_result + ]]) + end) + + it('can run named functions more than once', function() + eq(5, exec_lua [[ + count_of_vals = 0 + + vim.fn.timer_start(5, function() + count_of_vals = count_of_vals + 1 + end, {['repeat'] = 5}) + + vim.fn.wait(1000, function() + return count_of_vals >= 5 + end) + + return count_of_vals + ]]) + end) + + it('can handle clashing names', function() + eq(1, exec_lua [[ + local f_loc = function() return 1 end + + local result = nil + vim.fn.timer_start(100, function() + result = f_loc() + end) + + local f_loc = function() return 2 end + vim.wait(1000, function() return result ~= nil end) + + return result + ]]) + end) + + it('should handle passing functions around', function() + command [[ + function VimCanCallLuaCallbacks(Concat, Cb) + let message = a:Concat("Hello Vim", "I'm Lua") + call a:Cb(message) + endfunction + ]] + + eq("Hello Vim I'm Lua", exec_lua [[ + can_pass_lua_callback_to_vim_from_lua_result = "" + + vim.fn.VimCanCallLuaCallbacks( + function(greeting, message) return greeting .. " " .. message end, + function(message) can_pass_lua_callback_to_vim_from_lua_result = message end + ) + + return can_pass_lua_callback_to_vim_from_lua_result + ]]) + end) + + it('should handle funcrefs', function() + command [[ + function VimCanCallLuaCallbacks(Concat, Cb) + let message = a:Concat("Hello Vim", "I'm Lua") + call a:Cb(message) + endfunction + ]] + + eq("Hello Vim I'm Lua", exec_lua [[ + can_pass_lua_callback_to_vim_from_lua_result = "" + + vim.funcref('VimCanCallLuaCallbacks')( + function(greeting, message) return greeting .. " " .. message end, + function(message) can_pass_lua_callback_to_vim_from_lua_result = message end + ) + + return can_pass_lua_callback_to_vim_from_lua_result + ]]) + end) + + -- TODO(tjdevries): Need to figure + pending('should work with metatables using __call', function() + eq(true, exec_lua [[ + local this_is_local_variable = false + local callable_table = setmetatable({}, { + __call = function(...) + this_is_local_variable = true + end + }) + + vim.fn.timer_start(5, callable_table) + + vim.wait(1000, function() + return this_is_local_variable + end) + + return this_is_local_variable + ]]) end) it('correctly converts containers with type_idx', function() -- cgit From 6360cf7ce87407bd8a519b9a17f45b2148291904 Mon Sep 17 00:00:00 2001 From: TJ DeVries Date: Tue, 30 Jun 2020 02:05:06 -0400 Subject: lua: Add ability to pass tables with __call vim-patch:8.2.1054: not so easy to pass a lua function to Vim vim-patch:8.2.1084: Lua: registering function has useless code I think I have also opened up the possibility for people to use these callbacks elsewhere, since I've added a new struct that we should be able to use. Also, this should allow us to determine what the state of a list is in Lua or a dictionary in Lua, since we now can track the luaref as we go. --- test/functional/lua/luaeval_spec.lua | 78 +++++++++++++++++++++++++++++++++--- 1 file changed, 72 insertions(+), 6 deletions(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/luaeval_spec.lua b/test/functional/lua/luaeval_spec.lua index 4faacecd86..964ea4561e 100644 --- a/test/functional/lua/luaeval_spec.lua +++ b/test/functional/lua/luaeval_spec.lua @@ -295,13 +295,12 @@ describe('luaeval()', function() ]]) end) - -- TODO(tjdevries): Need to figure - pending('should work with metatables using __call', function() - eq(true, exec_lua [[ + it('should work with metatables using __call', function() + eq(1, exec_lua [[ local this_is_local_variable = false - local callable_table = setmetatable({}, { - __call = function(...) - this_is_local_variable = true + local callable_table = setmetatable({x = 1}, { + __call = function(t, ...) + this_is_local_variable = t.x end }) @@ -315,6 +314,73 @@ describe('luaeval()', function() ]]) end) + it('should handle being called from a timer once.', function() + eq(3, exec_lua [[ + local this_is_local_variable = false + local callable_table = setmetatable({5, 4, 3, 2, 1}, { + __call = function(t, ...) this_is_local_variable = t[3] end + }) + + vim.fn.timer_start(5, callable_table) + vim.wait(1000, function() + return this_is_local_variable + end) + + return this_is_local_variable + ]]) + end) + + it('should call functions once with __call metamethod', function() + eq(true, exec_lua [[ + local this_is_local_variable = false + local callable_table = setmetatable({a = true, b = false}, { + __call = function(t, ...) this_is_local_variable = t.a end + }) + + assert(getmetatable(callable_table).__call) + vim.fn.call(callable_table, {}) + + return this_is_local_variable + ]]) + end) + + it('should work with lists using __call', function() + eq(3, exec_lua [[ + local this_is_local_variable = false + local mt = { + __call = function(t, ...) + this_is_local_variable = t[3] + end + } + local callable_table = setmetatable({5, 4, 3, 2, 1}, mt) + + -- Call it once... + vim.fn.timer_start(5, callable_table) + vim.wait(1000, function() + return this_is_local_variable + end) + + assert(this_is_local_variable) + this_is_local_variable = false + + vim.fn.timer_start(5, callable_table) + vim.wait(1000, function() + return this_is_local_variable + end) + + return this_is_local_variable + ]]) + end) + + it('should not work with tables not using __call', function() + eq({false, 'Vim:E921: Invalid callback argument'}, exec_lua [[ + local this_is_local_variable = false + local callable_table = setmetatable({x = 1}, {}) + + return {pcall(function() vim.fn.timer_start(5, callable_table) end)} + ]]) + end) + it('correctly converts containers with type_idx', function() eq(5, eval('type(luaeval("{[vim.type_idx]=vim.types.float, [vim.val_idx]=0}"))')) eq(4, eval([[type(luaeval('{[vim.type_idx]=vim.types.dictionary}'))]])) -- cgit From 398201cfabaef47aa93c8a485336a00ef075ad3e Mon Sep 17 00:00:00 2001 From: TJ DeVries Date: Sun, 19 Jul 2020 17:16:48 -0400 Subject: lua: Fix crash on unprotected lua errors (#12658) Can be reproduced with a script like this: -- in some lua file vim.fn.timer_start(10, function() error("uh....") end) -- will cause neovim to crash with the following error. PANIC: unprotected error in call to Lua API (nlua_CFunction_func_call failed.) After this, it will instead print the error message from the top of the stack, like so. tmp/error_nvim.lua:10: uh... Also added an example test. Previously this test caused the embedded nvim to panic. --- test/functional/lua/luaeval_spec.lua | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'test/functional/lua') diff --git a/test/functional/lua/luaeval_spec.lua b/test/functional/lua/luaeval_spec.lua index 964ea4561e..75966393b1 100644 --- a/test/functional/lua/luaeval_spec.lua +++ b/test/functional/lua/luaeval_spec.lua @@ -255,6 +255,18 @@ describe('luaeval()', function() ]]) end) + it('can handle functions with errors', function() + eq(true, exec_lua [[ + vim.fn.timer_start(10, function() + error("dead function") + end) + + vim.wait(1000, function() return false end) + + return true + ]]) + end) + it('should handle passing functions around', function() command [[ function VimCanCallLuaCallbacks(Concat, Cb) -- cgit From 2c34780c32c479950ee6c6797b5fbb88b0f9fd51 Mon Sep 17 00:00:00 2001 From: Thomas Vigouroux Date: Thu, 16 Jul 2020 09:28:18 +0200 Subject: buffer_updates: emit valid old_byte_size Test this using treesitter highlighting, which is based on this old_byte_size. --- test/functional/lua/treesitter_spec.lua | 46 +++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) (limited to 'test/functional/lua') diff --git a/test/functional/lua/treesitter_spec.lua b/test/functional/lua/treesitter_spec.lua index 6ba4220849..aa3d55b06d 100644 --- a/test/functional/lua/treesitter_spec.lua +++ b/test/functional/lua/treesitter_spec.lua @@ -360,6 +360,52 @@ static int nlua_schedule(lua_State *const lstate) {8:}} | | ]]} + + feed("gg$") + feed("~") + screen:expect{grid=[[ + {2:/// Schedule Lua callback on main loop's event queu^E} | + {3:static} {3:int} nlua_schedule({3:lua_State} *{3:const} lstate) | + { | + {2:/*} | + {2: if (lua_type(lstate, 1) != LUA_TFUNCTION} | + {2: || lstate != lstate) {} | + {2: lua_pushliteral(lstate, "vim.schedule: expected function");} | + {2: return lua_error(lstate);} | + {2:*/} | + } | + | + {7:LuaRef} cb = nlua_ref(lstate, {5:1}); | + | + multiqueue_put(main_loop.events, nlua_schedule_event, | + {5:1}, ({3:void} *)({3:ptrdiff_t})cb); | + {4:return} {5:0}; | + {8:}} | + | + ]]} + + + feed("re") + screen:expect{grid=[[ + {2:/// Schedule Lua callback on main loop's event queu^e} | + {3:static} {3:int} nlua_schedule({3:lua_State} *{3:const} lstate) | + { | + {2:/*} | + {2: if (lua_type(lstate, 1) != LUA_TFUNCTION} | + {2: || lstate != lstate) {} | + {2: lua_pushliteral(lstate, "vim.schedule: expected function");} | + {2: return lua_error(lstate);} | + {2:*/} | + } | + | + {7:LuaRef} cb = nlua_ref(lstate, {5:1}); | + | + multiqueue_put(main_loop.events, nlua_schedule_event, | + {5:1}, ({3:void} *)({3:ptrdiff_t})cb); | + {4:return} {5:0}; | + {8:}} | + | + ]]} end) it('inspects language', function() -- cgit