aboutsummaryrefslogtreecommitdiff
path: root/test/functional/eval
diff options
context:
space:
mode:
authorZyX <kp-pav@yandex.ru>2017-12-03 16:49:30 +0300
committerZyX <kp-pav@yandex.ru>2017-12-03 16:49:30 +0300
commitc49e22d3964d6c7ae1c24e8ad01b5fec4ca40b57 (patch)
treeb7e59c416d1435725c65f8952b6e55c70544d97e /test/functional/eval
parent62108c3b0be46936c83f6d4c98b44ceb5e6f77fd (diff)
parent27a577586eace687c47e7398845178208cae524a (diff)
downloadrneovim-c49e22d3964d6c7ae1c24e8ad01b5fec4ca40b57.tar.gz
rneovim-c49e22d3964d6c7ae1c24e8ad01b5fec4ca40b57.tar.bz2
rneovim-c49e22d3964d6c7ae1c24e8ad01b5fec4ca40b57.zip
Merge branch 'master' into s-dash-stdin
Diffstat (limited to 'test/functional/eval')
-rw-r--r--test/functional/eval/api_functions_spec.lua24
-rw-r--r--test/functional/eval/buf_functions_spec.lua302
-rw-r--r--test/functional/eval/container_functions_spec.lua24
-rw-r--r--test/functional/eval/function_spec.lua29
-rw-r--r--test/functional/eval/glob_spec.lua4
-rw-r--r--test/functional/eval/hostname_spec.lua17
-rw-r--r--test/functional/eval/input_spec.lua440
-rw-r--r--test/functional/eval/json_functions_spec.lua110
-rw-r--r--test/functional/eval/map_functions_spec.lua159
-rw-r--r--test/functional/eval/match_functions_spec.lua61
-rw-r--r--test/functional/eval/minmax_functions_spec.lua51
-rw-r--r--test/functional/eval/modeline_spec.lua4
-rw-r--r--test/functional/eval/msgpack_functions_spec.lua157
-rw-r--r--test/functional/eval/null_spec.lua138
-rw-r--r--test/functional/eval/reltime_spec.lua4
-rw-r--r--test/functional/eval/server_spec.lua57
-rw-r--r--test/functional/eval/setpos_spec.lua9
-rw-r--r--test/functional/eval/sort_spec.lua41
-rw-r--r--test/functional/eval/special_vars_spec.lua13
-rw-r--r--test/functional/eval/string_spec.lua10
-rw-r--r--test/functional/eval/system_spec.lua126
-rw-r--r--test/functional/eval/timer_spec.lua28
-rw-r--r--test/functional/eval/writefile_spec.lua9
23 files changed, 1601 insertions, 216 deletions
diff --git a/test/functional/eval/api_functions_spec.lua b/test/functional/eval/api_functions_spec.lua
index 21dd228145..fea4a87a26 100644
--- a/test/functional/eval/api_functions_spec.lua
+++ b/test/functional/eval/api_functions_spec.lua
@@ -1,7 +1,7 @@
local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen')
local lfs = require('lfs')
-local neq, eq, execute = helpers.neq, helpers.eq, helpers.execute
+local neq, eq, command = helpers.neq, helpers.eq, helpers.command
local clear, curbufmeths = helpers.clear, helpers.curbufmeths
local exc_exec, expect, eval = helpers.exc_exec, helpers.expect, helpers.eval
local insert = helpers.insert
@@ -10,17 +10,17 @@ describe('api functions', function()
before_each(clear)
it("work", function()
- execute("call nvim_command('let g:test = 1')")
+ command("call nvim_command('let g:test = 1')")
eq(1, eval("nvim_get_var('test')"))
local buf = eval("nvim_get_current_buf()")
- execute("call nvim_buf_set_lines("..buf..", 0, -1, v:true, ['aa', 'bb'])")
+ command("call nvim_buf_set_lines("..buf..", 0, -1, v:true, ['aa', 'bb'])")
expect([[
aa
bb]])
- execute("call nvim_win_set_cursor(0, [1, 1])")
- execute("call nvim_input('ax<esc>')")
+ command("call nvim_win_set_cursor(0, [1, 1])")
+ command("call nvim_input('ax<esc>')")
expect([[
aax
bb]])
@@ -57,7 +57,7 @@ describe('api functions', function()
eq(bnr, bhnd)
eq(wid, whnd)
- execute("new") -- creates new buffer and new window
+ command("new") -- creates new buffer and new window
local bnr2 = eval("bufnr('')")
local bhnd2 = eval("nvim_get_current_buf()")
local wid2 = eval("win_getid()")
@@ -69,7 +69,7 @@ describe('api functions', function()
-- 0 is synonymous to the current buffer
eq(bnr2, eval("nvim_buf_get_number(0)"))
- execute("bn") -- show old buffer in new window
+ command("bn") -- show old buffer in new window
eq(bnr, eval("nvim_get_current_buf()"))
eq(bnr, eval("bufnr('')"))
eq(bnr, eval("nvim_buf_get_number(0)"))
@@ -81,7 +81,7 @@ describe('api functions', function()
curbufmeths.set_lines(0, -1, true, {"aa\0", "b\0b"})
eq({'aa\n', 'b\nb'}, eval("nvim_buf_get_lines(0, 0, -1, 1)"))
- execute('call nvim_buf_set_lines(0, 1, 2, v:true, ["xx", "\\nyy"])')
+ command('call nvim_buf_set_lines(0, 1, 2, v:true, ["xx", "\\nyy"])')
eq({'aa\0', 'xx', '\0yy'}, curbufmeths.get_lines(0, -1, 1))
end)
@@ -106,7 +106,7 @@ describe('api functions', function()
it('have metadata accessible with api_info()', function()
local api_keys = eval("sort(keys(api_info()))")
- eq({'error_types', 'functions', 'types', 'version'}, api_keys)
+ eq({'error_types', 'functions', 'types', 'ui_events', 'version'}, api_keys)
end)
it('are highlighted by vim.vim syntax file', function()
@@ -124,9 +124,9 @@ describe('api functions', function()
[5] = {bold = true, foreground = Screen.colors.Blue},
})
- execute("set ft=vim")
- execute("let &rtp='build/runtime/,'.&rtp")
- execute("syntax on")
+ command("set ft=vim")
+ command("let &rtp='build/runtime/,'.&rtp")
+ command("syntax on")
insert([[
call bufnr('%')
call nvim_input('typing...')
diff --git a/test/functional/eval/buf_functions_spec.lua b/test/functional/eval/buf_functions_spec.lua
new file mode 100644
index 0000000000..db50874c53
--- /dev/null
+++ b/test/functional/eval/buf_functions_spec.lua
@@ -0,0 +1,302 @@
+local helpers = require('test.functional.helpers')(after_each)
+
+local lfs = require('lfs')
+
+local eq = helpers.eq
+local clear = helpers.clear
+local funcs = helpers.funcs
+local meths = helpers.meths
+local command = helpers.command
+local exc_exec = helpers.exc_exec
+local bufmeths = helpers.bufmeths
+local winmeths = helpers.winmeths
+local curbufmeths = helpers.curbufmeths
+local curwinmeths = helpers.curwinmeths
+local curtabmeths = helpers.curtabmeths
+local get_pathsep = helpers.get_pathsep
+
+local fname = 'Xtest-functional-eval-buf_functions'
+local fname2 = fname .. '.2'
+local dirname = fname .. '.d'
+
+before_each(clear)
+
+for _, func in ipairs({'bufname(%s)', 'bufnr(%s)', 'bufwinnr(%s)',
+ 'getbufline(%s, 1)', 'getbufvar(%s, "changedtick")',
+ 'setbufvar(%s, "f", 0)'}) do
+ local funcname = func:match('%w+')
+ describe(funcname .. '() function', function()
+ it('errors out when receives v:true/v:false/v:null', function()
+ -- Not compatible with Vim: in Vim it always results in buffer not found
+ -- without any error messages.
+ for _, var in ipairs({'v:true', 'v:false', 'v:null'}) do
+ eq('Vim(call):E5300: Expected a Number or a String',
+ exc_exec('call ' .. func:format(var)))
+ end
+ end)
+ it('errors out when receives invalid argument', function()
+ eq('Vim(call):E745: Expected a Number or a String, List found',
+ exc_exec('call ' .. func:format('[]')))
+ eq('Vim(call):E728: Expected a Number or a String, Dictionary found',
+ exc_exec('call ' .. func:format('{}')))
+ eq('Vim(call):E805: Expected a Number or a String, Float found',
+ exc_exec('call ' .. func:format('0.0')))
+ eq('Vim(call):E703: Expected a Number or a String, Funcref found',
+ exc_exec('call ' .. func:format('function("tr")')))
+ end)
+ end)
+end
+
+describe('bufname() function', function()
+ it('returns empty string when buffer was not found', function()
+ command('file ' .. fname)
+ eq('', funcs.bufname(2))
+ eq('', funcs.bufname('non-existent-buffer'))
+ eq('', funcs.bufname('#'))
+ command('edit ' .. fname2)
+ eq(2, funcs.bufnr('%'))
+ eq('', funcs.bufname('X'))
+ end)
+ before_each(function()
+ lfs.mkdir(dirname)
+ end)
+ after_each(function()
+ lfs.rmdir(dirname)
+ end)
+ it('returns expected buffer name', function()
+ eq('', funcs.bufname('%')) -- Buffer has no name yet
+ command('file ' .. fname)
+ local wd = lfs.currentdir()
+ local sep = get_pathsep()
+ local curdirname = funcs.fnamemodify(wd, ':t')
+ for _, arg in ipairs({'%', 1, 'X', wd}) do
+ eq(fname, funcs.bufname(arg))
+ meths.set_current_dir('..')
+ eq(curdirname .. sep .. fname, funcs.bufname(arg))
+ meths.set_current_dir(curdirname)
+ meths.set_current_dir(dirname)
+ eq(wd .. sep .. fname, funcs.bufname(arg))
+ meths.set_current_dir('..')
+ eq(fname, funcs.bufname(arg))
+ command('enew')
+ end
+ eq('', funcs.bufname('%'))
+ eq('', funcs.bufname('$'))
+ eq(2, funcs.bufnr('%'))
+ end)
+end)
+
+describe('bufnr() function', function()
+ it('returns -1 when buffer was not found', function()
+ command('file ' .. fname)
+ eq(-1, funcs.bufnr(2))
+ eq(-1, funcs.bufnr('non-existent-buffer'))
+ eq(-1, funcs.bufnr('#'))
+ command('edit ' .. fname2)
+ eq(2, funcs.bufnr('%'))
+ eq(-1, funcs.bufnr('X'))
+ end)
+ it('returns expected buffer number', function()
+ eq(1, funcs.bufnr('%'))
+ command('file ' .. fname)
+ local wd = lfs.currentdir()
+ local curdirname = funcs.fnamemodify(wd, ':t')
+ eq(1, funcs.bufnr(fname))
+ eq(1, funcs.bufnr(wd))
+ eq(1, funcs.bufnr(curdirname))
+ eq(1, funcs.bufnr('X'))
+ end)
+ it('returns number of last buffer with "$"', function()
+ eq(1, funcs.bufnr('$'))
+ command('new')
+ eq(2, funcs.bufnr('$'))
+ command('new')
+ eq(3, funcs.bufnr('$'))
+ command('only')
+ eq(3, funcs.bufnr('$'))
+ eq(3, funcs.bufnr('%'))
+ command('buffer 1')
+ eq(3, funcs.bufnr('$'))
+ eq(1, funcs.bufnr('%'))
+ command('bwipeout 2')
+ eq(3, funcs.bufnr('$'))
+ eq(1, funcs.bufnr('%'))
+ command('bwipeout 3')
+ eq(1, funcs.bufnr('$'))
+ eq(1, funcs.bufnr('%'))
+ command('new')
+ eq(4, funcs.bufnr('$'))
+ end)
+end)
+
+describe('bufwinnr() function', function()
+ it('returns -1 when buffer was not found', function()
+ command('file ' .. fname)
+ eq(-1, funcs.bufwinnr(2))
+ eq(-1, funcs.bufwinnr('non-existent-buffer'))
+ eq(-1, funcs.bufwinnr('#'))
+ command('split ' .. fname2) -- It would be OK if there was one window
+ eq(2, funcs.bufnr('%'))
+ eq(-1, funcs.bufwinnr('X'))
+ end)
+ before_each(function()
+ lfs.mkdir(dirname)
+ end)
+ after_each(function()
+ lfs.rmdir(dirname)
+ end)
+ it('returns expected window number', function()
+ eq(1, funcs.bufwinnr('%'))
+ command('file ' .. fname)
+ command('vsplit')
+ command('split ' .. fname2)
+ eq(2, funcs.bufwinnr(fname))
+ eq(1, funcs.bufwinnr(fname2))
+ eq(-1, funcs.bufwinnr(fname:sub(1, #fname - 1)))
+ meths.set_current_dir(dirname)
+ eq(2, funcs.bufwinnr(fname))
+ eq(1, funcs.bufwinnr(fname2))
+ eq(-1, funcs.bufwinnr(fname:sub(1, #fname - 1)))
+ eq(1, funcs.bufwinnr('%'))
+ eq(2, funcs.bufwinnr(1))
+ eq(1, funcs.bufwinnr(2))
+ eq(-1, funcs.bufwinnr(3))
+ eq(1, funcs.bufwinnr('$'))
+ end)
+end)
+
+describe('getbufline() function', function()
+ it('returns empty list when buffer was not found', function()
+ command('file ' .. fname)
+ eq({}, funcs.getbufline(2, 1))
+ eq({}, funcs.getbufline('non-existent-buffer', 1))
+ eq({}, funcs.getbufline('#', 1))
+ command('edit ' .. fname2)
+ eq(2, funcs.bufnr('%'))
+ eq({}, funcs.getbufline('X', 1))
+ end)
+ it('returns empty list when range is invalid', function()
+ eq({}, funcs.getbufline(1, 0))
+ curbufmeths.set_lines(0, 1, false, {'foo', 'bar', 'baz'})
+ eq({}, funcs.getbufline(1, 2, 1))
+ eq({}, funcs.getbufline(1, -10, -20))
+ eq({}, funcs.getbufline(1, -2, -1))
+ eq({}, funcs.getbufline(1, -1, 9999))
+ end)
+ it('returns expected lines', function()
+ meths.set_option('hidden', true)
+ command('file ' .. fname)
+ curbufmeths.set_lines(0, 1, false, {'foo\0', '\0bar', 'baz'})
+ command('edit ' .. fname2)
+ curbufmeths.set_lines(0, 1, false, {'abc\0', '\0def', 'ghi'})
+ eq({'foo\n', '\nbar', 'baz'}, funcs.getbufline(1, 1, 9999))
+ eq({'abc\n', '\ndef', 'ghi'}, funcs.getbufline(2, 1, 9999))
+ eq({'foo\n', '\nbar', 'baz'}, funcs.getbufline(1, 1, '$'))
+ eq({'baz'}, funcs.getbufline(1, '$', '$'))
+ eq({'baz'}, funcs.getbufline(1, '$', 9999))
+ end)
+end)
+
+describe('getbufvar() function', function()
+ it('returns empty list when buffer was not found', function()
+ command('file ' .. fname)
+ eq('', funcs.getbufvar(2, '&autoindent'))
+ eq('', funcs.getbufvar('non-existent-buffer', '&autoindent'))
+ eq('', funcs.getbufvar('#', '&autoindent'))
+ command('edit ' .. fname2)
+ eq(2, funcs.bufnr('%'))
+ eq('', funcs.getbufvar('X', '&autoindent'))
+ end)
+ it('returns empty list when variable/option/etc was not found', function()
+ command('file ' .. fname)
+ eq('', funcs.getbufvar(1, '&autondent'))
+ eq('', funcs.getbufvar(1, 'changedtic'))
+ end)
+ it('returns expected option value', function()
+ eq(0, funcs.getbufvar(1, '&autoindent'))
+ eq(0, funcs.getbufvar(1, '&l:autoindent'))
+ eq(0, funcs.getbufvar(1, '&g:autoindent'))
+ -- Also works with global-only options
+ eq(0, funcs.getbufvar(1, '&hidden'))
+ eq(0, funcs.getbufvar(1, '&l:hidden'))
+ eq(0, funcs.getbufvar(1, '&g:hidden'))
+ -- Also works with window-local options
+ eq(0, funcs.getbufvar(1, '&number'))
+ eq(0, funcs.getbufvar(1, '&l:number'))
+ eq(0, funcs.getbufvar(1, '&g:number'))
+ command('new')
+ -- But with window-local options it probably does not what you expect
+ curwinmeths.set_option('number', true)
+ -- (note that current window’s buffer is 2, but getbufvar() receives 1)
+ eq(2, bufmeths.get_number(curwinmeths.get_buf()))
+ eq(1, funcs.getbufvar(1, '&number'))
+ eq(1, funcs.getbufvar(1, '&l:number'))
+ -- You can get global value though, if you find this useful.
+ eq(0, funcs.getbufvar(1, '&g:number'))
+ end)
+ it('returns expected variable value', function()
+ eq(2, funcs.getbufvar(1, 'changedtick'))
+ curbufmeths.set_lines(0, 1, false, {'abc\0', '\0def', 'ghi'})
+ eq(3, funcs.getbufvar(1, 'changedtick'))
+ curbufmeths.set_var('test', true)
+ eq(true, funcs.getbufvar(1, 'test'))
+ eq({test=true, changedtick=3}, funcs.getbufvar(1, ''))
+ command('new')
+ eq(3, funcs.getbufvar(1, 'changedtick'))
+ eq(true, funcs.getbufvar(1, 'test'))
+ eq({test=true, changedtick=3}, funcs.getbufvar(1, ''))
+ end)
+end)
+
+describe('setbufvar() function', function()
+ it('throws the error or ignores the input when buffer was not found', function()
+ command('file ' .. fname)
+ eq(0,
+ exc_exec('call setbufvar(2, "&autoindent", 0)'))
+ eq('Vim(call):E94: No matching buffer for non-existent-buffer',
+ exc_exec('call setbufvar("non-existent-buffer", "&autoindent", 0)'))
+ eq(0,
+ exc_exec('call setbufvar("#", "&autoindent", 0)'))
+ command('edit ' .. fname2)
+ eq(2, funcs.bufnr('%'))
+ eq('Vim(call):E93: More than one match for X',
+ exc_exec('call setbufvar("X", "&autoindent", 0)'))
+ end)
+ it('may set options, including window-local and global values', function()
+ local buf1 = meths.get_current_buf()
+ eq(false, curwinmeths.get_option('number'))
+ command('split')
+ command('new')
+ eq(2, bufmeths.get_number(curwinmeths.get_buf()))
+ funcs.setbufvar(1, '&number', true)
+ local windows = curtabmeths.list_wins()
+ eq(false, winmeths.get_option(windows[1], 'number'))
+ eq(true, winmeths.get_option(windows[2], 'number'))
+ eq(false, winmeths.get_option(windows[3], 'number'))
+ eq(false, winmeths.get_option(meths.get_current_win(), 'number'))
+
+ eq(false, meths.get_option('hidden'))
+ funcs.setbufvar(1, '&hidden', true)
+ eq(true, meths.get_option('hidden'))
+
+ eq(false, bufmeths.get_option(buf1, 'autoindent'))
+ funcs.setbufvar(1, '&autoindent', true)
+ eq(true, bufmeths.get_option(buf1, 'autoindent'))
+ eq('Vim(call):E355: Unknown option: xxx',
+ exc_exec('call setbufvar(1, "&xxx", 0)'))
+ end)
+ it('may set variables', function()
+ local buf1 = meths.get_current_buf()
+ command('split')
+ command('new')
+ eq(2, curbufmeths.get_number())
+ funcs.setbufvar(1, 'number', true)
+ eq(true, bufmeths.get_var(buf1, 'number'))
+ eq('Vim(call):E461: Illegal variable name: b:',
+ exc_exec('call setbufvar(1, "", 0)'))
+ eq(true, bufmeths.get_var(buf1, 'number'))
+ funcs.setbufvar(1, 'changedtick', true)
+ -- eq(true, bufmeths.get_var(buf1, 'changedtick'))
+ eq(2, funcs.getbufvar(1, 'changedtick'))
+ end)
+end)
diff --git a/test/functional/eval/container_functions_spec.lua b/test/functional/eval/container_functions_spec.lua
new file mode 100644
index 0000000000..04a3248c49
--- /dev/null
+++ b/test/functional/eval/container_functions_spec.lua
@@ -0,0 +1,24 @@
+local helpers = require('test.functional.helpers')(after_each)
+
+local eq = helpers.eq
+local eval = helpers.eval
+local meths = helpers.meths
+local clear = helpers.clear
+
+before_each(clear)
+
+describe('extend()', function()
+ it('suceeds to extend list with itself', function()
+ meths.set_var('l', {1, {}})
+ eq({1, {}, 1, {}}, eval('extend(l, l)'))
+ eq({1, {}, 1, {}}, meths.get_var('l'))
+
+ meths.set_var('l', {1, {}})
+ eq({1, {}, 1, {}}, eval('extend(l, l, 0)'))
+ eq({1, {}, 1, {}}, meths.get_var('l'))
+
+ meths.set_var('l', {1, {}})
+ eq({1, 1, {}, {}}, eval('extend(l, l, 1)'))
+ eq({1, 1, {}, {}}, meths.get_var('l'))
+ end)
+end)
diff --git a/test/functional/eval/function_spec.lua b/test/functional/eval/function_spec.lua
new file mode 100644
index 0000000000..776e760aaf
--- /dev/null
+++ b/test/functional/eval/function_spec.lua
@@ -0,0 +1,29 @@
+local helpers = require('test.functional.helpers')(after_each)
+
+local clear = helpers.clear
+local eq = helpers.eq
+local exc_exec = helpers.exc_exec
+
+describe('Up to MAX_FUNC_ARGS arguments are handled by', function()
+ local max_func_args = 20 -- from eval.h
+ local range = helpers.funcs.range
+
+ before_each(clear)
+
+ it('printf()', function()
+ local printf = helpers.funcs.printf
+ local rep = helpers.funcs['repeat']
+ local expected = '2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,'
+ eq(expected, printf(rep('%d,', max_func_args-1), unpack(range(2, max_func_args))))
+ local ret = exc_exec('call printf("", 2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21)')
+ eq('Vim(call):E740: Too many arguments for function printf', ret)
+ end)
+
+ it('rpcnotify()', function()
+ local rpcnotify = helpers.funcs.rpcnotify
+ local ret = rpcnotify(0, 'foo', unpack(range(3, max_func_args)))
+ eq(1, ret)
+ ret = exc_exec('call rpcnotify(0, "foo", 3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21)')
+ eq('Vim(call):E740: Too many arguments for function rpcnotify', ret)
+ end)
+end)
diff --git a/test/functional/eval/glob_spec.lua b/test/functional/eval/glob_spec.lua
index 599b3dcdc3..b8807ecfcc 100644
--- a/test/functional/eval/glob_spec.lua
+++ b/test/functional/eval/glob_spec.lua
@@ -1,13 +1,13 @@
local lfs = require('lfs')
local helpers = require('test.functional.helpers')(after_each)
-local clear, execute, eval, eq = helpers.clear, helpers.execute, helpers.eval, helpers.eq
+local clear, command, eval, eq = helpers.clear, helpers.command, helpers.eval, helpers.eq
before_each(function()
clear()
lfs.mkdir('test-glob')
-- Long path might cause "Press ENTER" prompt; use :silent to avoid it.
- execute('silent cd test-glob')
+ command('silent cd test-glob')
end)
after_each(function()
diff --git a/test/functional/eval/hostname_spec.lua b/test/functional/eval/hostname_spec.lua
new file mode 100644
index 0000000000..6d5b64b929
--- /dev/null
+++ b/test/functional/eval/hostname_spec.lua
@@ -0,0 +1,17 @@
+local helpers = require('test.functional.helpers')(after_each)
+local ok = helpers.ok
+local call = helpers.call
+local clear = helpers.clear
+
+describe('hostname()', function()
+ before_each(clear)
+
+ it('returns hostname string', function()
+ local actual = call('hostname')
+ ok(string.len(actual) > 0)
+ if call('executable', 'hostname') == 1 then
+ local expected = string.gsub(call('system', 'hostname'), '[\n\r]', '')
+ helpers.eq(expected, actual)
+ end
+ end)
+end)
diff --git a/test/functional/eval/input_spec.lua b/test/functional/eval/input_spec.lua
new file mode 100644
index 0000000000..1e6b107c60
--- /dev/null
+++ b/test/functional/eval/input_spec.lua
@@ -0,0 +1,440 @@
+local helpers = require('test.functional.helpers')(after_each)
+local Screen = require('test.functional.ui.screen')
+
+local eq = helpers.eq
+local feed = helpers.feed
+local meths = helpers.meths
+local clear = helpers.clear
+local source = helpers.source
+local command = helpers.command
+local exc_exec = helpers.exc_exec
+
+local screen
+
+before_each(function()
+ clear()
+ screen = Screen.new(25, 5)
+ screen:attach()
+ source([[
+ hi Test ctermfg=Red guifg=Red term=bold
+ function CustomCompl(...)
+ return 'TEST'
+ endfunction
+ function CustomListCompl(...)
+ return ['FOO']
+ endfunction
+
+ highlight RBP1 guibg=Red
+ highlight RBP2 guibg=Yellow
+ highlight RBP3 guibg=Green
+ highlight RBP4 guibg=Blue
+ let g:NUM_LVLS = 4
+ function Redraw()
+ redraw!
+ return ''
+ endfunction
+ cnoremap <expr> {REDRAW} Redraw()
+ function RainBowParens(cmdline)
+ let ret = []
+ let i = 0
+ let lvl = 0
+ while i < len(a:cmdline)
+ if a:cmdline[i] is# '('
+ call add(ret, [i, i + 1, 'RBP' . ((lvl % g:NUM_LVLS) + 1)])
+ let lvl += 1
+ elseif a:cmdline[i] is# ')'
+ let lvl -= 1
+ call add(ret, [i, i + 1, 'RBP' . ((lvl % g:NUM_LVLS) + 1)])
+ endif
+ let i += 1
+ endwhile
+ return ret
+ endfunction
+ ]])
+ screen:set_default_attr_ids({
+ EOB={bold = true, foreground = Screen.colors.Blue1},
+ T={foreground=Screen.colors.Red},
+ RBP1={background=Screen.colors.Red},
+ RBP2={background=Screen.colors.Yellow},
+ RBP3={background=Screen.colors.Green},
+ RBP4={background=Screen.colors.Blue},
+ })
+end)
+
+describe('input()', function()
+ it('works with multiline prompts', function()
+ feed([[:call input("Test\nFoo")<CR>]])
+ screen:expect([[
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ Test |
+ Foo^ |
+ ]])
+ end)
+ it('works with multiline prompts and :echohl', function()
+ feed([[:echohl Test | call input("Test\nFoo")<CR>]])
+ screen:expect([[
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {T:Test} |
+ {T:Foo}^ |
+ ]])
+ command('redraw!')
+ screen:expect([[
+ |
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {T:Foo}^ |
+ ]])
+ end)
+ it('allows unequal numeric arguments when using multiple args', function()
+ command('echohl Test')
+ feed([[:call input(1, 2)<CR>]])
+ screen:expect([[
+ |
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {T:1}2^ |
+ ]])
+ feed('<BS>')
+ screen:expect([[
+ |
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {T:1}^ |
+ ]])
+ end)
+ it('allows unequal numeric values when using {opts} dictionary', function()
+ command('echohl Test')
+ meths.set_var('opts', {prompt=1, default=2, cancelreturn=3})
+ feed([[:echo input(opts)<CR>]])
+ screen:expect([[
+ |
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {T:1}2^ |
+ ]])
+ feed('<BS>')
+ screen:expect([[
+ |
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {T:1}^ |
+ ]])
+ feed('<Esc>')
+ screen:expect([[
+ ^ |
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {T:3} |
+ ]])
+ end)
+ it('works with redraw', function()
+ command('echohl Test')
+ meths.set_var('opts', {prompt='Foo>', default='Bar'})
+ feed([[:echo inputdialog(opts)<CR>]])
+ screen:expect([[
+ |
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {T:Foo>}Bar^ |
+ ]])
+ command('redraw!')
+ screen:expect([[
+ |
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {T:Foo>}Bar^ |
+ ]])
+ feed('<BS>')
+ screen:expect([[
+ |
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {T:Foo>}Ba^ |
+ ]])
+ command('redraw!')
+ screen:expect([[
+ |
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {T:Foo>}Ba^ |
+ ]])
+ end)
+ it('allows omitting everything with dictionary argument', function()
+ command('echohl Test')
+ feed([[:call input({})<CR>]])
+ screen:expect([[
+ |
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ ^ |
+ ]])
+ end)
+ it('supports completion', function()
+ feed(':let var = input("", "", "custom,CustomCompl")<CR>')
+ feed('<Tab><CR>')
+ eq('TEST', meths.get_var('var'))
+
+ feed(':let var = input({"completion": "customlist,CustomListCompl"})<CR>')
+ feed('<Tab><CR>')
+ eq('FOO', meths.get_var('var'))
+ end)
+ it('supports cancelreturn', function()
+ feed(':let var = input({"cancelreturn": "BAR"})<CR>')
+ feed('<Esc>')
+ eq('BAR', meths.get_var('var'))
+ end)
+ it('supports default string', function()
+ feed(':let var = input("", "DEF1")<CR>')
+ feed('<CR>')
+ eq('DEF1', meths.get_var('var'))
+
+ feed(':let var = input({"default": "DEF2"})<CR>')
+ feed('<CR>')
+ eq('DEF2', meths.get_var('var'))
+ end)
+ it('errors out on invalid inputs', function()
+ eq('Vim(call):E730: using List as a String',
+ exc_exec('call input([])'))
+ eq('Vim(call):E730: using List as a String',
+ exc_exec('call input("", [])'))
+ eq('Vim(call):E730: using List as a String',
+ exc_exec('call input("", "", [])'))
+ eq('Vim(call):E730: using List as a String',
+ exc_exec('call input({"prompt": []})'))
+ eq('Vim(call):E730: using List as a String',
+ exc_exec('call input({"cancelreturn": []})'))
+ eq('Vim(call):E730: using List as a String',
+ exc_exec('call input({"default": []})'))
+ eq('Vim(call):E730: using List as a String',
+ exc_exec('call input({"completion": []})'))
+ eq('Vim(call):E5050: {opts} must be the only argument',
+ exc_exec('call input({}, "default")'))
+ eq('Vim(call):E118: Too many arguments for function: input',
+ exc_exec('call input("prompt> ", "default", "file", "extra")'))
+ end)
+ it('supports highlighting', function()
+ command('nnoremap <expr> X input({"highlight": "RainBowParens"})[-1]')
+ feed([[X]])
+ feed('(())')
+ screen:expect([[
+ |
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {RBP1:(}{RBP2:()}{RBP1:)}^ |
+ ]])
+ end)
+ it('is not hidden by :silent', function()
+ feed([[:silent call input('Foo: ')<CR>]])
+ screen:expect([[
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ Foo: ^ |
+ |
+ ]])
+ feed('Bar')
+ screen:expect([[
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ Foo: Bar^ |
+ |
+ ]])
+ feed('<CR>')
+ end)
+end)
+describe('inputdialog()', function()
+ it('works with multiline prompts', function()
+ feed([[:call inputdialog("Test\nFoo")<CR>]])
+ screen:expect([[
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ Test |
+ Foo^ |
+ ]])
+ end)
+ it('works with multiline prompts and :echohl', function()
+ feed([[:echohl Test | call inputdialog("Test\nFoo")<CR>]])
+ screen:expect([[
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {T:Test} |
+ {T:Foo}^ |
+ ]])
+ command('redraw!')
+ screen:expect([[
+ |
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {T:Foo}^ |
+ ]])
+ end)
+ it('allows unequal numeric arguments when using multiple args', function()
+ command('echohl Test')
+ feed([[:call inputdialog(1, 2)<CR>]])
+ screen:expect([[
+ |
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {T:1}2^ |
+ ]])
+ feed('<BS>')
+ screen:expect([[
+ |
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {T:1}^ |
+ ]])
+ end)
+ it('allows unequal numeric values when using {opts} dictionary', function()
+ command('echohl Test')
+ meths.set_var('opts', {prompt=1, default=2, cancelreturn=3})
+ feed([[:echo input(opts)<CR>]])
+ screen:expect([[
+ |
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {T:1}2^ |
+ ]])
+ feed('<BS>')
+ screen:expect([[
+ |
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {T:1}^ |
+ ]])
+ feed('<Esc>')
+ screen:expect([[
+ ^ |
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {T:3} |
+ ]])
+ end)
+ it('works with redraw', function()
+ command('echohl Test')
+ meths.set_var('opts', {prompt='Foo>', default='Bar'})
+ feed([[:echo input(opts)<CR>]])
+ screen:expect([[
+ |
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {T:Foo>}Bar^ |
+ ]])
+ command('redraw!')
+ screen:expect([[
+ |
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {T:Foo>}Bar^ |
+ ]])
+ feed('<BS>')
+ screen:expect([[
+ |
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {T:Foo>}Ba^ |
+ ]])
+ command('redraw!')
+ screen:expect([[
+ |
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {T:Foo>}Ba^ |
+ ]])
+ end)
+ it('allows omitting everything with dictionary argument', function()
+ command('echohl Test')
+ feed(':echo inputdialog({})<CR>')
+ screen:expect([[
+ |
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ ^ |
+ ]])
+ end)
+ it('supports completion', function()
+ feed(':let var = inputdialog({"completion": "customlist,CustomListCompl"})<CR>')
+ feed('<Tab><CR>')
+ eq('FOO', meths.get_var('var'))
+ end)
+ it('supports cancelreturn', function()
+ feed(':let var = inputdialog("", "", "CR1")<CR>')
+ feed('<Esc>')
+ eq('CR1', meths.get_var('var'))
+
+ feed(':let var = inputdialog({"cancelreturn": "BAR"})<CR>')
+ feed('<Esc>')
+ eq('BAR', meths.get_var('var'))
+ end)
+ it('supports default string', function()
+ feed(':let var = inputdialog("", "DEF1")<CR>')
+ feed('<CR>')
+ eq('DEF1', meths.get_var('var'))
+
+ feed(':let var = inputdialog({"default": "DEF2"})<CR>')
+ feed('<CR>')
+ eq('DEF2', meths.get_var('var'))
+ end)
+ it('errors out on invalid inputs', function()
+ eq('Vim(call):E730: using List as a String',
+ exc_exec('call inputdialog([])'))
+ eq('Vim(call):E730: using List as a String',
+ exc_exec('call inputdialog("", [])'))
+ eq('Vim(call):E730: using List as a String',
+ exc_exec('call inputdialog("", "", [])'))
+ eq('Vim(call):E730: using List as a String',
+ exc_exec('call inputdialog({"prompt": []})'))
+ eq('Vim(call):E730: using List as a String',
+ exc_exec('call inputdialog({"cancelreturn": []})'))
+ eq('Vim(call):E730: using List as a String',
+ exc_exec('call inputdialog({"default": []})'))
+ eq('Vim(call):E730: using List as a String',
+ exc_exec('call inputdialog({"completion": []})'))
+ eq('Vim(call):E5050: {opts} must be the only argument',
+ exc_exec('call inputdialog({}, "default")'))
+ eq('Vim(call):E118: Too many arguments for function: inputdialog',
+ exc_exec('call inputdialog("prompt> ", "default", "file", "extra")'))
+ end)
+ it('supports highlighting', function()
+ command('nnoremap <expr> X inputdialog({"highlight": "RainBowParens"})[-1]')
+ feed([[X]])
+ feed('(())')
+ screen:expect([[
+ |
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ {RBP1:(}{RBP2:()}{RBP1:)}^ |
+ ]])
+ end)
+end)
diff --git a/test/functional/eval/json_functions_spec.lua b/test/functional/eval/json_functions_spec.lua
index fc0a19bdfa..8dcaea806e 100644
--- a/test/functional/eval/json_functions_spec.lua
+++ b/test/functional/eval/json_functions_spec.lua
@@ -4,16 +4,17 @@ local funcs = helpers.funcs
local meths = helpers.meths
local eq = helpers.eq
local eval = helpers.eval
-local execute = helpers.execute
+local command = helpers.command
local exc_exec = helpers.exc_exec
local redir_exec = helpers.redir_exec
local NIL = helpers.NIL
+local source = helpers.source
describe('json_decode() function', function()
local restart = function(...)
clear(...)
- execute('language C')
- execute([[
+ source([[
+ language C
function Eq(exp, act)
let act = a:act
let exp = a:exp
@@ -45,8 +46,6 @@ describe('json_decode() function', function()
endif
return 1
endfunction
- ]])
- execute([[
function EvalEq(exp, act_expr)
let act = eval(a:act_expr)
if Eq(a:exp, act)
@@ -441,7 +440,7 @@ describe('json_decode() function', function()
local sp_decode_eq = function(expected, json)
meths.set_var('__json', json)
speq(expected, 'json_decode(g:__json)')
- execute('unlet! g:__json')
+ command('unlet! g:__json')
end
it('parses strings with NUL properly', function()
@@ -527,7 +526,7 @@ end)
describe('json_encode() function', function()
before_each(function()
clear()
- execute('language C')
+ command('language C')
end)
it('dumps strings', function()
@@ -576,94 +575,94 @@ describe('json_encode() function', function()
it('cannot dump generic mapping with generic mapping keys and values',
function()
- execute('let todump = {"_TYPE": v:msgpack_types.map, "_VAL": []}')
- execute('let todumpv1 = {"_TYPE": v:msgpack_types.map, "_VAL": []}')
- execute('let todumpv2 = {"_TYPE": v:msgpack_types.map, "_VAL": []}')
- execute('call add(todump._VAL, [todumpv1, todumpv2])')
+ command('let todump = {"_TYPE": v:msgpack_types.map, "_VAL": []}')
+ command('let todumpv1 = {"_TYPE": v:msgpack_types.map, "_VAL": []}')
+ command('let todumpv2 = {"_TYPE": v:msgpack_types.map, "_VAL": []}')
+ command('call add(todump._VAL, [todumpv1, todumpv2])')
eq('Vim(call):E474: Invalid key in special dictionary', exc_exec('call json_encode(todump)'))
end)
it('cannot dump generic mapping with ext key', function()
- execute('let todump = {"_TYPE": v:msgpack_types.ext, "_VAL": [5, ["",""]]}')
- execute('let todump = {"_TYPE": v:msgpack_types.map, "_VAL": [[todump, 1]]}')
+ command('let todump = {"_TYPE": v:msgpack_types.ext, "_VAL": [5, ["",""]]}')
+ command('let todump = {"_TYPE": v:msgpack_types.map, "_VAL": [[todump, 1]]}')
eq('Vim(call):E474: Invalid key in special dictionary', exc_exec('call json_encode(todump)'))
end)
it('cannot dump generic mapping with array key', function()
- execute('let todump = {"_TYPE": v:msgpack_types.array, "_VAL": [5, [""]]}')
- execute('let todump = {"_TYPE": v:msgpack_types.map, "_VAL": [[todump, 1]]}')
+ command('let todump = {"_TYPE": v:msgpack_types.array, "_VAL": [5, [""]]}')
+ command('let todump = {"_TYPE": v:msgpack_types.map, "_VAL": [[todump, 1]]}')
eq('Vim(call):E474: Invalid key in special dictionary', exc_exec('call json_encode(todump)'))
end)
it('cannot dump generic mapping with UINT64_MAX key', function()
- execute('let todump = {"_TYPE": v:msgpack_types.integer}')
- execute('let todump._VAL = [1, 3, 0x7FFFFFFF, 0x7FFFFFFF]')
- execute('let todump = {"_TYPE": v:msgpack_types.map, "_VAL": [[todump, 1]]}')
+ command('let todump = {"_TYPE": v:msgpack_types.integer}')
+ command('let todump._VAL = [1, 3, 0x7FFFFFFF, 0x7FFFFFFF]')
+ command('let todump = {"_TYPE": v:msgpack_types.map, "_VAL": [[todump, 1]]}')
eq('Vim(call):E474: Invalid key in special dictionary', exc_exec('call json_encode(todump)'))
end)
it('cannot dump generic mapping with floating-point key', function()
- execute('let todump = {"_TYPE": v:msgpack_types.float, "_VAL": 0.125}')
- execute('let todump = {"_TYPE": v:msgpack_types.map, "_VAL": [[todump, 1]]}')
+ command('let todump = {"_TYPE": v:msgpack_types.float, "_VAL": 0.125}')
+ command('let todump = {"_TYPE": v:msgpack_types.map, "_VAL": [[todump, 1]]}')
eq('Vim(call):E474: Invalid key in special dictionary', exc_exec('call json_encode(todump)'))
end)
it('can dump generic mapping with STR special key and NUL', function()
- execute('let todump = {"_TYPE": v:msgpack_types.string, "_VAL": ["\\n"]}')
- execute('let todump = {"_TYPE": v:msgpack_types.map, "_VAL": [[todump, 1]]}')
+ command('let todump = {"_TYPE": v:msgpack_types.string, "_VAL": ["\\n"]}')
+ command('let todump = {"_TYPE": v:msgpack_types.map, "_VAL": [[todump, 1]]}')
eq('{"\\u0000": 1}', eval('json_encode(todump)'))
end)
it('can dump generic mapping with BIN special key and NUL', function()
- execute('let todump = {"_TYPE": v:msgpack_types.binary, "_VAL": ["\\n"]}')
- execute('let todump = {"_TYPE": v:msgpack_types.map, "_VAL": [[todump, 1]]}')
+ command('let todump = {"_TYPE": v:msgpack_types.binary, "_VAL": ["\\n"]}')
+ command('let todump = {"_TYPE": v:msgpack_types.map, "_VAL": [[todump, 1]]}')
eq('{"\\u0000": 1}', eval('json_encode(todump)'))
end)
it('can dump STR special mapping with NUL and NL', function()
- execute('let todump = {"_TYPE": v:msgpack_types.string, "_VAL": ["\\n", ""]}')
+ command('let todump = {"_TYPE": v:msgpack_types.string, "_VAL": ["\\n", ""]}')
eq('"\\u0000\\n"', eval('json_encode(todump)'))
end)
it('can dump BIN special mapping with NUL and NL', function()
- execute('let todump = {"_TYPE": v:msgpack_types.binary, "_VAL": ["\\n", ""]}')
+ command('let todump = {"_TYPE": v:msgpack_types.binary, "_VAL": ["\\n", ""]}')
eq('"\\u0000\\n"', eval('json_encode(todump)'))
end)
it('cannot dump special ext mapping', function()
- execute('let todump = {"_TYPE": v:msgpack_types.ext, "_VAL": [5, ["",""]]}')
+ command('let todump = {"_TYPE": v:msgpack_types.ext, "_VAL": [5, ["",""]]}')
eq('Vim(call):E474: Unable to convert EXT string to JSON', exc_exec('call json_encode(todump)'))
end)
it('can dump special array mapping', function()
- execute('let todump = {"_TYPE": v:msgpack_types.array, "_VAL": [5, [""]]}')
+ command('let todump = {"_TYPE": v:msgpack_types.array, "_VAL": [5, [""]]}')
eq('[5, [""]]', eval('json_encode(todump)'))
end)
it('can dump special UINT64_MAX mapping', function()
- execute('let todump = {"_TYPE": v:msgpack_types.integer}')
- execute('let todump._VAL = [1, 3, 0x7FFFFFFF, 0x7FFFFFFF]')
+ command('let todump = {"_TYPE": v:msgpack_types.integer}')
+ command('let todump._VAL = [1, 3, 0x7FFFFFFF, 0x7FFFFFFF]')
eq('18446744073709551615', eval('json_encode(todump)'))
end)
it('can dump special INT64_MIN mapping', function()
- execute('let todump = {"_TYPE": v:msgpack_types.integer}')
- execute('let todump._VAL = [-1, 2, 0, 0]')
+ command('let todump = {"_TYPE": v:msgpack_types.integer}')
+ command('let todump._VAL = [-1, 2, 0, 0]')
eq('-9223372036854775808', eval('json_encode(todump)'))
end)
it('can dump special BOOLEAN true mapping', function()
- execute('let todump = {"_TYPE": v:msgpack_types.boolean, "_VAL": 1}')
+ command('let todump = {"_TYPE": v:msgpack_types.boolean, "_VAL": 1}')
eq('true', eval('json_encode(todump)'))
end)
it('can dump special BOOLEAN false mapping', function()
- execute('let todump = {"_TYPE": v:msgpack_types.boolean, "_VAL": 0}')
+ command('let todump = {"_TYPE": v:msgpack_types.boolean, "_VAL": 0}')
eq('false', eval('json_encode(todump)'))
end)
it('can dump special NIL mapping', function()
- execute('let todump = {"_TYPE": v:msgpack_types.nil, "_VAL": 0}')
+ command('let todump = {"_TYPE": v:msgpack_types.nil, "_VAL": 0}')
eq('null', eval('json_encode(todump)'))
end)
@@ -673,7 +672,7 @@ describe('json_encode() function', function()
end)
it('fails to dump a partial', function()
- execute('function T() dict\nendfunction')
+ command('function T() dict\nendfunction')
eq('Vim(call):E474: Error while dumping encode_tv2json() argument, itself: attempt to dump function reference',
exc_exec('call json_encode(function("T", [1, 2], {}))'))
end)
@@ -684,56 +683,56 @@ describe('json_encode() function', function()
end)
it('fails to dump a recursive list', function()
- execute('let todump = [[[]]]')
- execute('call add(todump[0][0], todump)')
+ command('let todump = [[[]]]')
+ command('call add(todump[0][0], todump)')
eq('Vim(call):E724: unable to correctly dump variable with self-referencing container',
exc_exec('call json_encode(todump)'))
end)
it('fails to dump a recursive dict', function()
- execute('let todump = {"d": {"d": {}}}')
- execute('call extend(todump.d.d, {"d": todump})')
+ command('let todump = {"d": {"d": {}}}')
+ command('call extend(todump.d.d, {"d": todump})')
eq('Vim(call):E724: unable to correctly dump variable with self-referencing container',
exc_exec('call json_encode([todump])'))
end)
it('can dump dict with two same dicts inside', function()
- execute('let inter = {}')
- execute('let todump = {"a": inter, "b": inter}')
+ command('let inter = {}')
+ command('let todump = {"a": inter, "b": inter}')
eq('{"a": {}, "b": {}}', eval('json_encode(todump)'))
end)
it('can dump list with two same lists inside', function()
- execute('let inter = []')
- execute('let todump = [inter, inter]')
+ command('let inter = []')
+ command('let todump = [inter, inter]')
eq('[[], []]', eval('json_encode(todump)'))
end)
it('fails to dump a recursive list in a special dict', function()
- execute('let todump = {"_TYPE": v:msgpack_types.array, "_VAL": []}')
- execute('call add(todump._VAL, todump)')
+ command('let todump = {"_TYPE": v:msgpack_types.array, "_VAL": []}')
+ command('call add(todump._VAL, todump)')
eq('Vim(call):E724: unable to correctly dump variable with self-referencing container',
exc_exec('call json_encode(todump)'))
end)
it('fails to dump a recursive (val) map in a special dict', function()
- execute('let todump = {"_TYPE": v:msgpack_types.map, "_VAL": []}')
- execute('call add(todump._VAL, ["", todump])')
+ command('let todump = {"_TYPE": v:msgpack_types.map, "_VAL": []}')
+ command('call add(todump._VAL, ["", todump])')
eq('Vim(call):E724: unable to correctly dump variable with self-referencing container',
exc_exec('call json_encode([todump])'))
end)
it('fails to dump a recursive (val) map in a special dict, _VAL reference', function()
- execute('let todump = {"_TYPE": v:msgpack_types.map, "_VAL": [["", []]]}')
- execute('call add(todump._VAL[0][1], todump._VAL)')
+ command('let todump = {"_TYPE": v:msgpack_types.map, "_VAL": [["", []]]}')
+ command('call add(todump._VAL[0][1], todump._VAL)')
eq('Vim(call):E724: unable to correctly dump variable with self-referencing container',
exc_exec('call json_encode(todump)'))
end)
it('fails to dump a recursive (val) special list in a special dict',
function()
- execute('let todump = {"_TYPE": v:msgpack_types.array, "_VAL": []}')
- execute('call add(todump._VAL, ["", todump._VAL])')
+ command('let todump = {"_TYPE": v:msgpack_types.array, "_VAL": []}')
+ command('call add(todump._VAL, ["", todump._VAL])')
eq('Vim(call):E724: unable to correctly dump variable with self-referencing container',
exc_exec('call json_encode(todump)'))
end)
@@ -777,4 +776,11 @@ describe('json_encode() function', function()
it('can dump NULL dictionary', function()
eq('{}', eval('json_encode(v:_null_dict)'))
end)
+
+ it('fails to parse NULL strings and lists', function()
+ eq('Vim(call):E474: Attempt to decode a blank string',
+ exc_exec('call json_decode($XXX_UNEXISTENT_VAR_XXX)'))
+ eq('Vim(call):E474: Attempt to decode a blank string',
+ exc_exec('call json_decode(v:_null_list)'))
+ end)
end)
diff --git a/test/functional/eval/map_functions_spec.lua b/test/functional/eval/map_functions_spec.lua
new file mode 100644
index 0000000000..e914f674aa
--- /dev/null
+++ b/test/functional/eval/map_functions_spec.lua
@@ -0,0 +1,159 @@
+local helpers = require('test.functional.helpers')(after_each)
+
+local clear = helpers.clear
+local eq = helpers.eq
+local eval = helpers.eval
+local funcs = helpers.funcs
+local nvim = helpers.nvim
+local source = helpers.source
+local command = helpers.command
+
+describe('maparg()', function()
+ before_each(clear)
+
+ local foo_bar_map_table = {
+ lhs='foo',
+ silent=0,
+ rhs='bar',
+ expr=0,
+ sid=0,
+ buffer=0,
+ nowait=0,
+ mode='n',
+ noremap=1,
+ }
+
+ it('returns a dictionary', function()
+ nvim('command', 'nnoremap foo bar')
+ eq('bar', funcs.maparg('foo'))
+ eq(foo_bar_map_table, funcs.maparg('foo', 'n', false, true))
+ end)
+
+ it('returns 1 for silent when <silent> is used', function()
+ nvim('command', 'nnoremap <silent> foo bar')
+ eq(1, funcs.maparg('foo', 'n', false, true)['silent'])
+
+ nvim('command', 'nnoremap baz bat')
+ eq(0, funcs.maparg('baz', 'n', false, true)['silent'])
+ end)
+
+ it('returns an empty string when no map is present', function()
+ eq('', funcs.maparg('not a mapping'))
+ end)
+
+ it('returns an empty dictionary when no map is present and dict is requested', function()
+ eq({}, funcs.maparg('not a mapping', 'n', false, true))
+ end)
+
+ it('returns the same value for noremap and <script>', function()
+ nvim('command', 'inoremap <script> hello world')
+ nvim('command', 'inoremap this that')
+ eq(
+ funcs.maparg('hello', 'i', false, true)['noremap'],
+ funcs.maparg('this', 'i', false, true)['noremap']
+ )
+ end)
+
+ it('returns a boolean for buffer', function()
+ -- Open enough windows to know we aren't on buffer number 1
+ nvim('command', 'new')
+ nvim('command', 'new')
+ nvim('command', 'new')
+ nvim('command', 'cnoremap <buffer> this that')
+ eq(1, funcs.maparg('this', 'c', false, true)['buffer'])
+
+ -- Global will return 0 always
+ nvim('command', 'nnoremap other another')
+ eq(0, funcs.maparg('other', 'n', false, true)['buffer'])
+ end)
+
+ it('returns script numbers', function()
+ source([[
+ function! s:maparg_test_function() abort
+ return 'testing'
+ endfunction
+
+ nnoremap fizz :call <SID>maparg_test_function()<CR>
+ ]])
+ eq(1, funcs.maparg('fizz', 'n', false, true)['sid'])
+ eq('testing', nvim('call_function', '<SNR>1_maparg_test_function', {}))
+ end)
+
+ it('works with <F12> and others', function()
+ source([[
+ let g:maparg_test_var = 0
+
+ nnoremap <F12> :let g:maparg_test_var = 1<CR>
+ ]])
+ eq(0, eval('g:maparg_test_var'))
+ source([[
+ call feedkeys("\<F12>")
+ ]])
+ eq(1, eval('g:maparg_test_var'))
+
+ eq(':let g:maparg_test_var = 1<CR>', funcs.maparg('<F12>', 'n', false, true)['rhs'])
+ end)
+
+ it('works with <expr>', function()
+ source([[
+ let counter = 0
+ inoremap <expr> <C-L> ListItem()
+ inoremap <expr> <C-R> ListReset()
+
+ func ListItem()
+ let g:counter += 1
+ return g:counter . '. '
+ endfunc
+
+ func ListReset()
+ let g:counter = 0
+ return ''
+ endfunc
+
+ call feedkeys("i\<C-L>")
+ ]])
+ eq(1, eval('g:counter'))
+
+ local map_dict = funcs.maparg('<C-L>', 'i', false, true)
+ eq(1, map_dict['expr'])
+ eq('i', map_dict['mode'])
+ end)
+
+ it('works with combining characters', function()
+ -- Using addacutes to make combining character better visible
+ local function ac(s)
+ local acute = '\204\129' -- U+0301 COMBINING ACUTE ACCENT
+ local ret = s:gsub('`', acute)
+ return ret
+ end
+ command(ac([[
+ nnoremap a b`
+ nnoremap c` d
+ nnoremap e` f`
+ ]]))
+ eq(ac('b`'), funcs.maparg(ac('a')))
+ eq(ac(''), funcs.maparg(ac('c')))
+ eq(ac('d'), funcs.maparg(ac('c`')))
+ eq(ac('f`'), funcs.maparg(ac('e`')))
+
+ local function acmap(lhs, rhs)
+ return {
+ lhs = ac(lhs),
+ rhs = ac(rhs),
+
+ buffer = 0,
+ expr = 0,
+ mode = 'n',
+ noremap = 1,
+ nowait = 0,
+ sid = 0,
+ silent = 0,
+ }
+ end
+
+ eq({}, funcs.maparg(ac('c'), 'n', 0, 1))
+ eq(acmap('a', 'b`'), funcs.maparg(ac('a'), 'n', 0, 1))
+ eq(acmap('c`', 'd'), funcs.maparg(ac('c`'), 'n', 0, 1))
+ eq(acmap('e`', 'f`'), funcs.maparg(ac('e`'), 'n', 0, 1))
+ end)
+end)
diff --git a/test/functional/eval/match_functions_spec.lua b/test/functional/eval/match_functions_spec.lua
new file mode 100644
index 0000000000..3150d89f62
--- /dev/null
+++ b/test/functional/eval/match_functions_spec.lua
@@ -0,0 +1,61 @@
+local helpers = require('test.functional.helpers')(after_each)
+
+local eq = helpers.eq
+local clear = helpers.clear
+local funcs = helpers.funcs
+local command = helpers.command
+
+before_each(clear)
+
+describe('setmatches()', function()
+ it('correctly handles case when both group and pattern entries are numbers',
+ function()
+ command('hi def link 1 PreProc')
+ eq(0, funcs.setmatches({{group=1, pattern=2, id=3, priority=4}}))
+ eq({{
+ group='1',
+ pattern='2',
+ id=3,
+ priority=4,
+ }}, funcs.getmatches())
+ eq(0, funcs.setmatches({{group=1, pattern=2, id=3, priority=4, conceal=5}}))
+ eq({{
+ group='1',
+ pattern='2',
+ id=3,
+ priority=4,
+ conceal='5',
+ }}, funcs.getmatches())
+ eq(0, funcs.setmatches({{group=1, pos1={2}, pos2={6}, id=3, priority=4, conceal=5}}))
+ eq({{
+ group='1',
+ pos1={2},
+ pos2={6},
+ id=3,
+ priority=4,
+ conceal='5',
+ }}, funcs.getmatches())
+ end)
+
+ it('fails with -1 if highlight group is not defined', function()
+ eq(-1, funcs.setmatches({{group=1, pattern=2, id=3, priority=4}}))
+ eq({}, funcs.getmatches())
+ eq(-1, funcs.setmatches({{group=1, pos1={2}, pos2={6}, id=3, priority=4, conceal=5}}))
+ eq({}, funcs.getmatches())
+ end)
+end)
+
+describe('matchadd()', function()
+ it('correctly works when first two arguments and conceal are numbers at once',
+ function()
+ command('hi def link 1 PreProc')
+ eq(4, funcs.matchadd(1, 2, 3, 4, {conceal=5}))
+ eq({{
+ group='1',
+ pattern='2',
+ priority=3,
+ id=4,
+ conceal='5',
+ }}, funcs.getmatches())
+ end)
+end)
diff --git a/test/functional/eval/minmax_functions_spec.lua b/test/functional/eval/minmax_functions_spec.lua
new file mode 100644
index 0000000000..c6eb754f91
--- /dev/null
+++ b/test/functional/eval/minmax_functions_spec.lua
@@ -0,0 +1,51 @@
+local helpers = require('test.functional.helpers')(after_each)
+
+local eq = helpers.eq
+local eval = helpers.eval
+local clear = helpers.clear
+local funcs = helpers.funcs
+local redir_exec = helpers.redir_exec
+
+before_each(clear)
+for _, func in ipairs({'min', 'max'}) do
+ describe(func .. '()', function()
+ it('gives a single error message when multiple values failed conversions',
+ function()
+ eq('\nE745: Using a List as a Number\n0',
+ redir_exec('echo ' .. func .. '([-5, [], [], [], 5])'))
+ eq('\nE745: Using a List as a Number\n0',
+ redir_exec('echo ' .. func .. '({1:-5, 2:[], 3:[], 4:[], 5:5})'))
+ for errmsg, errinput in pairs({
+ ['E745: Using a List as a Number'] = '[]',
+ ['E805: Using a Float as a Number'] = '0.0',
+ ['E703: Using a Funcref as a Number'] = 'function("tr")',
+ ['E728: Using a Dictionary as a Number'] = '{}',
+ }) do
+ eq('\n' .. errmsg .. '\n0',
+ redir_exec('echo ' .. func .. '([' .. errinput .. '])'))
+ eq('\n' .. errmsg .. '\n0',
+ redir_exec('echo ' .. func .. '({1:' .. errinput .. '})'))
+ end
+ end)
+ it('works with arrays/dictionaries with zero items', function()
+ eq(0, funcs[func]({}))
+ eq(0, eval(func .. '({})'))
+ end)
+ it('works with arrays/dictionaries with one item', function()
+ eq(5, funcs[func]({5}))
+ eq(5, funcs[func]({test=5}))
+ end)
+ it('works with NULL arrays/dictionaries', function()
+ eq(0, eval(func .. '(v:_null_list)'))
+ eq(0, eval(func .. '(v:_null_dict)'))
+ end)
+ it('errors out for invalid types', function()
+ for _, errinput in ipairs({'1', 'v:true', 'v:false', 'v:null',
+ 'function("tr")', '""'}) do
+ eq(('\nE712: Argument of %s() must be a List or Dictionary\n0'):format(
+ func),
+ redir_exec('echo ' .. func .. '(' .. errinput .. ')'))
+ end
+ end)
+ end)
+end
diff --git a/test/functional/eval/modeline_spec.lua b/test/functional/eval/modeline_spec.lua
index 0be7210a76..c5bb798f4a 100644
--- a/test/functional/eval/modeline_spec.lua
+++ b/test/functional/eval/modeline_spec.lua
@@ -1,5 +1,5 @@
local helpers = require('test.functional.helpers')(after_each)
-local clear, execute, write_file = helpers.clear, helpers.execute, helpers.write_file
+local clear, command, write_file = helpers.clear, helpers.command, helpers.write_file
local eq, eval = helpers.eq, helpers.eval
describe("modeline", function()
@@ -12,7 +12,7 @@ describe("modeline", function()
it('does not crash with a large version number', function()
write_file(tempfile, 'vim100000000000000000000000')
- execute('e! ' .. tempfile)
+ command('e! ' .. tempfile)
eq(2, eval('1+1')) -- Still alive?
end)
diff --git a/test/functional/eval/msgpack_functions_spec.lua b/test/functional/eval/msgpack_functions_spec.lua
index 44c01d2226..b241635dfe 100644
--- a/test/functional/eval/msgpack_functions_spec.lua
+++ b/test/functional/eval/msgpack_functions_spec.lua
@@ -2,7 +2,7 @@ local helpers = require('test.functional.helpers')(after_each)
local clear = helpers.clear
local funcs = helpers.funcs
local eval, eq = helpers.eval, helpers.eq
-local execute = helpers.execute
+local command = helpers.command
local nvim = helpers.nvim
local exc_exec = helpers.exc_exec
@@ -331,13 +331,14 @@ describe('msgpack*() functions', function()
obj_test('are able to dump and restore floating-point value', {0.125})
it('can restore and dump UINT64_MAX', function()
- execute('let dumped = ["\\xCF" . repeat("\\xFF", 8)]')
- execute('let parsed = msgpackparse(dumped)')
- execute('let dumped2 = msgpackdump(parsed)')
+ command('let dumped = ["\\xCF" . repeat("\\xFF", 8)]')
+ command('let parsed = msgpackparse(dumped)')
+ command('let dumped2 = msgpackdump(parsed)')
eq(1, eval('type(parsed[0]) == type(0) ' ..
'|| parsed[0]._TYPE is v:msgpack_types.integer'))
if eval('type(parsed[0]) == type(0)') == 1 then
- eq(1, eval('0xFFFFFFFFFFFFFFFF == parsed[0]'))
+ command('call assert_equal(0xFFFFFFFFFFFFFFFF, parsed[0])')
+ eq({}, eval('v:errors'))
else
eq({_TYPE={}, _VAL={1, 3, 0x7FFFFFFF, 0x7FFFFFFF}}, eval('parsed[0]'))
end
@@ -345,13 +346,14 @@ describe('msgpack*() functions', function()
end)
it('can restore and dump INT64_MIN', function()
- execute('let dumped = ["\\xD3\\x80" . repeat("\\n", 7)]')
- execute('let parsed = msgpackparse(dumped)')
- execute('let dumped2 = msgpackdump(parsed)')
+ command('let dumped = ["\\xD3\\x80" . repeat("\\n", 7)]')
+ command('let parsed = msgpackparse(dumped)')
+ command('let dumped2 = msgpackdump(parsed)')
eq(1, eval('type(parsed[0]) == type(0) ' ..
'|| parsed[0]._TYPE is v:msgpack_types.integer'))
if eval('type(parsed[0]) == type(0)') == 1 then
- eq(1, eval('-0x8000000000000000 == parsed[0]'))
+ command('call assert_equal(-0x7fffffffffffffff - 1, parsed[0])')
+ eq({}, eval('v:errors'))
else
eq({_TYPE={}, _VAL={-1, 2, 0, 0}}, eval('parsed[0]'))
end
@@ -359,33 +361,33 @@ describe('msgpack*() functions', function()
end)
it('can restore and dump BIN string with zero byte', function()
- execute('let dumped = ["\\xC4\\x01\\n"]')
- execute('let parsed = msgpackparse(dumped)')
- execute('let dumped2 = msgpackdump(parsed)')
+ command('let dumped = ["\\xC4\\x01\\n"]')
+ command('let parsed = msgpackparse(dumped)')
+ command('let dumped2 = msgpackdump(parsed)')
eq({{_TYPE={}, _VAL={'\n'}}}, eval('parsed'))
eq(1, eval('parsed[0]._TYPE is v:msgpack_types.binary'))
eq(1, eval('dumped ==# dumped2'))
end)
it('can restore and dump STR string with zero byte', function()
- execute('let dumped = ["\\xA1\\n"]')
- execute('let parsed = msgpackparse(dumped)')
- execute('let dumped2 = msgpackdump(parsed)')
+ command('let dumped = ["\\xA1\\n"]')
+ command('let parsed = msgpackparse(dumped)')
+ command('let dumped2 = msgpackdump(parsed)')
eq({{_TYPE={}, _VAL={'\n'}}}, eval('parsed'))
eq(1, eval('parsed[0]._TYPE is v:msgpack_types.string'))
eq(1, eval('dumped ==# dumped2'))
end)
it('can restore and dump BIN string with NL', function()
- execute('let dumped = ["\\xC4\\x01", ""]')
- execute('let parsed = msgpackparse(dumped)')
- execute('let dumped2 = msgpackdump(parsed)')
+ command('let dumped = ["\\xC4\\x01", ""]')
+ command('let parsed = msgpackparse(dumped)')
+ command('let dumped2 = msgpackdump(parsed)')
eq({"\n"}, eval('parsed'))
eq(1, eval('dumped ==# dumped2'))
end)
it('dump and restore special mapping with floating-point value', function()
- execute('let todump = {"_TYPE": v:msgpack_types.float, "_VAL": 0.125}')
+ command('let todump = {"_TYPE": v:msgpack_types.float, "_VAL": 0.125}')
eq({0.125}, eval('msgpackparse(msgpackdump([todump]))'))
end)
end)
@@ -394,52 +396,53 @@ describe('msgpackparse() function', function()
before_each(clear)
it('restores nil as v:null', function()
- execute('let dumped = ["\\xC0"]')
- execute('let parsed = msgpackparse(dumped)')
+ command('let dumped = ["\\xC0"]')
+ command('let parsed = msgpackparse(dumped)')
eq('[v:null]', eval('string(parsed)'))
end)
it('restores boolean false as v:false', function()
- execute('let dumped = ["\\xC2"]')
- execute('let parsed = msgpackparse(dumped)')
+ command('let dumped = ["\\xC2"]')
+ command('let parsed = msgpackparse(dumped)')
eq({false}, eval('parsed'))
end)
it('restores boolean true as v:true', function()
- execute('let dumped = ["\\xC3"]')
- execute('let parsed = msgpackparse(dumped)')
+ command('let dumped = ["\\xC3"]')
+ command('let parsed = msgpackparse(dumped)')
eq({true}, eval('parsed'))
end)
it('restores FIXSTR as special dict', function()
- execute('let dumped = ["\\xa2ab"]')
- execute('let parsed = msgpackparse(dumped)')
+ command('let dumped = ["\\xa2ab"]')
+ command('let parsed = msgpackparse(dumped)')
eq({{_TYPE={}, _VAL={'ab'}}}, eval('parsed'))
eq(1, eval('g:parsed[0]._TYPE is v:msgpack_types.string'))
end)
it('restores BIN 8 as string', function()
- execute('let dumped = ["\\xC4\\x02ab"]')
+ command('let dumped = ["\\xC4\\x02ab"]')
eq({'ab'}, eval('msgpackparse(dumped)'))
end)
it('restores FIXEXT1 as special dictionary', function()
- execute('let dumped = ["\\xD4\\x10", ""]')
- execute('let parsed = msgpackparse(dumped)')
+ command('let dumped = ["\\xD4\\x10", ""]')
+ command('let parsed = msgpackparse(dumped)')
eq({{_TYPE={}, _VAL={0x10, {"", ""}}}}, eval('parsed'))
eq(1, eval('g:parsed[0]._TYPE is v:msgpack_types.ext'))
end)
it('restores MAP with BIN key as special dictionary', function()
- execute('let dumped = ["\\x81\\xC4\\x01a\\xC4\\n"]')
- execute('let parsed = msgpackparse(dumped)')
+ command('let dumped = ["\\x81\\xC4\\x01a\\xC4\\n"]')
+ command('let parsed = msgpackparse(dumped)')
eq({{_TYPE={}, _VAL={{'a', ''}}}}, eval('parsed'))
eq(1, eval('g:parsed[0]._TYPE is v:msgpack_types.map'))
end)
it('restores MAP with duplicate STR keys as special dictionary', function()
- execute('let dumped = ["\\x82\\xA1a\\xC4\\n\\xA1a\\xC4\\n"]')
- execute('let parsed = msgpackparse(dumped)')
+ command('let dumped = ["\\x82\\xA1a\\xC4\\n\\xA1a\\xC4\\n"]')
+ -- FIXME Internal error bug
+ command('silent! let parsed = msgpackparse(dumped)')
eq({{_TYPE={}, _VAL={ {{_TYPE={}, _VAL={'a'}}, ''},
{{_TYPE={}, _VAL={'a'}}, ''}}} }, eval('parsed'))
eq(1, eval('g:parsed[0]._TYPE is v:msgpack_types.map'))
@@ -448,8 +451,8 @@ describe('msgpackparse() function', function()
end)
it('restores MAP with MAP key as special dictionary', function()
- execute('let dumped = ["\\x81\\x80\\xC4\\n"]')
- execute('let parsed = msgpackparse(dumped)')
+ command('let dumped = ["\\x81\\x80\\xC4\\n"]')
+ command('let parsed = msgpackparse(dumped)')
eq({{_TYPE={}, _VAL={{{}, ''}}}}, eval('parsed'))
eq(1, eval('g:parsed[0]._TYPE is v:msgpack_types.map'))
end)
@@ -460,7 +463,7 @@ describe('msgpackparse() function', function()
eval(cmd)
eval(cmd) -- do it again (try to force segfault)
local api_info = eval(cmd) -- do it again
- eq({'error_types', 'functions', 'types', 'version'}, api_info)
+ eq({'error_types', 'functions', 'types', 'ui_events', 'version'}, api_info)
end)
it('fails when called with no arguments', function()
@@ -494,7 +497,7 @@ describe('msgpackparse() function', function()
end)
it('fails to parse a partial', function()
- execute('function T() dict\nendfunction')
+ command('function T() dict\nendfunction')
eq('Vim(call):E686: Argument of msgpackparse() must be a List',
exc_exec('call msgpackparse(function("T", [1, 2], {}))'))
end)
@@ -514,10 +517,10 @@ describe('msgpackdump() function', function()
end)
it('can dump generic mapping with generic mapping keys and values', function()
- execute('let todump = {"_TYPE": v:msgpack_types.map, "_VAL": []}')
- execute('let todumpv1 = {"_TYPE": v:msgpack_types.map, "_VAL": []}')
- execute('let todumpv2 = {"_TYPE": v:msgpack_types.map, "_VAL": []}')
- execute('call add(todump._VAL, [todumpv1, todumpv2])')
+ command('let todump = {"_TYPE": v:msgpack_types.map, "_VAL": []}')
+ command('let todumpv1 = {"_TYPE": v:msgpack_types.map, "_VAL": []}')
+ command('let todumpv2 = {"_TYPE": v:msgpack_types.map, "_VAL": []}')
+ command('call add(todump._VAL, [todumpv1, todumpv2])')
eq({'\129\128\128'}, eval('msgpackdump([todump])'))
end)
@@ -530,130 +533,130 @@ describe('msgpackdump() function', function()
end)
it('can v:null', function()
- execute('let todump = v:null')
+ command('let todump = v:null')
end)
it('can dump special bool mapping (true)', function()
- execute('let todump = {"_TYPE": v:msgpack_types.boolean, "_VAL": 1}')
+ command('let todump = {"_TYPE": v:msgpack_types.boolean, "_VAL": 1}')
eq({'\195'}, eval('msgpackdump([todump])'))
end)
it('can dump special bool mapping (false)', function()
- execute('let todump = {"_TYPE": v:msgpack_types.boolean, "_VAL": 0}')
+ command('let todump = {"_TYPE": v:msgpack_types.boolean, "_VAL": 0}')
eq({'\194'}, eval('msgpackdump([todump])'))
end)
it('can dump special nil mapping', function()
- execute('let todump = {"_TYPE": v:msgpack_types.nil, "_VAL": 0}')
+ command('let todump = {"_TYPE": v:msgpack_types.nil, "_VAL": 0}')
eq({'\192'}, eval('msgpackdump([todump])'))
end)
it('can dump special ext mapping', function()
- execute('let todump = {"_TYPE": v:msgpack_types.ext, "_VAL": [5, ["",""]]}')
+ command('let todump = {"_TYPE": v:msgpack_types.ext, "_VAL": [5, ["",""]]}')
eq({'\212\005', ''}, eval('msgpackdump([todump])'))
end)
it('can dump special array mapping', function()
- execute('let todump = {"_TYPE": v:msgpack_types.array, "_VAL": [5, [""]]}')
+ command('let todump = {"_TYPE": v:msgpack_types.array, "_VAL": [5, [""]]}')
eq({'\146\005\145\196\n'}, eval('msgpackdump([todump])'))
end)
it('can dump special UINT64_MAX mapping', function()
- execute('let todump = {"_TYPE": v:msgpack_types.integer}')
- execute('let todump._VAL = [1, 3, 0x7FFFFFFF, 0x7FFFFFFF]')
+ command('let todump = {"_TYPE": v:msgpack_types.integer}')
+ command('let todump._VAL = [1, 3, 0x7FFFFFFF, 0x7FFFFFFF]')
eq({'\207\255\255\255\255\255\255\255\255'}, eval('msgpackdump([todump])'))
end)
it('can dump special INT64_MIN mapping', function()
- execute('let todump = {"_TYPE": v:msgpack_types.integer}')
- execute('let todump._VAL = [-1, 2, 0, 0]')
+ command('let todump = {"_TYPE": v:msgpack_types.integer}')
+ command('let todump._VAL = [-1, 2, 0, 0]')
eq({'\211\128\n\n\n\n\n\n\n'}, eval('msgpackdump([todump])'))
end)
it('fails to dump a function reference', function()
- execute('let Todump = function("tr")')
+ command('let Todump = function("tr")')
eq('Vim(call):E5004: Error while dumping msgpackdump() argument, index 0, itself: attempt to dump function reference',
exc_exec('call msgpackdump([Todump])'))
end)
it('fails to dump a partial', function()
- execute('function T() dict\nendfunction')
- execute('let Todump = function("T", [1, 2], {})')
+ command('function T() dict\nendfunction')
+ command('let Todump = function("T", [1, 2], {})')
eq('Vim(call):E5004: Error while dumping msgpackdump() argument, index 0, itself: attempt to dump function reference',
exc_exec('call msgpackdump([Todump])'))
end)
it('fails to dump a function reference in a list', function()
- execute('let todump = [function("tr")]')
+ command('let todump = [function("tr")]')
eq('Vim(call):E5004: Error while dumping msgpackdump() argument, index 0, index 0: attempt to dump function reference',
exc_exec('call msgpackdump([todump])'))
end)
it('fails to dump a recursive list', function()
- execute('let todump = [[[]]]')
- execute('call add(todump[0][0], todump)')
+ command('let todump = [[[]]]')
+ command('call add(todump[0][0], todump)')
eq('Vim(call):E5005: Unable to dump msgpackdump() argument, index 0: container references itself in index 0, index 0, index 0',
exc_exec('call msgpackdump([todump])'))
end)
it('fails to dump a recursive dict', function()
- execute('let todump = {"d": {"d": {}}}')
- execute('call extend(todump.d.d, {"d": todump})')
+ command('let todump = {"d": {"d": {}}}')
+ command('call extend(todump.d.d, {"d": todump})')
eq('Vim(call):E5005: Unable to dump msgpackdump() argument, index 0: container references itself in key \'d\', key \'d\', key \'d\'',
exc_exec('call msgpackdump([todump])'))
end)
it('can dump dict with two same dicts inside', function()
- execute('let inter = {}')
- execute('let todump = {"a": inter, "b": inter}')
+ command('let inter = {}')
+ command('let todump = {"a": inter, "b": inter}')
eq({"\130\161a\128\161b\128"}, eval('msgpackdump([todump])'))
end)
it('can dump list with two same lists inside', function()
- execute('let inter = []')
- execute('let todump = [inter, inter]')
+ command('let inter = []')
+ command('let todump = [inter, inter]')
eq({"\146\144\144"}, eval('msgpackdump([todump])'))
end)
it('fails to dump a recursive list in a special dict', function()
- execute('let todump = {"_TYPE": v:msgpack_types.array, "_VAL": []}')
- execute('call add(todump._VAL, todump)')
+ command('let todump = {"_TYPE": v:msgpack_types.array, "_VAL": []}')
+ command('call add(todump._VAL, todump)')
eq('Vim(call):E5005: Unable to dump msgpackdump() argument, index 0: container references itself in index 0',
exc_exec('call msgpackdump([todump])'))
end)
it('fails to dump a recursive (key) map in a special dict', function()
- execute('let todump = {"_TYPE": v:msgpack_types.map, "_VAL": []}')
- execute('call add(todump._VAL, [todump, 0])')
+ command('let todump = {"_TYPE": v:msgpack_types.map, "_VAL": []}')
+ command('call add(todump._VAL, [todump, 0])')
eq('Vim(call):E5005: Unable to dump msgpackdump() argument, index 0: container references itself in index 1',
exc_exec('call msgpackdump([todump])'))
end)
it('fails to dump a recursive (val) map in a special dict', function()
- execute('let todump = {"_TYPE": v:msgpack_types.map, "_VAL": []}')
- execute('call add(todump._VAL, [0, todump])')
+ command('let todump = {"_TYPE": v:msgpack_types.map, "_VAL": []}')
+ command('call add(todump._VAL, [0, todump])')
eq('Vim(call):E5005: Unable to dump msgpackdump() argument, index 0: container references itself in key 0 at index 0 from special map',
exc_exec('call msgpackdump([todump])'))
end)
it('fails to dump a recursive (key) map in a special dict, _VAL reference', function()
- execute('let todump = {"_TYPE": v:msgpack_types.map, "_VAL": [[[], []]]}')
- execute('call add(todump._VAL[0][0], todump._VAL)')
+ command('let todump = {"_TYPE": v:msgpack_types.map, "_VAL": [[[], []]]}')
+ command('call add(todump._VAL[0][0], todump._VAL)')
eq('Vim(call):E5005: Unable to dump msgpackdump() argument, index 0: container references itself in key [[[[...@0], []]]] at index 0 from special map, index 0',
exc_exec('call msgpackdump([todump])'))
end)
it('fails to dump a recursive (val) map in a special dict, _VAL reference', function()
- execute('let todump = {"_TYPE": v:msgpack_types.map, "_VAL": [[[], []]]}')
- execute('call add(todump._VAL[0][1], todump._VAL)')
+ command('let todump = {"_TYPE": v:msgpack_types.map, "_VAL": [[[], []]]}')
+ command('call add(todump._VAL[0][1], todump._VAL)')
eq('Vim(call):E5005: Unable to dump msgpackdump() argument, index 0: container references itself in key [] at index 0 from special map, index 0',
exc_exec('call msgpackdump([todump])'))
end)
it('fails to dump a recursive (val) special list in a special dict',
function()
- execute('let todump = {"_TYPE": v:msgpack_types.array, "_VAL": []}')
- execute('call add(todump._VAL, [0, todump._VAL])')
+ command('let todump = {"_TYPE": v:msgpack_types.array, "_VAL": []}')
+ command('call add(todump._VAL, [0, todump._VAL])')
eq('Vim(call):E5005: Unable to dump msgpackdump() argument, index 0: container references itself in index 0, index 1',
exc_exec('call msgpackdump([todump])'))
end)
@@ -689,7 +692,7 @@ describe('msgpackdump() function', function()
end)
it('fails to dump a partial', function()
- execute('function T() dict\nendfunction')
+ command('function T() dict\nendfunction')
eq('Vim(call):E686: Argument of msgpackdump() must be a List',
exc_exec('call msgpackdump(function("T", [1, 2], {}))'))
end)
diff --git a/test/functional/eval/null_spec.lua b/test/functional/eval/null_spec.lua
new file mode 100644
index 0000000000..6fd30caec9
--- /dev/null
+++ b/test/functional/eval/null_spec.lua
@@ -0,0 +1,138 @@
+local helpers = require('test.functional.helpers')(after_each)
+
+local curbufmeths = helpers.curbufmeths
+local redir_exec = helpers.redir_exec
+local exc_exec = helpers.exc_exec
+local command = helpers.command
+local clear = helpers.clear
+local meths = helpers.meths
+local funcs = helpers.funcs
+local eq = helpers.eq
+
+describe('NULL', function()
+ before_each(function()
+ clear()
+ command('let L = v:_null_list')
+ command('let D = v:_null_dict')
+ command('let S = $XXX_NONEXISTENT_VAR_XXX')
+ end)
+ local tmpfname = 'Xtest-functional-viml-null'
+ after_each(function()
+ os.remove(tmpfname)
+ end)
+ local null_test = function(name, cmd, err)
+ it(name, function()
+ eq(err, exc_exec(cmd))
+ end)
+ end
+ local null_expr_test = function(name, expr, err, val, after)
+ it(name, function()
+ eq((err == 0) and ('') or ('\n' .. err),
+ redir_exec('let g:_var = ' .. expr))
+ if val == nil then
+ eq(0, funcs.exists('g:_var'))
+ else
+ eq(val, meths.get_var('_var'))
+ end
+ if after ~= nil then
+ after()
+ end
+ end)
+ end
+ describe('list', function()
+ -- Incorrect behaviour
+
+ -- FIXME map() should not return 0 without error
+ null_expr_test('does not crash map()', 'map(L, "v:val")', 0, 0)
+ -- FIXME map() should not return 0 without error
+ null_expr_test('does not crash filter()', 'filter(L, "1")', 0, 0)
+ -- FIXME map() should at least return L
+ null_expr_test('makes map() return v:_null_list', 'map(L, "v:val") is# L', 0, 0)
+ -- FIXME filter() should at least return L
+ null_expr_test('makes filter() return v:_null_list', 'map(L, "1") is# L', 0, 0)
+ -- FIXME add() should not return 1 at all
+ null_expr_test('does not crash add()', 'add(L, 0)', 0, 1)
+ null_expr_test('does not crash extend()', 'extend(L, [1])', 'E742: Cannot change value of extend() argument', 0)
+ null_expr_test('does not crash extend() (second position)', 'extend([1], L)', 0, {1})
+ -- FIXME should be accepted by inputlist()
+ null_expr_test('is accepted as an empty list by inputlist()',
+ '[feedkeys("\\n"), inputlist(L)]', 'E686: Argument of inputlist() must be a List', {0, 0})
+ -- FIXME should be accepted by writefile(), return {0, {}}
+ null_expr_test('is accepted as an empty list by writefile()',
+ ('[writefile(L, "%s"), readfile("%s")]'):format(tmpfname, tmpfname),
+ 'E484: Can\'t open file ' .. tmpfname, {0, {}})
+ -- FIXME should give error message
+ null_expr_test('does not crash remove()', 'remove(L, 0)', 0, 0)
+ -- FIXME should return 0
+ null_expr_test('is accepted by setqflist()', 'setqflist(L)', 0, -1)
+ -- FIXME should return 0
+ null_expr_test('is accepted by setloclist()', 'setloclist(1, L)', 0, -1)
+ -- FIXME should return 0
+ null_expr_test('is accepted by setmatches()', 'setmatches(L)', 0, -1)
+ -- FIXME should return empty list or error out
+ null_expr_test('is accepted by sort()', 'sort(L)', 0, 0)
+ -- FIXME Should return 1
+ null_expr_test('is accepted by sort()', 'sort(L) is L', 0, 0)
+ -- FIXME should not error out
+ null_test('is accepted by :cexpr', 'cexpr L', 'Vim(cexpr):E777: String or List expected')
+ -- FIXME should not error out
+ null_test('is accepted by :lexpr', 'lexpr L', 'Vim(lexpr):E777: String or List expected')
+ null_test('is accepted by :for', 'for x in L|throw x|endfor', 0)
+
+ -- Subjectable behaviour
+
+ -- FIXME Should return 1
+ null_expr_test('is equal to empty list', 'L == []', 0, 0)
+ -- FIXME Should return 1
+ null_expr_test('is equal to empty list (reverse order)', '[] == L', 0, 0)
+ -- FIXME Should return 1
+ null_expr_test('is not locked', 'islocked("v:_null_list")', 0, 0)
+
+ -- Crashes
+
+ -- null_expr_test('does not crash setreg', 'setreg("x", L)', 0, 0)
+ -- null_expr_test('does not crash setline', 'setline(1, L)', 0, 0)
+ -- null_expr_test('does not crash system()', 'system("cat", L)', 0, '')
+ -- null_expr_test('does not crash systemlist()', 'systemlist("cat", L)', 0, {})
+
+ -- Correct behaviour
+ null_expr_test('does not crash append()', 'append(1, L)', 0, 0, function()
+ eq({''}, curbufmeths.get_lines(0, -1, false))
+ end)
+ null_expr_test('is identical to itself', 'L is L', 0, 1)
+ null_expr_test('can be sliced', 'L[:]', 0, {})
+ null_expr_test('can be copied', 'copy(L)', 0, {})
+ null_expr_test('can be deepcopied', 'deepcopy(L)', 0, {})
+ null_expr_test('does not crash when indexed', 'L[1]',
+ 'E684: list index out of range: 1\nE15: Invalid expression: L[1]', nil)
+ null_expr_test('does not crash call()', 'call("arglistid", L)', 0, 0)
+ null_expr_test('does not crash col()', 'col(L)', 0, 0)
+ null_expr_test('does not crash virtcol()', 'virtcol(L)', 0, 0)
+ null_expr_test('does not crash line()', 'line(L)', 0, 0)
+ null_expr_test('does not crash count()', 'count(L, 1)', 0, 0)
+ null_expr_test('does not crash cursor()', 'cursor(L)', 'E474: Invalid argument', -1)
+ null_expr_test('is empty', 'empty(L)', 0, 1)
+ null_expr_test('does not crash get()', 'get(L, 1, 10)', 0, 10)
+ null_expr_test('has zero length', 'len(L)', 0, 0)
+ null_expr_test('is accepted as an empty list by max()', 'max(L)', 0, 0)
+ null_expr_test('is accepted as an empty list by min()', 'min(L)', 0, 0)
+ null_expr_test('is stringified correctly', 'string(L)', 0, '[]')
+ null_expr_test('is JSON encoded correctly', 'json_encode(L)', 0, '[]')
+ null_test('does not crash lockvar', 'lockvar! L', 0)
+ null_expr_test('can be added to itself', '(L + L)', 0, {})
+ null_expr_test('can be added to itself', '(L + L) is L', 0, 1)
+ null_expr_test('can be added to non-empty list', '([1] + L)', 0, {1})
+ null_expr_test('can be added to non-empty list (reversed)', '(L + [1])', 0, {1})
+ null_expr_test('is equal to itself', 'L == L', 0, 1)
+ null_expr_test('is not not equal to itself', 'L != L', 0, 0)
+ null_expr_test('counts correctly', 'count([L], L)', 0, 1)
+ end)
+ describe('dict', function()
+ it('does not crash when indexing NULL dict', function()
+ eq('\nE716: Key not present in Dictionary: test\nE15: Invalid expression: v:_null_dict.test',
+ redir_exec('echo v:_null_dict.test'))
+ end)
+ null_expr_test('makes extend error out', 'extend(D, {})', 'E742: Cannot change value of extend() argument', 0)
+ null_expr_test('makes extend do nothing', 'extend({1: 2}, D)', 0, {['1']=2})
+ end)
+end)
diff --git a/test/functional/eval/reltime_spec.lua b/test/functional/eval/reltime_spec.lua
index 0b19d372ec..0181f09024 100644
--- a/test/functional/eval/reltime_spec.lua
+++ b/test/functional/eval/reltime_spec.lua
@@ -1,6 +1,6 @@
local helpers = require('test.functional.helpers')(after_each)
local clear, eq, ok = helpers.clear, helpers.eq, helpers.ok
-local neq, execute, funcs = helpers.neq, helpers.execute, helpers.funcs
+local neq, command, funcs = helpers.neq, helpers.command, helpers.funcs
local reltime, reltimestr, reltimefloat = funcs.reltime, funcs.reltimestr, funcs.reltimefloat
describe('reltimestr(), reltimefloat()', function()
@@ -8,7 +8,7 @@ describe('reltimestr(), reltimefloat()', function()
it('Checks', function()
local now = reltime()
- execute('sleep 10m')
+ command('sleep 10m')
local later = reltime()
local elapsed = reltime(now)
diff --git a/test/functional/eval/server_spec.lua b/test/functional/eval/server_spec.lua
index 420aea04aa..393616838e 100644
--- a/test/functional/eval/server_spec.lua
+++ b/test/functional/eval/server_spec.lua
@@ -1,20 +1,27 @@
local helpers = require('test.functional.helpers')(after_each)
-local nvim, eq, neq, eval = helpers.nvim, helpers.eq, helpers.neq, helpers.eval
+local eq, neq, eval = helpers.eq, helpers.neq, helpers.eval
+local command = helpers.command
local clear, funcs, meths = helpers.clear, helpers.funcs, helpers.meths
local os_name = helpers.os_name
+local function clear_serverlist()
+ for _, server in pairs(funcs.serverlist()) do
+ funcs.serverstop(server)
+ end
+end
+
describe('serverstart(), serverstop()', function()
before_each(clear)
it('sets $NVIM_LISTEN_ADDRESS on first invocation', function()
-- Unset $NVIM_LISTEN_ADDRESS
- nvim('command', 'let $NVIM_LISTEN_ADDRESS = ""')
+ command('let $NVIM_LISTEN_ADDRESS = ""')
local s = eval('serverstart()')
assert(s ~= nil and s:len() > 0, "serverstart() returned empty")
eq(s, eval('$NVIM_LISTEN_ADDRESS'))
- nvim('command', "call serverstop('"..s.."')")
+ command("call serverstop('"..s.."')")
eq('', eval('$NVIM_LISTEN_ADDRESS'))
end)
@@ -47,10 +54,48 @@ describe('serverstart(), serverstop()', function()
end)
it('serverstop() ignores invalid input', function()
- nvim('command', "call serverstop('')")
- nvim('command', "call serverstop('bogus-socket-name')")
+ command("call serverstop('')")
+ command("call serverstop('bogus-socket-name')")
end)
+ it('parses endpoints correctly', function()
+ clear_serverlist()
+ eq({}, funcs.serverlist())
+
+ local s = funcs.serverstart('127.0.0.1:0') -- assign random port
+ if #s > 0 then
+ assert(string.match(s, '127.0.0.1:%d+'))
+ eq(s, funcs.serverlist()[1])
+ clear_serverlist()
+ end
+
+ s = funcs.serverstart('127.0.0.1:') -- assign random port
+ if #s > 0 then
+ assert(string.match(s, '127.0.0.1:%d+'))
+ eq(s, funcs.serverlist()[1])
+ clear_serverlist()
+ end
+
+ local expected = {}
+ local v4 = '127.0.0.1:12345'
+ s = funcs.serverstart(v4)
+ if #s > 0 then
+ table.insert(expected, v4)
+ funcs.serverstart(v4) -- exists already; ignore
+ end
+
+ local v6 = '::1:12345'
+ s = funcs.serverstart(v6)
+ if #s > 0 then
+ table.insert(expected, v6)
+ funcs.serverstart(v6) -- exists already; ignore
+ end
+ eq(expected, funcs.serverlist())
+ clear_serverlist()
+
+ funcs.serverstart('127.0.0.1:65536') -- invalid port
+ eq({}, funcs.serverlist())
+ end)
end)
describe('serverlist()', function()
@@ -75,7 +120,7 @@ describe('serverlist()', function()
-- The new servers should be at the end of the list.
for i = 1, #servs do
eq(servs[i], new_servs[i + n])
- nvim('command', "call serverstop('"..servs[i].."')")
+ command("call serverstop('"..servs[i].."')")
end
-- After serverstop() the servers should NOT be in the list.
eq(n, eval('len(serverlist())'))
diff --git a/test/functional/eval/setpos_spec.lua b/test/functional/eval/setpos_spec.lua
index 2e27cd8ac0..6a8b3a8732 100644
--- a/test/functional/eval/setpos_spec.lua
+++ b/test/functional/eval/setpos_spec.lua
@@ -3,7 +3,7 @@ local setpos = helpers.funcs.setpos
local getpos = helpers.funcs.getpos
local insert = helpers.insert
local clear = helpers.clear
-local execute = helpers.execute
+local command = helpers.command
local eval = helpers.eval
local eq = helpers.eq
local exc_exec = helpers.exc_exec
@@ -16,7 +16,7 @@ describe('setpos() function', function()
First line of text
Second line of text
Third line of text]])
- execute('new')
+ command('new')
insert([[
Line of text 1
Line of text 2
@@ -34,7 +34,8 @@ describe('setpos() function', function()
it('can set lowercase marks in the current buffer', function()
setpos("'d", {0, 2, 1, 0})
eq(getpos("'d"), {0, 2, 1, 0})
- execute('undo', 'call setpos("\'d", [2, 3, 1, 0])')
+ command('undo')
+ command('call setpos("\'d", [2, 3, 1, 0])')
eq(getpos("'d"), {0, 3, 1, 0})
end)
it('can set lowercase marks in other buffers', function()
@@ -42,7 +43,7 @@ describe('setpos() function', function()
eq(0, retval)
setpos("'d", {1, 2, 1, 0})
eq(getpos("'d"), {0, 0, 0, 0})
- execute('wincmd w')
+ command('wincmd w')
eq(eval('bufnr("%")'), 1)
eq(getpos("'d"), {0, 2, 1, 0})
end)
diff --git a/test/functional/eval/sort_spec.lua b/test/functional/eval/sort_spec.lua
new file mode 100644
index 0000000000..4e5a0afba4
--- /dev/null
+++ b/test/functional/eval/sort_spec.lua
@@ -0,0 +1,41 @@
+local helpers = require('test.functional.helpers')(after_each)
+
+local eq = helpers.eq
+local NIL = helpers.NIL
+local eval = helpers.eval
+local clear = helpers.clear
+local meths = helpers.meths
+local funcs = helpers.funcs
+local command = helpers.command
+local exc_exec = helpers.exc_exec
+
+before_each(clear)
+
+describe('sort()', function()
+ it('errors out when sorting special values', function()
+ eq('Vim(call):E907: Using a special value as a Float',
+ exc_exec('call sort([v:true, v:false], "f")'))
+ end)
+
+ it('sorts “wrong” values between -0.0001 and 0.0001, preserving order',
+ function()
+ meths.set_var('list', {true, false, NIL, {}, {a=42}, 'check',
+ 0.0001, -0.0001})
+ command('call insert(g:list, function("tr"))')
+ local error_lines = funcs.split(
+ funcs.execute('silent! call sort(g:list, "f")'), '\n')
+ local errors = {}
+ for _, err in ipairs(error_lines) do
+ errors[err] = true
+ end
+ eq({
+ ['E891: Using a Funcref as a Float']=true,
+ ['E892: Using a String as a Float']=true,
+ ['E893: Using a List as a Float']=true,
+ ['E894: Using a Dictionary as a Float']=true,
+ ['E907: Using a special value as a Float']=true,
+ }, errors)
+ eq('[-1.0e-4, function(\'tr\'), v:true, v:false, v:null, [], {\'a\': 42}, \'check\', 1.0e-4]',
+ eval('string(g:list)'))
+ end)
+end)
diff --git a/test/functional/eval/special_vars_spec.lua b/test/functional/eval/special_vars_spec.lua
index 4c5d63ce23..b5773a5529 100644
--- a/test/functional/eval/special_vars_spec.lua
+++ b/test/functional/eval/special_vars_spec.lua
@@ -1,6 +1,6 @@
local helpers = require('test.functional.helpers')(after_each)
local exc_exec = helpers.exc_exec
-local execute = helpers.execute
+local command = helpers.command
local funcs = helpers.funcs
local clear = helpers.clear
local eval = helpers.eval
@@ -12,7 +12,7 @@ describe('Special values', function()
before_each(clear)
it('do not cause error when freed', function()
- execute([[
+ command([[
function Test()
try
return v:true
@@ -109,7 +109,7 @@ describe('Special values', function()
it('does not work with +=/-=/.=', function()
meths.set_var('true', true)
meths.set_var('false', false)
- execute('let null = v:null')
+ command('let null = v:null')
eq('Vim(let):E734: Wrong variable type for +=', exc_exec('let true += 1'))
eq('Vim(let):E734: Wrong variable type for +=', exc_exec('let false += 1'))
@@ -168,4 +168,11 @@ describe('Special values', function()
'Expected True but got v:null',
}, meths.get_vvar('errors'))
end)
+
+ describe('compat', function()
+ it('v:count is distinct from count', function()
+ command('let count = []') -- v:count is readonly
+ eq(1, eval('count is# g:["count"]'))
+ end)
+ end)
end)
diff --git a/test/functional/eval/string_spec.lua b/test/functional/eval/string_spec.lua
index f6279e85e8..adc1af9b8e 100644
--- a/test/functional/eval/string_spec.lua
+++ b/test/functional/eval/string_spec.lua
@@ -7,7 +7,6 @@ local eval = helpers.eval
local exc_exec = helpers.exc_exec
local redir_exec = helpers.redir_exec
local funcs = helpers.funcs
-local write_file = helpers.write_file
local NIL = helpers.NIL
local source = helpers.source
local dedent = helpers.dedent
@@ -105,10 +104,8 @@ describe('string() function', function()
end)
describe('used to represent funcrefs', function()
- local fname = 'Xtest-functional-eval-string_spec-fref-script.vim'
-
before_each(function()
- write_file(fname, [[
+ source([[
function Test1()
endfunction
@@ -120,11 +117,6 @@ describe('string() function', function()
let g:Test2_f = function('s:Test2')
]])
- command('source ' .. fname)
- end)
-
- after_each(function()
- os.remove(fname)
end)
it('dumps references to built-in functions', function()
diff --git a/test/functional/eval/system_spec.lua b/test/functional/eval/system_spec.lua
index ee75b593ff..7e213e2156 100644
--- a/test/functional/eval/system_spec.lua
+++ b/test/functional/eval/system_spec.lua
@@ -1,7 +1,11 @@
local helpers = require('test.functional.helpers')(after_each)
-local eq, call, clear, eval, execute, feed, nvim =
- helpers.eq, helpers.call, helpers.clear, helpers.eval, helpers.execute,
+
+local nvim_dir = helpers.nvim_dir
+local eq, call, clear, eval, feed_command, feed, nvim =
+ helpers.eq, helpers.call, helpers.clear, helpers.eval, helpers.feed_command,
helpers.feed, helpers.nvim
+local command = helpers.command
+local iswin = helpers.iswin
local Screen = require('test.functional.ui.screen')
@@ -31,8 +35,7 @@ describe('system()', function()
describe('command passed as a List', function()
local function printargs_path()
- return helpers.nvim_dir..'/printargs-test'
- .. (helpers.os_name() == 'windows' and '.exe' or '')
+ return nvim_dir..'/printargs-test' .. (iswin() and '.exe' or '')
end
it('sets v:shell_error if cmd[0] is not executable', function()
@@ -43,10 +46,10 @@ describe('system()', function()
it('parameter validation does NOT modify v:shell_error', function()
-- 1. Call system() with invalid parameters.
-- 2. Assert that v:shell_error was NOT set.
- execute('call system({})')
+ feed_command('call system({})')
eq('E475: Invalid argument: expected String or List', eval('v:errmsg'))
eq(0, eval('v:shell_error'))
- execute('call system([])')
+ feed_command('call system([])')
eq('E474: Invalid argument', eval('v:errmsg'))
eq(0, eval('v:shell_error'))
@@ -57,9 +60,9 @@ describe('system()', function()
-- 1. Call system() with invalid parameters.
-- 2. Assert that v:shell_error was NOT modified.
- execute('call system({})')
+ feed_command('call system({})')
eq(old_val, eval('v:shell_error'))
- execute('call system([])')
+ feed_command('call system([])')
eq(old_val, eval('v:shell_error'))
end)
@@ -86,23 +89,32 @@ describe('system()', function()
end)
it('does NOT run in shell', function()
- if helpers.os_name() ~= 'windows' then
+ if not iswin() then
eq("* $PATH %PATH%\n", eval("system(['echo', '*', '$PATH', '%PATH%'])"))
end
end)
end)
- if helpers.pending_win32(pending) then return end
-
it('sets v:shell_error', function()
- eval([[system("sh -c 'exit'")]])
- eq(0, eval('v:shell_error'))
- eval([[system("sh -c 'exit 1'")]])
- eq(1, eval('v:shell_error'))
- eval([[system("sh -c 'exit 5'")]])
- eq(5, eval('v:shell_error'))
- eval([[system('this-should-not-exist')]])
- eq(127, eval('v:shell_error'))
+ if iswin() then
+ eval([[system("cmd.exe /c exit")]])
+ eq(0, eval('v:shell_error'))
+ eval([[system("cmd.exe /c exit 1")]])
+ eq(1, eval('v:shell_error'))
+ eval([[system("cmd.exe /c exit 5")]])
+ eq(5, eval('v:shell_error'))
+ eval([[system('this-should-not-exist')]])
+ eq(1, eval('v:shell_error'))
+ else
+ eval([[system("sh -c 'exit'")]])
+ eq(0, eval('v:shell_error'))
+ eval([[system("sh -c 'exit 1'")]])
+ eq(1, eval('v:shell_error'))
+ eval([[system("sh -c 'exit 5'")]])
+ eq(5, eval('v:shell_error'))
+ eval([[system('this-should-not-exist')]])
+ eq(127, eval('v:shell_error'))
+ end
end)
describe('executes shell function if passed a string', function()
@@ -118,6 +130,40 @@ describe('system()', function()
screen:detach()
end)
+ if iswin() then
+ it('with shell=cmd.exe', function()
+ command('set shell=cmd.exe')
+ eq('""\n', eval([[system('echo ""')]]))
+ eq('"a b"\n', eval([[system('echo "a b"')]]))
+ eq('a \nb\n', eval([[system('echo a & echo b')]]))
+ eq('a \n', eval([[system('echo a 2>&1')]]))
+ eval([[system('cd "C:\Program Files"')]])
+ eq(0, eval('v:shell_error'))
+ end)
+
+ it('with shell=cmd', function()
+ command('set shell=cmd')
+ eq('"a b"\n', eval([[system('echo "a b"')]]))
+ end)
+
+ it('with shell=$COMSPEC', function()
+ local comspecshell = eval("fnamemodify($COMSPEC, ':t')")
+ if comspecshell == 'cmd.exe' then
+ command('set shell=$COMSPEC')
+ eq('"a b"\n', eval([[system('echo "a b"')]]))
+ else
+ pending('$COMSPEC is not cmd.exe: ' .. comspecshell)
+ end
+ end)
+
+ it('works with powershell', function()
+ helpers.set_shell_powershell()
+ eq('a\nb\n', eval([[system('echo a b')]]))
+ eq('C:\\\n', eval([[system('cd c:\; (Get-Location).Path')]]))
+ eq('a b\n', eval([[system('echo "a b"')]]))
+ end)
+ end
+
it('`echo` and waits for its return', function()
feed(':call system("echo")<cr>')
screen:expect([[
@@ -178,11 +224,15 @@ describe('system()', function()
describe('passing no input', function()
it('returns the program output', function()
- eq("echoed", eval('system("echo -n echoed")'))
+ if iswin() then
+ eq("echoed\n", eval('system("echo echoed")'))
+ else
+ eq("echoed", eval('system("echo -n echoed")'))
+ end
end)
it('to backgrounded command does not crash', function()
-- This is indeterminate, just exercise the codepath. May get E5677.
- execute('call system("echo -n echoed &")')
+ feed_command('call system("echo -n echoed &")')
local v_errnum = string.match(eval("v:errmsg"), "^E%d*:")
if v_errnum then
eq("E5677:", v_errnum)
@@ -197,7 +247,7 @@ describe('system()', function()
end)
it('to backgrounded command does not crash', function()
-- This is indeterminate, just exercise the codepath. May get E5677.
- execute('call system("cat - &")')
+ feed_command('call system("cat - &")')
local v_errnum = string.match(eval("v:errmsg"), "^E%d*:")
if v_errnum then
eq("E5677:", v_errnum)
@@ -275,21 +325,30 @@ describe('system()', function()
end)
end)
-if helpers.pending_win32(pending) then return end
-
describe('systemlist()', function()
-- Similar to `system()`, but returns List instead of String.
before_each(clear)
- it('sets the v:shell_error variable', function()
- eval([[systemlist("sh -c 'exit'")]])
- eq(0, eval('v:shell_error'))
- eval([[systemlist("sh -c 'exit 1'")]])
- eq(1, eval('v:shell_error'))
- eval([[systemlist("sh -c 'exit 5'")]])
- eq(5, eval('v:shell_error'))
- eval([[systemlist('this-should-not-exist')]])
- eq(127, eval('v:shell_error'))
+ it('sets v:shell_error', function()
+ if iswin() then
+ eval([[systemlist("cmd.exe /c exit")]])
+ eq(0, eval('v:shell_error'))
+ eval([[systemlist("cmd.exe /c exit 1")]])
+ eq(1, eval('v:shell_error'))
+ eval([[systemlist("cmd.exe /c exit 5")]])
+ eq(5, eval('v:shell_error'))
+ eval([[systemlist('this-should-not-exist')]])
+ eq(1, eval('v:shell_error'))
+ else
+ eval([[systemlist("sh -c 'exit'")]])
+ eq(0, eval('v:shell_error'))
+ eval([[systemlist("sh -c 'exit 1'")]])
+ eq(1, eval('v:shell_error'))
+ eval([[systemlist("sh -c 'exit 5'")]])
+ eq(5, eval('v:shell_error'))
+ eval([[systemlist('this-should-not-exist')]])
+ eq(127, eval('v:shell_error'))
+ end
end)
describe('exectues shell function', function()
@@ -387,6 +446,7 @@ describe('systemlist()', function()
after_each(delete_file(fname))
it('replaces NULs by newline characters', function()
+ if helpers.pending_win32(pending) then return end
eq({'part1\npart2\npart3'}, eval('systemlist("cat '..fname..'")'))
end)
end)
diff --git a/test/functional/eval/timer_spec.lua b/test/functional/eval/timer_spec.lua
index 4353619ff0..2dd9968a01 100644
--- a/test/functional/eval/timer_spec.lua
+++ b/test/functional/eval/timer_spec.lua
@@ -2,7 +2,7 @@ local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen')
local ok, feed, eq, eval = helpers.ok, helpers.feed, helpers.eq, helpers.eval
local source, nvim_async, run = helpers.source, helpers.nvim_async, helpers.run
-local clear, execute, funcs = helpers.clear, helpers.execute, helpers.funcs
+local clear, command, funcs = helpers.clear, helpers.command, helpers.funcs
local curbufmeths = helpers.curbufmeths
describe('timers', function()
@@ -17,14 +17,14 @@ describe('timers', function()
end)
it('works one-shot', function()
- execute("call timer_start(50, 'MyHandler')")
+ command("call timer_start(50, 'MyHandler')")
eq(0,eval("g:val"))
run(nil, nil, nil, 200)
eq(1,eval("g:val"))
end)
it('works one-shot when repeat=0', function()
- execute("call timer_start(50, 'MyHandler', {'repeat': 0})")
+ command("call timer_start(50, 'MyHandler', {'repeat': 0})")
eq(0,eval("g:val"))
run(nil, nil, nil, 200)
eq(1,eval("g:val"))
@@ -32,14 +32,14 @@ describe('timers', function()
it('works with repeat two', function()
- execute("call timer_start(50, 'MyHandler', {'repeat': 2})")
+ command("call timer_start(50, 'MyHandler', {'repeat': 2})")
eq(0,eval("g:val"))
run(nil, nil, nil, 300)
eq(2,eval("g:val"))
end)
it('are triggered during sleep', function()
- execute("call timer_start(50, 'MyHandler', {'repeat': 2})")
+ command("call timer_start(50, 'MyHandler', {'repeat': 2})")
nvim_async("command", "sleep 10")
eq(0,eval("g:val"))
run(nil, nil, nil, 300)
@@ -49,7 +49,7 @@ describe('timers', function()
it('works with zero timeout', function()
-- timer_start does still not invoke the callback immediately
eq(0,eval("[timer_start(0, 'MyHandler', {'repeat': 1000}), g:val][1]"))
- run(nil, nil, nil, 300)
+ run(nil, nil, nil, 400)
eq(1000,eval("g:val"))
end)
@@ -63,12 +63,12 @@ describe('timers', function()
end)
it('are paused when event processing is disabled', function()
- execute("call timer_start(50, 'MyHandler', {'repeat': -1})")
+ command("call timer_start(50, 'MyHandler', {'repeat': -1})")
run(nil, nil, nil, 100)
local count = eval("g:val")
-- shows two line error message and thus invokes the return prompt.
-- if we start to allow event processing here, we need to change this test.
- execute("throw 'fatal error'")
+ feed(':throw "fatal error"<CR>')
run(nil, nil, nil, 300)
feed("<cr>")
local diff = eval("g:val") - count
@@ -76,7 +76,7 @@ describe('timers', function()
end)
it('are triggered in blocking getchar() call', function()
- execute("call timer_start(50, 'MyHandler', {'repeat': -1})")
+ command("call timer_start(50, 'MyHandler', {'repeat': -1})")
nvim_async("command", "let g:c = getchar()")
run(nil, nil, nil, 300)
feed("c")
@@ -157,7 +157,7 @@ describe('timers', function()
endif
endfunc
]])
- execute("call timer_start(50, 'MyHandler', {'repeat': -1})")
+ command("call timer_start(50, 'MyHandler', {'repeat': -1})")
eq(0,eval("g:val"))
run(nil, nil, nil, 300)
eq(3,eval("g:val"))
@@ -170,8 +170,8 @@ describe('timers', function()
let g:val2 += 1
endfunc
]])
- execute("call timer_start(50, 'MyHandler', {'repeat': 3})")
- execute("call timer_start(100, 'MyHandler2', {'repeat': 2})")
+ command("call timer_start(50, 'MyHandler', {'repeat': 3})")
+ command("call timer_start(100, 'MyHandler2', {'repeat': 2})")
run(nil, nil, nil, 300)
eq(3,eval("g:val"))
eq(2,eval("g:val2"))
@@ -186,7 +186,7 @@ describe('timers', function()
let g:val += 1
endfunc
]])
- execute("call timer_start(5, 'MyHandler', {'repeat': 1})")
+ command("call timer_start(5, 'MyHandler', {'repeat': 1})")
run(nil, nil, nil, 300)
eq(1,eval("g:val"))
end)
@@ -201,7 +201,7 @@ describe('timers', function()
echo "evil"
endfunc
]])
- execute("call timer_start(100, 'MyHandler', {'repeat': 1})")
+ command("call timer_start(100, 'MyHandler', {'repeat': 1})")
feed(":good")
screen:sleep(200)
screen:expect([[
diff --git a/test/functional/eval/writefile_spec.lua b/test/functional/eval/writefile_spec.lua
index 3052c616e0..2f84114b9b 100644
--- a/test/functional/eval/writefile_spec.lua
+++ b/test/functional/eval/writefile_spec.lua
@@ -80,6 +80,13 @@ describe('writefile()', function()
eq('a\0\0\0b', read_file(fname))
end)
+ it('writes with s and S', function()
+ eq(0, funcs.writefile({'\na\nb\n'}, fname, 'bs'))
+ eq('\0a\0b\0', read_file(fname))
+ eq(0, funcs.writefile({'a\n\n\nb'}, fname, 'bS'))
+ eq('a\0\0\0b', read_file(fname))
+ end)
+
it('correctly overwrites file', function()
eq(0, funcs.writefile({'\na\nb\n'}, fname, 'b'))
eq('\0a\0b\0', read_file(fname))
@@ -115,6 +122,8 @@ describe('writefile()', function()
eq('\nE729: using Funcref as a String',
redir_exec(('call writefile(%s)'):format(args:format('function("tr")'))))
end
+ eq('\nE5060: Unknown flag: «»',
+ redir_exec(('call writefile([], "%s", "bs«»")'):format(fname)))
eq('TEST', read_file(fname))
end)