aboutsummaryrefslogtreecommitdiff
path: root/test/functional/ex_cmds
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/ex_cmds
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/ex_cmds')
-rw-r--r--test/functional/ex_cmds/arg_spec.lua8
-rw-r--r--test/functional/ex_cmds/bang_filter_spec.lua4
-rw-r--r--test/functional/ex_cmds/cd_spec.lua54
-rw-r--r--test/functional/ex_cmds/ctrl_c_spec.lua8
-rw-r--r--test/functional/ex_cmds/dict_notifications_spec.lua91
-rw-r--r--test/functional/ex_cmds/drop_spec.lua22
-rw-r--r--test/functional/ex_cmds/echo_spec.lua321
-rw-r--r--test/functional/ex_cmds/edit_spec.lua9
-rw-r--r--test/functional/ex_cmds/encoding_spec.lua10
-rw-r--r--test/functional/ex_cmds/file_spec.lua35
-rw-r--r--test/functional/ex_cmds/grep_spec.lua10
-rw-r--r--test/functional/ex_cmds/highlight_spec.lua43
-rw-r--r--test/functional/ex_cmds/menu_spec.lua589
-rw-r--r--test/functional/ex_cmds/mksession_spec.lua49
-rw-r--r--test/functional/ex_cmds/mkview_spec.lua67
-rw-r--r--test/functional/ex_cmds/oldfiles_spec.lua61
-rw-r--r--test/functional/ex_cmds/print_commands_spec.lua12
-rw-r--r--test/functional/ex_cmds/quickfix_commands_spec.lua111
-rw-r--r--test/functional/ex_cmds/recover_spec.lua47
-rw-r--r--test/functional/ex_cmds/script_spec.lua75
-rw-r--r--test/functional/ex_cmds/syntax_spec.lua17
-rw-r--r--test/functional/ex_cmds/undojoin_spec.lua8
-rw-r--r--test/functional/ex_cmds/write_spec.lua58
-rw-r--r--test/functional/ex_cmds/wundo_spec.lua15
-rw-r--r--test/functional/ex_cmds/wviminfo_spec.lua12
25 files changed, 1584 insertions, 152 deletions
diff --git a/test/functional/ex_cmds/arg_spec.lua b/test/functional/ex_cmds/arg_spec.lua
index e11b90532f..6d31f05c2a 100644
--- a/test/functional/ex_cmds/arg_spec.lua
+++ b/test/functional/ex_cmds/arg_spec.lua
@@ -1,5 +1,5 @@
local helpers = require("test.functional.helpers")(after_each)
-local eq, execute, funcs = helpers.eq, helpers.execute, helpers.funcs
+local eq, command, funcs = helpers.eq, helpers.command, helpers.funcs
local ok = helpers.ok
local clear = helpers.clear
@@ -9,15 +9,15 @@ describe(":argument", function()
end)
it("does not restart :terminal buffer", function()
- execute("terminal")
+ command("terminal")
helpers.feed([[<C-\><C-N>]])
- execute("argadd")
+ command("argadd")
helpers.feed([[<C-\><C-N>]])
local bufname_before = funcs.bufname("%")
local bufnr_before = funcs.bufnr("%")
helpers.ok(nil ~= string.find(bufname_before, "^term://")) -- sanity
- execute("argument 1")
+ command("argument 1")
helpers.feed([[<C-\><C-N>]])
local bufname_after = funcs.bufname("%")
diff --git a/test/functional/ex_cmds/bang_filter_spec.lua b/test/functional/ex_cmds/bang_filter_spec.lua
index a320e6d018..aaec983b73 100644
--- a/test/functional/ex_cmds/bang_filter_spec.lua
+++ b/test/functional/ex_cmds/bang_filter_spec.lua
@@ -1,7 +1,7 @@
-- Specs for bang/filter commands
local helpers = require('test.functional.helpers')(after_each)
-local feed, execute, clear = helpers.feed, helpers.execute, helpers.clear
+local feed, command, clear = helpers.feed, helpers.command, helpers.clear
local mkdir, write_file, rmdir = helpers.mkdir, helpers.write_file, helpers.rmdir
if helpers.pending_win32(pending) then return end
@@ -28,7 +28,7 @@ describe('issues', function()
end)
it('#3269 Last line of shell output is not truncated', function()
- execute([[nnoremap <silent>\l :!ls bang_filter_spec<cr>]])
+ command([[nnoremap <silent>\l :!ls bang_filter_spec<cr>]])
feed([[\l]])
screen:expect([[
~ |
diff --git a/test/functional/ex_cmds/cd_spec.lua b/test/functional/ex_cmds/cd_spec.lua
index 5bf4d22d0f..059cb26d5d 100644
--- a/test/functional/ex_cmds/cd_spec.lua
+++ b/test/functional/ex_cmds/cd_spec.lua
@@ -6,7 +6,7 @@ local helpers = require('test.functional.helpers')(after_each)
local eq = helpers.eq
local call = helpers.call
local clear = helpers.clear
-local execute = helpers.execute
+local command = helpers.command
local exc_exec = helpers.exc_exec
if helpers.pending_win32(pending) then return end
@@ -58,7 +58,7 @@ for _, cmd in ipairs {'cd', 'chdir'} do
eq(0, lwd(globalwin))
eq(0, lwd(globalwin, tabnr))
- execute('bot split')
+ command('bot split')
local localwin = call('winnr')
-- Initial window is still using globalDir
eq(globalDir, cwd(localwin))
@@ -66,7 +66,7 @@ for _, cmd in ipairs {'cd', 'chdir'} do
eq(0, lwd(globalwin))
eq(0, lwd(globalwin, tabnr))
- execute('silent l' .. cmd .. ' ' .. directories.window)
+ command('silent l' .. cmd .. ' ' .. directories.window)
-- From window with local dir, the original window
-- is still reporting the global dir
eq(globalDir, cwd(globalwin))
@@ -80,7 +80,7 @@ for _, cmd in ipairs {'cd', 'chdir'} do
eq(1, lwd(localwin))
eq(1, lwd(localwin, tabnr))
- execute('tabnew')
+ command('tabnew')
-- From new tab page, original window reports global dir
eq(globalDir, cwd(globalwin, tabnr))
eq(0, lwd(globalwin, tabnr))
@@ -100,8 +100,8 @@ for _, cmd in ipairs {'cd', 'chdir'} do
eq(0, lwd(-1, 0))
eq(0, lwd(-1, globaltab))
- execute('tabnew')
- execute('silent t' .. cmd .. ' ' .. directories.tab)
+ command('tabnew')
+ command('silent t' .. cmd .. ' ' .. directories.tab)
local localtab = call('tabpagenr')
-- From local tab page, original tab reports globalDir
@@ -114,7 +114,7 @@ for _, cmd in ipairs {'cd', 'chdir'} do
eq(1, lwd(-1, 0))
eq(1, lwd(-1, localtab))
- execute('tabnext')
+ command('tabnext')
-- From original tab page, local reports as such
eq(globalDir .. '/' .. directories.tab, cwd(-1, localtab))
eq(1, lwd(-1, localtab))
@@ -128,13 +128,13 @@ for _, cmd in ipairs {'cd', 'chdir'} do
end)
it('works with tab-local pwd', function()
- execute('silent t' .. cmd .. ' ' .. directories.tab)
+ command('silent t' .. cmd .. ' ' .. directories.tab)
eq(directories.start, cwd(-1, -1))
eq(0, lwd(-1, -1))
end)
it('works with window-local pwd', function()
- execute('silent l' .. cmd .. ' ' .. directories.window)
+ command('silent l' .. cmd .. ' ' .. directories.window)
eq(directories.start, cwd(-1, -1))
eq(0, lwd(-1, -1))
end)
@@ -145,18 +145,18 @@ for _, cmd in ipairs {'cd', 'chdir'} do
local globalDir = directories.start
-- Create a new tab and change directory
- execute('tabnew')
- execute('silent t' .. cmd .. ' ' .. directories.tab)
+ command('tabnew')
+ command('silent t' .. cmd .. ' ' .. directories.tab)
eq(globalDir .. '/' .. directories.tab, tcwd())
-- Create a new tab and verify it has inherited the directory
- execute('tabnew')
+ command('tabnew')
eq(globalDir .. '/' .. directories.tab, tcwd())
-- Change tab and change back, verify that directories are correct
- execute('tabnext')
+ command('tabnext')
eq(globalDir, tcwd())
- execute('tabprevious')
+ command('tabprevious')
eq(globalDir .. '/' .. directories.tab, tcwd())
end)
end)
@@ -164,7 +164,7 @@ for _, cmd in ipairs {'cd', 'chdir'} do
it('works', function()
local globalDir = directories.start
-- Create a new tab first and verify that is has the same working dir
- execute('tabnew')
+ command('tabnew')
eq(globalDir, cwd())
eq(globalDir, tcwd()) -- has no tab-local directory
eq(0, tlwd())
@@ -172,7 +172,7 @@ for _, cmd in ipairs {'cd', 'chdir'} do
eq(0, wlwd())
-- Change tab-local working directory and verify it is different
- execute('silent t' .. cmd .. ' ' .. directories.tab)
+ command('silent t' .. cmd .. ' ' .. directories.tab)
eq(globalDir .. '/' .. directories.tab, cwd())
eq(cwd(), tcwd()) -- working directory maches tab directory
eq(1, tlwd())
@@ -180,46 +180,46 @@ for _, cmd in ipairs {'cd', 'chdir'} do
eq(0, wlwd())
-- Create a new window in this tab to test `:lcd`
- execute('new')
+ command('new')
eq(1, tlwd()) -- Still tab-local working directory
eq(0, wlwd()) -- Still no window-local working directory
eq(globalDir .. '/' .. directories.tab, cwd())
- execute('silent l' .. cmd .. ' ../' .. directories.window)
+ command('silent l' .. cmd .. ' ../' .. directories.window)
eq(globalDir .. '/' .. directories.window, cwd())
eq(globalDir .. '/' .. directories.tab, tcwd())
eq(1, wlwd())
-- Verify the first window still has the tab local directory
- execute('wincmd w')
+ command('wincmd w')
eq(globalDir .. '/' .. directories.tab, cwd())
eq(globalDir .. '/' .. directories.tab, tcwd())
eq(0, wlwd()) -- No window-local directory
-- Change back to initial tab and verify working directory has stayed
- execute('tabnext')
+ command('tabnext')
eq(globalDir, cwd() )
eq(0, tlwd())
eq(0, wlwd())
-- Verify global changes don't affect local ones
- execute('silent ' .. cmd .. ' ' .. directories.global)
+ command('silent ' .. cmd .. ' ' .. directories.global)
eq(globalDir .. '/' .. directories.global, cwd())
- execute('tabnext')
+ command('tabnext')
eq(globalDir .. '/' .. directories.tab, cwd())
eq(globalDir .. '/' .. directories.tab, tcwd())
eq(0, wlwd()) -- Still no window-local directory in this window
-- Unless the global change happened in a tab with local directory
- execute('silent ' .. cmd .. ' ..')
+ command('silent ' .. cmd .. ' ..')
eq(globalDir, cwd() )
eq(0 , tlwd())
eq(0 , wlwd())
-- Which also affects the first tab
- execute('tabnext')
+ command('tabnext')
eq(globalDir, cwd())
-- But not in a window with its own local directory
- execute('tabnext | wincmd w')
+ command('tabnext | wincmd w')
eq(globalDir .. '/' .. directories.window, cwd() )
eq(0 , tlwd())
eq(globalDir .. '/' .. directories.window, wcwd())
@@ -280,8 +280,8 @@ describe("getcwd()", function ()
end)
it("returns empty string if working directory does not exist", function()
- execute("cd "..directories.global)
- execute("call delete('../"..directories.global.."', 'd')")
+ command("cd "..directories.global)
+ command("call delete('../"..directories.global.."', 'd')")
eq("", helpers.eval("getcwd()"))
end)
end)
diff --git a/test/functional/ex_cmds/ctrl_c_spec.lua b/test/functional/ex_cmds/ctrl_c_spec.lua
index 072fd2ad10..8f76099f79 100644
--- a/test/functional/ex_cmds/ctrl_c_spec.lua
+++ b/test/functional/ex_cmds/ctrl_c_spec.lua
@@ -1,7 +1,7 @@
local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen')
local clear, feed, source = helpers.clear, helpers.feed, helpers.source
-local execute = helpers.execute
+local command = helpers.command
describe("CTRL-C (mapped)", function()
before_each(function()
@@ -20,7 +20,7 @@ describe("CTRL-C (mapped)", function()
nnoremap <C-C> <NOP>
]])
- execute("silent edit! test/functional/fixtures/bigfile.txt")
+ command("silent edit! test/functional/fixtures/bigfile.txt")
local screen = Screen.new(52, 6)
screen:attach()
screen:set_default_attr_ids({
@@ -41,13 +41,13 @@ describe("CTRL-C (mapped)", function()
local function test_ctrl_c(ms)
feed(":global/^/p<CR>")
- helpers.sleep(ms)
+ screen:sleep(ms)
feed("<C-C>")
screen:expect([[Interrupt]], nil, nil, nil, true)
end
-- The test is time-sensitive. Try different sleep values.
- local ms_values = {1, 10, 100}
+ local ms_values = {100, 1000, 10000}
for i, ms in ipairs(ms_values) do
if i < #ms_values then
local status, _ = pcall(test_ctrl_c, ms)
diff --git a/test/functional/ex_cmds/dict_notifications_spec.lua b/test/functional/ex_cmds/dict_notifications_spec.lua
index 30753c34ac..e3b4a1c504 100644
--- a/test/functional/ex_cmds/dict_notifications_spec.lua
+++ b/test/functional/ex_cmds/dict_notifications_spec.lua
@@ -9,7 +9,7 @@ local eval = helpers.eval
describe('dictionary change notifications', function()
local channel
- setup(function()
+ before_each(function()
clear()
channel = nvim('get_api_info')[1]
nvim('set_var', 'channel', channel)
@@ -18,19 +18,15 @@ describe('dictionary change notifications', function()
-- the same set of tests are applied to top-level dictionaries(g:, b:, w: and
-- t:) and a dictionary variable, so we generate them in the following
-- function.
- local function gentests(dict_expr, dict_expr_suffix, dict_init)
- if not dict_expr_suffix then
- dict_expr_suffix = ''
- end
-
+ local function gentests(dict_expr, dict_init)
local function update(opval, key)
if not key then
key = 'watched'
end
if opval == '' then
- nvim('command', "unlet "..dict_expr..dict_expr_suffix..key)
+ command(('unlet %s[\'%s\']'):format(dict_expr, key))
else
- nvim('command', "let "..dict_expr..dict_expr_suffix..key.." "..opval)
+ command(('let %s[\'%s\'] %s'):format(dict_expr, key, opval))
end
end
@@ -48,9 +44,9 @@ describe('dictionary change notifications', function()
eq({'notification', 'values', {key, vals}}, next_msg())
end
- describe('watcher', function()
+ describe(dict_expr .. ' watcher', function()
if dict_init then
- setup(function()
+ before_each(function()
source(dict_init)
end)
end
@@ -58,7 +54,7 @@ describe('dictionary change notifications', function()
before_each(function()
source([[
function! g:Changed(dict, key, value)
- if a:dict != ]]..dict_expr..[[ |
+ if a:dict isnot ]]..dict_expr..[[ |
throw 'invalid dict'
endif
call rpcnotify(g:channel, 'values', a:key, a:value)
@@ -143,6 +139,32 @@ describe('dictionary change notifications', function()
]])
end)
+ it('is triggered for empty keys', function()
+ command([[
+ call dictwatcheradd(]]..dict_expr..[[, "", "g:Changed")
+ ]])
+ update('= 1', '')
+ verify_value({new = 1}, '')
+ update('= 2', '')
+ verify_value({old = 1, new = 2}, '')
+ command([[
+ call dictwatcherdel(]]..dict_expr..[[, "", "g:Changed")
+ ]])
+ end)
+
+ it('is triggered for empty keys when using catch-all *', function()
+ command([[
+ call dictwatcheradd(]]..dict_expr..[[, "*", "g:Changed")
+ ]])
+ update('= 1', '')
+ verify_value({new = 1}, '')
+ update('= 2', '')
+ verify_value({old = 1, new = 2}, '')
+ command([[
+ call dictwatcherdel(]]..dict_expr..[[, "*", "g:Changed")
+ ]])
+ end)
+
-- test a sequence of updates of different types to ensure proper memory
-- management(with ASAN)
local function test_updates(tests)
@@ -190,10 +212,10 @@ describe('dictionary change notifications', function()
gentests('b:')
gentests('w:')
gentests('t:')
- gentests('g:dict_var', '.', 'let g:dict_var = {}')
+ gentests('g:dict_var', 'let g:dict_var = {}')
describe('multiple watchers on the same dict/key', function()
- setup(function()
+ before_each(function()
source([[
function! g:Watcher1(dict, key, value)
call rpcnotify(g:channel, '1', a:key, a:value)
@@ -213,13 +235,37 @@ describe('dictionary change notifications', function()
end)
it('only removes watchers that fully match dict, key and callback', function()
+ nvim('command', 'let g:key = "value"')
+ eq({'notification', '1', {'key', {new = 'value'}}}, next_msg())
+ eq({'notification', '2', {'key', {new = 'value'}}}, next_msg())
nvim('command', 'call dictwatcherdel(g:, "key", "g:Watcher1")')
nvim('command', 'let g:key = "v2"')
eq({'notification', '2', {'key', {old = 'value', new = 'v2'}}}, next_msg())
end)
end)
+ it('errors out when adding to v:_null_dict', function()
+ command([[
+ function! g:Watcher1(dict, key, value)
+ call rpcnotify(g:channel, '1', a:key, a:value)
+ endfunction
+ ]])
+ eq('Vim(call):E46: Cannot change read-only variable "dictwatcheradd() argument"',
+ exc_exec('call dictwatcheradd(v:_null_dict, "x", "g:Watcher1")'))
+ end)
+
describe('errors', function()
+ before_each(function()
+ source([[
+ function! g:Watcher1(dict, key, value)
+ call rpcnotify(g:channel, '1', a:key, a:value)
+ endfunction
+ function! g:Watcher2(dict, key, value)
+ call rpcnotify(g:channel, '2', a:key, a:value)
+ endfunction
+ ]])
+ end)
+
-- WARNING: This suite depends on the above tests
it('fails to remove if no watcher with matching callback is found', function()
eq("Vim(call):Couldn't find a watcher matching key and callback",
@@ -236,15 +282,24 @@ describe('dictionary change notifications', function()
command('call dictwatcherdel(g:, "key", "g:InvalidCb")')
end)
- it('fails with empty keys', function()
- eq("Vim(call):E713: Cannot use empty key for Dictionary",
- exc_exec('call dictwatcheradd(g:, "", "g:Watcher1")'))
- eq("Vim(call):E713: Cannot use empty key for Dictionary",
- exc_exec('call dictwatcherdel(g:, "", "g:Watcher1")'))
+ it('fails to remove watcher from v:_null_dict', function()
+ eq("Vim(call):Couldn't find a watcher matching key and callback",
+ exc_exec('call dictwatcherdel(v:_null_dict, "x", "g:Watcher2")'))
end)
+ --[[
+ [ it("fails to add/remove if the callback doesn't exist", function()
+ [ eq("Vim(call):Function g:InvalidCb doesn't exist",
+ [ exc_exec('call dictwatcheradd(g:, "key", "g:InvalidCb")'))
+ [ eq("Vim(call):Function g:InvalidCb doesn't exist",
+ [ exc_exec('call dictwatcherdel(g:, "key", "g:InvalidCb")'))
+ [ end)
+ ]]
+
it('does not fail to replace a watcher function', function()
source([[
+ let g:key = 'v2'
+ call dictwatcheradd(g:, "key", "g:Watcher2")
function! g:ReplaceWatcher2()
function! g:Watcher2(dict, key, value)
call rpcnotify(g:channel, '2b', a:key, a:value)
diff --git a/test/functional/ex_cmds/drop_spec.lua b/test/functional/ex_cmds/drop_spec.lua
index 99db5ea333..9105b84367 100644
--- a/test/functional/ex_cmds/drop_spec.lua
+++ b/test/functional/ex_cmds/drop_spec.lua
@@ -1,6 +1,6 @@
local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen')
-local clear, feed, execute = helpers.clear, helpers.feed, helpers.execute
+local clear, feed, feed_command = helpers.clear, helpers.feed, helpers.feed_command
describe(":drop", function()
local screen
@@ -15,7 +15,7 @@ describe(":drop", function()
[2] = {reverse = true},
[3] = {bold = true},
})
- execute("set laststatus=2")
+ feed_command("set laststatus=2")
end)
after_each(function()
@@ -23,7 +23,7 @@ describe(":drop", function()
end)
it("works like :e when called with only one window open", function()
- execute("drop tmp1.vim")
+ feed_command("drop tmp1.vim")
screen:expect([[
^ |
{0:~ }|
@@ -39,10 +39,10 @@ describe(":drop", function()
end)
it("switches to an open window showing the buffer", function()
- execute("edit tmp1")
- execute("vsplit")
- execute("edit tmp2")
- execute("drop tmp1")
+ feed_command("edit tmp1")
+ feed_command("vsplit")
+ feed_command("edit tmp2")
+ feed_command("drop tmp1")
screen:expect([[
{2:|}^ |
{0:~ }{2:|}{0:~ }|
@@ -58,11 +58,11 @@ describe(":drop", function()
end)
it("splits off a new window when a buffer can't be abandoned", function()
- execute("edit tmp1")
- execute("vsplit")
- execute("edit tmp2")
+ feed_command("edit tmp1")
+ feed_command("vsplit")
+ feed_command("edit tmp2")
feed("iABC<esc>")
- execute("drop tmp3")
+ feed_command("drop tmp3")
screen:expect([[
^ {2:|} |
{0:~ }{2:|}{0:~ }|
diff --git a/test/functional/ex_cmds/echo_spec.lua b/test/functional/ex_cmds/echo_spec.lua
new file mode 100644
index 0000000000..10c7230896
--- /dev/null
+++ b/test/functional/ex_cmds/echo_spec.lua
@@ -0,0 +1,321 @@
+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 source = helpers.source
+local dedent = helpers.dedent
+local command = helpers.command
+local exc_exec = helpers.exc_exec
+local redir_exec = helpers.redir_exec
+
+describe(':echo', function()
+ before_each(function()
+ clear()
+ source([[
+ function String(s)
+ return execute('echo a:s')[1:]
+ endfunction
+ ]])
+ end)
+
+ describe('used to represent floating-point values', function()
+ it('dumps NaN values', function()
+ eq('str2float(\'nan\')', eval('String(str2float(\'nan\'))'))
+ end)
+
+ it('dumps infinite values', function()
+ eq('str2float(\'inf\')', eval('String(str2float(\'inf\'))'))
+ eq('-str2float(\'inf\')', eval('String(str2float(\'-inf\'))'))
+ end)
+
+ it('dumps regular values', function()
+ eq('1.5', funcs.String(1.5))
+ eq('1.56e-20', funcs.String(1.56000e-020))
+ eq('0.0', eval('String(0.0)'))
+ end)
+
+ it('dumps special v: values', function()
+ eq('v:true', eval('String(v:true)'))
+ eq('v:false', eval('String(v:false)'))
+ eq('v:null', eval('String(v:null)'))
+ eq('v:true', funcs.String(true))
+ eq('v:false', funcs.String(false))
+ eq('v:null', funcs.String(NIL))
+ end)
+
+ it('dumps values with at most six digits after the decimal point',
+ function()
+ eq('1.234568e-20', funcs.String(1.23456789123456789123456789e-020))
+ eq('1.234568', funcs.String(1.23456789123456789123456789))
+ end)
+
+ it('dumps values with at most seven digits before the decimal point',
+ function()
+ eq('1234567.891235', funcs.String(1234567.89123456789123456789))
+ eq('1.234568e7', funcs.String(12345678.9123456789123456789))
+ end)
+
+ it('dumps negative values', function()
+ eq('-1.5', funcs.String(-1.5))
+ eq('-1.56e-20', funcs.String(-1.56000e-020))
+ eq('-1.234568e-20', funcs.String(-1.23456789123456789123456789e-020))
+ eq('-1.234568', funcs.String(-1.23456789123456789123456789))
+ eq('-1234567.891235', funcs.String(-1234567.89123456789123456789))
+ eq('-1.234568e7', funcs.String(-12345678.9123456789123456789))
+ end)
+ end)
+
+ describe('used to represent numbers', function()
+ it('dumps regular values', function()
+ eq('0', funcs.String(0))
+ eq('-1', funcs.String(-1))
+ eq('1', funcs.String(1))
+ end)
+
+ it('dumps large values', function()
+ eq('2147483647', funcs.String(2^31-1))
+ eq('-2147483648', funcs.String(-2^31))
+ end)
+ end)
+
+ describe('used to represent strings', function()
+ it('dumps regular strings', function()
+ eq('test', funcs.String('test'))
+ end)
+
+ it('dumps empty strings', function()
+ eq('', funcs.String(''))
+ end)
+
+ it('dumps strings with \' inside', function()
+ eq('\'\'\'', funcs.String('\'\'\''))
+ eq('a\'b\'\'', funcs.String('a\'b\'\''))
+ eq('\'b\'\'d', funcs.String('\'b\'\'d'))
+ eq('a\'b\'c\'d', funcs.String('a\'b\'c\'d'))
+ end)
+
+ it('dumps NULL strings', function()
+ eq('', eval('String($XXX_UNEXISTENT_VAR_XXX)'))
+ end)
+
+ it('dumps NULL lists', function()
+ eq('[]', eval('String(v:_null_list)'))
+ end)
+
+ it('dumps NULL dictionaries', function()
+ eq('{}', eval('String(v:_null_dict)'))
+ end)
+ end)
+
+ describe('used to represent funcrefs', function()
+ before_each(function()
+ source([[
+ function Test1()
+ endfunction
+
+ function s:Test2() dict
+ endfunction
+
+ function g:Test3() dict
+ endfunction
+
+ let g:Test2_f = function('s:Test2')
+ ]])
+ end)
+
+ it('dumps references to built-in functions', function()
+ eq('function', eval('String(function("function"))'))
+ end)
+
+ it('dumps references to user functions', function()
+ eq('Test1', eval('String(function("Test1"))'))
+ eq('g:Test3', eval('String(function("g:Test3"))'))
+ end)
+
+ it('dumps references to script functions', function()
+ eq('<SNR>2_Test2', eval('String(Test2_f)'))
+ end)
+
+ it('dumps partials with self referencing a partial', function()
+ source([[
+ function TestDict() dict
+ endfunction
+ let d = {}
+ let TestDictRef = function('TestDict', d)
+ let d.tdr = TestDictRef
+ ]])
+ eq(dedent([[
+
+ function('TestDict', {'tdr': function('TestDict', {...@1})})
+ function('TestDict', {'tdr': function('TestDict', {...@1})})]]),
+ redir_exec('echo String(d.tdr)'))
+ end)
+
+ it('dumps automatically created partials', function()
+ eq('function(\'<SNR>2_Test2\', {\'f\': function(\'<SNR>2_Test2\')})',
+ eval('String({"f": Test2_f}.f)'))
+ eq('function(\'<SNR>2_Test2\', [1], {\'f\': function(\'<SNR>2_Test2\', [1])})',
+ eval('String({"f": function(Test2_f, [1])}.f)'))
+ end)
+
+ it('dumps manually created partials', function()
+ eq('function(\'Test3\', [1, 2], {})',
+ eval('String(function("Test3", [1, 2], {}))'))
+ eq('function(\'Test3\', {})',
+ eval('String(function("Test3", {}))'))
+ eq('function(\'Test3\', [1, 2])',
+ eval('String(function("Test3", [1, 2]))'))
+ end)
+
+ it('does not crash or halt when dumping partials with reference cycles in self',
+ function()
+ meths.set_var('d', {v=true})
+ eq(dedent([[
+
+ {'p': function('<SNR>2_Test2', {...@0}), 'f': function('<SNR>2_Test2'), 'v': v:true}
+ {'p': function('<SNR>2_Test2', {...@0}), 'f': function('<SNR>2_Test2'), 'v': v:true}]]),
+ redir_exec('echo String(extend(extend(g:d, {"f": g:Test2_f}), {"p": g:d.f}))'))
+ end)
+
+ it('does not show errors when dumping partials referencing the same dictionary',
+ function()
+ command('let d = {}')
+ -- Regression for “eval/typval_encode: Dump empty dictionary before
+ -- checking for refcycle”, results in error.
+ eq('[function(\'tr\', {}), function(\'tr\', {})]', eval('String([function("tr", d), function("tr", d)])'))
+ -- Regression for “eval: Work with reference cycles in partials (self)
+ -- properly”, results in crash.
+ eval('extend(d, {"a": 1})')
+ eq('[function(\'tr\', {\'a\': 1}), function(\'tr\', {\'a\': 1})]', eval('String([function("tr", d), function("tr", d)])'))
+ end)
+
+ it('does not crash or halt when dumping partials with reference cycles in arguments',
+ function()
+ meths.set_var('l', {})
+ eval('add(l, l)')
+ -- Regression: the below line used to crash (add returns original list and
+ -- there was error in dumping partials). Tested explicitly in
+ -- test/unit/api/private_helpers_spec.lua.
+ eval('add(l, function("Test1", l))')
+ eq(dedent([=[
+
+ function('Test1', [[[...@2], function('Test1', [[...@2]])], function('Test1', [[[...@4], function('Test1', [[...@4]])]])])
+ function('Test1', [[[...@2], function('Test1', [[...@2]])], function('Test1', [[[...@4], function('Test1', [[...@4]])]])])]=]),
+ redir_exec('echo String(function("Test1", l))'))
+ end)
+
+ it('does not crash or halt when dumping partials with reference cycles in self and arguments',
+ function()
+ meths.set_var('d', {v=true})
+ meths.set_var('l', {})
+ eval('add(l, l)')
+ eval('add(l, function("Test1", l))')
+ eval('add(l, function("Test1", d))')
+ eq(dedent([=[
+
+ {'p': function('<SNR>2_Test2', [[[...@3], function('Test1', [[...@3]]), function('Test1', {...@0})], function('Test1', [[[...@5], function('Test1', [[...@5]]), function('Test1', {...@0})]]), function('Test1', {...@0})], {...@0}), 'f': function('<SNR>2_Test2'), 'v': v:true}
+ {'p': function('<SNR>2_Test2', [[[...@3], function('Test1', [[...@3]]), function('Test1', {...@0})], function('Test1', [[[...@5], function('Test1', [[...@5]]), function('Test1', {...@0})]]), function('Test1', {...@0})], {...@0}), 'f': function('<SNR>2_Test2'), 'v': v:true}]=]),
+ redir_exec('echo String(extend(extend(g:d, {"f": g:Test2_f}), {"p": function(g:d.f, l)}))'))
+ end)
+ end)
+
+ describe('used to represent lists', function()
+ it('dumps empty list', function()
+ eq('[]', funcs.String({}))
+ end)
+
+ it('dumps nested lists', function()
+ eq('[[[[[]]]]]', funcs.String({{{{{}}}}}))
+ end)
+
+ it('dumps nested non-empty lists', function()
+ eq('[1, [[3, [[5], 4]], 2]]', funcs.String({1, {{3, {{5}, 4}}, 2}}))
+ end)
+
+ it('does not error when dumping recursive lists', function()
+ meths.set_var('l', {})
+ eval('add(l, l)')
+ eq(0, exc_exec('echo String(l)'))
+ end)
+
+ it('dumps recursive lists without error', function()
+ meths.set_var('l', {})
+ eval('add(l, l)')
+ eq('\n[[...@0]]\n[[...@0]]', redir_exec('echo String(l)'))
+ eq('\n[[[...@1]]]\n[[[...@1]]]', redir_exec('echo String([l])'))
+ end)
+ end)
+
+ describe('used to represent dictionaries', function()
+ it('dumps empty dictionary', function()
+ eq('{}', eval('String({})'))
+ end)
+
+ it('dumps list with two same empty dictionaries, also in partials', function()
+ command('let d = {}')
+ eq('[{}, {}]', eval('String([d, d])'))
+ eq('[function(\'tr\', {}), {}]', eval('String([function("tr", d), d])'))
+ eq('[{}, function(\'tr\', {})]', eval('String([d, function("tr", d)])'))
+ end)
+
+ it('dumps non-empty dictionary', function()
+ eq('{\'t\'\'est\': 1}', funcs.String({['t\'est']=1}))
+ end)
+
+ it('does not error when dumping recursive dictionaries', function()
+ meths.set_var('d', {d=1})
+ eval('extend(d, {"d": d})')
+ eq(0, exc_exec('echo String(d)'))
+ end)
+
+ it('dumps recursive dictionaries without the error', function()
+ meths.set_var('d', {d=1})
+ eval('extend(d, {"d": d})')
+ eq('\n{\'d\': {...@0}}\n{\'d\': {...@0}}',
+ redir_exec('echo String(d)'))
+ eq('\n{\'out\': {\'d\': {...@1}}}\n{\'out\': {\'d\': {...@1}}}',
+ redir_exec('echo String({"out": d})'))
+ end)
+ end)
+
+ describe('used to represent special values', function()
+ local function chr(n)
+ return ('%c'):format(n)
+ end
+ local function ctrl(c)
+ return ('%c'):format(c:upper():byte() - 0x40)
+ end
+ it('displays hex as hex', function()
+ -- Regression: due to missing (uint8_t) cast \x80 was represented as
+ -- ~@<80>.
+ eq('<80>', funcs.String(chr(0x80)))
+ eq('<81>', funcs.String(chr(0x81)))
+ eq('<8e>', funcs.String(chr(0x8e)))
+ eq('<c2>', funcs.String(('«'):sub(1, 1)))
+ eq('«', funcs.String(('«'):sub(1, 2)))
+ end)
+ it('displays ASCII control characters using ^X notation', function()
+ eq('^C', funcs.String(ctrl('c')))
+ eq('^A', funcs.String(ctrl('a')))
+ eq('^F', funcs.String(ctrl('f')))
+ end)
+ it('prints CR, NL and tab as-is', function()
+ eq('\n', funcs.String('\n'))
+ eq('\r', funcs.String('\r'))
+ eq('\t', funcs.String('\t'))
+ end)
+ it('prints non-printable UTF-8 in <> notation', function()
+ -- SINGLE SHIFT TWO, unicode control
+ eq('<8e>', funcs.String(funcs.nr2char(0x8E)))
+ -- Surrogate pair: U+1F0A0 PLAYING CARD BACK is represented in UTF-16 as
+ -- 0xD83C 0xDCA0. This is not valid in UTF-8.
+ eq('<d83c>', funcs.String(funcs.nr2char(0xD83C)))
+ eq('<dca0>', funcs.String(funcs.nr2char(0xDCA0)))
+ eq('<d83c><dca0>', funcs.String(funcs.nr2char(0xD83C) .. funcs.nr2char(0xDCA0)))
+ end)
+ end)
+end)
diff --git a/test/functional/ex_cmds/edit_spec.lua b/test/functional/ex_cmds/edit_spec.lua
index 3cc5f5fb95..6ed500a293 100644
--- a/test/functional/ex_cmds/edit_spec.lua
+++ b/test/functional/ex_cmds/edit_spec.lua
@@ -1,7 +1,8 @@
local helpers = require("test.functional.helpers")(after_each)
-local eq, execute, funcs = helpers.eq, helpers.execute, helpers.funcs
+local eq, command, funcs = helpers.eq, helpers.command, helpers.funcs
local ok = helpers.ok
local clear = helpers.clear
+local feed = helpers.feed
describe(":edit", function()
before_each(function()
@@ -9,13 +10,13 @@ describe(":edit", function()
end)
it("without arguments does not restart :terminal buffer", function()
- execute("terminal")
- helpers.feed([[<C-\><C-N>]])
+ command("terminal")
+ feed([[<C-\><C-N>]])
local bufname_before = funcs.bufname("%")
local bufnr_before = funcs.bufnr("%")
helpers.ok(nil ~= string.find(bufname_before, "^term://")) -- sanity
- execute("edit")
+ command("edit")
local bufname_after = funcs.bufname("%")
local bufnr_after = funcs.bufnr("%")
diff --git a/test/functional/ex_cmds/encoding_spec.lua b/test/functional/ex_cmds/encoding_spec.lua
index 87ed7a2d0a..7f2bd78a47 100644
--- a/test/functional/ex_cmds/encoding_spec.lua
+++ b/test/functional/ex_cmds/encoding_spec.lua
@@ -1,5 +1,5 @@
local helpers = require('test.functional.helpers')(after_each)
-local clear, execute, feed = helpers.clear, helpers.execute, helpers.feed
+local clear, feed_command, feed = helpers.clear, helpers.feed_command, helpers.feed
local eq, neq, eval = helpers.eq, helpers.neq, helpers.eval
describe('&encoding', function()
@@ -12,10 +12,10 @@ describe('&encoding', function()
end)
it('cannot be changed after setup', function()
- execute('set encoding=latin1')
+ feed_command('set encoding=latin1')
-- error message expected
feed('<cr>')
- neq(nil, string.find(eval('v:errmsg'), '^E474:'))
+ neq(nil, string.find(eval('v:errmsg'), '^E519:'))
eq('utf-8', eval('&encoding'))
-- check nvim is still in utf-8 mode
eq(3, eval('strwidth("Bär")'))
@@ -25,13 +25,13 @@ describe('&encoding', function()
clear('--cmd', 'set enc=latin1')
-- error message expected
feed('<cr>')
- neq(nil, string.find(eval('v:errmsg'), '^E474:'))
+ neq(nil, string.find(eval('v:errmsg'), '^E519:'))
eq('utf-8', eval('&encoding'))
eq(3, eval('strwidth("Bär")'))
end)
it('can be set to utf-8 without error', function()
- execute('set encoding=utf-8')
+ feed_command('set encoding=utf-8')
eq("", eval('v:errmsg'))
clear('--cmd', 'set enc=utf-8')
diff --git a/test/functional/ex_cmds/file_spec.lua b/test/functional/ex_cmds/file_spec.lua
new file mode 100644
index 0000000000..771c283134
--- /dev/null
+++ b/test/functional/ex_cmds/file_spec.lua
@@ -0,0 +1,35 @@
+local helpers = require('test.functional.helpers')(after_each)
+local lfs = require('lfs')
+local clear = helpers.clear
+local command = helpers.command
+local eq = helpers.eq
+local funcs = helpers.funcs
+local rmdir = helpers.rmdir
+
+describe(':file', function()
+ local swapdir = lfs.currentdir()..'/Xtest-file_spec'
+ before_each(function()
+ clear()
+ rmdir(swapdir)
+ lfs.mkdir(swapdir)
+ end)
+ after_each(function()
+ command('%bwipeout!')
+ rmdir(swapdir)
+ end)
+
+ it("rename does not lose swapfile #6487", function()
+ local testfile = 'test-file_spec'
+ local testfile_renamed = testfile..'-renamed'
+ -- Note: `set swapfile` *must* go after `set directory`: otherwise it may
+ -- attempt to create a swapfile in different directory.
+ command('set directory^='..swapdir..'//')
+ command('set swapfile fileformat=unix undolevels=-1')
+
+ command('edit! '..testfile)
+ -- Before #6487 this gave "E301: Oops, lost the swap file !!!" on Windows.
+ command('file '..testfile_renamed)
+ eq(testfile_renamed..'.swp',
+ string.match(funcs.execute('swapname'), '[^%%]+$'))
+ end)
+end)
diff --git a/test/functional/ex_cmds/grep_spec.lua b/test/functional/ex_cmds/grep_spec.lua
index 13f88b7e03..43ef1bd424 100644
--- a/test/functional/ex_cmds/grep_spec.lua
+++ b/test/functional/ex_cmds/grep_spec.lua
@@ -1,6 +1,6 @@
local helpers = require('test.functional.helpers')(after_each)
-local clear, execute, feed, ok, eval =
- helpers.clear, helpers.execute, helpers.feed, helpers.ok, helpers.eval
+local clear, feed_command, feed, ok, eval =
+ helpers.clear, helpers.feed_command, helpers.feed, helpers.ok, helpers.eval
describe(':grep', function()
before_each(clear)
@@ -11,10 +11,10 @@ describe(':grep', function()
return
end
- execute([[set grepprg=grep\ -r]])
+ feed_command([[set grepprg=grep\ -r]])
-- Change to test directory so that the test does not run too long.
- execute('cd test')
- execute('grep a **/*')
+ feed_command('cd test')
+ feed_command('grep a **/*')
feed('<cr>') -- Press ENTER
ok(eval('len(getqflist())') > 9000) -- IT'S OVER 9000!!1
end)
diff --git a/test/functional/ex_cmds/highlight_spec.lua b/test/functional/ex_cmds/highlight_spec.lua
new file mode 100644
index 0000000000..25968b8204
--- /dev/null
+++ b/test/functional/ex_cmds/highlight_spec.lua
@@ -0,0 +1,43 @@
+local Screen = require('test.functional.ui.screen')
+local helpers = require("test.functional.helpers")(after_each)
+local eq, command = helpers.eq, helpers.command
+local clear = helpers.clear
+local eval, exc_exec = helpers.eval, helpers.exc_exec
+
+describe(':highlight', function()
+ local screen
+
+ before_each(function()
+ clear()
+ screen = Screen.new()
+ screen:attach()
+ end)
+
+ after_each(function()
+ screen:detach()
+ end)
+
+ it('invalid color name', function()
+ eq('Vim(highlight):E421: Color name or number not recognized: ctermfg=#181818',
+ exc_exec("highlight normal ctermfg=#181818"))
+ eq('Vim(highlight):E421: Color name or number not recognized: ctermbg=#181818',
+ exc_exec("highlight normal ctermbg=#181818"))
+ end)
+
+ it('invalid group name', function()
+ eq('Vim(highlight):E411: highlight group not found: foo',
+ exc_exec("highlight foo"))
+ end)
+
+ it('"Normal" foreground with red', function()
+ eq('', eval('synIDattr(hlID("Normal"), "fg", "cterm")'))
+ command('highlight normal ctermfg=red')
+ eq('9', eval('synIDattr(hlID("Normal"), "fg", "cterm")'))
+ end)
+
+ it('"Normal" background with red', function()
+ eq('', eval('synIDattr(hlID("Normal"), "bg", "cterm")'))
+ command('highlight normal ctermbg=red')
+ eq('9', eval('synIDattr(hlID("Normal"), "bg", "cterm")'))
+ end)
+end)
diff --git a/test/functional/ex_cmds/menu_spec.lua b/test/functional/ex_cmds/menu_spec.lua
index 52df9e1592..2c0535acda 100644
--- a/test/functional/ex_cmds/menu_spec.lua
+++ b/test/functional/ex_cmds/menu_spec.lua
@@ -1,23 +1,25 @@
local helpers = require('test.functional.helpers')(after_each)
-local clear, execute, nvim = helpers.clear, helpers.execute, helpers.nvim
-local expect, feed, command = helpers.expect, helpers.feed, helpers.command
+local clear, command, nvim = helpers.clear, helpers.command, helpers.nvim
+local expect, feed = helpers.expect, helpers.feed
local eq, eval = helpers.eq, helpers.eval
+local funcs = helpers.funcs
+
describe(':emenu', function()
before_each(function()
clear()
- execute('nnoremenu Test.Test inormal<ESC>')
- execute('inoremenu Test.Test insert')
- execute('vnoremenu Test.Test x')
- execute('cnoremenu Test.Test cmdmode')
+ command('nnoremenu Test.Test inormal<ESC>')
+ command('inoremenu Test.Test insert')
+ command('vnoremenu Test.Test x')
+ command('cnoremenu Test.Test cmdmode')
- execute('nnoremenu Edit.Paste p')
- execute('cnoremenu Edit.Paste <C-R>"')
+ command('nnoremenu Edit.Paste p')
+ command('cnoremenu Edit.Paste <C-R>"')
end)
it('executes correct bindings in normal mode without using API', function()
- execute('emenu Test.Test')
+ command('emenu Test.Test')
expect('normal')
end)
@@ -56,3 +58,572 @@ describe(':emenu', function()
eq('thiscmdmode', eval('getcmdline()'))
end)
end)
+
+describe('menu_get', function()
+
+ before_each(function()
+ clear()
+ command('nnoremenu &Test.Test inormal<ESC>')
+ command('inoremenu Test.Test insert')
+ command('vnoremenu Test.Test x')
+ command('cnoremenu Test.Test cmdmode')
+ command('menu Test.Nested.test level1')
+ command('menu Test.Nested.Nested2 level2')
+
+ command('nnoremenu <script> Export.Script p')
+ command('tmenu Export.Script This is the tooltip')
+ command('menu ]Export.hidden thisoneshouldbehidden')
+
+ command('nnoremenu Edit.Paste p')
+ command('cnoremenu Edit.Paste <C-R>"')
+ end)
+
+ it("path='', modes='a'", function()
+ local m = funcs.menu_get("","a");
+ -- HINT: To print the expected table and regenerate the tests:
+ -- print(require('pl.pretty').dump(m))
+ local expected = {
+ {
+ shortcut = "T",
+ hidden = 0,
+ submenus = {
+ {
+ mappings = {
+ i = {
+ sid = 1,
+ noremap = 1,
+ enabled = 1,
+ rhs = "insert",
+ silent = 0
+ },
+ s = {
+ sid = 1,
+ noremap = 1,
+ enabled = 1,
+ rhs = "x",
+ silent = 0
+ },
+ n = {
+ sid = 1,
+ noremap = 1,
+ enabled = 1,
+ rhs = "inormal<Esc>",
+ silent = 0
+ },
+ v = {
+ sid = 1,
+ noremap = 1,
+ enabled = 1,
+ rhs = "x",
+ silent = 0
+ },
+ c = {
+ sid = 1,
+ noremap = 1,
+ enabled = 1,
+ rhs = "cmdmode",
+ silent = 0
+ }
+ },
+ priority = 500,
+ name = "Test",
+ hidden = 0
+ },
+ {
+ priority = 500,
+ name = "Nested",
+ submenus = {
+ {
+ mappings = {
+ o = {
+ sid = 0,
+ noremap = 0,
+ enabled = 1,
+ rhs = "level1",
+ silent = 0
+ },
+ v = {
+ sid = 0,
+ noremap = 0,
+ enabled = 1,
+ rhs = "level1",
+ silent = 0
+ },
+ s = {
+ sid = 0,
+ noremap = 0,
+ enabled = 1,
+ rhs = "level1",
+ silent = 0
+ },
+ n = {
+ sid = 0,
+ noremap = 0,
+ enabled = 1,
+ rhs = "level1",
+ silent = 0
+ }
+ },
+ priority = 500,
+ name = "test",
+ hidden = 0
+ },
+ {
+ mappings = {
+ o = {
+ sid = 0,
+ noremap = 0,
+ enabled = 1,
+ rhs = "level2",
+ silent = 0
+ },
+ v = {
+ sid = 0,
+ noremap = 0,
+ enabled = 1,
+ rhs = "level2",
+ silent = 0
+ },
+ s = {
+ sid = 0,
+ noremap = 0,
+ enabled = 1,
+ rhs = "level2",
+ silent = 0
+ },
+ n = {
+ sid = 0,
+ noremap = 0,
+ enabled = 1,
+ rhs = "level2",
+ silent = 0
+ }
+ },
+ priority = 500,
+ name = "Nested2",
+ hidden = 0
+ }
+ },
+ hidden = 0
+ }
+ },
+ priority = 500,
+ name = "Test"
+ },
+ {
+ priority = 500,
+ name = "Export",
+ submenus = {
+ {
+ tooltip = "This is the tooltip",
+ hidden = 0,
+ name = "Script",
+ priority = 500,
+ mappings = {
+ n = {
+ sid = 1,
+ noremap = 1,
+ enabled = 1,
+ rhs = "p",
+ silent = 0
+ }
+ }
+ }
+ },
+ hidden = 0
+ },
+ {
+ priority = 500,
+ name = "Edit",
+ submenus = {
+ {
+ mappings = {
+ c = {
+ sid = 1,
+ noremap = 1,
+ enabled = 1,
+ rhs = "<C-R>\"",
+ silent = 0
+ },
+ n = {
+ sid = 1,
+ noremap = 1,
+ enabled = 1,
+ rhs = "p",
+ silent = 0
+ }
+ },
+ priority = 500,
+ name = "Paste",
+ hidden = 0
+ }
+ },
+ hidden = 0
+ },
+ {
+ priority = 500,
+ name = "]Export",
+ submenus = {
+ {
+ mappings = {
+ o = {
+ sid = 0,
+ noremap = 0,
+ enabled = 1,
+ rhs = "thisoneshouldbehidden",
+ silent = 0
+ },
+ v = {
+ sid = 0,
+ noremap = 0,
+ enabled = 1,
+ rhs = "thisoneshouldbehidden",
+ silent = 0
+ },
+ s = {
+ sid = 0,
+ noremap = 0,
+ enabled = 1,
+ rhs = "thisoneshouldbehidden",
+ silent = 0
+ },
+ n = {
+ sid = 0,
+ noremap = 0,
+ enabled = 1,
+ rhs = "thisoneshouldbehidden",
+ silent = 0
+ }
+ },
+ priority = 500,
+ name = "hidden",
+ hidden = 0
+ }
+ },
+ hidden = 1
+ }
+ }
+ eq(expected, m)
+ end)
+
+ it('matching path, default modes', function()
+ local m = funcs.menu_get("Export", "a")
+ local expected = {
+ {
+ tooltip = "This is the tooltip",
+ hidden = 0,
+ name = "Script",
+ priority = 500,
+ mappings = {
+ n = {
+ sid = 1,
+ noremap = 1,
+ enabled = 1,
+ rhs = "p",
+ silent = 0
+ }
+ }
+ }
+ }
+ eq(expected, m)
+ end)
+
+ it('no path, matching modes', function()
+ local m = funcs.menu_get("","i")
+ local expected = {
+ {
+ shortcut = "T",
+ hidden = 0,
+ submenus = {
+ {
+ mappings = {
+ i = {
+ sid = 1,
+ noremap = 1,
+ enabled = 1,
+ rhs = "insert",
+ silent = 0
+ }
+ },
+ priority = 500,
+ name = "Test",
+ hidden = 0
+ },
+ {
+ }
+ },
+ priority = 500,
+ name = "Test"
+ }
+ }
+ eq(expected, m)
+ end)
+
+ it('matching path and modes', function()
+ local m = funcs.menu_get("Test","i")
+ local expected = {
+ {
+ mappings = {
+ i = {
+ sid = 1,
+ noremap = 1,
+ enabled = 1,
+ rhs = "insert",
+ silent = 0
+ }
+ },
+ priority = 500,
+ name = "Test",
+ hidden = 0
+ }
+ }
+ eq(expected, m)
+ end)
+end)
+
+describe('menu_get', function()
+
+ before_each(function()
+ clear()
+ end)
+
+ it('returns <keycode> representation of special keys', function()
+ command('nnoremenu &Test.Test inormal<ESC>')
+ command('inoremenu &Test.Test2 <Tab><Esc>')
+ command('vnoremenu &Test.Test3 yA<C-R>0<Tab>xyz<Esc>')
+ command('inoremenu &Test.Test4 <c-r>*')
+ command('inoremenu &Test.Test5 <c-R>+')
+ command('nnoremenu &Test.Test6 <Nop>')
+ command('nnoremenu &Test.Test7 <NOP>')
+ command('nnoremenu &Test.Test8 <NoP>')
+ command('nnoremenu &Test.Test9 ""')
+
+ local m = funcs.menu_get("");
+ local expected = {
+ {
+ shortcut = "T",
+ hidden = 0,
+ submenus = {
+ {
+ priority = 500,
+ mappings = {
+ n = {
+ sid = 1,
+ noremap = 1,
+ enabled = 1,
+ rhs = "inormal<Esc>",
+ silent = 0
+ }
+ },
+ name = "Test",
+ hidden = 0
+ },
+ {
+ priority = 500,
+ mappings = {
+ i = {
+ sid = 1,
+ noremap = 1,
+ enabled = 1,
+ rhs = "<Tab><Esc>",
+ silent = 0
+ }
+ },
+ name = "Test2",
+ hidden = 0
+ },
+ {
+ priority = 500,
+ mappings = {
+ s = {
+ sid = 1,
+ noremap = 1,
+ enabled = 1,
+ rhs = "yA<C-R>0<Tab>xyz<Esc>",
+ silent = 0
+ },
+ v = {
+ sid = 1,
+ noremap = 1,
+ enabled = 1,
+ rhs = "yA<C-R>0<Tab>xyz<Esc>",
+ silent = 0
+ }
+ },
+ name = "Test3",
+ hidden = 0
+ },
+ {
+ priority = 500,
+ mappings = {
+ i = {
+ sid = 1,
+ noremap = 1,
+ enabled = 1,
+ rhs = "<C-R>*",
+ silent = 0
+ }
+ },
+ name = "Test4",
+ hidden = 0
+ },
+ {
+ priority = 500,
+ mappings = {
+ i = {
+ sid = 1,
+ noremap = 1,
+ enabled = 1,
+ rhs = "<C-R>+",
+ silent = 0
+ }
+ },
+ name = "Test5",
+ hidden = 0
+ },
+ {
+ priority = 500,
+ mappings = {
+ n = {
+ sid = 1,
+ noremap = 1,
+ enabled = 1,
+ rhs = "",
+ silent = 0
+ }
+ },
+ name = "Test6",
+ hidden = 0
+ },
+ {
+ priority = 500,
+ mappings = {
+ n = {
+ sid = 1,
+ noremap = 1,
+ enabled = 1,
+ rhs = "",
+ silent = 0
+ }
+ },
+ name = "Test7",
+ hidden = 0
+ },
+ {
+ priority = 500,
+ mappings = {
+ n = {
+ sid = 1,
+ noremap = 1,
+ enabled = 1,
+ rhs = "",
+ silent = 0
+ }
+ },
+ name = "Test8",
+ hidden = 0
+ },
+ {
+ priority = 500,
+ mappings = {
+ n = {
+ sid = 1,
+ noremap = 1,
+ enabled = 1,
+ rhs = "\"\"",
+ silent = 0
+ }
+ },
+ name = "Test9",
+ hidden = 0
+ }
+ },
+ priority = 500,
+ name = "Test"
+ }
+ }
+
+ eq(m, expected)
+ end)
+
+ it('works with right-aligned text and spaces', function()
+ command('nnoremenu &Test<Tab>Y.Test<Tab>X\\ x inormal<Alt-j>')
+ command('nnoremenu &Test\\ 1.Test\\ 2 Wargl')
+ command('nnoremenu &Test4.Test<Tab>3 i space<Esc>')
+
+ local m = funcs.menu_get("");
+ local expected = {
+ {
+ shortcut = "T",
+ hidden = 0,
+ actext = "Y",
+ submenus = {
+ {
+ mappings = {
+ n = {
+ sid = 1,
+ noremap = 1,
+ enabled = 1,
+ rhs = "inormal<Alt-j>",
+ silent = 0
+ }
+ },
+ hidden = 0,
+ actext = "X x",
+ priority = 500,
+ name = "Test"
+ }
+ },
+ priority = 500,
+ name = "Test"
+ },
+ {
+ shortcut = "T",
+ hidden = 0,
+ submenus = {
+ {
+ priority = 500,
+ mappings = {
+ n = {
+ sid = 1,
+ noremap = 1,
+ enabled = 1,
+ rhs = "Wargl",
+ silent = 0
+ }
+ },
+ name = "Test 2",
+ hidden = 0
+ }
+ },
+ priority = 500,
+ name = "Test 1"
+ },
+ {
+ shortcut = "T",
+ hidden = 0,
+ submenus = {
+ {
+ mappings = {
+ n = {
+ sid = 1,
+ noremap = 1,
+ enabled = 1,
+ rhs = "i space<Esc>",
+ silent = 0
+ }
+ },
+ hidden = 0,
+ actext = "3",
+ priority = 500,
+ name = "Test"
+ }
+ },
+ priority = 500,
+ name = "Test4"
+ }
+ }
+
+ eq(m, expected)
+ end)
+end)
diff --git a/test/functional/ex_cmds/mksession_spec.lua b/test/functional/ex_cmds/mksession_spec.lua
new file mode 100644
index 0000000000..5d658f10bb
--- /dev/null
+++ b/test/functional/ex_cmds/mksession_spec.lua
@@ -0,0 +1,49 @@
+local lfs = require('lfs')
+local helpers = require('test.functional.helpers')(after_each)
+
+local clear = helpers.clear
+local command = helpers.command
+local get_pathsep = helpers.get_pathsep
+local eq = helpers.eq
+local funcs = helpers.funcs
+
+local file_prefix = 'Xtest-functional-ex_cmds-mksession_spec'
+
+describe(':mksession', function()
+ local session_file = file_prefix .. '.vim'
+ local tab_dir = file_prefix .. '.d'
+
+ before_each(function()
+ clear()
+ lfs.mkdir(tab_dir)
+ end)
+
+ after_each(function()
+ os.remove(session_file)
+ lfs.rmdir(tab_dir)
+ end)
+
+ it('restores tab-local working directories', function()
+ local tmpfile_base = file_prefix .. '-tmpfile'
+ local cwd_dir = funcs.getcwd()
+
+ -- :mksession does not save empty tabs, so create some buffers.
+ command('edit ' .. tmpfile_base .. '1')
+ command('tabnew')
+ command('edit ' .. tmpfile_base .. '2')
+ command('tcd ' .. tab_dir)
+ command('tabfirst')
+ command('mksession ' .. session_file)
+
+ -- Create a new test instance of Nvim.
+ clear()
+
+ command('source ' .. session_file)
+ -- First tab should have the original working directory.
+ command('tabnext 1')
+ eq(cwd_dir, funcs.getcwd())
+ -- Second tab should have the tab-local working directory.
+ command('tabnext 2')
+ eq(cwd_dir .. get_pathsep() .. tab_dir, funcs.getcwd())
+ end)
+end)
diff --git a/test/functional/ex_cmds/mkview_spec.lua b/test/functional/ex_cmds/mkview_spec.lua
new file mode 100644
index 0000000000..97a49dbbd5
--- /dev/null
+++ b/test/functional/ex_cmds/mkview_spec.lua
@@ -0,0 +1,67 @@
+local lfs = require('lfs')
+local helpers = require('test.functional.helpers')(after_each)
+
+local clear = helpers.clear
+local command = helpers.command
+local get_pathsep = helpers.get_pathsep
+local eq = helpers.eq
+local funcs = helpers.funcs
+local rmdir = helpers.rmdir
+
+local file_prefix = 'Xtest-functional-ex_cmds-mkview_spec'
+
+describe(':mkview', function()
+ local tmp_file_base = file_prefix .. '-tmpfile'
+ local local_dir = file_prefix .. '.d'
+ local view_dir = file_prefix .. '.view.d'
+
+ before_each(function()
+ clear()
+ lfs.mkdir(view_dir)
+ lfs.mkdir(local_dir)
+ end)
+
+ after_each(function()
+ -- Remove any views created in the view directory
+ rmdir(view_dir)
+ lfs.rmdir(local_dir)
+ end)
+
+ it('viewoption curdir restores local current directory', function()
+ local cwd_dir = funcs.getcwd()
+ local set_view_dir_command = 'set viewdir=' .. cwd_dir ..
+ get_pathsep() .. view_dir
+
+ -- By default the local current directory should save
+ command(set_view_dir_command)
+ command('edit ' .. tmp_file_base .. '1')
+ command('lcd ' .. local_dir)
+ command('mkview')
+
+ -- Create a new instance of Nvim to remove the 'lcd'
+ clear()
+
+ -- Disable saving the local current directory for the second view
+ command(set_view_dir_command)
+ command('set viewoptions-=curdir')
+ command('edit ' .. tmp_file_base .. '2')
+ command('lcd ' .. local_dir)
+ command('mkview')
+
+ -- Create a new instance of Nvim to test saved 'lcd' option
+ clear()
+ command(set_view_dir_command)
+
+ -- Load the view without a saved local current directory
+ command('edit ' .. tmp_file_base .. '2')
+ command('loadview')
+ -- The view's current directory should not have changed
+ eq(cwd_dir, funcs.getcwd())
+ -- Load the view with a saved local current directory
+ command('edit ' .. tmp_file_base .. '1')
+ command('loadview')
+ -- The view's local directory should have been saved
+ eq(cwd_dir .. get_pathsep() .. local_dir, funcs.getcwd())
+ end)
+
+end)
diff --git a/test/functional/ex_cmds/oldfiles_spec.lua b/test/functional/ex_cmds/oldfiles_spec.lua
index a161e49fc6..4002855c24 100644
--- a/test/functional/ex_cmds/oldfiles_spec.lua
+++ b/test/functional/ex_cmds/oldfiles_spec.lua
@@ -1,16 +1,18 @@
local Screen = require('test.functional.ui.screen')
local helpers = require('test.functional.helpers')(after_each)
-local buf, eq, execute = helpers.curbufmeths, helpers.eq, helpers.execute
+local buf, eq, feed_command = helpers.curbufmeths, helpers.eq, helpers.feed_command
local feed, nvim_prog, wait = helpers.feed, helpers.nvim_prog, helpers.wait
local ok, set_session, spawn = helpers.ok, helpers.set_session, helpers.spawn
+local eval = helpers.eval
-local shada_file = 'test.shada'
+local shada_file = 'Xtest.shada'
local function _clear()
- set_session(spawn({nvim_prog, '--embed', '-u', 'NONE', '--cmd',
+ set_session(spawn({nvim_prog, '--embed', '-u', 'NONE',
-- Need shada for these tests.
- 'set noswapfile undodir=. directory=. viewdir=. backupdir=. belloff= noshowcmd noruler'}))
+ '-i', shada_file,
+ '--cmd', 'set noswapfile undodir=. directory=. viewdir=. backupdir=. belloff= noshowcmd noruler'}))
end
describe(':oldfiles', function()
@@ -27,12 +29,12 @@ describe(':oldfiles', function()
it('shows most recently used files', function()
local screen = Screen.new(100, 5)
screen:attach()
- execute('edit testfile1')
- execute('edit testfile2')
- execute('wshada ' .. shada_file)
- execute('rshada! ' .. shada_file)
+ feed_command('edit testfile1')
+ feed_command('edit testfile2')
+ feed_command('wshada')
+ feed_command('rshada!')
local oldfiles = helpers.meths.get_vvar('oldfiles')
- execute('oldfiles')
+ feed_command('oldfiles')
screen:expect([[
testfile2 |
1: ]].. add_padding(oldfiles[1]) ..[[ |
@@ -41,6 +43,38 @@ describe(':oldfiles', function()
Press ENTER or type command to continue^ |
]])
end)
+
+ it('can be filtered with :filter', function()
+ feed_command('edit file_one.txt')
+ local file1 = buf.get_name()
+ feed_command('edit file_two.txt')
+ local file2 = buf.get_name()
+ feed_command('edit another.txt')
+ local another = buf.get_name()
+ feed_command('wshada')
+ feed_command('rshada!')
+
+ local function get_oldfiles(cmd)
+ local t = eval([[split(execute(']]..cmd..[['), "\n")]])
+ for i, _ in ipairs(t) do
+ t[i] = t[i]:gsub('^%d+:%s+', '')
+ end
+ table.sort(t)
+ return t
+ end
+
+ local oldfiles = get_oldfiles('oldfiles')
+ eq({another, file1, file2}, oldfiles)
+
+ oldfiles = get_oldfiles('filter file_ oldfiles')
+ eq({file1, file2}, oldfiles)
+
+ oldfiles = get_oldfiles('filter /another/ oldfiles')
+ eq({another}, oldfiles)
+
+ oldfiles = get_oldfiles('filter! file_ oldfiles')
+ eq({another}, oldfiles)
+ end)
end)
describe(':browse oldfiles', function()
@@ -50,14 +84,13 @@ describe(':browse oldfiles', function()
before_each(function()
_clear()
- execute('edit testfile1')
+ feed_command('edit testfile1')
filename = buf.get_name()
- execute('edit testfile2')
+ feed_command('edit testfile2')
filename2 = buf.get_name()
- execute('wshada ' .. shada_file)
+ feed_command('wshada')
wait()
_clear()
- execute('rshada! ' .. shada_file)
-- Ensure nvim is out of "Press ENTER..." prompt.
feed('<cr>')
@@ -70,7 +103,7 @@ describe(':browse oldfiles', function()
ok(filename == oldfiles[1] or filename == oldfiles[2])
ok(filename2 == oldfiles[1] or filename2 == oldfiles[2])
- execute('browse oldfiles')
+ feed_command('browse oldfiles')
end)
after_each(function()
diff --git a/test/functional/ex_cmds/print_commands_spec.lua b/test/functional/ex_cmds/print_commands_spec.lua
new file mode 100644
index 0000000000..98c0f74635
--- /dev/null
+++ b/test/functional/ex_cmds/print_commands_spec.lua
@@ -0,0 +1,12 @@
+local helpers = require('test.functional.helpers')(after_each)
+local clear, eq, command, funcs =
+ helpers.clear, helpers.eq, helpers.command, helpers.funcs
+
+describe(':z^', function()
+ before_each(clear)
+
+ it('correctly sets the cursor after :z^', function()
+ command('z^')
+ eq(1, funcs.line('.'))
+ end)
+end)
diff --git a/test/functional/ex_cmds/quickfix_commands_spec.lua b/test/functional/ex_cmds/quickfix_commands_spec.lua
new file mode 100644
index 0000000000..bf10f80401
--- /dev/null
+++ b/test/functional/ex_cmds/quickfix_commands_spec.lua
@@ -0,0 +1,111 @@
+local helpers = require('test.functional.helpers')(after_each)
+
+local eq = helpers.eq
+local clear = helpers.clear
+local funcs = helpers.funcs
+local command = helpers.command
+local exc_exec = helpers.exc_exec
+local write_file = helpers.write_file
+local curbufmeths = helpers.curbufmeths
+local source = helpers.source
+
+local file_base = 'Xtest-functional-ex_cmds-quickfix_commands'
+
+before_each(clear)
+
+for _, c in ipairs({'l', 'c'}) do
+ local file = ('%s.%s'):format(file_base, c)
+ local filecmd = c .. 'file'
+ local getfcmd = c .. 'getfile'
+ local addfcmd = c .. 'addfile'
+ local getlist = (c == 'c') and funcs.getqflist or (
+ function() return funcs.getloclist(0) end)
+
+ describe((':%s*file commands'):format(c), function()
+ before_each(function()
+ write_file(file, ([[
+ %s-1.res:700:10:Line 700
+ %s-2.res:800:15:Line 800
+ ]]):format(file, file))
+ end)
+ after_each(function()
+ os.remove(file)
+ end)
+
+ it('work', function()
+ command(('%s %s'):format(filecmd, file))
+ -- Second line of each entry (i.e. `nr=-1, …`) was obtained from actual
+ -- results. First line (i.e. `{lnum=…`) was obtained from legacy test.
+ local list = {
+ {lnum=700, col=10, text='Line 700',
+ nr=-1, bufnr=2, valid=1, pattern='', vcol=0, ['type']=''},
+ {lnum=800, col=15, text='Line 800',
+ nr=-1, bufnr=3, valid=1, pattern='', vcol=0, ['type']=''},
+ }
+ eq(list, getlist())
+ eq(('%s-1.res'):format(file), funcs.bufname(list[1].bufnr))
+ eq(('%s-2.res'):format(file), funcs.bufname(list[2].bufnr))
+
+ -- Run cfile/lfile from a modified buffer
+ command('enew!')
+ curbufmeths.set_lines(1, 1, true, {'Quickfix'})
+ eq(('Vim(%s):E37: No write since last change (add ! to override)'):format(
+ filecmd),
+ exc_exec(('%s %s'):format(filecmd, file)))
+
+ write_file(file, ([[
+ %s-3.res:900:30:Line 900
+ ]]):format(file))
+ command(('%s %s'):format(addfcmd, file))
+ list[#list + 1] = {
+ lnum=900, col=30, text='Line 900',
+ nr=-1, bufnr=5, valid=1, pattern='', vcol=0, ['type']='',
+ }
+ eq(list, getlist())
+ eq(('%s-3.res'):format(file), funcs.bufname(list[3].bufnr))
+
+ write_file(file, ([[
+ %s-1.res:222:77:Line 222
+ %s-2.res:333:88:Line 333
+ ]]):format(file, file))
+ command('enew!')
+ command(('%s %s'):format(getfcmd, file))
+ list = {
+ {lnum=222, col=77, text='Line 222',
+ nr=-1, bufnr=2, valid=1, pattern='', vcol=0, ['type']=''},
+ {lnum=333, col=88, text='Line 333',
+ nr=-1, bufnr=3, valid=1, pattern='', vcol=0, ['type']=''},
+ }
+ eq(list, getlist())
+ eq(('%s-1.res'):format(file), funcs.bufname(list[1].bufnr))
+ eq(('%s-2.res'):format(file), funcs.bufname(list[2].bufnr))
+ end)
+ end)
+end
+
+describe('quickfix', function()
+ it('location-list update on buffer modification', function()
+ source([[
+ new
+ setl bt=nofile
+ let lines = ['Line 1', 'Line 2', 'Line 3', 'Line 4', 'Line 5']
+ call append(0, lines)
+ new
+ setl bt=nofile
+ call append(0, lines)
+ let qf_item = {
+ \ 'lnum': 4,
+ \ 'text': "This is the error line.",
+ \ }
+ let qf_item['bufnr'] = bufnr('%')
+ call setloclist(0, [qf_item])
+ wincmd p
+ let qf_item['bufnr'] = bufnr('%')
+ call setloclist(0, [qf_item])
+ 1del _
+ call append(0, ['New line 1', 'New line 2', 'New line 3'])
+ silent ll
+ ]])
+ eq({0, 6, 1, 0, 1}, funcs.getcurpos())
+ end)
+end)
diff --git a/test/functional/ex_cmds/recover_spec.lua b/test/functional/ex_cmds/recover_spec.lua
index af1296c94c..cb68c29b9a 100644
--- a/test/functional/ex_cmds/recover_spec.lua
+++ b/test/functional/ex_cmds/recover_spec.lua
@@ -1,19 +1,18 @@
--- Tests for :recover
-
local helpers = require('test.functional.helpers')(after_each)
local lfs = require('lfs')
-local execute, eq, clear, eval, feed, expect, source =
- helpers.execute, helpers.eq, helpers.clear, helpers.eval, helpers.feed,
+local feed_command, eq, clear, eval, feed, expect, source =
+ helpers.feed_command, helpers.eq, helpers.clear, helpers.eval, helpers.feed,
helpers.expect, helpers.source
-
-if helpers.pending_win32(pending) then return end
+local command = helpers.command
+local ok = helpers.ok
+local rmdir = helpers.rmdir
describe(':recover', function()
before_each(clear)
it('fails if given a non-existent swapfile', function()
local swapname = 'bogus-swapfile'
- execute('recover '..swapname) -- This should not segfault. #2117
+ feed_command('recover '..swapname) -- This should not segfault. #2117
eq('E305: No swap file found for '..swapname, eval('v:errmsg'))
end)
@@ -23,30 +22,29 @@ describe(':preserve', function()
local swapdir = lfs.currentdir()..'/testdir_recover_spec'
before_each(function()
clear()
- helpers.rmdir(swapdir)
+ rmdir(swapdir)
lfs.mkdir(swapdir)
end)
after_each(function()
- helpers.rmdir(swapdir)
+ command('%bwipeout!')
+ rmdir(swapdir)
end)
it("saves to custom 'directory' and (R)ecovers (issue #1836)", function()
local testfile = 'testfile_recover_spec'
+ -- Put swapdir at the start of the 'directory' list. #1836
-- Note: `set swapfile` *must* go after `set directory`: otherwise it may
-- attempt to create a swapfile in different directory.
local init = [[
- set directory^=]]..swapdir..[[//
+ set directory^=]]..swapdir:gsub([[\]], [[\\]])..[[//
set swapfile fileformat=unix undolevels=-1
]]
source(init)
- execute('set swapfile fileformat=unix undolevels=-1')
- -- Put swapdir at the start of the 'directory' list. #1836
- execute('set directory^='..swapdir..'//')
- execute('edit '..testfile)
+ command('edit! '..testfile)
feed('isometext<esc>')
- execute('preserve')
- source('redir => g:swapname | swapname | redir END')
+ command('preserve')
+ source('redir => g:swapname | silent swapname | redir END')
local swappath1 = eval('g:swapname')
@@ -59,19 +57,20 @@ describe(':preserve', function()
source(init)
-- Use the "SwapExists" event to choose the (R)ecover choice at the dialog.
- execute('autocmd SwapExists * let v:swapchoice = "r"')
- execute('silent edit '..testfile)
- source('redir => g:swapname | swapname | redir END')
+ command('autocmd SwapExists * let v:swapchoice = "r"')
+ command('silent edit! '..testfile)
+ source('redir => g:swapname | silent swapname | redir END')
local swappath2 = eval('g:swapname')
+ expect('sometext')
-- swapfile from session 1 should end in .swp
- assert(testfile..'.swp' == string.match(swappath1, '[^%%]+$'))
-
+ eq(testfile..'.swp', string.match(swappath1, '[^%%]+$'))
-- swapfile from session 2 should end in .swo
- assert(testfile..'.swo' == string.match(swappath2, '[^%%]+$'))
-
- expect('sometext')
+ eq(testfile..'.swo', string.match(swappath2, '[^%%]+$'))
+ -- Verify that :swapname was not truncated (:help 'shortmess').
+ ok(nil == string.find(swappath1, '%.%.%.'))
+ ok(nil == string.find(swappath2, '%.%.%.'))
end)
end)
diff --git a/test/functional/ex_cmds/script_spec.lua b/test/functional/ex_cmds/script_spec.lua
new file mode 100644
index 0000000000..4e57d2755d
--- /dev/null
+++ b/test/functional/ex_cmds/script_spec.lua
@@ -0,0 +1,75 @@
+local helpers = require('test.functional.helpers')(after_each)
+
+local eq = helpers.eq
+local neq = helpers.neq
+local meths = helpers.meths
+local clear = helpers.clear
+local dedent = helpers.dedent
+local source = helpers.source
+local exc_exec = helpers.exc_exec
+local missing_provider = helpers.missing_provider
+
+before_each(clear)
+
+describe('script_get-based command', function()
+ local garbage = ')}{+*({}]*[;(+}{&[]}{*])('
+
+ local function test_garbage_exec(cmd, check_neq)
+ describe(cmd, function()
+ it('works correctly when skipping oneline variant', function()
+ eq(true, pcall(source, (dedent([[
+ if 0
+ %s %s
+ endif
+ ]])):format(cmd, garbage)))
+ eq('', meths.command_output('messages'))
+ if check_neq then
+ neq(0, exc_exec(dedent([[
+ %s %s
+ ]])):format(cmd, garbage))
+ end
+ end)
+ it('works correctly when skipping HEREdoc variant', function()
+ eq(true, pcall(source, (dedent([[
+ if 0
+ %s << EOF
+ %s
+ EOF
+ endif
+ ]])):format(cmd, garbage)))
+ eq('', meths.command_output('messages'))
+ if check_neq then
+ eq(true, pcall(source, (dedent([[
+ let g:exc = 0
+ try
+ %s << EOF
+ %s
+ EOF
+ catch
+ let g:exc = v:exception
+ endtry
+ ]])):format(cmd, garbage)))
+ neq(0, meths.get_var('exc'))
+ end
+ end)
+ end)
+ end
+
+ clear()
+
+ -- Built-in scripts
+ test_garbage_exec('lua', true)
+
+ -- Provider-based scripts
+ test_garbage_exec('ruby', not missing_provider('ruby'))
+ test_garbage_exec('python', not missing_provider('python'))
+ test_garbage_exec('python3', not missing_provider('python3'))
+
+ -- Missing scripts
+ test_garbage_exec('tcl', false)
+ test_garbage_exec('mzscheme', false)
+ test_garbage_exec('perl', false)
+
+ -- Not really a script
+ test_garbage_exec('xxxinvalidlanguagexxx', true)
+end)
diff --git a/test/functional/ex_cmds/syntax_spec.lua b/test/functional/ex_cmds/syntax_spec.lua
new file mode 100644
index 0000000000..c9e96703de
--- /dev/null
+++ b/test/functional/ex_cmds/syntax_spec.lua
@@ -0,0 +1,17 @@
+local helpers = require('test.functional.helpers')(after_each)
+
+local eq = helpers.eq
+local clear = helpers.clear
+local exc_exec = helpers.exc_exec
+
+describe(':syntax', function()
+ before_each(clear)
+
+ describe('keyword', function()
+ it('does not crash when group name contains unprintable characters',
+ function()
+ eq('Vim(syntax):E669: Unprintable character in group name',
+ exc_exec('syntax keyword \024 foo bar'))
+ end)
+ end)
+end)
diff --git a/test/functional/ex_cmds/undojoin_spec.lua b/test/functional/ex_cmds/undojoin_spec.lua
index ba1e46ceb3..7803906619 100644
--- a/test/functional/ex_cmds/undojoin_spec.lua
+++ b/test/functional/ex_cmds/undojoin_spec.lua
@@ -5,7 +5,7 @@ local clear = helpers.clear
local insert = helpers.insert
local feed = helpers.feed
local expect = helpers.expect
-local execute = helpers.execute
+local feed_command = helpers.feed_command
local exc_exec = helpers.exc_exec
describe(':undojoin command', function()
@@ -14,10 +14,10 @@ describe(':undojoin command', function()
insert([[
Line of text 1
Line of text 2]])
- execute('goto 1')
+ feed_command('goto 1')
end)
it('joins changes in a buffer', function()
- execute('undojoin | delete')
+ feed_command('undojoin | delete')
expect([[
Line of text 2]])
feed('u')
@@ -26,7 +26,7 @@ describe(':undojoin command', function()
end)
it('does not corrupt undolist when connected with redo', function()
feed('ixx<esc>')
- execute('undojoin | redo')
+ feed_command('undojoin | redo')
expect([[
xxLine of text 1
Line of text 2]])
diff --git a/test/functional/ex_cmds/write_spec.lua b/test/functional/ex_cmds/write_spec.lua
index 4ac9f312ef..863d439080 100644
--- a/test/functional/ex_cmds/write_spec.lua
+++ b/test/functional/ex_cmds/write_spec.lua
@@ -1,15 +1,29 @@
local helpers = require('test.functional.helpers')(after_each)
-local eq, eval, clear, write_file, execute, source, insert =
+local lfs = require('lfs')
+local eq, eval, clear, write_file, source, insert =
helpers.eq, helpers.eval, helpers.clear, helpers.write_file,
- helpers.execute, helpers.source, helpers.insert
+ helpers.source, helpers.insert
+local redir_exec = helpers.redir_exec
+local exc_exec = helpers.exc_exec
+local command = helpers.command
+local feed_command = helpers.feed_command
+local funcs = helpers.funcs
+local meths = helpers.meths
if helpers.pending_win32(pending) then return end
+local fname = 'Xtest-functional-ex_cmds-write'
+local fname_bak = fname .. '~'
+local fname_broken = fname_bak .. 'broken'
+
describe(':write', function()
local function cleanup()
os.remove('test_bkc_file.txt')
os.remove('test_bkc_link.txt')
os.remove('test_fifo')
+ os.remove(fname)
+ os.remove(fname_bak)
+ os.remove(fname_broken)
end
before_each(function()
clear()
@@ -20,9 +34,9 @@ describe(':write', function()
end)
it('&backupcopy=auto preserves symlinks', function()
- execute('set backupcopy=auto')
+ command('set backupcopy=auto')
write_file('test_bkc_file.txt', 'content0')
- execute("silent !ln -s test_bkc_file.txt test_bkc_link.txt")
+ command("silent !ln -s test_bkc_file.txt test_bkc_link.txt")
source([[
edit test_bkc_link.txt
call setline(1, ['content1'])
@@ -33,9 +47,9 @@ describe(':write', function()
end)
it('&backupcopy=no replaces symlink with new file', function()
- execute('set backupcopy=no')
+ command('set backupcopy=no')
write_file('test_bkc_file.txt', 'content0')
- execute("silent !ln -s test_bkc_file.txt test_bkc_link.txt")
+ command("silent !ln -s test_bkc_file.txt test_bkc_link.txt")
source([[
edit test_bkc_link.txt
call setline(1, ['content1'])
@@ -56,11 +70,41 @@ describe(':write', function()
insert(text)
-- Blocks until a consumer reads the FIFO.
- execute("write >> test_fifo")
+ feed_command("write >> test_fifo")
-- Read the FIFO, this will unblock the :write above.
local fifo = assert(io.open("test_fifo"))
eq(text.."\n", fifo:read("*all"))
fifo:close()
end)
+
+ it('errors out correctly', function()
+ command('let $HOME=""')
+ eq(funcs.fnamemodify('.', ':p:h'), funcs.fnamemodify('.', ':p:h:~'))
+ -- Message from check_overwrite
+ eq(('\nE17: "'..funcs.fnamemodify('.', ':p:h')..'" is a directory'),
+ redir_exec('write .'))
+ meths.set_option('writeany', true)
+ -- Message from buf_write
+ eq(('\nE502: "." is a directory'),
+ redir_exec('write .'))
+ funcs.mkdir(fname_bak)
+ meths.set_option('backupdir', '.')
+ meths.set_option('backup', true)
+ write_file(fname, 'content0')
+ eq(0, exc_exec('edit ' .. fname))
+ funcs.setline(1, 'TTY')
+ eq('Vim(write):E510: Can\'t make backup file (add ! to override)',
+ exc_exec('write'))
+ meths.set_option('backup', false)
+ funcs.setfperm(fname, 'r--------')
+ eq('Vim(write):E505: "Xtest-functional-ex_cmds-write" is read-only (add ! to override)',
+ exc_exec('write'))
+ os.remove(fname)
+ os.remove(fname_bak)
+ write_file(fname_bak, 'TTYX')
+ lfs.link(fname_bak .. ('/xxxxx'):rep(20), fname, true)
+ eq('Vim(write):E166: Can\'t open linked file for writing',
+ exc_exec('write!'))
+ end)
end)
diff --git a/test/functional/ex_cmds/wundo_spec.lua b/test/functional/ex_cmds/wundo_spec.lua
index e1216fa5d4..b6fcae0cf4 100644
--- a/test/functional/ex_cmds/wundo_spec.lua
+++ b/test/functional/ex_cmds/wundo_spec.lua
@@ -1,20 +1,21 @@
-- Specs for :wundo and underlying functions
local helpers = require('test.functional.helpers')(after_each)
-local execute, clear, eval, feed, spawn, nvim_prog, set_session =
- helpers.execute, helpers.clear, helpers.eval, helpers.feed, helpers.spawn,
+local command, clear, eval, spawn, nvim_prog, set_session =
+ helpers.command, helpers.clear, helpers.eval, helpers.spawn,
helpers.nvim_prog, helpers.set_session
describe(':wundo', function()
before_each(clear)
+ after_each(function()
+ os.remove(eval('getcwd()') .. '/foo')
+ end)
it('safely fails on new, non-empty buffer', function()
- feed('iabc<esc>')
- execute('wundo foo') -- This should not segfault. #1027
+ command('normal! iabc')
+ command('wundo foo') -- This should not segfault. #1027
--TODO: check messages for error message
-
- os.remove(eval('getcwd()') .. '/foo') --cleanup
end)
end)
@@ -23,7 +24,7 @@ describe('u_* functions', function()
local session = spawn({nvim_prog, '-u', 'NONE', '-i', 'NONE', '--embed',
'-c', 'set undodir=. undofile'})
set_session(session)
- execute('echo "True"') -- Should not error out due to crashed Neovim
+ command('echo "True"') -- Should not error out due to crashed Neovim
session:close()
end)
end)
diff --git a/test/functional/ex_cmds/wviminfo_spec.lua b/test/functional/ex_cmds/wviminfo_spec.lua
index 37f45da2d4..eebbd70f2b 100644
--- a/test/functional/ex_cmds/wviminfo_spec.lua
+++ b/test/functional/ex_cmds/wviminfo_spec.lua
@@ -1,8 +1,8 @@
local helpers = require('test.functional.helpers')(after_each)
local lfs = require('lfs')
-local execute, eq, neq, spawn, nvim_prog, set_session, wait, write_file
- = helpers.execute, helpers.eq, helpers.neq, helpers.spawn,
- helpers.nvim_prog, helpers.set_session, helpers.wait, helpers.write_file
+local command, eq, neq, spawn, nvim_prog, set_session, write_file =
+ helpers.command, helpers.eq, helpers.neq, helpers.spawn,
+ helpers.nvim_prog, helpers.set_session, helpers.write_file
describe(':wshada', function()
local shada_file = 'wshada_test'
@@ -24,8 +24,7 @@ describe(':wshada', function()
it('creates a shada file', function()
-- file should _not_ exist
eq(nil, lfs.attributes(shada_file))
- execute('wsh! '..shada_file)
- wait()
+ command('wsh! '..shada_file)
-- file _should_ exist
neq(nil, lfs.attributes(shada_file))
end)
@@ -40,8 +39,7 @@ describe(':wshada', function()
eq(text, io.open(shada_file):read())
neq(nil, lfs.attributes(shada_file))
- execute('wsh! '..shada_file)
- wait()
+ command('wsh! '..shada_file)
-- File should have been overwritten with a shada file.
local fp = io.open(shada_file, 'r')