Files
neovim/test/functional/vimscript/ctx_functions_spec.lua
Justin M. Keyes d8de4eb685 test: reorg #15698
Problem:
Subdirectories like "visual", "insert", "normal" encourage people to
separate *related* tests for no good reason.  Typically the _mode_ is
not the relevant topic of a test (and when it is, _then_ create
an appropriate describe() or it()).

Solution:
- Delete the various `test/functional/<mode>/` subdirectories, move
  their tests to more meaningful topics.
- Rename `…/normal/` to `…/editor/`.
  - Move or merge `…/visual/*` and `…/insert/*` tests into here where
    appropriate.
- Rename `…/eval/` to `…/vimscript/`.
  - Move `…/viml/*` into here also.

* test(reorg): insert/* => editor/mode_insert_spec.lua
* test(reorg): cmdline/* => editor/mode_cmdline_spec.lua
* test(reorg): eval core tests => eval_spec.lua
2021-09-17 09:16:40 -07:00

407 lines
12 KiB
Lua

local helpers = require('test.functional.helpers')(after_each)
local call = helpers.call
local clear = helpers.clear
local command = helpers.command
local eq = helpers.eq
local eval = helpers.eval
local feed = helpers.feed
local map = helpers.tbl_map
local nvim = helpers.nvim
local parse_context = helpers.parse_context
local redir_exec = helpers.redir_exec
local source = helpers.source
local trim = helpers.trim
local write_file = helpers.write_file
local pcall_err = helpers.pcall_err
describe('context functions', function()
local fname1 = 'Xtest-functional-eval-ctx1'
local fname2 = 'Xtest-functional-eval-ctx2'
local outofbounds =
'Vim:E475: Invalid value for argument index: out of bounds'
before_each(function()
clear()
write_file(fname1, "1\n2\n3")
write_file(fname2, "a\nb\nc")
end)
after_each(function()
os.remove(fname1)
os.remove(fname2)
end)
describe('ctxpush/ctxpop', function()
it('saves and restores registers properly', function()
local regs = {'1', '2', '3', 'a'}
local vals = {'1', '2', '3', 'hjkl'}
feed('i1<cr>2<cr>3<c-[>ddddddqahjklq')
eq(vals, map(function(r) return trim(call('getreg', r)) end, regs))
call('ctxpush')
call('ctxpush', {'regs'})
map(function(r) call('setreg', r, {}) end, regs)
eq({'', '', '', ''},
map(function(r) return trim(call('getreg', r)) end, regs))
call('ctxpop')
eq(vals, map(function(r) return trim(call('getreg', r)) end, regs))
map(function(r) call('setreg', r, {}) end, regs)
eq({'', '', '', ''},
map(function(r) return trim(call('getreg', r)) end, regs))
call('ctxpop')
eq(vals, map(function(r) return trim(call('getreg', r)) end, regs))
end)
it('saves and restores jumplist properly', function()
command('edit '..fname1)
feed('G')
feed('gg')
command('edit '..fname2)
local jumplist = call('getjumplist')
call('ctxpush')
call('ctxpush', {'jumps'})
command('clearjumps')
eq({{}, 0}, call('getjumplist'))
call('ctxpop')
eq(jumplist, call('getjumplist'))
command('clearjumps')
eq({{}, 0}, call('getjumplist'))
call('ctxpop')
eq(jumplist, call('getjumplist'))
end)
it('saves and restores buffer list properly', function()
command('edit '..fname1)
command('edit '..fname2)
command('edit TEST')
local bufs = call('map', call('getbufinfo'), 'v:val.name')
call('ctxpush')
call('ctxpush', {'bufs'})
command('%bwipeout')
eq({''}, call('map', call('getbufinfo'), 'v:val.name'))
call('ctxpop')
eq({'', unpack(bufs)}, call('map', call('getbufinfo'), 'v:val.name'))
command('%bwipeout')
eq({''}, call('map', call('getbufinfo'), 'v:val.name'))
call('ctxpop')
eq({'', unpack(bufs)}, call('map', call('getbufinfo'), 'v:val.name'))
end)
it('saves and restores global variables properly', function()
nvim('set_var', 'one', 1)
nvim('set_var', 'Two', 2)
nvim('set_var', 'THREE', 3)
eq({1, 2 ,3}, eval('[g:one, g:Two, g:THREE]'))
call('ctxpush')
call('ctxpush', {'gvars'})
nvim('del_var', 'one')
nvim('del_var', 'Two')
nvim('del_var', 'THREE')
eq('Vim:E121: Undefined variable: g:one', pcall_err(eval, 'g:one'))
eq('Vim:E121: Undefined variable: g:Two', pcall_err(eval, 'g:Two'))
eq('Vim:E121: Undefined variable: g:THREE', pcall_err(eval, 'g:THREE'))
call('ctxpop')
eq({1, 2 ,3}, eval('[g:one, g:Two, g:THREE]'))
nvim('del_var', 'one')
nvim('del_var', 'Two')
nvim('del_var', 'THREE')
eq('Vim:E121: Undefined variable: g:one', pcall_err(eval, 'g:one'))
eq('Vim:E121: Undefined variable: g:Two', pcall_err(eval, 'g:Two'))
eq('Vim:E121: Undefined variable: g:THREE', pcall_err(eval, 'g:THREE'))
call('ctxpop')
eq({1, 2 ,3}, eval('[g:one, g:Two, g:THREE]'))
end)
it('saves and restores script functions properly', function()
source([[
function s:greet(name)
echom 'Hello, '.a:name.'!'
endfunction
function s:greet_all(name, ...)
echom 'Hello, '.a:name.'!'
for more in a:000
echom 'Hello, '.more.'!'
endfor
endfunction
function Greet(name)
call call('s:greet', [a:name])
endfunction
function GreetAll(name, ...)
call call('s:greet_all', extend([a:name], a:000))
endfunction
function SaveSFuncs()
call ctxpush(['sfuncs'])
endfunction
function DeleteSFuncs()
delfunction s:greet
delfunction s:greet_all
endfunction
function RestoreFuncs()
call ctxpop()
endfunction
]])
eq('\nHello, World!', redir_exec([[call Greet('World')]]))
eq('\nHello, World!'..
'\nHello, One!'..
'\nHello, Two!'..
'\nHello, Three!',
redir_exec([[call GreetAll('World', 'One', 'Two', 'Three')]]))
call('SaveSFuncs')
call('DeleteSFuncs')
eq('\nError detected while processing function Greet:'..
'\nline 1:'..
'\nE117: Unknown function: s:greet',
redir_exec([[call Greet('World')]]))
eq('\nError detected while processing function GreetAll:'..
'\nline 1:'..
'\nE117: Unknown function: s:greet_all',
redir_exec([[call GreetAll('World', 'One', 'Two', 'Three')]]))
call('RestoreFuncs')
eq('\nHello, World!', redir_exec([[call Greet('World')]]))
eq('\nHello, World!'..
'\nHello, One!'..
'\nHello, Two!'..
'\nHello, Three!',
redir_exec([[call GreetAll('World', 'One', 'Two', 'Three')]]))
end)
it('saves and restores functions properly', function()
source([[
function Greet(name)
echom 'Hello, '.a:name.'!'
endfunction
function GreetAll(name, ...)
echom 'Hello, '.a:name.'!'
for more in a:000
echom 'Hello, '.more.'!'
endfor
endfunction
]])
eq('\nHello, World!', redir_exec([[call Greet('World')]]))
eq('\nHello, World!'..
'\nHello, One!'..
'\nHello, Two!'..
'\nHello, Three!',
redir_exec([[call GreetAll('World', 'One', 'Two', 'Three')]]))
call('ctxpush', {'funcs'})
command('delfunction Greet')
command('delfunction GreetAll')
eq('Vim:E117: Unknown function: Greet', pcall_err(call, 'Greet', 'World'))
eq('Vim:E117: Unknown function: GreetAll',
pcall_err(call, 'GreetAll', 'World', 'One', 'Two', 'Three'))
call('ctxpop')
eq('\nHello, World!', redir_exec([[call Greet('World')]]))
eq('\nHello, World!'..
'\nHello, One!'..
'\nHello, Two!'..
'\nHello, Three!',
redir_exec([[call GreetAll('World', 'One', 'Two', 'Three')]]))
end)
it('errors out when context stack is empty', function()
local err = 'Vim:Context stack is empty'
eq(err, pcall_err(call, 'ctxpop'))
eq(err, pcall_err(call, 'ctxpop'))
call('ctxpush')
call('ctxpush')
call('ctxpop')
call('ctxpop')
eq(err, pcall_err(call, 'ctxpop'))
end)
end)
describe('ctxsize()', function()
it('returns context stack size', function()
eq(0, call('ctxsize'))
call('ctxpush')
eq(1, call('ctxsize'))
call('ctxpush')
eq(2, call('ctxsize'))
call('ctxpush')
eq(3, call('ctxsize'))
call('ctxpop')
eq(2, call('ctxsize'))
call('ctxpop')
eq(1, call('ctxsize'))
call('ctxpop')
eq(0, call('ctxsize'))
end)
end)
describe('ctxget()', function()
it('errors out when index is out of bounds', function()
eq(outofbounds, pcall_err(call, 'ctxget'))
call('ctxpush')
eq(outofbounds, pcall_err(call, 'ctxget', 1))
call('ctxpop')
eq(outofbounds, pcall_err(call, 'ctxget', 0))
end)
it('returns context dictionary at index in context stack', function()
feed('i1<cr>2<cr>3<c-[>ddddddqahjklq')
command('edit! '..fname1)
feed('G')
feed('gg')
command('edit '..fname2)
nvim('set_var', 'one', 1)
nvim('set_var', 'Two', 2)
nvim('set_var', 'THREE', 3)
local with_regs = {
['regs'] = {
{['rt'] = 1, ['rc'] = {'1'}, ['n'] = 49, ['ru'] = true},
{['rt'] = 1, ['rc'] = {'2'}, ['n'] = 50},
{['rt'] = 1, ['rc'] = {'3'}, ['n'] = 51},
{['rc'] = {'hjkl'}, ['n'] = 97},
}
}
local with_jumps = {
['jumps'] = eval(([[
filter(map(getjumplist()[0], 'filter(
{ "f": expand("#".v:val.bufnr.":p"), "l": v:val.lnum },
{ k, v -> k != "l" || v != 1 })'), '!empty(v:val.f)')
]]):gsub('\n', ''))
}
local with_bufs = {
['bufs'] = eval([[
filter(map(getbufinfo(), '{ "f": v:val.name }'), '!empty(v:val.f)')
]])
}
local with_gvars = {
['gvars'] = {{'one', 1}, {'Two', 2}, {'THREE', 3}}
}
local with_all = {
['regs'] = with_regs['regs'],
['jumps'] = with_jumps['jumps'],
['bufs'] = with_bufs['bufs'],
['gvars'] = with_gvars['gvars'],
}
call('ctxpush')
eq(with_all, parse_context(call('ctxget')))
eq(with_all, parse_context(call('ctxget', 0)))
call('ctxpush', {'gvars'})
eq(with_gvars, parse_context(call('ctxget')))
eq(with_gvars, parse_context(call('ctxget', 0)))
eq(with_all, parse_context(call('ctxget', 1)))
call('ctxpush', {'bufs'})
eq(with_bufs, parse_context(call('ctxget')))
eq(with_bufs, parse_context(call('ctxget', 0)))
eq(with_gvars, parse_context(call('ctxget', 1)))
eq(with_all, parse_context(call('ctxget', 2)))
call('ctxpush', {'jumps'})
eq(with_jumps, parse_context(call('ctxget')))
eq(with_jumps, parse_context(call('ctxget', 0)))
eq(with_bufs, parse_context(call('ctxget', 1)))
eq(with_gvars, parse_context(call('ctxget', 2)))
eq(with_all, parse_context(call('ctxget', 3)))
call('ctxpush', {'regs'})
eq(with_regs, parse_context(call('ctxget')))
eq(with_regs, parse_context(call('ctxget', 0)))
eq(with_jumps, parse_context(call('ctxget', 1)))
eq(with_bufs, parse_context(call('ctxget', 2)))
eq(with_gvars, parse_context(call('ctxget', 3)))
eq(with_all, parse_context(call('ctxget', 4)))
call('ctxpop')
eq(with_jumps, parse_context(call('ctxget')))
eq(with_jumps, parse_context(call('ctxget', 0)))
eq(with_bufs, parse_context(call('ctxget', 1)))
eq(with_gvars, parse_context(call('ctxget', 2)))
eq(with_all, parse_context(call('ctxget', 3)))
call('ctxpop')
eq(with_bufs, parse_context(call('ctxget')))
eq(with_bufs, parse_context(call('ctxget', 0)))
eq(with_gvars, parse_context(call('ctxget', 1)))
eq(with_all, parse_context(call('ctxget', 2)))
call('ctxpop')
eq(with_gvars, parse_context(call('ctxget')))
eq(with_gvars, parse_context(call('ctxget', 0)))
eq(with_all, parse_context(call('ctxget', 1)))
call('ctxpop')
eq(with_all, parse_context(call('ctxget')))
eq(with_all, parse_context(call('ctxget', 0)))
end)
end)
describe('ctxset()', function()
it('errors out when index is out of bounds', function()
eq(outofbounds, pcall_err(call, 'ctxset', {dummy = 1}))
call('ctxpush')
eq(outofbounds, pcall_err(call, 'ctxset', {dummy = 1}, 1))
call('ctxpop')
eq(outofbounds, pcall_err(call, 'ctxset', {dummy = 1}, 0))
end)
it('sets context dictionary at index in context stack', function()
nvim('set_var', 'one', 1)
nvim('set_var', 'Two', 2)
nvim('set_var', 'THREE', 3)
call('ctxpush')
local ctx1 = call('ctxget')
nvim('set_var', 'one', 'a')
nvim('set_var', 'Two', 'b')
nvim('set_var', 'THREE', 'c')
call('ctxpush')
call('ctxpush')
local ctx2 = call('ctxget')
eq({'a', 'b' ,'c'}, eval('[g:one, g:Two, g:THREE]'))
call('ctxset', ctx1)
call('ctxset', ctx2, 2)
call('ctxpop')
eq({1, 2 ,3}, eval('[g:one, g:Two, g:THREE]'))
call('ctxpop')
eq({'a', 'b' ,'c'}, eval('[g:one, g:Two, g:THREE]'))
nvim('set_var', 'one', 1.5)
eq({1.5, 'b' ,'c'}, eval('[g:one, g:Two, g:THREE]'))
call('ctxpop')
eq({'a', 'b' ,'c'}, eval('[g:one, g:Two, g:THREE]'))
end)
end)
end)