build: enable lintlua for test/unit/ dir #26396

Problem:
Not all Lua code is checked by stylua. Automating code-style is an
important mechanism for reducing time spent on accidental
(non-essential) complexity.

Solution:
- Enable lintlua for `test/unit/` directory.
- TODO: only `test/functional/` remains unchecked.

previous: 45fe4d11ad
previous: 517f0cc634
This commit is contained in:
Justin M. Keyes 2023-12-04 14:32:39 -08:00 committed by GitHub
parent 45fe4d11ad
commit c3836e40a2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
51 changed files with 4067 additions and 2764 deletions

View File

@ -2,4 +2,10 @@
/runtime/lua/coxpcall.lua
/runtime/lua/vim/_meta
/runtime/lua/vim/re.lua
/test
/test/functional
/test/functional/fixtures/lua/syntax_error.lua
/test/functional/legacy/030_fileformats_spec.lua
/test/functional/legacy/044_099_regexp_multibyte_magic_spec.lua
/test/functional/legacy/093_mksession_cursor_cols_latin1_spec.lua
/test/functional/lua/luaeval_spec.lua

View File

@ -233,7 +233,7 @@ add_glob_target(
TARGET lintlua-stylua
COMMAND ${STYLUA_PRG}
FLAGS --color=always --check --respect-ignores
GLOB_DIRS runtime/ scripts/ src/
GLOB_DIRS runtime/ scripts/ src/ test/unit/
GLOB_PAT *.lua
TOUCH_STRATEGY SINGLE)
@ -260,7 +260,7 @@ add_glob_target(
TARGET formatlua
COMMAND ${STYLUA_PRG}
FLAGS --respect-ignores
GLOB_DIRS runtime/ scripts/ src/
GLOB_DIRS runtime/ scripts/ src/ test/unit/
GLOB_PAT *.lua)
add_custom_target(format)

View File

@ -27,7 +27,8 @@ describe('autocmd perf', function()
end)
it('nvim_create_autocmd, nvim_del_autocmd (same pattern)', function()
exec_lua([[
exec_lua(
[[
local N = ...
local ids = {}
@ -45,11 +46,14 @@ describe('autocmd perf', function()
vim.api.nvim_del_autocmd(ids[i])
end
stop('nvim_del_autocmd')
]], N)
]],
N
)
end)
it('nvim_create_autocmd, nvim_del_autocmd (unique patterns)', function()
exec_lua([[
exec_lua(
[[
local N = ...
local ids = {}
@ -67,11 +71,14 @@ describe('autocmd perf', function()
vim.api.nvim_del_autocmd(ids[i])
end
stop('nvim_del_autocmd')
]], N)
]],
N
)
end)
it('nvim_create_autocmd + nvim_del_autocmd', function()
exec_lua([[
exec_lua(
[[
local N = ...
start()
@ -83,11 +90,14 @@ describe('autocmd perf', function()
vim.api.nvim_del_autocmd(id)
end
stop('nvim_create_autocmd + nvim_del_autocmd')
]], N)
]],
N
)
end)
it('nvim_exec_autocmds (same pattern)', function()
exec_lua([[
exec_lua(
[[
local N = ...
for i = 1, N do
@ -100,11 +110,14 @@ describe('autocmd perf', function()
start()
vim.api.nvim_exec_autocmds('User', { pattern = 'Benchmark', modeline = false })
stop('nvim_exec_autocmds')
]], N)
]],
N
)
end)
it('nvim_del_augroup_by_id', function()
exec_lua([[
exec_lua(
[[
local N = ...
local group = vim.api.nvim_create_augroup('Benchmark', {})
@ -119,11 +132,14 @@ describe('autocmd perf', function()
start()
vim.api.nvim_del_augroup_by_id(group)
stop('nvim_del_augroup_by_id')
]], N)
]],
N
)
end)
it('nvim_del_augroup_by_name', function()
exec_lua([[
exec_lua(
[[
local N = ...
local group = vim.api.nvim_create_augroup('Benchmark', {})
@ -138,11 +154,14 @@ describe('autocmd perf', function()
start()
vim.api.nvim_del_augroup_by_name('Benchmark')
stop('nvim_del_augroup_by_id')
]], N)
]],
N
)
end)
it(':autocmd, :autocmd! (same pattern)', function()
exec_lua([[
exec_lua(
[[
local N = ...
start()
@ -154,11 +173,14 @@ describe('autocmd perf', function()
start()
vim.cmd('autocmd! User Benchmark')
stop(':autocmd!')
]], N)
]],
N
)
end)
it(':autocmd, :autocmd! (unique patterns)', function()
exec_lua([[
exec_lua(
[[
local N = ...
start()
@ -170,6 +192,8 @@ describe('autocmd perf', function()
start()
vim.cmd('autocmd! User')
stop(':autocmd!')
]], N)
]],
N
)
end)
end)

View File

@ -10,8 +10,7 @@ local result_file = 'benchmark.out'
local sample_file = 'test/old/testdir/samples/re.freeze.txt'
-- Vim script code that does both the work and the benchmarking of that work.
local measure_cmd =
[[call Measure(%d, ']] .. sample_file .. [[', '\s\+\%%#\@<!$', '+5')]]
local measure_cmd = [[call Measure(%d, ']] .. sample_file .. [[', '\s\+\%%#\@<!$', '+5')]]
local measure_script = [[
func Measure(re, file, pattern, arg)
let sstart = reltime()

View File

@ -4,7 +4,6 @@ local clear = helpers.clear
local exec_lua = helpers.exec_lua
describe('treesitter perf', function()
setup(function()
clear()
end)
@ -47,7 +46,5 @@ describe('treesitter perf', function()
return vim.uv.hrtime() - start
]]
end)
end)

View File

@ -1,12 +1,21 @@
local pretty = require 'pl.pretty'
local global_helpers = require('test.helpers')
local colors = setmetatable({}, {__index = function() return function(s) return s == nil and '' or tostring(s) end end})
local colors = setmetatable({}, {
__index = function()
return function(s)
return s == nil and '' or tostring(s)
end
end,
})
local enable_colors = true
if os.getenv "TEST_COLORS" then
local test_colors = os.getenv("TEST_COLORS"):lower()
local disable_colors = test_colors == 'false' or test_colors == '0' or test_colors == 'no' or test_colors == 'off'
if os.getenv 'TEST_COLORS' then
local test_colors = os.getenv('TEST_COLORS'):lower()
local disable_colors = test_colors == 'false'
or test_colors == '0'
or test_colors == 'no'
or test_colors == 'off'
enable_colors = not disable_colors
end
if enable_colors then
@ -18,15 +27,25 @@ return function(options)
local handler = require 'busted.outputHandlers.base'()
local c = {
succ = function(s) return colors.bright(colors.green(s)) end,
skip = function(s) return colors.bright(colors.yellow(s)) end,
fail = function(s) return colors.bright(colors.magenta(s)) end,
errr = function(s) return colors.bright(colors.red(s)) end,
succ = function(s)
return colors.bright(colors.green(s))
end,
skip = function(s)
return colors.bright(colors.yellow(s))
end,
fail = function(s)
return colors.bright(colors.magenta(s))
end,
errr = function(s)
return colors.bright(colors.red(s))
end,
test = tostring,
file = colors.cyan,
time = colors.dim,
note = colors.yellow,
sect = function(s) return colors.green(colors.dim(s)) end,
sect = function(s)
return colors.green(colors.dim(s))
end,
nmbr = colors.bright,
}
@ -39,9 +58,23 @@ return function(options)
local skippedString = c.skip('SKIP') .. '\n'
local failureString = c.fail('FAIL') .. '\n'
local errorString = c.errr('ERR') .. '\n'
local fileEndString = c.sect('--------') .. ' '.. c.nmbr('%d') .. ' %s from ' .. c.file('%s') .. ' ' .. c.time('(%.2f ms total)') .. '\n\n'
local fileEndString = c.sect('--------')
.. ' '
.. c.nmbr('%d')
.. ' %s from '
.. c.file('%s')
.. ' '
.. c.time('(%.2f ms total)')
.. '\n\n'
local globalTeardown = c.sect('--------') .. ' Global test environment teardown.\n'
local suiteEndString = c.sect('========') .. ' ' .. c.nmbr('%d') .. ' %s from ' .. c.nmbr('%d') .. ' test %s ran. ' .. c.time('(%.2f ms total)') .. '\n'
local suiteEndString = c.sect('========')
.. ' '
.. c.nmbr('%d')
.. ' %s from '
.. c.nmbr('%d')
.. ' test %s ran. '
.. c.time('(%.2f ms total)')
.. '\n'
local successStatus = c.succ('PASSED ') .. ' ' .. c.nmbr('%d') .. ' %s.\n'
local timeString = c.time('%.2f ms')
@ -107,8 +140,10 @@ return function(options)
local getFileLine = function(element)
local fileline = ''
if element.trace or element.trace.short_src then
fileline = colors.cyan(element.trace.short_src) .. ' @ ' ..
colors.cyan(element.trace.currentline) .. ': '
fileline = colors.cyan(element.trace.short_src)
.. ' @ '
.. colors.cyan(element.trace.currentline)
.. ': '
end
return fileline
end
@ -219,7 +254,9 @@ return function(options)
local elapsedTime_ms = getElapsedTime(file)
local tests = (fileTestCount == 1 and 'test' or 'tests')
fileCount = fileCount + 1
io.write(fileEndString:format(fileTestCount, tests, vim.fs.normalize(file.name), elapsedTime_ms))
io.write(
fileEndString:format(fileTestCount, tests, vim.fs.normalize(file.name), elapsedTime_ms)
)
io.flush()
return nil, true
end
@ -256,7 +293,7 @@ return function(options)
errorCount = errorCount + 1
string = errorString .. failureDescription(handler.errors[#handler.errors])
else
string = "unexpected test status! ("..status..")"
string = 'unexpected test status! (' .. status .. ')'
end
write_status(element, string)

View File

@ -3,13 +3,19 @@ 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
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
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
function Tabpage.new(id)
return setmetatable({ id = id }, Tabpage)
end
local Response = {}
Response.__index = Response
@ -17,7 +23,7 @@ Response.__index = Response
function Response.new(msgpack_rpc_stream, request_id)
return setmetatable({
_msgpack_rpc_stream = msgpack_rpc_stream,
_request_id = request_id
_request_id = request_id,
}, Response)
end
@ -41,19 +47,31 @@ function MsgpackRpcStream.new(stream)
_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
}
[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
}
})
[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
@ -80,12 +98,10 @@ function MsgpackRpcStream:read_start(request_cb, notification_cb, eof_cb)
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)
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))
request_cb(method_or_error, args_or_result, Response.new(self, id_or_cb))
else
notification_cb(method_or_error, args_or_result)
end

View File

@ -50,7 +50,7 @@ function Session.new(stream)
_pending_messages = {},
_prepare = uv.new_prepare(),
_timer = uv.new_timer(),
_is_running = false
_is_running = false,
}, Session)
end
@ -141,8 +141,12 @@ function Session: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
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)
self.closed = true
end
@ -187,7 +191,7 @@ function Session:_run(request_cb, notification_cb, timeout)
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."}
self.eof_err = { 1, 'EOF was received from Nvim. Likely the Nvim process crashed.' }
end)
uv.run()
self._prepare:stop()

View File

@ -6,7 +6,7 @@ StdioStream.__index = StdioStream
function StdioStream.open()
local self = setmetatable({
_in = uv.new_pipe(false),
_out = uv.new_pipe(false)
_out = uv.new_pipe(false),
}, StdioStream)
self._in:open(0)
self._out:open(1)
@ -42,7 +42,7 @@ function SocketStream.open(file)
local socket = uv.new_pipe(false)
local self = setmetatable({
_socket = socket,
_stream_error = nil
_stream_error = nil,
}, SocketStream)
uv.pipe_connect(socket, file, function(err)
self._stream_error = self._stream_error or err
@ -54,7 +54,7 @@ function SocketStream.connect(host, port)
local socket = uv.new_tcp()
local self = setmetatable({
_socket = socket,
_stream_error = nil
_stream_error = nil,
}, SocketStream)
uv.tcp_connect(socket, host, port, function(err)
self._stream_error = self._stream_error or err
@ -62,7 +62,6 @@ function SocketStream.connect(host, port)
return self
end
function SocketStream:write(data)
if self._stream_error then
error(self._stream_error)
@ -102,9 +101,9 @@ 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;
_child_stdin = uv.new_pipe(false),
_child_stdout = uv.new_pipe(false),
_exiting = false,
}, ChildProcessStream)
local prog = argv[1]
local args = {}
@ -163,7 +162,7 @@ function ChildProcessStream:close(signal)
end
return {
StdioStream = StdioStream;
ChildProcessStream = ChildProcessStream;
SocketStream = SocketStream;
StdioStream = StdioStream,
ChildProcessStream = ChildProcessStream,
SocketStream = SocketStream,
}

View File

