aboutsummaryrefslogtreecommitdiff
path: root/test/functional/ex_cmds
diff options
context:
space:
mode:
Diffstat (limited to 'test/functional/ex_cmds')
-rw-r--r--test/functional/ex_cmds/append_spec.lua6
-rw-r--r--test/functional/ex_cmds/arg_spec.lua30
-rw-r--r--test/functional/ex_cmds/bang_filter_spec.lua51
-rw-r--r--test/functional/ex_cmds/cd_spec.lua203
-rw-r--r--test/functional/ex_cmds/ctrl_c_spec.lua60
-rw-r--r--test/functional/ex_cmds/dict_notifications_spec.lua276
-rw-r--r--test/functional/ex_cmds/drop_spec.lua80
-rw-r--r--test/functional/ex_cmds/edit_spec.lua26
-rw-r--r--test/functional/ex_cmds/encoding_spec.lua27
-rw-r--r--test/functional/ex_cmds/grep_spec.lua2
-rw-r--r--test/functional/ex_cmds/menu_spec.lua4
-rw-r--r--test/functional/ex_cmds/oldfiles_spec.lua8
-rw-r--r--test/functional/ex_cmds/profile_spec.lua6
-rw-r--r--test/functional/ex_cmds/quit_spec.lua6
-rw-r--r--test/functional/ex_cmds/recover_spec.lua6
-rw-r--r--test/functional/ex_cmds/sign_spec.lua2
-rw-r--r--test/functional/ex_cmds/undojoin_spec.lua38
-rw-r--r--test/functional/ex_cmds/write_spec.lua48
-rw-r--r--test/functional/ex_cmds/wundo_spec.lua2
-rw-r--r--test/functional/ex_cmds/wviminfo_spec.lua3
20 files changed, 806 insertions, 78 deletions
diff --git a/test/functional/ex_cmds/append_spec.lua b/test/functional/ex_cmds/append_spec.lua
index 2d5ab8e8c8..0a4d701794 100644
--- a/test/functional/ex_cmds/append_spec.lua
+++ b/test/functional/ex_cmds/append_spec.lua
@@ -1,4 +1,4 @@
-local helpers = require('test.functional.helpers')
+local helpers = require('test.functional.helpers')(after_each)
local eq = helpers.eq
local feed = helpers.feed
@@ -22,8 +22,8 @@ local cmdtest = function(cmd, prep, ret1)
command(cmd .. '\nabc\ndef\n')
eq(ret1, buffer_contents())
end)
- -- Used to crash because this invokes history processing which uses
- -- hist_char2type which after fdb68e35e4c729c7ed097d8ade1da29e5b3f4b31
+ -- Used to crash because this invokes history processing which uses
+ -- hist_char2type which after fdb68e35e4c729c7ed097d8ade1da29e5b3f4b31
-- crashed.
it(cmd .. 's' .. prep .. ' the current line by default when feeding',
function()
diff --git a/test/functional/ex_cmds/arg_spec.lua b/test/functional/ex_cmds/arg_spec.lua
new file mode 100644
index 0000000000..e11b90532f
--- /dev/null
+++ b/test/functional/ex_cmds/arg_spec.lua
@@ -0,0 +1,30 @@
+local helpers = require("test.functional.helpers")(after_each)
+local eq, execute, funcs = helpers.eq, helpers.execute, helpers.funcs
+local ok = helpers.ok
+local clear = helpers.clear
+
+describe(":argument", function()
+ before_each(function()
+ clear()
+ end)
+
+ it("does not restart :terminal buffer", function()
+ execute("terminal")
+ helpers.feed([[<C-\><C-N>]])
+ execute("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")
+ helpers.feed([[<C-\><C-N>]])
+
+ local bufname_after = funcs.bufname("%")
+ local bufnr_after = funcs.bufnr("%")
+ eq("\n["..bufname_before.."] ", helpers.eval('execute("args")'))
+ ok(funcs.line('$') > 1)
+ eq(bufname_before, bufname_after)
+ eq(bufnr_before, bufnr_after)
+ end)
+end)
diff --git a/test/functional/ex_cmds/bang_filter_spec.lua b/test/functional/ex_cmds/bang_filter_spec.lua
new file mode 100644
index 0000000000..a320e6d018
--- /dev/null
+++ b/test/functional/ex_cmds/bang_filter_spec.lua
@@ -0,0 +1,51 @@
+-- Specs for bang/filter commands
+
+local helpers = require('test.functional.helpers')(after_each)
+local feed, execute, clear = helpers.feed, helpers.execute, helpers.clear
+local mkdir, write_file, rmdir = helpers.mkdir, helpers.write_file, helpers.rmdir
+
+if helpers.pending_win32(pending) then return end
+
+local Screen = require('test.functional.ui.screen')
+
+
+describe('issues', function()
+ local screen
+
+ before_each(function()
+ clear()
+ rmdir('bang_filter_spec')
+ mkdir('bang_filter_spec')
+ write_file('bang_filter_spec/f1', 'f1')
+ write_file('bang_filter_spec/f2', 'f2')
+ write_file('bang_filter_spec/f3', 'f3')
+ screen = Screen.new()
+ screen:attach()
+ end)
+
+ after_each(function()
+ rmdir('bang_filter_spec')
+ end)
+
+ it('#3269 Last line of shell output is not truncated', function()
+ execute([[nnoremap <silent>\l :!ls bang_filter_spec<cr>]])
+ feed([[\l]])
+ screen:expect([[
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ :!ls bang_filter_spec |
+ |
+ f1 |
+ f2 |
+ f3 |
+ Press ENTER or type command to continue^ |
+ ]])
+ end)
+
+end)
diff --git a/test/functional/ex_cmds/cd_spec.lua b/test/functional/ex_cmds/cd_spec.lua
index 69467632a4..5bf4d22d0f 100644
--- a/test/functional/ex_cmds/cd_spec.lua
+++ b/test/functional/ex_cmds/cd_spec.lua
@@ -1,49 +1,168 @@
-- Specs for :cd, :tcd, :lcd and getcwd()
-local helpers = require('test.functional.helpers')
-local execute, eq, clear, eval, exc_exec =
- helpers.execute, helpers.eq, helpers.clear, helpers.eval, helpers.exc_exec
local lfs = require('lfs')
+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 exc_exec = helpers.exc_exec
+
+if helpers.pending_win32(pending) then return end
-- These directories will be created for testing
local directories = {
- 'Xtest-functional-ex_cmds-cd_spec.1', -- Tab
- 'Xtest-functional-ex_cmds-cd_spec.2', -- Window
- 'Xtest-functional-ex_cmds-cd_spec.3', -- New global
+ tab = 'Xtest-functional-ex_cmds-cd_spec.tab', -- Tab
+ window = 'Xtest-functional-ex_cmds-cd_spec.window', -- Window
+ global = 'Xtest-functional-ex_cmds-cd_spec.global', -- New global
}
-- Shorthand writing to get the current working directory
-local cwd = function() return eval('getcwd( )') end -- effective working dir
-local wcwd = function() return eval('getcwd( 0 )') end -- window dir
-local tcwd = function() return eval('getcwd(-1, 0)') end -- tab dir
---local gcwd = function() return eval('getcwd(-1, -1)') end -- global dir
+local cwd = function(...) return call('getcwd', ...) end -- effective working dir
+local wcwd = function() return cwd(0) end -- window dir
+local tcwd = function() return cwd(-1, 0) end -- tab dir
-- Same, except these tell us if there is a working directory at all
---local lwd = function() return eval('haslocaldir( )') end -- effective working dir
-local wlwd = function() return eval('haslocaldir( 0 )') end -- window dir
-local tlwd = function() return eval('haslocaldir(-1, 0)') end -- tab dir
+local lwd = function(...) return call('haslocaldir', ...) end -- effective working dir
+local wlwd = function() return lwd(0) end -- window dir
+local tlwd = function() return lwd(-1, 0) end -- tab dir
--local glwd = function() return eval('haslocaldir(-1, -1)') end -- global dir
-- Test both the `cd` and `chdir` variants
for _, cmd in ipairs {'cd', 'chdir'} do
- describe(':*' .. cmd, function()
+ describe(':' .. cmd, function()
before_each(function()
clear()
- for _, d in ipairs(directories) do
+ for _, d in pairs(directories) do
lfs.mkdir(d)
end
+ directories.start = cwd()
end)
after_each(function()
- for _, d in ipairs(directories) do
+ for _, d in pairs(directories) do
lfs.rmdir(d)
end
end)
- it('works', function()
- -- Store the initial working directory
- local globalDir = cwd()
+ describe('using explicit scope', function()
+ it('for window', function()
+ local globalDir = directories.start
+ local globalwin = call('winnr')
+ local tabnr = call('tabpagenr')
+
+ -- Everything matches globalDir to start
+ eq(globalDir, cwd(globalwin))
+ eq(globalDir, cwd(globalwin, tabnr))
+ eq(0, lwd(globalwin))
+ eq(0, lwd(globalwin, tabnr))
+
+ execute('bot split')
+ local localwin = call('winnr')
+ -- Initial window is still using globalDir
+ eq(globalDir, cwd(localwin))
+ eq(globalDir, cwd(localwin, tabnr))
+ eq(0, lwd(globalwin))
+ eq(0, lwd(globalwin, tabnr))
+
+ execute('silent l' .. cmd .. ' ' .. directories.window)
+ -- From window with local dir, the original window
+ -- is still reporting the global dir
+ eq(globalDir, cwd(globalwin))
+ eq(globalDir, cwd(globalwin, tabnr))
+ eq(0, lwd(globalwin))
+ eq(0, lwd(globalwin, tabnr))
+
+ -- Window with local dir reports as such
+ eq(globalDir .. '/' .. directories.window, cwd(localwin))
+ eq(globalDir .. '/' .. directories.window, cwd(localwin, tabnr))
+ eq(1, lwd(localwin))
+ eq(1, lwd(localwin, tabnr))
+
+ execute('tabnew')
+ -- From new tab page, original window reports global dir
+ eq(globalDir, cwd(globalwin, tabnr))
+ eq(0, lwd(globalwin, tabnr))
+
+ -- From new tab page, local window reports as such
+ eq(globalDir .. '/' .. directories.window, cwd(localwin, tabnr))
+ eq(1, lwd(localwin, tabnr))
+ end)
+
+ it('for tab page', function()
+ local globalDir = directories.start
+ local globaltab = call('tabpagenr')
+
+ -- Everything matches globalDir to start
+ eq(globalDir, cwd(-1, 0))
+ eq(globalDir, cwd(-1, globaltab))
+ eq(0, lwd(-1, 0))
+ eq(0, lwd(-1, globaltab))
+
+ execute('tabnew')
+ execute('silent t' .. cmd .. ' ' .. directories.tab)
+ local localtab = call('tabpagenr')
+
+ -- From local tab page, original tab reports globalDir
+ eq(globalDir, cwd(-1, globaltab))
+ eq(0, lwd(-1, globaltab))
+
+ -- new tab reports local
+ eq(globalDir .. '/' .. directories.tab, cwd(-1, 0))
+ eq(globalDir .. '/' .. directories.tab, cwd(-1, localtab))
+ eq(1, lwd(-1, 0))
+ eq(1, lwd(-1, localtab))
+
+ execute('tabnext')
+ -- From original tab page, local reports as such
+ eq(globalDir .. '/' .. directories.tab, cwd(-1, localtab))
+ eq(1, lwd(-1, localtab))
+ end)
+ end)
+
+ describe('getcwd(-1, -1)', function()
+ it('works', function()
+ eq(directories.start, cwd(-1, -1))
+ eq(0, lwd(-1, -1))
+ end)
+ it('works with tab-local pwd', function()
+ execute('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)
+ eq(directories.start, cwd(-1, -1))
+ eq(0, lwd(-1, -1))
+ end)
+ end)
+
+ describe('Local directory gets inherited', function()
+ it('by tabs', function()
+ local globalDir = directories.start
+
+ -- Create a new tab and change directory
+ execute('tabnew')
+ execute('silent t' .. cmd .. ' ' .. directories.tab)
+ eq(globalDir .. '/' .. directories.tab, tcwd())
+
+ -- Create a new tab and verify it has inherited the directory
+ execute('tabnew')
+ eq(globalDir .. '/' .. directories.tab, tcwd())
+
+ -- Change tab and change back, verify that directories are correct
+ execute('tabnext')
+ eq(globalDir, tcwd())
+ execute('tabprevious')
+ eq(globalDir .. '/' .. directories.tab, tcwd())
+ end)
+ end)
+
+ it('works', function()
+ local globalDir = directories.start
-- Create a new tab first and verify that is has the same working dir
execute('tabnew')
eq(globalDir, cwd())
@@ -53,8 +172,8 @@ 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[1])
- eq(globalDir .. '/' .. directories[1], cwd())
+ execute('silent t' .. cmd .. ' ' .. directories.tab)
+ eq(globalDir .. '/' .. directories.tab, cwd())
eq(cwd(), tcwd()) -- working directory maches tab directory
eq(1, tlwd())
eq(cwd(), wcwd()) -- still no window-directory
@@ -64,16 +183,16 @@ for _, cmd in ipairs {'cd', 'chdir'} do
execute('new')
eq(1, tlwd()) -- Still tab-local working directory
eq(0, wlwd()) -- Still no window-local working directory
- eq(globalDir .. '/' .. directories[1], cwd())
- execute('silent l' .. cmd .. ' ../' .. directories[2])
- eq(globalDir .. '/' .. directories[2], cwd())
- eq(globalDir .. '/' .. directories[1], tcwd())
+ eq(globalDir .. '/' .. directories.tab, cwd())
+ execute('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')
- eq(globalDir .. '/' .. directories[1], cwd())
- eq(globalDir .. '/' .. directories[1], tcwd())
+ 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
@@ -83,11 +202,11 @@ for _, cmd in ipairs {'cd', 'chdir'} do
eq(0, wlwd())
-- Verify global changes don't affect local ones
- execute('silent ' .. cmd .. ' ' .. directories[3])
- eq(globalDir .. '/' .. directories[3], cwd())
+ execute('silent ' .. cmd .. ' ' .. directories.global)
+ eq(globalDir .. '/' .. directories.global, cwd())
execute('tabnext')
- eq(globalDir .. '/' .. directories[1], cwd())
- eq(globalDir .. '/' .. directories[1], tcwd())
+ 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
@@ -101,9 +220,9 @@ for _, cmd in ipairs {'cd', 'chdir'} do
-- But not in a window with its own local directory
execute('tabnext | wincmd w')
- eq(globalDir .. '/' .. directories[2], cwd() )
+ eq(globalDir .. '/' .. directories.window, cwd() )
eq(0 , tlwd())
- eq(globalDir .. '/' .. directories[2], wcwd())
+ eq(globalDir .. '/' .. directories.window, wcwd())
end)
end)
end
@@ -150,3 +269,21 @@ for _, cmd in ipairs {'getcwd', 'haslocaldir'} do
end)
end
+describe("getcwd()", function ()
+ before_each(function()
+ clear()
+ lfs.mkdir(directories.global)
+ end)
+
+ after_each(function()
+ helpers.rmdir(directories.global)
+ end)
+
+ it("returns empty string if working directory does not exist", function()
+ execute("cd "..directories.global)
+ execute("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
new file mode 100644
index 0000000000..072fd2ad10
--- /dev/null
+++ b/test/functional/ex_cmds/ctrl_c_spec.lua
@@ -0,0 +1,60 @@
+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
+
+describe("CTRL-C (mapped)", function()
+ before_each(function()
+ clear()
+ end)
+
+ it("interrupts :global", function()
+ -- Crashes luajit.
+ if helpers.skip_fragile(pending,
+ os.getenv("TRAVIS") or os.getenv("APPVEYOR")) then
+ return
+ end
+
+ source([[
+ set nomore nohlsearch undolevels=-1
+ nnoremap <C-C> <NOP>
+ ]])
+
+ execute("silent edit! test/functional/fixtures/bigfile.txt")
+ local screen = Screen.new(52, 6)
+ screen:attach()
+ screen:set_default_attr_ids({
+ [0] = {foreground = Screen.colors.White,
+ background = Screen.colors.Red},
+ [1] = {bold = true,
+ foreground = Screen.colors.SeaGreen}
+ })
+
+ screen:expect([[
+ ^0000;<control>;Cc;0;BN;;;;;N;NULL;;;; |
+ 0001;<control>;Cc;0;BN;;;;;N;START OF HEADING;;;; |
+ 0002;<control>;Cc;0;BN;;;;;N;START OF TEXT;;;; |
+ 0003;<control>;Cc;0;BN;;;;;N;END OF TEXT;;;; |
+ 0004;<control>;Cc;0;BN;;;;;N;END OF TRANSMISSION;;;;|
+ |
+ ]])
+
+ local function test_ctrl_c(ms)
+ feed(":global/^/p<CR>")
+ helpers.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}
+ for i, ms in ipairs(ms_values) do
+ if i < #ms_values then
+ local status, _ = pcall(test_ctrl_c, ms)
+ if status then break end
+ else -- Call the last attempt directly.
+ test_ctrl_c(ms)
+ end
+ end
+ end)
+end)
diff --git a/test/functional/ex_cmds/dict_notifications_spec.lua b/test/functional/ex_cmds/dict_notifications_spec.lua
new file mode 100644
index 0000000000..5e89986c0f
--- /dev/null
+++ b/test/functional/ex_cmds/dict_notifications_spec.lua
@@ -0,0 +1,276 @@
+local helpers = require('test.functional.helpers')(after_each)
+local clear, nvim, source = helpers.clear, helpers.nvim, helpers.source
+local eq, next_msg = helpers.eq, helpers.next_message
+local exc_exec = helpers.exc_exec
+local command = helpers.command
+local eval = helpers.eval
+
+
+describe('dictionary change notifications', function()
+ local channel
+
+ setup(function()
+ clear()
+ channel = nvim('get_api_info')[1]
+ nvim('set_var', 'channel', channel)
+ end)
+
+ -- 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 update(opval, key)
+ if not key then
+ key = 'watched'
+ end
+ if opval == '' then
+ nvim('command', "unlet "..dict_expr..dict_expr_suffix..key)
+ else
+ nvim('command', "let "..dict_expr..dict_expr_suffix..key.." "..opval)
+ end
+ end
+
+ local function verify_echo()
+ -- helper to verify that no notifications are sent after certain change
+ -- to a dict
+ nvim('command', "call rpcnotify(g:channel, 'echo')")
+ eq({'notification', 'echo', {}}, next_msg())
+ end
+
+ local function verify_value(vals, key)
+ if not key then
+ key = 'watched'
+ end
+ eq({'notification', 'values', {key, vals}}, next_msg())
+ end
+
+ describe('watcher', function()
+ if dict_init then
+ setup(function()
+ source(dict_init)
+ end)
+ end
+
+ before_each(function()
+ source([[
+ function! g:Changed(dict, key, value)
+ if a:dict != ]]..dict_expr..[[ |
+ throw 'invalid dict'
+ endif
+ call rpcnotify(g:channel, 'values', a:key, a:value)
+ endfunction
+ call dictwatcheradd(]]..dict_expr..[[, "watched", "g:Changed")
+ call dictwatcheradd(]]..dict_expr..[[, "watched2", "g:Changed")
+ ]])
+ end)
+
+ after_each(function()
+ source([[
+ call dictwatcherdel(]]..dict_expr..[[, "watched", "g:Changed")
+ call dictwatcherdel(]]..dict_expr..[[, "watched2", "g:Changed")
+ ]])
+ update('= "test"')
+ update('= "test2"', 'watched2')
+ update('', 'watched2')
+ update('')
+ verify_echo()
+ end)
+
+ it('is not triggered when unwatched keys are updated', function()
+ update('= "noop"', 'unwatched')
+ update('.= "noop2"', 'unwatched')
+ update('', 'unwatched')
+ verify_echo()
+ end)
+
+ it('is triggered by remove()', function()
+ update('= "test"')
+ verify_value({new = 'test'})
+ nvim('command', 'call remove('..dict_expr..', "watched")')
+ verify_value({old = 'test'})
+ end)
+
+ it('is triggered by extend()', function()
+ update('= "xtend"')
+ verify_value({new = 'xtend'})
+ nvim('command', [[
+ call extend(]]..dict_expr..[[, {'watched': 'xtend2', 'watched2': 5, 'watched3': 'a'})
+ ]])
+ verify_value({old = 'xtend', new = 'xtend2'})
+ verify_value({new = 5}, 'watched2')
+ update('')
+ verify_value({old = 'xtend2'})
+ update('', 'watched2')
+ verify_value({old = 5}, 'watched2')
+ update('', 'watched3')
+ verify_echo()
+ end)
+
+ it('is triggered with key patterns', function()
+ source([[
+ call dictwatcheradd(]]..dict_expr..[[, "wat*", "g:Changed")
+ ]])
+ update('= 1')
+ verify_value({new = 1})
+ verify_value({new = 1})
+ update('= 3', 'watched2')
+ verify_value({new = 3}, 'watched2')
+ verify_value({new = 3}, 'watched2')
+ verify_echo()
+ source([[
+ call dictwatcherdel(]]..dict_expr..[[, "wat*", "g:Changed")
+ ]])
+ -- watch every key pattern
+ source([[
+ call dictwatcheradd(]]..dict_expr..[[, "*", "g:Changed")
+ ]])
+ update('= 3', 'another_key')
+ update('= 4', 'another_key')
+ update('', 'another_key')
+ update('= 2')
+ verify_value({new = 3}, 'another_key')
+ verify_value({old = 3, new = 4}, 'another_key')
+ verify_value({old = 4}, 'another_key')
+ verify_value({old = 1, new = 2})
+ verify_value({old = 1, new = 2})
+ verify_echo()
+ source([[
+ 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)
+ it('test change sequence', function()
+ local input, output
+ for i = 1, #tests do
+ input, output = unpack(tests[i])
+ update(input)
+ verify_value(output)
+ end
+ end)
+ end
+
+ test_updates({
+ {'= 3', {new = 3}},
+ {'= 6', {old = 3, new = 6}},
+ {'+= 3', {old = 6, new = 9}},
+ {'', {old = 9}}
+ })
+
+ test_updates({
+ {'= "str"', {new = 'str'}},
+ {'= "str2"', {old = 'str', new = 'str2'}},
+ {'.= "2str"', {old = 'str2', new = 'str22str'}},
+ {'', {old = 'str22str'}}
+ })
+
+ test_updates({
+ {'= [1, 2]', {new = {1, 2}}},
+ {'= [1, 2, 3]', {old = {1, 2}, new = {1, 2, 3}}},
+ -- the += will update the list in place, so old and new are the same
+ {'+= [4, 5]', {old = {1, 2, 3, 4, 5}, new = {1, 2, 3, 4, 5}}},
+ {'', {old = {1, 2, 3, 4 ,5}}}
+ })
+
+ test_updates({
+ {'= {"k": "v"}', {new = {k = 'v'}}},
+ {'= {"k1": 2}', {old = {k = 'v'}, new = {k1 = 2}}},
+ {'', {old = {k1 = 2}}},
+ })
+ end)
+ end
+
+ gentests('g:')
+ gentests('b:')
+ gentests('w:')
+ gentests('t:')
+ gentests('g:dict_var', '.', 'let g:dict_var = {}')
+
+ describe('multiple watchers on the same dict/key', function()
+ setup(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
+ call dictwatcheradd(g:, "key", "g:Watcher1")
+ call dictwatcheradd(g:, "key", "g:Watcher2")
+ ]])
+ end)
+
+ it('invokes all callbacks when the key is changed', function()
+ nvim('command', 'let g:key = "value"')
+ eq({'notification', '1', {'key', {new = 'value'}}}, next_msg())
+ eq({'notification', '2', {'key', {new = 'value'}}}, next_msg())
+ end)
+
+ it('only removes watchers that fully match dict, key and callback', function()
+ 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)
+
+ describe('errors', function()
+ -- 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",
+ exc_exec('call dictwatcherdel(g:, "key", "g:Watcher1")'))
+ end)
+
+ it('fails to remove if no watcher with matching key is found', function()
+ eq("Vim(call):Couldn't find a watcher matching key and callback",
+ exc_exec('call dictwatcherdel(g:, "invalid_key", "g:Watcher2")'))
+ end)
+
+ it("does not fail to add/remove if the callback doesn't exist", function()
+ command('call dictwatcheradd(g:, "key", "g:InvalidCb")')
+ 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")'))
+ end)
+
+ it('does not fail to replace a watcher function', function()
+ source([[
+ function! g:ReplaceWatcher2()
+ function! g:Watcher2(dict, key, value)
+ call rpcnotify(g:channel, '2b', a:key, a:value)
+ endfunction
+ endfunction
+ ]])
+ command('call g:ReplaceWatcher2()')
+ command('let g:key = "value"')
+ eq({'notification', '2b', {'key', {old = 'v2', new = 'value'}}}, next_msg())
+
+ end)
+
+ it('does not crash when freeing a watched dictionary', function()
+ source([[
+ function! Watcher(dict, key, value)
+ echo a:key string(a:value)
+ endfunction
+
+ function! MakeWatch()
+ let d = {'foo': 'bar'}
+ call dictwatcheradd(d, 'foo', function('Watcher'))
+ endfunction
+ ]])
+
+ command('call MakeWatch()')
+ eq(2, eval('1+1')) -- Still alive?
+ end)
+ end)
+end)
diff --git a/test/functional/ex_cmds/drop_spec.lua b/test/functional/ex_cmds/drop_spec.lua
new file mode 100644
index 0000000000..99db5ea333
--- /dev/null
+++ b/test/functional/ex_cmds/drop_spec.lua
@@ -0,0 +1,80 @@
+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
+
+describe(":drop", function()
+ local screen
+
+ before_each(function()
+ clear()
+ screen = Screen.new(35, 10)
+ screen:attach()
+ screen:set_default_attr_ids({
+ [0] = {bold=true, foreground=Screen.colors.Blue},
+ [1] = {bold = true, reverse = true},
+ [2] = {reverse = true},
+ [3] = {bold = true},
+ })
+ execute("set laststatus=2")
+ end)
+
+ after_each(function()
+ screen:detach()
+ end)
+
+ it("works like :e when called with only one window open", function()
+ execute("drop tmp1.vim")
+ screen:expect([[
+ ^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {1:tmp1.vim }|
+ "tmp1.vim" [New File] |
+ ]])
+ end)
+
+ it("switches to an open window showing the buffer", function()
+ execute("edit tmp1")
+ execute("vsplit")
+ execute("edit tmp2")
+ execute("drop tmp1")
+ screen:expect([[
+ {2:|}^ |
+ {0:~ }{2:|}{0:~ }|
+ {0:~ }{2:|}{0:~ }|
+ {0:~ }{2:|}{0:~ }|
+ {0:~ }{2:|}{0:~ }|
+ {0:~ }{2:|}{0:~ }|
+ {0:~ }{2:|}{0:~ }|
+ {0:~ }{2:|}{0:~ }|
+ {2:tmp2 }{1:tmp1 }|
+ :drop tmp1 |
+ ]])
+ end)
+
+ it("splits off a new window when a buffer can't be abandoned", function()
+ execute("edit tmp1")
+ execute("vsplit")
+ execute("edit tmp2")
+ feed("iABC<esc>")
+ execute("drop tmp3")
+ screen:expect([[
+ ^ {2:|} |
+ {0:~ }{2:|}{0:~ }|
+ {0:~ }{2:|}{0:~ }|
+ {0:~ }{2:|}{0:~ }|
+ {1:tmp3 }{2:|}{0:~ }|
+ ABC {2:|}{0:~ }|
+ {0:~ }{2:|}{0:~ }|
+ {0:~ }{2:|}{0:~ }|
+ {2:tmp2 [+] tmp1 }|
+ "tmp3" [New File] |
+ ]])
+ end)
+
+end)
diff --git a/test/functional/ex_cmds/edit_spec.lua b/test/functional/ex_cmds/edit_spec.lua
new file mode 100644
index 0000000000..3cc5f5fb95
--- /dev/null
+++ b/test/functional/ex_cmds/edit_spec.lua
@@ -0,0 +1,26 @@
+local helpers = require("test.functional.helpers")(after_each)
+local eq, execute, funcs = helpers.eq, helpers.execute, helpers.funcs
+local ok = helpers.ok
+local clear = helpers.clear
+
+describe(":edit", function()
+ before_each(function()
+ clear()
+ end)
+
+ it("without arguments does not restart :terminal buffer", function()
+ execute("terminal")
+ 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("edit")
+
+ local bufname_after = funcs.bufname("%")
+ local bufnr_after = funcs.bufnr("%")
+ ok(funcs.line('$') > 1)
+ eq(bufname_before, bufname_after)
+ eq(bufnr_before, bufnr_after)
+ end)
+end)
diff --git a/test/functional/ex_cmds/encoding_spec.lua b/test/functional/ex_cmds/encoding_spec.lua
index 6d402b7974..87ed7a2d0a 100644
--- a/test/functional/ex_cmds/encoding_spec.lua
+++ b/test/functional/ex_cmds/encoding_spec.lua
@@ -1,4 +1,4 @@
-local helpers = require('test.functional.helpers')
+local helpers = require('test.functional.helpers')(after_each)
local clear, execute, feed = helpers.clear, helpers.execute, helpers.feed
local eq, neq, eval = helpers.eq, helpers.neq, helpers.eval
@@ -15,27 +15,26 @@ describe('&encoding', function()
execute('set encoding=latin1')
-- error message expected
feed('<cr>')
- neq(nil, string.find(eval('v:errmsg'), '^E905:'))
+ neq(nil, string.find(eval('v:errmsg'), '^E474:'))
eq('utf-8', eval('&encoding'))
-- check nvim is still in utf-8 mode
eq(3, eval('strwidth("Bär")'))
end)
- it('can be changed before startup', function()
- clear('set enc=latin1')
- execute('set encoding=utf-8')
+ it('cannot be changed before startup', function()
+ clear('--cmd', 'set enc=latin1')
-- error message expected
feed('<cr>')
- eq('latin1', eval('&encoding'))
- eq(4, eval('strwidth("Bär")'))
+ neq(nil, string.find(eval('v:errmsg'), '^E474:'))
+ eq('utf-8', eval('&encoding'))
+ eq(3, eval('strwidth("Bär")'))
end)
- it('is not changed by `set all&`', function()
- -- we need to set &encoding to something non-default. Use 'latin1'
- clear('set enc=latin1')
- execute('set all&')
- eq('latin1', eval('&encoding'))
- eq(4, eval('strwidth("Bär")'))
- end)
+ it('can be set to utf-8 without error', function()
+ execute('set encoding=utf-8')
+ eq("", eval('v:errmsg'))
+ clear('--cmd', 'set enc=utf-8')
+ eq("", eval('v:errmsg'))
+ end)
end)
diff --git a/test/functional/ex_cmds/grep_spec.lua b/test/functional/ex_cmds/grep_spec.lua
index f3ff0a3817..13f88b7e03 100644
--- a/test/functional/ex_cmds/grep_spec.lua
+++ b/test/functional/ex_cmds/grep_spec.lua
@@ -1,4 +1,4 @@
-local helpers = require('test.functional.helpers')
+local helpers = require('test.functional.helpers')(after_each)
local clear, execute, feed, ok, eval =
helpers.clear, helpers.execute, helpers.feed, helpers.ok, helpers.eval
diff --git a/test/functional/ex_cmds/menu_spec.lua b/test/functional/ex_cmds/menu_spec.lua
index f5fd30465d..52df9e1592 100644
--- a/test/functional/ex_cmds/menu_spec.lua
+++ b/test/functional/ex_cmds/menu_spec.lua
@@ -1,4 +1,4 @@
-local helpers = require('test.functional.helpers')
+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 eq, eval = helpers.eq, helpers.eval
@@ -39,7 +39,7 @@ describe(':emenu', function()
end)
it('executes correct bindings in command mode', function()
- feed('ithis is a sentence<esc>^"+yiwo<esc>')
+ feed('ithis is a sentence<esc>^yiwo<esc>')
-- Invoke "Edit.Paste" in normal-mode.
nvim('command', 'emenu Edit.Paste')
diff --git a/test/functional/ex_cmds/oldfiles_spec.lua b/test/functional/ex_cmds/oldfiles_spec.lua
index 5bba1a0e7c..a218bb6633 100644
--- a/test/functional/ex_cmds/oldfiles_spec.lua
+++ b/test/functional/ex_cmds/oldfiles_spec.lua
@@ -1,5 +1,5 @@
local Screen = require('test.functional.ui.screen')
-local helpers = require('test.functional.helpers')
+local helpers = require('test.functional.helpers')(after_each)
local buf, eq, execute = helpers.curbufmeths, helpers.eq, helpers.execute
local feed, nvim_prog, wait = helpers.feed, helpers.nvim_prog, helpers.wait
@@ -47,7 +47,7 @@ describe(':oldfiles', function()
end)
end)
-describe(':oldfiles!', function()
+describe(':browse oldfiles', function()
local filename
local filename2
local oldfiles
@@ -65,7 +65,7 @@ describe(':oldfiles!', function()
-- Ensure nvim is out of "Press ENTER..." screen
feed('<cr>')
-
+
-- Ensure v:oldfiles isn't busted. Since things happen so fast,
-- the ordering of v:oldfiles is unstable (it uses qsort() under-the-hood).
-- Let's verify the contents and the length of v:oldfiles before moving on.
@@ -74,7 +74,7 @@ describe(':oldfiles!', function()
ok(filename == oldfiles[1] or filename == oldfiles[2])
ok(filename2 == oldfiles[1] or filename2 == oldfiles[2])
- execute('oldfiles!')
+ execute('browse oldfiles')
end)
after_each(function()
diff --git a/test/functional/ex_cmds/profile_spec.lua b/test/functional/ex_cmds/profile_spec.lua
index 744b22621f..f185db192a 100644
--- a/test/functional/ex_cmds/profile_spec.lua
+++ b/test/functional/ex_cmds/profile_spec.lua
@@ -1,13 +1,13 @@
require('os')
local lfs = require('lfs')
-local helpers = require('test.functional.helpers')
+local helpers = require('test.functional.helpers')(after_each)
local eval = helpers.eval
local command = helpers.command
local eq, neq = helpers.eq, helpers.neq
-local tempfile = os.tmpname()
+local tempfile = helpers.tmpname()
--- os.tmpname() also creates the file on POSIX systems. Remove it again.
+-- tmpname() also creates the file on POSIX systems. Remove it again.
-- We just need the name, ignoring any race conditions.
if lfs.attributes(tempfile, 'uid') then
os.remove(tempfile)
diff --git a/test/functional/ex_cmds/quit_spec.lua b/test/functional/ex_cmds/quit_spec.lua
index a8156228d3..fe138a24c8 100644
--- a/test/functional/ex_cmds/quit_spec.lua
+++ b/test/functional/ex_cmds/quit_spec.lua
@@ -1,9 +1,9 @@
-local helpers = require('test.functional.helpers')
+local helpers = require('test.functional.helpers')(after_each)
local clear = helpers.clear
describe(':qa', function()
- before_each(function()
- clear('qa')
+ before_each(function()
+ clear('--cmd', 'qa')
end)
it('verify #3334', function()
diff --git a/test/functional/ex_cmds/recover_spec.lua b/test/functional/ex_cmds/recover_spec.lua
index e1d01f6896..af1296c94c 100644
--- a/test/functional/ex_cmds/recover_spec.lua
+++ b/test/functional/ex_cmds/recover_spec.lua
@@ -1,11 +1,13 @@
-- Tests for :recover
-local helpers = require('test.functional.helpers')
+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,
helpers.expect, helpers.source
+if helpers.pending_win32(pending) then return end
+
describe(':recover', function()
before_each(clear)
@@ -30,7 +32,7 @@ describe(':preserve', function()
it("saves to custom 'directory' and (R)ecovers (issue #1836)", function()
local testfile = 'testfile_recover_spec'
- -- Note: `set swapfile` *must* go after `set directory`: otherwise it may
+ -- Note: `set swapfile` *must* go after `set directory`: otherwise it may
-- attempt to create a swapfile in different directory.
local init = [[
set directory^=]]..swapdir..[[//
diff --git a/test/functional/ex_cmds/sign_spec.lua b/test/functional/ex_cmds/sign_spec.lua
index c50704504d..b37e6e8563 100644
--- a/test/functional/ex_cmds/sign_spec.lua
+++ b/test/functional/ex_cmds/sign_spec.lua
@@ -1,4 +1,4 @@
-local helpers = require('test.functional.helpers')
+local helpers = require('test.functional.helpers')(after_each)
local clear, nvim, eq = helpers.clear, helpers.nvim, helpers.eq
describe('sign', function()
diff --git a/test/functional/ex_cmds/undojoin_spec.lua b/test/functional/ex_cmds/undojoin_spec.lua
new file mode 100644
index 0000000000..ba1e46ceb3
--- /dev/null
+++ b/test/functional/ex_cmds/undojoin_spec.lua
@@ -0,0 +1,38 @@
+local helpers = require('test.functional.helpers')(after_each)
+
+local eq = helpers.eq
+local clear = helpers.clear
+local insert = helpers.insert
+local feed = helpers.feed
+local expect = helpers.expect
+local execute = helpers.execute
+local exc_exec = helpers.exc_exec
+
+describe(':undojoin command', function()
+ before_each(function()
+ clear()
+ insert([[
+ Line of text 1
+ Line of text 2]])
+ execute('goto 1')
+ end)
+ it('joins changes in a buffer', function()
+ execute('undojoin | delete')
+ expect([[
+ Line of text 2]])
+ feed('u')
+ expect([[
+ ]])
+ end)
+ it('does not corrupt undolist when connected with redo', function()
+ feed('ixx<esc>')
+ execute('undojoin | redo')
+ expect([[
+ xxLine of text 1
+ Line of text 2]])
+ end)
+ it('does not raise an error when called twice', function()
+ local ret = exc_exec('undojoin | undojoin')
+ eq(0, ret)
+ end)
+end)
diff --git a/test/functional/ex_cmds/write_spec.lua b/test/functional/ex_cmds/write_spec.lua
index d90b297ca8..4ac9f312ef 100644
--- a/test/functional/ex_cmds/write_spec.lua
+++ b/test/functional/ex_cmds/write_spec.lua
@@ -1,15 +1,26 @@
--- Specs for :write
+local helpers = require('test.functional.helpers')(after_each)
+local eq, eval, clear, write_file, execute, source, insert =
+ helpers.eq, helpers.eval, helpers.clear, helpers.write_file,
+ helpers.execute, helpers.source, helpers.insert
-local helpers = require('test.functional.helpers')
-local eq, eval, clear, write_file, execute, source =
- helpers.eq, helpers.eval, helpers.clear, helpers.write_file,
- helpers.execute, helpers.source
+if helpers.pending_win32(pending) then return end
describe(':write', function()
- it('&backupcopy=auto preserves symlinks', function()
- clear('set backupcopy=auto')
+ local function cleanup()
os.remove('test_bkc_file.txt')
os.remove('test_bkc_link.txt')
+ os.remove('test_fifo')
+ end
+ before_each(function()
+ clear()
+ cleanup()
+ end)
+ after_each(function()
+ cleanup()
+ end)
+
+ it('&backupcopy=auto preserves symlinks', function()
+ execute('set backupcopy=auto')
write_file('test_bkc_file.txt', 'content0')
execute("silent !ln -s test_bkc_file.txt test_bkc_link.txt")
source([[
@@ -22,9 +33,7 @@ describe(':write', function()
end)
it('&backupcopy=no replaces symlink with new file', function()
- clear('set backupcopy=no')
- os.remove('test_bkc_file.txt')
- os.remove('test_bkc_link.txt')
+ execute('set backupcopy=no')
write_file('test_bkc_file.txt', 'content0')
execute("silent !ln -s test_bkc_file.txt test_bkc_link.txt")
source([[
@@ -35,4 +44,23 @@ describe(':write', function()
eq(eval("['content0']"), eval("readfile('test_bkc_file.txt')"))
eq(eval("['content1']"), eval("readfile('test_bkc_link.txt')"))
end)
+
+ it("appends FIFO file", function()
+ if eval("executable('mkfifo')") == 0 then
+ pending('missing "mkfifo" command', function()end)
+ return
+ end
+
+ local text = "some fifo text from write_spec"
+ assert(os.execute("mkfifo test_fifo"))
+ insert(text)
+
+ -- Blocks until a consumer reads the FIFO.
+ execute("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)
end)
diff --git a/test/functional/ex_cmds/wundo_spec.lua b/test/functional/ex_cmds/wundo_spec.lua
index 969dfea3d9..e1216fa5d4 100644
--- a/test/functional/ex_cmds/wundo_spec.lua
+++ b/test/functional/ex_cmds/wundo_spec.lua
@@ -1,6 +1,6 @@
-- Specs for :wundo and underlying functions
-local helpers = require('test.functional.helpers')
+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,
helpers.nvim_prog, helpers.set_session
diff --git a/test/functional/ex_cmds/wviminfo_spec.lua b/test/functional/ex_cmds/wviminfo_spec.lua
index 21f14be62c..37f45da2d4 100644
--- a/test/functional/ex_cmds/wviminfo_spec.lua
+++ b/test/functional/ex_cmds/wviminfo_spec.lua
@@ -1,4 +1,5 @@
-local helpers, lfs = require('test.functional.helpers'), require('lfs')
+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