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