aboutsummaryrefslogtreecommitdiff
path: root/test/functional/eval
diff options
context:
space:
mode:
Diffstat (limited to 'test/functional/eval')
-rw-r--r--test/functional/eval/api_functions_spec.lua3
-rw-r--r--test/functional/eval/backtick_expansion_spec.lua16
-rw-r--r--test/functional/eval/buf_functions_spec.lua5
-rw-r--r--test/functional/eval/execute_spec.lua9
-rw-r--r--test/functional/eval/fnamemodify_spec.lua39
-rw-r--r--test/functional/eval/getline_spec.lua39
-rw-r--r--test/functional/eval/has_spec.lua6
-rw-r--r--test/functional/eval/hostname_spec.lua7
-rw-r--r--test/functional/eval/input_spec.lua74
-rw-r--r--test/functional/eval/interrupt_spec.lua61
-rw-r--r--test/functional/eval/json_functions_spec.lua7
-rw-r--r--test/functional/eval/map_functions_spec.lua41
-rw-r--r--test/functional/eval/match_functions_spec.lua94
-rw-r--r--test/functional/eval/msgpack_functions_spec.lua5
-rw-r--r--test/functional/eval/null_spec.lua101
-rw-r--r--test/functional/eval/server_spec.lua38
-rw-r--r--test/functional/eval/special_vars_spec.lua7
-rw-r--r--test/functional/eval/system_spec.lua77
18 files changed, 534 insertions, 95 deletions
diff --git a/test/functional/eval/api_functions_spec.lua b/test/functional/eval/api_functions_spec.lua
index fea4a87a26..6f440c7d82 100644
--- a/test/functional/eval/api_functions_spec.lua
+++ b/test/functional/eval/api_functions_spec.lua
@@ -106,7 +106,8 @@ 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', 'ui_events', 'version'}, api_keys)
+ eq({'error_types', 'functions', 'types',
+ 'ui_events', 'ui_options', 'version'}, api_keys)
end)
it('are highlighted by vim.vim syntax file', function()
diff --git a/test/functional/eval/backtick_expansion_spec.lua b/test/functional/eval/backtick_expansion_spec.lua
index 81e8e295fa..b1b44cfa8b 100644
--- a/test/functional/eval/backtick_expansion_spec.lua
+++ b/test/functional/eval/backtick_expansion_spec.lua
@@ -21,11 +21,19 @@ describe("backtick expansion", function()
end)
it("with default 'shell'", function()
- if helpers.pending_win32(pending) then return end -- Need win32 shell fixes
- command(":silent args `echo ***2`")
+ if helpers.iswin() then
+ command(":silent args `dir /b *2`")
+ else
+ command(":silent args `echo ***2`")
+ end
eq({ "file2", }, eval("argv()"))
- command(":silent args `echo */*4`")
- eq({ "subdir/file4", }, eval("argv()"))
+ if helpers.iswin() then
+ command(":silent args `dir /s/b *4`")
+ eq({ "subdir\\file4", }, eval("map(argv(), 'fnamemodify(v:val, \":.\")')"))
+ else
+ command(":silent args `echo */*4`")
+ eq({ "subdir/file4", }, eval("argv()"))
+ end
end)
it("with shell=fish", function()
diff --git a/test/functional/eval/buf_functions_spec.lua b/test/functional/eval/buf_functions_spec.lua
index db50874c53..7de58766b9 100644
--- a/test/functional/eval/buf_functions_spec.lua
+++ b/test/functional/eval/buf_functions_spec.lua
@@ -14,6 +14,7 @@ local curbufmeths = helpers.curbufmeths
local curwinmeths = helpers.curwinmeths
local curtabmeths = helpers.curtabmeths
local get_pathsep = helpers.get_pathsep
+local rmdir = helpers.rmdir
local fname = 'Xtest-functional-eval-buf_functions'
local fname2 = fname .. '.2'
@@ -61,7 +62,7 @@ describe('bufname() function', function()
lfs.mkdir(dirname)
end)
after_each(function()
- lfs.rmdir(dirname)
+ rmdir(dirname)
end)
it('returns expected buffer name', function()
eq('', funcs.bufname('%')) -- Buffer has no name yet
@@ -143,7 +144,7 @@ describe('bufwinnr() function', function()
lfs.mkdir(dirname)
end)
after_each(function()
- lfs.rmdir(dirname)
+ rmdir(dirname)
end)
it('returns expected window number', function()
eq(1, funcs.bufwinnr('%'))
diff --git a/test/functional/eval/execute_spec.lua b/test/functional/eval/execute_spec.lua
index 91966ed3dd..183884a51e 100644
--- a/test/functional/eval/execute_spec.lua
+++ b/test/functional/eval/execute_spec.lua
@@ -9,6 +9,7 @@ local funcs = helpers.funcs
local Screen = require('test.functional.ui.screen')
local command = helpers.command
local feed = helpers.feed
+local iswin = helpers.iswin
describe('execute()', function()
before_each(clear)
@@ -118,9 +119,11 @@ describe('execute()', function()
feed('<CR>')
end)
- -- This matches Vim behavior.
- it('does not capture shell-command output', function()
- eq('\n:!echo "foo"\13\n', funcs.execute('!echo "foo"'))
+ -- This deviates from vim behavior, but is consistent
+ -- with how nvim currently displays the output.
+ it('does capture shell-command output', function()
+ local win_lf = iswin() and '\13' or ''
+ eq('\n:!echo foo\r\n\nfoo'..win_lf..'\n', funcs.execute('!echo foo'))
end)
describe('{silent} argument', function()
diff --git a/test/functional/eval/fnamemodify_spec.lua b/test/functional/eval/fnamemodify_spec.lua
new file mode 100644
index 0000000000..fe6b50a544
--- /dev/null
+++ b/test/functional/eval/fnamemodify_spec.lua
@@ -0,0 +1,39 @@
+local helpers = require('test.functional.helpers')(after_each)
+local clear = helpers.clear
+local eq = helpers.eq
+local iswin = helpers.iswin
+local fnamemodify = helpers.funcs.fnamemodify
+local command = helpers.command
+local write_file = helpers.write_file
+
+describe('fnamemodify()', function()
+ setup(function()
+ write_file('Xtest-fnamemodify.txt', [[foobar]])
+ end)
+
+ before_each(clear)
+
+ teardown(function()
+ os.remove('Xtest-fnamemodify.txt')
+ end)
+
+ it('works', function()
+ local root = helpers.pathroot()
+ eq(root, fnamemodify([[/]], ':p:h'))
+ eq(root, fnamemodify([[/]], ':p'))
+ if iswin() then
+ eq(root, fnamemodify([[\]], ':p:h'))
+ eq(root, fnamemodify([[\]], ':p'))
+ command('set shellslash')
+ root = string.sub(root, 1, -2)..'/'
+ eq(root, fnamemodify([[\]], ':p:h'))
+ eq(root, fnamemodify([[\]], ':p'))
+ eq(root, fnamemodify([[/]], ':p:h'))
+ eq(root, fnamemodify([[/]], ':p'))
+ end
+ end)
+
+ it(':8 works', function()
+ eq('Xtest-fnamemodify.txt', fnamemodify([[Xtest-fnamemodify.txt]], ':8'))
+ end)
+end)
diff --git a/test/functional/eval/getline_spec.lua b/test/functional/eval/getline_spec.lua
new file mode 100644
index 0000000000..3c56bde094
--- /dev/null
+++ b/test/functional/eval/getline_spec.lua
@@ -0,0 +1,39 @@
+local helpers = require('test.functional.helpers')(after_each)
+
+local call = helpers.call
+local clear = helpers.clear
+local eq = helpers.eq
+local expect = helpers.expect
+
+describe('getline()', function()
+ before_each(function()
+ clear()
+ call('setline', 1, {'a', 'b', 'c'})
+ expect([[
+ a
+ b
+ c]])
+ end)
+
+ it('returns empty string for invalid line', function()
+ eq('', call('getline', -1))
+ eq('', call('getline', 0))
+ eq('', call('getline', 4))
+ end)
+
+ it('returns empty list for invalid range', function()
+ eq({}, call('getline', 2, 1))
+ eq({}, call('getline', -1, 1))
+ eq({}, call('getline', 4, 4))
+ end)
+
+ it('returns value of valid line', function()
+ eq('b', call('getline', 2))
+ eq('a', call('getline', '.'))
+ end)
+
+ it('returns value of valid range', function()
+ eq({'a', 'b'}, call('getline', 1, 2))
+ eq({'a', 'b', 'c'}, call('getline', 1, 4))
+ end)
+end)
diff --git a/test/functional/eval/has_spec.lua b/test/functional/eval/has_spec.lua
index 78c4e08fde..a3af2d1a20 100644
--- a/test/functional/eval/has_spec.lua
+++ b/test/functional/eval/has_spec.lua
@@ -57,4 +57,10 @@ describe('has()', function()
eq(0, funcs.has("unnamedplus"))
end
end)
+
+ it('"wsl"', function()
+ if 1 == funcs.has('win32') or 1 == funcs.has('mac') then
+ eq(0, funcs.has('wsl'))
+ end
+ end)
end)
diff --git a/test/functional/eval/hostname_spec.lua b/test/functional/eval/hostname_spec.lua
index f1867846c4..6112cf64e3 100644
--- a/test/functional/eval/hostname_spec.lua
+++ b/test/functional/eval/hostname_spec.lua
@@ -1,17 +1,20 @@
local helpers = require('test.functional.helpers')(after_each)
+local eq = helpers.eq
local ok = helpers.ok
local call = helpers.call
local clear = helpers.clear
+local iswin = helpers.iswin
describe('hostname()', function()
before_each(clear)
it('returns hostname string', function()
local actual = call('hostname')
- ok(string.len(actual) > 1)
+ ok(string.len(actual) > 0)
if call('executable', 'hostname') == 1 then
local expected = string.gsub(call('system', 'hostname'), '[\n\r]', '')
- helpers.eq(expected, actual)
+ eq((iswin() and expected:upper() or expected),
+ (iswin() and actual:upper() or actual))
end
end)
end)
diff --git a/test/functional/eval/input_spec.lua b/test/functional/eval/input_spec.lua
index 74ad32bc6c..1e6b107c60 100644
--- a/test/functional/eval/input_spec.lua
+++ b/test/functional/eval/input_spec.lua
@@ -23,10 +23,41 @@ before_each(function()
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)
@@ -196,6 +227,37 @@ describe('input()', function()
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()
@@ -363,4 +425,16 @@ describe('inputdialog()', function()
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/interrupt_spec.lua b/test/functional/eval/interrupt_spec.lua
new file mode 100644
index 0000000000..7f4ca95317
--- /dev/null
+++ b/test/functional/eval/interrupt_spec.lua
@@ -0,0 +1,61 @@
+local helpers = require('test.functional.helpers')(after_each)
+
+local command = helpers.command
+local meths = helpers.meths
+local clear = helpers.clear
+local sleep = helpers.sleep
+local wait = helpers.wait
+local feed = helpers.feed
+local eq = helpers.eq
+
+local dur
+local min_dur = 8
+local len = 131072
+
+describe('List support code', function()
+ if not pending('does not actually allows interrupting with just got_int', function() end) then return end
+ -- The following tests are confirmed to work with os_breakcheck() just before
+ -- `if (got_int) {break;}` in tv_list_copy and list_join_inner() and not to
+ -- work without.
+ setup(function()
+ clear()
+ dur = 0
+ while true do
+ command(([[
+ let rt = reltime()
+ let bl = range(%u)
+ let dur = reltimestr(reltime(rt))
+ ]]):format(len))
+ dur = tonumber(meths.get_var('dur'))
+ if dur >= min_dur then
+ -- print(('Using len %u, dur %g'):format(len, dur))
+ break
+ else
+ len = len * 2
+ end
+ end
+ end)
+ it('allows interrupting copy', function()
+ feed(':let t_rt = reltime()<CR>:let t_bl = copy(bl)<CR>')
+ sleep(min_dur / 16 * 1000)
+ feed('<C-c>')
+ wait()
+ command('let t_dur = reltimestr(reltime(t_rt))')
+ local t_dur = tonumber(meths.get_var('t_dur'))
+ if t_dur >= dur / 8 then
+ eq(nil, ('Took too long to cancel: %g >= %g'):format(t_dur, dur / 8))
+ end
+ end)
+ it('allows interrupting join', function()
+ feed(':let t_rt = reltime()<CR>:let t_j = join(bl)<CR>')
+ sleep(min_dur / 16 * 1000)
+ feed('<C-c>')
+ wait()
+ command('let t_dur = reltimestr(reltime(t_rt))')
+ local t_dur = tonumber(meths.get_var('t_dur'))
+ print(('t_dur: %g'):format(t_dur))
+ if t_dur >= dur / 8 then
+ eq(nil, ('Took too long to cancel: %g >= %g'):format(t_dur, dur / 8))
+ end
+ end)
+end)
diff --git a/test/functional/eval/json_functions_spec.lua b/test/functional/eval/json_functions_spec.lua
index 4d34cde849..8dcaea806e 100644
--- a/test/functional/eval/json_functions_spec.lua
+++ b/test/functional/eval/json_functions_spec.lua
@@ -776,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
index a260522aa3..e914f674aa 100644
--- a/test/functional/eval/map_functions_spec.lua
+++ b/test/functional/eval/map_functions_spec.lua
@@ -1,11 +1,12 @@
-
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)
@@ -117,4 +118,42 @@ describe('maparg()', function()
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
index 3150d89f62..7989b22b5e 100644
--- a/test/functional/eval/match_functions_spec.lua
+++ b/test/functional/eval/match_functions_spec.lua
@@ -1,9 +1,11 @@
local helpers = require('test.functional.helpers')(after_each)
+local Screen = require('test.functional.ui.screen')
local eq = helpers.eq
local clear = helpers.clear
local funcs = helpers.funcs
local command = helpers.command
+local exc_exec = helpers.exc_exec
before_each(clear)
@@ -59,3 +61,95 @@ describe('matchadd()', function()
}}, funcs.getmatches())
end)
end)
+
+describe('matchaddpos()', function()
+ it('errors out on invalid input', function()
+ command('hi clear PreProc')
+ eq('Vim(let):E5030: Empty list at position 0',
+ exc_exec('let val = matchaddpos("PreProc", [[]])'))
+ eq('Vim(let):E5030: Empty list at position 1',
+ exc_exec('let val = matchaddpos("PreProc", [1, v:_null_list])'))
+ eq('Vim(let):E5031: List or number required at position 1',
+ exc_exec('let val = matchaddpos("PreProc", [1, v:_null_dict])'))
+ end)
+ it('works with 0 lnum', function()
+ command('hi clear PreProc')
+ eq(4, funcs.matchaddpos('PreProc', {1}, 3, 4))
+ eq({{
+ group='PreProc',
+ pos1 = {1},
+ priority=3,
+ id=4,
+ }}, funcs.getmatches())
+ funcs.matchdelete(4)
+ eq(4, funcs.matchaddpos('PreProc', {{0}, 1}, 3, 4))
+ eq({{
+ group='PreProc',
+ pos1 = {1},
+ priority=3,
+ id=4,
+ }}, funcs.getmatches())
+ funcs.matchdelete(4)
+ eq(4, funcs.matchaddpos('PreProc', {0, 1}, 3, 4))
+ eq({{
+ group='PreProc',
+ pos1 = {1},
+ priority=3,
+ id=4,
+ }}, funcs.getmatches())
+ end)
+ it('works with negative numbers', function()
+ command('hi clear PreProc')
+ eq(4, funcs.matchaddpos('PreProc', {-10, 1}, 3, 4))
+ eq({{
+ group='PreProc',
+ pos1 = {1},
+ priority=3,
+ id=4,
+ }}, funcs.getmatches())
+ funcs.matchdelete(4)
+ eq(4, funcs.matchaddpos('PreProc', {{-10}, 1}, 3, 4))
+ eq({{
+ group='PreProc',
+ pos1 = {1},
+ priority=3,
+ id=4,
+ }}, funcs.getmatches())
+ funcs.matchdelete(4)
+ eq(4, funcs.matchaddpos('PreProc', {{2, -1}, 1}, 3, 4))
+ eq({{
+ group='PreProc',
+ pos1 = {1},
+ priority=3,
+ id=4,
+ }}, funcs.getmatches())
+ funcs.matchdelete(4)
+ eq(4, funcs.matchaddpos('PreProc', {{2, 0, -1}, 1}, 3, 4))
+ eq({{
+ group='PreProc',
+ pos1 = {1},
+ priority=3,
+ id=4,
+ }}, funcs.getmatches())
+ end)
+ it('works with zero length', function()
+ local screen = Screen.new(40, 5)
+ screen:attach()
+ funcs.setline(1, 'abcdef')
+ command('hi PreProc guifg=Red')
+ eq(4, funcs.matchaddpos('PreProc', {{1, 2, 0}}, 3, 4))
+ eq({{
+ group='PreProc',
+ pos1 = {1, 2, 0},
+ priority=3,
+ id=4,
+ }}, funcs.getmatches())
+ screen:expect([[
+ ^a{1:b}cdef |
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ |
+ ]], {[1] = {foreground = Screen.colors.Red}, [2] = {bold = true, foreground = Screen.colors.Blue1}})
+ end)
+end)
diff --git a/test/functional/eval/msgpack_functions_spec.lua b/test/functional/eval/msgpack_functions_spec.lua
index b241635dfe..a8a413f68b 100644
--- a/test/functional/eval/msgpack_functions_spec.lua
+++ b/test/functional/eval/msgpack_functions_spec.lua
@@ -463,7 +463,8 @@ 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', 'ui_events', 'version'}, api_info)
+ eq({'error_types', 'functions', 'types',
+ 'ui_events', 'ui_options', 'version'}, api_info)
end)
it('fails when called with no arguments', function()
@@ -628,7 +629,7 @@ describe('msgpackdump() function', function()
it('fails to dump a recursive (key) map in a special dict', function()
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',
+ eq('Vim(call):E5005: Unable to dump msgpackdump() argument, index 0: container references itself in index 0',
exc_exec('call msgpackdump([todump])'))
end)
diff --git a/test/functional/eval/null_spec.lua b/test/functional/eval/null_spec.lua
index 6fd30caec9..afe999e1fa 100644
--- a/test/functional/eval/null_spec.lua
+++ b/test/functional/eval/null_spec.lua
@@ -41,43 +41,9 @@ describe('NULL', function()
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)
+ -- FIXME Should error out with different message
+ null_test('makes :unlet act as if it is not a list', ':unlet L[0]',
+ 'Vim(unlet):E689: Can only index a List or Dictionary')
-- Subjectable behaviour
@@ -85,20 +51,19 @@ describe('NULL', function()
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('can be indexed with error message for empty list', 'L[0]',
+ 'E684: list index out of range: 0\nE15: Invalid expression: L[0]', nil)
+ null_expr_test('can be splice-indexed', 'L[:]', 0, {})
+ null_expr_test('is not locked', 'islocked("v:_null_list")', 0, 0)
+ null_test('is accepted by :for', 'for x in L|throw x|endfor', 0)
null_expr_test('does not crash append()', 'append(1, L)', 0, 0, function()
eq({''}, curbufmeths.get_lines(0, -1, false))
end)
+ null_expr_test('does not crash setline()', 'setline(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, {})
@@ -111,6 +76,8 @@ describe('NULL', function()
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('does not crash map()', 'map(L, "v:val")', 0, {})
+ null_expr_test('does not crash filter()', 'filter(L, "1")', 0, {})
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)
@@ -126,6 +93,44 @@ describe('NULL', function()
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)
+ null_expr_test('makes map() return v:_null_list', 'map(L, "v:val") is# L', 0, 1)
+ null_expr_test('makes filter() return v:_null_list', 'filter(L, "1") is# L', 0, 1)
+ null_test('is treated by :let as empty list', ':let [l] = L', 'Vim(let):E688: More targets than List items')
+ null_expr_test('is accepted as an empty list by inputlist()', '[feedkeys("\\n"), inputlist(L)]',
+ 'Type number and <Enter> or click with mouse (empty cancels): ', {0, 0})
+ null_expr_test('is accepted as an empty list by writefile()',
+ ('[writefile(L, "%s"), readfile("%s")]'):format(tmpfname, tmpfname),
+ 0, {0, {}})
+ null_expr_test('makes add() error out', 'add(L, 0)',
+ 'E742: Cannot change value of add() argument', 1)
+ null_expr_test('makes insert() error out', 'insert(L, 1)',
+ 'E742: Cannot change value of insert() argument', 0)
+ null_expr_test('does not crash remove()', 'remove(L, 0)',
+ 'E742: Cannot change value of remove() argument', 0)
+ null_expr_test('makes reverse() error out', 'reverse(L)',
+ 'E742: Cannot change value of reverse() argument', 0)
+ null_expr_test('makes sort() error out', 'sort(L)',
+ 'E742: Cannot change value of sort() argument', 0)
+ null_expr_test('makes uniq() error out', 'uniq(L)',
+ 'E742: Cannot change value of uniq() argument', 0)
+ 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})
+ null_expr_test('makes join() return empty string', 'join(L, "")', 0, '')
+ null_expr_test('makes msgpackdump() return empty list', 'msgpackdump(L)', 0, {})
+ null_expr_test('does not crash system()', 'system("cat", L)', 0, '')
+ null_expr_test('does not crash setreg', 'setreg("x", L)', 0, 0)
+ null_expr_test('does not crash systemlist()', 'systemlist("cat", L)', 0, {})
+ null_test('does not make Neovim crash when v:oldfiles gets assigned to that', ':let v:oldfiles = L|oldfiles', 0)
+ null_expr_test('does not make complete() crash or error out',
+ 'execute(":normal i\\<C-r>=complete(1, L)[-1]\\n")',
+ '', '\n', function()
+ eq({''}, curbufmeths.get_lines(0, -1, false))
+ end)
+ null_expr_test('is accepted by setmatches()', 'setmatches(L)', 0, 0)
+ null_expr_test('is accepted by setqflist()', 'setqflist(L)', 0, 0)
+ null_expr_test('is accepted by setloclist()', 'setloclist(1, L)', 0, 0)
+ null_test('is accepted by :cexpr', 'cexpr L', 0)
+ null_test('is accepted by :lexpr', 'lexpr L', 0)
end)
describe('dict', function()
it('does not crash when indexing NULL dict', function()
@@ -134,5 +139,9 @@ describe('NULL', function()
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})
+ null_expr_test('does not crash map()', 'map(D, "v:val")', 0, {})
+ null_expr_test('does not crash filter()', 'filter(D, "1")', 0, {})
+ null_expr_test('makes map() return v:_null_dict', 'map(D, "v:val") is# D', 0, 1)
+ null_expr_test('makes filter() return v:_null_dict', 'filter(D, "1") is# D', 0, 1)
end)
end)
diff --git a/test/functional/eval/server_spec.lua b/test/functional/eval/server_spec.lua
index 115114c3c3..393616838e 100644
--- a/test/functional/eval/server_spec.lua
+++ b/test/functional/eval/server_spec.lua
@@ -63,23 +63,33 @@ describe('serverstart(), serverstop()', function()
eq({}, funcs.serverlist())
local s = funcs.serverstart('127.0.0.1:0') -- assign random port
- assert(string.match(s, '127.0.0.1:%d+'))
- eq(s, funcs.serverlist()[1])
- clear_serverlist()
+ 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
- assert(string.match(s, '127.0.0.1:%d+'))
- eq(s, funcs.serverlist()[1])
- clear_serverlist()
+ if #s > 0 then
+ assert(string.match(s, '127.0.0.1:%d+'))
+ eq(s, funcs.serverlist()[1])
+ clear_serverlist()
+ end
- funcs.serverstart('127.0.0.1:12345')
- funcs.serverstart('127.0.0.1:12345') -- exists already; ignore
- funcs.serverstart('::1:12345')
- funcs.serverstart('::1:12345') -- exists already; ignore
- local expected = {
- '127.0.0.1:12345',
- '::1:12345',
- }
+ 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()
diff --git a/test/functional/eval/special_vars_spec.lua b/test/functional/eval/special_vars_spec.lua
index 3d9358447e..b5773a5529 100644
--- a/test/functional/eval/special_vars_spec.lua
+++ b/test/functional/eval/special_vars_spec.lua
@@ -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/system_spec.lua b/test/functional/eval/system_spec.lua
index 7e213e2156..201426c40b 100644
--- a/test/functional/eval/system_spec.lua
+++ b/test/functional/eval/system_spec.lua
@@ -5,6 +5,7 @@ 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 exc_exec = helpers.exc_exec
local iswin = helpers.iswin
local Screen = require('test.functional.ui.screen')
@@ -89,7 +90,9 @@ describe('system()', function()
end)
it('does NOT run in shell', function()
- if not iswin() then
+ if iswin() then
+ eq("%PATH%\n", eval("system(['powershell', '-NoProfile', '-NoLogo', '-ExecutionPolicy', 'RemoteSigned', '-Command', 'echo', '%PATH%'])"))
+ else
eq("* $PATH %PATH%\n", eval("system(['echo', '*', '$PATH', '%PATH%'])"))
end
end)
@@ -117,33 +120,47 @@ describe('system()', function()
end
end)
- describe('executes shell function if passed a string', function()
+ describe('executes shell function', function()
local screen
before_each(function()
- clear()
- screen = Screen.new()
- screen:attach()
+ clear()
+ screen = Screen.new()
+ screen:attach()
end)
after_each(function()
- screen:detach()
+ screen:detach()
end)
if iswin() then
+ local function test_more()
+ eq('root = true', eval([[get(split(system('"more" ".editorconfig"'), "\n"), 0, '')]]))
+ end
+ local function test_shell_unquoting()
+ eval([[system('"ping" "-n" "1" "127.0.0.1"')]])
+ eq(0, eval('v:shell_error'))
+ eq('"a b"\n', eval([[system('cmd /s/c "cmd /s/c "cmd /s/c "echo "a b""""')]]))
+ eq('"a b"\n', eval([[system('powershell -NoProfile -NoLogo -ExecutionPolicy RemoteSigned -Command echo ''\^"a b\^"''')]]))
+ end
+
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')]]))
+ test_more()
eval([[system('cd "C:\Program Files"')]])
eq(0, eval('v:shell_error'))
+ test_shell_unquoting()
end)
it('with shell=cmd', function()
command('set shell=cmd')
eq('"a b"\n', eval([[system('echo "a b"')]]))
+ test_more()
+ test_shell_unquoting()
end)
it('with shell=$COMSPEC', function()
@@ -151,6 +168,8 @@ describe('system()', function()
if comspecshell == 'cmd.exe' then
command('set shell=$COMSPEC')
eq('"a b"\n', eval([[system('echo "a b"')]]))
+ test_more()
+ test_shell_unquoting()
else
pending('$COMSPEC is not cmd.exe: ' .. comspecshell)
end
@@ -184,8 +203,10 @@ describe('system()', function()
]])
end)
- it('`yes` and is interrupted with CTRL-C', function()
- feed(':call system("yes")<cr>')
+ it('`yes` interrupted with CTRL-C', function()
+ feed(':call system("' .. (iswin()
+ and 'for /L %I in (1,0,2) do @echo y'
+ or 'yes') .. '")<cr>')
screen:expect([[
|
~ |
@@ -200,8 +221,11 @@ describe('system()', function()
~ |
~ |
~ |
- :call system("yes") |
- ]])
+]] .. (iswin()
+ and [[
+ :call system("for /L %I in (1,0,2) do @echo y") |]]
+ or [[
+ :call system("yes") |]]))
feed('<c-c>')
screen:expect([[
^ |
@@ -231,6 +255,8 @@ describe('system()', function()
end
end)
it('to backgrounded command does not crash', function()
+ -- cmd.exe doesn't background a command with &
+ if iswin() then return end
-- This is indeterminate, just exercise the codepath. May get E5677.
feed_command('call system("echo -n echoed &")')
local v_errnum = string.match(eval("v:errmsg"), "^E%d*:")
@@ -246,14 +272,20 @@ describe('system()', function()
eq("input", eval('system("cat -", "input")'))
end)
it('to backgrounded command does not crash', function()
+ -- cmd.exe doesn't background a command with &
+ if iswin() then return end
-- This is indeterminate, just exercise the codepath. May get E5677.
- feed_command('call system("cat - &")')
+ feed_command('call system("cat - &", "input")')
local v_errnum = string.match(eval("v:errmsg"), "^E%d*:")
if v_errnum then
eq("E5677:", v_errnum)
end
eq(2, eval("1+1")) -- Still alive?
end)
+ it('works with an empty string', function()
+ eq("test\n", eval('system("echo test", "")'))
+ eq(2, eval("1+1")) -- Still alive?
+ end)
end)
describe('passing a lot of input', function()
@@ -271,9 +303,12 @@ describe('system()', function()
end)
end)
- describe('input passed as Number', function()
- it('stringifies the input', function()
- eq('1', eval('system("cat", 1)'))
+ describe('Number input', function()
+ it('is treated as a buffer id', function()
+ command("put ='text in buffer 1'")
+ eq('\ntext in buffer 1\n', eval('system("cat", 1)'))
+ eq('Vim(echo):E86: Buffer 42 does not exist',
+ exc_exec('echo system("cat", 42)'))
end)
end)
@@ -284,7 +319,7 @@ describe('system()', function()
after_each(delete_file(fname))
it('replaces NULs by SOH characters', function()
- eq('part1\001part2\001part3\n', eval('system("cat '..fname..'")'))
+ eq('part1\001part2\001part3\n', eval([[system('"cat" "]]..fname..[["')]]))
end)
end)
@@ -351,7 +386,7 @@ describe('systemlist()', function()
end
end)
- describe('exectues shell function', function()
+ describe('executes shell function', function()
local screen
before_each(function()
@@ -384,7 +419,7 @@ describe('systemlist()', function()
]])
end)
- it('`yes` and is interrupted with CTRL-C', function()
+ it('`yes` interrupted with CTRL-C', function()
feed(':call systemlist("yes | xargs")<cr>')
screen:expect([[
|
@@ -442,12 +477,14 @@ describe('systemlist()', function()
describe('with output containing NULs', function()
local fname = 'Xtest'
- before_each(create_file_with_nuls(fname))
+ before_each(function()
+ command('set ff=unix')
+ create_file_with_nuls(fname)()
+ end)
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..'")'))
+ eq({'part1\npart2\npart3'}, eval([[systemlist('"cat" "]]..fname..[["')]]))
end)
end)