aboutsummaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/CMakeLists.txt96
-rw-r--r--test/busted_runner.lua11
-rw-r--r--test/client/msgpack_rpc_stream.lua112
-rw-r--r--test/client/session.lua192
-rw-r--r--test/client/uv_stream.lua169
-rw-r--r--test/functional/api/autocmd_spec.lua116
-rw-r--r--test/functional/api/buffer_spec.lua20
-rw-r--r--test/functional/api/buffer_updates_spec.lua2
-rw-r--r--test/functional/api/command_spec.lua2
-rw-r--r--test/functional/api/extmark_spec.lua14
-rw-r--r--test/functional/api/highlight_spec.lua67
-rw-r--r--test/functional/api/proc_spec.lua4
-rw-r--r--test/functional/api/rpc_fixture.lua7
-rw-r--r--test/functional/api/server_requests_spec.lua17
-rw-r--r--test/functional/api/ui_spec.lua26
-rw-r--r--test/functional/api/vim_spec.lua58
-rw-r--r--test/functional/core/exit_spec.lua32
-rw-r--r--test/functional/ex_cmds/oldfiles_spec.lua5
-rw-r--r--test/functional/ex_cmds/profile_spec.lua1
-rw-r--r--test/functional/ex_cmds/swapfile_preserve_recover_spec.lua63
-rw-r--r--test/functional/helpers.lua16
-rw-r--r--test/functional/legacy/move_spec.lua49
-rw-r--r--test/functional/lua/api_spec.lua2
-rw-r--r--test/functional/lua/filetype_spec.lua20
-rw-r--r--test/functional/lua/vim_spec.lua4
-rw-r--r--test/functional/shada/helpers.lua1
-rw-r--r--test/functional/shada/history_spec.lua1
-rw-r--r--test/functional/shada/shada_spec.lua42
-rw-r--r--test/functional/terminal/tui_spec.lua37
-rw-r--r--test/functional/treesitter/language_spec.lua2
-rw-r--r--test/functional/treesitter/parser_spec.lua8
-rw-r--r--test/functional/ui/bufhl_spec.lua4
-rw-r--r--test/functional/ui/decorations_spec.lua14
-rw-r--r--test/functional/ui/fold_spec.lua132
-rw-r--r--test/functional/ui/screen.lua2
-rw-r--r--test/functional/ui/screen_basic_spec.lua81
-rw-r--r--test/functional/ui/searchhl_spec.lua29
-rw-r--r--test/functional/ui/statuscolumn_spec.lua2
-rw-r--r--test/helpers.lua2
39 files changed, 1186 insertions, 276 deletions
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
new file mode 100644
index 0000000000..dc74838760
--- /dev/null
+++ b/test/CMakeLists.txt
@@ -0,0 +1,96 @@
+add_subdirectory(functional/fixtures) # compile test programs
+get_directory_property(GENERATED_HELP_TAGS DIRECTORY ${PROJECT_SOURCE_DIR}/runtime DEFINITION GENERATED_HELP_TAGS)
+
+if(NOT BUSTED_OUTPUT_TYPE)
+ set(BUSTED_OUTPUT_TYPE "nvim")
+endif()
+
+find_program(BUSTED_PRG NAMES busted busted.bat)
+if(BUSTED_PRG)
+ get_target_property(TEST_INCLUDE_DIRS main_lib INTERFACE_INCLUDE_DIRECTORIES)
+
+ set(UNITTEST_PREREQS nvim)
+ set(FUNCTIONALTEST_PREREQS nvim printenv-test printargs-test shell-test pwsh-test streams-test tty-test ${GENERATED_HELP_TAGS})
+ set(BENCHMARK_PREREQS nvim tty-test)
+
+ check_lua_module(${LUA_PRG} "ffi" LUA_HAS_FFI)
+ if(LUA_HAS_FFI)
+ add_custom_target(unittest
+ COMMAND ${CMAKE_COMMAND}
+ -D BUSTED_PRG=${BUSTED_PRG}
+ -D LUA_PRG=${LUA_PRG}
+ -D NVIM_PRG=$<TARGET_FILE:nvim>
+ -D WORKING_DIR=${PROJECT_SOURCE_DIR}
+ -D BUSTED_OUTPUT_TYPE=${BUSTED_OUTPUT_TYPE}
+ -D TEST_DIR=${CMAKE_CURRENT_SOURCE_DIR}
+ -D BUILD_DIR=${CMAKE_BINARY_DIR}
+ -D TEST_TYPE=unit
+ -D CIRRUS_CI=$ENV{CIRRUS_CI}
+ -D CI_BUILD=${CI_BUILD}
+ -P ${PROJECT_SOURCE_DIR}/cmake/RunTests.cmake
+ DEPENDS ${UNITTEST_PREREQS}
+ USES_TERMINAL)
+ set_target_properties(unittest PROPERTIES FOLDER test)
+ else()
+ message(WARNING "disabling unit tests: no Luajit FFI in ${LUA_PRG}")
+ endif()
+
+ configure_file(
+ ${CMAKE_SOURCE_DIR}/test/cmakeconfig/paths.lua.in
+ ${CMAKE_BINARY_DIR}/test/cmakeconfig/paths.lua)
+
+ add_custom_target(functionaltest
+ COMMAND ${CMAKE_COMMAND}
+ -D BUSTED_PRG=${BUSTED_PRG}
+ -D LUA_PRG=${LUA_PRG}
+ -D NVIM_PRG=$<TARGET_FILE:nvim>
+ -D WORKING_DIR=${PROJECT_SOURCE_DIR}
+ -D BUSTED_OUTPUT_TYPE=${BUSTED_OUTPUT_TYPE}
+ -D TEST_DIR=${CMAKE_CURRENT_SOURCE_DIR}
+ -D BUILD_DIR=${CMAKE_BINARY_DIR}
+ -D DEPS_PREFIX=${DEPS_PREFIX}
+ -D TEST_TYPE=functional
+ -D CIRRUS_CI=$ENV{CIRRUS_CI}
+ -D CI_BUILD=${CI_BUILD}
+ -P ${PROJECT_SOURCE_DIR}/cmake/RunTests.cmake
+ DEPENDS ${FUNCTIONALTEST_PREREQS}
+ USES_TERMINAL)
+ set_target_properties(functionaltest PROPERTIES FOLDER test)
+
+ add_custom_target(benchmark
+ COMMAND ${CMAKE_COMMAND}
+ -D BUSTED_PRG=${BUSTED_PRG}
+ -D LUA_PRG=${LUA_PRG}
+ -D NVIM_PRG=$<TARGET_FILE:nvim>
+ -D WORKING_DIR=${PROJECT_SOURCE_DIR}
+ -D BUSTED_OUTPUT_TYPE=${BUSTED_OUTPUT_TYPE}
+ -D TEST_DIR=${CMAKE_CURRENT_SOURCE_DIR}
+ -D BUILD_DIR=${CMAKE_BINARY_DIR}
+ -D TEST_TYPE=benchmark
+ -D CIRRUS_CI=$ENV{CIRRUS_CI}
+ -D CI_BUILD=${CI_BUILD}
+ -P ${PROJECT_SOURCE_DIR}/cmake/RunTests.cmake
+ DEPENDS ${BENCHMARK_PREREQS}
+ USES_TERMINAL)
+ set_target_properties(benchmark PROPERTIES FOLDER test)
+endif()
+
+find_program(BUSTED_LUA_PRG busted-lua)
+if(BUSTED_LUA_PRG)
+ add_custom_target(functionaltest-lua
+ COMMAND ${CMAKE_COMMAND}
+ -D BUSTED_PRG=${BUSTED_LUA_PRG}
+ -D LUA_PRG=${LUA_PRG}
+ -D NVIM_PRG=$<TARGET_FILE:nvim>
+ -D WORKING_DIR=${PROJECT_SOURCE_DIR}
+ -D BUSTED_OUTPUT_TYPE=${BUSTED_OUTPUT_TYPE}
+ -D TEST_DIR=${CMAKE_CURRENT_SOURCE_DIR}
+ -D BUILD_DIR=${CMAKE_BINARY_DIR}
+ -D TEST_TYPE=functional
+ -D CIRRUS_CI=$ENV{CIRRUS_CI}
+ -D CI_BUILD=${CI_BUILD}
+ -P ${PROJECT_SOURCE_DIR}/cmake/RunTests.cmake
+ DEPENDS ${FUNCTIONALTEST_PREREQS}
+ USES_TERMINAL)
+ set_target_properties(functionaltest-lua PROPERTIES FOLDER test)
+endif()
diff --git a/test/busted_runner.lua b/test/busted_runner.lua
index b195ce3cc5..62d1e611e7 100644
--- a/test/busted_runner.lua
+++ b/test/busted_runner.lua
@@ -1 +1,12 @@
+local platform = vim.loop.os_uname()
+if platform and platform.sysname:lower():find'windows' then
+ local deps_prefix = os.getenv 'DEPS_PREFIX'
+ if deps_prefix ~= nil and deps_prefix ~= "" then
+ package.path = deps_prefix.."/share/lua/5.1/?.lua;"..deps_prefix.."/share/lua/5.1/?/init.lua;"..package.path
+ package.path = deps_prefix.."/bin/lua/?.lua;"..deps_prefix.."/bin/lua/?/init.lua;"..package.path
+ package.cpath = deps_prefix.."/lib/lua/5.1/?.dll;"..package.cpath;
+ package.cpath = deps_prefix.."/bin/?.dll;"..deps_prefix.."/bin/loadall.dll;"..package.cpath;
+ end
+end
+
require 'busted.runner'({ standalone = false })
diff --git a/test/client/msgpack_rpc_stream.lua b/test/client/msgpack_rpc_stream.lua
new file mode 100644
index 0000000000..5711616b17
--- /dev/null
+++ b/test/client/msgpack_rpc_stream.lua
@@ -0,0 +1,112 @@
+local mpack = require('mpack')
+
+-- temporary hack to be able to manipulate buffer/window/tabpage
+local Buffer = {}
+Buffer.__index = Buffer
+function Buffer.new(id) return setmetatable({id=id}, Buffer) end
+local Window = {}
+Window.__index = Window
+function Window.new(id) return setmetatable({id=id}, Window) end
+local Tabpage = {}
+Tabpage.__index = Tabpage
+function Tabpage.new(id) return setmetatable({id=id}, Tabpage) end
+
+local Response = {}
+Response.__index = Response
+
+function Response.new(msgpack_rpc_stream, request_id)
+ return setmetatable({
+ _msgpack_rpc_stream = msgpack_rpc_stream,
+ _request_id = request_id
+ }, Response)
+end
+
+function Response:send(value, is_error)
+ local data = self._msgpack_rpc_stream._session:reply(self._request_id)
+ if is_error then
+ data = data .. self._msgpack_rpc_stream._pack(value)
+ data = data .. self._msgpack_rpc_stream._pack(mpack.NIL)
+ else
+ data = data .. self._msgpack_rpc_stream._pack(mpack.NIL)
+ data = data .. self._msgpack_rpc_stream._pack(value)
+ end
+ self._msgpack_rpc_stream._stream:write(data)
+end
+
+local MsgpackRpcStream = {}
+MsgpackRpcStream.__index = MsgpackRpcStream
+
+function MsgpackRpcStream.new(stream)
+ return setmetatable({
+ _stream = stream,
+ _pack = mpack.Packer({
+ ext = {
+ [Buffer] = function(o) return 0, mpack.encode(o.id) end,
+ [Window] = function(o) return 1, mpack.encode(o.id) end,
+ [Tabpage] = function(o) return 2, mpack.encode(o.id) end
+ }
+ }),
+ _session = mpack.Session({
+ unpack = mpack.Unpacker({
+ ext = {
+ [0] = function(_c, s) return Buffer.new(mpack.decode(s)) end,
+ [1] = function(_c, s) return Window.new(mpack.decode(s)) end,
+ [2] = function(_c, s) return Tabpage.new(mpack.decode(s)) end
+ }
+ })
+ }),
+ }, MsgpackRpcStream)
+end
+
+function MsgpackRpcStream:write(method, args, response_cb)
+ local data
+ if response_cb then
+ assert(type(response_cb) == 'function')
+ data = self._session:request(response_cb)
+ else
+ data = self._session:notify()
+ end
+
+ data = data .. self._pack(method) .. self._pack(args)
+ self._stream:write(data)
+end
+
+function MsgpackRpcStream:read_start(request_cb, notification_cb, eof_cb)
+ self._stream:read_start(function(data)
+ if not data then
+ return eof_cb()
+ end
+ local type, id_or_cb, method_or_error, args_or_result
+ local pos = 1
+ local len = #data
+ while pos <= len do
+ type, id_or_cb, method_or_error, args_or_result, pos =
+ self._session:receive(data, pos)
+ if type == 'request' or type == 'notification' then
+ if type == 'request' then
+ request_cb(method_or_error, args_or_result, Response.new(self,
+ id_or_cb))
+ else
+ notification_cb(method_or_error, args_or_result)
+ end
+ elseif type == 'response' then
+ if method_or_error == mpack.NIL then
+ method_or_error = nil
+ else
+ args_or_result = nil
+ end
+ id_or_cb(method_or_error, args_or_result)
+ end
+ end
+ end)
+end
+
+function MsgpackRpcStream:read_stop()
+ self._stream:read_stop()
+end
+
+function MsgpackRpcStream:close(signal)
+ self._stream:close(signal)
+end
+
+return MsgpackRpcStream
diff --git a/test/client/session.lua b/test/client/session.lua
new file mode 100644
index 0000000000..0509fa88be
--- /dev/null
+++ b/test/client/session.lua
@@ -0,0 +1,192 @@
+local uv = require('luv')
+local MsgpackRpcStream = require('test.client.msgpack_rpc_stream')
+
+local Session = {}
+Session.__index = Session
+if package.loaded['jit'] then
+ -- luajit pcall is already coroutine safe
+ Session.safe_pcall = pcall
+else
+ Session.safe_pcall = require'coxpcall'.pcall
+end
+
+local function resume(co, ...)
+ local status, result = coroutine.resume(co, ...)
+
+ if coroutine.status(co) == 'dead' then
+ if not status then
+ error(result)
+ end
+ return
+ end
+
+ assert(coroutine.status(co) == 'suspended')
+ result(co)
+end
+
+local function coroutine_exec(func, ...)
+ local args = {...}
+ local on_complete
+
+ if #args > 0 and type(args[#args]) == 'function' then
+ -- completion callback
+ on_complete = table.remove(args)
+ end
+
+ resume(coroutine.create(function()
+ local status, result, flag = Session.safe_pcall(func, unpack(args))
+ if on_complete then
+ coroutine.yield(function()
+ -- run the completion callback on the main thread
+ on_complete(status, result, flag)
+ end)
+ end
+ end))
+end
+
+function Session.new(stream)
+ return setmetatable({
+ _msgpack_rpc_stream = MsgpackRpcStream.new(stream),
+ _pending_messages = {},
+ _prepare = uv.new_prepare(),
+ _timer = uv.new_timer(),
+ _is_running = false
+ }, Session)
+end
+
+function Session:next_message(timeout)
+ local function on_request(method, args, response)
+ table.insert(self._pending_messages, {'request', method, args, response})
+ uv.stop()
+ end
+
+ local function on_notification(method, args)
+ table.insert(self._pending_messages, {'notification', method, args})
+ uv.stop()
+ end
+
+ if self._is_running then
+ error('Event loop already running')
+ end
+
+ if #self._pending_messages > 0 then
+ return table.remove(self._pending_messages, 1)
+ end
+
+ self:_run(on_request, on_notification, timeout)
+ return table.remove(self._pending_messages, 1)
+end
+
+function Session:notify(method, ...)
+ self._msgpack_rpc_stream:write(method, {...})
+end
+
+function Session:request(method, ...)
+ local args = {...}
+ local err, result
+ if self._is_running then
+ err, result = self:_yielding_request(method, args)
+ else
+ err, result = self:_blocking_request(method, args)
+ end
+
+ if err then
+ return false, err
+ end
+
+ return true, result
+end
+
+function Session:run(request_cb, notification_cb, setup_cb, timeout)
+ local function on_request(method, args, response)
+ coroutine_exec(request_cb, method, args, function(status, result, flag)
+ if status then
+ response:send(result, flag)
+ else
+ response:send(result, true)
+ end
+ end)
+ end
+
+ local function on_notification(method, args)
+ coroutine_exec(notification_cb, method, args)
+ end
+
+ self._is_running = true
+
+ if setup_cb then
+ coroutine_exec(setup_cb)
+ end
+
+ while #self._pending_messages > 0 do
+ local msg = table.remove(self._pending_messages, 1)
+ if msg[1] == 'request' then
+ on_request(msg[2], msg[3], msg[4])
+ else
+ on_notification(msg[2], msg[3])
+ end
+ end
+
+ self:_run(on_request, on_notification, timeout)
+ self._is_running = false
+end
+
+function Session:stop()
+ uv.stop()
+end
+
+function Session:close(signal)
+ if not self._timer:is_closing() then self._timer:close() end
+ if not self._prepare:is_closing() then self._prepare:close() end
+ self._msgpack_rpc_stream:close(signal)
+end
+
+function Session:_yielding_request(method, args)
+ return coroutine.yield(function(co)
+ self._msgpack_rpc_stream:write(method, args, function(err, result)
+ resume(co, err, result)
+ end)
+ end)
+end
+
+function Session:_blocking_request(method, args)
+ local err, result
+
+ local function on_request(method_, args_, response)
+ table.insert(self._pending_messages, {'request', method_, args_, response})
+ end
+
+ local function on_notification(method_, args_)
+ table.insert(self._pending_messages, {'notification', method_, args_})
+ end
+
+ self._msgpack_rpc_stream:write(method, args, function(e, r)
+ err = e
+ result = r
+ uv.stop()
+ end)
+
+ self:_run(on_request, on_notification)
+ return (err or self.eof_err), result
+end
+
+function Session:_run(request_cb, notification_cb, timeout)
+ if type(timeout) == 'number' then
+ self._prepare:start(function()
+ self._timer:start(timeout, 0, function()
+ uv.stop()
+ end)
+ self._prepare:stop()
+ end)
+ end
+ self._msgpack_rpc_stream:read_start(request_cb, notification_cb, function()
+ uv.stop()
+ self.eof_err = {1, "EOF was received from Nvim. Likely the Nvim process crashed."}
+ end)
+ uv.run()
+ self._prepare:stop()
+ self._timer:stop()
+ self._msgpack_rpc_stream:read_stop()
+end
+
+return Session
diff --git a/test/client/uv_stream.lua b/test/client/uv_stream.lua
new file mode 100644
index 0000000000..cea77f0dbd
--- /dev/null
+++ b/test/client/uv_stream.lua
@@ -0,0 +1,169 @@
+local uv = require('luv')
+
+local StdioStream = {}
+StdioStream.__index = StdioStream
+
+function StdioStream.open()
+ local self = setmetatable({
+ _in = uv.new_pipe(false),
+ _out = uv.new_pipe(false)
+ }, StdioStream)
+ self._in:open(0)
+ self._out:open(1)
+ return self
+end
+
+function StdioStream:write(data)
+ self._out:write(data)
+end
+
+function StdioStream:read_start(cb)
+ self._in:read_start(function(err, chunk)
+ if err then
+ error(err)
+ end
+ cb(chunk)
+ end)
+end
+
+function StdioStream:read_stop()
+ self._in:read_stop()
+end
+
+function StdioStream:close()
+ self._in:close()
+ self._out:close()
+end
+
+local SocketStream = {}
+SocketStream.__index = SocketStream
+
+function SocketStream.open(file)
+ local socket = uv.new_pipe(false)
+ local self = setmetatable({
+ _socket = socket,
+ _stream_error = nil
+ }, SocketStream)
+ uv.pipe_connect(socket, file, function (err)
+ self._stream_error = self._stream_error or err
+ end)
+ return self
+end
+
+function SocketStream.connect(host, port)
+ local socket = uv.new_tcp()
+ local self = setmetatable({
+ _socket = socket,
+ _stream_error = nil
+ }, SocketStream)
+ uv.tcp_connect(socket, host, port, function (err)
+ self._stream_error = self._stream_error or err
+ end)
+ return self
+end
+
+
+function SocketStream:write(data)
+ if self._stream_error then
+ error(self._stream_error)
+ end
+ uv.write(self._socket, data, function(err)
+ if err then
+ error(self._stream_error or err)
+ end
+ end)
+end
+
+function SocketStream:read_start(cb)
+ if self._stream_error then
+ error(self._stream_error)
+ end
+ uv.read_start(self._socket, function(err, chunk)
+ if err then
+ error(err)
+ end
+ cb(chunk)
+ end)
+end
+
+function SocketStream:read_stop()
+ if self._stream_error then
+ error(self._stream_error)
+ end
+ uv.read_stop(self._socket)
+end
+
+function SocketStream:close()
+ uv.close(self._socket)
+end
+
+local ChildProcessStream = {}
+ChildProcessStream.__index = ChildProcessStream
+
+function ChildProcessStream.spawn(argv, env, io_extra)
+ local self = setmetatable({
+ _child_stdin = uv.new_pipe(false);
+ _child_stdout = uv.new_pipe(false);
+ _exiting = false;
+ }, ChildProcessStream)
+ local prog = argv[1]
+ local args = {}
+ for i = 2, #argv do
+ args[#args + 1] = argv[i]
+ end
+ self._proc, self._pid = uv.spawn(prog, {
+ stdio = {self._child_stdin, self._child_stdout, 2, io_extra},
+ args = args,
+ env = env,
+ }, function(status, signal)
+ self.status = status
+ self.signal = signal
+ end)
+
+ if not self._proc then
+ local err = self._pid
+ error(err)
+ end
+
+ return self
+end
+
+function ChildProcessStream:write(data)
+ self._child_stdin:write(data)
+end
+
+function ChildProcessStream:read_start(cb)
+ self._child_stdout:read_start(function(err, chunk)
+ if err then
+ error(err)
+ end
+ cb(chunk)
+ end)
+end
+
+function ChildProcessStream:read_stop()
+ self._child_stdout:read_stop()
+end
+
+function ChildProcessStream:close(signal)
+ if self._closed then
+ return
+ end
+ self._closed = true
+ self:read_stop()
+ self._child_stdin:close()
+ self._child_stdout:close()
+ if type(signal) == 'string' then
+ self._proc:kill('sig'..signal)
+ end
+ while self.status == nil do
+ uv.run 'once'
+ end
+ return self.status, self.signal
+end
+
+return {
+ StdioStream = StdioStream;
+ ChildProcessStream = ChildProcessStream;
+ SocketStream = SocketStream;
+}
diff --git a/test/functional/api/autocmd_spec.lua b/test/functional/api/autocmd_spec.lua
index 22a1311ee9..f10f18174e 100644
--- a/test/functional/api/autocmd_spec.lua
+++ b/test/functional/api/autocmd_spec.lua
@@ -14,14 +14,31 @@ before_each(clear)
describe('autocmd api', function()
describe('nvim_create_autocmd', function()
- it('"command" and "callback" are mutually exclusive', function()
- local rv = pcall_err(meths.create_autocmd, "BufReadPost", {
- pattern = "*.py,*.pyi",
+ it('validation', function()
+ eq("Cannot use both 'callback' and 'command'", pcall_err(meths.create_autocmd, 'BufReadPost', {
+ pattern = '*.py,*.pyi',
command = "echo 'Should Have Errored",
- callback = "NotAllowed",
- })
-
- eq("specify either 'callback' or 'command', not both", rv)
+ callback = 'NotAllowed',
+ }))
+ eq("Cannot use both 'pattern' and 'buffer' for the same autocmd", pcall_err(meths.create_autocmd, 'FileType', {
+ command = 'let g:called = g:called + 1',
+ buffer = 0,
+ pattern = '*.py',
+ }))
+ eq("Required: 'event'", pcall_err(meths.create_autocmd, {}, {
+ command = 'ls',
+ }))
+ eq("Required: 'command' or 'callback'", pcall_err(meths.create_autocmd, 'FileType', {
+ }))
+ eq('Invalid desc: expected String, got Integer', pcall_err(meths.create_autocmd, 'FileType', {
+ command = 'ls',
+ desc = 42,
+ }))
+ eq('Invalid callback: expected Lua function or Vim function name, got Integer', pcall_err(meths.create_autocmd, 'FileType', {
+ callback = 0,
+ }))
+ eq("Invalid 'event' item: expected String, got Array", pcall_err(meths.create_autocmd,
+ {'FileType', {}}, {}))
end)
it('doesnt leak when you use ++once', function()
@@ -59,18 +76,8 @@ describe('autocmd api', function()
eq(1, meths.get_var('called'))
end)
- it('does not allow passing buffer and patterns', function()
- local rv = pcall_err(meths.create_autocmd, "Filetype", {
- command = "let g:called = g:called + 1",
- buffer = 0,
- pattern = "*.py",
- })
-
- eq("cannot pass both: 'pattern' and 'buffer' for the same autocmd", rv)
- end)
-
it('does not allow passing invalid buffers', function()
- local ok, msg = pcall(meths.create_autocmd, "Filetype", {
+ local ok, msg = pcall(meths.create_autocmd, 'FileType', {
command = "let g:called = g:called + 1",
buffer = -1,
})
@@ -295,7 +302,7 @@ describe('autocmd api', function()
describe('nvim_get_autocmds', function()
describe('events', function()
- it('should return one autocmd when there is only one for an event', function()
+ it('returns one autocmd when there is only one for an event', function()
command [[au! InsertEnter]]
command [[au InsertEnter * :echo "1"]]
@@ -303,7 +310,7 @@ describe('autocmd api', function()
eq(1, #aus)
end)
- it('should return two autocmds when there are two for an event', function()
+ it('returns two autocmds when there are two for an event', function()
command [[au! InsertEnter]]
command [[au InsertEnter * :echo "1"]]
command [[au InsertEnter * :echo "2"]]
@@ -312,7 +319,7 @@ describe('autocmd api', function()
eq(2, #aus)
end)
- it('should return the same thing if you use string or list', function()
+ it('returns the same thing if you use string or list', function()
command [[au! InsertEnter]]
command [[au InsertEnter * :echo "1"]]
command [[au InsertEnter * :echo "2"]]
@@ -322,7 +329,7 @@ describe('autocmd api', function()
eq(string_aus, array_aus)
end)
- it('should return two autocmds when there are two for an event', function()
+ it('returns two autocmds when there are two for an event', function()
command [[au! InsertEnter]]
command [[au! InsertLeave]]
command [[au InsertEnter * :echo "1"]]
@@ -332,7 +339,7 @@ describe('autocmd api', function()
eq(2, #aus)
end)
- it('should return different IDs for different autocmds', function()
+ it('returns different IDs for different autocmds', function()
command [[au! InsertEnter]]
command [[au! InsertLeave]]
command [[au InsertEnter * :echo "1"]]
@@ -356,7 +363,7 @@ describe('autocmd api', function()
eq(first, new_aus[1])
end)
- it('should return event name', function()
+ it('returns event name', function()
command [[au! InsertEnter]]
command [[au InsertEnter * :echo "1"]]
@@ -364,7 +371,7 @@ describe('autocmd api', function()
eq({ { buflocal = false, command = ':echo "1"', event = "InsertEnter", once = false, pattern = "*" } }, aus)
end)
- it('should work with buffer numbers', function()
+ it('works with buffer numbers', function()
command [[new]]
command [[au! InsertEnter]]
command [[au InsertEnter <buffer=1> :echo "1"]]
@@ -407,8 +414,8 @@ describe('autocmd api', function()
pattern = "<buffer=2>",
}}, aus)
- eq("Invalid value for 'buffer': must be an integer or array of integers", pcall_err(meths.get_autocmds, { event = "InsertEnter", buffer = "foo" }))
- eq("Invalid value for 'buffer': must be an integer", pcall_err(meths.get_autocmds, { event = "InsertEnter", buffer = { "foo", 42 } }))
+ eq("Invalid buffer: expected Integer or Array, got String", pcall_err(meths.get_autocmds, { event = "InsertEnter", buffer = "foo" }))
+ eq("Invalid buffer: expected Integer, got String", pcall_err(meths.get_autocmds, { event = "InsertEnter", buffer = { "foo", 42 } }))
eq("Invalid buffer id: 42", pcall_err(meths.get_autocmds, { event = "InsertEnter", buffer = { 42 } }))
local bufs = {}
@@ -416,10 +423,10 @@ describe('autocmd api', function()
table.insert(bufs, meths.create_buf(true, false))
end
- eq("Too many buffers. Please limit yourself to 256 or fewer", pcall_err(meths.get_autocmds, { event = "InsertEnter", buffer = bufs }))
+ eq("Too many buffers (maximum of 256)", pcall_err(meths.get_autocmds, { event = "InsertEnter", buffer = bufs }))
end)
- it('should return autocmds when group is specified by id', function()
+ it('returns autocmds when group is specified by id', function()
local auid = meths.create_augroup("nvim_test_augroup", { clear = true })
meths.create_autocmd("FileType", { group = auid, command = 'echo "1"' })
meths.create_autocmd("FileType", { group = auid, command = 'echo "2"' })
@@ -431,7 +438,7 @@ describe('autocmd api', function()
eq(0, #aus2)
end)
- it('should return autocmds when group is specified by name', function()
+ it('returns autocmds when group is specified by name', function()
local auname = "nvim_test_augroup"
meths.create_augroup(auname, { clear = true })
meths.create_autocmd("FileType", { group = auname, command = 'echo "1"' })
@@ -531,7 +538,7 @@ describe('autocmd api', function()
command [[augroup END]]
end)
- it('should return all groups if no group is specified', function()
+ it('returns all groups if no group is specified', function()
local aus = meths.get_autocmds { event = "InsertEnter" }
if #aus ~= 4 then
eq({}, aus)
@@ -540,7 +547,7 @@ describe('autocmd api', function()
eq(4, #aus)
end)
- it('should return only the group specified', function()
+ it('returns only the group specified', function()
local aus = meths.get_autocmds {
event = "InsertEnter",
group = "GroupOne",
@@ -551,7 +558,7 @@ describe('autocmd api', function()
eq("GroupOne", aus[1].group_name)
end)
- it('should return only the group specified, multiple values', function()
+ it('returns only the group specified, multiple values', function()
local aus = meths.get_autocmds {
event = "InsertEnter",
group = "GroupTwo",
@@ -578,7 +585,7 @@ describe('autocmd api', function()
]], {}))
eq(false, success)
- matches('invalid augroup: NotDefined', code)
+ matches("Invalid group: 'NotDefined'", code)
end)
it('raises error for undefined augroup id', function()
@@ -596,7 +603,7 @@ describe('autocmd api', function()
]], {}))
eq(false, success)
- matches('invalid augroup: 1', code)
+ matches('Invalid group: 1', code)
end)
it('raises error for invalid group type', function()
@@ -611,7 +618,7 @@ describe('autocmd api', function()
]], {}))
eq(false, success)
- matches("'group' must be a string or an integer", code)
+ matches("Invalid group: expected String or Integer, got Boolean", code)
end)
it('raises error for invalid pattern array', function()
@@ -625,7 +632,7 @@ describe('autocmd api', function()
]], {}))
eq(false, success)
- matches("All entries in 'pattern' must be strings", code)
+ matches("Invalid 'pattern' item: expected String, got Array", code)
end)
end)
@@ -640,7 +647,7 @@ describe('autocmd api', function()
command [[au InsertEnter <buffer> :echo "Buffer"]]
end)
- it('should should return for literal match', function()
+ it('returns for literal match', function()
local aus = meths.get_autocmds {
event = "InsertEnter",
pattern = "*"
@@ -650,7 +657,7 @@ describe('autocmd api', function()
eq([[:echo "No Group"]], aus[1].command)
end)
- it('should return for multiple matches', function()
+ it('returns for multiple matches', function()
-- vim.api.nvim_get_autocmds
local aus = meths.get_autocmds {
event = "InsertEnter",
@@ -687,6 +694,23 @@ describe('autocmd api', function()
end)
describe('nvim_exec_autocmds', function()
+ it('validation', function()
+ eq('Invalid group: 9997999', pcall_err(meths.exec_autocmds, 'FileType', {
+ group = 9997999,
+ }))
+ eq("Invalid group: 'bogus'", pcall_err(meths.exec_autocmds, 'FileType', {
+ group = 'bogus',
+ }))
+ eq('Invalid group: expected String or Integer, got Array', pcall_err(meths.exec_autocmds, 'FileType', {
+ group = {},
+ }))
+ eq('Invalid buffer: expected Integer, got Array', pcall_err(meths.exec_autocmds, 'FileType', {
+ buffer = {},
+ }))
+ eq("Invalid 'event' item: expected String, got Array", pcall_err(meths.exec_autocmds,
+ {'FileType', {}}, {}))
+ end)
+
it("can trigger builtin autocmds", function()
meths.set_var("autocmd_executed", false)
@@ -1036,7 +1060,7 @@ describe('autocmd api', function()
local augroup = "WillBeDeleted"
meths.create_augroup(augroup, { clear = true })
- meths.create_autocmd({"Filetype"}, {
+ meths.create_autocmd({"FileType"}, {
pattern = "*",
command = "echo 'does not matter'",
})
@@ -1055,7 +1079,7 @@ describe('autocmd api', function()
meths.set_var("value_set", false)
meths.create_augroup(augroup, { clear = true })
- meths.create_autocmd("Filetype", {
+ meths.create_autocmd("FileType", {
pattern = "<buffer>",
command = "let g:value_set = v:true",
})
@@ -1171,6 +1195,16 @@ describe('autocmd api', function()
end)
describe('nvim_clear_autocmds', function()
+ it('validation', function()
+ eq("Cannot use both 'pattern' and 'buffer'", pcall_err(meths.clear_autocmds, {
+ pattern = '*',
+ buffer = 42,
+ }))
+ eq("Invalid 'event' item: expected String, got Array", pcall_err(meths.clear_autocmds, {
+ event = {'FileType', {}}
+ }))
+ end)
+
it('should clear based on event + pattern', function()
command('autocmd InsertEnter *.py :echo "Python can be cool sometimes"')
command('autocmd InsertEnter *.txt :echo "Text Files Are Cool"')
diff --git a/test/functional/api/buffer_spec.lua b/test/functional/api/buffer_spec.lua
index 6b13729994..d454765edb 100644
--- a/test/functional/api/buffer_spec.lua
+++ b/test/functional/api/buffer_spec.lua
@@ -193,7 +193,7 @@ describe('api/buf', function()
it('fails correctly when input is not valid', function()
eq(1, api.curbufmeths.get_number())
- eq([[String cannot contain newlines]],
+ eq([['replacement string' item contains newlines]],
pcall_err(bufmeths.set_lines, 1, 1, 2, false, {'b\na'}))
end)
@@ -553,20 +553,20 @@ describe('api/buf', function()
insert([[
hello foo!
text]])
- eq('start_row out of bounds', pcall_err(set_text, 2, 0, 3, 0, {}))
- eq('start_row out of bounds', pcall_err(set_text, -3, 0, 0, 0, {}))
- eq('end_row out of bounds', pcall_err(set_text, 0, 0, 2, 0, {}))
- eq('end_row out of bounds', pcall_err(set_text, 0, 0, -3, 0, {}))
- eq('start_col out of bounds', pcall_err(set_text, 1, 5, 1, 5, {}))
- eq('end_col out of bounds', pcall_err(set_text, 1, 0, 1, 5, {}))
+ eq("Invalid 'start_row': out of range", pcall_err(set_text, 2, 0, 3, 0, {}))
+ eq("Invalid 'start_row': out of range", pcall_err(set_text, -3, 0, 0, 0, {}))
+ eq("Invalid 'end_row': out of range", pcall_err(set_text, 0, 0, 2, 0, {}))
+ eq("Invalid 'end_row': out of range", pcall_err(set_text, 0, 0, -3, 0, {}))
+ eq("Invalid 'start_col': out of range", pcall_err(set_text, 1, 5, 1, 5, {}))
+ eq("Invalid 'end_col': out of range", pcall_err(set_text, 1, 0, 1, 5, {}))
end)
it('errors when start is greater than end', function()
insert([[
hello foo!
text]])
- eq('start is higher than end', pcall_err(set_text, 1, 0, 0, 0, {}))
- eq('start is higher than end', pcall_err(set_text, 0, 1, 0, 0, {}))
+ eq("'start' is higher than 'end'", pcall_err(set_text, 1, 0, 0, 0, {}))
+ eq("'start' is higher than 'end'", pcall_err(set_text, 0, 1, 0, 0, {}))
end)
it('no heap-use-after-free when called consecutively #19643', function()
@@ -611,7 +611,7 @@ describe('api/buf', function()
end)
it('errors when start is greater than end', function()
- eq('start is higher than end', pcall_err(get_text, 1, 0, 0, 0, {}))
+ eq("'start' is higher than 'end'", pcall_err(get_text, 1, 0, 0, 0, {}))
eq('start_col must be less than end_col', pcall_err(get_text, 0, 1, 0, 0, {}))
end)
end)
diff --git a/test/functional/api/buffer_updates_spec.lua b/test/functional/api/buffer_updates_spec.lua
index d5f06c8f1f..1510d31945 100644
--- a/test/functional/api/buffer_updates_spec.lua
+++ b/test/functional/api/buffer_updates_spec.lua
@@ -762,7 +762,7 @@ describe('API: buffer events:', function()
it('returns a proper error on nonempty options dict', function()
clear()
local b = editoriginal(false)
- eq("unexpected key: builtin", pcall_err(buffer, 'attach', b, false, {builtin="asfd"}))
+ eq("Invalid key: 'builtin'", pcall_err(buffer, 'attach', b, false, {builtin="asfd"}))
end)
it('nvim_buf_attach returns response after delay #8634', function()
diff --git a/test/functional/api/command_spec.lua b/test/functional/api/command_spec.lua
index d0fb26edc7..189f9d4f98 100644
--- a/test/functional/api/command_spec.lua
+++ b/test/functional/api/command_spec.lua
@@ -543,7 +543,7 @@ describe('nvim_create_user_command', function()
end)
it('does not allow invalid command names', function()
- matches("'name' must begin with an uppercase letter", pcall_err(exec_lua, [[
+ matches("Invalid command name %(must begin with an uppercase letter%): 'test'", pcall_err(exec_lua, [[
vim.api.nvim_create_user_command('test', 'echo "hi"', {})
]]))
diff --git a/test/functional/api/extmark_spec.lua b/test/functional/api/extmark_spec.lua
index 9902826c72..fab1557204 100644
--- a/test/functional/api/extmark_spec.lua
+++ b/test/functional/api/extmark_spec.lua
@@ -106,7 +106,7 @@ describe('API/extmarks', function()
end_col = 0,
end_row = 1
})
- eq("end_col value outside range",
+ eq("Invalid 'end_col': out of range",
pcall_err(set_extmark, ns, marks[2], 0, 0, { end_col = 1, end_row = 1 }))
end)
@@ -1344,10 +1344,10 @@ describe('API/extmarks', function()
it('throws consistent error codes', function()
local ns_invalid = ns2 + 1
- eq("Invalid ns_id", pcall_err(set_extmark, ns_invalid, marks[1], positions[1][1], positions[1][2]))
- eq("Invalid ns_id", pcall_err(curbufmeths.del_extmark, ns_invalid, marks[1]))
- eq("Invalid ns_id", pcall_err(get_extmarks, ns_invalid, positions[1], positions[2]))
- eq("Invalid ns_id", pcall_err(get_extmark_by_id, ns_invalid, marks[1]))
+ eq("Invalid ns_id: 3", pcall_err(set_extmark, ns_invalid, marks[1], positions[1][1], positions[1][2]))
+ eq("Invalid ns_id: 3", pcall_err(curbufmeths.del_extmark, ns_invalid, marks[1]))
+ eq("Invalid ns_id: 3", pcall_err(get_extmarks, ns_invalid, positions[1], positions[2]))
+ eq("Invalid ns_id: 3", pcall_err(get_extmark_by_id, ns_invalid, marks[1]))
end)
it('when col = line-length, set the mark on eol', function()
@@ -1362,13 +1362,13 @@ describe('API/extmarks', function()
it('when col = line-length, set the mark on eol', function()
local invalid_col = init_text:len() + 1
- eq("col value outside range", pcall_err(set_extmark, ns, marks[1], 0, invalid_col))
+ eq("Invalid 'col': out of range", pcall_err(set_extmark, ns, marks[1], 0, invalid_col))
end)
it('fails when line > line_count', function()
local invalid_col = init_text:len() + 1
local invalid_lnum = 3
- eq('line value outside range', pcall_err(set_extmark, ns, marks[1], invalid_lnum, invalid_col))
+ eq("Invalid 'line': out of range", pcall_err(set_extmark, ns, marks[1], invalid_lnum, invalid_col))
eq({}, get_extmark_by_id(ns, marks[1]))
end)
diff --git a/test/functional/api/highlight_spec.lua b/test/functional/api/highlight_spec.lua
index 7f044977cb..73551de42e 100644
--- a/test/functional/api/highlight_spec.lua
+++ b/test/functional/api/highlight_spec.lua
@@ -57,9 +57,7 @@ describe('API: highlight',function()
eq(expected_rgb, nvim("get_hl_by_id", hl_id, true))
-- Test invalid id.
- local err, emsg = pcall(meths.get_hl_by_id, 30000, false)
- eq(false, err)
- eq('Invalid highlight id: 30000', string.match(emsg, 'Invalid.*'))
+ eq('Invalid highlight id: 30000', pcall_err(meths.get_hl_by_id, 30000, false))
-- Test all highlight properties.
command('hi NewHighlight gui=underline,bold,italic,reverse,strikethrough,altfont,nocombine')
@@ -70,22 +68,14 @@ describe('API: highlight',function()
eq(expected_undercurl, nvim("get_hl_by_id", hl_id, true))
-- Test nil argument.
- err, emsg = pcall(meths.get_hl_by_id, { nil }, false)
- eq(false, err)
eq('Wrong type for argument 1 when calling nvim_get_hl_by_id, expecting Integer',
- string.match(emsg, 'Wrong.*'))
+ pcall_err(meths.get_hl_by_id, { nil }, false))
-- Test 0 argument.
- err, emsg = pcall(meths.get_hl_by_id, 0, false)
- eq(false, err)
- eq('Invalid highlight id: 0',
- string.match(emsg, 'Invalid.*'))
+ eq('Invalid highlight id: 0', pcall_err(meths.get_hl_by_id, 0, false))
-- Test -1 argument.
- err, emsg = pcall(meths.get_hl_by_id, -1, false)
- eq(false, err)
- eq('Invalid highlight id: -1',
- string.match(emsg, 'Invalid.*'))
+ eq('Invalid highlight id: -1', pcall_err(meths.get_hl_by_id, -1, false))
-- Test highlight group without ctermbg value.
command('hi Normal ctermfg=red ctermbg=yellow')
@@ -119,22 +109,16 @@ describe('API: highlight',function()
eq(expected_normal, nvim("get_hl_by_name", 'Normal', true))
-- Test invalid name.
- local err, emsg = pcall(meths.get_hl_by_name , 'unknown_highlight', false)
- eq(false, err)
- eq('Invalid highlight name: unknown_highlight',
- string.match(emsg, 'Invalid.*'))
+ eq("Invalid highlight name: 'unknown_highlight'",
+ pcall_err(meths.get_hl_by_name , 'unknown_highlight', false))
-- Test nil argument.
- err, emsg = pcall(meths.get_hl_by_name , { nil }, false)
- eq(false, err)
eq('Wrong type for argument 1 when calling nvim_get_hl_by_name, expecting String',
- string.match(emsg, 'Wrong.*'))
+ pcall_err(meths.get_hl_by_name , { nil }, false))
-- Test empty string argument.
- err, emsg = pcall(meths.get_hl_by_name , '', false)
- eq(false, err)
- eq('Invalid highlight name: ',
- string.match(emsg, 'Invalid.*'))
+ eq('Invalid highlight name',
+ pcall_err(meths.get_hl_by_name , '', false))
-- Test "standout" attribute. #8054
eq({ underline = true, },
@@ -155,7 +139,7 @@ describe('API: highlight',function()
it('nvim_get_hl_id_by_name', function()
-- precondition: use a hl group that does not yet exist
- eq('Invalid highlight name: Shrubbery', pcall_err(meths.get_hl_by_name, "Shrubbery", true))
+ eq("Invalid highlight name: 'Shrubbery'", pcall_err(meths.get_hl_by_name, "Shrubbery", true))
eq(0, funcs.hlID("Shrubbery"))
local hl_id = meths.get_hl_id_by_name("Shrubbery")
@@ -253,25 +237,32 @@ describe("API: set highlight", function()
before_each(clear)
- it ("can set gui highlight", function()
+ it('validation', function()
+ eq("Invalid 'blend': out of range",
+ pcall_err(meths.set_hl, 0, 'Test_hl3', {fg='#FF00FF', blend=999}))
+ eq("Invalid blend: expected Integer, got Array",
+ pcall_err(meths.set_hl, 0, 'Test_hl3', {fg='#FF00FF', blend={}}))
+ end)
+
+ it("can set gui highlight", function()
local ns = get_ns()
meths.set_hl(ns, 'Test_hl', highlight1)
eq(highlight1, meths.get_hl_by_name('Test_hl', true))
end)
- it ("can set cterm highlight", function()
+ it("can set cterm highlight", function()
local ns = get_ns()
meths.set_hl(ns, 'Test_hl', highlight2_config)
eq(highlight2_result, meths.get_hl_by_name('Test_hl', false))
end)
- it ("can set empty cterm attr", function()
+ it("can set empty cterm attr", function()
local ns = get_ns()
meths.set_hl(ns, 'Test_hl', { cterm = {} })
eq({}, meths.get_hl_by_name('Test_hl', false))
end)
- it ("cterm attr defaults to gui attr", function()
+ it("cterm attr defaults to gui attr", function()
local ns = get_ns()
meths.set_hl(ns, 'Test_hl', highlight1)
eq({
@@ -280,14 +271,14 @@ describe("API: set highlight", function()
}, meths.get_hl_by_name('Test_hl', false))
end)
- it ("can overwrite attr for cterm", function()
+ it("can overwrite attr for cterm", function()
local ns = get_ns()
meths.set_hl(ns, 'Test_hl', highlight3_config)
eq(highlight3_result_gui, meths.get_hl_by_name('Test_hl', true))
eq(highlight3_result_cterm, meths.get_hl_by_name('Test_hl', false))
end)
- it ("can set a highlight in the global namespace", function()
+ it("can set a highlight in the global namespace", function()
meths.set_hl(0, 'Test_hl', highlight2_config)
eq('Test_hl xxx cterm=underline,reverse ctermfg=8 ctermbg=15 gui=underline,reverse',
exec_capture('highlight Test_hl'))
@@ -307,7 +298,7 @@ describe("API: set highlight", function()
exec_capture('highlight Test_hl3'))
end)
- it ("can modify a highlight in the global namespace", function()
+ it("can modify a highlight in the global namespace", function()
meths.set_hl(0, 'Test_hl3', { bg = 'red', fg = 'blue'})
eq('Test_hl3 xxx guifg=Blue guibg=Red',
exec_capture('highlight Test_hl3'))
@@ -328,17 +319,17 @@ describe("API: set highlight", function()
eq('Test_hl3 xxx ctermbg=9',
exec_capture('highlight Test_hl3'))
- eq("'redd' is not a valid color",
+ eq("Invalid highlight color: 'redd'",
pcall_err(meths.set_hl, 0, 'Test_hl3', {fg='redd'}))
- eq("'bleu' is not a valid color",
+ eq("Invalid highlight color: 'bleu'",
pcall_err(meths.set_hl, 0, 'Test_hl3', {ctermfg='bleu'}))
meths.set_hl(0, 'Test_hl3', {fg='#FF00FF'})
eq('Test_hl3 xxx guifg=#ff00ff',
exec_capture('highlight Test_hl3'))
- eq("'#FF00FF' is not a valid color",
+ eq("Invalid highlight color: '#FF00FF'",
pcall_err(meths.set_hl, 0, 'Test_hl3', {ctermfg='#FF00FF'}))
for _, fg_val in ipairs{ nil, 'NONE', 'nOnE', '', -1 } do
@@ -353,14 +344,14 @@ describe("API: set highlight", function()
end)
- it ("correctly sets 'Normal' internal properties", function()
+ it("correctly sets 'Normal' internal properties", function()
-- Normal has some special handling internally. #18024
meths.set_hl(0, 'Normal', {fg='#000083', bg='#0000F3'})
eq({foreground = 131, background = 243}, nvim("get_hl_by_name", 'Normal', true))
end)
it('does not segfault on invalid group name #20009', function()
- eq('Invalid highlight name: foo bar', pcall_err(meths.set_hl, 0, 'foo bar', {bold = true}))
+ eq("Invalid highlight name: 'foo bar'", pcall_err(meths.set_hl, 0, 'foo bar', {bold = true}))
assert_alive()
end)
end)
diff --git a/test/functional/api/proc_spec.lua b/test/functional/api/proc_spec.lua
index 2028a8fba5..315653af14 100644
--- a/test/functional/api/proc_spec.lua
+++ b/test/functional/api/proc_spec.lua
@@ -42,7 +42,7 @@ describe('API', function()
end)
end)
- it('validates input', function()
+ it('validation', function()
local status, rv = pcall(request, "nvim_get_proc_children", -1)
eq(false, status)
eq("Invalid pid: -1", string.match(rv, "Invalid.*"))
@@ -68,7 +68,7 @@ describe('API', function()
neq(pid, pinfo.ppid)
end)
- it('validates input', function()
+ it('validation', function()
local status, rv = pcall(request, "nvim_get_proc", -1)
eq(false, status)
eq("Invalid pid: -1", string.match(rv, "Invalid.*"))
diff --git a/test/functional/api/rpc_fixture.lua b/test/functional/api/rpc_fixture.lua
index 94df751363..c860a6da59 100644
--- a/test/functional/api/rpc_fixture.lua
+++ b/test/functional/api/rpc_fixture.lua
@@ -4,9 +4,8 @@
package.path = arg[1]
package.cpath = arg[2]
-local mpack = require('mpack')
-local StdioStream = require('nvim.stdio_stream')
-local Session = require('nvim.session')
+local StdioStream = require'test.client.uv_stream'.StdioStream
+local Session = require'test.client.session'
local stdio_stream = StdioStream.open()
local session = Session.new(stdio_stream)
@@ -19,7 +18,7 @@ local function on_request(method, args)
return "done!"
elseif method == "exit" then
session:stop()
- return mpack.NIL
+ return vim.NIL
end
end
diff --git a/test/functional/api/server_requests_spec.lua b/test/functional/api/server_requests_spec.lua
index ceff390dc5..cb273aedba 100644
--- a/test/functional/api/server_requests_spec.lua
+++ b/test/functional/api/server_requests_spec.lua
@@ -237,7 +237,7 @@ describe('server -> client', function()
\ }
]])
meths.set_var("args", {
- helpers.test_lua_prg,
+ nvim_prog, '-ll',
'test/functional/api/rpc_fixture.lua',
package.path,
package.cpath,
@@ -337,6 +337,21 @@ describe('server -> client', function()
eq('localhost:', string.sub(address,1,10))
connect_test(server, 'tcp', address)
end)
+
+ it('does not crash on receiving UI events', function()
+ local server = spawn(nvim_argv)
+ set_session(server)
+ local address = funcs.serverlist()[1]
+ local client = spawn(nvim_argv, false, nil, true)
+ set_session(client)
+
+ local id = funcs.sockconnect('pipe', address, {rpc=true})
+ funcs.rpcrequest(id, 'nvim_ui_attach', 80, 24, {})
+ assert_alive()
+
+ server:close()
+ client:close()
+ end)
end)
describe('connecting to its own pipe address', function()
diff --git a/test/functional/api/ui_spec.lua b/test/functional/api/ui_spec.lua
index 279cd1856d..5654ef31ef 100644
--- a/test/functional/api/ui_spec.lua
+++ b/test/functional/api/ui_spec.lua
@@ -11,17 +11,37 @@ describe('nvim_ui_attach()', function()
before_each(function()
clear()
end)
+
it('handles very large width/height #2180', function()
local screen = Screen.new(999, 999)
screen:attach()
eq(999, eval('&lines'))
eq(999, eval('&columns'))
end)
- it('invalid option returns error', function()
+
+ it('validation', function()
eq('No such UI option: foo',
pcall_err(meths.ui_attach, 80, 24, { foo={'foo'} }))
- end)
- it('validates channel arg', function()
+
+ eq('Invalid ext_linegrid: expected Boolean, got Array',
+ pcall_err(meths.ui_attach, 80, 24, { ext_linegrid={} }))
+ eq('Invalid override: expected Boolean, got Array',
+ pcall_err(meths.ui_attach, 80, 24, { override={} }))
+ eq('Invalid rgb: expected Boolean, got Array',
+ pcall_err(meths.ui_attach, 80, 24, { rgb={} }))
+ eq('Invalid term_name: expected String, got Boolean',
+ pcall_err(meths.ui_attach, 80, 24, { term_name=true }))
+ eq('Invalid term_colors: expected Integer, got Boolean',
+ pcall_err(meths.ui_attach, 80, 24, { term_colors=true }))
+ eq('Invalid term_background: expected String, got Boolean',
+ pcall_err(meths.ui_attach, 80, 24, { term_background=true }))
+ eq('Invalid stdin_fd: expected Integer, got String',
+ pcall_err(meths.ui_attach, 80, 24, { stdin_fd='foo' }))
+ eq('Invalid stdin_tty: expected Boolean, got String',
+ pcall_err(meths.ui_attach, 80, 24, { stdin_tty='foo' }))
+ eq('Invalid stdout_tty: expected Boolean, got String',
+ pcall_err(meths.ui_attach, 80, 24, { stdout_tty='foo' }))
+
eq('UI not attached to channel: 1',
pcall_err(request, 'nvim_ui_try_resize', 40, 10))
eq('UI not attached to channel: 1',
diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua
index 8fcdd9620b..469d8e8b6a 100644
--- a/test/functional/api/vim_spec.lua
+++ b/test/functional/api/vim_spec.lua
@@ -59,7 +59,7 @@ describe('API', function()
-- XXX: This must be the last one, else next one will fail:
-- "Packer instance already working. Use another Packer ..."
- matches("can't serialize object$",
+ matches("can't serialize object of type .$",
pcall_err(request, nil))
end)
@@ -1155,7 +1155,7 @@ describe('API', function()
describe('nvim_put', function()
it('validates args', function()
- eq('Invalid lines (expected array of strings)',
+ eq("Invalid line: expected String, got Integer",
pcall_err(request, 'nvim_put', {42}, 'l', false, false))
eq("Invalid type: 'x'",
pcall_err(request, 'nvim_put', {'foo'}, 'x', false, false))
@@ -1410,6 +1410,15 @@ describe('API', function()
ok(not nvim('get_option_value', 'equalalways', {}))
end)
+ it('validation', function()
+ eq("Invalid scope: expected 'local' or 'global'",
+ pcall_err(nvim, 'get_option_value', 'scrolloff', {scope = 'bogus'}))
+ eq("Invalid scope: expected 'local' or 'global'",
+ pcall_err(nvim, 'set_option_value', 'scrolloff', 1, {scope = 'bogus'}))
+ eq("Invalid scope: expected String, got Integer",
+ pcall_err(nvim, 'get_option_value', 'scrolloff', {scope = 42}))
+ end)
+
it('can get local values when global value is set', function()
eq(0, nvim('get_option_value', 'scrolloff', {}))
eq(-1, nvim('get_option_value', 'scrolloff', {scope = 'local'}))
@@ -1780,9 +1789,9 @@ describe('API', function()
it('validates args', function()
eq("Invalid key: 'blah'",
pcall_err(nvim, 'get_context', {blah={}}))
- eq('invalid value for key: types',
+ eq("Invalid types: expected Array, got Integer",
pcall_err(nvim, 'get_context', {types=42}))
- eq('unexpected type: zub',
+ eq("Invalid type: 'zub'",
pcall_err(nvim, 'get_context', {types={'jumps', 'zub', 'zam',}}))
end)
it('returns map of current editor state', function()
@@ -2223,15 +2232,14 @@ describe('API', function()
eq(5, meths.get_var('avar'))
end)
- it('throws error on malformed arguments', function()
+ it('validation', function()
local req = {
{'nvim_set_var', {'avar', 1}},
{'nvim_set_var'},
{'nvim_set_var', {'avar', 2}},
}
- local status, err = pcall(meths.call_atomic, req)
- eq(false, status)
- ok(err:match('Items in calls array must be arrays of size 2') ~= nil)
+ eq('calls item must be a 2-item Array',
+ pcall_err(meths.call_atomic, req))
-- call before was done, but not after
eq(1, meths.get_var('avar'))
@@ -2239,18 +2247,16 @@ describe('API', function()
{ 'nvim_set_var', { 'bvar', { 2, 3 } } },
12,
}
- status, err = pcall(meths.call_atomic, req)
- eq(false, status)
- ok(err:match('Items in calls array must be arrays') ~= nil)
+ eq("Invalid calls item: expected Array, got Integer",
+ pcall_err(meths.call_atomic, req))
eq({2,3}, meths.get_var('bvar'))
req = {
{'nvim_set_current_line', 'little line'},
{'nvim_set_var', {'avar', 3}},
}
- status, err = pcall(meths.call_atomic, req)
- eq(false, status)
- ok(err:match('Args must be Array') ~= nil)
+ eq("Invalid args: expected Array, got String",
+ pcall_err(meths.call_atomic, req))
-- call before was done, but not after
eq(1, meths.get_var('avar'))
eq({''}, meths.buf_get_lines(0, 0, -1, true))
@@ -2750,7 +2756,7 @@ describe('API', function()
describe('nvim_get_option_info', function()
it('should error for unknown options', function()
- eq("no such option: 'bogus'", pcall_err(meths.get_option_info, 'bogus'))
+ eq("Invalid option (not found): 'bogus'", pcall_err(meths.get_option_info, 'bogus'))
end)
it('should return the same options for short and long name', function()
@@ -3031,10 +3037,10 @@ describe('API', function()
eq(true, meths.del_mark('F'))
eq({0, 0}, meths.buf_get_mark(buf, 'F'))
end)
- it('fails when invalid marks are used', function()
- eq(false, pcall(meths.del_mark, 'f'))
- eq(false, pcall(meths.del_mark, '!'))
- eq(false, pcall(meths.del_mark, 'fail'))
+ it('validation', function()
+ eq("Invalid mark name (must be file/uppercase): 'f'", pcall_err(meths.del_mark, 'f'))
+ eq("Invalid mark name (must be file/uppercase): '!'", pcall_err(meths.del_mark, '!'))
+ eq("Invalid mark name (must be a single char): 'fail'", pcall_err(meths.del_mark, 'fail'))
end)
end)
describe('nvim_get_mark', function()
@@ -3048,10 +3054,10 @@ describe('API', function()
assert(string.find(mark[4], "mybuf$"))
eq({2, 2, buf.id, mark[4]}, mark)
end)
- it('fails when invalid marks are used', function()
- eq(false, pcall(meths.del_mark, 'f'))
- eq(false, pcall(meths.del_mark, '!'))
- eq(false, pcall(meths.del_mark, 'fail'))
+ it('validation', function()
+ eq("Invalid mark name (must be file/uppercase): 'f'", pcall_err(meths.get_mark, 'f', {}))
+ eq("Invalid mark name (must be file/uppercase): '!'", pcall_err(meths.get_mark, '!', {}))
+ eq("Invalid mark name (must be a single char): 'fail'", pcall_err(meths.get_mark, 'fail', {}))
end)
it('returns the expected when mark is not set', function()
eq(true, meths.del_mark('A'))
@@ -3113,15 +3119,15 @@ describe('API', function()
meths.eval_statusline('a%=b', { fillchar = '\031', maxwidth = 5 }))
end)
it('rejects multiple-character fillchar', function()
- eq('fillchar must be a single character',
+ eq('Invalid fillchar: expected single character',
pcall_err(meths.eval_statusline, '', { fillchar = 'aa' }))
end)
it('rejects empty string fillchar', function()
- eq('fillchar must be a single character',
+ eq('Invalid fillchar: expected single character',
pcall_err(meths.eval_statusline, '', { fillchar = '' }))
end)
it('rejects non-string fillchar', function()
- eq('fillchar must be a single character',
+ eq("Invalid fillchar: expected String, got Integer",
pcall_err(meths.eval_statusline, '', { fillchar = 1 }))
end)
it('rejects invalid string', function()
diff --git a/test/functional/core/exit_spec.lua b/test/functional/core/exit_spec.lua
index 05a69e1992..dc4b45b4d9 100644
--- a/test/functional/core/exit_spec.lua
+++ b/test/functional/core/exit_spec.lua
@@ -25,30 +25,34 @@ describe('v:exiting', function()
eq(1, eval('v:exiting is v:null'))
end)
- it('is 0 on normal exit', function()
+ local function test_exiting(setup_fn)
local function on_setup()
- command('autocmd VimLeavePre * call rpcrequest('..cid..', "")')
- command('autocmd VimLeave * call rpcrequest('..cid..', "")')
- command('quit')
+ command('autocmd VimLeavePre * call rpcrequest('..cid..', "exit", "VimLeavePre")')
+ command('autocmd VimLeave * call rpcrequest('..cid..', "exit", "VimLeave")')
+ setup_fn()
end
- local function on_request()
+ local requests_args = {}
+ local function on_request(name, args)
+ eq('exit', name)
+ table.insert(requests_args, args)
eq(0, eval('v:exiting'))
return ''
end
run(on_request, nil, on_setup)
+ eq({{'VimLeavePre'}, {'VimLeave'}}, requests_args)
+ end
+
+ it('is 0 on normal exit', function()
+ test_exiting(function()
+ command('quit')
+ end)
end)
+
it('is 0 on exit from Ex mode involving try-catch vim-patch:8.0.0184', function()
- local function on_setup()
- command('autocmd VimLeavePre * call rpcrequest('..cid..', "")')
- command('autocmd VimLeave * call rpcrequest('..cid..', "")')
+ test_exiting(function()
feed('gQ')
feed_command('try', 'call NoFunction()', 'catch', 'echo "bye"', 'endtry', 'quit')
- end
- local function on_request()
- eq(0, eval('v:exiting'))
- return ''
- end
- run(on_request, nil, on_setup)
+ end)
end)
end)
diff --git a/test/functional/ex_cmds/oldfiles_spec.lua b/test/functional/ex_cmds/oldfiles_spec.lua
index 5f87c3cdd9..19611429e0 100644
--- a/test/functional/ex_cmds/oldfiles_spec.lua
+++ b/test/functional/ex_cmds/oldfiles_spec.lua
@@ -2,6 +2,8 @@ local Screen = require('test.functional.ui.screen')
local helpers = require('test.functional.helpers')(after_each)
local clear = helpers.clear
+local command = helpers.command
+local expect_exit = helpers.expect_exit
local buf, eq, feed_command = helpers.curbufmeths, helpers.eq, helpers.feed_command
local feed, poke_eventloop = helpers.feed, helpers.poke_eventloop
local ok = helpers.ok
@@ -19,6 +21,7 @@ describe(':oldfiles', function()
before_each(_clear)
after_each(function()
+ expect_exit(command, 'qall!')
os.remove(shada_file)
end)
@@ -42,6 +45,7 @@ describe(':oldfiles', function()
|
Press ENTER or type command to continue^ |
]])
+ feed('<CR>')
end)
it('can be filtered with :filter', function()
@@ -107,6 +111,7 @@ describe(':browse oldfiles', function()
end)
after_each(function()
+ expect_exit(command, 'qall!')
os.remove(shada_file)
end)
diff --git a/test/functional/ex_cmds/profile_spec.lua b/test/functional/ex_cmds/profile_spec.lua
index 2b92f8d0de..bf045a4d1d 100644
--- a/test/functional/ex_cmds/profile_spec.lua
+++ b/test/functional/ex_cmds/profile_spec.lua
@@ -30,6 +30,7 @@ describe(':profile', function()
before_each(helpers.clear)
after_each(function()
+ helpers.expect_exit(command, 'qall!')
if lfs.attributes(tempfile, 'uid') ~= nil then
os.remove(tempfile)
end
diff --git a/test/functional/ex_cmds/swapfile_preserve_recover_spec.lua b/test/functional/ex_cmds/swapfile_preserve_recover_spec.lua
index 8eed00c973..ad59025d47 100644
--- a/test/functional/ex_cmds/swapfile_preserve_recover_spec.lua
+++ b/test/functional/ex_cmds/swapfile_preserve_recover_spec.lua
@@ -13,6 +13,7 @@ local nvim_prog = helpers.nvim_prog
local ok = helpers.ok
local rmdir = helpers.rmdir
local new_argv = helpers.new_argv
+local new_pipename = helpers.new_pipename
local pesc = helpers.pesc
local os_kill = helpers.os_kill
local set_session = helpers.set_session
@@ -37,10 +38,21 @@ describe(':recover', function()
end)
-describe(':preserve', function()
+describe("preserve and (R)ecover with custom 'directory'", function()
local swapdir = lfs.currentdir()..'/Xtest_recover_dir'
+ local testfile = 'Xtest_recover_file1'
+ -- 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:gsub([[\]], [[\\]])..[[//
+ set swapfile fileformat=unix undolevels=-1
+ ]]
+
+ local nvim1
before_each(function()
- clear()
+ nvim1 = spawn(new_argv())
+ set_session(nvim1)
rmdir(swapdir)
lfs.mkdir(swapdir)
end)
@@ -49,25 +61,15 @@ describe(':preserve', function()
rmdir(swapdir)
end)
- it("saves to custom 'directory' and (R)ecovers #1836", function()
- local testfile = 'Xtest_recover_file1'
- -- 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:gsub([[\]], [[\\]])..[[//
- set swapfile fileformat=unix undolevels=-1
- ]]
-
+ local function setup_swapname()
exec(init)
command('edit! '..testfile)
feed('isometext<esc>')
- command('preserve')
exec('redir => g:swapname | silent swapname | redir END')
+ return eval('g:swapname')
+ end
- local swappath1 = eval('g:swapname')
-
- os_kill(eval('getpid()'))
+ local function test_recover(swappath1)
-- Start another Nvim instance.
local nvim2 = spawn({nvim_prog, '-u', 'NONE', '-i', 'NONE', '--embed'},
true)
@@ -90,6 +92,35 @@ describe(':preserve', function()
-- Verify that :swapname was not truncated (:help 'shortmess').
ok(nil == string.find(swappath1, '%.%.%.'))
ok(nil == string.find(swappath2, '%.%.%.'))
+ end
+
+ it('with :preserve and SIGKILL', function()
+ local swappath1 = setup_swapname()
+ command('preserve')
+ os_kill(eval('getpid()'))
+ test_recover(swappath1)
+ end)
+
+ it('closing stdio channel without :preserve #22096', function()
+ local swappath1 = setup_swapname()
+ nvim1:close()
+ test_recover(swappath1)
+ end)
+
+ it('killing TUI process without :preserve #22096', function()
+ helpers.skip(helpers.is_os('win'))
+ local screen = Screen.new()
+ screen:attach()
+ local child_server = new_pipename()
+ funcs.termopen({nvim_prog, '-u', 'NONE', '-i', 'NONE', '--listen', child_server})
+ screen:expect({any = pesc('[No Name]')}) -- Wait for the child process to start.
+ local child_session = helpers.connect(child_server)
+ set_session(child_session)
+ local swappath1 = setup_swapname()
+ set_session(nvim1)
+ command('call chanclose(&channel)') -- Kill the child process.
+ screen:expect({any = pesc('[Process exited 1]')}) -- Wait for the child process to stop.
+ test_recover(swappath1)
end)
end)
diff --git a/test/functional/helpers.lua b/test/functional/helpers.lua
index 6400db9f87..cd6b535477 100644
--- a/test/functional/helpers.lua
+++ b/test/functional/helpers.lua
@@ -1,14 +1,11 @@
-require('coxpcall')
local luv = require('luv')
local lfs = require('lfs')
-local mpack = require('mpack')
local global_helpers = require('test.helpers')
--- nvim client: Found in .deps/usr/share/lua/<version>/nvim/ if "bundled".
-local Session = require('nvim.session')
-local TcpStream = require('nvim.tcp_stream')
-local SocketStream = require('nvim.socket_stream')
-local ChildProcessStream = require('nvim.child_process_stream')
+local Session = require('test.client.session')
+local uv_stream = require('test.client.uv_stream')
+local SocketStream = uv_stream.SocketStream
+local ChildProcessStream = uv_stream.ChildProcessStream
local check_cores = global_helpers.check_cores
local check_logs = global_helpers.check_logs
@@ -23,7 +20,6 @@ local tbl_contains = global_helpers.tbl_contains
local fail = global_helpers.fail
local module = {
- NIL = mpack.NIL,
mkdir = lfs.mkdir,
}
@@ -202,7 +198,7 @@ function module.expect_msg_seq(...)
end
local function call_and_stop_on_error(lsession, ...)
- local status, result = copcall(...) -- luacheck: ignore
+ local status, result = Session.safe_pcall(...) -- luacheck: ignore
if not status then
lsession:stop()
last_error = result
@@ -428,7 +424,7 @@ end
-- Creates a new Session connected by domain socket (named pipe) or TCP.
function module.connect(file_or_address)
local addr, port = string.match(file_or_address, "(.*):(%d+)")
- local stream = (addr and port) and TcpStream.open(addr, port) or
+ local stream = (addr and port) and SocketStream.connect(addr, port) or
SocketStream.open(file_or_address)
return Session.new(stream)
end
diff --git a/test/functional/legacy/move_spec.lua b/test/functional/legacy/move_spec.lua
new file mode 100644
index 0000000000..855996da8f
--- /dev/null
+++ b/test/functional/legacy/move_spec.lua
@@ -0,0 +1,49 @@
+local helpers = require('test.functional.helpers')(after_each)
+local Screen = require('test.functional.ui.screen')
+local clear = helpers.clear
+local feed = helpers.feed
+local funcs = helpers.funcs
+
+before_each(clear)
+
+describe(':move', function()
+ -- oldtest: Test_move_undo()
+ it('redraws correctly when undone', function()
+ local screen = Screen.new(60, 10)
+ screen:set_default_attr_ids({
+ [0] = {bold = true, foreground = Screen.colors.Blue}, -- NonText
+ })
+ screen:attach()
+
+ funcs.setline(1, {'First', 'Second', 'Third', 'Fourth'})
+ feed('gg:move +1<CR>')
+ screen:expect([[
+ Second |
+ ^First |
+ Third |
+ Fourth |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ :move +1 |
+ ]])
+
+ -- here the display would show the last few lines scrolled down
+ feed('u')
+ feed(':<Esc>')
+ screen:expect([[
+ ^First |
+ Second |
+ Third |
+ Fourth |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+ end)
+end)
diff --git a/test/functional/lua/api_spec.lua b/test/functional/lua/api_spec.lua
index 03832978a4..dc6452dd62 100644
--- a/test/functional/lua/api_spec.lua
+++ b/test/functional/lua/api_spec.lua
@@ -33,7 +33,7 @@ describe('luaeval(vim.api.…)', function()
describe('with errors', function()
it('transforms API error from nvim_buf_set_lines into lua error', function()
funcs.setline(1, {"abc", "def", "a\nb", "ttt"})
- eq({false, 'String cannot contain newlines'},
+ eq({false, "'replacement string' item contains newlines"},
funcs.luaeval('{pcall(vim.api.nvim_buf_set_lines, 1, 1, 2, false, {"b\\na"})}'))
end)
diff --git a/test/functional/lua/filetype_spec.lua b/test/functional/lua/filetype_spec.lua
index 2a7be53164..add69235b6 100644
--- a/test/functional/lua/filetype_spec.lua
+++ b/test/functional/lua/filetype_spec.lua
@@ -94,6 +94,26 @@ describe('vim.filetype', function()
return vim.filetype.match({ buf = 0 })
]])
end)
+
+ it('works with contents #22180', function()
+ eq('sh', exec_lua [[
+ -- Needs to be set so detect#sh doesn't fail
+ vim.g.ft_ignore_pat = '\\.\\(Z\\|gz\\|bz2\\|zip\\|tgz\\)$'
+ return vim.filetype.match({ contents = { '#!/usr/bin/env bash' } })
+ ]])
+ end)
+
+ it('considers extension mappings when matching from hashbang', function()
+ eq('fooscript', exec_lua [[
+ vim.filetype.add({
+ extension = {
+ foo = 'fooscript',
+ }
+ })
+ return vim.filetype.match({ contents = { '#!/usr/bin/env foo' } })
+ ]])
+ end)
+
end)
describe('filetype.lua', function()
diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua
index 867f366d06..b43e5b28db 100644
--- a/test/functional/lua/vim_spec.lua
+++ b/test/functional/lua/vim_spec.lua
@@ -1458,7 +1458,7 @@ describe('lua stdlib', function()
]]
eq('', funcs.luaeval "vim.bo.filetype")
eq(true, funcs.luaeval "vim.bo[BUF].modifiable")
- matches("no such option: 'nosuchopt'$",
+ matches("Invalid option %(not found%): 'nosuchopt'$",
pcall_err(exec_lua, 'return vim.bo.nosuchopt'))
matches("Expected lua string$",
pcall_err(exec_lua, 'return vim.bo[0][0].autoread'))
@@ -1479,7 +1479,7 @@ describe('lua stdlib', function()
eq(0, funcs.luaeval "vim.wo.cole")
eq(0, funcs.luaeval "vim.wo[0].cole")
eq(0, funcs.luaeval "vim.wo[1001].cole")
- matches("no such option: 'notanopt'$",
+ matches("Invalid option %(not found%): 'notanopt'$",
pcall_err(exec_lua, 'return vim.wo.notanopt'))
matches("Expected lua string$",
pcall_err(exec_lua, 'return vim.wo[0][0].list'))
diff --git a/test/functional/shada/helpers.lua b/test/functional/shada/helpers.lua
index fb3ec4a87c..cd99d38345 100644
--- a/test/functional/shada/helpers.lua
+++ b/test/functional/shada/helpers.lua
@@ -33,6 +33,7 @@ local function reset(o)
end
local clear = function()
+ helpers.expect_exit(helpers.command, 'qall!')
os.remove(tmpname)
end
diff --git a/test/functional/shada/history_spec.lua b/test/functional/shada/history_spec.lua
index d1daf6c7cc..aa4106ad63 100644
--- a/test/functional/shada/history_spec.lua
+++ b/test/functional/shada/history_spec.lua
@@ -32,7 +32,6 @@ describe('ShaDa support code', function()
nvim_command('rshada')
eq('" Test 2', funcs.histget(':', -1))
eq('" Test', funcs.histget(':', -2))
- expect_exit(nvim_command, 'qall')
end)
it('respects &history when dumping',
diff --git a/test/functional/shada/shada_spec.lua b/test/functional/shada/shada_spec.lua
index 88a99d9b55..24bd363e95 100644
--- a/test/functional/shada/shada_spec.lua
+++ b/test/functional/shada/shada_spec.lua
@@ -126,34 +126,16 @@ describe('ShaDa support code', function()
wshada(s .. table.concat(msgpack, e .. s) .. e)
eq(0, exc_exec('wshada ' .. shada_fname))
local found = 0
- local typ = mpack.unpack(s)
+ local typ = mpack.decode(s)
for _, v in ipairs(read_shada_file(shada_fname)) do
if v.type == typ then
found = found + 1
- eq(mpack.unpack(msgpack[found]), v.timestamp)
+ eq(mpack.decode(msgpack[found]), v.timestamp)
end
end
eq(#msgpack, found)
end)
- it('does not write NONE file', function()
- local session = spawn({nvim_prog, '-u', 'NONE', '-i', 'NONE', '--embed',
- '--headless', '--cmd', 'qall'}, true)
- session:close()
- eq(nil, lfs.attributes('NONE'))
- eq(nil, lfs.attributes('NONE.tmp.a'))
- end)
-
- it('does not read NONE file', function()
- write_file('NONE', '\005\001\015\131\161na\162rX\194\162rc\145\196\001-')
- local session = spawn({nvim_prog, '-u', 'NONE', '-i', 'NONE', '--embed',
- '--headless'}, true)
- set_session(session)
- eq('', funcs.getreg('a'))
- session:close()
- os.remove('NONE')
- end)
-
local marklike = {[7]=true, [8]=true, [10]=true, [11]=true}
local find_file = function(fname)
local found = {}
@@ -263,3 +245,23 @@ describe('ShaDa support code', function()
meths.set_option('shada', '')
end)
end)
+
+describe('ShaDa support code', function()
+ it('does not write NONE file', function()
+ local session = spawn({nvim_prog, '-u', 'NONE', '-i', 'NONE', '--embed',
+ '--headless', '--cmd', 'qall'}, true)
+ session:close()
+ eq(nil, lfs.attributes('NONE'))
+ eq(nil, lfs.attributes('NONE.tmp.a'))
+ end)
+
+ it('does not read NONE file', function()
+ write_file('NONE', '\005\001\015\131\161na\162rX\194\162rc\145\196\001-')
+ local session = spawn({nvim_prog, '-u', 'NONE', '-i', 'NONE', '--embed',
+ '--headless'}, true)
+ set_session(session)
+ eq('', funcs.getreg('a'))
+ session:close()
+ os.remove('NONE')
+ end)
+end)
diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua
index 1d9e7b8e11..4e62354ed8 100644
--- a/test/functional/terminal/tui_spec.lua
+++ b/test/functional/terminal/tui_spec.lua
@@ -2365,18 +2365,18 @@ describe("TUI as a client", function()
set_session(client_super)
local screen_client = thelpers.screen_setup(0,
- string.format([=[["%s", "-u", "NONE", "-i", "NONE", "--server", "%s", "--remote-ui"]]=],
+ string.format([=[["%s", "--server", "%s", "--remote-ui"]]=],
nvim_prog, server_pipe))
- screen_client:expect{grid=[[
- Hello, Worl{1:d} |
- {4:~ }|
- {4:~ }|
- {4:~ }|
- {5:[No Name] [+] }|
- |
- {3:-- TERMINAL --} |
- ]]}
+ screen_client:expect{grid=[[
+ Hello, Worl{1:d} |
+ {4:~ }|
+ {4:~ }|
+ {4:~ }|
+ {5:[No Name] [+] }|
+ |
+ {3:-- TERMINAL --} |
+ ]]}
feed_data(":q!\n")
@@ -2394,7 +2394,7 @@ describe("TUI as a client", function()
set_session(client_super)
local screen = thelpers.screen_setup(0,
- string.format([=[["%s", "-u", "NONE", "-i", "NONE", "--server", "%s", "--remote-ui"]]=],
+ string.format([=[["%s", "--server", "%s", "--remote-ui"]]=],
nvim_prog, server_pipe))
screen:expect{grid=[[
@@ -2407,15 +2407,24 @@ describe("TUI as a client", function()
{3:-- TERMINAL --} |
]]}
+ -- No heap-use-after-free when receiving UI events after deadly signal #22184
+ server:request('nvim_input', ('a'):rep(1000))
+ exec_lua([[vim.loop.kill(vim.fn.jobpid(vim.bo.channel), 'sigterm')]])
+ screen:expect({any = '%[Process exited 1%]'})
+
+ eq(0, meths.get_vvar('shell_error'))
+ -- exits on input eof #22244
+ funcs.system({nvim_prog, '--server', server_pipe, '--remote-ui'})
+ eq(1, meths.get_vvar('shell_error'))
+
client_super:close()
server:close()
end)
-
it("throws error when no server exists", function()
clear()
local screen = thelpers.screen_setup(0,
- string.format([=[["%s", "-u", "NONE", "-i", "NONE", "--server", "127.0.0.1:2436546", "--remote-ui"]]=],
+ string.format([=[["%s", "--server", "127.0.0.1:2436546", "--remote-ui"]]=],
nvim_prog), 60)
screen:expect([[
@@ -2462,7 +2471,7 @@ describe("TUI as a client", function()
set_session(client_super)
local screen_client = thelpers.screen_setup(0,
- string.format([=[["%s", "-u", "NONE", "-i", "NONE", "--server", "%s", "--remote-ui"]]=],
+ string.format([=[["%s", "--server", "%s", "--remote-ui"]]=],
nvim_prog, server_pipe))
screen_client:expect{grid=[[
diff --git a/test/functional/treesitter/language_spec.lua b/test/functional/treesitter/language_spec.lua
index df45c9b384..51d8eb62f3 100644
--- a/test/functional/treesitter/language_spec.lua
+++ b/test/functional/treesitter/language_spec.lua
@@ -82,7 +82,7 @@ describe('treesitter language API', function()
command("set filetype=borklang")
-- Should throw an error when filetype changes to borklang
eq(".../language.lua:0: no parser for 'borklang' language, see :help treesitter-parsers",
- pcall_err(exec_lua, "new_parser = vim.treesitter.get_parser(0)"))
+ pcall_err(exec_lua, "new_parser = vim.treesitter.get_parser(0, 'borklang')"))
end)
it('retrieve the tree given a range', function ()
diff --git a/test/functional/treesitter/parser_spec.lua b/test/functional/treesitter/parser_spec.lua
index f006ad4539..2d0d57fbd0 100644
--- a/test/functional/treesitter/parser_spec.lua
+++ b/test/functional/treesitter/parser_spec.lua
@@ -277,6 +277,9 @@ end]]
function fake_node:end_()
return 3, 0, 23
end
+ function fake_node:range()
+ return 3, 0, 3, 0
+ end
return vim.treesitter.get_node_text(fake_node, 0) == nil
]])
eq(true, result)
@@ -296,6 +299,9 @@ end]]
function fake_node:end_()
return 1, 0, 7
end
+ function fake_node:range()
+ return 1, 0, 1, 0
+ end
return vim.treesitter.get_node_text(fake_node, 0) == ''
]])
eq(true, result)
@@ -728,7 +734,7 @@ int x = INT_MAX;
return list
]]
- eq({ 'offset!', 'set!' }, res_list)
+ eq({ 'gsub!', 'offset!', 'set!' }, res_list)
end)
end)
end)
diff --git a/test/functional/ui/bufhl_spec.lua b/test/functional/ui/bufhl_spec.lua
index 46bfae8de2..76baf2cddb 100644
--- a/test/functional/ui/bufhl_spec.lua
+++ b/test/functional/ui/bufhl_spec.lua
@@ -751,8 +751,8 @@ describe('Buffer highlighting', function()
it('validates contents', function()
-- this used to leak memory
- eq('Chunk is not an array', pcall_err(set_virtual_text, id1, 0, {"texty"}, {}))
- eq('Chunk is not an array', pcall_err(set_virtual_text, id1, 0, {{"very"}, "texty"}, {}))
+ eq('Invalid chunk: expected Array, got String', pcall_err(set_virtual_text, id1, 0, {"texty"}, {}))
+ eq('Invalid chunk: expected Array, got String', pcall_err(set_virtual_text, id1, 0, {{"very"}, "texty"}, {}))
end)
it('can be retrieved', function()
diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua
index 489c33d8b1..6ed32a8cd4 100644
--- a/test/functional/ui/decorations_spec.lua
+++ b/test/functional/ui/decorations_spec.lua
@@ -2109,6 +2109,20 @@ l5
|
]]}
end)
+
+ it('does not set signcolumn for signs without text', function()
+ screen:try_resize(20, 3)
+ meths.win_set_option(0, 'signcolumn', 'auto')
+ insert(example_text)
+ feed 'gg'
+ meths.buf_set_extmark(0, ns, 0, -1, {number_hl_group='Error'})
+ screen:expect{grid=[[
+ ^l1 |
+ l2 |
+ |
+ ]]}
+ end)
+
end)
describe('decorations: virt_text', function()
diff --git a/test/functional/ui/fold_spec.lua b/test/functional/ui/fold_spec.lua
index 46a478c1ea..420a4654f8 100644
--- a/test/functional/ui/fold_spec.lua
+++ b/test/functional/ui/fold_spec.lua
@@ -10,6 +10,7 @@ local meths = helpers.meths
local exec = helpers.exec
local exec_lua = helpers.exec_lua
local assert_alive = helpers.assert_alive
+local poke_eventloop = helpers.poke_eventloop
local content1 = [[
@@ -90,10 +91,10 @@ describe("folded lines", function()
end)
it("highlights with CursorLineFold when 'cursorline' is set", function()
- command("set cursorline foldcolumn=2 foldmethod=marker")
+ command("set number cursorline foldcolumn=2")
command("hi link CursorLineFold Search")
insert(content1)
- feed("zf3j")
+ feed("ggzf3jj")
if multigrid then
screen:expect([[
## grid 1
@@ -106,26 +107,26 @@ describe("folded lines", function()
[2:---------------------------------------------]|
[3:---------------------------------------------]|
## grid 2
- {7: }This is a |
- {7: }valid English |
- {7: }sentence composed by |
- {7: }an exhausted developer |
- {7: }in his cave. |
- {6: }{12:^ }|
+ {7:+ }{8: 1 }{5:+-- 4 lines: This is a················}|
+ {6: }{9: 5 }{12:^in his cave. }|
+ {7: }{8: 6 } |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
{1:~ }|
## grid 3
|
]])
else
screen:expect([[
- {7: }This is a |
- {7: }valid English |
- {7: }sentence composed by |
- {7: }an exhausted developer |
- {7: }in his cave. |
- {6: }{12:^ }|
- {1:~ }|
- |
+ {7:+ }{8: 1 }{5:+-- 4 lines: This is a················}|
+ {6: }{9: 5 }{12:^in his cave. }|
+ {7: }{8: 6 } |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
]])
end
feed("k")
@@ -141,28 +142,36 @@ describe("folded lines", function()
[2:---------------------------------------------]|
[3:---------------------------------------------]|
## grid 2
- {7: }This is a |
- {7: }valid English |
- {7: }sentence composed by |
- {7: }an exhausted developer |
- {6: }{12:^in his cave. }|
- {7: } |
+ {6:+ }{9: 1 }{12:^+-- 4 lines: This is a················}|
+ {7: }{8: 5 }in his cave. |
+ {7: }{8: 6 } |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
{1:~ }|
## grid 3
|
]])
else
screen:expect([[
- {7: }This is a |
- {7: }valid English |
- {7: }sentence composed by |
- {7: }an exhausted developer |
- {6: }{12:^in his cave. }|
- {7: } |
- {1:~ }|
- |
+ {6:+ }{9: 1 }{12:^+-- 4 lines: This is a················}|
+ {7: }{8: 5 }in his cave. |
+ {7: }{8: 6 } |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
]])
end
+ -- CursorLine is applied correctly with screenrow motions #22232
+ feed("jgk")
+ poke_eventloop()
+ screen:expect_unchanged()
+ -- CursorLine is applied correctly when closing a fold when cursor is not at fold start
+ feed("zo4Gzc")
+ poke_eventloop()
+ screen:expect_unchanged()
command("set cursorlineopt=line")
if multigrid then
screen:expect([[
@@ -176,26 +185,61 @@ describe("folded lines", function()
[2:---------------------------------------------]|
[3:---------------------------------------------]|
## grid 2
- {7: }This is a |
- {7: }valid English |
- {7: }sentence composed by |
- {7: }an exhausted developer |
- {7: }{12:^in his cave. }|
- {7: } |
+ {7:+ }{8: 1 }{12:^+-- 4 lines: This is a················}|
+ {7: }{8: 5 }in his cave. |
+ {7: }{8: 6 } |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
{1:~ }|
## grid 3
|
]])
else
screen:expect([[
- {7: }This is a |
- {7: }valid English |
- {7: }sentence composed by |
- {7: }an exhausted developer |
- {7: }{12:^in his cave. }|
- {7: } |
- {1:~ }|
- |
+ {7:+ }{8: 1 }{12:^+-- 4 lines: This is a················}|
+ {7: }{8: 5 }in his cave. |
+ {7: }{8: 6 } |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]])
+ end
+ command("set relativenumber cursorlineopt=number")
+ if multigrid then
+ screen:expect([[
+ ## grid 1
+ [2:---------------------------------------------]|
+ [2:---------------------------------------------]|
+ [2:---------------------------------------------]|
+ [2:---------------------------------------------]|
+ [2:---------------------------------------------]|
+ [2:---------------------------------------------]|
+ [2:---------------------------------------------]|
+ [3:---------------------------------------------]|
+ ## grid 2
+ {6:+ }{9:1 }{5:^+-- 4 lines: This is a················}|
+ {7: }{8: 1 }in his cave. |
+ {7: }{8: 2 } |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ## grid 3
+ |
+ ]])
+ else
+ screen:expect([[
+ {6:+ }{9:1 }{5:^+-- 4 lines: This is a················}|
+ {7: }{8: 1 }in his cave. |
+ {7: }{8: 2 } |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
]])
end
end)
diff --git a/test/functional/ui/screen.lua b/test/functional/ui/screen.lua
index 3b9cce0e6f..a059fb5b89 100644
--- a/test/functional/ui/screen.lua
+++ b/test/functional/ui/screen.lua
@@ -214,7 +214,7 @@ function Screen:attach(options, session)
-- simplify test code by doing the same.
self._options.rgb = true
end
- if self._options.ext_multigrid or self._options.ext_float then
+ if self._options.ext_multigrid then
self._options.ext_linegrid = true
end
end
diff --git a/test/functional/ui/screen_basic_spec.lua b/test/functional/ui/screen_basic_spec.lua
index 3bd2289a73..439021ad87 100644
--- a/test/functional/ui/screen_basic_spec.lua
+++ b/test/functional/ui/screen_basic_spec.lua
@@ -61,6 +61,7 @@ local function screen_tests(linegrid)
[5] = {background = Screen.colors.LightGrey, underline = true, bold = true, foreground = Screen.colors.Fuchsia},
[6] = {bold = true, foreground = Screen.colors.Fuchsia},
[7] = {bold = true, foreground = Screen.colors.SeaGreen},
+ [8] = {foreground = Screen.colors.White, background = Screen.colors.Red},
} )
end)
@@ -866,12 +867,9 @@ local function screen_tests(linegrid)
end)
describe('resize', function()
- before_each(function()
+ it('rebuilds the whole screen', function()
screen:try_resize(25, 5)
feed('iresize')
- end)
-
- it('rebuilds the whole screen', function()
screen:expect([[
resize^ |
{0:~ }|
@@ -882,6 +880,7 @@ local function screen_tests(linegrid)
end)
it('has minimum width/height values', function()
+ feed('iresize')
screen:try_resize(1, 1)
screen:expect([[
resize^ |
@@ -896,7 +895,8 @@ local function screen_tests(linegrid)
end)
it('VimResized autocommand does not cause invalid UI events #20692 #20759', function()
- feed('<Esc>')
+ screen:try_resize(25, 5)
+ feed('iresize<Esc>')
command([[autocmd VimResized * redrawtabline]])
command([[autocmd VimResized * lua vim.api.nvim_echo({ { 'Hello' } }, false, {})]])
command([[autocmd VimResized * let g:echospace = v:echospace]])
@@ -919,6 +919,77 @@ local function screen_tests(linegrid)
]])
eq(29, meths.get_var('echospace'))
end)
+
+ it('messages from the same Ex command as resize are visible #22225', function()
+ feed(':set columns=20 | call<CR>')
+ screen:expect([[
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ {1: }|
+ {8:E471: Argument requi}|
+ {8:red} |
+ {7:Press ENTER or type }|
+ {7:command to continue}^ |
+ ]])
+ feed('<CR>')
+ screen:expect([[
+ ^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+ feed(':set columns=0<CR>')
+ screen:expect([[
+ |
+ |
+ |
+ |
+ |
+ {1: }|
+ {8:E594: Need a}|
+ {8:t least 12 c}|
+ {8:olumns: colu}|
+ {8:mns=0} |
+ {7:Press ENTER }|
+ {7:or type comm}|
+ {7:and to conti}|
+ {7:nue}^ |
+ ]])
+ feed('<CR>')
+ screen:expect([[
+ ^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+ end)
end)
describe('press enter', function()
diff --git a/test/functional/ui/searchhl_spec.lua b/test/functional/ui/searchhl_spec.lua
index 18bbb56a61..404cc6d043 100644
--- a/test/functional/ui/searchhl_spec.lua
+++ b/test/functional/ui/searchhl_spec.lua
@@ -10,7 +10,6 @@ local testprg = helpers.testprg
describe('search highlighting', function()
local screen
- local colors = Screen.colors
before_each(function()
clear()
@@ -18,9 +17,9 @@ describe('search highlighting', function()
screen:attach()
screen:set_default_attr_ids( {
[1] = {bold=true, foreground=Screen.colors.Blue},
- [2] = {background = colors.Yellow}, -- Search
+ [2] = {background = Screen.colors.Yellow}, -- Search
[3] = {reverse = true},
- [4] = {foreground = colors.Red}, -- Message
+ [4] = {foreground = Screen.colors.Red}, -- Message
[6] = {foreground = Screen.colors.Blue4, background = Screen.colors.LightGrey}, -- Folded
})
end)
@@ -498,6 +497,20 @@ describe('search highlighting', function()
{1:~ }│{1:~ }|
//^ |
]])
+ feed('<Esc>')
+
+ -- incsearch works after c_CTRL-R_CTRL-R
+ command('let @" = "file"')
+ feed('/<C-R><C-R>"')
+ screen:expect([[
+ the first line │the first line |
+ in a little {3:file} │in a little {2:file} |
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ /file^ |
+ ]])
end)
it('works with incsearch and offset', function()
@@ -572,12 +585,12 @@ describe('search highlighting', function()
it('works with matchadd and syntax', function()
screen:set_default_attr_ids {
[1] = {bold=true, foreground=Screen.colors.Blue};
- [2] = {background = colors.Yellow};
+ [2] = {background = Screen.colors.Yellow};
[3] = {reverse = true};
- [4] = {foreground = colors.Red};
- [5] = {bold = true, background = colors.Green};
- [6] = {italic = true, background = colors.Magenta};
- [7] = {bold = true, background = colors.Yellow};
+ [4] = {foreground = Screen.colors.Red};
+ [5] = {bold = true, background = Screen.colors.Green};
+ [6] = {italic = true, background = Screen.colors.Magenta};
+ [7] = {bold = true, background = Screen.colors.Yellow};
[8] = {foreground = Screen.colors.Blue4, background = Screen.colors.LightGray};
}
feed_command('set hlsearch')
diff --git a/test/functional/ui/statuscolumn_spec.lua b/test/functional/ui/statuscolumn_spec.lua
index 3233e6cd19..287686cf37 100644
--- a/test/functional/ui/statuscolumn_spec.lua
+++ b/test/functional/ui/statuscolumn_spec.lua
@@ -456,7 +456,7 @@ describe('statuscolumn', function()
14 aaaaa |
|
]])
- command('set stc=') -- also for the default sign column
+ command('set stc=') -- also for the default fold column
screen:expect_unchanged()
-- 'statuscolumn' is not too wide with custom (bogus) fold column
command([[set stc=%{foldlevel(v:lnum)>0?repeat('-',foldlevel(v:lnum)):''}%=%l\ ]])
diff --git a/test/helpers.lua b/test/helpers.lua
index 82ff23bef8..d45536b42b 100644
--- a/test/helpers.lua
+++ b/test/helpers.lua
@@ -1,5 +1,5 @@
require('test.compat')
-local shared = require('vim.shared')
+local shared = vim
local assert = require('luassert')
local busted = require('busted')
local luv = require('luv')