buf_functions_spec.lua 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  1. local helpers = require('test.functional.helpers')(after_each)
  2. local lfs = require('lfs')
  3. local eq = helpers.eq
  4. local clear = helpers.clear
  5. local funcs = helpers.funcs
  6. local meths = helpers.meths
  7. local command = helpers.command
  8. local exc_exec = helpers.exc_exec
  9. local bufmeths = helpers.bufmeths
  10. local winmeths = helpers.winmeths
  11. local curbufmeths = helpers.curbufmeths
  12. local curwinmeths = helpers.curwinmeths
  13. local curtabmeths = helpers.curtabmeths
  14. local get_pathsep = helpers.get_pathsep
  15. local rmdir = helpers.rmdir
  16. local pcall_err = helpers.pcall_err
  17. local fname = 'Xtest-functional-eval-buf_functions'
  18. local fname2 = fname .. '.2'
  19. local dirname = fname .. '.d'
  20. before_each(clear)
  21. for _, func in ipairs({'bufname(%s)', 'bufnr(%s)', 'bufwinnr(%s)',
  22. 'getbufline(%s, 1)', 'getbufvar(%s, "changedtick")',
  23. 'setbufvar(%s, "f", 0)'}) do
  24. local funcname = func:match('%w+')
  25. describe(funcname .. '() function', function()
  26. it('errors out when receives v:true/v:false/v:null', function()
  27. -- Not compatible with Vim: in Vim it always results in buffer not found
  28. -- without any error messages.
  29. for _, var in ipairs({'v:true', 'v:false'}) do
  30. eq('Vim(call):E5299: Expected a Number or a String, Boolean found',
  31. exc_exec('call ' .. func:format(var)))
  32. end
  33. eq('Vim(call):E5300: Expected a Number or a String',
  34. exc_exec('call ' .. func:format('v:null')))
  35. end)
  36. it('errors out when receives invalid argument', function()
  37. eq('Vim(call):E745: Expected a Number or a String, List found',
  38. exc_exec('call ' .. func:format('[]')))
  39. eq('Vim(call):E728: Expected a Number or a String, Dictionary found',
  40. exc_exec('call ' .. func:format('{}')))
  41. eq('Vim(call):E805: Expected a Number or a String, Float found',
  42. exc_exec('call ' .. func:format('0.0')))
  43. eq('Vim(call):E703: Expected a Number or a String, Funcref found',
  44. exc_exec('call ' .. func:format('function("tr")')))
  45. end)
  46. end)
  47. end
  48. describe('bufname() function', function()
  49. it('returns empty string when buffer was not found', function()
  50. command('file ' .. fname)
  51. eq('', funcs.bufname(2))
  52. eq('', funcs.bufname('non-existent-buffer'))
  53. eq('', funcs.bufname('#'))
  54. command('edit ' .. fname2)
  55. eq(2, funcs.bufnr('%'))
  56. eq('', funcs.bufname('X'))
  57. end)
  58. before_each(function()
  59. lfs.mkdir(dirname)
  60. end)
  61. after_each(function()
  62. rmdir(dirname)
  63. end)
  64. it('returns expected buffer name', function()
  65. eq('', funcs.bufname('%')) -- Buffer has no name yet
  66. command('file ' .. fname)
  67. local wd = lfs.currentdir()
  68. local sep = get_pathsep()
  69. local curdirname = funcs.fnamemodify(wd, ':t')
  70. for _, arg in ipairs({'%', 1, 'X', wd}) do
  71. eq(fname, funcs.bufname(arg))
  72. meths.set_current_dir('..')
  73. eq(curdirname .. sep .. fname, funcs.bufname(arg))
  74. meths.set_current_dir(curdirname)
  75. meths.set_current_dir(dirname)
  76. eq(wd .. sep .. fname, funcs.bufname(arg))
  77. meths.set_current_dir('..')
  78. eq(fname, funcs.bufname(arg))
  79. command('enew')
  80. end
  81. eq('', funcs.bufname('%'))
  82. eq('', funcs.bufname('$'))
  83. eq(2, funcs.bufnr('%'))
  84. end)
  85. end)
  86. describe('bufnr() function', function()
  87. it('returns -1 when buffer was not found', function()
  88. command('file ' .. fname)
  89. eq(-1, funcs.bufnr(2))
  90. eq(-1, funcs.bufnr('non-existent-buffer'))
  91. eq(-1, funcs.bufnr('#'))
  92. command('edit ' .. fname2)
  93. eq(2, funcs.bufnr('%'))
  94. eq(-1, funcs.bufnr('X'))
  95. end)
  96. it('returns expected buffer number', function()
  97. eq(1, funcs.bufnr('%'))
  98. command('file ' .. fname)
  99. local wd = lfs.currentdir()
  100. local curdirname = funcs.fnamemodify(wd, ':t')
  101. eq(1, funcs.bufnr(fname))
  102. eq(1, funcs.bufnr(wd))
  103. eq(1, funcs.bufnr(curdirname))
  104. eq(1, funcs.bufnr('X'))
  105. end)
  106. it('returns number of last buffer with "$"', function()
  107. eq(1, funcs.bufnr('$'))
  108. command('new')
  109. eq(2, funcs.bufnr('$'))
  110. command('new')
  111. eq(3, funcs.bufnr('$'))
  112. command('only')
  113. eq(3, funcs.bufnr('$'))
  114. eq(3, funcs.bufnr('%'))
  115. command('buffer 1')
  116. eq(3, funcs.bufnr('$'))
  117. eq(1, funcs.bufnr('%'))
  118. command('bwipeout 2')
  119. eq(3, funcs.bufnr('$'))
  120. eq(1, funcs.bufnr('%'))
  121. command('bwipeout 3')
  122. eq(1, funcs.bufnr('$'))
  123. eq(1, funcs.bufnr('%'))
  124. command('new')
  125. eq(4, funcs.bufnr('$'))
  126. end)
  127. end)
  128. describe('bufwinnr() function', function()
  129. it('returns -1 when buffer was not found', function()
  130. command('file ' .. fname)
  131. eq(-1, funcs.bufwinnr(2))
  132. eq(-1, funcs.bufwinnr('non-existent-buffer'))
  133. eq(-1, funcs.bufwinnr('#'))
  134. command('split ' .. fname2) -- It would be OK if there was one window
  135. eq(2, funcs.bufnr('%'))
  136. eq(-1, funcs.bufwinnr('X'))
  137. end)
  138. before_each(function()
  139. lfs.mkdir(dirname)
  140. end)
  141. after_each(function()
  142. rmdir(dirname)
  143. end)
  144. it('returns expected window number', function()
  145. eq(1, funcs.bufwinnr('%'))
  146. command('file ' .. fname)
  147. command('vsplit')
  148. command('split ' .. fname2)
  149. eq(2, funcs.bufwinnr(fname))
  150. eq(1, funcs.bufwinnr(fname2))
  151. eq(-1, funcs.bufwinnr(fname:sub(1, #fname - 1)))
  152. meths.set_current_dir(dirname)
  153. eq(2, funcs.bufwinnr(fname))
  154. eq(1, funcs.bufwinnr(fname2))
  155. eq(-1, funcs.bufwinnr(fname:sub(1, #fname - 1)))
  156. eq(1, funcs.bufwinnr('%'))
  157. eq(2, funcs.bufwinnr(1))
  158. eq(1, funcs.bufwinnr(2))
  159. eq(-1, funcs.bufwinnr(3))
  160. eq(1, funcs.bufwinnr('$'))
  161. end)
  162. end)
  163. describe('getbufline() function', function()
  164. it('returns empty list when buffer was not found', function()
  165. command('file ' .. fname)
  166. eq({}, funcs.getbufline(2, 1))
  167. eq({}, funcs.getbufline('non-existent-buffer', 1))
  168. eq({}, funcs.getbufline('#', 1))
  169. command('edit ' .. fname2)
  170. eq(2, funcs.bufnr('%'))
  171. eq({}, funcs.getbufline('X', 1))
  172. end)
  173. it('returns empty list when range is invalid', function()
  174. eq({}, funcs.getbufline(1, 0))
  175. curbufmeths.set_lines(0, 1, false, {'foo', 'bar', 'baz'})
  176. eq({}, funcs.getbufline(1, 2, 1))
  177. eq({}, funcs.getbufline(1, -10, -20))
  178. eq({}, funcs.getbufline(1, -2, -1))
  179. eq({}, funcs.getbufline(1, -1, 9999))
  180. end)
  181. it('returns expected lines', function()
  182. meths.set_option('hidden', true)
  183. command('file ' .. fname)
  184. curbufmeths.set_lines(0, 1, false, {'foo\0', '\0bar', 'baz'})
  185. command('edit ' .. fname2)
  186. curbufmeths.set_lines(0, 1, false, {'abc\0', '\0def', 'ghi'})
  187. eq({'foo\n', '\nbar', 'baz'}, funcs.getbufline(1, 1, 9999))
  188. eq({'abc\n', '\ndef', 'ghi'}, funcs.getbufline(2, 1, 9999))
  189. eq({'foo\n', '\nbar', 'baz'}, funcs.getbufline(1, 1, '$'))
  190. eq({'baz'}, funcs.getbufline(1, '$', '$'))
  191. eq({'baz'}, funcs.getbufline(1, '$', 9999))
  192. end)
  193. end)
  194. describe('getbufvar() function', function()
  195. it('returns empty list when buffer was not found', function()
  196. command('file ' .. fname)
  197. eq('', funcs.getbufvar(2, '&autoindent'))
  198. eq('', funcs.getbufvar('non-existent-buffer', '&autoindent'))
  199. eq('', funcs.getbufvar('#', '&autoindent'))
  200. command('edit ' .. fname2)
  201. eq(2, funcs.bufnr('%'))
  202. eq('', funcs.getbufvar('X', '&autoindent'))
  203. end)
  204. it('returns empty list when variable/option/etc was not found', function()
  205. command('file ' .. fname)
  206. eq('', funcs.getbufvar(1, '&autondent'))
  207. eq('', funcs.getbufvar(1, 'changedtic'))
  208. end)
  209. it('returns expected option value', function()
  210. eq(0, funcs.getbufvar(1, '&autoindent'))
  211. eq(0, funcs.getbufvar(1, '&l:autoindent'))
  212. eq(0, funcs.getbufvar(1, '&g:autoindent'))
  213. -- Also works with global-only options
  214. eq(1, funcs.getbufvar(1, '&hidden'))
  215. eq(1, funcs.getbufvar(1, '&l:hidden'))
  216. eq(1, funcs.getbufvar(1, '&g:hidden'))
  217. -- Also works with window-local options
  218. eq(0, funcs.getbufvar(1, '&number'))
  219. eq(0, funcs.getbufvar(1, '&l:number'))
  220. eq(0, funcs.getbufvar(1, '&g:number'))
  221. command('new')
  222. -- But with window-local options it probably does not what you expect
  223. command("setl number")
  224. -- (note that current window’s buffer is 2, but getbufvar() receives 1)
  225. eq({id=2}, curwinmeths.get_buf())
  226. eq(1, funcs.getbufvar(1, '&number'))
  227. eq(1, funcs.getbufvar(1, '&l:number'))
  228. -- You can get global value though, if you find this useful.
  229. eq(0, funcs.getbufvar(1, '&g:number'))
  230. end)
  231. it('returns expected variable value', function()
  232. eq(2, funcs.getbufvar(1, 'changedtick'))
  233. curbufmeths.set_lines(0, 1, false, {'abc\0', '\0def', 'ghi'})
  234. eq(3, funcs.getbufvar(1, 'changedtick'))
  235. curbufmeths.set_var('test', true)
  236. eq(true, funcs.getbufvar(1, 'test'))
  237. eq({test=true, changedtick=3}, funcs.getbufvar(1, ''))
  238. command('new')
  239. eq(3, funcs.getbufvar(1, 'changedtick'))
  240. eq(true, funcs.getbufvar(1, 'test'))
  241. eq({test=true, changedtick=3}, funcs.getbufvar(1, ''))
  242. end)
  243. end)
  244. describe('setbufvar() function', function()
  245. it('throws the error or ignores the input when buffer was not found', function()
  246. command('file ' .. fname)
  247. eq(0,
  248. exc_exec('call setbufvar(2, "&autoindent", 0)'))
  249. eq('Vim(call):E94: No matching buffer for non-existent-buffer',
  250. exc_exec('call setbufvar("non-existent-buffer", "&autoindent", 0)'))
  251. eq(0,
  252. exc_exec('call setbufvar("#", "&autoindent", 0)'))
  253. command('edit ' .. fname2)
  254. eq(2, funcs.bufnr('%'))
  255. eq('Vim(call):E93: More than one match for X',
  256. exc_exec('call setbufvar("X", "&autoindent", 0)'))
  257. end)
  258. it('may set options, including window-local and global values', function()
  259. local buf1 = meths.get_current_buf()
  260. eq(false, curwinmeths.get_option('number'))
  261. command('split')
  262. command('new')
  263. eq(2, bufmeths.get_number(curwinmeths.get_buf()))
  264. funcs.setbufvar(1, '&number', true)
  265. local windows = curtabmeths.list_wins()
  266. eq(false, winmeths.get_option(windows[1], 'number'))
  267. eq(true, winmeths.get_option(windows[2], 'number'))
  268. eq(false, winmeths.get_option(windows[3], 'number'))
  269. eq(false, winmeths.get_option(meths.get_current_win(), 'number'))
  270. eq(true, meths.get_option('hidden'))
  271. funcs.setbufvar(1, '&hidden', 0)
  272. eq(false, meths.get_option('hidden'))
  273. eq(false, bufmeths.get_option(buf1, 'autoindent'))
  274. funcs.setbufvar(1, '&autoindent', true)
  275. eq(true, bufmeths.get_option(buf1, 'autoindent'))
  276. eq('Vim(call):E355: Unknown option: xxx',
  277. exc_exec('call setbufvar(1, "&xxx", 0)'))
  278. end)
  279. it('may set variables', function()
  280. local buf1 = meths.get_current_buf()
  281. command('split')
  282. command('new')
  283. eq(2, curbufmeths.get_number())
  284. funcs.setbufvar(1, 'number', true)
  285. eq(true, bufmeths.get_var(buf1, 'number'))
  286. eq('Vim(call):E461: Illegal variable name: b:',
  287. exc_exec('call setbufvar(1, "", 0)'))
  288. eq(true, bufmeths.get_var(buf1, 'number'))
  289. eq('Vim:E46: Cannot change read-only variable "b:changedtick"',
  290. pcall_err(funcs.setbufvar, 1, 'changedtick', true))
  291. eq(2, funcs.getbufvar(1, 'changedtick'))
  292. end)
  293. end)