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.lua25
-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.lua5
-rw-r--r--test/functional/eval/input_spec.lua25
-rw-r--r--test/functional/eval/interrupt_spec.lua61
-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.lua76
-rw-r--r--test/functional/eval/system_spec.lua77
15 files changed, 456 insertions, 121 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..925e311c7d 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)
@@ -105,22 +106,30 @@ describe('execute()', function()
end)
it('does not corrupt the command display #5422', function()
- local screen = Screen.new(70, 5)
+ local screen = Screen.new(70, 7)
screen:attach()
feed(':echo execute("hi ErrorMsg")<CR>')
screen:expect([[
- ~ |
- ~ |
+ |
+ {1:~ }|
+ {1:~ }|
+ {2: }|
:echo execute("hi ErrorMsg") |
ErrorMsg xxx ctermfg=15 ctermbg=1 guifg=White guibg=Red |
- Press ENTER or type command to continue^ |
- ]])
+ {3:Press ENTER or type command to continue}^ |
+ ]], {
+ [1] = {bold = true, foreground = Screen.colors.Blue1},
+ [2] = {bold = true, reverse = true},
+ [3] = {bold = true, foreground = Screen.colors.SeaGreen4},
+ })
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 6d5b64b929..6112cf64e3 100644
--- a/test/functional/eval/hostname_spec.lua
+++ b/test/functional/eval/hostname_spec.lua
@@ -1,7 +1,9 @@
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)
@@ -11,7 +13,8 @@ describe('hostname()', function()
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 1e6b107c60..777f49462d 100644
--- a/test/functional/eval/input_spec.lua
+++ b/test/functional/eval/input_spec.lua
@@ -58,6 +58,7 @@ before_each(function()
RBP2={background=Screen.colors.Yellow},
RBP3={background=Screen.colors.Green},
RBP4={background=Screen.colors.Blue},
+ SEP={bold = true, reverse = true},
})
end)
@@ -65,9 +66,9 @@ describe('input()', function()
it('works with multiline prompts', function()
feed([[:call input("Test\nFoo")<CR>]])
screen:expect([[
+ |
{EOB:~ }|
- {EOB:~ }|
- {EOB:~ }|
+ {SEP: }|
Test |
Foo^ |
]])
@@ -75,9 +76,9 @@ describe('input()', function()
it('works with multiline prompts and :echohl', function()
feed([[:echohl Test | call input("Test\nFoo")<CR>]])
screen:expect([[
+ |
{EOB:~ }|
- {EOB:~ }|
- {EOB:~ }|
+ {SEP: }|
{T:Test} |
{T:Foo}^ |
]])
@@ -242,17 +243,17 @@ describe('input()', function()
it('is not hidden by :silent', function()
feed([[:silent call input('Foo: ')<CR>]])
screen:expect([[
+ |
{EOB:~ }|
- {EOB:~ }|
- {EOB:~ }|
+ {SEP: }|
Foo: ^ |
|
]])
feed('Bar')
screen:expect([[
+ |
{EOB:~ }|
- {EOB:~ }|
- {EOB:~ }|
+ {SEP: }|
Foo: Bar^ |
|
]])
@@ -263,9 +264,9 @@ describe('inputdialog()', function()
it('works with multiline prompts', function()
feed([[:call inputdialog("Test\nFoo")<CR>]])
screen:expect([[
+ |
{EOB:~ }|
- {EOB:~ }|
- {EOB:~ }|
+ {SEP: }|
Test |
Foo^ |
]])
@@ -273,9 +274,9 @@ describe('inputdialog()', function()
it('works with multiline prompts and :echohl', function()
feed([[:echohl Test | call inputdialog("Test\nFoo")<CR>]])
screen:expect([[
+ |
{EOB:~ }|
- {EOB:~ }|
- {EOB:~ }|
+ {SEP: }|
{T:Test} |
{T:Foo}^ |
]])
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/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 393616838e..4e4aed864b 100644
--- a/test/functional/eval/server_spec.lua
+++ b/test/functional/eval/server_spec.lua
@@ -1,31 +1,40 @@
-
local helpers = require('test.functional.helpers')(after_each)
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 iswin = helpers.iswin
+local ok = helpers.ok
+local matches = helpers.matches
local function clear_serverlist()
- for _, server in pairs(funcs.serverlist()) do
- funcs.serverstop(server)
- end
+ for _, server in pairs(funcs.serverlist()) do
+ funcs.serverstop(server)
+ end
end
-describe('serverstart(), serverstop()', function()
+describe('server', function()
before_each(clear)
- it('sets $NVIM_LISTEN_ADDRESS on first invocation', function()
+ it('serverstart() sets $NVIM_LISTEN_ADDRESS on first invocation', function()
-- Unset $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'))
- command("call serverstop('"..s.."')")
+ eq(1, eval("serverstop('"..s.."')"))
eq('', eval('$NVIM_LISTEN_ADDRESS'))
end)
- it('sets v:servername _only_ on nvim startup unless all servers are stopped',
+ it('sets new v:servername if $NVIM_LISTEN_ADDRESS is invalid', function()
+ clear({env={NVIM_LISTEN_ADDRESS='.'}})
+ eq('.', eval('$NVIM_LISTEN_ADDRESS'))
+ local servers = funcs.serverlist()
+ eq(1, #servers)
+ ok(string.len(servers[1]) > 4) -- Like /tmp/nvim…/… or \\.\pipe\…
+ end)
+
+ it('sets v:servername at startup or if all servers were stopped',
function()
local initial_server = meths.get_vvar('servername')
assert(initial_server ~= nil and initial_server:len() > 0,
@@ -38,24 +47,23 @@ describe('serverstart(), serverstop()', function()
neq(initial_server, s)
-- serverstop() does _not_ modify v:servername...
- funcs.serverstop(s)
+ eq(1, funcs.serverstop(s))
eq(initial_server, meths.get_vvar('servername'))
-- ...unless we stop _all_ servers.
- funcs.serverstop(funcs.serverlist()[1])
+ eq(1, funcs.serverstop(funcs.serverlist()[1]))
eq('', meths.get_vvar('servername'))
-- v:servername will take the next available server.
- local servername = (os_name() == 'windows'
- and [[\\.\pipe\Xtest-functional-server-pipe]]
- or 'Xtest-functional-server-socket')
+ local servername = (iswin() and [[\\.\pipe\Xtest-functional-server-pipe]]
+ or 'Xtest-functional-server-socket')
funcs.serverstart(servername)
eq(servername, meths.get_vvar('servername'))
end)
- it('serverstop() ignores invalid input', function()
- command("call serverstop('')")
- command("call serverstop('bogus-socket-name')")
+ it('serverstop() returns false for invalid input', function()
+ eq(0, eval("serverstop('')"))
+ eq(0, eval("serverstop('bogus-socket-name')"))
end)
it('parses endpoints correctly', function()
@@ -96,17 +104,13 @@ describe('serverstart(), serverstop()', function()
funcs.serverstart('127.0.0.1:65536') -- invalid port
eq({}, funcs.serverlist())
end)
-end)
-
-describe('serverlist()', function()
- before_each(clear)
- it('returns the list of servers', function()
+ it('serverlist() returns the list of servers', function()
-- There should already be at least one server.
local n = eval('len(serverlist())')
- -- Add a few
- local servs = (os_name() == 'windows'
+ -- Add some servers.
+ local servs = (iswin()
and { [[\\.\pipe\Xtest-pipe0934]], [[\\.\pipe\Xtest-pipe4324]] }
or { [[Xtest-pipe0934]], [[Xtest-pipe4324]] })
for _, s in ipairs(servs) do
@@ -120,9 +124,31 @@ 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])
- command("call serverstop('"..servs[i].."')")
+ eq(1, eval("serverstop('"..servs[i].."')"))
end
-- After serverstop() the servers should NOT be in the list.
eq(n, eval('len(serverlist())'))
end)
end)
+
+describe('startup --listen', function()
+ it('validates', function()
+ clear()
+
+ local cmd = { unpack(helpers.nvim_argv) }
+ table.insert(cmd, '--listen')
+ matches('nvim.*: Argument missing after: "%-%-listen"', funcs.system(cmd))
+
+ cmd = { unpack(helpers.nvim_argv) }
+ table.insert(cmd, '--listen2')
+ matches('nvim.*: Garbage after option argument: "%-%-listen2"', funcs.system(cmd))
+ end)
+
+ it('sets v:servername, overrides $NVIM_LISTEN_ADDRESS', function()
+ local addr = (iswin() and [[\\.\pipe\Xtest-listen-pipe]]
+ or 'Xtest-listen-pipe')
+ clear({ env={ NVIM_LISTEN_ADDRESS='Xtest-env-pipe' },
+ args={ '--listen', addr } })
+ eq(addr, meths.get_vvar('servername'))
+ 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)