luaeval_spec.lua 20 KB

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