aboutsummaryrefslogtreecommitdiff
path: root/test/functional/viml
diff options
context:
space:
mode:
Diffstat (limited to 'test/functional/viml')
-rw-r--r--test/functional/viml/completion_spec.lua693
-rw-r--r--test/functional/viml/errorlist_spec.lua73
-rw-r--r--test/functional/viml/function_spec.lua29
3 files changed, 779 insertions, 16 deletions
diff --git a/test/functional/viml/completion_spec.lua b/test/functional/viml/completion_spec.lua
index 5e3d4a6658..2b3844bf6d 100644
--- a/test/functional/viml/completion_spec.lua
+++ b/test/functional/viml/completion_spec.lua
@@ -1,12 +1,26 @@
-
local helpers = require('test.functional.helpers')
-local clear, feed, execute = helpers.clear, helpers.feed, helpers.execute
+local Screen = require('test.functional.ui.screen')
+local clear, feed = helpers.clear, helpers.feed
local eval, eq, neq = helpers.eval, helpers.eq, helpers.neq
-local execute, source = helpers.execute, helpers.source
+local execute, source, expect = helpers.execute, helpers.source, helpers.expect
describe('completion', function()
+ local screen
+
before_each(function()
clear()
+ screen = Screen.new(60, 8)
+ screen:attach()
+ screen:set_default_attr_ignore({{bold=true, foreground=Screen.colors.Blue}})
+ screen:set_default_attr_ids({
+ [1] = {background = Screen.colors.LightMagenta},
+ [2] = {background = Screen.colors.Grey},
+ [3] = {bold = true},
+ [4] = {bold = true, foreground = Screen.colors.SeaGreen},
+ [5] = {foreground = Screen.colors.Red},
+ [6] = {background = Screen.colors.Black},
+ [7] = {foreground = Screen.colors.White, background = Screen.colors.Red},
+ })
end)
describe('v:completed_item', function()
@@ -14,18 +28,40 @@ describe('completion', function()
eq({}, eval('v:completed_item'))
end)
it('is empty dict if the candidate is not inserted', function()
- feed('ifoo<ESC>o<C-x><C-n><C-e><ESC>')
+ feed('ifoo<ESC>o<C-x><C-n>')
+ screen:expect([[
+ foo |
+ foo^ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ {3:-- Keyword Local completion (^N^P) The only match} |
+ ]])
+ feed('<C-e>')
+ screen:expect([[
+ foo |
+ ^ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ {3:-- INSERT --} |
+ ]])
+ feed('<ESC>')
eq({}, eval('v:completed_item'))
end)
it('returns expected dict in normal completion', function()
- feed('ifoo<ESC>o<C-x><C-n><ESC>')
+ feed('ifoo<ESC>o<C-x><C-n>')
eq('foo', eval('getline(2)'))
eq({word = 'foo', abbr = '', menu = '', info = '', kind = ''},
eval('v:completed_item'))
end)
it('is readonly', function()
+ screen:try_resize(80, 8)
feed('ifoo<ESC>o<C-x><C-n><ESC>')
-
execute('let v:completed_item.word = "bar"')
neq(nil, string.find(eval('v:errmsg'), '^E46: '))
execute('let v:errmsg = ""')
@@ -50,17 +86,29 @@ describe('completion', function()
source([[
function! TestOmni(findstart, base) abort
return a:findstart ? 0 : [{'word': 'foo', 'abbr': 'bar',
- \ 'menu': 'baz', 'info': 'foobar', 'kind': 'foobaz'}]
+ \ 'menu': 'baz', 'info': 'foobar', 'kind': 'foobaz'},
+ \ {'word': 'word', 'abbr': 'abbr', 'menu': 'menu', 'info': 'info', 'kind': 'kind'}]
endfunction
setlocal omnifunc=TestOmni
]])
- feed('i<C-x><C-o><ESC>')
+ feed('i<C-x><C-o>')
eq('foo', eval('getline(1)'))
+ screen:expect([[
+ foo^ |
+ {2:bar foobaz baz } |
+ {1:abbr kind menu } |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ {3:-- Omni completion (^O^N^P) }{4:match 1 of 2} |
+ ]])
eq({word = 'foo', abbr = 'bar', menu = 'baz',
info = 'foobar', kind = 'foobaz'},
eval('v:completed_item'))
end)
end)
+
describe('completeopt', function()
before_each(function()
source([[
@@ -73,31 +121,644 @@ describe('completion', function()
it('inserts the first candidate if default', function()
execute('set completeopt+=menuone')
- feed('ifoo<ESC>o<C-x><C-n>bar<ESC>')
+ feed('ifoo<ESC>o')
+ screen:expect([[
+ foo |
+ ^ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ {3:-- INSERT --} |
+ ]])
+ feed('<C-x>')
+ -- the ^X prompt, only test this once
+ screen:expect([[
+ foo |
+ ^ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ {3:-- ^X mode (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)} |
+ ]])
+ feed('<C-n>')
+ screen:expect([[
+ foo |
+ foo^ |
+ {2:foo } |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ {3:-- Keyword Local completion (^N^P) The only match} |
+ ]])
+ feed('bar<ESC>')
eq('foobar', eval('getline(2)'))
- feed('o<C-r>=TestComplete()<CR><ESC>')
+ feed('o<C-r>=TestComplete()<CR>')
+ screen:expect([[
+ foo |
+ foobar |
+ foo^ |
+ {2:foo } |
+ ~ |
+ ~ |
+ ~ |
+ {3:-- INSERT --} |
+ ]])
eq('foo', eval('getline(3)'))
end)
it('selects the first candidate if noinsert', function()
execute('set completeopt+=menuone,noinsert')
- feed('ifoo<ESC>o<C-x><C-n><C-y><ESC>')
+ feed('ifoo<ESC>o<C-x><C-n>')
+ screen:expect([[
+ foo |
+ ^ |
+ {2:foo } |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ {3:-- Keyword Local completion (^N^P) The only match} |
+ ]])
+ feed('<C-y>')
+ screen:expect([[
+ foo |
+ foo^ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ {3:-- INSERT --} |
+ ]])
+ feed('<ESC>')
eq('foo', eval('getline(2)'))
- feed('o<C-r>=TestComplete()<CR><C-y><ESC>')
+ feed('o<C-r>=TestComplete()<CR>')
+ screen:expect([[
+ foo |
+ foo |
+ ^ |
+ {2:foo } |
+ ~ |
+ ~ |
+ ~ |
+ {3:-- INSERT --} |
+ ]])
+ feed('<C-y><ESC>')
eq('foo', eval('getline(3)'))
end)
it('does not insert the first candidate if noselect', function()
execute('set completeopt+=menuone,noselect')
- feed('ifoo<ESC>o<C-x><C-n>bar<ESC>')
+ feed('ifoo<ESC>o<C-x><C-n>')
+ screen:expect([[
+ foo |
+ ^ |
+ {1:foo } |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ {3:-- Keyword Local completion (^N^P) }{5:Back at original} |
+ ]])
+ feed('b')
+ screen:expect([[
+ foo |
+ b^ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ {3:-- Keyword Local completion (^N^P) }{5:Back at original} |
+ ]])
+ feed('ar<ESC>')
eq('bar', eval('getline(2)'))
- feed('o<C-r>=TestComplete()<CR>bar<ESC>')
+ feed('o<C-r>=TestComplete()<CR>')
+ screen:expect([[
+ foo |
+ bar |
+ ^ |
+ {1:foo } |
+ ~ |
+ ~ |
+ ~ |
+ {3:-- INSERT --} |
+ ]])
+ feed('bar<ESC>')
eq('bar', eval('getline(3)'))
end)
it('does not select/insert the first candidate if noselect and noinsert', function()
execute('set completeopt+=menuone,noselect,noinsert')
- feed('ifoo<ESC>o<C-x><C-n><ESC>')
+ feed('ifoo<ESC>o<C-x><C-n>')
+ screen:expect([[
+ foo |
+ ^ |
+ {1:foo } |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ {3:-- Keyword Local completion (^N^P) }{5:Back at original} |
+ ]])
+ feed('<ESC>')
+ screen:expect([[
+ foo |
+ ^ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ |
+ ]])
eq('', eval('getline(2)'))
- feed('o<C-r>=TestComplete()<CR><ESC>')
+ feed('o<C-r>=TestComplete()<CR>')
+ screen:expect([[
+ foo |
+ |
+ ^ |
+ {1:foo } |
+ ~ |
+ ~ |
+ ~ |
+ {3:-- INSERT --} |
+ ]])
+ feed('<ESC>')
+ screen:expect([[
+ foo |
+ |
+ ^ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ |
+ ]])
eq('', eval('getline(3)'))
end)
+ it('does not change modified state if noinsert', function()
+ execute('set completeopt+=menuone,noinsert')
+ execute('setlocal nomodified')
+ feed('i<C-r>=TestComplete()<CR><ESC>')
+ eq(0, eval('&l:modified'))
+ end)
+ it('does not change modified state if noselect', function()
+ execute('set completeopt+=menuone,noselect')
+ execute('setlocal nomodified')
+ feed('i<C-r>=TestComplete()<CR><ESC>')
+ eq(0, eval('&l:modified'))
+ end)
+ end)
+
+ describe("refresh:always", function()
+ before_each(function()
+ source([[
+ function! TestCompletion(findstart, base) abort
+ if a:findstart
+ let line = getline('.')
+ let start = col('.') - 1
+ while start > 0 && line[start - 1] =~ '\a'
+ let start -= 1
+ endwhile
+ return start
+ else
+ let ret = []
+ for m in split("January February March April May June July August September October November December")
+ if m =~ a:base " match by regex
+ call add(ret, m)
+ endif
+ endfor
+ return {'words':ret, 'refresh':'always'}
+ endif
+ endfunction
+
+ set completeopt=menuone,noselect
+ set completefunc=TestCompletion
+ ]])
+ end )
+
+ it('completes on each input char', function ()
+ feed('i<C-x><C-u>')
+ screen:expect([[
+ ^ |
+ {1:January }{6: } |
+ {1:February }{6: } |
+ {1:March }{6: } |
+ {1:April }{2: } |
+ {1:May }{2: } |
+ {1:June }{2: } |
+ {3:-- User defined completion (^U^N^P) }{5:Back at original} |
+ ]])
+ feed('u')
+ screen:expect([[
+ u^ |
+ {1:January } |
+ {1:February } |
+ {1:June } |
+ {1:July } |
+ {1:August } |
+ ~ |
+ {3:-- User defined completion (^U^N^P) }{5:Back at original} |
+ ]])
+ feed('g')
+ screen:expect([[
+ ug^ |
+ {1:August } |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ {3:-- User defined completion (^U^N^P) }{5:Back at original} |
+ ]])
+ feed('<Down>')
+ screen:expect([[
+ ug^ |
+ {2:August } |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ {3:-- User defined completion (^U^N^P) The only match} |
+ ]])
+ feed('<C-y>')
+ screen:expect([[
+ August^ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ {3:-- INSERT --} |
+ ]])
+ expect('August')
+ end)
+ it("repeats correctly after backspace #2674", function ()
+ feed('o<C-x><C-u>Ja')
+ screen:expect([[
+ |
+ Ja^ |
+ {1:January } |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ {3:-- User defined completion (^U^N^P) }{5:Back at original} |
+ ]])
+ feed('<BS>')
+ screen:expect([[
+ |
+ J^ |
+ {1:January } |
+ {1:June } |
+ {1:July } |
+ ~ |
+ ~ |
+ {3:-- User defined completion (^U^N^P) }{5:Back at original} |
+ ]])
+ feed('<C-n>')
+ screen:expect([[
+ |
+ January^ |
+ {2:January } |
+ {1:June } |
+ {1:July } |
+ ~ |
+ ~ |
+ {3:-- User defined completion (^U^N^P) }{4:match 1 of 3} |
+ ]])
+ feed('<C-n>')
+ screen:expect([[
+ |
+ June^ |
+ {1:January } |
+ {2:June } |
+ {1:July } |
+ ~ |
+ ~ |
+ {3:-- User defined completion (^U^N^P) }{4:match 2 of 3} |
+ ]])
+ feed('<Esc>')
+ screen:expect([[
+ |
+ Jun^e |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ |
+ ]])
+ feed('.')
+ screen:expect([[
+ |
+ June |
+ Jun^e |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ |
+ ]])
+ expect([[
+
+ June
+ June]])
+ end)
+ end)
+
+ describe('with a lot of items', function()
+ before_each(function()
+ source([[
+ function! TestComplete() abort
+ call complete(1, map(range(0,100), "string(v:val)"))
+ return ''
+ endfunction
+ ]])
+ execute("set completeopt=menuone,noselect")
+ end)
+
+ it("works", function()
+ feed('i<C-r>=TestComplete()<CR>')
+ screen:expect([[
+ ^ |
+ {1:0 }{6: } |
+ {1:1 }{2: } |
+ {1:2 }{2: } |
+ {1:3 }{2: } |
+ {1:4 }{2: } |
+ {1:5 }{2: } |
+ {3:-- INSERT --} |
+ ]])
+ feed('7')
+ screen:expect([[
+ 7^ |
+ {1:7 }{6: } |
+ {1:70 }{6: } |
+ {1:71 }{6: } |
+ {1:72 }{2: } |
+ {1:73 }{2: } |
+ {1:74 }{2: } |
+ {3:-- INSERT --} |
+ ]])
+ feed('<c-n>')
+ screen:expect([[
+ 7^ |
+ {2:7 }{6: } |
+ {1:70 }{6: } |
+ {1:71 }{6: } |
+ {1:72 }{2: } |
+ {1:73 }{2: } |
+ {1:74 }{2: } |
+ {3:-- INSERT --} |
+ ]])
+ feed('<c-n>')
+ screen:expect([[
+ 70^ |
+ {1:7 }{6: } |
+ {2:70 }{6: } |
+ {1:71 }{6: } |
+ {1:72 }{2: } |
+ {1:73 }{2: } |
+ {1:74 }{2: } |
+ {3:-- INSERT --} |
+ ]])
+ end)
+
+ it('can be navigated with <PageDown>, <PageUp>', function()
+ feed('i<C-r>=TestComplete()<CR>')
+ screen:expect([[
+ ^ |
+ {1:0 }{6: } |
+ {1:1 }{2: } |
+ {1:2 }{2: } |
+ {1:3 }{2: } |
+ {1:4 }{2: } |
+ {1:5 }{2: } |
+ {3:-- INSERT --} |
+ ]])
+ feed('<PageDown>')
+ screen:expect([[
+ ^ |
+ {1:0 }{6: } |
+ {1:1 }{2: } |
+ {1:2 }{2: } |
+ {2:3 } |
+ {1:4 }{2: } |
+ {1:5 }{2: } |
+ {3:-- INSERT --} |
+ ]])
+ feed('<PageDown>')
+ screen:expect([[
+ ^ |
+ {1:5 }{6: } |
+ {1:6 }{2: } |
+ {2:7 } |
+ {1:8 }{2: } |
+ {1:9 }{2: } |
+ {1:10 }{2: } |
+ {3:-- INSERT --} |
+ ]])
+ feed('<Down>')
+ screen:expect([[
+ ^ |
+ {1:5 }{6: } |
+ {1:6 }{2: } |
+ {1:7 }{2: } |
+ {2:8 } |
+ {1:9 }{2: } |
+ {1:10 }{2: } |
+ {3:-- INSERT --} |
+ ]])
+ feed('<PageUp>')
+ screen:expect([[
+ ^ |
+ {1:2 }{6: } |
+ {1:3 }{2: } |
+ {2:4 } |
+ {1:5 }{2: } |
+ {1:6 }{2: } |
+ {1:7 }{2: } |
+ {3:-- INSERT --} |
+ ]])
+ feed('<PageUp>') -- stop on first item
+ screen:expect([[
+ ^ |
+ {2:0 }{6: } |
+ {1:1 }{2: } |
+ {1:2 }{2: } |
+ {1:3 }{2: } |
+ {1:4 }{2: } |
+ {1:5 }{2: } |
+ {3:-- INSERT --} |
+ ]])
+ feed('<PageUp>') -- when on first item, unselect
+ screen:expect([[
+ ^ |
+ {1:0 }{6: } |
+ {1:1 }{2: } |
+ {1:2 }{2: } |
+ {1:3 }{2: } |
+ {1:4 }{2: } |
+ {1:5 }{2: } |
+ {3:-- INSERT --} |
+ ]])
+ feed('<PageUp>') -- when unselected, select last item
+ screen:expect([[
+ ^ |
+ {1:95 }{2: } |
+ {1:96 }{2: } |
+ {1:97 }{2: } |
+ {1:98 }{2: } |
+ {1:99 }{2: } |
+ {2:100 }{6: } |
+ {3:-- INSERT --} |
+ ]])
+ feed('<PageUp>')
+ screen:expect([[
+ ^ |
+ {1:94 }{2: } |
+ {1:95 }{2: } |
+ {2:96 } |
+ {1:97 }{2: } |
+ {1:98 }{2: } |
+ {1:99 }{6: } |
+ {3:-- INSERT --} |
+ ]])
+ feed('<cr>')
+ screen:expect([[
+ 96^ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ {3:-- INSERT --} |
+ ]])
+ end)
+ end)
+
+
+ it('disables folding during completion', function ()
+ execute("set foldmethod=indent")
+ feed('i<Tab>foo<CR><Tab>bar<Esc>gg')
+ screen:expect([[
+ ^foo |
+ bar |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ |
+ ]])
+ feed('A<C-x><C-l>')
+ screen:expect([[
+ foo^ |
+ bar |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ {3:-- Whole line completion (^L^N^P) }{7:Pattern not found} |
+ ]])
+ eq(-1, eval('foldclosed(1)'))
+ end)
+
+ it('popupmenu is not interrupted by events', function ()
+ execute("set complete=.")
+
+ feed('ifoobar fooegg<cr>f<c-p>')
+ screen:expect([[
+ foobar fooegg |
+ fooegg^ |
+ {1:foobar } |
+ {2:fooegg } |
+ ~ |
+ ~ |
+ ~ |
+ {3:-- Keyword completion (^N^P) }{4:match 1 of 2} |
+ ]])
+
+ eval('1 + 1')
+ -- popupmenu still visible
+ screen:expect([[
+ foobar fooegg |
+ fooegg^ |
+ {1:foobar } |
+ {2:fooegg } |
+ ~ |
+ ~ |
+ ~ |
+ {3:-- Keyword completion (^N^P) }{4:match 1 of 2} |
+ ]])
+
+ feed('<c-p>')
+ -- Didn't restart completion: old matches still used
+ screen:expect([[
+ foobar fooegg |
+ foobar^ |
+ {2:foobar } |
+ {1:fooegg } |
+ ~ |
+ ~ |
+ ~ |
+ {3:-- Keyword completion (^N^P) }{4:match 2 of 2} |
+ ]])
+ end)
+
+ describe('from the commandline window', function()
+
+ it('is cleared after CTRL-C', function ()
+ feed('q:')
+ feed('ifoo faa fee f')
+ screen:expect([[
+ |
+ {8:[No Name] }|
+ :foo faa fee f^ |
+ :~ |
+ :~ |
+ :~ |
+ {9:[Command Line] }|
+ {3:-- INSERT --} |
+ ]], {[3] = {bold = true},
+ [4] = {bold = true, foreground = Screen.colors.SeaGreen},
+ [8] = {reverse = true},
+ [9] = {bold = true, reverse = true}})
+ feed('<c-x><c-n>')
+ screen:expect([[
+ |
+ {8:[No Name] }|
+ :foo faa fee foo^ |
+ :~ {2: foo } |
+ :~ {1: faa } |
+ :~ {1: fee } |
+ {9:[Command Line] }|
+ {3:-- Keyword Local completion (^N^P) }{4:match 1 of 3} |
+ ]],{[1] = {background = Screen.colors.LightMagenta},
+ [2] = {background = Screen.colors.Grey},
+ [3] = {bold = true},
+ [4] = {bold = true, foreground = Screen.colors.SeaGreen},
+ [8] = {reverse = true},
+ [9] = {bold = true, reverse = true}})
+ feed('<c-c>')
+ screen:expect([[
+ |
+ {8:[No Name] }|
+ :foo faa fee foo |
+ :~ |
+ :~ |
+ :~ |
+ {9:[Command Line] }|
+ :foo faa fee foo^ |
+ ]], {[8] = {reverse = true}, [9] = {bold = true, reverse = true}})
+ end)
end)
end)
diff --git a/test/functional/viml/errorlist_spec.lua b/test/functional/viml/errorlist_spec.lua
new file mode 100644
index 0000000000..30cb86f8d1
--- /dev/null
+++ b/test/functional/viml/errorlist_spec.lua
@@ -0,0 +1,73 @@
+local helpers = require('test.functional.helpers')
+
+local clear = helpers.clear
+local command = helpers.command
+local eq = helpers.eq
+local exc_exec = helpers.exc_exec
+local get_cur_win_var = helpers.curwinmeths.get_var
+
+describe('setqflist()', function()
+ local setqflist = helpers.funcs.setqflist
+
+ before_each(clear)
+
+ it('requires a list for {list}', function()
+ eq('Vim(call):E714: List required', exc_exec('call setqflist("foo")'))
+ eq('Vim(call):E714: List required', exc_exec('call setqflist(5)'))
+ eq('Vim(call):E714: List required', exc_exec('call setqflist({})'))
+ end)
+
+ it('requires a string for {action}', function()
+ eq('Vim(call):E114: String required', exc_exec('call setqflist([], 5)'))
+ eq('Vim(call):E114: String required', exc_exec('call setqflist([], [])'))
+ eq('Vim(call):E114: String required', exc_exec('call setqflist([], {})'))
+ end)
+
+ it('sets w:quickfix_title', function()
+ setqflist({''}, 'r', 'foo')
+ command('copen')
+ eq(':foo', get_cur_win_var('quickfix_title'))
+ end)
+
+ it('requires string or number for {title}', function()
+ command('copen')
+ setqflist({}, 'r', '5')
+ eq(':5', get_cur_win_var('quickfix_title'))
+ setqflist({}, 'r', 6)
+ eq(':6', get_cur_win_var('quickfix_title'))
+ local exc = exc_exec('call setqflist([], "r", function("function"))')
+ eq('Vim(call):E729: using Funcref as a String', exc)
+ exc = exc_exec('call setqflist([], "r", [])')
+ eq('Vim(call):E730: using List as a String', exc)
+ exc = exc_exec('call setqflist([], "r", {})')
+ eq('Vim(call):E731: using Dictionary as a String', exc)
+ end)
+end)
+
+describe('setloclist()', function()
+ local setloclist = helpers.funcs.setloclist
+
+ before_each(clear)
+
+ it('requires a list for {list}', function()
+ eq('Vim(call):E714: List required', exc_exec('call setloclist(0, "foo")'))
+ eq('Vim(call):E714: List required', exc_exec('call setloclist(0, 5)'))
+ eq('Vim(call):E714: List required', exc_exec('call setloclist(0, {})'))
+ end)
+
+ it('requires a string for {action}', function()
+ eq('Vim(call):E114: String required', exc_exec('call setloclist(0, [], 5)'))
+ eq('Vim(call):E114: String required', exc_exec('call setloclist(0, [], [])'))
+ eq('Vim(call):E114: String required', exc_exec('call setloclist(0, [], {})'))
+ end)
+
+ it('sets w:quickfix_title for the correct window', function()
+ command('rightbelow vsplit')
+ setloclist(1, {}, 'r', 'foo')
+ setloclist(2, {}, 'r', 'bar')
+ command('lopen')
+ eq(':bar', get_cur_win_var('quickfix_title'))
+ command('lclose | wincmd w | lopen')
+ eq(':foo', get_cur_win_var('quickfix_title'))
+ end)
+end)
diff --git a/test/functional/viml/function_spec.lua b/test/functional/viml/function_spec.lua
new file mode 100644
index 0000000000..665f5d4467
--- /dev/null
+++ b/test/functional/viml/function_spec.lua
@@ -0,0 +1,29 @@
+local helpers = require('test.functional.helpers')
+
+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)