luaeval_spec.lua 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592
  1. -- Test suite for testing luaeval() function
  2. local t = require('test.testutil')
  3. local n = require('test.functional.testnvim')()
  4. local Screen = require('test.functional.ui.screen')
  5. local pcall_err = t.pcall_err
  6. local exc_exec = n.exc_exec
  7. local remove_trace = t.remove_trace
  8. local exec_lua = n.exec_lua
  9. local command = n.command
  10. local api = n.api
  11. local fn = n.fn
  12. local clear = n.clear
  13. local eval = n.eval
  14. local feed = n.feed
  15. local assert_alive = n.assert_alive
  16. local NIL = vim.NIL
  17. local eq = t.eq
  18. before_each(clear)
  19. local function startswith(expected, actual)
  20. eq(expected, actual:sub(1, #expected))
  21. end
  22. describe('luaeval()', function()
  23. local nested_by_level = {}
  24. local nested = {}
  25. local nested_s = '{}'
  26. for i=1,100 do
  27. if i % 2 == 0 then
  28. nested = {nested}
  29. nested_s = '{' .. nested_s .. '}'
  30. else
  31. nested = {nested=nested}
  32. nested_s = '{nested=' .. nested_s .. '}'
  33. end
  34. nested_by_level[i] = {o=nested, s=nested_s}
  35. end
  36. describe('second argument', function()
  37. it('is successfully received', function()
  38. local q = {t=true, f=false, --[[n=NIL,]] d={l={'string', 42, 0.42}}}
  39. eq(q, fn.luaeval("_A", q))
  40. -- Not tested: nil, funcrefs, returned object identity: behaviour will
  41. -- most likely change.
  42. end)
  43. end)
  44. describe('lua values', function()
  45. it('are successfully transformed', function()
  46. eq({n=1, f=1.5, s='string', l={4, 2}},
  47. fn.luaeval('{n=1, f=1.5, s="string", l={4, 2}}'))
  48. -- Not tested: nil inside containers: behaviour will most likely change.
  49. eq(NIL, fn.luaeval('nil'))
  50. eq({['']=1}, fn.luaeval('{[""]=1}'))
  51. end)
  52. end)
  53. describe('recursive lua values', function()
  54. it('are successfully transformed', function()
  55. command('lua rawset(_G, "d", {})')
  56. command('lua rawset(d, "d", d)')
  57. eq('\n{\'d\': {...@0}}', fn.execute('echo luaeval("d")'))
  58. command('lua rawset(_G, "l", {})')
  59. command('lua table.insert(l, l)')
  60. eq('\n[[...@0]]', fn.execute('echo luaeval("l")'))
  61. end)
  62. end)
  63. describe('strings with NULs', function()
  64. it('are successfully converted to blobs', function()
  65. command([[let s = luaeval('"\0"')]])
  66. eq('\000', api.nvim_get_var('s'))
  67. end)
  68. it('are successfully converted to special dictionaries in table keys', function()
  69. command([[let d = luaeval('{["\0"]=1}')]])
  70. eq({_TYPE={}, _VAL={{'\000', 1}}}, api.nvim_get_var('d'))
  71. eq(1, fn.eval('d._TYPE is v:msgpack_types.map'))
  72. eq(eval('v:t_blob'), fn.eval('type(d._VAL[0][0])'))
  73. end)
  74. it('are successfully converted to blobs from a list', function()
  75. command([[let l = luaeval('{"abc", "a\0b", "c\0d", "def"}')]])
  76. eq({'abc', 'a\000b', 'c\000d', 'def'}, api.nvim_get_var('l'))
  77. end)
  78. end)
  79. -- Not checked: funcrefs converted to NIL. To be altered to something more
  80. -- meaningful later.
  81. it('correctly evaluates scalars', function()
  82. -- Also test method call (->) syntax
  83. eq(1, fn.luaeval('1'))
  84. eq(0, eval('"1"->luaeval()->type()'))
  85. eq(1.5, fn.luaeval('1.5'))
  86. eq(5, eval('"1.5"->luaeval()->type()'))
  87. eq("test", fn.luaeval('"test"'))
  88. eq(1, eval('"\'test\'"->luaeval()->type()'))
  89. eq('', fn.luaeval('""'))
  90. eq('\000', fn.luaeval([['\0']]))
  91. eq('\000\n\000', fn.luaeval([['\0\n\0']]))
  92. eq(10, eval([[type(luaeval("'\\0\\n\\0'"))]]))
  93. eq(true, fn.luaeval('true'))
  94. eq(false, fn.luaeval('false'))
  95. eq(NIL, fn.luaeval('nil'))
  96. end)
  97. it('correctly evaluates containers', function()
  98. eq({}, fn.luaeval('{}'))
  99. eq(3, eval('type(luaeval("{}"))'))
  100. eq({test=1, foo=2}, fn.luaeval('{test=1, foo=2}'))
  101. eq(4, eval('type(luaeval("{test=1, foo=2}"))'))
  102. eq({4, 2}, fn.luaeval('{4, 2}'))
  103. eq(3, eval('type(luaeval("{4, 2}"))'))
  104. eq({NIL, 20}, fn.luaeval('{[2] = 20}'))
  105. eq(3, eval('type(luaeval("{[2] = 20}"))'))
  106. eq({10, NIL, 30}, fn.luaeval('{[1] = 10, [3] = 30}'))
  107. eq(3, eval('type(luaeval("{[1] = 10, [3] = 30}"))'))
  108. local level = 30
  109. eq(nested_by_level[level].o, fn.luaeval(nested_by_level[level].s))
  110. eq({_TYPE={}, _VAL={{'\000\n\000', '\000\n\000\000'}}},
  111. fn.luaeval([[{['\0\n\0']='\0\n\0\0'}]]))
  112. eq(1, eval([[luaeval('{["\0\n\0"]="\0\n\0\0"}')._TYPE is v:msgpack_types.map]]))
  113. eq(eval("v:t_blob"), eval([[type(luaeval('{["\0\n\0"]="\0\n\0\0"}')._VAL[0][0])]]))
  114. eq({nested={{_TYPE={}, _VAL={{'\000\n\000', '\000\n\000\000'}}}}},
  115. fn.luaeval([[{nested={{['\0\n\0']='\0\n\0\0'}}}]]))
  116. end)
  117. it('correctly passes scalars as argument', function()
  118. eq(1, fn.luaeval('_A', 1))
  119. eq(1.5, fn.luaeval('_A', 1.5))
  120. eq('', fn.luaeval('_A', ''))
  121. eq('test', fn.luaeval('_A', 'test'))
  122. eq(NIL, fn.luaeval('_A', NIL))
  123. eq(true, fn.luaeval('_A', true))
  124. eq(false, fn.luaeval('_A', false))
  125. end)
  126. it('correctly passes containers as argument', function()
  127. eq({}, fn.luaeval('_A', {}))
  128. eq({test=1}, fn.luaeval('_A', {test=1}))
  129. eq({4, 2}, fn.luaeval('_A', {4, 2}))
  130. local level = 28
  131. eq(nested_by_level[level].o, fn.luaeval('_A', nested_by_level[level].o))
  132. end)
  133. local function sp(typ, val)
  134. return ('{"_TYPE": v:msgpack_types.%s, "_VAL": %s}'):format(typ, val)
  135. end
  136. local function mapsp(...)
  137. local val = ''
  138. for i=1,(select('#', ...)/2) do
  139. val = ('%s[%s,%s],'):format(val, select(i * 2 - 1, ...),
  140. select(i * 2, ...))
  141. end
  142. return sp('map', '[' .. val .. ']')
  143. end
  144. local function luaevalarg(argexpr, expr)
  145. return eval((([=[
  146. [
  147. extend(g:, {'_ret': luaeval(%s, %s)})._ret,
  148. type(g:_ret)==type({})&&has_key(g:_ret, '_TYPE')
  149. ? [
  150. get(keys(filter(copy(v:msgpack_types), 'v:val is g:_ret._TYPE')), 0,
  151. g:_ret._TYPE),
  152. get(g:_ret, '_VAL', g:_ret)
  153. ]
  154. : [0, g:_ret]][1]
  155. ]=]):format(expr or '"_A"', argexpr):gsub('\n', '')))
  156. end
  157. it('correctly passes special dictionaries', function()
  158. eq({0, '\000\n\000'}, luaevalarg(sp('string', '["\\n", "\\n"]')))
  159. eq({0, true}, luaevalarg(sp('boolean', 1)))
  160. eq({0, false}, luaevalarg(sp('boolean', 0)))
  161. eq({0, NIL}, luaevalarg(sp('nil', 0)))
  162. eq({0, {[""]=""}}, luaevalarg(mapsp(sp('string', '[""]'), '""')))
  163. end)
  164. it('issues an error in some cases', function()
  165. eq("Vim(call):E5100: Cannot convert given Lua table: table should contain either only integer keys or only string keys",
  166. exc_exec('call luaeval("{1, foo=2}")'))
  167. startswith("Vim(call):E5107: Error loading lua [string \"luaeval()\"]:",
  168. exc_exec('call luaeval("1, 2, 3")'))
  169. startswith("Vim(call):E5108: Error executing lua [string \"luaeval()\"]:",
  170. exc_exec('call luaeval("(nil)()")'))
  171. end)
  172. it('should handle sending lua functions to viml', function()
  173. eq(true, exec_lua [[
  174. can_pass_lua_callback_to_vim_from_lua_result = nil
  175. vim.fn.call(function()
  176. can_pass_lua_callback_to_vim_from_lua_result = true
  177. end, {})
  178. return can_pass_lua_callback_to_vim_from_lua_result
  179. ]])
  180. end)
  181. it('run functions even in timers', function()
  182. eq(true, exec_lua [[
  183. can_pass_lua_callback_to_vim_from_lua_result = nil
  184. vim.fn.timer_start(50, function()
  185. can_pass_lua_callback_to_vim_from_lua_result = true
  186. end)
  187. vim.wait(1000, function()
  188. return can_pass_lua_callback_to_vim_from_lua_result
  189. end)
  190. return can_pass_lua_callback_to_vim_from_lua_result
  191. ]])
  192. end)
  193. it('can run named functions more than once', function()
  194. eq(5, exec_lua [[
  195. count_of_vals = 0
  196. vim.fn.timer_start(5, function()
  197. count_of_vals = count_of_vals + 1
  198. end, {['repeat'] = 5})
  199. vim.fn.wait(1000, function()
  200. return count_of_vals >= 5
  201. end)
  202. return count_of_vals
  203. ]])
  204. end)
  205. it('can handle clashing names', function()
  206. eq(1, exec_lua [[
  207. local f_loc = function() return 1 end
  208. local result = nil
  209. vim.fn.timer_start(100, function()
  210. result = f_loc()
  211. end)
  212. local f_loc = function() return 2 end
  213. vim.wait(1000, function() return result ~= nil end)
  214. return result
  215. ]])
  216. end)
  217. it('can handle functions with errors', function()
  218. eq(true, exec_lua [[
  219. vim.fn.timer_start(10, function()
  220. error("dead function")
  221. end)
  222. vim.wait(1000, function() return false end)
  223. return true
  224. ]])
  225. end)
  226. it('should handle passing functions around', function()
  227. command [[
  228. function VimCanCallLuaCallbacks(Concat, Cb)
  229. let message = a:Concat("Hello Vim", "I'm Lua")
  230. call a:Cb(message)
  231. endfunction
  232. ]]
  233. eq("Hello Vim I'm Lua", exec_lua [[
  234. can_pass_lua_callback_to_vim_from_lua_result = ""
  235. vim.fn.VimCanCallLuaCallbacks(
  236. function(greeting, message) return greeting .. " " .. message end,
  237. function(message) can_pass_lua_callback_to_vim_from_lua_result = message end
  238. )
  239. return can_pass_lua_callback_to_vim_from_lua_result
  240. ]])
  241. end)
  242. it('should handle funcrefs', function()
  243. command [[
  244. function VimCanCallLuaCallbacks(Concat, Cb)
  245. let message = a:Concat("Hello Vim", "I'm Lua")
  246. call a:Cb(message)
  247. endfunction
  248. ]]
  249. eq("Hello Vim I'm Lua", exec_lua [[
  250. can_pass_lua_callback_to_vim_from_lua_result = ""
  251. vim.funcref('VimCanCallLuaCallbacks')(
  252. function(greeting, message) return greeting .. " " .. message end,
  253. function(message) can_pass_lua_callback_to_vim_from_lua_result = message end
  254. )
  255. return can_pass_lua_callback_to_vim_from_lua_result
  256. ]])
  257. end)
  258. it('should work with metatables using __call', function()
  259. eq(1, exec_lua [[
  260. local this_is_local_variable = false
  261. local callable_table = setmetatable({x = 1}, {
  262. __call = function(t, ...)
  263. this_is_local_variable = t.x
  264. end
  265. })
  266. vim.fn.timer_start(5, callable_table)
  267. vim.wait(1000, function()
  268. return this_is_local_variable
  269. end)
  270. return this_is_local_variable
  271. ]])
  272. end)
  273. it('should handle being called from a timer once.', function()
  274. eq(3, exec_lua [[
  275. local this_is_local_variable = false
  276. local callable_table = setmetatable({5, 4, 3, 2, 1}, {
  277. __call = function(t, ...) this_is_local_variable = t[3] end
  278. })
  279. vim.fn.timer_start(5, callable_table)
  280. vim.wait(1000, function()
  281. return this_is_local_variable
  282. end)
  283. return this_is_local_variable
  284. ]])
  285. end)
  286. it('should call functions once with __call metamethod', function()
  287. eq(true, exec_lua [[
  288. local this_is_local_variable = false
  289. local callable_table = setmetatable({a = true, b = false}, {
  290. __call = function(t, ...) this_is_local_variable = t.a end
  291. })
  292. assert(getmetatable(callable_table).__call)
  293. vim.fn.call(callable_table, {})
  294. return this_is_local_variable
  295. ]])
  296. end)
  297. it('should work with lists using __call', function()
  298. eq(3, exec_lua [[
  299. local this_is_local_variable = false
  300. local mt = {
  301. __call = function(t, ...)
  302. this_is_local_variable = t[3]
  303. end
  304. }
  305. local callable_table = setmetatable({5, 4, 3, 2, 1}, mt)
  306. -- Call it once...
  307. vim.fn.timer_start(5, callable_table)
  308. vim.wait(1000, function()
  309. return this_is_local_variable
  310. end)
  311. assert(this_is_local_variable)
  312. this_is_local_variable = false
  313. vim.fn.timer_start(5, callable_table)
  314. vim.wait(1000, function()
  315. return this_is_local_variable
  316. end)
  317. return this_is_local_variable
  318. ]])
  319. end)
  320. it('should not work with tables not using __call', function()
  321. eq({false, 'Vim:E921: Invalid callback argument'}, exec_lua [[
  322. local this_is_local_variable = false
  323. local callable_table = setmetatable({x = 1}, {})
  324. return {pcall(function() vim.fn.timer_start(5, callable_table) end)}
  325. ]])
  326. end)
  327. it('correctly converts containers with type_idx', function()
  328. eq(5, eval('type(luaeval("{[vim.type_idx]=vim.types.float, [vim.val_idx]=0}"))'))
  329. eq(4, eval([[type(luaeval('{[vim.type_idx]=vim.types.dictionary}'))]]))
  330. eq(3, eval([[type(luaeval('{[vim.type_idx]=vim.types.array}'))]]))
  331. eq({}, fn.luaeval('{[vim.type_idx]=vim.types.array}'))
  332. -- Presence of type_idx makes Vim ignore some keys
  333. eq({42}, fn.luaeval('{[vim.type_idx]=vim.types.array, [vim.val_idx]=10, [5]=1, foo=2, [1]=42}'))
  334. eq({foo=2}, fn.luaeval('{[vim.type_idx]=vim.types.dictionary, [vim.val_idx]=10, [5]=1, foo=2, [1]=42}'))
  335. eq(10, fn.luaeval('{[vim.type_idx]=vim.types.float, [vim.val_idx]=10, [5]=1, foo=2, [1]=42}'))
  336. -- The following should not crash
  337. eq({}, fn.luaeval('{[vim.type_idx]=vim.types.dictionary}'))
  338. end)
  339. it('correctly converts self-containing containers', function()
  340. api.nvim_set_var('l', {})
  341. eval('add(l, l)')
  342. eq(true, eval('luaeval("_A == _A[1]", l)'))
  343. eq(true, eval('luaeval("_A[1] == _A[1][1]", [l])'))
  344. eq(true, eval('luaeval("_A.d == _A.d[1]", {"d": l})'))
  345. eq(true, eval('luaeval("_A ~= _A[1]", [l])'))
  346. api.nvim_set_var('d', {foo=42})
  347. eval('extend(d, {"d": d})')
  348. eq(true, eval('luaeval("_A == _A.d", d)'))
  349. eq(true, eval('luaeval("_A[1] == _A[1].d", [d])'))
  350. eq(true, eval('luaeval("_A.d == _A.d.d", {"d": d})'))
  351. eq(true, eval('luaeval("_A ~= _A.d", {"d": d})'))
  352. end)
  353. it('errors out correctly when doing incorrect things in lua', function()
  354. -- Conversion errors
  355. eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: attempt to call field \'xxx_nonexistent_key_xxx\' (a nil value)',
  356. remove_trace(exc_exec([[call luaeval("vim.xxx_nonexistent_key_xxx()")]])))
  357. eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: ERROR',
  358. remove_trace(exc_exec([[call luaeval("error('ERROR')")]])))
  359. eq('Vim(call):E5108: Error executing lua [NULL]',
  360. remove_trace(exc_exec([[call luaeval("error(nil)")]])))
  361. end)
  362. it('does not leak memory when called with too long line',
  363. function()
  364. local s = ('x'):rep(65536)
  365. eq('Vim(call):E5107: Error loading lua [string "luaeval()"]:1: unexpected symbol near \')\'',
  366. exc_exec([[call luaeval("(']] .. s ..[[' + )")]]))
  367. eq(s, fn.luaeval('"' .. s .. '"'))
  368. end)
  369. end)
  370. describe('v:lua', function()
  371. before_each(function()
  372. exec_lua([[
  373. function _G.foo(a,b,n)
  374. _G.val = n
  375. return a+b
  376. end
  377. mymod = {}
  378. function mymod.noisy(name)
  379. vim.api.nvim_set_current_line("hey "..name)
  380. end
  381. function mymod.crashy()
  382. nonexistent()
  383. end
  384. function mymod.whatis(value)
  385. return type(value) .. ": " .. tostring(value)
  386. end
  387. function mymod.omni(findstart, base)
  388. if findstart == 1 then
  389. return 5
  390. else
  391. if base == 'st' then
  392. return {'stuff', 'steam', 'strange things'}
  393. end
  394. end
  395. end
  396. ]])
  397. end)
  398. it('works in expressions', function()
  399. eq(7, eval('v:lua.foo(3,4,v:null)'))
  400. eq(true, exec_lua([[return _G.val == vim.NIL]]))
  401. eq(NIL, eval('v:lua.mymod.noisy("eval")'))
  402. eq("hey eval", api.nvim_get_current_line())
  403. eq("string: abc", eval('v:lua.mymod.whatis(0z616263)'))
  404. eq("string: ", eval('v:lua.mymod.whatis(v:_null_blob)'))
  405. eq("Vim:E5108: Error executing lua [string \"<nvim>\"]:0: attempt to call global 'nonexistent' (a nil value)",
  406. pcall_err(eval, 'v:lua.mymod.crashy()'))
  407. end)
  408. it('works when called as a method', function()
  409. eq(123, eval('110->v:lua.foo(13)'))
  410. eq(true, exec_lua([[return _G.val == nil]]))
  411. eq(321, eval('300->v:lua.foo(21, "boop")'))
  412. eq("boop", exec_lua([[return _G.val]]))
  413. eq(NIL, eval('"there"->v:lua.mymod.noisy()'))
  414. eq("hey there", api.nvim_get_current_line())
  415. eq({5, 10, 15, 20}, eval('[[1], [2, 3], [4]]->v:lua.vim.tbl_flatten()->map({_, v -> v * 5})'))
  416. eq("Vim:E5108: Error executing lua [string \"<nvim>\"]:0: attempt to call global 'nonexistent' (a nil value)",
  417. pcall_err(eval, '"huh?"->v:lua.mymod.crashy()'))
  418. end)
  419. it('works in :call', function()
  420. command(":call v:lua.mymod.noisy('command')")
  421. eq("hey command", api.nvim_get_current_line())
  422. eq("Vim(call):E5108: Error executing lua [string \"<nvim>\"]:0: attempt to call global 'nonexistent' (a nil value)",
  423. pcall_err(command, 'call v:lua.mymod.crashy()'))
  424. end)
  425. it('works in func options', function()
  426. local screen = Screen.new(60, 8)
  427. api.nvim_set_option_value('omnifunc', 'v:lua.mymod.omni', {})
  428. feed('isome st<c-x><c-o>')
  429. screen:expect{grid=[[
  430. some stuff^ |
  431. {1:~ }{12: stuff }{1: }|
  432. {1:~ }{4: steam }{1: }|
  433. {1:~ }{4: strange things }{1: }|
  434. {1:~ }|*3
  435. {5:-- Omni completion (^O^N^P) }{6:match 1 of 3} |
  436. ]]}
  437. api.nvim_set_option_value('operatorfunc', 'v:lua.mymod.noisy', {})
  438. feed('<Esc>g@g@')
  439. eq("hey line", api.nvim_get_current_line())
  440. end)
  441. it('supports packages', function()
  442. command('set pp+=test/functional/fixtures')
  443. eq('\tbadval', eval("v:lua.require'leftpad'('badval')"))
  444. eq(9003, eval("v:lua.require'bar'.doit()"))
  445. eq(9004, eval("v:lua.require'baz-quux'.doit()"))
  446. eq(9003, eval("1 ? v:lua.require'bar'.doit() : v:lua.require'baz-quux'.doit()"))
  447. eq(9004, eval("0 ? v:lua.require'bar'.doit() : v:lua.require'baz-quux'.doit()"))
  448. end)
  449. it('throw errors for invalid use', function()
  450. eq([[Vim(let):E15: Invalid expression: "v:lua.func"]], pcall_err(command, "let g:Func = v:lua.func"))
  451. eq([[Vim(let):E15: Invalid expression: "v:lua"]], pcall_err(command, "let g:Func = v:lua"))
  452. eq([[Vim(let):E15: Invalid expression: "v:['lua']"]], pcall_err(command, "let g:Func = v:['lua']"))
  453. eq([[Vim:E15: Invalid expression: "v:['lua'].foo()"]], pcall_err(eval, "v:['lua'].foo()"))
  454. eq("Vim(call):E461: Illegal variable name: v:['lua']", pcall_err(command, "call v:['lua'].baar()"))
  455. eq("Vim:E1085: Not a callable type: v:lua", pcall_err(eval, "v:lua()"))
  456. eq("Vim(let):E46: Cannot change read-only variable \"v:['lua']\"", pcall_err(command, "let v:['lua'] = 'xx'"))
  457. eq("Vim(let):E46: Cannot change read-only variable \"v:lua\"", pcall_err(command, "let v:lua = 'xx'"))
  458. eq("Vim:E107: Missing parentheses: v:lua.func", pcall_err(eval, "'bad'->v:lua.func"))
  459. eq("Vim:E274: No white space allowed before parenthesis", pcall_err(eval, "'bad'->v:lua.func ()"))
  460. eq("Vim:E107: Missing parentheses: v:lua", pcall_err(eval, "'bad'->v:lua"))
  461. eq("Vim:E1085: Not a callable type: v:lua", pcall_err(eval, "'bad'->v:lua()"))
  462. eq([[Vim:E15: Invalid expression: "v:lua.()"]], pcall_err(eval, "'bad'->v:lua.()"))
  463. eq("Vim:E1085: Not a callable type: v:lua", pcall_err(eval, "v:lua()"))
  464. eq([[Vim:E15: Invalid expression: "v:lua.()"]], pcall_err(eval, "v:lua.()"))
  465. end)
  466. describe('invalid use in fold text', function()
  467. before_each(function()
  468. feed('ifoo<CR>bar<Esc>')
  469. command('1,2fold')
  470. end)
  471. it('with missing function name when used as simple function', function()
  472. api.nvim_set_option_value('debug', 'throw', {})
  473. eq(
  474. [[Vim(eval):E15: Invalid expression: "v:lua.()"]],
  475. pcall_err(command, 'set foldtext=v:lua.() | eval foldtextresult(1)')
  476. )
  477. end)
  478. it('with missing function name when used in expression', function()
  479. api.nvim_set_option_value('debug', 'throw', {})
  480. eq(
  481. [[Vim(eval):E15: Invalid expression: "+v:lua.()"]],
  482. pcall_err(command, 'set foldtext=+v:lua.() | eval foldtextresult(1)')
  483. )
  484. end)
  485. it('with non-existent function when used as simple function', function()
  486. command('set foldtext=v:lua.NoSuchFunc() | eval foldtextresult(1)')
  487. assert_alive()
  488. end)
  489. it('with non-existent function when used in expression', function()
  490. command('set foldtext=+v:lua.NoSuchFunc() | eval foldtextresult(1)')
  491. assert_alive()
  492. end)
  493. end)
  494. end)