neovim/test/functional/lua/with_spec.lua
Evgeni Chasnovski f8795365de
test(lua): cover vim._with() with tests
Problem: `vim._with()` has many different use cases which are not
  covered with tests.

Solution: cover with tests. Some (many) test cases are intentionally
  marked as "pending" because they cover cases which don't work as
  expected at the moment (and fixing them requires specific knowledge of
  C codebase). Use them as a reference for future fixes.
  Also some of "can be nested" tests currently might pass only because
  the tested context doesn't work.
2024-06-24 20:23:11 +03:00

877 lines
26 KiB
Lua

local t = require('test.testutil')
local n = require('test.functional.testnvim')()
local Screen = require('test.functional.ui.screen')
local fn = n.fn
local api = n.api
local command = n.command
local eq = t.eq
local exec_lua = n.exec_lua
local exec_capture = n.exec_capture
local matches = t.matches
local pcall_err = t.pcall_err
describe('vim._with', function()
before_each(function()
n.clear()
exec_lua([[
_G.fn = vim.fn
_G.api = vim.api
_G.setup_buffers = function()
return api.nvim_create_buf(false, true), api.nvim_get_current_buf()
end
_G.setup_windows = function()
local other_win = api.nvim_get_current_win()
vim.cmd.new()
return other_win, api.nvim_get_current_win()
end
]])
end)
local validate_events_trigger = function()
local out = exec_lua [[
-- Needs three global values defined:
-- - `test_events` - array of events which are tested.
-- - `test_context` - context to be tested.
-- - `test_trig_event` - callable triggering at least one tested event.
_G.n_events = 0
local opts = { callback = function() _G.n_events = _G.n_events + 1 end }
api.nvim_create_autocmd(_G.test_events, opts)
local context = { bo = { commentstring = '-- %s' } }
-- Should not trigger events on its own
vim._with(_G.test_context, function() end)
local is_no_events = _G.n_events == 0
-- Should trigger events if specifically asked inside callback
local is_events = vim._with(_G.test_context, function()
_G.test_trig_event()
return _G.n_events > 0
end)
return { is_no_events, is_events }
]]
eq({ true, true }, out)
end
describe('`buf` context', function()
it('works', function()
local out = exec_lua [[
local other_buf, cur_buf = setup_buffers()
local inner = vim._with({ buf = other_buf }, function()
return api.nvim_get_current_buf()
end)
return { inner == other_buf, api.nvim_get_current_buf() == cur_buf }
]]
eq({ true, true }, out)
end)
it('does not trigger events', function()
exec_lua [[
_G.test_events = { 'BufEnter', 'BufLeave', 'BufWinEnter', 'BufWinLeave' }
_G.test_context = { buf = other_buf }
_G.test_trig_event = function() vim.cmd.new() end
]]
validate_events_trigger()
end)
it('can access buffer options', function()
local out = exec_lua [[
other_buf, cur_buf = setup_buffers()
vim.bo[other_buf].commentstring = '## %s'
vim.bo[cur_buf].commentstring = '// %s'
vim._with({ buf = other_buf }, function()
vim.cmd.set('commentstring=--\\ %s')
end)
return vim.bo[other_buf].commentstring == '-- %s' and
vim.bo[cur_buf].commentstring == '// %s'
]]
eq(true, out)
end)
it('works with different kinds of buffers', function()
exec_lua [[
local validate = function(buf)
vim._with({ buf = buf }, function()
assert(api.nvim_get_current_buf() == buf)
end)
end
-- Current
validate(api.nvim_get_current_buf())
-- Hidden listed
local listed = api.nvim_create_buf(true, true)
validate(listed)
-- Visible
local other_win, cur_win = setup_windows()
api.nvim_win_set_buf(other_win, listed)
validate(listed)
-- Shown but not visible
vim.cmd.tabnew()
validate(listed)
-- Shown in several windows
api.nvim_win_set_buf(0, listed)
validate(listed)
-- Shown in floating window
local float_buf = api.nvim_create_buf(false, true)
local config = { relative = 'editor', row = 1, col = 1, width = 5, height = 5 }
api.nvim_open_win(float_buf, false, config)
validate(float_buf)
]]
end)
it('does not cause ml_get errors with invalid visual selection', function()
exec_lua [[
api.nvim_buf_set_lines(0, 0, -1, true, { 'a', 'b', 'c' })
api.nvim_feedkeys(vim.keycode('G<C-V>'), 'txn', false)
local other_buf, _ = setup_buffers()
vim._with({ buf = buf }, function() vim.cmd.redraw() end)
]]
end)
it('can be nested', function()
exec_lua [[
local other_buf, cur_buf = setup_buffers()
vim._with({ buf = other_buf }, function()
assert(api.nvim_get_current_buf() == other_buf)
inner = vim._with({ buf = cur_buf }, function()
assert(api.nvim_get_current_buf() == cur_buf)
end)
assert(api.nvim_get_current_buf() == other_buf)
end)
assert(api.nvim_get_current_buf() == cur_buf)
]]
end)
it('can be nested crazily with hidden buffers', function()
local out = exec_lua([[
local n = 0
local function with_recursive_nested_bufs()
n = n + 1
if n > 20 then return true end
local other_buf, _ = setup_buffers()
vim.bo[other_buf].commentstring = '## %s'
local callback = function()
return api.nvim_get_current_buf() == other_buf
and vim.bo[other_buf].commentstring == '## %s'
and with_recursive_nested_bufs()
end
return vim._with({ buf = other_buf }, callback) and
api.nvim_buf_delete(other_buf, {}) == nil
end
return with_recursive_nested_bufs()
]])
eq(true, out)
end)
end)
describe('`emsg_silent` context', function()
pending('works', function()
local ok = pcall(
exec_lua,
[[
_G.f = function()
error('This error should not interfer with execution', 0)
end
-- Should not produce error same as `vim.cmd('silent! lua _G.f()')`
vim._with({ emsg_silent = true }, f)
]]
)
eq(true, ok)
-- Should properly report errors afterwards
ok = pcall(exec_lua, 'lua _G.f()')
eq(false, ok)
end)
it('can be nested', function()
local ok = pcall(
exec_lua,
[[
_G.f = function()
error('This error should not interfer with execution', 0)
end
-- Should produce error same as `_G.f()`
vim._with({ emsg_silent = true }, function()
vim._with( { emsg_silent = false }, f)
end)
]]
)
eq(false, ok)
end)
end)
describe('`hide` context', function()
pending('works', function()
local ok = pcall(
exec_lua,
[[
vim.o.hidden = false
vim.bo.modified = true
local init_buf = api.nvim_get_current_buf()
-- Should not produce error same as `vim.cmd('hide enew')`
vim._with({ hide = true }, function()
vim.cmd.enew()
end)
assert(api.nvim_get_current_buf() ~= init_buf)
]]
)
eq(true, ok)
end)
it('can be nested', function()
local ok = pcall(
exec_lua,
[[
vim.o.hidden = false
vim.bo.modified = true
-- Should produce error same as `vim.cmd.enew()`
vim._with({ hide = true }, function()
vim._with({ hide = false }, function()
vim.cmd.enew()
end)
end)
]]
)
eq(false, ok)
end)
end)
describe('`horizontal` context', function()
local is_approx_eq = function(dim, id_1, id_2)
local f = dim == 'height' and api.nvim_win_get_height or api.nvim_win_get_width
return math.abs(f(id_1) - f(id_2)) <= 1
end
local win_id_1, win_id_2, win_id_3
before_each(function()
win_id_1 = api.nvim_get_current_win()
command('wincmd v | wincmd 5>')
win_id_2 = api.nvim_get_current_win()
command('wincmd s | wincmd 5+')
win_id_3 = api.nvim_get_current_win()
eq(is_approx_eq('width', win_id_1, win_id_2), false)
eq(is_approx_eq('height', win_id_3, win_id_2), false)
end)
pending('works', function()
exec_lua [[
-- Should be same as `vim.cmd('horizontal wincmd =')`
vim._with({ horizontal = true }, function()
vim.cmd.wincmd('=')
end)
]]
eq(is_approx_eq('width', win_id_1, win_id_2), true)
eq(is_approx_eq('height', win_id_3, win_id_2), false)
end)
pending('can be nested', function()
exec_lua [[
-- Should be same as `vim.cmd.wincmd('=')`
vim._with({ horizontal = true }, function()
vim._with({ horizontal = false }, function()
vim.cmd.wincmd('=')
end)
end)
]]
eq(is_approx_eq('width', win_id_1, win_id_2), true)
eq(is_approx_eq('height', win_id_3, win_id_2), true)
end)
end)
describe('`keepalt` context', function()
pending('works', function()
local out = exec_lua [[
vim.cmd('edit alt')
vim.cmd('edit new')
assert(fn.bufname('#') == 'alt')
-- Should work as `vim.cmd('keepalt edit very-new')`
vim._with({ keepalt = true }, function()
vim.cmd.edit('very-new')
end)
return fn.bufname('#') == 'alt'
]]
eq(true, out)
end)
it('can be nested', function()
local out = exec_lua [[
vim.cmd('edit alt')
vim.cmd('edit new')
assert(fn.bufname('#') == 'alt')
-- Should work as `vim.cmd.edit('very-new')`
vim._with({ keepalt = true }, function()
vim._with({ keepalt = false }, function()
vim.cmd.edit('very-new')
end)
end)
return fn.bufname('#') == 'alt'
]]
eq(false, out)
end)
end)
describe('`keepjumps` context', function()
pending('works', function()
local out = exec_lua [[
api.nvim_buf_set_lines(0, 0, -1, false, { 'aaa', 'bbb', 'ccc' })
local jumplist_before = fn.getjumplist()
-- Should work as `vim.cmd('keepjumps normal! Ggg')`
vim._with({ keepjumps = true }, function()
vim.cmd('normal! Ggg')
end)
return vim.deep_equal(jumplist_before, fn.getjumplist())
]]
eq(true, out)
end)
it('can be nested', function()
local out = exec_lua [[
api.nvim_buf_set_lines(0, 0, -1, false, { 'aaa', 'bbb', 'ccc' })
local jumplist_before = fn.getjumplist()
vim._with({ keepjumps = true }, function()
vim._with({ keepjumps = false }, function()
vim.cmd('normal! Ggg')
end)
end)
return vim.deep_equal(jumplist_before, fn.getjumplist())
]]
eq(false, out)
end)
end)
describe('`keepmarks` context', function()
pending('works', function()
local out = exec_lua [[
vim.cmd('set cpoptions+=R')
api.nvim_buf_set_lines(0, 0, -1, false, { 'bbb', 'ccc', 'aaa' })
api.nvim_buf_set_mark(0, 'm', 2, 2, {})
-- Should be the same as `vim.cmd('keepmarks %!sort')`
vim._with({ keepmarks = true }, function()
vim.cmd('%!sort')
end)
return api.nvim_buf_get_mark(0, 'm')
]]
eq({ 2, 2 }, out)
end)
it('can be nested', function()
local out = exec_lua [[
vim.cmd('set cpoptions+=R')
api.nvim_buf_set_lines(0, 0, -1, false, { 'bbb', 'ccc', 'aaa' })
api.nvim_buf_set_mark(0, 'm', 2, 2, {})
vim._with({ keepmarks = true }, function()
vim._with({ keepmarks = false }, function()
vim.cmd('%!sort')
end)
end)
return api.nvim_buf_get_mark(0, 'm')
]]
eq({ 0, 2 }, out)
end)
end)
describe('`keepatterns` context', function()
pending('works', function()
local out = exec_lua [[
api.nvim_buf_set_lines(0, 0, -1, false, { 'aaa', 'bbb' })
vim.cmd('/aaa')
-- Should be the same as `vim.cmd('keeppatterns /bbb')`
vim._with({ keeppatterns = true }, function()
vim.cmd('/bbb')
end)
return fn.getreg('/')
]]
eq('aaa', out)
end)
it('can be nested', function()
local out = exec_lua [[
api.nvim_buf_set_lines(0, 0, -1, false, { 'aaa', 'bbb' })
vim.cmd('/aaa')
vim._with({ keeppatterns = true }, function()
vim._with({ keeppatterns = false }, function()
vim.cmd('/bbb')
end)
end)
return fn.getreg('/')
]]
eq('bbb', out)
end)
end)
describe('`lockmarks` context', function()
it('works', function()
local mark = exec_lua [[
api.nvim_buf_set_lines(0, 0, 0, false, { 'aaa', 'bbb', 'ccc' })
api.nvim_buf_set_mark(0, 'm', 2, 2, {})
-- Should be same as `:lockmarks lua api.nvim_buf_set_lines(...)`
vim._with({ lockmarks = true }, function()
api.nvim_buf_set_lines(0, 0, 2, false, { 'uuu', 'vvv', 'www' })
end)
return api.nvim_buf_get_mark(0, 'm')
]]
eq({ 2, 2 }, mark)
end)
it('can be nested', function()
local mark = exec_lua [[
api.nvim_buf_set_lines(0, 0, 0, false, { 'aaa', 'bbb', 'ccc' })
api.nvim_buf_set_mark(0, 'm', 2, 2, {})
vim._with({ lockmarks = true }, function()
vim._with({ lockmarks = false }, function()
api.nvim_buf_set_lines(0, 0, 2, false, { 'uuu', 'vvv', 'www' })
end)
end)
return api.nvim_buf_get_mark(0, 'm')
]]
eq({ 0, 2 }, mark)
end)
end)
describe('`noautocmd` context', function()
it('works', function()
local out = exec_lua [[
_G.n_events = 0
vim.cmd('au ModeChanged * lua _G.n_events = _G.n_events + 1')
-- Should be the same as `vim.cmd('noautocmd normal! vv')`
vim._with({ noautocmd = true }, function()
vim.cmd('normal! vv')
end)
return _G.n_events
]]
eq(0, out)
end)
it('works with User events', function()
local out = exec_lua [[
_G.n_events = 0
vim.cmd('au User MyEvent lua _G.n_events = _G.n_events + 1')
-- Should be the same as `vim.cmd('noautocmd doautocmd User MyEvent')`
vim._with({ noautocmd = true }, function()
api.nvim_exec_autocmds('User', { pattern = 'MyEvent' })
end)
return _G.n_events
]]
eq(0, out)
end)
pending('can be nested', function()
local out = exec_lua [[
_G.n_events = 0
vim.cmd('au ModeChanged * lua _G.n_events = _G.n_events + 1')
vim._with({ noautocmd = true }, function()
vim._with({ noautocmd = false }, function()
vim.cmd('normal! vv')
end)
end)
return _G.n_events
]]
eq(2, out)
end)
end)
describe('`sandbox` context', function()
it('works', function()
local ok, err = pcall(
exec_lua,
[[
-- Should work as `vim.cmd('sandbox call append(0, "aaa")')`
vim._with({ sandbox = true }, function()
fn.append(0, 'aaa')
end)
]]
)
eq(false, ok)
matches('Not allowed in sandbox', err)
end)
it('can NOT be nested', function()
-- This behavior is intentionally different from other flags as allowing
-- disabling `sandbox` from nested function seems to be against the point
-- of using `sandbox` context in the first place
local ok, err = pcall(
exec_lua,
[[
vim._with({ sandbox = true }, function()
vim._with({ sandbox = false }, function()
fn.append(0, 'aaa')
end)
end)
]]
)
eq(false, ok)
matches('Not allowed in sandbox', err)
end)
end)
describe('`silent` context', function()
it('works', function()
exec_lua [[
-- Should be same as `vim.cmd('silent lua print("aaa")')`
vim._with({ silent = true }, function() print('aaa') end)
]]
eq('', exec_capture('messages'))
exec_lua [[ vim._with({ silent = true }, function() vim.cmd.echomsg('"bbb"') end) ]]
eq('', exec_capture('messages'))
local screen = Screen.new(20, 5)
screen:set_default_attr_ids {
[1] = { bold = true, reverse = true },
[2] = { bold = true, foreground = Screen.colors.Blue },
}
screen:attach()
exec_lua [[ vim._with({ silent = true }, function() vim.cmd.echo('"ccc"') end) ]]
screen:expect [[
^ |
{2:~ }|*3
|
]]
end)
pending('can be nested', function()
exec_lua [[ vim._with({ silent = true }, function()
vim._with({ silent = false }, function()
print('aaa')
end)
end)]]
eq('aaa', exec_capture('messages'))
end)
end)
describe('`unsilent` context', function()
it('works', function()
exec_lua [[
_G.f = function()
-- Should be same as `vim.cmd('unsilent lua print("aaa")')`
vim._with({ unsilent = true }, function() print('aaa') end)
end
]]
command('silent lua f()')
eq('aaa', exec_capture('messages'))
end)
pending('can be nested', function()
exec_lua [[
_G.f = function()
vim._with({ unsilent = true }, function()
vim._with({ unsilent = false }, function() print('aaa') end)
end)
end
]]
command('silent lua f()')
eq('', exec_capture('messages'))
end)
end)
describe('`win` context', function()
it('works', function()
local out = exec_lua [[
local other_win, cur_win = setup_windows()
local inner = vim._with({ win = other_win }, function()
return api.nvim_get_current_win()
end)
return { inner == other_win, api.nvim_get_current_win() == cur_win }
]]
eq({ true, true }, out)
end)
it('does not trigger events', function()
exec_lua [[
_G.test_events = { 'WinEnter', 'WinLeave', 'BufWinEnter', 'BufWinLeave' }
_G.test_context = { win = other_win }
_G.test_trig_event = function() vim.cmd.new() end
]]
validate_events_trigger()
end)
it('can access window options', function()
local out = exec_lua [[
local other_win, cur_win = setup_windows()
vim.wo[other_win].winblend = 10
vim.wo[cur_win].winblend = 25
vim._with({ win = other_win }, function()
vim.cmd.setlocal('winblend=0')
end)
return vim.wo[other_win].winblend == 0 and vim.wo[cur_win].winblend == 25
]]
eq(true, out)
end)
it('works with different kinds of windows', function()
exec_lua [[
local validate = function(win)
vim._with({ win = win }, function()
assert(api.nvim_get_current_win() == win)
end)
end
-- Current
validate(api.nvim_get_current_win())
-- Not visible
local other_win, cur_win = setup_windows()
vim.cmd.tabnew()
validate(other_win)
-- Floating
local float_win = api.nvim_open_win(
api.nvim_create_buf(false, true),
false,
{ relative = 'editor', row = 1, col = 1, height = 5, width = 5}
)
validate(float_win)
]]
end)
it('does not cause ml_get errors with invalid visual selection', function()
exec_lua [[
local feedkeys = function(keys) api.nvim_feedkeys(vim.keycode(keys), 'txn', false) end
-- Add lines to the current buffer and make another window looking into an empty buffer.
local win_empty, win_lines = setup_windows()
api.nvim_buf_set_lines(0, 0, -1, true, { 'a', 'b', 'c' })
-- Start Visual in current window, redraw in other window with fewer lines.
-- Should be fixed by vim-patch:8.2.4018.
feedkeys('G<C-V>')
vim._with({ win = win_empty }, function() vim.cmd.redraw() end)
-- Start Visual in current window, extend it in other window with more lines.
-- Fixed for win_execute by vim-patch:8.2.4026, but nvim_win_call should also not be affected.
feedkeys('<Esc>gg')
api.nvim_set_current_win(win_empty)
feedkeys('gg<C-V>')
vim._with({ win = win_lines }, function() feedkeys('G<C-V>') end)
vim.cmd.redraw()
]]
end)
it('can be nested', function()
exec_lua [[
local other_win, cur_win = setup_windows()
vim._with({ win = other_win }, function()
assert(api.nvim_get_current_win() == other_win)
inner = vim._with({ win = cur_win }, function()
assert(api.nvim_get_current_win() == cur_win)
end)
assert(api.nvim_get_current_win() == other_win)
end)
assert(api.nvim_get_current_win() == cur_win)
]]
end)
it('updates ruler if cursor moved', function()
local screen = Screen.new(30, 5)
screen:set_default_attr_ids {
[1] = { reverse = true },
[2] = { bold = true, reverse = true },
}
screen:attach()
exec_lua [[
vim.opt.ruler = true
local lines = {}
for i = 0, 499 do lines[#lines + 1] = tostring(i) end
api.nvim_buf_set_lines(0, 0, -1, true, lines)
api.nvim_win_set_cursor(0, { 20, 0 })
vim.cmd 'split'
_G.win = api.nvim_get_current_win()
vim.cmd "wincmd w | redraw"
]]
screen:expect [[
19 |
{1:[No Name] [+] 20,1 3%}|
^19 |
{2:[No Name] [+] 20,1 3%}|
|
]]
exec_lua [[
vim._with({ win = win }, function() api.nvim_win_set_cursor(0, { 100, 0 }) end)
vim.cmd "redraw"
]]
screen:expect [[
99 |
{1:[No Name] [+] 100,1 19%}|
^19 |
{2:[No Name] [+] 20,1 3%}|
|
]]
end)
it('layout in current tabpage does not affect windows in others', function()
command('tab split')
local t2_move_win = api.nvim_get_current_win()
command('vsplit')
local t2_other_win = api.nvim_get_current_win()
command('tabprevious')
matches('E36: Not enough room$', pcall_err(command, 'execute "split|"->repeat(&lines)'))
command('vsplit')
exec_lua('vim._with({ win = ... }, function() vim.cmd.wincmd "J" end)', t2_move_win)
eq({ 'col', { { 'leaf', t2_other_win }, { 'leaf', t2_move_win } } }, fn.winlayout(2))
end)
end)
it('returns what callback returns', function()
local out_verify = exec_lua [[
out = { vim._with({}, function()
return 'a', 2, nil, { 4 }, function() end
end) }
return {
out[1] == 'a', out[2] == 2, out[3] == nil,
vim.deep_equal(out[4], { 4 }),
type(out[5]) == 'function',
vim.tbl_count(out),
}
]]
eq({ true, true, true, true, true, 4 }, out_verify)
end)
it('can return values by reference', function()
local out = exec_lua [[
local val = { 4, 10 }
local ref = vim._with({}, function() return val end)
ref[1] = 7
return val
]]
eq({ 7, 10 }, out)
end)
it('can not work with conflicting `buf` and `win`', function()
local out = exec_lua [[
local other_buf, cur_buf = setup_buffers()
local other_win, cur_win = setup_windows()
assert(api.nvim_win_get_buf(other_win) ~= other_buf)
local _, err = pcall(vim._with, { buf = other_buf, win = other_win }, function() end)
return err
]]
matches('Can not set both `buf` and `win`', out)
end)
pending('can forward command modifiers to user command', function()
local out = exec_lua [[
local test_flags = {
'emsg_silent',
'hide',
'keepalt',
'keepjumps',
'keepmarks',
'keeppatterns',
'lockmarks',
'noautocmd',
'silent',
'unsilent',
}
local used_smods
local command = function(data)
used_smods = data.smods
end
api.nvim_create_user_command('DummyLog', command, {})
local res = {}
for _, flag in ipairs(test_flags) do
used_smods = nil
vim._with({ [flag] = true }, function() vim.cmd('DummyLog') end)
res[flag] = used_smods[flag]
end
return res
]]
for k, v in pairs(out) do
eq({ k, true }, { k, v })
end
end)
it('handles error in callback', function()
-- Should still restore initial context
local out_buf = exec_lua [[
local other_buf, cur_buf = setup_buffers()
local context = { buf = other_buf }
local ok, err = pcall(vim._with, context, function() error('Oops buf', 0) end)
return {
ok,
err,
api.nvim_get_current_buf() == cur_buf,
}
]]
eq({ false, 'Oops buf', true }, out_buf)
local out_win = exec_lua [[
local other_win, cur_win = setup_windows()
vim.wo[other_win].winblend = 25
local context = { win = other_win, wo = { winblend = 50 } }
local ok, err = pcall(vim._with, context, function() error('Oops win', 0) end)
return {
ok,
err,
api.nvim_get_current_win() == cur_win,
vim.wo[other_win].winblend,
}
]]
eq({ false, 'Oops win', true, 25 }, out_win)
end)
it('validates arguments', function()
exec_lua [[
_G.get_error = function(...)
local _, err = pcall(vim._with, ...)
return err or ''
end
]]
local get_error = function(string_args)
return exec_lua('return get_error(' .. string_args .. ')')
end
matches('context.*table', get_error("'a', function() end"))
matches('f.*function', get_error('{}, 1'))
local validate_context = function(bad_context, expected_type)
local bad_field = vim.tbl_keys(bad_context)[1]
matches(
'context%.' .. bad_field .. '.*' .. expected_type,
get_error(vim.inspect(bad_context) .. ', function() end')
)
end
validate_context({ buf = 'a' }, 'number')
validate_context({ emsg_silent = 1 }, 'boolean')
validate_context({ hide = 1 }, 'boolean')
validate_context({ keepalt = 1 }, 'boolean')
validate_context({ keepjumps = 1 }, 'boolean')
validate_context({ keepmarks = 1 }, 'boolean')
validate_context({ keeppatterns = 1 }, 'boolean')
validate_context({ lockmarks = 1 }, 'boolean')
validate_context({ noautocmd = 1 }, 'boolean')
validate_context({ sandbox = 1 }, 'boolean')
validate_context({ silent = 1 }, 'boolean')
validate_context({ unsilent = 1 }, 'boolean')
validate_context({ win = 'a' }, 'number')
matches('Invalid buffer', get_error('{ buf = -1 }, function() end'))
matches('Invalid window', get_error('{ win = -1 }, function() end'))
end)
end)