api_spec.lua 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. -- Test suite for testing interactions with API bindings
  2. local helpers = require('test.functional.helpers')(after_each)
  3. local exc_exec = helpers.exc_exec
  4. local funcs = helpers.funcs
  5. local clear = helpers.clear
  6. local eval = helpers.eval
  7. local NIL = helpers.NIL
  8. local eq = helpers.eq
  9. before_each(clear)
  10. describe('luaeval(vim.api.…)', function()
  11. describe('with channel_id and buffer handle', function()
  12. describe('nvim_buf_get_lines', function()
  13. it('works', function()
  14. funcs.setline(1, {"abc", "def", "a\nb", "ttt"})
  15. eq({{_TYPE={}, _VAL={'a\nb'}}},
  16. funcs.luaeval('vim.api.nvim_buf_get_lines(1, 2, 3, false)'))
  17. end)
  18. end)
  19. describe('nvim_buf_set_lines', function()
  20. it('works', function()
  21. funcs.setline(1, {"abc", "def", "a\nb", "ttt"})
  22. eq(NIL, funcs.luaeval('vim.api.nvim_buf_set_lines(1, 1, 2, false, {"b\\0a"})'))
  23. eq({'abc', {_TYPE={}, _VAL={'b\na'}}, {_TYPE={}, _VAL={'a\nb'}}, 'ttt'},
  24. funcs.luaeval('vim.api.nvim_buf_get_lines(1, 0, 4, false)'))
  25. end)
  26. end)
  27. end)
  28. describe('with errors', function()
  29. it('transforms API error from nvim_buf_set_lines into lua error', function()
  30. funcs.setline(1, {"abc", "def", "a\nb", "ttt"})
  31. eq({false, 'String cannot contain newlines'},
  32. funcs.luaeval('{pcall(vim.api.nvim_buf_set_lines, 1, 1, 2, false, {"b\\na"})}'))
  33. end)
  34. it('transforms API error from nvim_win_set_cursor into lua error', function()
  35. eq({false, 'Argument "pos" must be a [row, col] array'},
  36. funcs.luaeval('{pcall(vim.api.nvim_win_set_cursor, 0, {1, 2, 3})}'))
  37. -- Used to produce a memory leak due to a bug in nvim_win_set_cursor
  38. eq({false, 'Invalid window id'},
  39. funcs.luaeval('{pcall(vim.api.nvim_win_set_cursor, -1, {1, 2, 3})}'))
  40. end)
  41. it('transforms API error from nvim_win_set_cursor + same array as in first test into lua error',
  42. function()
  43. eq({false, 'Argument "pos" must be a [row, col] array'},
  44. funcs.luaeval('{pcall(vim.api.nvim_win_set_cursor, 0, {"b\\na"})}'))
  45. end)
  46. end)
  47. it('correctly evaluates API code which calls luaeval', function()
  48. local str = (([===[vim.api.nvim_eval([==[
  49. luaeval('vim.api.nvim_eval([=[
  50. luaeval("vim.api.nvim_eval([[
  51. luaeval(1)
  52. ]])")
  53. ]=])')
  54. ]==])]===]):gsub('\n', ' '))
  55. eq(1, funcs.luaeval(str))
  56. end)
  57. it('correctly converts from API objects', function()
  58. eq(1, funcs.luaeval('vim.api.nvim_eval("1")'))
  59. eq('1', funcs.luaeval([[vim.api.nvim_eval('"1"')]]))
  60. eq({}, funcs.luaeval('vim.api.nvim_eval("[]")'))
  61. eq({}, funcs.luaeval('vim.api.nvim_eval("{}")'))
  62. eq(1, funcs.luaeval('vim.api.nvim_eval("1.0")'))
  63. eq(true, funcs.luaeval('vim.api.nvim_eval("v:true")'))
  64. eq(false, funcs.luaeval('vim.api.nvim_eval("v:false")'))
  65. eq(NIL, funcs.luaeval('vim.api.nvim_eval("v:null")'))
  66. eq(0, eval([[type(luaeval('vim.api.nvim_eval("1")'))]]))
  67. eq(1, eval([[type(luaeval('vim.api.nvim_eval("''1''")'))]]))
  68. eq(3, eval([[type(luaeval('vim.api.nvim_eval("[]")'))]]))
  69. eq(4, eval([[type(luaeval('vim.api.nvim_eval("{}")'))]]))
  70. eq(5, eval([[type(luaeval('vim.api.nvim_eval("1.0")'))]]))
  71. eq(6, eval([[type(luaeval('vim.api.nvim_eval("v:true")'))]]))
  72. eq(6, eval([[type(luaeval('vim.api.nvim_eval("v:false")'))]]))
  73. eq(7, eval([[type(luaeval('vim.api.nvim_eval("v:null")'))]]))
  74. eq({foo=42}, funcs.luaeval([[vim.api.nvim_eval('{"foo": 42}')]]))
  75. eq({42}, funcs.luaeval([[vim.api.nvim_eval('[42]')]]))
  76. eq({foo={bar=42}, baz=50}, funcs.luaeval([[vim.api.nvim_eval('{"foo": {"bar": 42}, "baz": 50}')]]))
  77. eq({{42}, {}}, funcs.luaeval([=[vim.api.nvim_eval('[[42], []]')]=]))
  78. end)
  79. it('correctly converts to API objects', function()
  80. eq(1, funcs.luaeval('vim.api.nvim__id(1)'))
  81. eq('1', funcs.luaeval('vim.api.nvim__id("1")'))
  82. eq({1}, funcs.luaeval('vim.api.nvim__id({1})'))
  83. eq({foo=1}, funcs.luaeval('vim.api.nvim__id({foo=1})'))
  84. eq(1.5, funcs.luaeval('vim.api.nvim__id(1.5)'))
  85. eq(true, funcs.luaeval('vim.api.nvim__id(true)'))
  86. eq(false, funcs.luaeval('vim.api.nvim__id(false)'))
  87. eq(NIL, funcs.luaeval('vim.api.nvim__id(nil)'))
  88. eq(0, eval([[type(luaeval('vim.api.nvim__id(1)'))]]))
  89. eq(1, eval([[type(luaeval('vim.api.nvim__id("1")'))]]))
  90. eq(3, eval([[type(luaeval('vim.api.nvim__id({1})'))]]))
  91. eq(4, eval([[type(luaeval('vim.api.nvim__id({foo=1})'))]]))
  92. eq(5, eval([[type(luaeval('vim.api.nvim__id(1.5)'))]]))
  93. eq(6, eval([[type(luaeval('vim.api.nvim__id(true)'))]]))
  94. eq(6, eval([[type(luaeval('vim.api.nvim__id(false)'))]]))
  95. eq(7, eval([[type(luaeval('vim.api.nvim__id(nil)'))]]))
  96. eq({foo=1, bar={42, {{baz=true}, 5}}}, funcs.luaeval('vim.api.nvim__id({foo=1, bar={42, {{baz=true}, 5}}})'))
  97. end)
  98. it('correctly converts container objects with type_idx to API objects', function()
  99. eq(5, eval('type(luaeval("vim.api.nvim__id({[vim.type_idx]=vim.types.float, [vim.val_idx]=0})"))'))
  100. eq(4, eval([[type(luaeval('vim.api.nvim__id({[vim.type_idx]=vim.types.dictionary})'))]]))
  101. eq(3, eval([[type(luaeval('vim.api.nvim__id({[vim.type_idx]=vim.types.array})'))]]))
  102. eq({}, funcs.luaeval('vim.api.nvim__id({[vim.type_idx]=vim.types.array})'))
  103. -- Presence of type_idx makes Vim ignore some keys
  104. eq({42}, funcs.luaeval('vim.api.nvim__id({[vim.type_idx]=vim.types.array, [vim.val_idx]=10, [5]=1, foo=2, [1]=42})'))
  105. eq({foo=2}, funcs.luaeval('vim.api.nvim__id({[vim.type_idx]=vim.types.dictionary, [vim.val_idx]=10, [5]=1, foo=2, [1]=42})'))
  106. eq(10, funcs.luaeval('vim.api.nvim__id({[vim.type_idx]=vim.types.float, [vim.val_idx]=10, [5]=1, foo=2, [1]=42})'))
  107. eq({}, funcs.luaeval('vim.api.nvim__id({[vim.type_idx]=vim.types.array, [vim.val_idx]=10, [5]=1, foo=2})'))
  108. end)
  109. it('correctly converts arrays with type_idx to API objects', function()
  110. eq(3, eval([[type(luaeval('vim.api.nvim__id_array({[vim.type_idx]=vim.types.array})'))]]))
  111. eq({}, funcs.luaeval('vim.api.nvim__id_array({[vim.type_idx]=vim.types.array})'))
  112. eq({42}, funcs.luaeval('vim.api.nvim__id_array({[vim.type_idx]=vim.types.array, [vim.val_idx]=10, [5]=1, foo=2, [1]=42})'))
  113. eq({{foo=2}}, funcs.luaeval('vim.api.nvim__id_array({{[vim.type_idx]=vim.types.dictionary, [vim.val_idx]=10, [5]=1, foo=2, [1]=42}})'))
  114. eq({10}, funcs.luaeval('vim.api.nvim__id_array({{[vim.type_idx]=vim.types.float, [vim.val_idx]=10, [5]=1, foo=2, [1]=42}})'))
  115. eq({}, funcs.luaeval('vim.api.nvim__id_array({[vim.type_idx]=vim.types.array, [vim.val_idx]=10, [5]=1, foo=2})'))
  116. eq({}, funcs.luaeval('vim.api.nvim__id_array({})'))
  117. eq(3, eval([[type(luaeval('vim.api.nvim__id_array({})'))]]))
  118. end)
  119. it('correctly converts dictionaries with type_idx to API objects', function()
  120. eq(4, eval([[type(luaeval('vim.api.nvim__id_dictionary({[vim.type_idx]=vim.types.dictionary})'))]]))
  121. eq({}, funcs.luaeval('vim.api.nvim__id_dictionary({[vim.type_idx]=vim.types.dictionary})'))
  122. eq({v={42}}, funcs.luaeval('vim.api.nvim__id_dictionary({v={[vim.type_idx]=vim.types.array, [vim.val_idx]=10, [5]=1, foo=2, [1]=42}})'))
  123. eq({foo=2}, funcs.luaeval('vim.api.nvim__id_dictionary({[vim.type_idx]=vim.types.dictionary, [vim.val_idx]=10, [5]=1, foo=2, [1]=42})'))
  124. eq({v=10}, funcs.luaeval('vim.api.nvim__id_dictionary({v={[vim.type_idx]=vim.types.float, [vim.val_idx]=10, [5]=1, foo=2, [1]=42}})'))
  125. eq({v={}}, funcs.luaeval('vim.api.nvim__id_dictionary({v={[vim.type_idx]=vim.types.array, [vim.val_idx]=10, [5]=1, foo=2}})'))
  126. -- If API requests dictionary, then empty table will be the one. This is not
  127. -- the case normally because empty table is an empty arrray.
  128. eq({}, funcs.luaeval('vim.api.nvim__id_dictionary({})'))
  129. eq(4, eval([[type(luaeval('vim.api.nvim__id_dictionary({})'))]]))
  130. end)
  131. it('errors out correctly when working with API', function()
  132. -- Conversion errors
  133. eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [string "<VimL compiled string>"]:1: Cannot convert given lua type',
  134. exc_exec([[call luaeval("vim.api.nvim__id(vim.api.nvim__id)")]]))
  135. eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [string "<VimL compiled string>"]:1: Cannot convert given lua table',
  136. exc_exec([[call luaeval("vim.api.nvim__id({1, foo=42})")]]))
  137. eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [string "<VimL compiled string>"]:1: Cannot convert given lua type',
  138. exc_exec([[call luaeval("vim.api.nvim__id({42, vim.api.nvim__id})")]]))
  139. -- Errors in number of arguments
  140. eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [string "<VimL compiled string>"]:1: Expected 1 argument',
  141. exc_exec([[call luaeval("vim.api.nvim__id()")]]))
  142. eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [string "<VimL compiled string>"]:1: Expected 1 argument',
  143. exc_exec([[call luaeval("vim.api.nvim__id(1, 2)")]]))
  144. eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [string "<VimL compiled string>"]:1: Expected 2 arguments',
  145. exc_exec([[call luaeval("vim.api.nvim_set_var(1, 2, 3)")]]))
  146. -- Error in argument types
  147. eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [string "<VimL compiled string>"]:1: Expected lua string',
  148. exc_exec([[call luaeval("vim.api.nvim_set_var(1, 2)")]]))
  149. eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [string "<VimL compiled string>"]:1: Expected lua number',
  150. exc_exec([[call luaeval("vim.api.nvim_buf_get_lines(0, 'test', 1, false)")]]))
  151. eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [string "<VimL compiled string>"]:1: Number is not integral',
  152. exc_exec([[call luaeval("vim.api.nvim_buf_get_lines(0, 1.5, 1, false)")]]))
  153. eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [string "<VimL compiled string>"]:1: Expected lua table',
  154. exc_exec([[call luaeval("vim.api.nvim__id_float('test')")]]))
  155. eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [string "<VimL compiled string>"]:1: Unexpected type',
  156. exc_exec([[call luaeval("vim.api.nvim__id_float({[vim.type_idx]=vim.types.dictionary})")]]))
  157. eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [string "<VimL compiled string>"]:1: Expected lua table',
  158. exc_exec([[call luaeval("vim.api.nvim__id_array(1)")]]))
  159. eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [string "<VimL compiled string>"]:1: Unexpected type',
  160. exc_exec([[call luaeval("vim.api.nvim__id_array({[vim.type_idx]=vim.types.dictionary})")]]))
  161. eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [string "<VimL compiled string>"]:1: Expected lua table',
  162. exc_exec([[call luaeval("vim.api.nvim__id_dictionary(1)")]]))
  163. eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [string "<VimL compiled string>"]:1: Unexpected type',
  164. exc_exec([[call luaeval("vim.api.nvim__id_dictionary({[vim.type_idx]=vim.types.array})")]]))
  165. -- TODO: check for errors with Tabpage argument
  166. -- TODO: check for errors with Window argument
  167. -- TODO: check for errors with Buffer argument
  168. end)
  169. it('accepts any value as API Boolean', function()
  170. eq('', funcs.luaeval('vim.api.nvim_replace_termcodes("", vim, false, nil)'))
  171. eq('', funcs.luaeval('vim.api.nvim_replace_termcodes("", 0, 1.5, "test")'))
  172. eq('', funcs.luaeval('vim.api.nvim_replace_termcodes("", true, {}, {[vim.type_idx]=vim.types.array})'))
  173. end)
  174. end)