@ -25,7 +25,7 @@ local module = {
local function relpath(p)
p = vim.fs.normalize(p)
local cwd = luv.cwd()
return p:gsub("^" .. cwd)
return p:gsub('^' .. cwd)
end
--- @param path string
@ -94,7 +94,7 @@ function module.retry(max, max_ms, fn)
end
luv.update_time() -- Update cached value of luv.now() (libuv: uv_now()).
if (max and tries >= max) or (luv.now() - start_time > timeout) then
busted.fail(string.format("retry() attempts: %d\n%s", tries, tostring(result)), 2)
busted.fail(string.format('retry() attempts: %d\n%s', tries, tostring(result)), 2)
end
tries = tries + 1
luv.sleep(20) -- Avoid hot loop...
@ -120,7 +120,10 @@ end
--- @param expected (any) description of expected result
--- @param actual (any) description of actual result
function module.ok(cond, expected, actual)
assert((not expected and not actual) or (expected and actual), 'if "expected" is given, "actual" is also required')
assert(
(not expected and not actual) or (expected and actual),
'if "expected" is given, "actual" is also required'
)
local msg = expected and ('expected %s, got: %s'):format(expected, tostring(actual)) or nil
return assert(cond, msg)
end
@ -129,7 +132,7 @@ local function epicfail(state, arguments, _)
state.failure_message = arguments[1]
return false
end
assert:register("assertion", "epicfail", epicfail)
assert:register('assertion', 'epicfail', epicfail)
function module.fail(msg)
return assert.epicfail(msg)
end
@ -157,14 +160,26 @@ function module.assert_log(pat, logfile, nrlines, inverse)
module.retry(nil, 1000, function()
local lines = module.read_file_list(logfile, -nrlines) or {}
local msg = string.format('Pattern %q %sfound in log (last %d lines): %s:\n%s',
pat, (inverse and '' or 'not '), nrlines, logfile, ' '..table.concat(lines, '\n '))
local msg = string.format(
'Pattern %q %sfound in log (last %d lines): %s:\n%s',
pat,
(inverse and '' or 'not '),
nrlines,
logfile,
' ' .. table.concat(lines, '\n ')
)
for _, line in ipairs(lines) do
if line:match(pat) then
if inverse then error(msg) else return end
if inverse then
error(msg)
else
return
end
end
if not inverse then error(msg) end
end
if not inverse then
error(msg)
end
end)
end
@ -186,7 +201,8 @@ function module.pcall(fn, ...)
-- C:/long/path/foo.lua:186: Expected string, got number
-- to:
-- .../foo.lua:0: Expected string, got number
local errmsg = tostring(rv):gsub('([%s<])vim[/\\]([^%s:/\\]+):%d+', '%1\xffvim\xff%2:0')
local errmsg = tostring(rv)
:gsub('([%s<])vim[/\\]([^%s:/\\]+):%d+', '%1\xffvim\xff%2:0')
:gsub('[^%s<]-[/\\]([^%s:/\\]+):%d+', '.../%1:0')
:gsub('\xffvim\xff', 'vim/')
@ -233,7 +249,8 @@ end
function module.pcall_err_withtrace(fn, ...)
local errmsg = module.pcall_err_withfile(fn, ...)
return errmsg:gsub('^%.%.%./helpers%.lua:0: ', '')
return errmsg
:gsub('^%.%.%./helpers%.lua:0: ', '')
:gsub('^Error executing lua:- ', '')
:gsub('^%[string "<nvim>"%]:0: ', '')
end
@ -243,7 +260,7 @@ function module.pcall_err(...)
end
function module.remove_trace(s)
return (s:gsub("\n%s*stack traceback:.*", ""))
return (s:gsub('\n%s*stack traceback:.*', ''))
end
-- initial_path: directory to recurse into
@ -256,7 +273,9 @@ function module.glob(initial_path, re, exc_re)
local checked_files = {}
local function is_excluded(path)
for _, pat in pairs(exc_re) do
if path:match(pat) then return true end
if path:match(pat) then
return true
end
end
return false
end
@ -331,9 +350,10 @@ function module.check_logs()
end
end
end
assert(0 == #runtime_errors, string.format(
'Found runtime errors in logfile(s): %s',
table.concat(runtime_errors, ', ')))
assert(
0 == #runtime_errors,
string.format('Found runtime errors in logfile(s): %s', table.concat(runtime_errors, ', '))
)
end
function module.sysname()
@ -344,18 +364,16 @@ function module.sysname()
end
function module.is_os(s)
if not (s == 'win'
or s == 'mac'
or s == 'freebsd'
or s == 'openbsd'
or s == 'bsd') then
if not (s == 'win' or s == 'mac' or s == 'freebsd' or s == 'openbsd' or s == 'bsd') then
error('unknown platform: ' .. tostring(s))
end
return not not ((s == 'win' and (module.sysname():find('windows') or module.sysname():find('mingw')))
return not not (
(s == 'win' and (module.sysname():find('windows') or module.sysname():find('mingw')))
or (s == 'mac' and module.sysname() == 'darwin')
or (s == 'freebsd' and module.sysname() == 'freebsd')
or (s == 'openbsd' and module.sysname() == 'openbsd')
or (s == 'bsd' and module.sysname():find('bsd')))
or (s == 'bsd' and module.sysname():find('bsd'))
)
end
local function tmpdir_get()
@ -371,7 +389,7 @@ end
module.tmpname = (function()
local seq = 0
local tmpdir = tmpdir_get()
return (function()
return function()
if tmpdir_is_local(tmpdir) then
-- Cannot control os.tmpname() dir, so hack our own tmpname() impl.
seq = seq + 1
@ -392,7 +410,7 @@ module.tmpname = (function()
return fname
end
end
end)
end
end)()
function module.hasenv(name)
@ -417,14 +435,17 @@ function module.check_cores(app, force) -- luacheck: ignore
end
app = app or 'build/bin/nvim' -- luacheck: ignore
local initial_path, re, exc_re
local gdb_db_cmd = 'gdb -n -batch -ex "thread apply all bt full" "$_NVIM_TEST_APP" -c "$_NVIM_TEST_CORE"'
local gdb_db_cmd =
'gdb -n -batch -ex "thread apply all bt full" "$_NVIM_TEST_APP" -c "$_NVIM_TEST_CORE"'
local lldb_db_cmd = 'lldb -Q -o "bt all" -f "$_NVIM_TEST_APP" -c "$_NVIM_TEST_CORE"'
local random_skip = false
-- Workspace-local $TMPDIR, scrubbed and pattern-escaped.
-- "./Xtest-tmpdir/" => "Xtest%-tmpdir"
local local_tmpdir = (tmpdir_is_local(tmpdir_get())
local local_tmpdir = (
tmpdir_is_local(tmpdir_get())
and relpath(tmpdir_get()):gsub('^[ ./]+', ''):gsub('%/+$', ''):gsub('([^%w])', '%%%1')
or nil)
or nil
)
local db_cmd
if module.hasenv('NVIM_TEST_CORE_GLOB_DIRECTORY') then
initial_path = os.getenv('NVIM_TEST_CORE_GLOB_DIRECTORY')
@ -457,7 +478,7 @@ function module.check_cores(app, force) -- luacheck: ignore
local found_cores = 0
local out = io.stdout
for _, core in ipairs(cores) do
local len = 80 - #core - #('Core file ') - 2
local len = 80 - #core - #'Core file ' - 2
local esigns = ('='):rep(len / 2)
out:write(('\n%s Core file %s %s\n'):format(esigns, core, esigns))
out:flush()
@ -471,7 +492,7 @@ function module.check_cores(app, force) -- luacheck: ignore
end
tests_skipped = 0
if found_cores > 0 then
error("crash detected (see above)")
error('crash detected (see above)')
end
end
@ -611,13 +632,38 @@ local function format_float(v)
end
local SUBTBL = {
'\\000', '\\001', '\\002', '\\003', '\\004',
'\\005', '\\006', '\\007', '\\008', '\\t',
'\\n', '\\011', '\\012', '\\r', '\\014',
'\\015', '\\016', '\\017', '\\018', '\\019',
'\\020', '\\021', '\\022', '\\023', '\\024',
'\\025', '\\026', '\\027', '\\028', '\\029',
'\\030', '\\031',
'\\000',
'\\001',
'\\002',
'\\003',
'\\004',
'\\005',
'\\006',
'\\007',
'\\008',
'\\t',
'\\n',
'\\011',
'\\012',
'\\r',
'\\014',
'\\015',
'\\016',
'\\017',
'\\018',
'\\019',
'\\020',
'\\021',
'\\022',
'\\023',
'\\024',
'\\025',
'\\026',
'\\027',
'\\028',
'\\029',
'\\030',
'\\031',
}
-- Formats Lua value `v`.
@ -647,13 +693,14 @@ function module.format_luav(v, indent, opts)
if opts.literal_strings then
ret = v
else
local quote = opts.dquote_strings and '"' or '\''
ret = quote .. tostring(v):gsub(
opts.dquote_strings and '["\\]' or '[\'\\]',
'\\%0'):gsub(
'[%z\1-\31]', function(match)
local quote = opts.dquote_strings and '"' or "'"
ret = quote
.. tostring(v)
:gsub(opts.dquote_strings and '["\\]' or "['\\]", '\\%0')
:gsub('[%z\1-\31]', function(match)
return SUBTBL[match:byte() + 1]
end) .. quote
end)
.. quote
end
elseif type(v) == 'table' then
if v == module.REMOVE_THIS then
@ -664,8 +711,7 @@ function module.format_luav(v, indent, opts)
local non_empty = false
local format_luav = module.format_luav
for i, subv in ipairs(v) do
ret = ('%s%s%s,%s'):format(ret, next_indent,
format_luav(subv, next_indent_arg, opts), nl)
ret = ('%s%s%s,%s'):format(ret, next_indent, format_luav(subv, next_indent_arg, opts), nl)
processed_keys[i] = true
non_empty = true
end
@ -674,8 +720,7 @@ function module.format_luav(v, indent, opts)
if type(k) == 'string' and k:match('^[a-zA-Z_][a-zA-Z0-9_]*$') then
ret = ret .. next_indent .. k .. ' = '
else
ret = ('%s%s[%s] = '):format(ret, next_indent,
format_luav(k, nil, opts))
ret = ('%s%s[%s] = '):format(ret, next_indent, format_luav(k, nil, opts))
end
ret = ret .. format_luav(subv, next_indent_arg, opts) .. ',' .. nl
non_empty = true
@ -767,27 +812,27 @@ end
function module.hexdump(str)
local len = string.len(str)
local dump = ""
local hex = ""
local asc = ""
local dump = ''
local hex = ''
local asc = ''
for i = 1, len do
if 1 == i % 8 then
dump = dump .. hex .. asc .. "\n"
hex = string.format("%04x: ", i - 1)
asc = ""
dump = dump .. hex .. asc .. '\n'
hex = string.format('%04x: ', i - 1)
asc = ''
end
local ord = string.byte(str, i)
hex = hex .. string.format("%02x ", ord)
hex = hex .. string.format('%02x ', ord)
if ord >= 32 and ord <= 126 then
asc = asc .. string.char(ord)
else
asc = asc .. "."
asc = asc .. '.'
end
end
return dump .. hex .. string.rep(" ", 8 - len % 8) .. asc
return dump .. hex .. string.rep(' ', 8 - len % 8) .. asc
end
-- Reads text lines from `filename` into a table.
@ -805,16 +850,16 @@ function module.read_file_list(filename, start)
-- There is no need to read more than the last 2MB of the log file, so seek
-- to that.
local file_size = file:seek("end")
local file_size = file:seek('end')
local offset = file_size - 2000000
if offset < 0 then
offset = 0
end
file:seek("set", offset)
file:seek('set', offset)
local lines = {}
local i = 1
local line = file:read("*l")
local line = file:read('*l')
while line ~= nil do
if i >= start then
table.insert(lines, line)
@ -823,7 +868,7 @@ function module.read_file_list(filename, start)
end
end
i = i + 1
line = file:read("*l")
line = file:read('*l')
end
file:close()
return lines
@ -875,9 +920,12 @@ function module.read_nvim_log(logfile, ci_rename)
local is_ci = module.is_ci()
local keep = is_ci and 100 or 10
local lines = module.read_file_list(logfile, -keep) or {}
local log = (('-'):rep(78)..'\n'
local log = (
('-'):rep(78)
.. '\n'
.. string.format('$NVIM_LOG_FILE: %s\n', logfile)
..(#lines > 0 and '(last '..tostring(keep)..' lines)\n' or '(empty)\n'))
.. (#lines > 0 and '(last ' .. tostring(keep) .. ' lines)\n' or '(empty)\n')
)
for _, line in ipairs(lines) do
log = log .. line .. '\n'
end

View File

@ -2,8 +2,12 @@ local platform = vim.uv.os_uname()
local deps_install_dir = table.remove(_G.arg, 1)
local subcommand = table.remove(_G.arg, 1)
local suffix = (platform and platform.sysname:lower():find 'windows') and '.dll' or '.so'
package.path = deps_install_dir.."/share/lua/5.1/?.lua;"..deps_install_dir.."/share/lua/5.1/?/init.lua;"..package.path
package.cpath = deps_install_dir.."/lib/lua/5.1/?"..suffix..";"..package.cpath;
package.path = deps_install_dir
.. '/share/lua/5.1/?.lua;'
.. deps_install_dir
.. '/share/lua/5.1/?/init.lua;'
.. package.path
package.cpath = deps_install_dir .. '/lib/lua/5.1/?' .. suffix .. ';' .. package.cpath
local uv = vim.uv
@ -39,7 +43,9 @@ function lfs.attributes(path, attr)
if attr == 'mode' then
return stat and stat.type or ''
elseif attr == 'modification' then
if not stat then return nil end
if not stat then
return nil
end
local mtime = stat.mtime
return mtime.sec + mtime.nsec * 1e-9
else
@ -74,9 +80,9 @@ function lfs.mkdir(dir)
return uv.fs_mkdir(dir, 493) -- octal 755
end
if subcommand == "busted" then
if subcommand == 'busted' then
require 'busted.runner'({ standalone = false })
elseif subcommand == "luacheck" then
elseif subcommand == 'luacheck' then
require 'luacheck.main'
else
error 'unknown subcommand'

View File

@ -13,9 +13,11 @@ local int_type = eval_helpers.int_type
local flt_type = eval_helpers.flt_type
local type_key = eval_helpers.type_key
local api = cimport('./src/nvim/api/private/defs.h',
local api = cimport(
'./src/nvim/api/private/defs.h',
'./src/nvim/api/private/helpers.h',
'./src/nvim/memory.h')
'./src/nvim/memory.h'
)
local obj2lua
@ -68,14 +70,18 @@ end
obj2lua = function(obj)
init_obj2lua_tab()
return ((obj2lua_tab[tonumber(obj['type'])] or function(obj_inner)
assert(false, 'Converting ' .. tostring(tonumber(obj_inner['type'])) .. ' is not implementing yet')
end)(obj))
return (
(obj2lua_tab[tonumber(obj['type'])] or function(obj_inner)
assert(
false,
'Converting ' .. tostring(tonumber(obj_inner['type'])) .. ' is not implementing yet'
)
end)(obj)
)
end
local obj = function(typ, data)
return ffi.gc(ffi.new('Object', {['type']=typ, data=data}),
api.api_free_object)
return ffi.gc(ffi.new('Object', { ['type'] = typ, data = data }), api.api_free_object)
end
local lua2obj
@ -89,11 +95,13 @@ local lua2obj_type_tab = {
end,
[list_type] = function(l)
local len = #l
local arr = obj(api.kObjectTypeArray, {array={
local arr = obj(api.kObjectTypeArray, {
array = {
size = len,
capacity = len,
items = ffi.cast('Object *', api.xmalloc(len * ffi.sizeof('Object'))),
}})
},
})
for i = 1, len do
arr.data.array.items[i - 1] = ffi.gc(lua2obj(l[i]), nil)
end
@ -107,17 +115,19 @@ local lua2obj_type_tab = {
end
end
local len = #kvs
local dct = obj(api.kObjectTypeDictionary, {dictionary={
local dct = obj(api.kObjectTypeDictionary, {
dictionary = {
size = len,
capacity = len,
items=ffi.cast('KeyValuePair *',
api.xmalloc(len * ffi.sizeof('KeyValuePair'))),
}})
items = ffi.cast('KeyValuePair *', api.xmalloc(len * ffi.sizeof('KeyValuePair'))),
},
})
for i = 1, len do
local key, val = unpack(kvs[i])
dct.data.dictionary.items[i - 1] = ffi.new(
'KeyValuePair', {key=ffi.gc(lua2obj(key), nil).data.string,
value=ffi.gc(lua2obj(val), nil)})
'KeyValuePair',
{ key = ffi.gc(lua2obj(key), nil).data.string, value = ffi.gc(lua2obj(val), nil) }
)
end
return dct
end,
@ -139,10 +149,13 @@ lua2obj = function(l)
elseif type(l) == 'boolean' then
return obj(api.kObjectTypeBoolean, { boolean = l })
elseif type(l) == 'string' then
return obj(api.kObjectTypeString, {string={
return obj(
api.kObjectTypeString,
{ string = {
size = #l,
data = api.xmemdupz(to_cstr(l), #l),
}})
} }
)
elseif l == nil or l == nil_value then
return obj(api.kObjectTypeNil, { integer = 0 })
end

View File

@ -48,7 +48,10 @@ describe('vim_to_object', function()
simple_test('converts dictionary with containers inside', { test = {}, test2 = { 1, 2 } })
simple_test('converts empty list', { [type_key] = list_type })
simple_test('converts list with scalar values', { 1, 2, 'test', 'foo' })
simple_test('converts list with containers inside', {{}, {test={}, test3={test4=true}}})
simple_test(
'converts list with containers inside',
{ {}, { test = {}, test3 = { test4 = true } } }
)
local dct = {}
dct.dct = dct
@ -60,13 +63,19 @@ describe('vim_to_object', function()
local dct2 = { test = true, dict = nil_value }
dct2.dct = { dct2 }
different_output_test('outputs nil for nested dictionaries (2 level, in list)',
dct2, {dct={nil_value}, test=true, dict=nil_value})
different_output_test(
'outputs nil for nested dictionaries (2 level, in list)',
dct2,
{ dct = { nil_value }, test = true, dict = nil_value }
)
local dct3 = { test = true, dict = nil_value }
dct3.dct = { dctin = dct3 }
different_output_test('outputs nil for nested dictionaries (2 level, in dict)',
dct3, {dct={dctin=nil_value}, test=true, dict=nil_value})
different_output_test(
'outputs nil for nested dictionaries (2 level, in dict)',
dct3,
{ dct = { dctin = nil_value }, test = true, dict = nil_value }
)
local lst2 = {}
lst2[1] = { lst2 }
@ -74,8 +83,11 @@ describe('vim_to_object', function()
local lst3 = { nil, true, false, 'ttest' }
lst3[1] = { lst = lst3 }
different_output_test('outputs nil for nested lists (2 level, in dict)',
lst3, {{lst=nil_value}, true, false, 'ttest'})
different_output_test(
'outputs nil for nested lists (2 level, in dict)',
lst3,
{ { lst = nil_value }, true, false, 'ttest' }
)
itp('outputs empty list for NULL list', function()
local tt = typvalt('VAR_LIST', { v_list = NULL })

View File

@ -1,14 +1,13 @@
local helpers = require("test.unit.helpers")(after_each)
local helpers = require('test.unit.helpers')(after_each)
local itp = helpers.gen_itp(it)
local to_cstr = helpers.to_cstr
local eq = helpers.eq
local NULL = helpers.NULL
local buffer = helpers.cimport("./src/nvim/buffer.h")
local buffer = helpers.cimport('./src/nvim/buffer.h')
describe('buffer functions', function()
local buflist_new = function(file, flags)
local c_file = to_cstr(file)
return buffer.buflist_new(c_file, c_file, 1, flags)
@ -36,7 +35,6 @@ describe('buffer functions', function()
end)
describe('buf_valid', function()
itp('should view NULL as an invalid buffer', function()
eq(false, buffer.buf_valid(NULL))
end)
@ -72,9 +70,7 @@ describe('buffer functions', function()
end)
end)
describe('buflist_findpat', function()
local ALLOW_UNLISTED = 1
local ONLY_LISTED = 0
@ -95,9 +91,9 @@ describe('buffer functions', function()
local buf2 = buflist_new(path2, buffer.BLN_LISTED)
local buf3 = buflist_new(path3, buffer.BLN_LISTED)
eq(buf1.handle, buflist_findpat("test", ONLY_LISTED))
eq(buf2.handle, buflist_findpat("file", ONLY_LISTED))
eq(buf3.handle, buflist_findpat("path", ONLY_LISTED))
eq(buf1.handle, buflist_findpat('test', ONLY_LISTED))
eq(buf2.handle, buflist_findpat('file', ONLY_LISTED))
eq(buf3.handle, buflist_findpat('path', ONLY_LISTED))
close_buffer(NULL, buf1, buffer.DOBUF_WIPE, 0, 0)
close_buffer(NULL, buf2, buffer.DOBUF_WIPE, 0, 0)
@ -111,7 +107,7 @@ describe('buffer functions', function()
local buf3 = buflist_new(path3, buffer.BLN_LISTED)
-- Then: buf2 is the buffer that is found
eq(buf2.handle, buflist_findpat("test", ONLY_LISTED))
eq(buf2.handle, buflist_findpat('test', ONLY_LISTED))
--}
--{ When: We close buf2
@ -121,7 +117,7 @@ describe('buffer functions', function()
local buf1 = buflist_new(path1, buffer.BLN_LISTED)
-- Then: buf3 is found since 'file' appears at the end of the name
eq(buf3.handle, buflist_findpat("file", ONLY_LISTED))
eq(buf3.handle, buflist_findpat('file', ONLY_LISTED))
--}
close_buffer(NULL, buf1, buffer.DOBUF_WIPE, 0, 0)
@ -133,7 +129,7 @@ describe('buffer functions', function()
local buf2 = buflist_new(path2, buffer.BLN_LISTED)
local buf3 = buflist_new(path3, buffer.BLN_LISTED)
eq(buf3.handle, buflist_findpat("_test_", ONLY_LISTED))
eq(buf3.handle, buflist_findpat('_test_', ONLY_LISTED))
close_buffer(NULL, buf1, buffer.DOBUF_WIPE, 0, 0)
close_buffer(NULL, buf2, buffer.DOBUF_WIPE, 0, 0)
@ -145,25 +141,25 @@ describe('buffer functions', function()
local buf3 = buflist_new(path3, buffer.BLN_LISTED)
-- Then: We should find the buffer when it is given a unique pattern
eq(buf3.handle, buflist_findpat("_test_", ONLY_LISTED))
eq(buf3.handle, buflist_findpat('_test_', ONLY_LISTED))
--}
--{ When: We unlist the buffer
close_buffer(NULL, buf3, buffer.DOBUF_DEL, 0, 0)
-- Then: It should not find the buffer when searching only listed buffers
eq(-1, buflist_findpat("_test_", ONLY_LISTED))
eq(-1, buflist_findpat('_test_', ONLY_LISTED))
-- And: It should find the buffer when including unlisted buffers
eq(buf3.handle, buflist_findpat("_test_", ALLOW_UNLISTED))
eq(buf3.handle, buflist_findpat('_test_', ALLOW_UNLISTED))
--}
--{ When: We wipe the buffer
close_buffer(NULL, buf3, buffer.DOBUF_WIPE, 0, 0)
-- Then: It should not find the buffer at all
eq(-1, buflist_findpat("_test_", ONLY_LISTED))
eq(-1, buflist_findpat("_test_", ALLOW_UNLISTED))
eq(-1, buflist_findpat('_test_', ONLY_LISTED))
eq(-1, buflist_findpat('_test_', ALLOW_UNLISTED))
--}
end)
@ -173,7 +169,7 @@ describe('buffer functions', function()
local buf2 = buflist_new(path2, buffer.BLN_LISTED)
-- Then: The first buffer is preferred when both are listed
eq(buf1.handle, buflist_findpat("test", ONLY_LISTED))
eq(buf1.handle, buflist_findpat('test', ONLY_LISTED))
--}
--{ When: The first buffer is unlisted
@ -181,13 +177,13 @@ describe('buffer functions', function()
-- Then: The second buffer is preferred because
-- unlisted buffers are not allowed
eq(buf2.handle, buflist_findpat("test", ONLY_LISTED))
eq(buf2.handle, buflist_findpat('test', ONLY_LISTED))
--}
--{ When: We allow unlisted buffers
-- Then: The second buffer is still preferred
-- because listed buffers are preferred to unlisted
eq(buf2.handle, buflist_findpat("test", ALLOW_UNLISTED))
eq(buf2.handle, buflist_findpat('test', ALLOW_UNLISTED))
--}
--{ When: We unlist the second buffer
@ -196,10 +192,10 @@ describe('buffer functions', function()
-- Then: The first buffer is preferred again
-- because buf1 matches better which takes precedence
-- when both buffers have the same listing status.
eq(buf1.handle, buflist_findpat("test", ALLOW_UNLISTED))
eq(buf1.handle, buflist_findpat('test', ALLOW_UNLISTED))
-- And: Neither buffer is returned when ignoring unlisted
eq(-1, buflist_findpat("test", ONLY_LISTED))
eq(-1, buflist_findpat('test', ONLY_LISTED))
--}
close_buffer(NULL, buf1, buffer.DOBUF_WIPE, 0, 0)

View File

@ -1,4 +1,4 @@
local helpers = require("test.unit.helpers")(after_each)
local helpers = require('test.unit.helpers')(after_each)
local bit = require('bit')
local itp = helpers.gen_itp(it)
@ -44,7 +44,9 @@ local function argreset(arg, args)
end
local function test_vim_str2nr(s, what, exp, maxlen, strict)
if strict == nil then strict = true end
if strict == nil then
strict = true
end
local bits = {}
for k, _ in pairs(exp) do
bits[#bits + 1] = k
@ -54,7 +56,7 @@ local function test_vim_str2nr(s, what, exp, maxlen, strict)
for k, _ in pairs(ARGTYPES) do
args[k] = arginit(k)
end
for case = 0, ((2 ^ (#bits)) - 1) do
for case = 0, ((2 ^ #bits) - 1) do
local cv = {}
for b = 0, (#bits - 1) do
if bit.band(case, (2 ^ b)) == 0 then
@ -66,9 +68,17 @@ local function test_vim_str2nr(s, what, exp, maxlen, strict)
lib.vim_str2nr(s, cv.pre, cv.len, what, cv.num, cv.unum, maxlen, strict, nil)
for cck, ccv in pairs(cv) do
if exp[cck] ~= tonumber(ccv[0]) then
error(('Failed check (%s = %d) in test (s=%s, w=%u, m=%d, strict=%s): %d'):format(
cck, exp[cck], s, tonumber(what), maxlen, tostring(strict), tonumber(ccv[0])
))
error(
('Failed check (%s = %d) in test (s=%s, w=%u, m=%d, strict=%s): %d'):format(
cck,
exp[cck],
s,
tonumber(what),
maxlen,
tostring(strict),
tonumber(ccv[0])
)
)
end
end
end
@ -88,12 +98,42 @@ describe('vim_str2nr()', function()
test_vim_str2nr('', lib.STR2NR_OCT, { len = 0, num = 0, unum = 0, pre = 0 }, 0)
test_vim_str2nr('', lib.STR2NR_OOCT, { len = 0, num = 0, unum = 0, pre = 0 }, 0)
test_vim_str2nr('', lib.STR2NR_HEX, { len = 0, num = 0, unum = 0, pre = 0 }, 0)
test_vim_str2nr('', lib.STR2NR_FORCE + lib.STR2NR_DEC, {len = 0, num = 0, unum = 0, pre = 0}, 0)
test_vim_str2nr('', lib.STR2NR_FORCE + lib.STR2NR_BIN, {len = 0, num = 0, unum = 0, pre = 0}, 0)
test_vim_str2nr('', lib.STR2NR_FORCE + lib.STR2NR_OCT, {len = 0, num = 0, unum = 0, pre = 0}, 0)
test_vim_str2nr('', lib.STR2NR_FORCE + lib.STR2NR_OOCT, {len = 0, num = 0, unum = 0, pre = 0}, 0)
test_vim_str2nr('', lib.STR2NR_FORCE + lib.STR2NR_OCT + lib.STR2NR_OOCT, {len = 0, num = 0, unum = 0, pre = 0}, 0)
test_vim_str2nr('', lib.STR2NR_FORCE + lib.STR2NR_HEX, {len = 0, num = 0, unum = 0, pre = 0}, 0)
test_vim_str2nr(
'',
lib.STR2NR_FORCE + lib.STR2NR_DEC,
{ len = 0, num = 0, unum = 0, pre = 0 },
0
)
test_vim_str2nr(
'',
lib.STR2NR_FORCE + lib.STR2NR_BIN,
{ len = 0, num = 0, unum = 0, pre = 0 },
0
)
test_vim_str2nr(
'',
lib.STR2NR_FORCE + lib.STR2NR_OCT,
{ len = 0, num = 0, unum = 0, pre = 0 },
0
)
test_vim_str2nr(
'',
lib.STR2NR_FORCE + lib.STR2NR_OOCT,
{ len = 0, num = 0, unum = 0, pre = 0 },
0
)
test_vim_str2nr(
'',
lib.STR2NR_FORCE + lib.STR2NR_OCT + lib.STR2NR_OOCT,
{ len = 0, num = 0, unum = 0, pre = 0 },
0
)
test_vim_str2nr(
'',
lib.STR2NR_FORCE + lib.STR2NR_HEX,
{ len = 0, num = 0, unum = 0, pre = 0 },
0
)
end)
itp('works with decimal numbers', function()
for _, flags in ipairs({

View File

@ -6,9 +6,13 @@ local eq = helpers.eq
local neq = helpers.neq
local ffi = helpers.ffi
local decode = cimport('./src/nvim/eval/decode.h', './src/nvim/eval/typval.h',
'./src/nvim/globals.h', './src/nvim/memory.h',
'./src/nvim/message.h')
local decode = cimport(
'./src/nvim/eval/decode.h',
'./src/nvim/eval/typval.h',
'./src/nvim/globals.h',
'./src/nvim/memory.h',
'./src/nvim/message.h'
)
describe('json_decode_string()', function()
local char = function(c)
@ -74,8 +78,7 @@ describe('json_decode_string()', function()
collectgarbage('restart')
check_failure(']test', 1, 'E474: No container to close: ]')
check_failure('[}test', 2, 'E474: Closing list with curly bracket: }')
check_failure('{]test', 2,
'E474: Closing dictionary with square bracket: ]')
check_failure('{]test', 2, 'E474: Closing dictionary with square bracket: ]')
check_failure('[1,]test', 4, 'E474: Trailing comma: ]')
check_failure('{"1":}test', 6, 'E474: Expected value after colon: }')
check_failure('{"1"}test', 5, 'E474: Expected value: }')
@ -93,16 +96,20 @@ describe('json_decode_string()', function()
check_failure('ttest', 1, 'E474: Expected true: t')
check_failure('ftest', 1, 'E474: Expected false: f')
check_failure('"\\test', 2, 'E474: Unfinished escape sequence: "\\')
check_failure('"\\u"test', 4,
'E474: Unfinished unicode escape sequence: "\\u"')
check_failure('"\\uXXXX"est', 8,
'E474: Expected four hex digits after \\u: \\uXXXX"')
check_failure('"\\u"test', 4, 'E474: Unfinished unicode escape sequence: "\\u"')
check_failure('"\\uXXXX"est', 8, 'E474: Expected four hex digits after \\u: \\uXXXX"')
check_failure('"\\?"test', 4, 'E474: Unknown escape sequence: \\?"')
check_failure(
'"\t"test', 3,
'E474: ASCII control characters cannot be present inside string: \t"')
'"\t"test',
3,
'E474: ASCII control characters cannot be present inside string: \t"'
)
check_failure('"\194"test', 3, 'E474: Only UTF-8 strings allowed: \194"')
check_failure('"\252\144\128\128\128\128"test', 8, 'E474: Only UTF-8 code points up to U+10FFFF are allowed to appear unescaped: \252\144\128\128\128\128"')
check_failure(
'"\252\144\128\128\128\128"test',
8,
'E474: Only UTF-8 code points up to U+10FFFF are allowed to appear unescaped: \252\144\128\128\128\128"'
)
check_failure('"test', 1, 'E474: Expected string end: "')
check_failure('-test', 1, 'E474: Missing number after minus sign: -')
check_failure('-1.test', 3, 'E474: Missing number after decimal dot: -1.')

View File

@ -96,6 +96,9 @@ describe('encode_list_write()', function()
eq(0, encode_list_write(l, '\n\n\n'))
eq({ null_string, null_string, null_string, null_string }, lst2tbl(l))
eq(0, encode_list_write(l, '\n\n\n'))
eq({null_string, null_string, null_string, null_string, null_string, null_string, null_string}, lst2tbl(l))
eq(
{ null_string, null_string, null_string, null_string, null_string, null_string, null_string },
lst2tbl(l)
)
end)
end)

View File

@ -6,8 +6,12 @@ local to_cstr = helpers.to_cstr
local ffi = helpers.ffi
local eq = helpers.eq
local eval = cimport('./src/nvim/eval.h', './src/nvim/eval/typval.h',
'./src/nvim/hashtab.h', './src/nvim/memory.h')
local eval = cimport(
'./src/nvim/eval.h',
'./src/nvim/eval/typval.h',
'./src/nvim/hashtab.h',
'./src/nvim/memory.h'
)
local null_string = { [true] = 'NULL string' }
local null_list = { [true] = 'NULL list' }
@ -35,7 +39,9 @@ end
local function li_alloc(nogc)
local gcfunc = tv_list_item_free
if nogc then gcfunc = nil end
if nogc then
gcfunc = nil
end
local li = ffi.gc(tv_list_item_alloc(), gcfunc)
li.li_next = nil
li.li_prev = nil
@ -182,9 +188,11 @@ end
typvalt2lua = function(t, processed)
typvalt2lua_tab_init()
return ((typvalt2lua_tab[tonumber(t.v_type)] or function(t_inner)
return (
(typvalt2lua_tab[tonumber(t.v_type)] or function(t_inner)
assert(false, 'Converting ' .. tonumber(t_inner.v_type) .. ' was not implemented yet')
end)(t, processed or {}))
end)(t, processed or {})
)
end
local function list_iter(l)
@ -242,7 +250,9 @@ local function dict_iter(d, return_hi)
hi = d.dv_hashtab.ht_array,
}
local function f(s, _)
if s.todo == 0 then return nil end
if s.todo == 0 then
return nil
end
while s.todo > 0 do
if s.hi.hi_key ~= nil and s.hi.hi_key ~= hi_key_removed then
local key = ffi.string(s.hi.hi_key)
@ -250,8 +260,7 @@ local function dict_iter(d, return_hi)
if return_hi then
ret = s.hi
else
ret = ffi.cast('dictitem_T*',
s.hi.hi_key - ffi.offsetof('dictitem_T', 'di_key'))
ret = ffi.cast('dictitem_T*', s.hi.hi_key - ffi.offsetof('dictitem_T', 'di_key'))
end
s.todo = s.todo - 1
s.hi = s.hi + 1
@ -333,12 +342,15 @@ local lua2typvalt_type_tab = {
return typvalt(eval.VAR_PARTIAL, { v_partial = processed[l] })
end
if l.args or l.dict then
local pt = populate_partial(ffi.gc(ffi.cast('partial_T*',
eval.xcalloc(1, ffi.sizeof('partial_T'))), nil), l, processed)
local pt = populate_partial(
ffi.gc(ffi.cast('partial_T*', eval.xcalloc(1, ffi.sizeof('partial_T'))), nil),
l,
processed
)
return typvalt(eval.VAR_PARTIAL, { v_partial = pt })
else
return typvalt(eval.VAR_FUNC, {
v_string=eval.xmemdupz(to_cstr(l.value), #l.value)
v_string = eval.xmemdupz(to_cstr(l.value), #l.value),
})
end
end,
@ -408,24 +420,44 @@ local function alloc_len(len, get_ptr)
end
local alloc_logging_helpers = {
list = function(l) return {func='calloc', args={1, ffi.sizeof('list_T')}, ret=void(l)} end,
li = function(li) return {func='malloc', args={ffi.sizeof('listitem_T')}, ret=void(li)} end,
dict = function(d) return {func='calloc', args={1, ffi.sizeof('dict_T')}, ret=void(d)} end,
list = function(l)
return { func = 'calloc', args = { 1, ffi.sizeof('list_T') }, ret = void(l) }
end,
li = function(li)
return { func = 'malloc', args = { ffi.sizeof('listitem_T') }, ret = void(li) }
end,
dict = function(d)
return { func = 'calloc', args = { 1, ffi.sizeof('dict_T') }, ret = void(d) }
end,
di = function(di, size)
size = alloc_len(size, function() return di.di_key end)
return {func='malloc', args={ffi.offsetof('dictitem_T', 'di_key') + size + 1}, ret=void(di)}
size = alloc_len(size, function()
return di.di_key
end)
return {
func = 'malloc',
args = { ffi.offsetof('dictitem_T', 'di_key') + size + 1 },
ret = void(di),
}
end,
str = function(s, size)
size = alloc_len(size, function() return s end)
size = alloc_len(size, function()
return s
end)
return { func = 'malloc', args = { size + 1 }, ret = void(s) }
end,
dwatcher = function(w) return {func='malloc', args={ffi.sizeof('DictWatcher')}, ret=void(w)} end,
dwatcher = function(w)
return { func = 'malloc', args = { ffi.sizeof('DictWatcher') }, ret = void(w) }
end,
freed = function(p) return {func='free', args={type(p) == 'table' and p or void(p)}} end,
freed = function(p)
return { func = 'free', args = { type(p) == 'table' and p or void(p) } }
end,
-- lua_…: allocated by this file, not by some Neovim function
lua_pt = function(pt) return {func='calloc', args={1, ffi.sizeof('partial_T')}, ret=void(pt)} end,
lua_pt = function(pt)
return { func = 'calloc', args = { 1, ffi.sizeof('partial_T') }, ret = void(pt) }
end,
lua_tvs = function(argv, argc)
argc = alloc_len(argc)
return { func = 'malloc', args = { ffi.sizeof('typval_T') * argc }, ret = void(argv) }
@ -437,14 +469,15 @@ local function int(n)
end
local function list(...)
return populate_list(ffi.gc(eval.tv_list_alloc(select('#', ...)),
eval.tv_list_unref),
{...}, {})
return populate_list(
ffi.gc(eval.tv_list_alloc(select('#', ...)), eval.tv_list_unref),
{ ... },
{}
)
end
local function dict(d)
return populate_dict(ffi.gc(eval.tv_dict_alloc(), eval.tv_dict_free),
d or {}, {})
return populate_dict(ffi.gc(eval.tv_dict_alloc(), eval.tv_dict_free), d or {}, {})
end
local callback2tbl_type_tab = nil
@ -454,14 +487,16 @@ local function init_callback2tbl_type_tab()
return
end
callback2tbl_type_tab = {
[tonumber(eval.kCallbackNone)] = function(_) return {type='none'} end,
[tonumber(eval.kCallbackNone)] = function(_)
return { type = 'none' }
end,
[tonumber(eval.kCallbackFuncref)] = function(cb)
return { type = 'fref', fref = ffi.string(cb.data.funcref) }
end,
[tonumber(eval.kCallbackPartial)] = function(cb)
local lua_pt = partial2lua(cb.data.partial)
return { type = 'pt', fref = ffi.string(lua_pt.value), pt = lua_pt }
end
end,
}
end
@ -475,13 +510,16 @@ local function tbl2callback(tbl)
if tbl.type == 'none' then
ret = ffi.new('Callback[1]', { { type = eval.kCallbackNone } })
elseif tbl.type == 'fref' then
ret = ffi.new('Callback[1]', {{type=eval.kCallbackFuncref,
data={funcref=eval.xstrdup(tbl.fref)}}})
ret = ffi.new(
'Callback[1]',
{ { type = eval.kCallbackFuncref, data = { funcref = eval.xstrdup(tbl.fref) } } }
)
elseif tbl.type == 'pt' then
local pt = ffi.gc(ffi.cast('partial_T*',
eval.xcalloc(1, ffi.sizeof('partial_T'))), nil)
ret = ffi.new('Callback[1]', {{type=eval.kCallbackPartial,
data={partial=populate_partial(pt, tbl.pt, {})}}})
local pt = ffi.gc(ffi.cast('partial_T*', eval.xcalloc(1, ffi.sizeof('partial_T'))), nil)
ret = ffi.new(
'Callback[1]',
{ { type = eval.kCallbackPartial, data = { partial = populate_partial(pt, tbl.pt, {}) } } }
)
else
assert(false)
end
@ -495,8 +533,8 @@ local function dict_watchers(d)
local qs = {}
local key_patterns = {}
while q ~= h do
local qitem = ffi.cast('DictWatcher *',
ffi.cast('char *', q) - ffi.offsetof('DictWatcher', 'node'))
local qitem =
ffi.cast('DictWatcher *', ffi.cast('char *', q) - ffi.offsetof('DictWatcher', 'node'))
ret[#ret + 1] = {
cb = callback2tbl(qitem.callback),
pat = ffi.string(qitem.key_pattern, qitem.key_pattern_len),
@ -510,8 +548,7 @@ local function dict_watchers(d)
end
local function eval0(expr)
local tv = ffi.gc(ffi.new('typval_T', {v_type=eval.VAR_UNKNOWN}),
eval.tv_clear)
local tv = ffi.gc(ffi.new('typval_T', { v_type = eval.VAR_UNKNOWN }), eval.tv_clear)
local evalarg = ffi.new('evalarg_T', { eval_flags = eval.EVAL_EVALUATE })
if eval.eval0(to_cstr(expr), tv, nil, evalarg) == 0 then
return nil

View File

@ -8,8 +8,7 @@ local eq = helpers.eq
local eval0 = eval_helpers.eval0
local eval = cimport('./src/nvim/eval.h', './src/nvim/eval/typval.h',
'./src/nvim/memory.h')
local eval = cimport('./src/nvim/eval.h', './src/nvim/eval/typval.h', './src/nvim/memory.h')
describe('NULL typval_T', function()
itp('is produced by $XXX_UNEXISTENT_VAR_XXX', function()

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
local helpers = require("test.unit.helpers")(after_each)
local helpers = require('test.unit.helpers')(after_each)
local itp = helpers.gen_itp(it)
--{:cimport, :internalize, :eq, :neq, :ffi, :lib, :cstr, :to_cstr} = require 'test.unit.helpers'
@ -7,11 +7,10 @@ local ffi = helpers.ffi
local to_cstr = helpers.to_cstr
local NULL = helpers.NULL
local fileio = helpers.cimport("./src/nvim/fileio.h")
local fileio = helpers.cimport('./src/nvim/fileio.h')
describe('file_pat functions', function()
describe('file_pat_to_reg_pat', function()
local file_pat_to_reg_pat = function(pat)
local res = fileio.file_pat_to_reg_pat(to_cstr(pat), NULL, NULL, 0)
return ffi.string(res)
@ -37,10 +36,12 @@ describe('file_pat functions', function()
eq('^foo.bar$', file_pat_to_reg_pat('foo?bar'))
end)
itp('replaces a glob (*) in the middle of a path with regex multiple any character (.*)',
itp(
'replaces a glob (*) in the middle of a path with regex multiple any character (.*)',
function()
eq('^foo.*bar$', file_pat_to_reg_pat('foo*bar'))
end)
end
)
itp([[unescapes \? to ?]], function()
eq('^foo?bar$', file_pat_to_reg_pat([[foo\?bar]]))

View File

@ -24,99 +24,141 @@ SOFTWARE. --]]
-- work.
-- see: http://lua-users.org/wiki/LpegRecipes
local lpeg = require "lpeg"
local lpeg = require 'lpeg'
local C, P, R, S, V = lpeg.C, lpeg.P, lpeg.R, lpeg.S, lpeg.V
local Carg, Cc, Cp, Ct = lpeg.Carg, lpeg.Cc, lpeg.Cp, lpeg.Ct
local tokens = P { "tokens";
local tokens = P {
'tokens',
-- Comment of form /* ... */
comment = Ct(P"/*" * C((V"newline" + (1 - P"*/"))^0) * P"*/" * Cc"comment"),
comment = Ct(P '/*' * C((V 'newline' + (1 - P '*/')) ^ 0) * P '*/' * Cc 'comment'),
-- Single line comment
line_comment = Ct(P"//" * C((1 - V"newline")^0) * Cc"comment_line"),
line_comment = Ct(P '//' * C((1 - V 'newline') ^ 0) * Cc 'comment_line'),
-- Single platform independent line break which increments line number
newline = (P"\r\n" + P"\n\r" + S"\r\n") * (Cp() * Carg(1)) / function(pos, state)
newline = (P '\r\n' + P '\n\r' + S '\r\n') * (Cp() * Carg(1)) / function(pos, state)
state.line = state.line + 1
state.line_start = pos
end,
-- Line continuation
line_extend = Ct(C(P[[\]] * V"newline") * Cc"line_extend"),
line_extend = Ct(C(P [[\]] * V 'newline') * Cc 'line_extend'),
-- Whitespace of any length (includes newlines)
whitespace = Ct(C((S" \t" + V"newline")^1) * Cc"whitespace"),
whitespace = Ct(C((S ' \t' + V 'newline') ^ 1) * Cc 'whitespace'),
-- Special form of #include with filename followed in angled brackets (matches 3 tokens)
include = Ct(C(P"#include") * Cc"preprocessor") *
Ct(C(S" \t"^1) * Cc"whitespace") *
Ct(C(P"<" * (1 - P">")^1 * P">") * Cc"string"),
include = Ct(C(P '#include') * Cc 'preprocessor') * Ct(C(S ' \t' ^ 1) * Cc 'whitespace') * Ct(
C(P '<' * (1 - P '>') ^ 1 * P '>') * Cc 'string'
),
-- Preprocessor instruction
preprocessor = V"include" +
Ct(C(P"#" * P" "^0 * ( P"define" + P"elif" + P"else" + P"endif" + P"#" +
P"error" + P"ifdef" + P"ifndef" + P"if" + P"import" +
P"include" + P"line" + P"pragma" + P"undef" + P"using" +
P"pragma"
) * #S" \r\n\t") * Cc"preprocessor"),
preprocessor = V 'include'
+ Ct(
C(
P '#'
* P ' ' ^ 0
* (P 'define' + P 'elif' + P 'else' + P 'endif' + P '#' + P 'error' + P 'ifdef' + P 'ifndef' + P 'if' + P 'import' + P 'include' + P 'line' + P 'pragma' + P 'undef' + P 'using' + P 'pragma')
* #S ' \r\n\t'
) * Cc 'preprocessor'
),
-- Identifier of form [a-zA-Z_][a-zA-Z0-9_]*
identifier = Ct(C(R("az","AZ","__") * R("09","az","AZ","__")^0) * Cc"identifier"),
identifier = Ct(C(R('az', 'AZ', '__') * R('09', 'az', 'AZ', '__') ^ 0) * Cc 'identifier'),
-- Single character in a string
sstring_char = R("\001&","([","]\255") + (P"\\" * S[[ntvbrfa\?'"0x]]),
dstring_char = R("\001!","#[","]\255") + (P"\\" * S[[ntvbrfa\?'"0x]]),
sstring_char = R('\001&', '([', ']\255') + (P '\\' * S [[ntvbrfa\?'"0x]]),
dstring_char = R('\001!', '#[', ']\255') + (P '\\' * S [[ntvbrfa\?'"0x]]),
-- String literal
string = Ct(C(P"'" * (V"sstring_char" + P'"')^0 * P"'" +
P'"' * (V"dstring_char" + P"'")^0 * P'"') * Cc"string"),
string = Ct(
C(
P "'" * (V 'sstring_char' + P '"') ^ 0 * P "'"
+ P '"' * (V 'dstring_char' + P "'") ^ 0 * P '"'
) * Cc 'string'
),
-- Operator
operator = Ct(C(P">>=" + P"<<=" + P"..." +
P"::" + P"<<" + P">>" + P"<=" + P">=" + P"==" + P"!=" +
P"||" + P"&&" + P"++" + P"--" + P"->" + P"+=" + P"-=" +
P"*=" + P"/=" + P"|=" + P"&=" + P"^=" + S"+-*/=<>%^|&.?:!~,") * Cc"operator"),
operator = Ct(
C(
P '>>='
+ P '<<='
+ P '...'
+ P '::'
+ P '<<'
+ P '>>'
+ P '<='
+ P '>='
+ P '=='
+ P '!='
+ P '||'
+ P '&&'
+ P '++'
+ P '--'
+ P '->'
+ P '+='
+ P '-='
+ P '*='
+ P '/='
+ P '|='
+ P '&='
+ P '^='
+ S '+-*/=<>%^|&.?:!~,'
) * Cc 'operator'
),
-- Misc. char (token type is the character itself)
char = Ct(C(S"[]{}();") / function(x) return x, x end),
char = Ct(C(S '[]{}();') / function(x)
return x, x
end),
-- Hex, octal or decimal number
int = Ct(C((P"0x" * R("09","af","AF")^1) + (P"0" * R"07"^0) + R"09"^1) * Cc"integer"),
int = Ct(
C((P '0x' * R('09', 'af', 'AF') ^ 1) + (P '0' * R '07' ^ 0) + R '09' ^ 1) * Cc 'integer'
),
-- Floating point number
f_exponent = S"eE" + S"+-"^-1 * R"09"^1,
f_terminator = S"fFlL",
float = Ct(C(
R"09"^1 * V"f_exponent" * V"f_terminator"^-1 +
R"09"^0 * P"." * R"09"^1 * V"f_exponent"^-1 * V"f_terminator"^-1 +
R"09"^1 * P"." * R"09"^0 * V"f_exponent"^-1 * V"f_terminator"^-1
) * Cc"float"),
f_exponent = S 'eE' + S '+-' ^ -1 * R '09' ^ 1,
f_terminator = S 'fFlL',
float = Ct(
C(
R '09' ^ 1 * V 'f_exponent' * V 'f_terminator' ^ -1
+ R '09' ^ 0 * P '.' * R '09' ^ 1 * V 'f_exponent' ^ -1 * V 'f_terminator' ^ -1
+ R '09' ^ 1 * P '.' * R '09' ^ 0 * V 'f_exponent' ^ -1 * V 'f_terminator' ^ -1
) * Cc 'float'
),
-- Any token
token = V"comment" +
V"line_comment" +
V"identifier" +
V"whitespace" +
V"line_extend" +
V"preprocessor" +
V"string" +
V"char" +
V"operator" +
V"float" +
V"int",
token = V 'comment'
+ V 'line_comment'
+ V 'identifier'
+ V 'whitespace'
+ V 'line_extend'
+ V 'preprocessor'
+ V 'string'
+ V 'char'
+ V 'operator'
+ V 'float'
+ V 'int',
-- Error for when nothing else matches
error = (Cp() * C(P(1) ^ -8) * Carg(1)) / function(pos, where, state)
error(("Tokenising error on line %i, position %i, near '%s'")
:format(state.line, pos - state.line_start + 1, where))
error(
("Tokenising error on line %i, position %i, near '%s'"):format(
state.line,
pos - state.line_start + 1,
where
)
)
end,
-- Match end of input or throw error
finish = -P(1) + V"error",
finish = -P(1) + V 'error',
-- Match stream of tokens into a table
tokens = Ct(V"token" ^ 0) * V"finish",
tokens = Ct(V 'token' ^ 0) * V 'finish',
}
local function TokeniseC(str)
@ -132,10 +174,37 @@ local function set(t)
end
local C_keywords = set { -- luacheck: ignore
"break", "case", "char", "const", "continue", "default", "do", "double",
"else", "enum", "extern", "float", "for", "goto", "if", "int", "long",
"register", "return", "short", "signed", "sizeof", "static", "struct",
"switch", "typedef", "union", "unsigned", "void", "volatile", "while",
'break',
'case',
'char',
'const',
'continue',
'default',
'do',
'double',
'else',
'enum',
'extern',
'float',
'for',
'goto',
'if',
'int',
'long',
'register',
'return',
'short',
'signed',
'sizeof',
'static',
'struct',
'switch',
'typedef',
'union',
'unsigned',
'void',
'volatile',
'while',
}
-- Very primitive C formatter that tries to put "things" inside braces on one
@ -174,7 +243,7 @@ local function formatc(str)
-- if we're not inside a block, we're at the basic statement level,
-- and ';' indicates we're at the end of a statement, so we put end
-- it with a newline.
token[1] = token[1] .. "\n"
token[1] = token[1] .. '\n'
end_at_brace = false
end
elseif typ == 'identifier' then
@ -194,20 +263,20 @@ local function formatc(str)
-- if we're not inside a block, we're at the basic statement level,
-- and ';' indicates we're at the end of a statement, so we put end
-- it with a newline.
token[1] = ";\n"
token[1] = ';\n'
end
elseif typ == 'whitespace' then
-- replace all whitespace by one space
local repl = " "
local repl = ' '
-- except when allow_on_nl is true and there's a newline in the whitespace
if string.find(token[1], "[\r\n]+") and allow_one_nl == true then
if string.find(token[1], '[\r\n]+') and allow_one_nl == true then
-- in that case we replace all whitespace by one newline
repl = "\n"
repl = '\n'
allow_one_nl = false
end
token[1] = string.gsub(token[1], "%s+", repl)
token[1] = string.gsub(token[1], '%s+', repl)
end
result[#result + 1] = token[1]
end
@ -217,7 +286,7 @@ end
-- standalone operation (very handy for debugging)
local function standalone(...) -- luacheck: ignore
local Preprocess = require("preprocess")
local Preprocess = require('preprocess')
Preprocess.add_to_include_path('./../../src')
Preprocess.add_to_include_path('./../../build/include')
Preprocess.add_to_include_path('./../../.deps/usr/include')

View File

@ -1,4 +1,4 @@
local helpers = require("test.unit.helpers")(after_each)
local helpers = require('test.unit.helpers')(after_each)
local itp = helpers.gen_itp(it)
local cimport = helpers.cimport
@ -157,7 +157,9 @@ local ga_append_ints = function(garr, ...)
end
-- enhanced constructors
local garray_ctype = function(...) return ffi.typeof('garray_T[1]')(...) end
local garray_ctype = function(...)
return ffi.typeof('garray_T[1]')(...)
end
local new_garray = function()
local garr = garray_ctype()
return ffi.gc(garr, ga_clear)
@ -165,7 +167,7 @@ end
local new_string_garray = function()
local garr = garray_ctype()
ga_init(garr, ffi.sizeof("unsigned char *"), 1)
ga_init(garr, ffi.sizeof('unsigned char *'), 1)
return ffi.gc(garr, ga_clear_strings)
end
@ -182,7 +184,6 @@ local ga_scramble = function(garr)
end
describe('garray', function()
describe('ga_init', function()
itp('initializes the values of the garray', function()
local garr = new_garray()
@ -252,7 +253,7 @@ describe('garray', function()
-- this is the actual ga_append, the others are just emulated lua
-- versions
local garr = new_garray()
ga_init(garr, ffi.sizeof("uint8_t"), 1)
ga_init(garr, ffi.sizeof('uint8_t'), 1)
ga_append(garr, 'h')
ga_append(garr, 'e')
ga_append(garr, 'l')
@ -265,13 +266,13 @@ describe('garray', function()
itp('can append integers', function()
local garr = new_garray()
ga_init(garr, ffi.sizeof("int"), 1)
ga_init(garr, ffi.sizeof('int'), 1)
local input = {
-20,
94,
867615,
90927,
86
86,
}
ga_append_ints(garr, unpack(input))
local ints = ga_data_as_ints(garr)
@ -283,11 +284,11 @@ describe('garray', function()
itp('can append strings to a growing array of strings', function()
local garr = new_string_garray()
local input = {
"some",
"str",
"\r\n\r●●●●●●,,,",
"hmm",
"got it"
'some',
'str',
'\r\n\r●●●●●●,,,',
'hmm',
'got it',
}
ga_append_strings(garr, unpack(input))
-- check that we can get the same strings out of the array
@ -301,8 +302,8 @@ describe('garray', function()
describe('ga_concat', function()
itp('concatenates the parameter to the growing byte array', function()
local garr = new_garray()
ga_init(garr, ffi.sizeof("char"), 1)
local str = "ohwell●●"
ga_init(garr, ffi.sizeof('char'), 1)
local str = 'ohwell●●'
local loop = 5
for _ = 1, loop do
ga_concat(garr, str)
@ -338,7 +339,7 @@ describe('garray', function()
test_concat_fn({
'oh',
'my',
'neovim'
'neovim',
}, ga_concat_strings)
end)
end)
@ -353,7 +354,7 @@ describe('garray', function()
test_concat_fn({
'oh',
'my',
'neovim'
'neovim',
}, ga_concat_strings_sep, sep)
end)
end)
@ -370,13 +371,13 @@ describe('garray', function()
'bbb',
'ccc',
'ccc',
'ddd●●'
'ddd●●',
}
local sorted_dedup_input = {
'aaa',
'bbb',
'ccc',
'ddd●●'
'ddd●●',
}
ga_append_strings(garr, unpack(input))
ga_remove_duplicate_strings(garr)

View File

@ -133,25 +133,28 @@ local pragma_pack_id = 1
local function filter_complex_blocks(body)
local result = {} --- @type string[]
for line in body:gmatch("[^\r\n]+") do
if not (string.find(line, "(^)", 1, true) ~= nil
or string.find(line, "_ISwupper", 1, true)
or string.find(line, "_Float")
or string.find(line, "__s128")
or string.find(line, "__u128")
or string.find(line, "msgpack_zone_push_finalizer")
or string.find(line, "msgpack_unpacker_reserve_buffer")
or string.find(line, "value_init_")
or string.find(line, "UUID_NULL") -- static const uuid_t UUID_NULL = {...}
or string.find(line, "inline _Bool")) then
for line in body:gmatch('[^\r\n]+') do
if
not (
string.find(line, '(^)', 1, true) ~= nil
or string.find(line, '_ISwupper', 1, true)
or string.find(line, '_Float')
or string.find(line, '__s128')
or string.find(line, '__u128')
or string.find(line, 'msgpack_zone_push_finalizer')
or string.find(line, 'msgpack_unpacker_reserve_buffer')
or string.find(line, 'value_init_')
or string.find(line, 'UUID_NULL') -- static const uuid_t UUID_NULL = {...}
or string.find(line, 'inline _Bool')
)
then
result[#result + 1] = line
end
end
return table.concat(result, "\n")
return table.concat(result, '\n')
end
local cdef = ffi.cdef
local cimportstr
@ -185,8 +188,7 @@ local function cimport(...)
cdefs = cdefs_init
end
for _, path in ipairs({ ... }) do
if not (path:sub(1, 1) == '/' or path:sub(1, 1) == '.'
or path:sub(2, 2) == ':') then
if not (path:sub(1, 1) == '/' or path:sub(1, 1) == '.' or path:sub(2, 2) == ':') then
path = './' .. path
end
if not preprocess_cache[path] then
@ -205,15 +207,15 @@ local function cimport(...)
body = filter_complex_blocks(body)
-- add the formatted lines to a set
local new_cdefs = Set:new()
for line in body:gmatch("[^\r\n]+") do
for line in body:gmatch('[^\r\n]+') do
line = trim(line)
-- give each #pragma pack an unique id, so that they don't get removed
-- if they are inserted into the set
-- (they are needed in the right order with the struct definitions,
-- otherwise luajit has wrong memory layouts for the sturcts)
if line:match("#pragma%s+pack") then
if line:match('#pragma%s+pack') then
--- @type string
line = line .. " // " .. pragma_pack_id
line = line .. ' // ' .. pragma_pack_id
pragma_pack_id = pragma_pack_id + 1
end
new_cdefs:add(line)
@ -314,7 +316,9 @@ local function alloc_log_new()
log_entry.args[i] = self.null
end
end
if self.hook then self:hook(log_entry) end
if self.hook then
self:hook(log_entry)
end
if log_entry.ret then
return log_entry.ret
end
@ -365,11 +369,9 @@ local function alloc_log_new()
log:set_mocks()
end
function log:before_each()
end
function log:before_each() end
function log:after_each()
end
function log:after_each() end
log:setup()
@ -400,10 +402,9 @@ function sc.pipe()
local ret = ffi.new('int[2]', { -1, -1 })
ffi.errno(0)
local res = ffi.C.pipe(ret)
if (res ~= 0) then
if res ~= 0 then
local err = ffi.errno(0)
assert(res == 0, ("pipe() error: %u: %s"):format(
err, ffi.string(ffi.C.strerror(err))))
assert(res == 0, ('pipe() error: %u: %s'):format(err, ffi.string(ffi.C.strerror(err))))
end
assert(ret[0] ~= -1 and ret[1] ~= -1)
return ret[0], ret[1]
@ -415,15 +416,12 @@ function sc.read(rd, len)
local total_bytes_read = 0
ffi.errno(0)
while total_bytes_read < len do
local bytes_read = tonumber(ffi.C.read(
rd,
ffi.cast('void*', ret + total_bytes_read),
len - total_bytes_read))
local bytes_read =
tonumber(ffi.C.read(rd, ffi.cast('void*', ret + total_bytes_read), len - total_bytes_read))
if bytes_read == -1 then
local err = ffi.errno(0)
if err ~= ffi.C.kPOSIXErrnoEINTR then
assert(false, ("read() error: %u: %s"):format(
err, ffi.string(ffi.C.strerror(err))))
assert(false, ('read() error: %u: %s'):format(err, ffi.string(ffi.C.strerror(err))))
end
elseif bytes_read == 0 then
break
@ -439,15 +437,16 @@ function sc.write(wr, s)
local total_bytes_written = 0
ffi.errno(0)
while total_bytes_written < #s do
local bytes_written = tonumber(ffi.C.write(
wr,
ffi.cast('void*', wbuf + total_bytes_written),
#s - total_bytes_written))
local bytes_written = tonumber(
ffi.C.write(wr, ffi.cast('void*', wbuf + total_bytes_written), #s - total_bytes_written)
)
if bytes_written == -1 then
local err = ffi.errno(0)
if err ~= ffi.C.kPOSIXErrnoEINTR then
assert(false, ("write() error: %u: %s ('%s')"):format(
err, ffi.string(ffi.C.strerror(err)), s))
assert(
false,
("write() error: %u: %s ('%s')"):format(err, ffi.string(ffi.C.strerror(err)), s)
)
end
elseif bytes_written == 0 then
break
@ -472,8 +471,7 @@ function sc.wait(pid)
if err == ffi.C.kPOSIXErrnoECHILD then
break
elseif err ~= ffi.C.kPOSIXErrnoEINTR then
assert(false, ("waitpid() error: %u: %s"):format(
err, ffi.string(ffi.C.strerror(err))))
assert(false, ('waitpid() error: %u: %s'):format(err, ffi.string(ffi.C.strerror(err))))
end
else
assert(r == pid)
@ -499,8 +497,7 @@ if os.getenv('NVIM_TEST_PRINT_SYSCALLS') == '1' then
(function(k, v)
sc[k] = function(...)
local rets = { v(...) }
io.stderr:write(('%s(%s) = %s\n'):format(k, format_list({...}),
format_list(rets)))
io.stderr:write(('%s(%s) = %s\n'):format(k, format_list({ ... }), format_list(rets)))
return unpack(rets)
end
end)(k_, v_)
@ -512,9 +509,13 @@ local function just_fail(_)
end
say:set('assertion.just_fail.positive', '%s')
say:set('assertion.just_fail.negative', '%s')
assert:register('assertion', 'just_fail', just_fail,
assert:register(
'assertion',
'just_fail',
just_fail,
'assertion.just_fail.positive',
'assertion.just_fail.negative')
'assertion.just_fail.negative'
)
local hook_fnamelen = 30
local hook_sfnamelen = 30
@ -615,11 +616,14 @@ local function child_sethook(wr)
.. whatchar
.. namewhatchar
.. ' '
.. source .. (' '):rep(hook_sfnamelen - #source)
.. source
.. (' '):rep(hook_sfnamelen - #source)
.. ':'
.. funcname .. (' '):rep(hook_fnamelen - #funcname)
.. funcname
.. (' '):rep(hook_fnamelen - #funcname)
.. ':'
.. ('0'):rep(hook_numlen - #lnum_s) .. lnum_s
.. ('0'):rep(hook_numlen - #lnum_s)
.. lnum_s
.. '\n'
)
-- eq(hook_msglen, #msg)
@ -751,7 +755,7 @@ local function itp_parent(rd, pid, allow_failure, location)
end
elseif status ~= 0 then
if not allow_failure then
error("child process errored out with status "..status.."!\n\n"..location)
error('child process errored out with status ' .. status .. '!\n\n' .. location)
end
end
end
@ -760,7 +764,9 @@ local function gen_itp(it)
child_calls_mod = {}
child_calls_mod_once = {}
child_cleanups_mod_once = {}
preprocess_cache_mod = map(function(v) return v end, preprocess_cache_init)
preprocess_cache_mod = map(function(v)
return v
end, preprocess_cache_init)
previous_defines_mod = previous_defines_init
cdefs_mod = cdefs_init:copy()
local function itp(name, func, allow_failure)
@ -794,8 +800,7 @@ local function cppimport(path)
return cimport(Paths.test_source_path .. '/test/includes/pre/' .. path)
end
cimport('./src/nvim/types.h', './src/nvim/main.h', './src/nvim/os/time.h',
'./src/nvim/os/fs.h')
cimport('./src/nvim/types.h', './src/nvim/main.h', './src/nvim/os/time.h', './src/nvim/os/fs.h')
local function conv_enum(etab, eval)
local n = tonumber(eval)
@ -853,7 +858,9 @@ end
local function is_asan()
cimport('./src/nvim/version.h')
local status, res = pcall(function() return lib.version_cflags end)
local status, res = pcall(function()
return lib.version_cflags
end)
if status then
return ffi.string(res):match('-fsanitize=[a-z,]*address')
else

View File

@ -1,10 +1,10 @@
local helpers = require("test.unit.helpers")(after_each)
local helpers = require('test.unit.helpers')(after_each)
local itp = helpers.gen_itp(it)
local eq = helpers.eq
local indent = helpers.cimport("./src/nvim/indent.h")
local globals = helpers.cimport("./src/nvim/globals.h")
local indent = helpers.cimport('./src/nvim/indent.h')
local globals = helpers.cimport('./src/nvim/globals.h')
describe('get_sts_value', function()
itp([[returns 'softtabstop' when it is non-negative]], function()

View File

@ -1,4 +1,4 @@
local helpers = require("test.unit.helpers")(after_each)
local helpers = require('test.unit.helpers')(after_each)
local itp = helpers.gen_itp(it)
local ffi = helpers.ffi
@ -9,7 +9,6 @@ local keycodes = helpers.cimport('./src/nvim/keycodes.h')
local NULL = helpers.NULL
describe('keycodes.c', function()
describe('find_special_key()', function()
local srcp = ffi.new('const unsigned char *[1]')
local modp = ffi.new('int[1]')
@ -28,31 +27,26 @@ describe('keycodes.c', function()
itp('case-insensitive', function()
-- Compare other capitalizations to this.
srcp[0] = '<C-A>'
local all_caps_key =
keycodes.find_special_key(srcp, 5, modp, 0, NULL)
local all_caps_key = keycodes.find_special_key(srcp, 5, modp, 0, NULL)
local all_caps_mod = modp[0]
srcp[0] = '<C-a>'
eq(all_caps_key,
keycodes.find_special_key(srcp, 5, modp, 0, NULL))
eq(all_caps_key, keycodes.find_special_key(srcp, 5, modp, 0, NULL))
eq(all_caps_mod, modp[0])
srcp[0] = '<c-A>'
eq(all_caps_key,
keycodes.find_special_key(srcp, 5, modp, 0, NULL))
eq(all_caps_key, keycodes.find_special_key(srcp, 5, modp, 0, NULL))
eq(all_caps_mod, modp[0])
srcp[0] = '<c-a>'
eq(all_caps_key,
keycodes.find_special_key(srcp, 5, modp, 0, NULL))
eq(all_caps_key, keycodes.find_special_key(srcp, 5, modp, 0, NULL))
eq(all_caps_mod, modp[0])
end)
itp('double-quote in keycode #7411', function()
-- Unescaped with in_string=false
srcp[0] = '<C-">'
eq(string.byte('"'),
keycodes.find_special_key(srcp, 5, modp, 0, NULL))
eq(string.byte('"'), keycodes.find_special_key(srcp, 5, modp, 0, NULL))
-- Unescaped with in_string=true
eq(0, keycodes.find_special_key(srcp, 5, modp, keycodes.FSK_IN_STRING, NULL))
@ -64,9 +58,7 @@ describe('keycodes.c', function()
eq(0, keycodes.find_special_key(srcp, 6, modp, 0, NULL))
-- Escaped with in_string=true
eq(string.byte('"'),
keycodes.find_special_key(srcp, 6, modp, keycodes.FSK_IN_STRING, NULL))
eq(string.byte('"'), keycodes.find_special_key(srcp, 6, modp, keycodes.FSK_IN_STRING, NULL))
end)
end)
end)

View File

@ -1,15 +1,17 @@
local helpers = require("test.unit.helpers")(after_each)
local helpers = require('test.unit.helpers')(after_each)
local itp = helpers.gen_itp(it)
local ffi = helpers.ffi
local eq = helpers.eq
local ok = helpers.ok
local lib = helpers.cimport("./src/nvim/marktree.h")
local lib = helpers.cimport('./src/nvim/marktree.h')
local function tablelength(t)
local count = 0
for _ in pairs(t) do count = count + 1 end
for _ in pairs(t) do
count = count + 1
end
return count
end
@ -32,15 +34,27 @@ local function shadoworder(tree, shadow, iter, giveorder)
local mark = lib.marktree_itr_current(iter)
local id = tonumber(mark.id)
local spos = shadow[id]
if (mark.pos.row ~= spos[1] or mark.pos.col ~= spos[2]) then
error("invalid pos for "..id..":("..mark.pos.row..", "..mark.pos.col..") instead of ("..spos[1]..", "..spos[2]..")")
if mark.pos.row ~= spos[1] or mark.pos.col ~= spos[2] then
error(
'invalid pos for '
.. id
.. ':('
.. mark.pos.row
.. ', '
.. mark.pos.col
.. ') instead of ('
.. spos[1]
.. ', '
.. spos[2]
.. ')'
)
end
if lib.mt_right_test(mark) ~= spos[3] then
error("invalid gravity for "..id..":("..mark.pos.row..", "..mark.pos.col..")")
error('invalid gravity for ' .. id .. ':(' .. mark.pos.row .. ', ' .. mark.pos.col .. ')')
end
if count > 0 then
if not pos_leq(last, spos) then
error("DISORDER")
error('DISORDER')
end
end
count = count + 1
@ -52,16 +66,20 @@ local function shadoworder(tree, shadow, iter, giveorder)
until not lib.marktree_itr_next(tree, iter)
local shadowlen = tablelength(shadow)
if shadowlen ~= count then
error("missed some keys? (shadow "..shadowlen..", tree "..count..")")
error('missed some keys? (shadow ' .. shadowlen .. ', tree ' .. count .. ')')
end
return id2pos, pos2id
end
local function shadowsplice(shadow, start, old_extent, new_extent)
local old_end = {start[1] + old_extent[1],
(old_extent[1] == 0 and start[2] or 0) + old_extent[2]}
local new_end = {start[1] + new_extent[1],
(new_extent[1] == 0 and start[2] or 0) + new_extent[2]}
local old_end = {
start[1] + old_extent[1],
(old_extent[1] == 0 and start[2] or 0) + old_extent[2],
}
local new_end = {
start[1] + new_extent[1],
(new_extent[1] == 0 and start[2] or 0) + new_extent[2],
}
local delta = { new_end[1] - old_end[1], new_end[2] - old_end[2] }
for _, pos in pairs(shadow) do
if pos_leq(start, pos) then
@ -83,7 +101,15 @@ local function shadowsplice(shadow, start, old_extent, new_extent)
end
local function dosplice(tree, shadow, start, old_extent, new_extent)
lib.marktree_splice(tree, start[1], start[2], old_extent[1], old_extent[2], new_extent[1], new_extent[2])
lib.marktree_splice(
tree,
start[1],
start[2],
old_extent[1],
old_extent[2],
new_extent[1],
new_extent[2]
)
shadowsplice(shadow, start, old_extent, new_extent)
end
@ -98,7 +124,7 @@ local function put(tree, row, col, gravitate, end_row, end_col, end_gravitate)
end_col = end_col or -1
end_gravitate = end_gravitate or false
lib.marktree_put_test(tree, ns, my_id, row, col, gravitate, end_row, end_col, end_gravitate);
lib.marktree_put_test(tree, ns, my_id, row, col, gravitate, end_row, end_col, end_gravitate)
return my_id
end
@ -108,10 +134,10 @@ describe('marktree', function()
end)
itp('works', function()
local tree = ffi.new("MarkTree[1]") -- zero initialized by luajit
local tree = ffi.new('MarkTree[1]') -- zero initialized by luajit
local shadow = {}
local iter = ffi.new("MarkTreeIter[1]")
local iter2 = ffi.new("MarkTreeIter[1]")
local iter = ffi.new('MarkTreeIter[1]')
local iter2 = ffi.new('MarkTreeIter[1]')
for i = 1, 100 do
for j = 1, 100 do
@ -224,27 +250,39 @@ describe('marktree', function()
itp("'intersect_mov' function works correctly", function()
local function mov(x, y, w)
local xa = ffi.new("uint64_t[?]", #x)
for i, xi in ipairs(x) do xa[i-1] = xi end
local ya = ffi.new("uint64_t[?]", #y)
for i, yi in ipairs(y) do ya[i-1] = yi end
local wa = ffi.new("uint64_t[?]", #w)
for i, wi in ipairs(w) do wa[i-1] = wi end
local xa = ffi.new('uint64_t[?]', #x)
for i, xi in ipairs(x) do
xa[i - 1] = xi
end
local ya = ffi.new('uint64_t[?]', #y)
for i, yi in ipairs(y) do
ya[i - 1] = yi
end
local wa = ffi.new('uint64_t[?]', #w)
for i, wi in ipairs(w) do
wa[i - 1] = wi
end
local dummy_size = #x + #y + #w
local wouta = ffi.new("uint64_t[?]", dummy_size)
local douta = ffi.new("uint64_t[?]", dummy_size)
local wsize = ffi.new("size_t[1]")
local wouta = ffi.new('uint64_t[?]', dummy_size)
local douta = ffi.new('uint64_t[?]', dummy_size)
local wsize = ffi.new('size_t[1]')
wsize[0] = dummy_size
local dsize = ffi.new("size_t[1]")
local dsize = ffi.new('size_t[1]')
dsize[0] = dummy_size
local status = lib.intersect_mov_test(xa, #x, ya, #y, wa, #w, wouta, wsize, douta, dsize)
if status == 0 then error'wowza' end
if status == 0 then
error 'wowza'
end
local wout, dout = {}, {}
for i = 0,tonumber(wsize[0])-1 do table.insert(wout, tonumber(wouta[i])) end
for i = 0,tonumber(dsize[0])-1 do table.insert(dout, tonumber(douta[i])) end
for i = 0, tonumber(wsize[0]) - 1 do
table.insert(wout, tonumber(wouta[i]))
end
for i = 0, tonumber(dsize[0]) - 1 do
table.insert(dout, tonumber(douta[i]))
end
return { wout, dout }
end
@ -260,10 +298,12 @@ describe('marktree', function()
eq({ { 1, 3, 5, 7, 9 }, { 2, 6, 10 } }, mov({ 1, 3, 5, 7, 9 }, { 2, 4, 6, 8, 10 }, { 4, 8 }))
eq({ { 1, 4, 7 }, { 2, 5, 8 } }, mov({ 1, 3, 4, 6, 7, 9 }, { 2, 3, 5, 6, 8, 9 }, {}))
eq({ { 1, 4, 7 }, {} }, mov({ 1, 3, 4, 6, 7, 9 }, { 2, 3, 5, 6, 8, 9 }, { 2, 5, 8 }))
eq({{0,1,4,7,10}, {}}, mov({1,3,4,6,7,9}, {2,3,5,6,8,9}, {0,2,5,8,10}))
eq(
{ { 0, 1, 4, 7, 10 }, {} },
mov({ 1, 3, 4, 6, 7, 9 }, { 2, 3, 5, 6, 8, 9 }, { 0, 2, 5, 8, 10 })
)
end)
local function check_intersections(tree)
lib.marktree_check(tree)
-- to debug stuff disable this branch
@ -279,13 +319,13 @@ describe('marktree', function()
if not val then
local str2 = lib.mt_inspect(tree, true, true)
local dot2 = ffi.string(str2.data, str2.size)
print("actual:\n\n".."Xafile.dot".."\n\nexpected:\n\n".."Xefile.dot".."\n")
print("nivå", tree[0].root.level);
print('actual:\n\n' .. 'Xafile.dot' .. '\n\nexpected:\n\n' .. 'Xefile.dot' .. '\n')
print('nivå', tree[0].root.level)
io.stdout:flush()
local afil = io.open("Xafile.dot", "wb")
local afil = io.open('Xafile.dot', 'wb')
afil:write(dot1)
afil:close()
local efil = io.open("Xefile.dot", "wb")
local efil = io.open('Xefile.dot', 'wb')
efil:write(dot2)
efil:close()
ok(false)
@ -295,7 +335,7 @@ describe('marktree', function()
end
itp('works with intersections', function()
local tree = ffi.new("MarkTree[1]") -- zero initialized by luajit
local tree = ffi.new('MarkTree[1]') -- zero initialized by luajit
local ids = {}
@ -324,7 +364,7 @@ describe('marktree', function()
end)
itp('works with intersections with a big tree', function()
local tree = ffi.new("MarkTree[1]") -- zero initialized by luajit
local tree = ffi.new('MarkTree[1]') -- zero initialized by luajit
local ids = {}
@ -339,7 +379,7 @@ describe('marktree', function()
eq(2000, tree[0].n_keys)
ok(tree[0].root.level >= 2)
local iter = ffi.new("MarkTreeIter[1]")
local iter = ffi.new('MarkTreeIter[1]')
local k = 0
for i = 1, 20 do
@ -367,7 +407,7 @@ describe('marktree', function()
end)
itp('works with intersections and marktree_splice', function()
local tree = ffi.new("MarkTree[1]") -- zero initialized by luajit
local tree = ffi.new('MarkTree[1]') -- zero initialized by luajit
for i = 1, 1000 do
put(tree, 1, i, false, 2, 1000 - i, false)
@ -387,8 +427,8 @@ describe('marktree', function()
end)
itp('marktree_move should preserve key order', function()
local tree = ffi.new("MarkTree[1]") -- zero initialized by luajit
local iter = ffi.new("MarkTreeIter[1]")
local tree = ffi.new('MarkTree[1]') -- zero initialized by luajit
local iter = ffi.new('MarkTreeIter[1]')
local ids = {}
-- new index and old index look the same, but still have to move because
@ -405,7 +445,7 @@ describe('marktree', function()
end)
itp('works with intersections and marktree_move', function()
local tree = ffi.new("MarkTree[1]") -- zero initialized by luajit
local tree = ffi.new('MarkTree[1]') -- zero initialized by luajit
local ids = {}
@ -416,7 +456,7 @@ describe('marktree', function()
end
end
local iter = ffi.new("MarkTreeIter[1]")
local iter = ffi.new('MarkTreeIter[1]')
for i = 1, 1000 do
local which = i % 2
lib.marktree_lookup_ns(tree, ns, ids[i], which, iter)
@ -425,11 +465,10 @@ describe('marktree', function()
check_intersections(tree)
end
end
end)
itp('works with intersections with a even bigger tree', function()
local tree = ffi.new("MarkTree[1]") -- zero initialized by luajit
local tree = ffi.new('MarkTree[1]') -- zero initialized by luajit
local ids = {}
@ -467,8 +506,8 @@ describe('marktree', function()
ok(tree[0].root.level >= 3)
check_intersections(tree)
local iter = ffi.new("MarkTreeIter[1]")
local pair = ffi.new("MTPair[1]")
local iter = ffi.new('MarkTreeIter[1]')
local pair = ffi.new('MTPair[1]')
for i = 1, 10 do
-- use array as set and not {[id]=true} map, to detect duplicates
local set = {}
@ -499,7 +538,7 @@ describe('marktree', function()
end)
itp('works with intersections with a even bigger tree and splice', function()
local tree = ffi.new("MarkTree[1]") -- zero initialized by luajit
local tree = ffi.new('MarkTree[1]') -- zero initialized by luajit
-- too much overhead on ASAN
local size_factor = helpers.is_asan() and 3 or 10

View File

@ -1,4 +1,4 @@
local helpers = require("test.unit.helpers")(after_each)
local helpers = require('test.unit.helpers')(after_each)
local itp = helpers.gen_itp(it)
local ffi = helpers.ffi
@ -16,8 +16,7 @@ describe('mbyte', function()
return table.concat(s)
end
before_each(function()
end)
before_each(function() end)
itp('utf_ptr2char', function()
-- For strings with length 1 the first byte is returned.
@ -48,8 +47,8 @@ describe('mbyte', function()
describe('utfc_ptr2schar_len', function()
local function test_seq(seq)
local firstc = ffi.new("int[1]")
local buf = ffi.new("char[32]")
local firstc = ffi.new('int[1]')
local buf = ffi.new('char[32]')
lib.schar_get(buf, lib.utfc_ptr2schar_len(to_string(seq), #seq, firstc))
return { ffi.string(buf), firstc[0] }
end
@ -89,36 +88,35 @@ describe('mbyte', function()
eq(byte(0x7f), test_seq { 0x7f, 0xc2, 0x80 })
-- Combining character is U+0300
eq({"\x7f\xcc\x80", 0x7f}, test_seq{0x7f, 0xcc, 0x80})
eq({ '\x7f\xcc\x80', 0x7f }, test_seq { 0x7f, 0xcc, 0x80 })
-- No UTF-8 sequence
eq({ '', 0xc2 }, test_seq { 0xc2, 0x7f, 0xcc })
-- Incomplete combining character
eq({"\xc2\x80", 0x80}, test_seq{0xc2, 0x80, 0xcc})
eq({ '\xc2\x80', 0x80 }, test_seq { 0xc2, 0x80, 0xcc })
-- One UTF-8 character (composing only)
eq({" \xe2\x83\x90", 0x20d0}, test_seq{0xe2, 0x83, 0x90})
eq({ ' \xe2\x83\x90', 0x20d0 }, test_seq { 0xe2, 0x83, 0x90 })
end)
itp('4-byte sequences', function()
-- No following combining character
eq(byte(0x7f), test_seq { 0x7f, 0x7f, 0xcc, 0x80 })
-- No second UTF-8 character
eq(byte(0x7f), test_seq { 0x7f, 0xc2, 0xcc, 0x80 })
-- Combining character U+0300
eq({"\x7f\xcc\x80", 0x7f}, test_seq{0x7f, 0xcc, 0x80, 0xcc})
eq({ '\x7f\xcc\x80', 0x7f }, test_seq { 0x7f, 0xcc, 0x80, 0xcc })
-- No UTF-8 sequence
eq({ '', 0xc2 }, test_seq { 0xc2, 0x7f, 0xcc, 0x80 })
-- No following UTF-8 character
eq({"\xc2\x80", 0x80}, test_seq{0xc2, 0x80, 0xcc, 0xcc})
eq({ '\xc2\x80', 0x80 }, test_seq { 0xc2, 0x80, 0xcc, 0xcc })
-- Combining character U+0301
eq({"\xc2\x80\xcc\x81", 0x80}, test_seq{0xc2, 0x80, 0xcc, 0x81})
eq({ '\xc2\x80\xcc\x81', 0x80 }, test_seq { 0xc2, 0x80, 0xcc, 0x81 })
-- One UTF-8 character
eq({"\xf4\x80\x80\x80", 0x100000}, test_seq{0xf4, 0x80, 0x80, 0x80})
eq({ '\xf4\x80\x80\x80', 0x100000 }, test_seq { 0xf4, 0x80, 0x80, 0x80 })
end)
itp('5+-byte sequences', function()
@ -128,46 +126,81 @@ describe('mbyte', function()
eq(byte(0x7f), test_seq { 0x7f, 0xc2, 0xcc, 0x80, 0x80 })
-- Combining character U+0300
eq({"\x7f\xcc\x80", 0x7f}, test_seq{0x7f, 0xcc, 0x80, 0xcc, 0x00})
eq({ '\x7f\xcc\x80', 0x7f }, test_seq { 0x7f, 0xcc, 0x80, 0xcc, 0x00 })
-- Combining characters U+0300 and U+0301
eq({"\x7f\xcc\x80\xcc\x81", 0x7f}, test_seq{0x7f, 0xcc, 0x80, 0xcc, 0x81})
eq({ '\x7f\xcc\x80\xcc\x81', 0x7f }, test_seq { 0x7f, 0xcc, 0x80, 0xcc, 0x81 })
-- Combining characters U+0300, U+0301, U+0302
eq({"\x7f\xcc\x80\xcc\x81\xcc\x82", 0x7f}, test_seq{0x7f, 0xcc, 0x80, 0xcc, 0x81, 0xcc, 0x82})
eq(
{ '\x7f\xcc\x80\xcc\x81\xcc\x82', 0x7f },
test_seq { 0x7f, 0xcc, 0x80, 0xcc, 0x81, 0xcc, 0x82 }
)
-- Combining characters U+0300, U+0301, U+0302, U+0303
eq({"\x7f\xcc\x80\xcc\x81\xcc\x82\xcc\x83", 0x7f}, test_seq{0x7f, 0xcc, 0x80, 0xcc, 0x81, 0xcc, 0x82, 0xcc, 0x83})
eq(
{ '\x7f\xcc\x80\xcc\x81\xcc\x82\xcc\x83', 0x7f },
test_seq { 0x7f, 0xcc, 0x80, 0xcc, 0x81, 0xcc, 0x82, 0xcc, 0x83 }
)
-- Combining characters U+0300, U+0301, U+0302, U+0303, U+0304
eq({"\x7f\xcc\x80\xcc\x81\xcc\x82\xcc\x83\xcc\x84", 0x7f}, test_seq{0x7f, 0xcc, 0x80, 0xcc, 0x81, 0xcc, 0x82, 0xcc, 0x83, 0xcc, 0x84})
eq(
{ '\x7f\xcc\x80\xcc\x81\xcc\x82\xcc\x83\xcc\x84', 0x7f },
test_seq { 0x7f, 0xcc, 0x80, 0xcc, 0x81, 0xcc, 0x82, 0xcc, 0x83, 0xcc, 0x84 }
)
-- Combining characters U+0300, U+0301, U+0302, U+0303, U+0304, U+0305
eq({"\x7f\xcc\x80\xcc\x81\xcc\x82\xcc\x83\xcc\x84\xcc\x85", 0x7f}, test_seq{0x7f, 0xcc, 0x80, 0xcc, 0x81, 0xcc, 0x82, 0xcc, 0x83, 0xcc, 0x84, 0xcc, 0x85})
eq(
{ '\x7f\xcc\x80\xcc\x81\xcc\x82\xcc\x83\xcc\x84\xcc\x85', 0x7f },
test_seq { 0x7f, 0xcc, 0x80, 0xcc, 0x81, 0xcc, 0x82, 0xcc, 0x83, 0xcc, 0x84, 0xcc, 0x85 }
)
-- Combining characters U+0300, U+0301, U+0302, U+0303, U+0304, U+0305, U+0306
eq({"\x7f\xcc\x80\xcc\x81\xcc\x82\xcc\x83\xcc\x84\xcc\x85\xcc\x86", 0x7f}, test_seq{0x7f, 0xcc, 0x80, 0xcc, 0x81, 0xcc, 0x82, 0xcc, 0x83, 0xcc, 0x84, 0xcc, 0x85, 0xcc, 0x86})
eq(
{ '\x7f\xcc\x80\xcc\x81\xcc\x82\xcc\x83\xcc\x84\xcc\x85\xcc\x86', 0x7f },
test_seq {
0x7f,
0xcc,
0x80,
0xcc,
0x81,
0xcc,
0x82,
0xcc,
0x83,
0xcc,
0x84,
0xcc,
0x85,
0xcc,
0x86,
}
)
-- Only three following combining characters U+0300, U+0301, U+0302
eq({"\x7f\xcc\x80\xcc\x81\xcc\x82", 0x7f}, test_seq{0x7f, 0xcc, 0x80, 0xcc, 0x81, 0xcc, 0x82, 0xc2, 0x80, 0xcc, 0x84, 0xcc, 0x85})
eq(
{ '\x7f\xcc\x80\xcc\x81\xcc\x82', 0x7f },
test_seq { 0x7f, 0xcc, 0x80, 0xcc, 0x81, 0xcc, 0x82, 0xc2, 0x80, 0xcc, 0x84, 0xcc, 0x85 }
)
-- No UTF-8 sequence
eq({ '', 0xc2 }, test_seq { 0xc2, 0x7f, 0xcc, 0x80, 0x80 })
-- No following UTF-8 character
eq({"\xc2\x80", 0x80}, test_seq{0xc2, 0x80, 0xcc, 0xcc, 0x80})
eq({ '\xc2\x80', 0x80 }, test_seq { 0xc2, 0x80, 0xcc, 0xcc, 0x80 })
-- Combining character U+0301
eq({"\xc2\x80\xcc\x81", 0x80}, test_seq{0xc2, 0x80, 0xcc, 0x81, 0x7f})
eq({ '\xc2\x80\xcc\x81', 0x80 }, test_seq { 0xc2, 0x80, 0xcc, 0x81, 0x7f })
-- Combining character U+0301
eq({"\xc2\x80\xcc\x81", 0x80}, test_seq{0xc2, 0x80, 0xcc, 0x81, 0xcc})
eq({ '\xc2\x80\xcc\x81', 0x80 }, test_seq { 0xc2, 0x80, 0xcc, 0x81, 0xcc })
-- One UTF-8 character
eq({"\xf4\x80\x80\x80", 0x100000}, test_seq{0xf4, 0x80, 0x80, 0x80, 0x7f})
eq({ '\xf4\x80\x80\x80', 0x100000 }, test_seq { 0xf4, 0x80, 0x80, 0x80, 0x7f })
-- One UTF-8 character
eq({"\xf4\x80\x80\x80", 0x100000}, test_seq{0xf4, 0x80, 0x80, 0x80, 0x80})
eq({ '\xf4\x80\x80\x80', 0x100000 }, test_seq { 0xf4, 0x80, 0x80, 0x80, 0x80 })
-- One UTF-8 character
eq({"\xf4\x80\x80\x80", 0x100000}, test_seq{0xf4, 0x80, 0x80, 0x80, 0xcc})
eq({ '\xf4\x80\x80\x80', 0x100000 }, test_seq { 0xf4, 0x80, 0x80, 0x80, 0xcc })
-- Combining characters U+1AB0 and U+0301
eq({"\xf4\x80\x80\x80\xe1\xaa\xb0\xcc\x81", 0x100000}, test_seq{0xf4, 0x80, 0x80, 0x80, 0xe1, 0xaa, 0xb0, 0xcc, 0x81})
eq(
{ '\xf4\x80\x80\x80\xe1\xaa\xb0\xcc\x81', 0x100000 },
test_seq { 0xf4, 0x80, 0x80, 0x80, 0xe1, 0xaa, 0xb0, 0xcc, 0x81 }
)
end)
end)
end)

View File

@ -1,4 +1,4 @@
local helpers = require("test.unit.helpers")(after_each)
local helpers = require('test.unit.helpers')(after_each)
local itp = helpers.gen_itp(it)
local cimport = helpers.cimport
@ -22,8 +22,7 @@ describe('xstrlcat()', function()
assert.is_true(dsize >= 1 + string.len(dst)) -- sanity check for tests
local dst_cstr = cstr(dsize, dst)
local src_cstr = dst_cstr + src_idx -- pointer into `dst` (overlaps)
eq(string.len(dst) + string.len(dst) - src_idx,
cimp.xstrlcat(dst_cstr, src_cstr, dsize))
eq(string.len(dst) + string.len(dst) - src_idx, cimp.xstrlcat(dst_cstr, src_cstr, dsize))
return ffi.string(dst_cstr)
end
@ -48,5 +47,4 @@ describe('xstrlcat()', function()
eq('', test_xstrlcat('', 'b', 1))
eq('ABCיהZd', test_xstrlcat('ABCיהZ', 'defgiיהZ', 10))
end)
end)

View File

@ -1,12 +1,11 @@
local helpers = require("test.unit.helpers")(after_each)
local helpers = require('test.unit.helpers')(after_each)
local itp = helpers.gen_itp(it)
local ffi = helpers.ffi
local eq = helpers.eq
local to_cstr = helpers.to_cstr
local cimp = helpers.cimport('./src/nvim/message.h', './src/nvim/memory.h',
'./src/nvim/strings.h')
local cimp = helpers.cimport('./src/nvim/message.h', './src/nvim/memory.h', './src/nvim/strings.h')
describe('trunc_string', function()
local buflen = 40

View File

@ -35,7 +35,9 @@ end
describe('msgpack', function()
describe('unpacker', function()
itp('does not crash when paused between `cells` and `wrap` params of `grid_line` #25184', function()
itp(
'does not crash when paused between `cells` and `wrap` params of `grid_line` #25184',
function()
-- [kMessageTypeNotification, "redraw", [
-- ["grid_line",
-- [2, 0, 0, [[" " , 0, 77]], false]
@ -54,13 +56,15 @@ describe('msgpack', function()
unpacker[0].read_size = unpacker[0].read_size + 1
finished = unpacker_advance(unpacker)
eq(finished, true)
end)
end
)
itp('does not crash when parsing grid_line event with 0 `cells` #25184', function()
local unpacker = make_unpacker()
lib.unpacker_init(unpacker)
unpacker_goto(unpacker,
unpacker_goto(
unpacker,
-- [kMessageTypeNotification, "redraw", [
-- ["grid_line",
-- [2, 0, 0, [], false]

View File

@ -1,4 +1,4 @@
local helpers = require("test.unit.helpers")(after_each)
local helpers = require('test.unit.helpers')(after_each)
local itp = helpers.gen_itp(it)
local child_call_once = helpers.child_call_once
@ -6,9 +6,9 @@ local cimport = helpers.cimport
local ffi = helpers.ffi
local eq = helpers.eq
local multiqueue = cimport("./test/unit/fixtures/multiqueue.h")
local multiqueue = cimport('./test/unit/fixtures/multiqueue.h')
describe("multiqueue (multi-level event-queue)", function()
describe('multiqueue (multi-level event-queue)', function()
local parent, child1, child2, child3
local function put(q, str)

View File

@ -1,28 +1,27 @@
local helpers = require("test.unit.helpers")(after_each)
local helpers = require('test.unit.helpers')(after_each)
local itp = helpers.gen_itp(it)
local to_cstr = helpers.to_cstr
local eq = helpers.eq
local optionstr = helpers.cimport("./src/nvim/optionstr.h")
local optionstr = helpers.cimport('./src/nvim/optionstr.h')
local check_ff_value = function(ff)
return optionstr.check_ff_value(to_cstr(ff))
end
describe('check_ff_value', function()
itp('views empty string as valid', function()
eq(1, check_ff_value(""))
eq(1, check_ff_value(''))
end)
itp('views "unix", "dos" and "mac" as valid', function()
eq(1, check_ff_value("unix"))
eq(1, check_ff_value("dos"))
eq(1, check_ff_value("mac"))
eq(1, check_ff_value('unix'))
eq(1, check_ff_value('dos'))
eq(1, check_ff_value('mac'))
end)
itp('views "foo" as invalid', function()
eq(0, check_ff_value("foo"))
eq(0, check_ff_value('foo'))
end)
end)

View File

@ -62,7 +62,7 @@ describe('env.c', function()
eq('non-empty', os.getenv(name))
end)
itp("`overwrite` behavior", function()
itp('`overwrite` behavior', function()
local name = 'NVIM_UNIT_TEST_SETENV_2N'
local value = 'NVIM_UNIT_TEST_SETENV_2V'
local value_updated = 'NVIM_UNIT_TEST_SETENV_2V_UPDATED'
@ -245,7 +245,7 @@ describe('env.c', function()
local input = '~/foo ~ foo'
local homedir = cstr(255, '')
cimp.expand_env_esc(to_cstr('~'), homedir, 255, false, true, NULL)
local output_expected = ffi.string(homedir) .. "/foo ~ foo"
local output_expected = ffi.string(homedir) .. '/foo ~ foo'
local output = cstr(255, '')
cimp.expand_env_esc(to_cstr(input), output, 255, false, true, NULL)
eq(ffi.string(output), ffi.string(output_expected))
@ -256,7 +256,7 @@ describe('env.c', function()
local dst = cstr(255, '')
cimp.expand_env_esc(to_cstr('~'), dst, 255, false, true, NULL)
local homedir = ffi.string(dst)
local output_expected = homedir .. "/foo " .. homedir .. " foo"
local output_expected = homedir .. '/foo ' .. homedir .. ' foo'
local output = cstr(255, '')
cimp.expand_env_esc(input, output, 255, false, false, NULL)
eq(output_expected, ffi.string(output))
@ -267,8 +267,9 @@ describe('env.c', function()
cimp.os_get_username(name_out, 100)
local curuser = ffi.string(name_out)
local src = to_cstr("~"..curuser.."/Vcs/django-rest-framework/rest_framework/renderers.py")
local dst = cstr(256, "~"..curuser)
local src =
to_cstr('~' .. curuser .. '/Vcs/django-rest-framework/rest_framework/renderers.py')
local dst = cstr(256, '~' .. curuser)
cimp.expand_env_esc(src, dst, 256, false, false, NULL)
local len = string.len(ffi.string(dst))
assert.True(len > 56)

View File

@ -26,7 +26,7 @@ local linkb = dir .. '/broken.lnk'
local filec = dir .. '/created-file.dat'
before_each(function()
mkdir(dir);
mkdir(dir)
local f1 = io.open(file1, 'w')
f1:write(fcontents)
@ -193,7 +193,9 @@ describe('file_open', function()
local err, _ = file_open(linkf, m.kFileNoSymlink, 384)
-- err is UV_EMLINK in FreeBSD, but if I use `ok(err == m.UV_ELOOP or err ==
-- m.UV_EMLINK)`, then I loose the ability to see actual `err` value.
if err ~= m.UV_ELOOP then eq(m.UV_EMLINK, err) end
if err ~= m.UV_ELOOP then
eq(m.UV_EMLINK, err)
end
end)
itp('can open an existing file write-only with kFileCreate', function()
@ -249,8 +251,7 @@ describe('file_open', function()
eq(nil, attrs)
end)
itp('can truncate an existing file with kFileTruncate when opening a symlink',
function()
itp('can truncate an existing file with kFileTruncate when opening a symlink', function()
local err, fp = file_open(linkf, m.kFileTruncate, 384)
eq(0, err)
eq(true, fp.wr)
@ -356,8 +357,7 @@ describe('file_read', function()
local exp_s = fcontents:sub(shift + 1, shift + size)
if shift + size >= #fcontents then
exp_err = #fcontents - shift
exp_s = (fcontents:sub(shift + 1, shift + size)
.. (('\0'):rep(size - exp_err)))
exp_s = (fcontents:sub(shift + 1, shift + size) .. (('\0'):rep(size - exp_err)))
end
eq({ exp_err, exp_s }, { file_read(fp, size) })
shift = shift + size
@ -379,8 +379,7 @@ describe('file_read', function()
eq(0, err)
eq(false, fp.wr)
eq({ 5, fcontents:sub(1, 5) }, { file_read(fp, 5) })
eq({#fcontents - 5, fcontents:sub(6) .. (('\0'):rep(5))},
{file_read(fp, #fcontents)})
eq({ #fcontents - 5, fcontents:sub(6) .. (('\0'):rep(5)) }, { file_read(fp, #fcontents) })
eq(0, m.file_close(fp, false))
end)
@ -395,8 +394,7 @@ describe('file_read', function()
local exp_s = fcontents:sub(shift + 1, shift + size)
if shift + size >= #fcontents then
exp_err = #fcontents - shift
exp_s = (fcontents:sub(shift + 1, shift + size)
.. (('\0'):rep(size - exp_err)))
exp_s = (fcontents:sub(shift + 1, shift + size) .. (('\0'):rep(size - exp_err)))
end
eq({ exp_err, exp_s }, { file_read(fp, size) })
shift = shift + size

View File

@ -68,7 +68,7 @@ describe('fs.c', function()
end
before_each(function()
mkdir('unit-test-directory');
mkdir('unit-test-directory')
io.open('unit-test-directory/test.file', 'w'):close()
@ -284,17 +284,19 @@ describe('fs.c', function()
end)
-- Some systems may not have `id` utility.
if (os.execute('id -G > /dev/null 2>&1') ~= 0) then
if os.execute('id -G > /dev/null 2>&1') ~= 0 then
pending('skipped (missing `id` utility)', function() end)
else
itp('owner of a file may change the group of the file to any group of which that owner is a member', function()
itp(
'owner of a file may change the group of the file to any group of which that owner is a member',
function()
local file_gid = luv.fs_stat(filename).gid
-- Gets ID of any group of which current user is a member except the
-- group that owns the file.
local id_fd = io.popen('id -G')
local new_gid = id_fd:read('*n')
if (new_gid == file_gid) then
if new_gid == file_gid then
new_gid = id_fd:read('*n')
end
id_fd:close()
@ -305,10 +307,11 @@ describe('fs.c', function()
eq(0, (os_fchown(filename, -1, new_gid)))
eq(new_gid, luv.fs_stat(filename).gid)
end
end)
end
)
end
if (ffi.os == 'Windows' or ffi.C.geteuid() == 0) then
if ffi.os == 'Windows' or ffi.C.geteuid() == 0 then
pending('skipped (uv_fs_chown is no-op on Windows)', function() end)
else
itp('returns nonzero if process has not enough permissions', function()
@ -318,7 +321,6 @@ describe('fs.c', function()
end
end)
describe('os_file_is_readable', function()
itp('returns false if the file is not readable', function()
local perm = os_getperm('unit-test-directory/test.file')
@ -330,13 +332,11 @@ describe('fs.c', function()
end)
itp('returns false if the file does not exist', function()
eq(false, os_file_is_readable(
'unit-test-directory/what_are_you_smoking.gif'))
eq(false, os_file_is_readable('unit-test-directory/what_are_you_smoking.gif'))
end)
itp('returns true if the file is readable', function()
eq(true, os_file_is_readable(
'unit-test-directory/test.file'))
eq(true, os_file_is_readable('unit-test-directory/test.file'))
end)
end)
@ -494,9 +494,14 @@ describe('fs.c', function()
local dup0 = fs.os_dup(0)
local dup1 = fs.os_dup(1)
local dup2 = fs.os_dup(2)
local tbl = {[0]=true, [1]=true, [2]=true,
[tonumber(dup0)]=true, [tonumber(dup1)]=true,
[tonumber(dup2)]=true}
local tbl = {
[0] = true,
[1] = true,
[2] = true,
[tonumber(dup0)] = true,
[tonumber(dup1)] = true,
[tonumber(dup2)] = true,
}
local i = 0
for _, _ in pairs(tbl) do
i = i + 1
@ -522,12 +527,15 @@ describe('fs.c', function()
eq(ffi.C.UV_ENOENT, (os_open('non-existing-file', ffi.C.kO_RDWR, 0)))
end)
itp('returns non-negative for O_CREAT on a non-existing file which then can be closed', function()
itp(
'returns non-negative for O_CREAT on a non-existing file which then can be closed',
function()
assert_file_does_not_exist(new_file)
local fd = os_open(new_file, ffi.C.kO_CREAT, 0)
assert.is_true(0 <= fd)
eq(0, os_close(fd))
end)
end
)
itp('returns non-negative for O_CREAT on a existing file which then can be closed', function()
assert_file_exists(existing_file)
@ -544,7 +552,7 @@ describe('fs.c', function()
itp('sets `rwx` permissions for O_CREAT 700 which then can be closed', function()
assert_file_does_not_exist(new_file)
--create the file
local fd = os_open(new_file, ffi.C.kO_CREAT, tonumber("700", 8))
local fd = os_open(new_file, ffi.C.kO_CREAT, tonumber('700', 8))
--verify permissions
eq(33216, luv.fs_stat(new_file).mode)
eq(0, os_close(fd))
@ -553,17 +561,20 @@ describe('fs.c', function()
itp('sets `rw` permissions for O_CREAT 600 which then can be closed', function()
assert_file_does_not_exist(new_file)
--create the file
local fd = os_open(new_file, ffi.C.kO_CREAT, tonumber("600", 8))
local fd = os_open(new_file, ffi.C.kO_CREAT, tonumber('600', 8))
--verify permissions
eq(33152, luv.fs_stat(new_file).mode)
eq(0, os_close(fd))
end)
itp('returns a non-negative file descriptor for an existing file which then can be closed', function()
itp(
'returns a non-negative file descriptor for an existing file which then can be closed',
function()
local fd = os_open(existing_file, ffi.C.kO_RDWR, 0)
assert.is_true(0 <= fd)
eq(0, os_close(fd))
end)
end
)
end)
describe('os_close', function()
@ -613,19 +624,24 @@ describe('fs.c', function()
itp('can read the whole file in two calls, one partially', function()
local fd = os_open(file, ffi.C.kO_RDONLY, 0)
ok(fd >= 0)
eq({false, #fcontents * 3/4, fcontents:sub(1, #fcontents * 3/4)},
{os_read(fd, #fcontents * 3/4)})
eq({true,
eq(
{ false, #fcontents * 3 / 4, fcontents:sub(1, #fcontents * 3 / 4) },
{ os_read(fd, #fcontents * 3 / 4) }
)
eq({
true,
(#fcontents * 1 / 4),
fcontents:sub(#fcontents * 3/4 + 1) .. ('\0'):rep(#fcontents * 2/4)},
{os_read(fd, #fcontents * 3/4)})
fcontents:sub(#fcontents * 3 / 4 + 1) .. ('\0'):rep(#fcontents * 2 / 4),
}, { os_read(fd, #fcontents * 3 / 4) })
eq(0, os_close(fd))
end)
end)
describe('os_readv', function()
-- Function may be absent
if not pcall(function() return fs.os_readv end) then
if not pcall(function()
return fs.os_readv
end) then
return
end
local file = 'test-unit-os-fs_spec-os_readv.dat'
@ -659,16 +675,21 @@ describe('fs.c', function()
itp('can read the whole file at once and then report eof', function()
local fd = os_open(file, ffi.C.kO_RDONLY, 0)
ok(fd >= 0)
eq({false,
eq({
false,
#fcontents,
{fcontents:sub(1, #fcontents * 1/4),
{
fcontents:sub(1, #fcontents * 1 / 4),
fcontents:sub(#fcontents * 1 / 4 + 1, #fcontents * 3 / 4),
fcontents:sub(#fcontents * 3 / 4 + 1, #fcontents * 15 / 16),
fcontents:sub(#fcontents * 15/16 + 1, #fcontents)}},
{os_readv(fd, {#fcontents * 1/4,
#fcontents * 2/4,
#fcontents * 3/16,
#fcontents * 1/16})})
fcontents:sub(#fcontents * 15 / 16 + 1, #fcontents),
},
}, {
os_readv(
fd,
{ #fcontents * 1 / 4, #fcontents * 2 / 4, #fcontents * 3 / 16, #fcontents * 1 / 16 }
),
})
eq({ true, 0, { '\0' } }, { os_readv(fd, { 1 }) })
eq(0, os_close(fd))
end)
@ -676,12 +697,15 @@ describe('fs.c', function()
itp('can read the whole file in two calls, one partially', function()
local fd = os_open(file, ffi.C.kO_RDONLY, 0)
ok(fd >= 0)
eq({false, #fcontents * 3/4, {fcontents:sub(1, #fcontents * 3/4)}},
{os_readv(fd, {#fcontents * 3/4})})
eq({true,
eq(
{ false, #fcontents * 3 / 4, { fcontents:sub(1, #fcontents * 3 / 4) } },
{ os_readv(fd, { #fcontents * 3 / 4 }) }
)
eq({
true,
(#fcontents * 1 / 4),
{fcontents:sub(#fcontents * 3/4 + 1) .. ('\0'):rep(#fcontents * 2/4)}},
{os_readv(fd, {#fcontents * 3/4})})
{ fcontents:sub(#fcontents * 3 / 4 + 1) .. ('\0'):rep(#fcontents * 2 / 4) },
}, { os_readv(fd, { #fcontents * 3 / 4 }) })
eq(0, os_close(fd))
end)
end)
@ -784,8 +808,7 @@ describe('fs.c', function()
itp('fails to create a directory where there is a file', function()
local mode = ffi.C.kS_IRUSR + ffi.C.kS_IWUSR + ffi.C.kS_IXUSR
local ret, failed_dir, created_dir = os_mkdir_recurse(
'unit-test-directory/test.file', mode)
local ret, failed_dir, created_dir = os_mkdir_recurse('unit-test-directory/test.file', mode)
neq(0, ret)
eq('unit-test-directory/test.file', failed_dir)
eq(nil, created_dir)
@ -793,8 +816,8 @@ describe('fs.c', function()
itp('fails to create a directory where there is a file in path', function()
local mode = ffi.C.kS_IRUSR + ffi.C.kS_IWUSR + ffi.C.kS_IXUSR
local ret, failed_dir, created_dir = os_mkdir_recurse(
'unit-test-directory/test.file/test', mode)
local ret, failed_dir, created_dir =
os_mkdir_recurse('unit-test-directory/test.file/test', mode)
neq(0, ret)
eq('unit-test-directory/test.file', failed_dir)
eq(nil, created_dir)
@ -802,8 +825,8 @@ describe('fs.c', function()
itp('succeeds to create a directory', function()
local mode = ffi.C.kS_IRUSR + ffi.C.kS_IWUSR + ffi.C.kS_IXUSR
local ret, failed_dir, created_dir = os_mkdir_recurse(
'unit-test-directory/new-dir-recurse', mode)
local ret, failed_dir, created_dir =
os_mkdir_recurse('unit-test-directory/new-dir-recurse', mode)
eq(0, ret)
eq(nil, failed_dir)
ok(endswith(created_dir, 'unit-test-directory/new-dir-recurse'))
@ -814,8 +837,8 @@ describe('fs.c', function()
itp('succeeds to create a directory ending with ///', function()
local mode = ffi.C.kS_IRUSR + ffi.C.kS_IWUSR + ffi.C.kS_IXUSR
local ret, failed_dir, created_dir = os_mkdir_recurse(
'unit-test-directory/new-dir-recurse///', mode)
local ret, failed_dir, created_dir =
os_mkdir_recurse('unit-test-directory/new-dir-recurse///', mode)
eq(0, ret)
eq(nil, failed_dir)
ok(endswith(created_dir, 'unit-test-directory/new-dir-recurse'))
@ -826,8 +849,8 @@ describe('fs.c', function()
itp('succeeds to create a directory ending with /', function()
local mode = ffi.C.kS_IRUSR + ffi.C.kS_IWUSR + ffi.C.kS_IXUSR
local ret, failed_dir, created_dir = os_mkdir_recurse(
'unit-test-directory/new-dir-recurse/', mode)
local ret, failed_dir, created_dir =
os_mkdir_recurse('unit-test-directory/new-dir-recurse/', mode)
eq(0, ret)
eq(nil, failed_dir)
ok(endswith(created_dir, 'unit-test-directory/new-dir-recurse'))
@ -838,8 +861,8 @@ describe('fs.c', function()
itp('succeeds to create a directory tree', function()
local mode = ffi.C.kS_IRUSR + ffi.C.kS_IWUSR + ffi.C.kS_IXUSR
local ret, failed_dir, created_dir = os_mkdir_recurse(
'unit-test-directory/new-dir-recurse/1/2/3', mode)
local ret, failed_dir, created_dir =
os_mkdir_recurse('unit-test-directory/new-dir-recurse/1/2/3', mode)
eq(0, ret)
eq(nil, failed_dir)
ok(endswith(created_dir, 'unit-test-directory/new-dir-recurse'))

View File

@ -21,9 +21,7 @@ describe('shell functions', function()
end)
local function shell_build_argv(cmd, extra_args)
local res = cimported.shell_build_argv(
cmd and to_cstr(cmd),
extra_args and to_cstr(extra_args))
local res = cimported.shell_build_argv(cmd and to_cstr(cmd), extra_args and to_cstr(extra_args))
-- `res` is zero-indexed (C pointer, not Lua table)!
local argc = 0
local ret = {}
@ -40,9 +38,7 @@ describe('shell functions', function()
local function shell_argv_to_str(argv_table)
-- C string array (char **).
local argv = (argv_table
and ffi.new("char*[?]", #argv_table+1)
or NULL)
local argv = (argv_table and ffi.new('char*[?]', #argv_table + 1) or NULL)
local argc = 1
while argv_table ~= nil and argv_table[argc] ~= nil do
@ -64,8 +60,7 @@ describe('shell functions', function()
local output = ffi.new('char *[1]')
local nread = ffi.new('size_t[1]')
local argv = ffi.cast('char**',
cimported.shell_build_argv(to_cstr(cmd), nil))
local argv = ffi.cast('char**', cimported.shell_build_argv(to_cstr(cmd), nil))
local status = cimported.os_system(argv, input_or, input_len, output, nread)
return status, intern(output[0], nread[0])
@ -119,19 +114,17 @@ describe('shell functions', function()
itp('splits and unquotes &shell and &shellcmdflag', function()
cimported.p_sh = to_cstr('/Program" "Files/zsh -f')
cimported.p_shcf = to_cstr('-x -o "sh word split" "-"c')
eq({'/Program Files/zsh', '-f',
'ghi jkl',
'-x', '-o', 'sh word split',
'-c', 'abc def'},
shell_build_argv('abc def', 'ghi jkl'))
eq(
{ '/Program Files/zsh', '-f', 'ghi jkl', '-x', '-o', 'sh word split', '-c', 'abc def' },
shell_build_argv('abc def', 'ghi jkl')
)
end)
itp('applies shellxescape (p_sxe) and shellxquote (p_sxq)', function()
cimported.p_sxq = to_cstr('(')
cimported.p_sxe = to_cstr('"&|<>()@^')
local argv = ffi.cast('char**',
cimported.shell_build_argv(to_cstr('echo &|<>()@^'), nil))
local argv = ffi.cast('char**', cimported.shell_build_argv(to_cstr('echo &|<>()@^'), nil))
eq(ffi.string(argv[0]), '/bin/sh')
eq(ffi.string(argv[1]), '-c')
eq(ffi.string(argv[2]), '(echo ^&^|^<^>^(^)^@^^)')
@ -142,8 +135,7 @@ describe('shell functions', function()
cimported.p_sxq = to_cstr('"(')
cimported.p_sxe = to_cstr('"&|<>()@^')
local argv = ffi.cast('char**', cimported.shell_build_argv(
to_cstr('echo -n some text'), nil))
local argv = ffi.cast('char**', cimported.shell_build_argv(to_cstr('echo -n some text'), nil))
eq(ffi.string(argv[0]), '/bin/sh')
eq(ffi.string(argv[1]), '-c')
eq(ffi.string(argv[2]), '"(echo -n some text)"')
@ -154,8 +146,7 @@ describe('shell functions', function()
cimported.p_sxq = to_cstr('"')
cimported.p_sxe = to_cstr('')
local argv = ffi.cast('char**', cimported.shell_build_argv(
to_cstr('echo -n some text'), nil))
local argv = ffi.cast('char**', cimported.shell_build_argv(to_cstr('echo -n some text'), nil))
eq(ffi.string(argv[0]), '/bin/sh')
eq(ffi.string(argv[1]), '-c')
eq(ffi.string(argv[2]), '"echo -n some text"')
@ -163,8 +154,7 @@ describe('shell functions', function()
end)
itp('with empty shellxquote/shellxescape', function()
local argv = ffi.cast('char**', cimported.shell_build_argv(
to_cstr('echo -n some text'), nil))
local argv = ffi.cast('char**', cimported.shell_build_argv(to_cstr('echo -n some text'), nil))
eq(ffi.string(argv[0]), '/bin/sh')
eq(ffi.string(argv[1]), '-c')
eq(ffi.string(argv[2]), 'echo -n some text')
@ -178,7 +168,9 @@ describe('shell functions', function()
eq("'foo' '' 'bar'", shell_argv_to_str({ 'foo', '', 'bar' }))
eq("'/bin/sh' '-c' 'abc def'", shell_argv_to_str({ '/bin/sh', '-c', 'abc def' }))
eq("'abc def' 'ghi jkl'", shell_argv_to_str({ 'abc def', 'ghi jkl' }))
eq("'/bin/sh' '-c' 'abc def' '"..('x'):rep(225).."...",
shell_argv_to_str({'/bin/sh', '-c', 'abc def', ('x'):rep(999)}))
eq(
"'/bin/sh' '-c' 'abc def' '" .. ('x'):rep(225) .. '...',
shell_argv_to_str({ '/bin/sh', '-c', 'abc def', ('x'):rep(999) })
)
end)
end)

View File

@ -184,7 +184,7 @@ describe('path.c', function()
itp('returns the executable name of an invocation given a relative invocation', function()
local invk, len = invocation_path_tail('directory/exe a b c')
compare("exe a b c", invk, len)
compare('exe a b c', invk, len)
eq(3, len)
end)
@ -202,7 +202,7 @@ describe('path.c', function()
itp('does not count arguments to the executable as part of its path', function()
local invk, len = invocation_path_tail('exe a/b\\c')
compare("exe a/b\\c", invk, len)
compare('exe a/b\\c', invk, len)
eq(3, len)
end)
@ -212,17 +212,17 @@ describe('path.c', function()
end)
itp('is equivalent to path_tail when args do not contain a path separator', function()
local ptail = cimp.path_tail(to_cstr("a/b/c x y z"))
local ptail = cimp.path_tail(to_cstr('a/b/c x y z'))
neq(NULL, ptail)
local tail = ffi.string(ptail)
local invk, _ = invocation_path_tail("a/b/c x y z")
local invk, _ = invocation_path_tail('a/b/c x y z')
eq(tail, ffi.string(invk))
end)
itp('is not equivalent to path_tail when args contain a path separator', function()
local ptail = cimp.path_tail(to_cstr("a/b/c x y/z"))
local ptail = cimp.path_tail(to_cstr('a/b/c x y/z'))
neq(NULL, ptail)
local invk, _ = invocation_path_tail("a/b/c x y/z")
local invk, _ = invocation_path_tail('a/b/c x y/z')
neq((ffi.string(ptail)), (ffi.string(invk)))
end)
end)
@ -334,7 +334,7 @@ describe('path.c path_guess_exepath', function()
local name = 'cat' -- Some executable in $PATH.
local bufsize = 255
local buf = cstr(bufsize, '')
local insane_path = orig_path_env..':'..(("x/"):rep(4097))
local insane_path = orig_path_env .. ':' .. (('x/'):rep(4097))
cimp.os_setenv('PATH', insane_path, true)
cimp.path_guess_exepath(name, buf, bufsize)
@ -356,7 +356,7 @@ end)
describe('path.c', function()
setup(function()
mkdir('unit-test-directory');
mkdir('unit-test-directory')
io.open('unit-test-directory/test.file', 'w'):close()
-- Since the tests are executed, they are called by an executable. We use
@ -441,7 +441,9 @@ describe('path.c', function()
eq(OK, result)
end)
itp('enters given directory (instead of just concatenating the strings) if possible and if path contains a slash', function()
itp(
'enters given directory (instead of just concatenating the strings) if possible and if path contains a slash',
function()
local old_dir = luv.cwd()
luv.chdir('..')
local expected = luv.cwd() .. '/test.file'
@ -452,7 +454,8 @@ describe('path.c', function()
local buf, result = vim_FullName(filename, buflen, do_expand)
eq(expected, ffi.string(buf))
eq(OK, result)
end)
end
)
itp('just copies the path if it is already absolute and force=0', function()
local absolute_path = '/absolute/path'
@ -544,8 +547,12 @@ describe('path.c', function()
return ffi.string(c_file)
end
before_each(function() mkdir('CamelCase') end)
after_each(function() luv.fs_rmdir('CamelCase') end)
before_each(function()
mkdir('CamelCase')
end)
after_each(function()
luv.fs_rmdir('CamelCase')
end)
if ffi.os == 'Windows' or ffi.os == 'OSX' then
itp('Corrects the case of file names in Mac and Windows', function()
@ -565,14 +572,14 @@ describe('path.c', function()
local path1 = cstr(100, 'path1')
local to_append = to_cstr('path2')
eq(OK, (cimp.append_path(path1, to_append, 100)))
eq("path1/path2", (ffi.string(path1)))
eq('path1/path2', (ffi.string(path1)))
end)
itp('joins given paths without adding an unnecessary slash', function()
local path1 = cstr(100, 'path1/')
local to_append = to_cstr('path2')
eq(OK, cimp.append_path(path1, to_append, 100))
eq("path1/path2", (ffi.string(path1)))
eq('path1/path2', (ffi.string(path1)))
end)
itp('fails and uses filename if there is not enough space left for to_append', function()

View File

@ -1,7 +1,7 @@
-- helps managing loading different headers into the LuaJIT ffi. Untested on
-- windows, will probably need quite a bit of adjustment to run there.
local ffi = require("ffi")
local ffi = require('ffi')
local global_helpers = require('test.helpers')
local argss_to_cmd = global_helpers.argss_to_cmd
@ -12,37 +12,37 @@ local repeated_read_cmd = global_helpers.repeated_read_cmd
--- @type Compiler[]
local ccs = {}
local env_cc = os.getenv("CC")
local env_cc = os.getenv('CC')
if env_cc then
table.insert(ccs, {path = {"/usr/bin/env", env_cc}, type = "gcc"})
table.insert(ccs, { path = { '/usr/bin/env', env_cc }, type = 'gcc' })
end
if ffi.os == "Windows" then
table.insert(ccs, {path = {"cl"}, type = "msvc"})
if ffi.os == 'Windows' then
table.insert(ccs, { path = { 'cl' }, type = 'msvc' })
end
table.insert(ccs, {path = {"/usr/bin/env", "cc"}, type = "gcc"})
table.insert(ccs, {path = {"/usr/bin/env", "gcc"}, type = "gcc"})
table.insert(ccs, {path = {"/usr/bin/env", "gcc-4.9"}, type = "gcc"})
table.insert(ccs, {path = {"/usr/bin/env", "gcc-4.8"}, type = "gcc"})
table.insert(ccs, {path = {"/usr/bin/env", "gcc-4.7"}, type = "gcc"})
table.insert(ccs, {path = {"/usr/bin/env", "clang"}, type = "clang"})
table.insert(ccs, {path = {"/usr/bin/env", "icc"}, type = "gcc"})
table.insert(ccs, { path = { '/usr/bin/env', 'cc' }, type = 'gcc' })
table.insert(ccs, { path = { '/usr/bin/env', 'gcc' }, type = 'gcc' })
table.insert(ccs, { path = { '/usr/bin/env', 'gcc-4.9' }, type = 'gcc' })
table.insert(ccs, { path = { '/usr/bin/env', 'gcc-4.8' }, type = 'gcc' })
table.insert(ccs, { path = { '/usr/bin/env', 'gcc-4.7' }, type = 'gcc' })
table.insert(ccs, { path = { '/usr/bin/env', 'clang' }, type = 'clang' })
table.insert(ccs, { path = { '/usr/bin/env', 'icc' }, type = 'gcc' })
-- parse Makefile format dependencies into a Lua table
--- @param deps string
--- @return string[]
local function parse_make_deps(deps)
-- remove line breaks and line concatenators
deps = deps:gsub("\n", ""):gsub("\\", "")
deps = deps:gsub('\n', ''):gsub('\\', '')
-- remove the Makefile "target:" element
deps = deps:gsub(".+:", "")
deps = deps:gsub('.+:', '')
-- remove redundant spaces
deps = deps:gsub(" +", " ")
deps = deps:gsub(' +', ' ')
-- split according to token (space in this case)
local headers = {} --- @type string[]
for token in deps:gmatch("[^%s]+") do
for token in deps:gmatch('[^%s]+') do
-- headers[token] = true
headers[#headers + 1] = token
end
@ -50,9 +50,9 @@ local function parse_make_deps(deps)
-- resolve path redirections (..) to normalize all paths
for i, v in ipairs(headers) do
-- double dots (..)
headers[i] = v:gsub("/[^/%s]+/%.%.", "")
headers[i] = v:gsub('/[^/%s]+/%.%.', '')
-- single dot (.)
headers[i] = v:gsub("%./", "")
headers[i] = v:gsub('%./', '')
end
return headers
@ -80,7 +80,7 @@ local function headerize(headers, global)
formatted[#formatted + 1] = string.format(fmt, hdr)
end
return table.concat(formatted, "\n")
return table.concat(formatted, '\n')
end
--- @class Gcc
@ -160,7 +160,7 @@ function Gcc:dependencies(hdr)
--- @type string
local cmd = argss_to_cmd(self.path, { '-M', hdr }) .. ' 2>&1'
local out = assert(io.popen(cmd))
local deps = out:read("*a")
local deps = out:read('*a')
out:close()
if deps then
return parse_make_deps(deps)
@ -174,10 +174,14 @@ function Gcc:filter_standard_defines(defines)
local pseudoheader_fname = 'tmp_empty_pseudoheader.h'
local pseudoheader_file = assert(io.open(pseudoheader_fname, 'w'))
pseudoheader_file:close()
local standard_defines = assert(repeated_read_cmd(self.path,
local standard_defines = assert(
repeated_read_cmd(
self.path,
self.preprocessor_extra_flags,
self.get_defines_extra_flags,
{pseudoheader_fname}))
{ pseudoheader_fname }
)
)
os.remove(pseudoheader_fname)
self.standard_defines = {} --- @type table<string,true>
for line in standard_defines:gmatch('[^\n]+') do
@ -192,7 +196,7 @@ function Gcc:filter_standard_defines(defines)
end
end
return table.concat(ret, "\n")
return table.concat(ret, '\n')
end
--- returns a stream representing a preprocessed form of the passed-in headers.
@ -206,20 +210,29 @@ function Gcc:preprocess(previous_defines, ...)
local pseudoheader_fname = 'tmp_pseudoheader.h'
local pseudoheader_file = assert(io.open(pseudoheader_fname, 'w'))
pseudoheader_file:write(previous_defines)
pseudoheader_file:write("\n")
pseudoheader_file:write('\n')
pseudoheader_file:write(pseudoheader)
pseudoheader_file:flush()
pseudoheader_file:close()
local defines = assert(repeated_read_cmd(self.path, self.preprocessor_extra_flags,
local defines = assert(
repeated_read_cmd(
self.path,
self.preprocessor_extra_flags,
self.get_defines_extra_flags,
{pseudoheader_fname}))
{ pseudoheader_fname }
)
)
defines = self:filter_standard_defines(defines)
local declarations = assert(repeated_read_cmd(self.path,
local declarations = assert(
repeated_read_cmd(
self.path,
self.preprocessor_extra_flags,
self.get_declarations_extra_flags,
{pseudoheader_fname}))
{ pseudoheader_fname }
)
)
os.remove(pseudoheader_fname)
@ -233,7 +246,7 @@ end
--- @return Gcc?
local function find_best_cc(compilers)
for _, meta in pairs(compilers) do
local version = assert(io.popen(tostring(meta.path) .. " -v 2>&1"))
local version = assert(io.popen(tostring(meta.path) .. ' -v 2>&1'))
version:close()
if version then
return Gcc:new({ path = meta.path })

View File

@ -10,11 +10,11 @@ local prof = cimport('./src/nvim/profile.h')
local function split(inputstr, sep)
if sep == nil then
sep = "%s"
sep = '%s'
end
local t, i = {}, 1
for str in string.gmatch(inputstr, "([^"..sep.."]+)") do
for str in string.gmatch(inputstr, '([^' .. sep .. ']+)') do
t[i] = str
i = i + 1
end
@ -23,8 +23,8 @@ local function split(inputstr, sep)
end
local function trim(s)
local from = s:match"^%s*()"
return from > #s and "" or s:match(".*%S", from)
local from = s:match '^%s*()'
return from > #s and '' or s:match('.*%S', from)
end
local function starts(str, start)
@ -34,25 +34,33 @@ end
local function cmp_assert(v1, v2, op, opstr)
local res = op(v1, v2)
if res == false then
print(string.format("expected: %f %s %f", v1, opstr, v2))
print(string.format('expected: %f %s %f', v1, opstr, v2))
end
assert.is_true(res)
end
local function lt(a, b) -- luacheck: ignore
cmp_assert(a, b, function(x, y) return x < y end, "<")
cmp_assert(a, b, function(x, y)
return x < y
end, '<')
end
local function lte(a, b) -- luacheck: ignore
cmp_assert(a, b, function(x, y) return x <= y end, "<=")
cmp_assert(a, b, function(x, y)
return x <= y
end, '<=')
end
local function gt(a, b) -- luacheck: ignore
cmp_assert(a, b, function(x, y) return x > y end, ">")
cmp_assert(a, b, function(x, y)
return x > y
end, '>')
end
local function gte(a, b)
cmp_assert(a, b, function(x, y) return x >= y end, ">=")
cmp_assert(a, b, function(x, y)
return x >= y
end, '>=')
end
-- missing functions:
@ -61,21 +69,43 @@ end
-- profile_set_wait
-- profile_sub_wait
describe('profiling related functions', function()
local function profile_start() return prof.profile_start() end
local function profile_end(t) return prof.profile_end(t) end
local function profile_zero() return prof.profile_zero() end
local function profile_setlimit(ms) return prof.profile_setlimit(ms) end
local function profile_passed_limit(t) return prof.profile_passed_limit(t) end
local function profile_add(t1, t2) return prof.profile_add(t1, t2) end
local function profile_sub(t1, t2) return prof.profile_sub(t1, t2) end
local function profile_divide(t, cnt) return prof.profile_divide(t, cnt) end
local function profile_cmp(t1, t2) return prof.profile_cmp(t1, t2) end
local function profile_equal(t1, t2) return prof.profile_equal(t1, t2) end
local function profile_msg(t) return ffi.string(prof.profile_msg(t)) end
local function profile_start()
return prof.profile_start()
end
local function profile_end(t)
return prof.profile_end(t)
end
local function profile_zero()
return prof.profile_zero()
end
local function profile_setlimit(ms)
return prof.profile_setlimit(ms)
end
local function profile_passed_limit(t)
return prof.profile_passed_limit(t)
end
local function profile_add(t1, t2)
return prof.profile_add(t1, t2)
end
local function profile_sub(t1, t2)
return prof.profile_sub(t1, t2)
end
local function profile_divide(t, cnt)
return prof.profile_divide(t, cnt)
end
local function profile_cmp(t1, t2)
return prof.profile_cmp(t1, t2)
end
local function profile_equal(t1, t2)
return prof.profile_equal(t1, t2)
end
local function profile_msg(t)
return ffi.string(prof.profile_msg(t))
end
local function toseconds(t) -- luacheck: ignore
local str = trim(profile_msg(t))
local spl = split(str, ".")
local spl = split(str, '.')
local s, us = spl[1], spl[2]
return tonumber(s) + tonumber(us) / 1000000
end
@ -199,14 +229,14 @@ describe('profiling related functions', function()
describe('profile_msg', function()
itp('prints the zero time as 0.00000', function()
local str = trim(profile_msg(profile_zero()))
eq(str, "0.000000")
eq(str, '0.000000')
end)
itp('prints the time passed, in seconds.microsends', function()
local start = profile_start()
local endt = profile_end(start)
local str = trim(profile_msg(endt))
local spl = split(str, ".")
local spl = split(str, '.')
-- string has two parts (before dot and after dot)
eq(2, #spl)
@ -215,11 +245,11 @@ describe('profiling related functions', function()
-- zero seconds have passed (if this is not true, either LuaJIT is too
-- slow or the profiling functions are too slow and need to be fixed)
eq(s, "0")
eq(s, '0')
-- more or less the same goes for the microsecond part, if it doesn't
-- start with 0, it's too slow.
assert.is_true(starts(us, "0"))
assert.is_true(starts(us, '0'))
end)
end)

View File

@ -1,4 +1,4 @@
local helpers = require("test.unit.helpers")(after_each)
local helpers = require('test.unit.helpers')(after_each)
local itp = helpers.gen_itp(it)
local eq = helpers.eq
@ -7,7 +7,7 @@ local cstr = helpers.cstr
local to_cstr = helpers.to_cstr
local child_call_once = helpers.child_call_once
local rbuffer = helpers.cimport("./test/unit/fixtures/rbuffer.h")
local rbuffer = helpers.cimport('./test/unit/fixtures/rbuffer.h')
describe('rbuffer functions', function()
local capacity = 16
@ -187,8 +187,19 @@ describe('rbuffer functions', function()
read(10)
write('long string')
collect_chars()
eq({{'l', 0}, {'o', 1}, {'n', 2}, {'g', 3}, {' ', 4}, {'s', 5},
{'t', 6}, {'r', 7}, {'i', 8}, {'n', 9}, {'g', 10}}, chars)
eq({
{ 'l', 0 },
{ 'o', 1 },
{ 'n', 2 },
{ 'g', 3 },
{ ' ', 4 },
{ 's', 5 },
{ 't', 6 },
{ 'r', 7 },
{ 'i', 8 },
{ 'n', 9 },
{ 'g', 10 },
}, chars)
end)
end)
end)
@ -218,8 +229,19 @@ describe('rbuffer functions', function()
read(10)
write('long string')
collect_chars()
eq({{'g', 10}, {'n', 9}, {'i', 8}, {'r', 7}, {'t', 6}, {'s', 5},
{' ', 4}, {'g', 3}, {'n', 2}, {'o', 1}, {'l', 0}}, chars)
eq({
{ 'g', 10 },
{ 'n', 9 },
{ 'i', 8 },
{ 'r', 7 },
{ 't', 6 },
{ 's', 5 },
{ ' ', 4 },
{ 'g', 3 },
{ 'n', 2 },
{ 'o', 1 },
{ 'l', 0 },
}, chars)
end)
end)
end)

View File

@ -1,42 +1,42 @@
local helpers = require("test.unit.helpers")(after_each)
local helpers = require('test.unit.helpers')(after_each)
local itp = helpers.gen_itp(it)
local to_cstr = helpers.to_cstr
local eq = helpers.eq
local search = helpers.cimport("./src/nvim/search.h")
local search = helpers.cimport('./src/nvim/search.h')
local globals = helpers.cimport('./src/nvim/globals.h')
local ffi = helpers.ffi
itp('pat_has_uppercase', function()
-- works on empty string
eq(false, search.pat_has_uppercase(to_cstr("")))
eq(false, search.pat_has_uppercase(to_cstr('')))
-- works with utf uppercase
eq(false, search.pat_has_uppercase(to_cstr("ä")))
eq(true, search.pat_has_uppercase(to_cstr("Ä")))
eq(true, search.pat_has_uppercase(to_cstr("äaÅ")))
eq(false, search.pat_has_uppercase(to_cstr('ä')))
eq(true, search.pat_has_uppercase(to_cstr('Ä')))
eq(true, search.pat_has_uppercase(to_cstr('äaÅ')))
-- works when pat ends with backslash
eq(false, search.pat_has_uppercase(to_cstr("\\")))
eq(false, search.pat_has_uppercase(to_cstr("ab$\\")))
eq(false, search.pat_has_uppercase(to_cstr('\\')))
eq(false, search.pat_has_uppercase(to_cstr('ab$\\')))
-- skips escaped characters
eq(false, search.pat_has_uppercase(to_cstr("\\Ab")))
eq(true, search.pat_has_uppercase(to_cstr("\\AU")))
eq(false, search.pat_has_uppercase(to_cstr('\\Ab')))
eq(true, search.pat_has_uppercase(to_cstr('\\AU')))
-- skips _X escaped characters
eq(false, search.pat_has_uppercase(to_cstr("\\_Ab")))
eq(true, search.pat_has_uppercase(to_cstr("\\_AU")))
eq(false, search.pat_has_uppercase(to_cstr('\\_Ab')))
eq(true, search.pat_has_uppercase(to_cstr('\\_AU')))
-- skips %X escaped characters
eq(false, search.pat_has_uppercase(to_cstr("aa\\%Ab")))
eq(true, search.pat_has_uppercase(to_cstr("aab\\%AU")))
eq(false, search.pat_has_uppercase(to_cstr('aa\\%Ab')))
eq(true, search.pat_has_uppercase(to_cstr('aab\\%AU')))
end)
describe('search_regcomp', function()
local search_regcomp = function(pat, pat_save, pat_use, options)
local regmatch = ffi.new("regmmatch_T")
local regmatch = ffi.new('regmmatch_T')
local fail = search.search_regcomp(to_cstr(pat), nil, pat_save, pat_use, options, regmatch)
return fail, regmatch
end
@ -45,13 +45,13 @@ describe('search_regcomp', function()
return helpers.internalize(search.get_search_pat())
end
itp("accepts regexp pattern with invalid utf", function()
itp('accepts regexp pattern with invalid utf', function()
--crafted to call reverse_text with invalid utf
globals.curwin.w_onebuf_opt.wo_rl = 1
globals.curwin.w_onebuf_opt.wo_rlc = to_cstr('s')
globals.cmdmod.cmod_flags = globals.CMOD_KEEPPATTERNS
local fail = search_regcomp("a\192", 0,0,0)
local fail = search_regcomp('a\192', 0, 0, 0)
eq(1, fail)
eq("\192a", get_search_pat())
eq('\192a', get_search_pat())
end)
end)

View File

@ -1,4 +1,4 @@
local helpers = require("test.unit.helpers")(after_each)
local helpers = require('test.unit.helpers')(after_each)
local itp = helpers.gen_itp(it)
local to_cstr = helpers.to_cstr
@ -6,9 +6,9 @@ local get_str = helpers.ffi.string
local eq = helpers.eq
local NULL = helpers.NULL
local buffer = helpers.cimport("./src/nvim/buffer.h")
local globals = helpers.cimport("./src/nvim/globals.h")
local stl = helpers.cimport("./src/nvim/statusline.h")
local buffer = helpers.cimport('./src/nvim/buffer.h')
local globals = helpers.cimport('./src/nvim/globals.h')
local stl = helpers.cimport('./src/nvim/statusline.h')
describe('build_stl_str_hl', function()
local buffer_byte_size = 100
@ -22,13 +22,14 @@ describe('build_stl_str_hl', function()
-- .fillchar The fill character used in the statusline
-- .maximum_cell_count The number of cells available in the statusline
local function build_stl_str_hl(arg)
output_buffer = to_cstr(string.rep(" ", buffer_byte_size))
output_buffer = to_cstr(string.rep(' ', buffer_byte_size))
local pat = arg.pat or ''
local fillchar = arg.fillchar or (' '):byte()
local maximum_cell_count = arg.maximum_cell_count or buffer_byte_size
return stl.build_stl_str_hl(globals.curwin,
return stl.build_stl_str_hl(
globals.curwin,
output_buffer,
buffer_byte_size,
to_cstr(pat),
@ -38,7 +39,8 @@ describe('build_stl_str_hl', function()
maximum_cell_count,
NULL,
NULL,
NULL)
NULL
)
end
-- Use this function to simplify testing the comparison between
@ -54,12 +56,7 @@ describe('build_stl_str_hl', function()
-- .expected_byte_length The expected byte length of the string (defaults to byte length of expected_stl)
-- .file_name The name of the file to be tested (useful in %f type tests)
-- .fillchar The character that will be used to fill any 'extra' space in the stl
local function statusline_test(description,
statusline_cell_count,
input_stl,
expected_stl,
arg)
local function statusline_test(description, statusline_cell_count, input_stl, expected_stl, arg)
-- arg is the optional parameter
-- so we either fill in option with arg or an empty dictionary
local option = arg or {}
@ -75,9 +72,11 @@ describe('build_stl_str_hl', function()
buffer.setfname(globals.curbuf, nil, NULL, 1)
end
local result_cell_count = build_stl_str_hl{pat=input_stl,
local result_cell_count = build_stl_str_hl {
pat = input_stl,
maximum_cell_count = statusline_cell_count,
fillchar=fillchar}
fillchar = fillchar,
}
eq(expected_stl, get_str(output_buffer, expected_byte_length))
eq(expected_cell_count, result_cell_count)
@ -85,198 +84,383 @@ describe('build_stl_str_hl', function()
end
-- expression testing
statusline_test('Should expand expression', 2,
'%!expand(20+1)', '21')
statusline_test('Should expand broken expression to itself', 11,
'%!expand(20+1', 'expand(20+1')
statusline_test('Should expand expression', 2, '%!expand(20+1)', '21')
statusline_test('Should expand broken expression to itself', 11, '%!expand(20+1', 'expand(20+1')
-- file name testing
statusline_test('should print no file name', 10,
'%f', '[No Name]',
{expected_cell_count=9})
statusline_test('should print the relative file name', 30,
'%f', 'test/unit/buffer_spec.lua',
{file_name='test/unit/buffer_spec.lua', expected_cell_count=25})
statusline_test('should print the full file name', 40,
'%F', '/test/unit/buffer_spec.lua',
{file_name='/test/unit/buffer_spec.lua', expected_cell_count=26})
statusline_test('should print no file name', 10, '%f', '[No Name]', { expected_cell_count = 9 })
statusline_test(
'should print the relative file name',
30,
'%f',
'test/unit/buffer_spec.lua',
{ file_name = 'test/unit/buffer_spec.lua', expected_cell_count = 25 }
)
statusline_test(
'should print the full file name',
40,
'%F',
'/test/unit/buffer_spec.lua',
{ file_name = '/test/unit/buffer_spec.lua', expected_cell_count = 26 }
)
-- fillchar testing
statusline_test('should handle `!` as a fillchar', 10,
'abcde%=', 'abcde!!!!!',
{fillchar=('!'):byte()})
statusline_test('should handle `~` as a fillchar', 10,
'%=abcde', '~~~~~abcde',
{fillchar=('~'):byte()})
statusline_test('should put fillchar `!` in between text', 10,
'abc%=def', 'abc!!!!def',
{fillchar=('!'):byte()})
statusline_test('should put fillchar `~` in between text', 10,
'abc%=def', 'abc~~~~def',
{fillchar=('~'):byte()})
statusline_test('should put fillchar `━` in between text', 10,
'abc%=def', 'abc━━━━def',
{fillchar=0x2501})
statusline_test('should handle zero-fillchar as a space', 10,
'abcde%=', 'abcde ',
{fillchar=0})
statusline_test('should print the tail file name', 80,
'%t', 'buffer_spec.lua',
{file_name='test/unit/buffer_spec.lua', expected_cell_count=15})
statusline_test(
'should handle `!` as a fillchar',
10,
'abcde%=',
'abcde!!!!!',
{ fillchar = ('!'):byte() }
)
statusline_test(
'should handle `~` as a fillchar',
10,
'%=abcde',
'~~~~~abcde',
{ fillchar = ('~'):byte() }
)
statusline_test(
'should put fillchar `!` in between text',
10,
'abc%=def',
'abc!!!!def',
{ fillchar = ('!'):byte() }
)
statusline_test(
'should put fillchar `~` in between text',
10,
'abc%=def',
'abc~~~~def',
{ fillchar = ('~'):byte() }
)
statusline_test(
'should put fillchar `━` in between text',
10,
'abc%=def',
'abc━━━━def',
{ fillchar = 0x2501 }
)
statusline_test(
'should handle zero-fillchar as a space',
10,
'abcde%=',
'abcde ',
{ fillchar = 0 }
)
statusline_test(
'should print the tail file name',
80,
'%t',
'buffer_spec.lua',
{ file_name = 'test/unit/buffer_spec.lua', expected_cell_count = 15 }
)
-- standard text testing
statusline_test('should copy plain text', 80,
'this is a test', 'this is a test',
{expected_cell_count=14})
statusline_test(
'should copy plain text',
80,
'this is a test',
'this is a test',
{ expected_cell_count = 14 }
)
-- line number testing
statusline_test('should print the buffer number', 80,
'%n', '1',
{expected_cell_count=1})
statusline_test('should print the current line number in the buffer', 80,
'%l', '0',
{expected_cell_count=1})
statusline_test('should print the number of lines in the buffer', 80,
'%L', '1',
{expected_cell_count=1})
statusline_test('should print the buffer number', 80, '%n', '1', { expected_cell_count = 1 })
statusline_test(
'should print the current line number in the buffer',
80,
'%l',
'0',
{ expected_cell_count = 1 }
)
statusline_test(
'should print the number of lines in the buffer',
80,
'%L',
'1',
{ expected_cell_count = 1 }
)
-- truncation testing
statusline_test('should truncate when standard text pattern is too long', 10,
'0123456789abcde', '<6789abcde')
statusline_test('should truncate when using =', 10,
'abcdef%=ghijkl', 'abcdef<jkl')
statusline_test('should truncate centered text when using ==', 10,
'abcde%=gone%=fghij', 'abcde<ghij')
statusline_test('should respect the `<` marker', 10,
'abc%<defghijkl', 'abc<ghijkl')
statusline_test('should truncate at `<` with one `=`, test 1', 10,
'abc%<def%=ghijklmno', 'abc<jklmno')
statusline_test('should truncate at `<` with one `=`, test 2', 10,
'abcdef%=ghijkl%<mno', 'abcdefghi>')
statusline_test('should truncate at `<` with one `=`, test 3', 10,
'abc%<def%=ghijklmno', 'abc<jklmno')
statusline_test('should truncate at `<` with one `=`, test 4', 10,
'abc%<def%=ghij', 'abcdefghij')
statusline_test('should truncate at `<` with one `=`, test 4', 10,
'abc%<def%=ghijk', 'abc<fghijk')
statusline_test(
'should truncate when standard text pattern is too long',
10,
'0123456789abcde',
'<6789abcde'
)
statusline_test('should truncate when using =', 10, 'abcdef%=ghijkl', 'abcdef<jkl')
statusline_test(
'should truncate centered text when using ==',
10,
'abcde%=gone%=fghij',
'abcde<ghij'
)
statusline_test('should respect the `<` marker', 10, 'abc%<defghijkl', 'abc<ghijkl')
statusline_test(
'should truncate at `<` with one `=`, test 1',
10,
'abc%<def%=ghijklmno',
'abc<jklmno'
)
statusline_test(
'should truncate at `<` with one `=`, test 2',
10,
'abcdef%=ghijkl%<mno',
'abcdefghi>'
)
statusline_test(
'should truncate at `<` with one `=`, test 3',
10,
'abc%<def%=ghijklmno',
'abc<jklmno'
)
statusline_test('should truncate at `<` with one `=`, test 4', 10, 'abc%<def%=ghij', 'abcdefghij')
statusline_test(
'should truncate at `<` with one `=`, test 4',
10,
'abc%<def%=ghijk',
'abc<fghijk'
)
statusline_test('should truncate at `<` with many `=`, test 4', 10,
'ab%<cdef%=g%=h%=ijk', 'ab<efghijk')
statusline_test(
'should truncate at `<` with many `=`, test 4',
10,
'ab%<cdef%=g%=h%=ijk',
'ab<efghijk'
)
statusline_test('should truncate at the first `<`', 10,
'abc%<def%<ghijklm', 'abc<hijklm')
statusline_test('should truncate at the first `<`', 10, 'abc%<def%<ghijklm', 'abc<hijklm')
statusline_test('should ignore trailing %', 3, 'abc%', 'abc')
-- alignment testing with fillchar
local function statusline_test_align(description,
local function statusline_test_align(
description,
statusline_cell_count,
input_stl,
expected_stl,
arg)
arg
)
arg = arg or {}
statusline_test(description .. ' without fillchar',
statusline_cell_count, input_stl, expected_stl:gsub('%~', ' '), arg)
statusline_test(
description .. ' without fillchar',
statusline_cell_count,
input_stl,
expected_stl:gsub('%~', ' '),
arg
)
arg.fillchar = ('!'):byte()
statusline_test(description .. ' with fillchar `!`',
statusline_cell_count, input_stl, expected_stl:gsub('%~', '!'), arg)
statusline_test(
description .. ' with fillchar `!`',
statusline_cell_count,
input_stl,
expected_stl:gsub('%~', '!'),
arg
)
arg.fillchar = 0x2501
statusline_test(description .. ' with fillchar `━`',
statusline_cell_count, input_stl, expected_stl:gsub('%~', ''), arg)
statusline_test(
description .. ' with fillchar `━`',
statusline_cell_count,
input_stl,
expected_stl:gsub('%~', ''),
arg
)
end
statusline_test_align('should right align when using =', 20,
'neo%=vim', 'neo~~~~~~~~~~~~~~vim')
statusline_test_align('should, when possible, center text when using %=text%=', 20,
'abc%=neovim%=def', 'abc~~~~neovim~~~~def')
statusline_test_align('should handle uneven spacing in the buffer when using %=text%=', 20,
'abc%=neo_vim%=def', 'abc~~~neo_vim~~~~def')
statusline_test_align('should have equal spaces even with non-equal sides when using =', 20,
'foobar%=test%=baz', 'foobar~~~test~~~~baz')
statusline_test_align('should have equal spaces even with longer right side when using =', 20,
'a%=test%=longtext', 'a~~~test~~~~longtext')
statusline_test_align('should handle an empty left side when using ==', 20,
'%=test%=baz', '~~~~~~test~~~~~~~baz')
statusline_test_align('should handle an empty right side when using ==', 20,
'foobar%=test%=', 'foobar~~~~~test~~~~~')
statusline_test_align('should handle consecutive empty ==', 20,
'%=%=test%=', '~~~~~~~~~~test~~~~~~')
statusline_test_align('should handle an = alone', 20,
'%=', '~~~~~~~~~~~~~~~~~~~~')
statusline_test_align('should right align text when it is alone with =', 20,
'%=foo', '~~~~~~~~~~~~~~~~~foo')
statusline_test_align('should left align text when it is alone with =', 20,
'foo%=', 'foo~~~~~~~~~~~~~~~~~')
statusline_test_align('should right align when using =', 20, 'neo%=vim', 'neo~~~~~~~~~~~~~~vim')
statusline_test_align(
'should, when possible, center text when using %=text%=',
20,
'abc%=neovim%=def',
'abc~~~~neovim~~~~def'
)
statusline_test_align(
'should handle uneven spacing in the buffer when using %=text%=',
20,
'abc%=neo_vim%=def',
'abc~~~neo_vim~~~~def'
)
statusline_test_align(
'should have equal spaces even with non-equal sides when using =',
20,
'foobar%=test%=baz',
'foobar~~~test~~~~baz'
)
statusline_test_align(
'should have equal spaces even with longer right side when using =',
20,
'a%=test%=longtext',
'a~~~test~~~~longtext'
)
statusline_test_align(
'should handle an empty left side when using ==',
20,
'%=test%=baz',
'~~~~~~test~~~~~~~baz'
)
statusline_test_align(
'should handle an empty right side when using ==',
20,
'foobar%=test%=',
'foobar~~~~~test~~~~~'
)
statusline_test_align(
'should handle consecutive empty ==',
20,
'%=%=test%=',
'~~~~~~~~~~test~~~~~~'
)
statusline_test_align('should handle an = alone', 20, '%=', '~~~~~~~~~~~~~~~~~~~~')
statusline_test_align(
'should right align text when it is alone with =',
20,
'%=foo',
'~~~~~~~~~~~~~~~~~foo'
)
statusline_test_align(
'should left align text when it is alone with =',
20,
'foo%=',
'foo~~~~~~~~~~~~~~~~~'
)
statusline_test_align('should approximately center text when using %=text%=', 21,
'abc%=neovim%=def', 'abc~~~~neovim~~~~~def')
statusline_test_align('should completely fill the buffer when using %=text%=', 21,
'abc%=neo_vim%=def', 'abc~~~~neo_vim~~~~def')
statusline_test_align('should have equal spacing even with non-equal sides when using =', 21,
'foobar%=test%=baz', 'foobar~~~~test~~~~baz')
statusline_test_align('should have equal spacing even with longer right side when using =', 21,
'a%=test%=longtext', 'a~~~~test~~~~longtext')
statusline_test_align('should handle an empty left side when using ==', 21,
'%=test%=baz', '~~~~~~~test~~~~~~~baz')
statusline_test_align('should handle an empty right side when using ==', 21,
'foobar%=test%=', 'foobar~~~~~test~~~~~~')
statusline_test_align(
'should approximately center text when using %=text%=',
21,
'abc%=neovim%=def',
'abc~~~~neovim~~~~~def'
)
statusline_test_align(
'should completely fill the buffer when using %=text%=',
21,
'abc%=neo_vim%=def',
'abc~~~~neo_vim~~~~def'
)
statusline_test_align(
'should have equal spacing even with non-equal sides when using =',
21,
'foobar%=test%=baz',
'foobar~~~~test~~~~baz'
)
statusline_test_align(
'should have equal spacing even with longer right side when using =',
21,
'a%=test%=longtext',
'a~~~~test~~~~longtext'
)
statusline_test_align(
'should handle an empty left side when using ==',
21,
'%=test%=baz',
'~~~~~~~test~~~~~~~baz'
)
statusline_test_align(
'should handle an empty right side when using ==',
21,
'foobar%=test%=',
'foobar~~~~~test~~~~~~'
)
statusline_test_align('should quadrant the text when using 3 %=', 40,
'abcd%=n%=eovim%=ef', 'abcd~~~~~~~~~n~~~~~~~~~eovim~~~~~~~~~~ef')
statusline_test_align('should work well with %t', 40,
'%t%=right_aligned', 'buffer_spec.lua~~~~~~~~~~~~right_aligned',
{file_name='test/unit/buffer_spec.lua'})
statusline_test_align('should work well with %t and regular text', 40,
'l%=m_l %t m_r%=r', 'l~~~~~~~m_l buffer_spec.lua m_r~~~~~~~~r',
{file_name='test/unit/buffer_spec.lua'})
statusline_test_align('should work well with %=, %t, %L, and %l', 40,
'%t %= %L %= %l', 'buffer_spec.lua ~~~~~~~~~ 1 ~~~~~~~~~~ 0',
{file_name='test/unit/buffer_spec.lua'})
statusline_test_align(
'should quadrant the text when using 3 %=',
40,
'abcd%=n%=eovim%=ef',
'abcd~~~~~~~~~n~~~~~~~~~eovim~~~~~~~~~~ef'
)
statusline_test_align(
'should work well with %t',
40,
'%t%=right_aligned',
'buffer_spec.lua~~~~~~~~~~~~right_aligned',
{ file_name = 'test/unit/buffer_spec.lua' }
)
statusline_test_align(
'should work well with %t and regular text',
40,
'l%=m_l %t m_r%=r',
'l~~~~~~~m_l buffer_spec.lua m_r~~~~~~~~r',
{ file_name = 'test/unit/buffer_spec.lua' }
)
statusline_test_align(
'should work well with %=, %t, %L, and %l',
40,
'%t %= %L %= %l',
'buffer_spec.lua ~~~~~~~~~ 1 ~~~~~~~~~~ 0',
{ file_name = 'test/unit/buffer_spec.lua' }
)
statusline_test_align('should quadrant the text when using 3 %=', 41,
'abcd%=n%=eovim%=ef', 'abcd~~~~~~~~~n~~~~~~~~~eovim~~~~~~~~~~~ef')
statusline_test_align('should work well with %t', 41,
'%t%=right_aligned', 'buffer_spec.lua~~~~~~~~~~~~~right_aligned',
{file_name='test/unit/buffer_spec.lua'})
statusline_test_align('should work well with %t and regular text', 41,
'l%=m_l %t m_r%=r', 'l~~~~~~~~m_l buffer_spec.lua m_r~~~~~~~~r',
{file_name='test/unit/buffer_spec.lua'})
statusline_test_align('should work well with %=, %t, %L, and %l', 41,
'%t %= %L %= %l', 'buffer_spec.lua ~~~~~~~~~~ 1 ~~~~~~~~~~ 0',
{file_name='test/unit/buffer_spec.lua'})
statusline_test_align(
'should quadrant the text when using 3 %=',
41,
'abcd%=n%=eovim%=ef',
'abcd~~~~~~~~~n~~~~~~~~~eovim~~~~~~~~~~~ef'
)
statusline_test_align(
'should work well with %t',
41,
'%t%=right_aligned',
'buffer_spec.lua~~~~~~~~~~~~~right_aligned',
{ file_name = 'test/unit/buffer_spec.lua' }
)
statusline_test_align(
'should work well with %t and regular text',
41,
'l%=m_l %t m_r%=r',
'l~~~~~~~~m_l buffer_spec.lua m_r~~~~~~~~r',
{ file_name = 'test/unit/buffer_spec.lua' }
)
statusline_test_align(
'should work well with %=, %t, %L, and %l',
41,
'%t %= %L %= %l',
'buffer_spec.lua ~~~~~~~~~~ 1 ~~~~~~~~~~ 0',
{ file_name = 'test/unit/buffer_spec.lua' }
)
statusline_test_align('should work with 10 %=', 50,
statusline_test_align(
'should work with 10 %=',
50,
'aaaa%=b%=c%=d%=e%=fg%=hi%=jk%=lmnop%=qrstuv%=wxyz',
'aaaa~~b~~c~~d~~e~~fg~~hi~~jk~~lmnop~~qrstuv~~~wxyz')
'aaaa~~b~~c~~d~~e~~fg~~hi~~jk~~lmnop~~qrstuv~~~wxyz'
)
-- stl item testing
local tabline = ''
for i = 1, 1000 do
tabline = tabline .. (i % 2 == 0 and '%#TabLineSel#' or '%#TabLineFill#') .. tostring(i % 2)
end
statusline_test('should handle a large amount of any items', 20,
tabline,
'<1010101010101010101') -- Should not show any error
statusline_test('should handle a larger amount of = than stl initial item', 20,
statusline_test('should handle a large amount of any items', 20, tabline, '<1010101010101010101') -- Should not show any error
statusline_test(
'should handle a larger amount of = than stl initial item',
20,
('%='):rep(STL_INITIAL_ITEMS * 5),
' ') -- Should not show any error
statusline_test('should handle many extra characters', 20,
' '
) -- Should not show any error
statusline_test(
'should handle many extra characters',
20,
'a' .. ('a'):rep(STL_INITIAL_ITEMS * 5),
'<aaaaaaaaaaaaaaaaaaa') -- Does not show any error
statusline_test('should handle many extra characters and flags', 20,
'<aaaaaaaaaaaaaaaaaaa'
) -- Does not show any error
statusline_test(
'should handle many extra characters and flags',
20,
'a' .. ('%=a'):rep(STL_INITIAL_ITEMS * 2),
'a<aaaaaaaaaaaaaaaaaa') -- Should not show any error
'a<aaaaaaaaaaaaaaaaaa'
) -- Should not show any error
-- multi-byte testing
statusline_test('should handle multibyte characters', 10,
'Ĉ%=x', 'Ĉ x')
statusline_test('should handle multibyte characters and different fillchars', 10,
'Ą%=mid%=end', 'Ą@mid@@end',
{fillchar=('@'):byte()})
statusline_test('should handle multibyte characters', 10, 'Ĉ%=x', 'Ĉ x')
statusline_test(
'should handle multibyte characters and different fillchars',
10,
'Ą%=mid%=end',
'Ą@mid@@end',
{ fillchar = ('@'):byte() }
)
-- escaping % testing
statusline_test('should handle escape of %', 4, 'abc%%', 'abc%')
statusline_test('case where escaped % does not fit', 3, 'abc%%abcabc', '<bc')
statusline_test('escaped % is first', 1, '%%', '%')
end)

View File

@ -1,4 +1,4 @@
local helpers = require("test.unit.helpers")(after_each)
local helpers = require('test.unit.helpers')(after_each)
local itp = helpers.gen_itp(it)
local cimport = helpers.cimport
@ -6,8 +6,7 @@ local eq = helpers.eq
local ffi = helpers.ffi
local to_cstr = helpers.to_cstr
local strings = cimport('stdlib.h', './src/nvim/strings.h',
'./src/nvim/memory.h')
local strings = cimport('stdlib.h', './src/nvim/strings.h', './src/nvim/memory.h')
describe('vim_strsave_escaped()', function()
local vim_strsave_escaped = function(s, chars)
@ -148,14 +147,30 @@ describe('vim_snprintf()', function()
end
end
local function i(n) return ffi.cast('int', n) end
local function l(n) return ffi.cast('long', n) end
local function ll(n) return ffi.cast('long long', n) end
local function z(n) return ffi.cast('ptrdiff_t', n) end
local function u(n) return ffi.cast('unsigned', n) end
local function ul(n) return ffi.cast('unsigned long', n) end
local function ull(n) return ffi.cast('unsigned long long', n) end
local function uz(n) return ffi.cast('size_t', n) end
local function i(n)
return ffi.cast('int', n)
end
local function l(n)
return ffi.cast('long', n)
end
local function ll(n)
return ffi.cast('long long', n)
end
local function z(n)
return ffi.cast('ptrdiff_t', n)
end
local function u(n)
return ffi.cast('unsigned', n)
end
local function ul(n)
return ffi.cast('unsigned long', n)
end
local function ull(n)
return ffi.cast('unsigned long long', n)
end
local function uz(n)
return ffi.cast('size_t', n)
end
itp('truncation', function()
for bsize = 0, 14 do
@ -239,42 +254,44 @@ describe('strcase_save()' , function()
end
itp('decodes overlong encoded characters.', function()
eq("A", strcase_save("\xc1\x81", true))
eq("a", strcase_save("\xc1\x81", false))
eq('A', strcase_save('\xc1\x81', true))
eq('a', strcase_save('\xc1\x81', false))
end)
end)
describe("reverse_text", function()
describe('reverse_text', function()
local reverse_text = function(str)
return helpers.internalize(strings.reverse_text(to_cstr(str)))
end
itp("handles empty string", function()
eq("", reverse_text(""))
itp('handles empty string', function()
eq('', reverse_text(''))
end)
itp("handles simple cases", function()
eq("a", reverse_text("a"))
eq("ba", reverse_text("ab"))
itp('handles simple cases', function()
eq('a', reverse_text('a'))
eq('ba', reverse_text('ab'))
end)
itp("handles multibyte characters", function()
eq("bα", reverse_text("αb"))
eq("Yötön yö", reverse_text("öy nötöY"))
itp('handles multibyte characters', function()
eq('bα', reverse_text('αb'))
eq('Yötön yö', reverse_text('öy nötöY'))
end)
itp("handles combining chars", function()
local utf8_COMBINING_RING_ABOVE = "\204\138"
local utf8_COMBINING_RING_BELOW = "\204\165"
eq("bba" .. utf8_COMBINING_RING_ABOVE .. utf8_COMBINING_RING_BELOW .. "aa",
reverse_text("aaa" .. utf8_COMBINING_RING_ABOVE .. utf8_COMBINING_RING_BELOW .. "bb"))
itp('handles combining chars', function()
local utf8_COMBINING_RING_ABOVE = '\204\138'
local utf8_COMBINING_RING_BELOW = '\204\165'
eq(
'bba' .. utf8_COMBINING_RING_ABOVE .. utf8_COMBINING_RING_BELOW .. 'aa',
reverse_text('aaa' .. utf8_COMBINING_RING_ABOVE .. utf8_COMBINING_RING_BELOW .. 'bb')
)
end)
itp("treats invalid utf as separate characters", function()
eq("\192ba", reverse_text("ab\192"))
itp('treats invalid utf as separate characters', function()
eq('\192ba', reverse_text('ab\192'))
end)
itp("treats an incomplete utf continuation sequence as valid", function()
eq("\194ba", reverse_text("ab\194"))
itp('treats an incomplete utf continuation sequence as valid', function()
eq('\194ba', reverse_text('ab\194'))
end)
end)

View File

@ -39,7 +39,6 @@ child_call_once(function()
undo.u_compute_hash(file_buffer, buffer_hash)
end)
describe('u_write_undo', function()
setup(function()
mkdir('unit-test-directory')
@ -68,7 +67,7 @@ describe('u_write_undo', function()
itp('writes an undo file to undodir given a buffer and hash', function()
u_write_undo(nil, false, file_buffer, buffer_hash)
local correct_name = ffi.string(undo.u_get_undo_file_name(file_buffer.b_ffname, false))
local undo_file = io.open(correct_name, "r")
local undo_file = io.open(correct_name, 'r')
neq(undo_file, nil)
local success, err = os.remove(correct_name) -- delete the file now that we're done with it.
@ -78,9 +77,9 @@ describe('u_write_undo', function()
end)
itp('writes a correctly-named undo file to undodir given a name, buffer, and hash', function()
local correct_name = "undofile.test"
local correct_name = 'undofile.test'
u_write_undo(correct_name, false, file_buffer, buffer_hash)
local undo_file = io.open(correct_name, "r")
local undo_file = io.open(correct_name, 'r')
neq(undo_file, nil)
local success, err = os.remove(correct_name) -- delete the file now that we're done with it.
@ -96,9 +95,9 @@ describe('u_write_undo', function()
itp('writes the undofile with the same permissions as the original file', function()
-- Create Test file and set permissions
local test_file_name = "./test.file"
local test_permission_file = io.open(test_file_name, "w")
test_permission_file:write("testing permissions")
local test_file_name = './test.file'
local test_permission_file = io.open(test_file_name, 'w')
test_permission_file:write('testing permissions')
test_permission_file:close()
local test_permissions = luv.fs_stat(test_file_name).mode
@ -129,7 +128,7 @@ describe('u_write_undo', function()
itp('writes an undofile only readable by the user if the buffer is unnamed', function()
local correct_permissions = 33152
local undo_file_name = "test.undo"
local undo_file_name = 'test.undo'
-- Create vim buffer
file_buffer = buffer.buflist_new(nil, nil, 1, buffer.BLN_LISTED)
@ -149,7 +148,7 @@ describe('u_write_undo', function()
end)
itp('forces writing undo file for :wundo! command', function()
local file_contents = "testing permissions"
local file_contents = 'testing permissions'
-- Write a text file where the undofile should go
local correct_name = ffi.string(undo.u_get_undo_file_name(file_buffer.b_ffname, false))
helpers.write_file(correct_name, file_contents, true, false)
@ -198,13 +197,13 @@ describe('u_write_undo', function()
file_buffer.b_u_numhead = 0 -- Mark it as if there is no undo information
local correct_name = ffi.string(undo.u_get_undo_file_name(file_buffer.b_ffname, false))
local existing_file = io.open(correct_name,"r")
local existing_file = io.open(correct_name, 'r')
if existing_file then
existing_file:close()
os.remove(correct_name)
end
u_write_undo(nil, false, file_buffer, buffer_hash)
local undo_file = io.open(correct_name, "r")
local undo_file = io.open(correct_name, 'r')
eq(undo_file, nil)
end)

View File

@ -83,24 +83,23 @@ local function eltkn2lua(pstate, tkn)
type = conv_eltkn_type(tkn.type),
}
pstate_set_str(pstate, tkn.start, tkn.len, ret)
if not ret.error and (#(ret.str) ~= ret.len) then
if not ret.error and (#ret.str ~= ret.len) then
ret.error = '#str /= len'
end
if ret.type == 'Comparison' then
ret.data = {
type = conv_cmp_type(tkn.data.cmp.type),
ccs = conv_ccs(tkn.data.cmp.ccs),
inv = (not not tkn.data.cmp.inv),
inv = not not tkn.data.cmp.inv,
}
elseif ret.type == 'Multiplication' then
ret.data = { type = conv_enum(eltkn_mul_type_tab, tkn.data.mul.type) }
elseif bracket_types[ret.type] then
ret.data = { closing = (not not tkn.data.brc.closing) }
ret.data = { closing = not not tkn.data.brc.closing }
elseif ret.type == 'Register' then
ret.data = { name = intchar2lua(tkn.data.reg.name) }
elseif (ret.type == 'SingleQuotedString'
or ret.type == 'DoubleQuotedString') then
ret.data = { closed = (not not tkn.data.str.closed) }
elseif ret.type == 'SingleQuotedString' or ret.type == 'DoubleQuotedString' then
ret.data = { closed = not not tkn.data.str.closed }
elseif ret.type == 'Option' then
ret.data = {
scope = conv_enum(eltkn_opt_scope_tab, tkn.data.opt.scope),
@ -109,16 +108,15 @@ local function eltkn2lua(pstate, tkn)
elseif ret.type == 'PlainIdentifier' then
ret.data = {
scope = intchar2lua(tkn.data.var.scope),
autoload = (not not tkn.data.var.autoload),
autoload = not not tkn.data.var.autoload,
}
elseif ret.type == 'Number' then
ret.data = {
is_float = (not not tkn.data.num.is_float),
is_float = not not tkn.data.num.is_float,
base = tonumber(tkn.data.num.base),
}
ret.data.val = tonumber(tkn.data.num.is_float
and tkn.data.num.val.floating
or tkn.data.num.val.integer)
ret.data.val =
tonumber(tkn.data.num.is_float and tkn.data.num.val.floating or tkn.data.num.val.integer)
elseif ret.type == 'Assignment' then
ret.data = { type = conv_expr_asgn_type(tkn.data.ass.type) }
elseif ret.type == 'Invalid' then
@ -151,24 +149,31 @@ describe('Expressions lexer', function()
end
local function singl_eltkn_test(typ, str, data)
local pstate = new_pstate({ str })
eq({data=data, len=#str, start={col=0, line=0}, str=str, type=typ},
next_eltkn(pstate, flags))
eq(
{ data = data, len = #str, start = { col = 0, line = 0 }, str = str, type = typ },
next_eltkn(pstate, flags)
)
check_advance(pstate, #str, 0)
if not (
if
not (
typ == 'Spacing'
or (typ == 'Register' and str == '@')
or ((typ == 'SingleQuotedString' or typ == 'DoubleQuotedString')
and not data.closed)
) then
or ((typ == 'SingleQuotedString' or typ == 'DoubleQuotedString') and not data.closed)
)
then
pstate = new_pstate({ str .. ' ' })
eq({data=data, len=#str, start={col=0, line=0}, str=str, type=typ},
next_eltkn(pstate, flags))
eq(
{ data = data, len = #str, start = { col = 0, line = 0 }, str = str, type = typ },
next_eltkn(pstate, flags)
)
check_advance(pstate, #str, 0)
end
pstate = new_pstate({ 'x' .. str })
pstate.pos.col = 1
eq({data=data, len=#str, start={col=1, line=0}, str=str, type=typ},
next_eltkn(pstate, flags))
eq(
{ data = data, len = #str, start = { col = 1, line = 0 }, str = str, type = typ },
next_eltkn(pstate, flags)
)
check_advance(pstate, #str, 1)
end
local function scope_test(scope)
@ -179,15 +184,23 @@ describe('Expressions lexer', function()
singl_eltkn_test('Comparison', op, { type = cmp_type, inv = false, ccs = 'UseOption' })
singl_eltkn_test('Comparison', inv_op, { type = cmp_type, inv = true, ccs = 'UseOption' })
singl_eltkn_test('Comparison', op .. '#', { type = cmp_type, inv = false, ccs = 'MatchCase' })
singl_eltkn_test('Comparison', inv_op .. '#', {type=cmp_type, inv=true, ccs='MatchCase'})
singl_eltkn_test(
'Comparison',
inv_op .. '#',
{ type = cmp_type, inv = true, ccs = 'MatchCase' }
)
singl_eltkn_test('Comparison', op .. '?', { type = cmp_type, inv = false, ccs = 'IgnoreCase' })
singl_eltkn_test('Comparison', inv_op .. '?', {type=cmp_type, inv=true, ccs='IgnoreCase'})
singl_eltkn_test(
'Comparison',
inv_op .. '?',
{ type = cmp_type, inv = true, ccs = 'IgnoreCase' }
)
end
local function simple_test(pstate_arg, exp_type, exp_len, exp)
local pstate = new_pstate(pstate_arg)
exp = shallowcopy(exp)
exp.type = exp_type
exp.len = exp_len or #(pstate_arg[0])
exp.len = exp_len or #pstate_arg[0]
exp.start = { col = 0, line = 0 }
eq(exp, next_eltkn(pstate, flags))
end
@ -211,7 +224,11 @@ describe('Expressions lexer', function()
singl_eltkn_test('Spacing', ' \t\t \t\t')
singl_eltkn_test('Spacing', ' ')
singl_eltkn_test('Spacing', '\t')
singl_eltkn_test('Invalid', '\x01\x02\x03', {error='E15: Invalid control character present in input: %.*s'})
singl_eltkn_test(
'Invalid',
'\x01\x02\x03',
{ error = 'E15: Invalid control character present in input: %.*s' }
)
singl_eltkn_test('Number', '0123', { is_float = false, base = 8, val = 83 })
singl_eltkn_test('Number', '01234567', { is_float = false, base = 8, val = 342391 })
singl_eltkn_test('Number', '012345678', { is_float = false, base = 10, val = 12345678 })
@ -254,14 +271,14 @@ describe('Expressions lexer', function()
singl_eltkn_test('Register', '@\r', { name = 13 })
singl_eltkn_test('Register', '@ ', { name = ' ' })
singl_eltkn_test('Register', '@\t', { name = 9 })
singl_eltkn_test('SingleQuotedString', '\'test', {closed=false})
singl_eltkn_test('SingleQuotedString', '\'test\'', {closed=true})
singl_eltkn_test('SingleQuotedString', '\'\'\'\'', {closed=true})
singl_eltkn_test('SingleQuotedString', '\'x\'\'\'', {closed=true})
singl_eltkn_test('SingleQuotedString', '\'\'\'x\'', {closed=true})
singl_eltkn_test('SingleQuotedString', '\'\'\'', {closed=false})
singl_eltkn_test('SingleQuotedString', '\'x\'\'', {closed=false})
singl_eltkn_test('SingleQuotedString', '\'\'\'x', {closed=false})
singl_eltkn_test('SingleQuotedString', "'test", { closed = false })
singl_eltkn_test('SingleQuotedString', "'test'", { closed = true })
singl_eltkn_test('SingleQuotedString', "''''", { closed = true })
singl_eltkn_test('SingleQuotedString', "'x'''", { closed = true })
singl_eltkn_test('SingleQuotedString', "'''x'", { closed = true })
singl_eltkn_test('SingleQuotedString', "'''", { closed = false })
singl_eltkn_test('SingleQuotedString', "'x''", { closed = false })
singl_eltkn_test('SingleQuotedString', "'''x", { closed = false })
singl_eltkn_test('DoubleQuotedString', '"test', { closed = false })
singl_eltkn_test('DoubleQuotedString', '"test"', { closed = true })
singl_eltkn_test('DoubleQuotedString', '"\\""', { closed = true })
@ -282,24 +299,112 @@ describe('Expressions lexer', function()
singl_eltkn_test('Invalid', '~', { error = 'E15: Unidentified character: %.*s' })
simple_test({ { data = nil, size = 0 } }, 'EOC', 0, { error = 'start.col >= #pstr' })
simple_test({ '' }, 'EOC', 0, { error = 'start.col >= #pstr' })
simple_test({'2.'}, 'Number', 1, {data={is_float=false, base=10, val=2}, str='2'})
simple_test({'2e5'}, 'Number', 1, {data={is_float=false, base=10, val=2}, str='2'})
simple_test({'2.x'}, 'Number', 1, {data={is_float=false, base=10, val=2}, str='2'})
simple_test({'2.2.'}, 'Number', 1, {data={is_float=false, base=10, val=2}, str='2'})
simple_test({'2.0x'}, 'Number', 1, {data={is_float=false, base=10, val=2}, str='2'})
simple_test({'2.0e'}, 'Number', 1, {data={is_float=false, base=10, val=2}, str='2'})
simple_test({'2.0e+'}, 'Number', 1, {data={is_float=false, base=10, val=2}, str='2'})
simple_test({'2.0e-'}, 'Number', 1, {data={is_float=false, base=10, val=2}, str='2'})
simple_test({'2.0e+x'}, 'Number', 1, {data={is_float=false, base=10, val=2}, str='2'})
simple_test({'2.0e-x'}, 'Number', 1, {data={is_float=false, base=10, val=2}, str='2'})
simple_test({'2.0e+1a'}, 'Number', 1, {data={is_float=false, base=10, val=2}, str='2'})
simple_test({'2.0e-1a'}, 'Number', 1, {data={is_float=false, base=10, val=2}, str='2'})
simple_test({'0b102'}, 'Number', 4, {data={is_float=false, base=2, val=2}, str='0b10'})
simple_test({'10F'}, 'Number', 2, {data={is_float=false, base=10, val=10}, str='10'})
simple_test({'0x0123456789ABCDEFG'}, 'Number', 18, {data={is_float=false, base=16, val=81985529216486895}, str='0x0123456789ABCDEF'})
simple_test({{data='00', size=2}}, 'Number', 2, {data={is_float=false, base=8, val=0}, str='00'})
simple_test({{data='009', size=2}}, 'Number', 2, {data={is_float=false, base=8, val=0}, str='00'})
simple_test({{data='01', size=1}}, 'Number', 1, {data={is_float=false, base=10, val=0}, str='0'})
simple_test(
{ '2.' },
'Number',
1,
{ data = { is_float = false, base = 10, val = 2 }, str = '2' }
)
simple_test(
{ '2e5' },
'Number',
1,
{ data = { is_float = false, base = 10, val = 2 }, str = '2' }
)
simple_test(
{ '2.x' },
'Number',
1,
{ data = { is_float = false, base = 10, val = 2 }, str = '2' }
)
simple_test(
{ '2.2.' },
'Number',
1,
{ data = { is_float = false, base = 10, val = 2 }, str = '2' }
)
simple_test(
{ '2.0x' },
'Number',
1,
{ data = { is_float = false, base = 10, val = 2 }, str = '2' }
)
simple_test(
{ '2.0e' },
'Number',
1,
{ data = { is_float = false, base = 10, val = 2 }, str = '2' }
)
simple_test(
{ '2.0e+' },
'Number',
1,
{ data = { is_float = false, base = 10, val = 2 }, str = '2' }
)
simple_test(
{ '2.0e-' },
'Number',
1,
{ data = { is_float = false, base = 10, val = 2 }, str = '2' }
)
simple_test(
{ '2.0e+x' },
'Number',
1,
{ data = { is_float = false, base = 10, val = 2 }, str = '2' }
)
simple_test(
{ '2.0e-x' },
'Number',
1,
{ data = { is_float = false, base = 10, val = 2 }, str = '2' }
)
simple_test(
{ '2.0e+1a' },
'Number',
1,
{ data = { is_float = false, base = 10, val = 2 }, str = '2' }
)
simple_test(
{ '2.0e-1a' },
'Number',
1,
{ data = { is_float = false, base = 10, val = 2 }, str = '2' }
)
simple_test(
{ '0b102' },
'Number',
4,
{ data = { is_float = false, base = 2, val = 2 }, str = '0b10' }
)
simple_test(
{ '10F' },
'Number',
2,
{ data = { is_float = false, base = 10, val = 10 }, str = '10' }
)
simple_test({ '0x0123456789ABCDEFG' }, 'Number', 18, {
data = { is_float = false, base = 16, val = 81985529216486895 },
str = '0x0123456789ABCDEF',
})
simple_test(
{ { data = '00', size = 2 } },
'Number',
2,
{ data = { is_float = false, base = 8, val = 0 }, str = '00' }
)
simple_test(
{ { data = '009', size = 2 } },
'Number',
2,
{ data = { is_float = false, base = 8, val = 0 }, str = '00' }
)
simple_test(
{ { data = '01', size = 1 } },
'Number',
1,
{ data = { is_float = false, base = 10, val = 0 }, str = '0' }
)
end
local function regular_scope_tests()
@ -312,29 +417,104 @@ describe('Expressions lexer', function()
scope_test('l')
scope_test('a')
simple_test({'g:'}, 'PlainIdentifier', 2, {data={scope='g', autoload=false}, str='g:'})
simple_test({'g:is#foo'}, 'PlainIdentifier', 8, {data={scope='g', autoload=true}, str='g:is#foo'})
simple_test({'g:isnot#foo'}, 'PlainIdentifier', 11, {data={scope='g', autoload=true}, str='g:isnot#foo'})
simple_test(
{ 'g:' },
'PlainIdentifier',
2,
{ data = { scope = 'g', autoload = false }, str = 'g:' }
)
simple_test(
{ 'g:is#foo' },
'PlainIdentifier',
8,
{ data = { scope = 'g', autoload = true }, str = 'g:is#foo' }
)
simple_test(
{ 'g:isnot#foo' },
'PlainIdentifier',
11,
{ data = { scope = 'g', autoload = true }, str = 'g:isnot#foo' }
)
end
local function regular_is_tests()
comparison_test('is', 'isnot', 'Identical')
simple_test({'is'}, 'Comparison', 2, {data={type='Identical', inv=false, ccs='UseOption'}, str='is'})
simple_test({'isnot'}, 'Comparison', 5, {data={type='Identical', inv=true, ccs='UseOption'}, str='isnot'})
simple_test({'is?'}, 'Comparison', 3, {data={type='Identical', inv=false, ccs='IgnoreCase'}, str='is?'})
simple_test({'isnot?'}, 'Comparison', 6, {data={type='Identical', inv=true, ccs='IgnoreCase'}, str='isnot?'})
simple_test({'is#'}, 'Comparison', 3, {data={type='Identical', inv=false, ccs='MatchCase'}, str='is#'})
simple_test({'isnot#'}, 'Comparison', 6, {data={type='Identical', inv=true, ccs='MatchCase'}, str='isnot#'})
simple_test({'is#foo'}, 'Comparison', 3, {data={type='Identical', inv=false, ccs='MatchCase'}, str='is#'})
simple_test({'isnot#foo'}, 'Comparison', 6, {data={type='Identical', inv=true, ccs='MatchCase'}, str='isnot#'})
simple_test(
{ 'is' },
'Comparison',
2,
{ data = { type = 'Identical', inv = false, ccs = 'UseOption' }, str = 'is' }
)
simple_test(
{ 'isnot' },
'Comparison',
5,
{ data = { type = 'Identical', inv = true, ccs = 'UseOption' }, str = 'isnot' }
)
simple_test(
{ 'is?' },
'Comparison',
3,
{ data = { type = 'Identical', inv = false, ccs = 'IgnoreCase' }, str = 'is?' }
)
simple_test(
{ 'isnot?' },
'Comparison',
6,
{ data = { type = 'Identical', inv = true, ccs = 'IgnoreCase' }, str = 'isnot?' }
)
simple_test(
{ 'is#' },
'Comparison',
3,
{ data = { type = 'Identical', inv = false, ccs = 'MatchCase' }, str = 'is#' }
)
simple_test(
{ 'isnot#' },
'Comparison',
6,
{ data = { type = 'Identical', inv = true, ccs = 'MatchCase' }, str = 'isnot#' }
)
simple_test(
{ 'is#foo' },
'Comparison',
3,
{ data = { type = 'Identical', inv = false, ccs = 'MatchCase' }, str = 'is#' }
)
simple_test(
{ 'isnot#foo' },
'Comparison',
6,
{ data = { type = 'Identical', inv = true, ccs = 'MatchCase' }, str = 'isnot#' }
)
end
local function regular_number_tests()
simple_test({'2.0'}, 'Number', 1, {data={is_float=false, base=10, val=2}, str='2'})
simple_test({'2.0e5'}, 'Number', 1, {data={is_float=false, base=10, val=2}, str='2'})
simple_test({'2.0e+5'}, 'Number', 1, {data={is_float=false, base=10, val=2}, str='2'})
simple_test({'2.0e-5'}, 'Number', 1, {data={is_float=false, base=10, val=2}, str='2'})
simple_test(
{ '2.0' },
'Number',
1,
{ data = { is_float = false, base = 10, val = 2 }, str = '2' }
)
simple_test(
{ '2.0e5' },
'Number',
1,
{ data = { is_float = false, base = 10, val = 2 }, str = '2' }
)
simple_test(
{ '2.0e+5' },
'Number',
1,
{ data = { is_float = false, base = 10, val = 2 }, str = '2' }
)
simple_test(
{ '2.0e-5' },
'Number',
1,
{ data = { is_float = false, base = 10, val = 2 }, str = '2' }
)
end
local function regular_eoc_tests()
@ -369,7 +549,12 @@ describe('Expressions lexer', function()
regular_is_tests()
regular_number_tests()
simple_test({'g:'}, 'PlainIdentifier', 1, {data={scope=0, autoload=false}, str='g'})
simple_test(
{ 'g:' },
'PlainIdentifier',
1,
{ data = { scope = 0, autoload = false }, str = 'g' }
)
end)
itp('allows floats', function()
flags = tonumber(lib.kELFlagAllowFloat)
@ -379,20 +564,72 @@ describe('Expressions lexer', function()
regular_scope_tests()
regular_is_tests()
simple_test({'2.2'}, 'Number', 3, {data={is_float=true, base=10, val=2.2}, str='2.2'})
simple_test({'2.0e5'}, 'Number', 5, {data={is_float=true, base=10, val=2e5}, str='2.0e5'})
simple_test({'2.0e+5'}, 'Number', 6, {data={is_float=true, base=10, val=2e5}, str='2.0e+5'})
simple_test({'2.0e-5'}, 'Number', 6, {data={is_float=true, base=10, val=2e-5}, str='2.0e-5'})
simple_test({'2.500000e-5'}, 'Number', 11, {data={is_float=true, base=10, val=2.5e-5}, str='2.500000e-5'})
simple_test({'2.5555e2'}, 'Number', 8, {data={is_float=true, base=10, val=2.5555e2}, str='2.5555e2'})
simple_test({'2.5555e+2'}, 'Number', 9, {data={is_float=true, base=10, val=2.5555e2}, str='2.5555e+2'})
simple_test({'2.5555e-2'}, 'Number', 9, {data={is_float=true, base=10, val=2.5555e-2}, str='2.5555e-2'})
simple_test({{data='2.5e-5', size=3}},
'Number', 3, {data={is_float=true, base=10, val=2.5}, str='2.5'})
simple_test({{data='2.5e5', size=4}},
'Number', 1, {data={is_float=false, base=10, val=2}, str='2'})
simple_test({{data='2.5e-50', size=6}},
'Number', 6, {data={is_float=true, base=10, val=2.5e-5}, str='2.5e-5'})
simple_test(
{ '2.2' },
'Number',
3,
{ data = { is_float = true, base = 10, val = 2.2 }, str = '2.2' }
)
simple_test(
{ '2.0e5' },
'Number',
5,
{ data = { is_float = true, base = 10, val = 2e5 }, str = '2.0e5' }
)
simple_test(
{ '2.0e+5' },
'Number',
6,
{ data = { is_float = true, base = 10, val = 2e5 }, str = '2.0e+5' }
)
simple_test(
{ '2.0e-5' },
'Number',
6,
{ data = { is_float = true, base = 10, val = 2e-5 }, str = '2.0e-5' }
)
simple_test(
{ '2.500000e-5' },
'Number',
11,
{ data = { is_float = true, base = 10, val = 2.5e-5 }, str = '2.500000e-5' }
)
simple_test(
{ '2.5555e2' },
'Number',
8,
{ data = { is_float = true, base = 10, val = 2.5555e2 }, str = '2.5555e2' }
)
simple_test(
{ '2.5555e+2' },
'Number',
9,
{ data = { is_float = true, base = 10, val = 2.5555e2 }, str = '2.5555e+2' }
)
simple_test(
{ '2.5555e-2' },
'Number',
9,
{ data = { is_float = true, base = 10, val = 2.5555e-2 }, str = '2.5555e-2' }
)
simple_test(
{ { data = '2.5e-5', size = 3 } },
'Number',
3,
{ data = { is_float = true, base = 10, val = 2.5 }, str = '2.5' }
)
simple_test(
{ { data = '2.5e5', size = 4 } },
'Number',
1,
{ data = { is_float = false, base = 10, val = 2 }, str = '2' }
)
simple_test(
{ { data = '2.5e-50', size = 6 } },
'Number',
6,
{ data = { is_float = true, base = 10, val = 2.5e-5 }, str = '2.5e-5' }
)
end)
itp('treats `is` as an identifier', function()
flags = tonumber(lib.kELFlagIsNotCmp)
@ -402,14 +639,54 @@ describe('Expressions lexer', function()
regular_scope_tests()
regular_number_tests()
simple_test({'is'}, 'PlainIdentifier', 2, {data={scope=0, autoload=false}, str='is'})
simple_test({'isnot'}, 'PlainIdentifier', 5, {data={scope=0, autoload=false}, str='isnot'})
simple_test({'is?'}, 'PlainIdentifier', 2, {data={scope=0, autoload=false}, str='is'})
simple_test({'isnot?'}, 'PlainIdentifier', 5, {data={scope=0, autoload=false}, str='isnot'})
simple_test({'is#'}, 'PlainIdentifier', 3, {data={scope=0, autoload=true}, str='is#'})
simple_test({'isnot#'}, 'PlainIdentifier', 6, {data={scope=0, autoload=true}, str='isnot#'})
simple_test({'is#foo'}, 'PlainIdentifier', 6, {data={scope=0, autoload=true}, str='is#foo'})
simple_test({'isnot#foo'}, 'PlainIdentifier', 9, {data={scope=0, autoload=true}, str='isnot#foo'})
simple_test(
{ 'is' },
'PlainIdentifier',
2,
{ data = { scope = 0, autoload = false }, str = 'is' }
)
simple_test(
{ 'isnot' },
'PlainIdentifier',
5,
{ data = { scope = 0, autoload = false }, str = 'isnot' }
)
simple_test(
{ 'is?' },
'PlainIdentifier',
2,
{ data = { scope = 0, autoload = false }, str = 'is' }
)
simple_test(
{ 'isnot?' },
'PlainIdentifier',
5,
{ data = { scope = 0, autoload = false }, str = 'isnot' }
)
simple_test(
{ 'is#' },
'PlainIdentifier',
3,
{ data = { scope = 0, autoload = true }, str = 'is#' }
)
simple_test(
{ 'isnot#' },
'PlainIdentifier',
6,
{ data = { scope = 0, autoload = true }, str = 'isnot#' }
)
simple_test(
{ 'is#foo' },
'PlainIdentifier',
6,
{ data = { scope = 0, autoload = true }, str = 'is#foo' }
)
simple_test(
{ 'isnot#foo' },
'PlainIdentifier',
9,
{ data = { scope = 0, autoload = true }, str = 'isnot#foo' }
)
end)
itp('forbids EOC', function()
flags = tonumber(lib.kELFlagForbidEOC)

View File

@ -25,8 +25,7 @@ local conv_cmp_type = viml_helpers.conv_cmp_type
local pstate_set_str = viml_helpers.pstate_set_str
local conv_expr_asgn_type = viml_helpers.conv_expr_asgn_type
local lib = cimport('./src/nvim/viml/parser/expressions.h',
'./src/nvim/syntax.h')
local lib = cimport('./src/nvim/viml/parser/expressions.h', './src/nvim/syntax.h')
local alloc_log = alloc_log_new()
@ -136,22 +135,18 @@ child_call_once(function()
-- linking, otherwise it will be created as cleared. So existence
-- of the group is checked here and not in the next pass over
-- nvim_hl_defs.
eq(true, not not (nvim_hl_defs[grp_link]
or predefined_hl_defs[grp_link]))
eq(false, not not (nvim_hl_defs[new_grp]
or predefined_hl_defs[new_grp]))
eq(true, not not (nvim_hl_defs[grp_link] or predefined_hl_defs[grp_link]))
eq(false, not not (nvim_hl_defs[new_grp] or predefined_hl_defs[new_grp]))
nvim_hl_defs[new_grp] = { 'link', grp_link }
else
local new_grp, grp_args = s:match('^(%w+) (.*)')
neq(nil, new_grp)
eq(false, not not (nvim_hl_defs[new_grp]
or predefined_hl_defs[new_grp]))
eq(false, not not (nvim_hl_defs[new_grp] or predefined_hl_defs[new_grp]))
nvim_hl_defs[new_grp] = { 'definition', grp_args }
end
end)
if not err then
msg = format_string(
'Error while processing string %s at position %u:\n%s', s, i, msg)
msg = format_string('Error while processing string %s at position %u:\n%s', s, i, msg)
error(msg)
end
i = i + 1
@ -185,12 +180,12 @@ local function hls_to_hl_fs(hls)
local col_shift = col - next_col
assert(col_shift >= 0)
next_col = col + #str
ret[i] = format_string('hl(%r, %r%s)',
ret[i] = format_string(
'hl(%r, %r%s)',
group,
str,
(col_shift == 0
and ''
or (', %u'):format(col_shift)))
(col_shift == 0 and '' or (', %u'):format(col_shift))
)
end
return ret
end
@ -205,9 +200,9 @@ local function format_check(expr, format_check_data, opts)
dig_len = #opts.funcname + 2
else
print(format_string('\n_check_parsing(%r, %r, {', opts, expr))
dig_len = #('_check_parsing(, \'') + #(format_string('%r', opts))
dig_len = #"_check_parsing(, '" + #(format_string('%r', opts))
end
local digits = ' --' .. (' '):rep(dig_len - #(' --'))
local digits = ' --' .. (' '):rep(dig_len - #' --')
local digits2 = digits:sub(1, -10)
for i = 0, #expr - 1 do
if i % 10 == 0 then
@ -240,10 +235,9 @@ local function format_check(expr, format_check_data, opts)
diffs[flags] = dictdiff(zdata, v)
if diffs[flags] then
if flags == 3 + zflags then
if (dictdiff(format_check_data[1 + zflags],
format_check_data[3 + zflags]) == nil
or dictdiff(format_check_data[2 + zflags],
format_check_data[3 + zflags]) == nil)
if
dictdiff(format_check_data[1 + zflags], format_check_data[3 + zflags]) == nil
or dictdiff(format_check_data[2 + zflags], format_check_data[3 + zflags]) == nil
then
diffs[flags] = nil
else
@ -268,7 +262,7 @@ local function format_check(expr, format_check_data, opts)
end
if diff.hl_fs then
print(' hl_fs = ' .. format_luav(diff.hl_fs, ' ', {
literal_strings=true
literal_strings = true,
}) .. ',')
end
print(' },')
@ -280,7 +274,9 @@ local function format_check(expr, format_check_data, opts)
end
local east_node_type_tab
make_enum_conv_tab(lib, {
make_enum_conv_tab(
lib,
{
'kExprNodeMissing',
'kExprNodeOpMissing',
'kExprNodeTernary',
@ -320,7 +316,12 @@ make_enum_conv_tab(lib, {
'kExprNodeOption',
'kExprNodeEnvironment',
'kExprNodeAssignment',
}, 'kExprNode', function(ret) east_node_type_tab = ret end)
},
'kExprNode',
function(ret)
east_node_type_tab = ret
end
)
local function conv_east_node_type(typ)
return conv_enum(east_node_type_tab, typ)
@ -346,25 +347,35 @@ local function eastnode2lua(pstate, eastnode, checked_nodes)
ret_str = ('%u:%u:%s'):format(str.start.line, str.start.col, str.str)
end
if typ == 'Register' then
typ = typ .. ('(name=%s)'):format(
tostring(intchar2lua(eastnode.data.reg.name)))
typ = typ .. ('(name=%s)'):format(tostring(intchar2lua(eastnode.data.reg.name)))
elseif typ == 'PlainIdentifier' then
typ = typ .. ('(scope=%s,ident=%s)'):format(
typ = typ
.. ('(scope=%s,ident=%s)'):format(
tostring(intchar2lua(eastnode.data.var.scope)),
ffi.string(eastnode.data.var.ident, eastnode.data.var.ident_len))
ffi.string(eastnode.data.var.ident, eastnode.data.var.ident_len)
)
elseif typ == 'PlainKey' then
typ = typ .. ('(key=%s)'):format(
ffi.string(eastnode.data.var.ident, eastnode.data.var.ident_len))
elseif (typ == 'UnknownFigure' or typ == 'DictLiteral'
or typ == 'CurlyBracesIdentifier' or typ == 'Lambda') then
typ = typ .. ('(%s)'):format(
typ = typ
.. ('(key=%s)'):format(ffi.string(eastnode.data.var.ident, eastnode.data.var.ident_len))
elseif
typ == 'UnknownFigure'
or typ == 'DictLiteral'
or typ == 'CurlyBracesIdentifier'
or typ == 'Lambda'
then
typ = typ
.. ('(%s)'):format(
(eastnode.data.fig.type_guesses.allow_lambda and '\\' or '-')
.. (eastnode.data.fig.type_guesses.allow_dict and 'd' or '-')
.. (eastnode.data.fig.type_guesses.allow_ident and 'i' or '-'))
.. (eastnode.data.fig.type_guesses.allow_ident and 'i' or '-')
)
elseif typ == 'Comparison' then
typ = typ .. ('(type=%s,inv=%u,ccs=%s)'):format(
conv_cmp_type(eastnode.data.cmp.type), eastnode.data.cmp.inv and 1 or 0,
conv_ccs(eastnode.data.cmp.ccs))
typ = typ
.. ('(type=%s,inv=%u,ccs=%s)'):format(
conv_cmp_type(eastnode.data.cmp.type),
eastnode.data.cmp.inv and 1 or 0,
conv_ccs(eastnode.data.cmp.ccs)
)
elseif typ == 'Integer' then
typ = typ .. ('(val=%u)'):format(tonumber(eastnode.data.num.value))
elseif typ == 'Float' then
@ -380,11 +391,13 @@ local function eastnode2lua(pstate, eastnode, checked_nodes)
typ = ('%s(scope=%s,ident=%s)'):format(
typ,
tostring(intchar2lua(eastnode.data.opt.scope)),
ffi.string(eastnode.data.opt.ident, eastnode.data.opt.ident_len))
ffi.string(eastnode.data.opt.ident, eastnode.data.opt.ident_len)
)
elseif typ == 'Environment' then
typ = ('%s(ident=%s)'):format(
typ,
ffi.string(eastnode.data.env.ident, eastnode.data.env.ident_len))
ffi.string(eastnode.data.env.ident, eastnode.data.env.ident_len)
)
elseif typ == 'Assignment' then
typ = ('%s(%s)'):format(typ, conv_expr_asgn_type(eastnode.data.ass.type))
end
@ -433,22 +446,21 @@ local function phl2lua(pstate)
local ret = {}
for i = 0, (tonumber(pstate.colors.size) - 1) do
local chunk = pstate.colors.items[i]
local chunk_tbl = pstate_set_str(
pstate, chunk.start, chunk.end_col - chunk.start.col, {
local chunk_tbl = pstate_set_str(pstate, chunk.start, chunk.end_col - chunk.start.col, {
group = ffi.string(chunk.group),
})
ret[i + 1] = ('%s:%u:%u:%s'):format(
chunk_tbl.group,
chunk_tbl.start.line,
chunk_tbl.start.col,
chunk_tbl.str)
chunk_tbl.str
)
end
return ret
end
describe('Expressions parser', function()
local function _check_parsing(opts, str, exp_ast, exp_highlighting_fs,
nz_flags_exps)
local function _check_parsing(opts, str, exp_ast, exp_highlighting_fs, nz_flags_exps)
local zflags = opts.flags[1]
nz_flags_exps = nz_flags_exps or {}
local format_check_data = {}
@ -499,8 +511,7 @@ describe('Expressions parser', function()
alloc_log:check({})
end)
if not err then
msg = format_string('Error while processing test (%r, %u):\n%s',
str, flags, msg)
msg = format_string('Error while processing test (%r, %u):\n%s', str, flags, msg)
error(msg)
end
end
@ -514,16 +525,11 @@ describe('Expressions parser', function()
error(('Unknown group: Nvim%s'):format(group))
end
local col = next_col + (shift or 0)
return (('%s:%u:%u:%s'):format(
'Nvim' .. group,
0,
col,
str)), (col + #str)
return (('%s:%u:%u:%s'):format('Nvim' .. group, 0, col, str)), (col + #str)
end
end
local function fmtn(typ, args, rest)
return ('%s(%s)%s'):format(typ, args, rest)
end
require('test.unit.viml.expressions.parser_tests')(
itp, _check_parsing, hl, fmtn)
require('test.unit.viml.expressions.parser_tests')(itp, _check_parsing, hl, fmtn)
end)

View File

@ -142,7 +142,7 @@ return function(itp, _check_parsing, hl, fmtn)
len = 2,
err = REMOVE_THIS,
ast = {
'Register(name=a):0:0:@a'
'Register(name=a):0:0:@a',
},
},
hl_fs = {
@ -174,7 +174,7 @@ return function(itp, _check_parsing, hl, fmtn)
len = 6,
err = REMOVE_THIS,
ast = {
'Register(name=a):0:0: @a'
'Register(name=a):0:0: @a',
},
},
hl_fs = {
@ -541,7 +541,7 @@ return function(itp, _check_parsing, hl, fmtn)
children = {
{
'Nested:0:4:(',
children = { 'Register(name=b):0:5:@b' }
children = { 'Register(name=b):0:5:@b' },
},
},
},
@ -579,7 +579,7 @@ return function(itp, _check_parsing, hl, fmtn)
children = {
{
'Nested:0:4:(',
children = { 'Register(name=b):0:5:@b' }
children = { 'Register(name=b):0:5:@b' },
},
},
},
@ -600,13 +600,13 @@ return function(itp, _check_parsing, hl, fmtn)
hl('BinaryPlus', '+'),
hl('Register', '@c'),
})
check_parsing(
'@a + (@b + @c) + @d(@e) + (+@f) + ((+@g(@h))(@j)(@k))(@l)', {--[[
check_parsing('@a + (@b + @c) + @d(@e) + (+@f) + ((+@g(@h))(@j)(@k))(@l)', {--[[
| | | | | | | | || | | || | | ||| || || || ||
000000000011111111112222222222333333333344444444445555555
012345678901234567890123456789012345678901234567890123456
]]
ast = {{
ast = {
{
'BinaryPlus:0:31: +',
children = {
{
@ -696,7 +696,8 @@ return function(itp, _check_parsing, hl, fmtn)
},
},
},
}},
},
},
}, {
hl('Register', '@a'),
hl('BinaryPlus', '+', 1),
@ -2851,7 +2852,7 @@ return function(itp, _check_parsing, hl, fmtn)
},
err = {
arg = '{a : b',
msg = 'E723: Missing end of Dictionary \'}\': %.*s',
msg = "E723: Missing end of Dictionary '}': %.*s",
},
}, {
hl('Dict', '{'),
@ -3182,7 +3183,7 @@ return function(itp, _check_parsing, hl, fmtn)
},
err = {
arg = '?b',
msg = 'E109: Missing \':\' after \'?\': %.*s',
msg = "E109: Missing ':' after '?': %.*s",
},
}, {
hl('IdentifierName', 'a'),
@ -3207,7 +3208,7 @@ return function(itp, _check_parsing, hl, fmtn)
},
err = {
arg = '?b:',
msg = 'E109: Missing \':\' after \'?\': %.*s',
msg = "E109: Missing ':' after '?': %.*s",
},
}, {
hl('IdentifierName', 'a'),
@ -4840,7 +4841,7 @@ return function(itp, _check_parsing, hl, fmtn)
},
err = {
arg = '[1',
msg = 'E697: Missing end of List \']\': %.*s',
msg = "E697: Missing end of List ']': %.*s",
},
}, {
hl('List', '['),
@ -4848,15 +4849,15 @@ return function(itp, _check_parsing, hl, fmtn)
})
end)
itp('works with strings', function()
check_parsing('\'abc\'', {
check_parsing("'abc'", {
-- 01234
ast = {
fmtn('SingleQuotedString', 'val="abc"', ':0:0:\'abc\''),
fmtn('SingleQuotedString', 'val="abc"', ":0:0:'abc'"),
},
}, {
hl('SingleQuote', '\''),
hl('SingleQuote', "'"),
hl('SingleQuotedBody', 'abc'),
hl('SingleQuote', '\''),
hl('SingleQuote', "'"),
})
check_parsing('"abc"', {
-- 01234
@ -4868,14 +4869,14 @@ return function(itp, _check_parsing, hl, fmtn)
hl('DoubleQuotedBody', 'abc'),
hl('DoubleQuote', '"'),
})
check_parsing('\'\'', {
check_parsing("''", {
-- 01
ast = {
fmtn('SingleQuotedString', 'val=NULL', ':0:0:\'\''),
fmtn('SingleQuotedString', 'val=NULL', ":0:0:''"),
},
}, {
hl('SingleQuote', '\''),
hl('SingleQuote', '\''),
hl('SingleQuote', "'"),
hl('SingleQuote', "'"),
})
check_parsing('""', {
-- 01
@ -4898,17 +4899,17 @@ return function(itp, _check_parsing, hl, fmtn)
}, {
hl('InvalidDoubleQuote', '"'),
})
check_parsing('\'', {
check_parsing("'", {
-- 0
ast = {
fmtn('SingleQuotedString', 'val=NULL', ':0:0:\''),
fmtn('SingleQuotedString', 'val=NULL', ":0:0:'"),
},
err = {
arg = '\'',
arg = "'",
msg = 'E115: Missing single quote: %.*s',
},
}, {
hl('InvalidSingleQuote', '\''),
hl('InvalidSingleQuote', "'"),
})
check_parsing('"a', {
-- 01
@ -4923,71 +4924,71 @@ return function(itp, _check_parsing, hl, fmtn)
hl('InvalidDoubleQuote', '"'),
hl('InvalidDoubleQuotedBody', 'a'),
})
check_parsing('\'a', {
check_parsing("'a", {
-- 01
ast = {
fmtn('SingleQuotedString', 'val="a"', ':0:0:\'a'),
fmtn('SingleQuotedString', 'val="a"', ":0:0:'a"),
},
err = {
arg = '\'a',
arg = "'a",
msg = 'E115: Missing single quote: %.*s',
},
}, {
hl('InvalidSingleQuote', '\''),
hl('InvalidSingleQuote', "'"),
hl('InvalidSingleQuotedBody', 'a'),
})
check_parsing('\'abc\'\'def\'', {
check_parsing("'abc''def'", {
-- 0123456789
ast = {
fmtn('SingleQuotedString', 'val="abc\'def"', ':0:0:\'abc\'\'def\''),
fmtn('SingleQuotedString', 'val="abc\'def"', ":0:0:'abc''def'"),
},
}, {
hl('SingleQuote', '\''),
hl('SingleQuote', "'"),
hl('SingleQuotedBody', 'abc'),
hl('SingleQuotedQuote', '\'\''),
hl('SingleQuotedQuote', "''"),
hl('SingleQuotedBody', 'def'),
hl('SingleQuote', '\''),
hl('SingleQuote', "'"),
})
check_parsing('\'abc\'\'', {
check_parsing("'abc''", {
-- 012345
ast = {
fmtn('SingleQuotedString', 'val="abc\'"', ':0:0:\'abc\'\''),
fmtn('SingleQuotedString', 'val="abc\'"', ":0:0:'abc''"),
},
err = {
arg = '\'abc\'\'',
arg = "'abc''",
msg = 'E115: Missing single quote: %.*s',
},
}, {
hl('InvalidSingleQuote', '\''),
hl('InvalidSingleQuote', "'"),
hl('InvalidSingleQuotedBody', 'abc'),
hl('InvalidSingleQuotedQuote', '\'\''),
hl('InvalidSingleQuotedQuote', "''"),
})
check_parsing('\'\'\'\'\'\'\'\'', {
check_parsing("''''''''", {
-- 01234567
ast = {
fmtn('SingleQuotedString', 'val="\'\'\'"', ':0:0:\'\'\'\'\'\'\'\''),
fmtn('SingleQuotedString', "val=\"'''\"", ":0:0:''''''''"),
},
}, {
hl('SingleQuote', '\''),
hl('SingleQuotedQuote', '\'\''),
hl('SingleQuotedQuote', '\'\''),
hl('SingleQuotedQuote', '\'\''),
hl('SingleQuote', '\''),
hl('SingleQuote', "'"),
hl('SingleQuotedQuote', "''"),
hl('SingleQuotedQuote', "''"),
hl('SingleQuotedQuote', "''"),
hl('SingleQuote', "'"),
})
check_parsing('\'\'\'a\'\'\'\'bc\'', {
check_parsing("'''a''''bc'", {
-- 01234567890
-- 0 1
ast = {
fmtn('SingleQuotedString', 'val="\'a\'\'bc"', ':0:0:\'\'\'a\'\'\'\'bc\''),
fmtn('SingleQuotedString', "val=\"'a''bc\"", ":0:0:'''a''''bc'"),
},
}, {
hl('SingleQuote', '\''),
hl('SingleQuotedQuote', '\'\''),
hl('SingleQuote', "'"),
hl('SingleQuotedQuote', "''"),
hl('SingleQuotedBody', 'a'),
hl('SingleQuotedQuote', '\'\''),
hl('SingleQuotedQuote', '\'\''),
hl('SingleQuotedQuote', "''"),
hl('SingleQuotedQuote', "''"),
hl('SingleQuotedBody', 'bc'),
hl('SingleQuote', '\''),
hl('SingleQuote', "'"),
})
check_parsing('"\\"\\"\\"\\""', {
-- 0123456789
@ -5006,7 +5007,11 @@ return function(itp, _check_parsing, hl, fmtn)
-- 0123456789012345678901234
-- 0 1 2
ast = {
fmtn('DoubleQuotedString', 'val="abc\\"def\\"ghi\\"jkl\\"mno"', ':0:0:"abc\\"def\\"ghi\\"jkl\\"mno"'),
fmtn(
'DoubleQuotedString',
'val="abc\\"def\\"ghi\\"jkl\\"mno"',
':0:0:"abc\\"def\\"ghi\\"jkl\\"mno"'
),
},
}, {
hl('DoubleQuote', '"'),
@ -6977,8 +6982,7 @@ return function(itp, _check_parsing, hl, fmtn)
arg = '\0002&A:\000',
msg = 'E15: Expected value, got EOC: %.*s',
},
}, {
}, {
}, {}, {
[2] = {
ast = {
len = REMOVE_THIS,
@ -7076,8 +7080,7 @@ return function(itp, _check_parsing, hl, fmtn)
arg = '|"\\U\\',
msg = 'E15: Expected value, got EOC: %.*s',
},
}, {
}, {
}, {}, {
[2] = {
ast = {
len = REMOVE_THIS,
@ -7109,8 +7112,7 @@ return function(itp, _check_parsing, hl, fmtn)
arg = '|"\\e"',
msg = 'E15: Expected value, got EOC: %.*s',
},
}, {
}, {
}, {}, {
[2] = {
ast = {
len = REMOVE_THIS,
@ -7142,8 +7144,7 @@ return function(itp, _check_parsing, hl, fmtn)
arg = '|\029',
msg = 'E15: Expected value, got EOC: %.*s',
},
}, {
}, {
}, {}, {
[2] = {
ast = {
len = REMOVE_THIS,
@ -7373,7 +7374,7 @@ return function(itp, _check_parsing, hl, fmtn)
hl_fs = {
[2] = REMOVE_THIS,
[3] = REMOVE_THIS,
}
},
},
})

View File

@ -76,7 +76,7 @@ local function pstate_set_str(pstate, start, len, ret)
ret = ret or {}
ret.start = {
line = tonumber(start.line),
col = tonumber(start.col)
col = tonumber(start.col),
}
ret.len = tonumber(len)
ret.str, ret.error = pstate_str(pstate, start, len)
@ -84,36 +84,57 @@ local function pstate_set_str(pstate, start, len, ret)
end
local eltkn_cmp_type_tab
make_enum_conv_tab(lib, {
make_enum_conv_tab(
lib,
{
'kExprCmpEqual',
'kExprCmpMatches',
'kExprCmpGreater',
'kExprCmpGreaterOrEqual',
'kExprCmpIdentical',
}, 'kExprCmp', function(ret) eltkn_cmp_type_tab = ret end)
},
'kExprCmp',
function(ret)
eltkn_cmp_type_tab = ret
end
)
local function conv_cmp_type(typ)
return conv_enum(eltkn_cmp_type_tab, typ)
end
local ccs_tab
make_enum_conv_tab(lib, {
make_enum_conv_tab(
lib,
{
'kCCStrategyUseOption',
'kCCStrategyMatchCase',
'kCCStrategyIgnoreCase',
}, 'kCCStrategy', function(ret) ccs_tab = ret end)
},
'kCCStrategy',
function(ret)
ccs_tab = ret
end
)
local function conv_ccs(ccs)
return conv_enum(ccs_tab, ccs)
end
local expr_asgn_type_tab
make_enum_conv_tab(lib, {
make_enum_conv_tab(
lib,
{
'kExprAsgnPlain',
'kExprAsgnAdd',
'kExprAsgnSubtract',
'kExprAsgnConcat',
}, 'kExprAsgn', function(ret) expr_asgn_type_tab = ret end)
},
'kExprAsgn',
function(ret)
expr_asgn_type_tab = ret
end
)
local function conv_expr_asgn_type(expr_asgn_type)
return conv_enum(expr_asgn_type_tab, expr_asgn_type)