neovim

Neovim text editor
git clone https://git.dasho.dev/neovim.git
Log | Files | Refs | README

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)