diff options
Diffstat (limited to 'test')
-rw-r--r-- | test/functional/api/vim_spec.lua | 60 | ||||
-rw-r--r-- | test/functional/eval/ctx_functions_spec.lua | 408 | ||||
-rw-r--r-- | test/functional/helpers.lua | 19 |
3 files changed, 487 insertions, 0 deletions
diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index a3d57662b3..110b3a4b16 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -11,6 +11,7 @@ local meth_pcall = helpers.meth_pcall local meths = helpers.meths local ok, nvim_async, feed = helpers.ok, helpers.nvim_async, helpers.feed local os_name = helpers.os_name +local parse_context = helpers.parse_context local request = helpers.request local source = helpers.source local next_msg = helpers.next_msg @@ -680,6 +681,65 @@ describe('API', function() end) end) + describe('nvim_get_context', function() + it('returns context dictionary of current editor state', function() + local ctx_items = {'regs', 'jumps', 'buflist', 'gvars'} + eq({}, parse_context(nvim('get_context', ctx_items))) + + feed('i1<cr>2<cr>3<c-[>ddddddqahjklquuu') + feed('gg') + feed('G') + command('edit! BUF1') + command('edit BUF2') + nvim('set_var', 'one', 1) + nvim('set_var', 'Two', 2) + nvim('set_var', 'THREE', 3) + + local expected_ctx = { + ['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}, + }, + + ['jumps'] = eval(([[ + filter(map(add( + getjumplist()[0], { 'bufnr': bufnr('%'), 'lnum': getcurpos()[1] }), + 'filter( + { "f": expand("#".v:val.bufnr.":p"), "l": v:val.lnum }, + { k, v -> k != "l" || v != 1 })'), '!empty(v:val.f)') + ]]):gsub('\n', '')), + + ['buflist'] = eval([[ + filter(map(getbufinfo(), '{ "f": v:val.name }'), '!empty(v:val.f)') + ]]), + + ['gvars'] = {{'one', 1}, {'Two', 2}, {'THREE', 3}}, + } + + eq(expected_ctx, parse_context(nvim('get_context', ctx_items))) + end) + end) + + describe('nvim_load_context', function() + it('sets current editor state to given context dictionary', function() + local ctx_items = {'regs', 'jumps', 'buflist', 'gvars'} + eq({}, parse_context(nvim('get_context', ctx_items))) + + nvim('set_var', 'one', 1) + nvim('set_var', 'Two', 2) + nvim('set_var', 'THREE', 3) + local ctx = nvim('get_context', ctx_items) + nvim('set_var', 'one', 'a') + nvim('set_var', 'Two', 'b') + nvim('set_var', 'THREE', 'c') + eq({'a', 'b' ,'c'}, eval('[g:one, g:Two, g:THREE]')) + nvim('load_context', ctx) + eq({1, 2 ,3}, eval('[g:one, g:Two, g:THREE]')) + end) + end) + describe('nvim_replace_termcodes', function() it('escapes K_SPECIAL as K_SPECIAL KS_SPECIAL KE_FILLER', function() eq('\128\254X', helpers.nvim('replace_termcodes', '\128', true, true, true)) diff --git a/test/functional/eval/ctx_functions_spec.lua b/test/functional/eval/ctx_functions_spec.lua new file mode 100644 index 0000000000..35133e2341 --- /dev/null +++ b/test/functional/eval/ctx_functions_spec.lua @@ -0,0 +1,408 @@ +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 expect_err = helpers.expect_err +local feed = helpers.feed +local map = helpers.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 + +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 buflist = call('map', call('getbufinfo'), 'v:val.name') + call('ctxpush') + call('ctxpush', {'buflist'}) + + command('%bwipeout') + eq({''}, call('map', call('getbufinfo'), 'v:val.name')) + + call('ctxpop') + eq({'', unpack(buflist)}, call('map', call('getbufinfo'), 'v:val.name')) + + command('%bwipeout') + eq({''}, call('map', call('getbufinfo'), 'v:val.name')) + + call('ctxpop') + eq({'', unpack(buflist)}, 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') + expect_err('E121: Undefined variable: g:one', eval, 'g:one') + expect_err('E121: Undefined variable: g:Two', eval, 'g:Two') + expect_err('E121: Undefined variable: g:THREE', 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') + expect_err('E121: Undefined variable: g:one', eval, 'g:one') + expect_err('E121: Undefined variable: g:Two', eval, 'g:Two') + expect_err('E121: Undefined variable: g:THREE', 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') + + expect_err('Vim:E117: Unknown function: Greet', call, 'Greet', 'World') + expect_err('Vim:E117: Unknown function: Greet', 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' + expect_err(err, call, 'ctxpop') + expect_err(err, call, 'ctxpop') + call('ctxpush') + call('ctxpush') + call('ctxpop') + call('ctxpop') + expect_err(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() + expect_err(outofbounds, call, 'ctxget') + call('ctxpush') + expect_err(outofbounds, call, 'ctxget', 1) + call('ctxpop') + expect_err(outofbounds, 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(add( + getjumplist()[0], { 'bufnr': bufnr('%'), 'lnum': getcurpos()[1] }), + '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_buflist = { + ['buflist'] = 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'], + ['buflist'] = with_buflist['buflist'], + ['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', {'buflist'}) + eq(with_buflist, parse_context(call('ctxget'))) + eq(with_buflist, 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_buflist, 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_buflist, 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_buflist, 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_buflist, parse_context(call('ctxget'))) + eq(with_buflist, 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() + expect_err(outofbounds, call, 'ctxset', {dummy = 1}) + call('ctxpush') + expect_err(outofbounds, call, 'ctxset', {dummy = 1}, 1) + call('ctxpop') + expect_err(outofbounds, 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) diff --git a/test/functional/helpers.lua b/test/functional/helpers.lua index ce7d348747..8223290760 100644 --- a/test/functional/helpers.lua +++ b/test/functional/helpers.lua @@ -13,6 +13,8 @@ local check_cores = global_helpers.check_cores local check_logs = global_helpers.check_logs local dedent = global_helpers.dedent local eq = global_helpers.eq +local filter = global_helpers.filter +local map = global_helpers.map local ok = global_helpers.ok local sleep = global_helpers.sleep local tbl_contains = global_helpers.tbl_contains @@ -763,6 +765,22 @@ local function load_adjust(num) return math.ceil(num * load_factor) end +local function parse_context(ctx) + local parsed = {} + for _, item in ipairs({'regs', 'jumps', 'buflist', 'gvars'}) do + parsed[item] = filter(function(v) + return type(v) == 'table' + end, nvim_call('msgpackparse', ctx[item])) + end + parsed['buflist'] = parsed['buflist'][1] + return map(function(v) + if #v == 0 then + return nil + end + return v + end, parsed) +end + local module = { NIL = mpack.NIL, alter_slashes = alter_slashes, @@ -810,6 +828,7 @@ local module = { nvim_prog_abs = nvim_prog_abs, nvim_set = nvim_set, os_name = os_name, + parse_context = parse_context, pathroot = pathroot, pending_win32 = pending_win32, prepend_argv = prepend_argv, |