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,14 +4,13 @@ local clear = helpers.clear
local exec_lua = helpers.exec_lua
describe('treesitter perf', function()
setup(function()
clear()
end)
it('can handle large folds', function()
helpers.command'edit ./src/nvim/eval.c'
exec_lua[[
helpers.command 'edit ./src/nvim/eval.c'
exec_lua [[
local parser = vim.treesitter.get_parser(0, "c", {})
vim.treesitter.highlighter.new(parser)
@ -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,49 +27,73 @@ 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,
}
local repeatSuiteString = '\nRepeating all tests (run %d of %d) . . .\n\n'
local randomizeString = c.note('Note: Randomizing test order with a seed of %d.\n')
local globalSetup = c.sect('--------') .. ' Global test environment setup.\n'
local fileStartString = c.sect('--------') .. ' Running tests from ' .. c.file('%s') .. '\n'
local runString = c.sect('RUN ') .. ' ' .. c.test('%s') .. ': '
local successString = c.succ('OK') .. '\n'
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 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 successStatus = c.succ('PASSED ') .. ' ' .. c.nmbr('%d') .. ' %s.\n'
local timeString = c.time('%.2f ms')
local randomizeString = c.note('Note: Randomizing test order with a seed of %d.\n')
local globalSetup = c.sect('--------') .. ' Global test environment setup.\n'
local fileStartString = c.sect('--------') .. ' Running tests from ' .. c.file('%s') .. '\n'
local runString = c.sect('RUN ') .. ' ' .. c.test('%s') .. ': '
local successString = c.succ('OK') .. '\n'
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 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 successStatus = c.succ('PASSED ') .. ' ' .. c.nmbr('%d') .. ' %s.\n'
local timeString = c.time('%.2f ms')
local summaryStrings = {
skipped = {
header = c.skip('SKIPPED ') .. ' ' .. c.nmbr('%d') .. ' %s, listed below:\n',
test = c.skip('SKIPPED ') .. ' %s\n',
test = c.skip('SKIPPED ') .. ' %s\n',
footer = ' ' .. c.nmbr('%d') .. ' SKIPPED %s\n',
},
failure = {
header = c.fail('FAILED ') .. ' ' .. c.nmbr('%d') .. ' %s, listed below:\n',
test = c.fail('FAILED ') .. ' %s\n',
test = c.fail('FAILED ') .. ' %s\n',
footer = ' ' .. c.nmbr('%d') .. ' FAILED %s\n',
},
error = {
header = c.errr('ERROR ') .. ' ' .. c.nmbr('%d') .. ' %s, listed below:\n',
test = c.errr('ERROR ') .. ' %s\n',
test = c.errr('ERROR ') .. ' %s\n',
footer = ' ' .. c.nmbr('%d') .. ' %s\n',
},
}
@ -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
@ -67,7 +85,7 @@ function MsgpackRpcStream:write(method, args, response_cb)
data = self._session:notify()
end
data = data .. self._pack(method) .. self._pack(args)
data = data .. self._pack(method) .. self._pack(args)
self._stream:write(data)
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

@ -7,7 +7,7 @@ if package.loaded['jit'] then
-- luajit pcall is already coroutine safe
Session.safe_pcall = pcall
else
Session.safe_pcall = require'coxpcall'.pcall
Session.safe_pcall = require 'coxpcall'.pcall
end
local function resume(co, ...)
@ -25,7 +25,7 @@ local function resume(co, ...)
end
local function coroutine_exec(func, ...)
local args = {...}
local args = { ... }
local on_complete
if #args > 0 and type(args[#args]) == 'function' then
@ -50,18 +50,18 @@ function Session.new(stream)
_pending_messages = {},
_prepare = uv.new_prepare(),
_timer = uv.new_timer(),
_is_running = false
_is_running = false,
}, Session)
end
function Session:next_message(timeout)
local function on_request(method, args, response)
table.insert(self._pending_messages, {'request', method, args, response})
table.insert(self._pending_messages, { 'request', method, args, response })
uv.stop()
end
local function on_notification(method, args)
table.insert(self._pending_messages, {'notification', method, args})
table.insert(self._pending_messages, { 'notification', method, args })
uv.stop()
end
@ -83,11 +83,11 @@ function Session:next_message(timeout)
end
function Session:notify(method, ...)
self._msgpack_rpc_stream:write(method, {...})
self._msgpack_rpc_stream:write(method, { ... })
end
function Session:request(method, ...)
local args = {...}
local args = { ... }
local err, result
if self._is_running then
err, result = self:_yielding_request(method, args)
@ -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
@ -159,11 +163,11 @@ function Session:_blocking_request(method, args)
local err, result
local function on_request(method_, args_, response)
table.insert(self._pending_messages, {'request', method_, args_, response})
table.insert(self._pending_messages, { 'request', method_, args_, response })
end
local function on_notification(method_, args_)
table.insert(self._pending_messages, {'notification', method_, args_})
table.insert(self._pending_messages, { 'notification', method_, args_ })
end
self._msgpack_rpc_stream:write(method, args, function(e, r)
@ -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,9 +42,9 @@ 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)
uv.pipe_connect(socket, file, function(err)
self._stream_error = self._stream_error or err
end)
return self
@ -54,15 +54,14 @@ 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)
uv.tcp_connect(socket, host, port, function(err)
self._stream_error = self._stream_error or err
end)
return self
end
function SocketStream:write(data)
if self._stream_error then
error(self._stream_error)
@ -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 = {}
@ -112,7 +111,7 @@ function ChildProcessStream.spawn(argv, env, io_extra)
args[#args + 1] = argv[i]
end
self._proc, self._pid = uv.spawn(prog, {
stdio = {self._child_stdin, self._child_stdout, 2, io_extra},
stdio = { self._child_stdin, self._child_stdout, 2, io_extra },
args = args,
env = env,
}, function(status, signal)
@ -154,7 +153,7 @@ function ChildProcessStream:close(signal)
self._child_stdin:close()
self._child_stdout:close()
if type(signal) == 'string' then
self._proc:kill('sig'..signal)
self._proc:kill('sig' .. signal)
end
while self.status == nil do
uv.run 'once'
@ -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
@ -60,7 +60,7 @@ function module.argss_to_cmd(...)
for i = 1, select('#', ...) do
local arg = select(i, ...)
if type(arg) == 'string' then
cmd = cmd .. ' ' ..shell_quote(arg)
cmd = cmd .. ' ' .. shell_quote(arg)
else
for _, subarg in ipairs(arg) do
cmd = cmd .. ' ' .. shell_quote(subarg)
@ -92,19 +92,19 @@ function module.retry(max, max_ms, fn)
if status then
return result
end
luv.update_time() -- Update cached value of luv.now() (libuv: uv_now()).
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...
luv.sleep(20) -- Avoid hot loop...
end
end
local check_logs_useless_lines = {
['Warning: noted but unhandled ioctl']=1,
['could cause spurious value errors to appear']=2,
['See README_MISSING_SYSCALL_OR_IOCTL for guidance']=3,
['Warning: noted but unhandled ioctl'] = 1,
['could cause spurious value errors to appear'] = 2,
['See README_MISSING_SYSCALL_OR_IOCTL for guidance'] = 3,
}
function module.eq(expected, actual, context)
@ -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 '))
for _,line in ipairs(lines) do
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
end
if not inverse then error(msg) end
if not inverse then
error(msg)
end
end)
end
@ -186,9 +201,10 @@ 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')
:gsub('[^%s<]-[/\\]([^%s:/\\]+):%d+', '.../%1:0')
:gsub('\xffvim\xff', 'vim/')
local errmsg = tostring(rv)
:gsub('([%s<])vim[/\\]([^%s:/\\]+):%d+', '%1\xffvim\xff%2:0')
:gsub('[^%s<]-[/\\]([^%s:/\\]+):%d+', '.../%1:0')
:gsub('\xffvim\xff', 'vim/')
-- Scrub numbers in paths/stacktraces:
-- shared.lua:0: in function 'gsplit'
@ -233,9 +249,10 @@ end
function module.pcall_err_withtrace(fn, ...)
local errmsg = module.pcall_err_withfile(fn, ...)
return errmsg:gsub('^%.%.%./helpers%.lua:0: ', '')
:gsub('^Error executing lua:- ' ,'')
:gsub('^%[string "<nvim>"%]:0: ' ,'')
return errmsg
:gsub('^%.%.%./helpers%.lua:0: ', '')
:gsub('^Error executing lua:- ', '')
:gsub('^%[string "<nvim>"%]:0: ', '')
end
function module.pcall_err(...)
@ -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
@ -251,12 +268,14 @@ end
-- exc_re: exclude pattern(s) (string or table)
function module.glob(initial_path, re, exc_re)
exc_re = type(exc_re) == 'table' and exc_re or { exc_re }
local paths_to_check = {initial_path}
local paths_to_check = { initial_path }
local ret = {}
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
@ -318,7 +337,7 @@ function module.check_logs()
out:write(start_msg .. '\n')
if status then
for line in f:lines() do
out:write('= '..line..'\n')
out:write('= ' .. line .. '\n')
end
f:close()
else
@ -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
error('unknown platform: '..tostring(s))
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
@ -384,15 +402,15 @@ module.tmpname = (function()
if module.is_os('win') and fname:sub(1, 2) == '\\s' then
-- In Windows tmpname() returns a filename starting with
-- special sequence \s, prepend $TEMP path
return tmpdir..fname
return tmpdir .. fname
elseif fname:match('^/tmp') and module.is_os('mac') then
-- In OS X /tmp links to /private/tmp
return '/private'..fname
return '/private' .. fname
else
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())
and relpath(tmpdir_get()):gsub('^[ ./]+',''):gsub('%/+$',''):gsub('([^%w])', '%%%1')
or nil)
local local_tmpdir = (
tmpdir_is_local(tmpdir_get())
and relpath(tmpdir_get()):gsub('^[ ./]+', ''):gsub('%/+$', ''):gsub('([^%w])', '%%%1')
or nil
)
local db_cmd
if module.hasenv('NVIM_TEST_CORE_GLOB_DIRECTORY') then
initial_path = os.getenv('NVIM_TEST_CORE_GLOB_DIRECTORY')
@ -444,7 +465,7 @@ function module.check_cores(app, force) -- luacheck: ignore
else
re = '/core[^/]*$'
end
exc_re = { '^/%.deps$', '^/%'..deps_prefix()..'$', local_tmpdir, '^/%node_modules$' }
exc_re = { '^/%.deps$', '^/%' .. deps_prefix() .. '$', local_tmpdir, '^/%node_modules$' }
db_cmd = gdb_db_cmd
random_skip = true
end
@ -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
@ -597,9 +618,9 @@ function module.dedent(str, leave_indent)
-- create a pattern for the indent
indent = indent:gsub('%s', '[ \t]')
-- strip it from the first line
str = str:gsub('^'..indent, left_indent)
str = str:gsub('^' .. indent, left_indent)
-- strip it from the remaining lines
str = str:gsub('[\n]'..indent, '\n' .. left_indent)
str = str:gsub('[\n]' .. indent, '\n' .. left_indent)
return str
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
@ -684,7 +729,7 @@ function module.format_luav(v, indent, opts)
if nl == ' ' and non_empty then
ret = ret:sub(1, -3)
end
ret = ret .. indent .. '}'
ret = ret .. indent .. '}'
end
elseif type(v) == 'number' then
if v % 1 == 0 then
@ -709,7 +754,7 @@ end
-- Commit: 520c0b91a528
function module.format_string(fmt, ...)
local i = 0
local args = {...}
local args = { ... }
local function getarg()
i = i + 1
return args[i]
@ -728,7 +773,7 @@ function module.format_string(fmt, ...)
-- Builtin %q is replaced here as it gives invalid and inconsistent with
-- luajit results for e.g. "\e" on lua: luajit transforms that into `\27`,
-- lua leaves as-is.
arg = module.format_luav(arg, nil, {dquote_strings = (subfmt:sub(-1) == 'q')})
arg = module.format_luav(arg, nil, { dquote_strings = (subfmt:sub(-1) == 'q') })
subfmt = subfmt:sub(1, -2) .. 's'
end
if subfmt == '%e' then
@ -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,13 +920,16 @@ 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'
..string.format('$NVIM_LOG_FILE: %s\n', logfile)
..(#lines > 0 and '(last '..tostring(keep)..' lines)\n' or '(empty)\n'))
for _,line in ipairs(lines) do
log = log..line..'\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')
)
for _, line in ipairs(lines) do
log = log .. line .. '\n'
end
log = log..('-'):rep(78)..'\n'
log = log .. ('-'):rep(78) .. '\n'
if is_ci and ci_rename then
os.rename(logfile, logfile .. '.displayed')
end

View File

@ -1,9 +1,13 @@
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;
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
local uv = vim.uv
@ -15,14 +19,14 @@ local system = {}
package.loaded['system.core'] = system
function system.monotime()
uv.update_time()
return uv.now()*1e-3
return uv.now() * 1e-3
end
function system.gettime()
local sec, usec = uv.gettimeofday()
return sec+usec*1e-6
return sec + usec * 1e-6
end
function system.sleep(sec)
uv.sleep(sec*1e3)
uv.sleep(sec * 1e3)
end
local term = {}
@ -31,7 +35,7 @@ function term.isatty(_)
return uv.guess_handle(1) == 'tty'
end
local lfs = {_VERSION = 'fake'}
local lfs = { _VERSION = 'fake' }
package.loaded['lfs'] = lfs
function lfs.attributes(path, attr)
@ -39,9 +43,11 @@ 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
return mtime.sec + mtime.nsec * 1e-9
else
error('not implemented')
end
@ -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',
'./src/nvim/api/private/helpers.h',
'./src/nvim/memory.h')
local api = cimport(
'./src/nvim/api/private/defs.h',
'./src/nvim/api/private/helpers.h',
'./src/nvim/memory.h'
)
local obj2lua
@ -27,8 +29,8 @@ local function init_obj2lua_tab()
end
obj2lua_tab = {
[tonumber(api.kObjectTypeArray)] = function(obj)
local ret = {[type_key]=list_type}
for i = 1,tonumber(obj.data.array.size) do
local ret = { [type_key] = list_type }
for i = 1, tonumber(obj.data.array.size) do
ret[i] = obj2lua(obj.data.array.items[i - 1])
end
if ret[1] then
@ -38,7 +40,7 @@ local function init_obj2lua_tab()
end,
[tonumber(api.kObjectTypeDictionary)] = function(obj)
local ret = {}
for i = 1,tonumber(obj.data.dictionary.size) do
for i = 1, tonumber(obj.data.dictionary.size) do
local kv_pair = obj.data.dictionary.items[i - 1]
ret[ffi.string(kv_pair.key.data, kv_pair.key.size)] = obj2lua(kv_pair.value)
end
@ -58,7 +60,7 @@ local function init_obj2lua_tab()
return tonumber(obj.data.floating)
end,
[tonumber(api.kObjectTypeInteger)] = function(obj)
return {[type_key]=int_type, value=tonumber(obj.data.integer)}
return { [type_key] = int_type, value = tonumber(obj.data.integer) }
end,
[tonumber(api.kObjectTypeString)] = function(obj)
return ffi.string(obj.data.string.data, obj.data.string.size)
@ -68,32 +70,38 @@ 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
local lua2obj_type_tab = {
[int_type] = function(l)
return obj(api.kObjectTypeInteger, {integer=l.value})
return obj(api.kObjectTypeInteger, { integer = l.value })
end,
[flt_type] = function(l)
return obj(api.kObjectTypeFloat, {floating=l})
return obj(api.kObjectTypeFloat, { floating = l })
end,
[list_type] = function(l)
local len = #l
local arr = obj(api.kObjectTypeArray, {array={
size=len,
capacity=len,
items=ffi.cast('Object *', api.xmalloc(len * ffi.sizeof('Object'))),
}})
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
@ -103,21 +111,23 @@ local lua2obj_type_tab = {
local kvs = {}
for k, v in pairs(l) do
if type(k) == 'string' then
kvs[#kvs + 1] = {k, v}
kvs[#kvs + 1] = { k, v }
end
end
local len = #kvs
local dct = obj(api.kObjectTypeDictionary, {dictionary={
size=len,
capacity=len,
items=ffi.cast('KeyValuePair *',
api.xmalloc(len * ffi.sizeof('KeyValuePair'))),
}})
local dct = obj(api.kObjectTypeDictionary, {
dictionary = {
size = len,
capacity = len,
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,
@ -137,28 +147,31 @@ lua2obj = function(l)
elseif type(l) == 'number' then
return lua2obj_type_tab[flt_type](l)
elseif type(l) == 'boolean' then
return obj(api.kObjectTypeBoolean, {boolean=l})
return obj(api.kObjectTypeBoolean, { boolean = l })
elseif type(l) == 'string' then
return obj(api.kObjectTypeString, {string={
size=#l,
data=api.xmemdupz(to_cstr(l), #l),
}})
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})
return obj(api.kObjectTypeNil, { integer = 0 })
end
end
return {
list_type=list_type,
dict_type=dict_type,
func_type=func_type,
int_type=int_type,
flt_type=flt_type,
list_type = list_type,
dict_type = dict_type,
func_type = func_type,
int_type = int_type,
flt_type = flt_type,
nil_value=nil_value,
nil_value = nil_value,
type_key=type_key,
type_key = type_key,
obj2lua=obj2lua,
lua2obj=lua2obj,
obj2lua = obj2lua,
lua2obj = lua2obj,
}

View File

@ -42,49 +42,61 @@ describe('vim_to_object', function()
simple_test('converts -1.5', -1.5)
simple_test('converts empty string', '')
simple_test('converts non-empty string', 'foobar')
simple_test('converts integer 10', {[type_key]=int_type, value=10})
simple_test('converts integer 10', { [type_key] = int_type, value = 10 })
simple_test('converts empty dictionary', {})
simple_test('converts dictionary with scalar values', {test=10, test2=true, test3='test'})
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 dictionary with scalar values', { test = 10, test2 = true, test3 = 'test' })
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 } } }
)
local dct = {}
dct.dct = dct
different_output_test('outputs nil for nested dictionaries (1 level)', dct, {dct=nil_value})
different_output_test('outputs nil for nested dictionaries (1 level)', dct, { dct = nil_value })
local lst = {}
lst[1] = lst
different_output_test('outputs nil for nested lists (1 level)', lst, {nil_value})
different_output_test('outputs nil for nested lists (1 level)', lst, { nil_value })
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})
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 }
)
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})
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 }
)
local lst2 = {}
lst2[1] = {lst2}
different_output_test('outputs nil for nested lists (2 level, in list)', lst2, {{nil_value}})
lst2[1] = { lst2 }
different_output_test('outputs nil for nested lists (2 level, in list)', lst2, { { nil_value } })
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'})
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' }
)
itp('outputs empty list for NULL list', function()
local tt = typvalt('VAR_LIST', {v_list=NULL})
local tt = typvalt('VAR_LIST', { v_list = NULL })
eq(nil, tt.vval.v_list)
eq({[type_key]=list_type}, obj2lua(api.vim_to_object(tt)))
eq({ [type_key] = list_type }, obj2lua(api.vim_to_object(tt)))
end)
itp('outputs empty dict for NULL dict', function()
local tt = typvalt('VAR_DICT', {v_dict=NULL})
local tt = typvalt('VAR_DICT', { v_dict = NULL })
eq(nil, tt.vval.v_dict)
eq({}, obj2lua(api.vim_to_object(tt)))
end)
@ -92,15 +104,15 @@ describe('vim_to_object', function()
itp('regression: partials in a list', function()
local llist = {
{
[type_key]=func_type,
value='printf',
args={'%s'},
dict={v=1},
[type_key] = func_type,
value = 'printf',
args = { '%s' },
dict = { v = 1 },
},
{},
}
local list = lua2typvalt(llist)
eq(llist, typvalt2lua(list))
eq({nil_value, {}}, obj2lua(api.vim_to_object(list)))
eq({ nil_value, {} }, obj2lua(api.vim_to_object(list)))
end)
end)

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 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,11 +70,9 @@ describe('buffer functions', function()
end)
end)
describe('buflist_findpat', function()
local ALLOW_UNLISTED = 1
local ONLY_LISTED = 0
local ONLY_LISTED = 0
local buflist_findpat = function(pat, allow_unlisted)
return buffer.buflist_findpat(to_cstr(pat), NULL, allow_unlisted, 0, 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)
@ -26,10 +26,10 @@ local ucnt = 4242
local function arginit(arg)
if arg == 'unum' then
ucnt = ucnt + 1
return ARGTYPES[arg]({ucnt})
return ARGTYPES[arg]({ ucnt })
else
icnt = icnt - 1
return ARGTYPES[arg]({icnt})
return ARGTYPES[arg]({ icnt })
end
end
@ -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
@ -82,18 +92,48 @@ end
describe('vim_str2nr()', function()
itp('works fine when it has nothing to do', function()
test_vim_str2nr('', 0, {len = 0, num = 0, unum = 0, pre = 0}, 0)
test_vim_str2nr('', lib.STR2NR_ALL, {len = 0, num = 0, unum = 0, pre = 0}, 0)
test_vim_str2nr('', lib.STR2NR_BIN, {len = 0, num = 0, unum = 0, pre = 0}, 0)
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('', 0, { len = 0, num = 0, unum = 0, pre = 0 }, 0)
test_vim_str2nr('', lib.STR2NR_ALL, { len = 0, num = 0, unum = 0, pre = 0 }, 0)
test_vim_str2nr('', lib.STR2NR_BIN, { len = 0, num = 0, unum = 0, pre = 0 }, 0)
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
)
end)
itp('works with decimal numbers', function()
for _, flags in ipairs({
@ -110,30 +150,30 @@ describe('vim_str2nr()', function()
lib.STR2NR_FORCE + lib.STR2NR_DEC,
}) do
-- Check that all digits are recognized
test_vim_str2nr( '12345', flags, {len = 5, num = 12345, unum = 12345, pre = 0}, 0)
test_vim_str2nr( '67890', flags, {len = 5, num = 67890, unum = 67890, pre = 0}, 0)
test_vim_str2nr( '12345A', flags, {len = 0}, 0)
test_vim_str2nr( '67890A', flags, {len = 0}, 0)
test_vim_str2nr( '12345A', flags, {len = 5, num = 12345, unum = 12345, pre = 0}, 0, false)
test_vim_str2nr( '67890A', flags, {len = 5, num = 67890, unum = 67890, pre = 0}, 0, false)
test_vim_str2nr('12345', flags, { len = 5, num = 12345, unum = 12345, pre = 0 }, 0)
test_vim_str2nr('67890', flags, { len = 5, num = 67890, unum = 67890, pre = 0 }, 0)
test_vim_str2nr('12345A', flags, { len = 0 }, 0)
test_vim_str2nr('67890A', flags, { len = 0 }, 0)
test_vim_str2nr('12345A', flags, { len = 5, num = 12345, unum = 12345, pre = 0 }, 0, false)
test_vim_str2nr('67890A', flags, { len = 5, num = 67890, unum = 67890, pre = 0 }, 0, false)
test_vim_str2nr( '42', flags, {len = 2, num = 42, unum = 42, pre = 0}, 0)
test_vim_str2nr( '42', flags, {len = 1, num = 4, unum = 4, pre = 0}, 1)
test_vim_str2nr( '42', flags, {len = 2, num = 42, unum = 42, pre = 0}, 2)
test_vim_str2nr( '42', flags, {len = 2, num = 42, unum = 42, pre = 0}, 3) -- includes NUL byte in maxlen
test_vim_str2nr('42', flags, { len = 2, num = 42, unum = 42, pre = 0 }, 0)
test_vim_str2nr('42', flags, { len = 1, num = 4, unum = 4, pre = 0 }, 1)
test_vim_str2nr('42', flags, { len = 2, num = 42, unum = 42, pre = 0 }, 2)
test_vim_str2nr('42', flags, { len = 2, num = 42, unum = 42, pre = 0 }, 3) -- includes NUL byte in maxlen
test_vim_str2nr( '42x', flags, {len = 0}, 0)
test_vim_str2nr( '42x', flags, {len = 0}, 3)
test_vim_str2nr( '42x', flags, {len = 2, num = 42, unum = 42, pre = 0}, 0, false)
test_vim_str2nr( '42x', flags, {len = 2, num = 42, unum = 42, pre = 0}, 3, false)
test_vim_str2nr('42x', flags, { len = 0 }, 0)
test_vim_str2nr('42x', flags, { len = 0 }, 3)
test_vim_str2nr('42x', flags, { len = 2, num = 42, unum = 42, pre = 0 }, 0, false)
test_vim_str2nr('42x', flags, { len = 2, num = 42, unum = 42, pre = 0 }, 3, false)
test_vim_str2nr('-42', flags, {len = 3, num = -42, unum = 42, pre = 0}, 3)
test_vim_str2nr('-42', flags, {len = 1, num = 0, unum = 0, pre = 0}, 1)
test_vim_str2nr('-42', flags, { len = 3, num = -42, unum = 42, pre = 0 }, 3)
test_vim_str2nr('-42', flags, { len = 1, num = 0, unum = 0, pre = 0 }, 1)
test_vim_str2nr('-42x', flags, {len = 0}, 0)
test_vim_str2nr('-42x', flags, {len = 0}, 4)
test_vim_str2nr('-42x', flags, {len = 3, num = -42, unum = 42, pre = 0}, 0, false)
test_vim_str2nr('-42x', flags, {len = 3, num = -42, unum = 42, pre = 0}, 4, false)
test_vim_str2nr('-42x', flags, { len = 0 }, 0)
test_vim_str2nr('-42x', flags, { len = 0 }, 4)
test_vim_str2nr('-42x', flags, { len = 3, num = -42, unum = 42, pre = 0 }, 0, false)
test_vim_str2nr('-42x', flags, { len = 3, num = -42, unum = 42, pre = 0 }, 4, false)
end
end)
itp('works with binary numbers', function()
@ -154,66 +194,66 @@ describe('vim_str2nr()', function()
BIN = ('B'):byte()
end
test_vim_str2nr( '0b101', flags, {len = 5, num = 5, unum = 5, pre = bin}, 0)
test_vim_str2nr( '0b101', flags, {len = 1, num = 0, unum = 0, pre = 0 }, 1)
test_vim_str2nr( '0b101', flags, {len = 0}, 2)
test_vim_str2nr( '0b101', flags, {len = 1, num = 0, unum = 0, pre = 0 }, 2, false)
test_vim_str2nr( '0b101', flags, {len = 3, num = 1, unum = 1, pre = bin}, 3)
test_vim_str2nr( '0b101', flags, {len = 4, num = 2, unum = 2, pre = bin}, 4)
test_vim_str2nr( '0b101', flags, {len = 5, num = 5, unum = 5, pre = bin}, 5)
test_vim_str2nr( '0b101', flags, {len = 5, num = 5, unum = 5, pre = bin}, 6)
test_vim_str2nr('0b101', flags, { len = 5, num = 5, unum = 5, pre = bin }, 0)
test_vim_str2nr('0b101', flags, { len = 1, num = 0, unum = 0, pre = 0 }, 1)
test_vim_str2nr('0b101', flags, { len = 0 }, 2)
test_vim_str2nr('0b101', flags, { len = 1, num = 0, unum = 0, pre = 0 }, 2, false)
test_vim_str2nr('0b101', flags, { len = 3, num = 1, unum = 1, pre = bin }, 3)
test_vim_str2nr('0b101', flags, { len = 4, num = 2, unum = 2, pre = bin }, 4)
test_vim_str2nr('0b101', flags, { len = 5, num = 5, unum = 5, pre = bin }, 5)
test_vim_str2nr('0b101', flags, { len = 5, num = 5, unum = 5, pre = bin }, 6)
test_vim_str2nr( '0b1012', flags, {len = 0}, 0)
test_vim_str2nr( '0b1012', flags, {len = 0}, 6)
test_vim_str2nr( '0b1012', flags, {len = 5, num = 5, unum = 5, pre = bin}, 0, false)
test_vim_str2nr( '0b1012', flags, {len = 5, num = 5, unum = 5, pre = bin}, 6, false)
test_vim_str2nr('0b1012', flags, { len = 0 }, 0)
test_vim_str2nr('0b1012', flags, { len = 0 }, 6)
test_vim_str2nr('0b1012', flags, { len = 5, num = 5, unum = 5, pre = bin }, 0, false)
test_vim_str2nr('0b1012', flags, { len = 5, num = 5, unum = 5, pre = bin }, 6, false)
test_vim_str2nr('-0b101', flags, {len = 6, num = -5, unum = 5, pre = bin}, 0)
test_vim_str2nr('-0b101', flags, {len = 1, num = 0, unum = 0, pre = 0 }, 1)
test_vim_str2nr('-0b101', flags, {len = 2, num = 0, unum = 0, pre = 0 }, 2)
test_vim_str2nr('-0b101', flags, {len = 0}, 3)
test_vim_str2nr('-0b101', flags, {len = 2, num = 0, unum = 0, pre = 0 }, 3, false)
test_vim_str2nr('-0b101', flags, {len = 4, num = -1, unum = 1, pre = bin}, 4)
test_vim_str2nr('-0b101', flags, {len = 5, num = -2, unum = 2, pre = bin}, 5)
test_vim_str2nr('-0b101', flags, {len = 6, num = -5, unum = 5, pre = bin}, 6)
test_vim_str2nr('-0b101', flags, {len = 6, num = -5, unum = 5, pre = bin}, 7)
test_vim_str2nr('-0b101', flags, { len = 6, num = -5, unum = 5, pre = bin }, 0)
test_vim_str2nr('-0b101', flags, { len = 1, num = 0, unum = 0, pre = 0 }, 1)
test_vim_str2nr('-0b101', flags, { len = 2, num = 0, unum = 0, pre = 0 }, 2)
test_vim_str2nr('-0b101', flags, { len = 0 }, 3)
test_vim_str2nr('-0b101', flags, { len = 2, num = 0, unum = 0, pre = 0 }, 3, false)
test_vim_str2nr('-0b101', flags, { len = 4, num = -1, unum = 1, pre = bin }, 4)
test_vim_str2nr('-0b101', flags, { len = 5, num = -2, unum = 2, pre = bin }, 5)
test_vim_str2nr('-0b101', flags, { len = 6, num = -5, unum = 5, pre = bin }, 6)
test_vim_str2nr('-0b101', flags, { len = 6, num = -5, unum = 5, pre = bin }, 7)
test_vim_str2nr('-0b1012', flags, {len = 0}, 0)
test_vim_str2nr('-0b1012', flags, {len = 0}, 7)
test_vim_str2nr('-0b1012', flags, {len = 6, num = -5, unum = 5, pre = bin}, 0, false)
test_vim_str2nr('-0b1012', flags, {len = 6, num = -5, unum = 5, pre = bin}, 7, false)
test_vim_str2nr('-0b1012', flags, { len = 0 }, 0)
test_vim_str2nr('-0b1012', flags, { len = 0 }, 7)
test_vim_str2nr('-0b1012', flags, { len = 6, num = -5, unum = 5, pre = bin }, 0, false)
test_vim_str2nr('-0b1012', flags, { len = 6, num = -5, unum = 5, pre = bin }, 7, false)
test_vim_str2nr( '0B101', flags, {len = 5, num = 5, unum = 5, pre = BIN}, 0)
test_vim_str2nr( '0B101', flags, {len = 1, num = 0, unum = 0, pre = 0 }, 1)
test_vim_str2nr( '0B101', flags, {len = 0}, 2)
test_vim_str2nr( '0B101', flags, {len = 1, num = 0, unum = 0, pre = 0 }, 2, false)
test_vim_str2nr( '0B101', flags, {len = 3, num = 1, unum = 1, pre = BIN}, 3)
test_vim_str2nr( '0B101', flags, {len = 4, num = 2, unum = 2, pre = BIN}, 4)
test_vim_str2nr( '0B101', flags, {len = 5, num = 5, unum = 5, pre = BIN}, 5)
test_vim_str2nr( '0B101', flags, {len = 5, num = 5, unum = 5, pre = BIN}, 6)
test_vim_str2nr('0B101', flags, { len = 5, num = 5, unum = 5, pre = BIN }, 0)
test_vim_str2nr('0B101', flags, { len = 1, num = 0, unum = 0, pre = 0 }, 1)
test_vim_str2nr('0B101', flags, { len = 0 }, 2)
test_vim_str2nr('0B101', flags, { len = 1, num = 0, unum = 0, pre = 0 }, 2, false)
test_vim_str2nr('0B101', flags, { len = 3, num = 1, unum = 1, pre = BIN }, 3)
test_vim_str2nr('0B101', flags, { len = 4, num = 2, unum = 2, pre = BIN }, 4)
test_vim_str2nr('0B101', flags, { len = 5, num = 5, unum = 5, pre = BIN }, 5)
test_vim_str2nr('0B101', flags, { len = 5, num = 5, unum = 5, pre = BIN }, 6)
test_vim_str2nr( '0B1012', flags, {len = 0}, 0)
test_vim_str2nr( '0B1012', flags, {len = 0}, 6)
test_vim_str2nr( '0B1012', flags, {len = 5, num = 5, unum = 5, pre = BIN}, 0, false)
test_vim_str2nr( '0B1012', flags, {len = 5, num = 5, unum = 5, pre = BIN}, 6, false)
test_vim_str2nr('0B1012', flags, { len = 0 }, 0)
test_vim_str2nr('0B1012', flags, { len = 0 }, 6)
test_vim_str2nr('0B1012', flags, { len = 5, num = 5, unum = 5, pre = BIN }, 0, false)
test_vim_str2nr('0B1012', flags, { len = 5, num = 5, unum = 5, pre = BIN }, 6, false)
test_vim_str2nr('-0B101', flags, {len = 6, num = -5, unum = 5, pre = BIN}, 0)
test_vim_str2nr('-0B101', flags, {len = 1, num = 0, unum = 0, pre = 0 }, 1)
test_vim_str2nr('-0B101', flags, {len = 2, num = 0, unum = 0, pre = 0 }, 2)
test_vim_str2nr('-0B101', flags, {len = 0}, 3)
test_vim_str2nr('-0B101', flags, {len = 2, num = 0, unum = 0, pre = 0 }, 3, false)
test_vim_str2nr('-0B101', flags, {len = 4, num = -1, unum = 1, pre = BIN}, 4)
test_vim_str2nr('-0B101', flags, {len = 5, num = -2, unum = 2, pre = BIN}, 5)
test_vim_str2nr('-0B101', flags, {len = 6, num = -5, unum = 5, pre = BIN}, 6)
test_vim_str2nr('-0B101', flags, {len = 6, num = -5, unum = 5, pre = BIN}, 7)
test_vim_str2nr('-0B101', flags, { len = 6, num = -5, unum = 5, pre = BIN }, 0)
test_vim_str2nr('-0B101', flags, { len = 1, num = 0, unum = 0, pre = 0 }, 1)
test_vim_str2nr('-0B101', flags, { len = 2, num = 0, unum = 0, pre = 0 }, 2)
test_vim_str2nr('-0B101', flags, { len = 0 }, 3)
test_vim_str2nr('-0B101', flags, { len = 2, num = 0, unum = 0, pre = 0 }, 3, false)
test_vim_str2nr('-0B101', flags, { len = 4, num = -1, unum = 1, pre = BIN }, 4)
test_vim_str2nr('-0B101', flags, { len = 5, num = -2, unum = 2, pre = BIN }, 5)
test_vim_str2nr('-0B101', flags, { len = 6, num = -5, unum = 5, pre = BIN }, 6)
test_vim_str2nr('-0B101', flags, { len = 6, num = -5, unum = 5, pre = BIN }, 7)
test_vim_str2nr('-0B1012', flags, {len = 0}, 0)
test_vim_str2nr('-0B1012', flags, {len = 0}, 7)
test_vim_str2nr('-0B1012', flags, {len = 6, num = -5, unum = 5, pre = BIN}, 0, false)
test_vim_str2nr('-0B1012', flags, {len = 6, num = -5, unum = 5, pre = BIN}, 7, false)
test_vim_str2nr('-0B1012', flags, { len = 0 }, 0)
test_vim_str2nr('-0B1012', flags, { len = 0 }, 7)
test_vim_str2nr('-0B1012', flags, { len = 6, num = -5, unum = 5, pre = BIN }, 0, false)
test_vim_str2nr('-0B1012', flags, { len = 6, num = -5, unum = 5, pre = BIN }, 7, false)
if flags > lib.STR2NR_FORCE then
test_vim_str2nr('-101', flags, {len = 4, num = -5, unum = 5, pre = 0}, 0)
test_vim_str2nr('-101', flags, { len = 4, num = -5, unum = 5, pre = 0 }, 0)
end
end
end)
@ -236,42 +276,42 @@ describe('vim_str2nr()', function()
end
-- Check that all digits are recognized
test_vim_str2nr( '012345670', flags, {len = 9, num = 2739128, unum = 2739128, pre = oct}, 0)
test_vim_str2nr('012345670', flags, { len = 9, num = 2739128, unum = 2739128, pre = oct }, 0)
test_vim_str2nr( '054', flags, {len = 3, num = 44, unum = 44, pre = oct}, 0)
test_vim_str2nr( '054', flags, {len = 1, num = 0, unum = 0, pre = 0 }, 1)
test_vim_str2nr( '054', flags, {len = 2, num = 5, unum = 5, pre = oct}, 2)
test_vim_str2nr( '054', flags, {len = 3, num = 44, unum = 44, pre = oct}, 3)
test_vim_str2nr( '0548', flags, {len = 3, num = 44, unum = 44, pre = oct}, 3)
test_vim_str2nr( '054', flags, {len = 3, num = 44, unum = 44, pre = oct}, 4)
test_vim_str2nr('054', flags, { len = 3, num = 44, unum = 44, pre = oct }, 0)
test_vim_str2nr('054', flags, { len = 1, num = 0, unum = 0, pre = 0 }, 1)
test_vim_str2nr('054', flags, { len = 2, num = 5, unum = 5, pre = oct }, 2)
test_vim_str2nr('054', flags, { len = 3, num = 44, unum = 44, pre = oct }, 3)
test_vim_str2nr('0548', flags, { len = 3, num = 44, unum = 44, pre = oct }, 3)
test_vim_str2nr('054', flags, { len = 3, num = 44, unum = 44, pre = oct }, 4)
test_vim_str2nr( '054x', flags, {len = 0}, 4)
test_vim_str2nr( '054x', flags, {len = 0}, 0)
test_vim_str2nr( '054x', flags, {len = 3, num = 44, unum = 44, pre = oct}, 4, false)
test_vim_str2nr( '054x', flags, {len = 3, num = 44, unum = 44, pre = oct}, 0, false)
test_vim_str2nr('054x', flags, { len = 0 }, 4)
test_vim_str2nr('054x', flags, { len = 0 }, 0)
test_vim_str2nr('054x', flags, { len = 3, num = 44, unum = 44, pre = oct }, 4, false)
test_vim_str2nr('054x', flags, { len = 3, num = 44, unum = 44, pre = oct }, 0, false)
test_vim_str2nr('-054', flags, {len = 4, num = -44, unum = 44, pre = oct}, 0)
test_vim_str2nr('-054', flags, {len = 1, num = 0, unum = 0, pre = 0 }, 1)
test_vim_str2nr('-054', flags, {len = 2, num = 0, unum = 0, pre = 0 }, 2)
test_vim_str2nr('-054', flags, {len = 3, num = -5, unum = 5, pre = oct}, 3)
test_vim_str2nr('-054', flags, {len = 4, num = -44, unum = 44, pre = oct}, 4)
test_vim_str2nr('-0548', flags, {len = 4, num = -44, unum = 44, pre = oct}, 4)
test_vim_str2nr('-054', flags, {len = 4, num = -44, unum = 44, pre = oct}, 5)
test_vim_str2nr('-054', flags, { len = 4, num = -44, unum = 44, pre = oct }, 0)
test_vim_str2nr('-054', flags, { len = 1, num = 0, unum = 0, pre = 0 }, 1)
test_vim_str2nr('-054', flags, { len = 2, num = 0, unum = 0, pre = 0 }, 2)
test_vim_str2nr('-054', flags, { len = 3, num = -5, unum = 5, pre = oct }, 3)
test_vim_str2nr('-054', flags, { len = 4, num = -44, unum = 44, pre = oct }, 4)
test_vim_str2nr('-0548', flags, { len = 4, num = -44, unum = 44, pre = oct }, 4)
test_vim_str2nr('-054', flags, { len = 4, num = -44, unum = 44, pre = oct }, 5)
test_vim_str2nr('-054x', flags, {len = 0}, 5)
test_vim_str2nr('-054x', flags, {len = 0}, 0)
test_vim_str2nr('-054x', flags, {len = 4, num = -44, unum = 44, pre = oct}, 5, false)
test_vim_str2nr('-054x', flags, {len = 4, num = -44, unum = 44, pre = oct}, 0, false)
test_vim_str2nr('-054x', flags, { len = 0 }, 5)
test_vim_str2nr('-054x', flags, { len = 0 }, 0)
test_vim_str2nr('-054x', flags, { len = 4, num = -44, unum = 44, pre = oct }, 5, false)
test_vim_str2nr('-054x', flags, { len = 4, num = -44, unum = 44, pre = oct }, 0, false)
if flags > lib.STR2NR_FORCE then
test_vim_str2nr('-54', flags, {len = 3, num = -44, unum = 44, pre = 0}, 0)
test_vim_str2nr('-0548', flags, {len = 0}, 5)
test_vim_str2nr('-0548', flags, {len = 0}, 0)
test_vim_str2nr('-0548', flags, {len = 4, num = -44, unum = 44, pre = 0}, 5, false)
test_vim_str2nr('-0548', flags, {len = 4, num = -44, unum = 44, pre = 0}, 0, false)
test_vim_str2nr('-54', flags, { len = 3, num = -44, unum = 44, pre = 0 }, 0)
test_vim_str2nr('-0548', flags, { len = 0 }, 5)
test_vim_str2nr('-0548', flags, { len = 0 }, 0)
test_vim_str2nr('-0548', flags, { len = 4, num = -44, unum = 44, pre = 0 }, 5, false)
test_vim_str2nr('-0548', flags, { len = 4, num = -44, unum = 44, pre = 0 }, 0, false)
else
test_vim_str2nr('-0548', flags, {len = 5, num = -548, unum = 548, pre = 0}, 5)
test_vim_str2nr('-0548', flags, {len = 5, num = -548, unum = 548, pre = 0}, 0)
test_vim_str2nr('-0548', flags, { len = 5, num = -548, unum = 548, pre = 0 }, 5)
test_vim_str2nr('-0548', flags, { len = 5, num = -548, unum = 548, pre = 0 }, 0)
end
end
end)
@ -298,73 +338,73 @@ describe('vim_str2nr()', function()
OCT = ('O'):byte()
end
test_vim_str2nr( '0o054', flags, {len = 5, num = 44, unum = 44, pre = oct}, 0)
test_vim_str2nr( '0o054', flags, {len = 1, num = 0, unum = 0, pre = 0 }, 1)
test_vim_str2nr( '0o054', flags, {len = 0}, 2)
test_vim_str2nr( '0o054', flags, {len = 3, num = 0, unum = 0, pre = oct}, 3)
test_vim_str2nr( '0o054', flags, {len = 4, num = 5, unum = 5, pre = oct}, 4)
test_vim_str2nr( '0o054', flags, {len = 5, num = 44, unum = 44, pre = oct}, 5)
test_vim_str2nr( '0o0548', flags, {len = 5, num = 44, unum = 44, pre = oct}, 5)
test_vim_str2nr( '0o054', flags, {len = 5, num = 44, unum = 44, pre = oct}, 6)
test_vim_str2nr('0o054', flags, { len = 5, num = 44, unum = 44, pre = oct }, 0)
test_vim_str2nr('0o054', flags, { len = 1, num = 0, unum = 0, pre = 0 }, 1)
test_vim_str2nr('0o054', flags, { len = 0 }, 2)
test_vim_str2nr('0o054', flags, { len = 3, num = 0, unum = 0, pre = oct }, 3)
test_vim_str2nr('0o054', flags, { len = 4, num = 5, unum = 5, pre = oct }, 4)
test_vim_str2nr('0o054', flags, { len = 5, num = 44, unum = 44, pre = oct }, 5)
test_vim_str2nr('0o0548', flags, { len = 5, num = 44, unum = 44, pre = oct }, 5)
test_vim_str2nr('0o054', flags, { len = 5, num = 44, unum = 44, pre = oct }, 6)
test_vim_str2nr( '0o054x', flags, {len = 0}, 6)
test_vim_str2nr( '0o054x', flags, {len = 0}, 0)
test_vim_str2nr( '0o054x', flags, {len = 5, num = 44, unum = 44, pre = oct}, 6, false)
test_vim_str2nr( '0o054x', flags, {len = 5, num = 44, unum = 44, pre = oct}, 0, false)
test_vim_str2nr('0o054x', flags, { len = 0 }, 6)
test_vim_str2nr('0o054x', flags, { len = 0 }, 0)
test_vim_str2nr('0o054x', flags, { len = 5, num = 44, unum = 44, pre = oct }, 6, false)
test_vim_str2nr('0o054x', flags, { len = 5, num = 44, unum = 44, pre = oct }, 0, false)
test_vim_str2nr('-0o054', flags, {len = 6, num = -44, unum = 44, pre = oct}, 0)
test_vim_str2nr('-0o054', flags, {len = 1, num = 0, unum = 0, pre = 0 }, 1)
test_vim_str2nr('-0o054', flags, {len = 2, num = 0, unum = 0, pre = 0 }, 2)
test_vim_str2nr('-0o054', flags, {len = 0}, 3)
test_vim_str2nr('-0o054', flags, {len = 4, num = 0, unum = 0, pre = oct}, 4)
test_vim_str2nr('-0o054', flags, {len = 5, num = -5, unum = 5, pre = oct}, 5)
test_vim_str2nr('-0o054', flags, {len = 6, num = -44, unum = 44, pre = oct}, 6)
test_vim_str2nr('-0o0548', flags, {len = 6, num = -44, unum = 44, pre = oct}, 6)
test_vim_str2nr('-0o054', flags, {len = 6, num = -44, unum = 44, pre = oct}, 7)
test_vim_str2nr('-0o054', flags, { len = 6, num = -44, unum = 44, pre = oct }, 0)
test_vim_str2nr('-0o054', flags, { len = 1, num = 0, unum = 0, pre = 0 }, 1)
test_vim_str2nr('-0o054', flags, { len = 2, num = 0, unum = 0, pre = 0 }, 2)
test_vim_str2nr('-0o054', flags, { len = 0 }, 3)
test_vim_str2nr('-0o054', flags, { len = 4, num = 0, unum = 0, pre = oct }, 4)
test_vim_str2nr('-0o054', flags, { len = 5, num = -5, unum = 5, pre = oct }, 5)
test_vim_str2nr('-0o054', flags, { len = 6, num = -44, unum = 44, pre = oct }, 6)
test_vim_str2nr('-0o0548', flags, { len = 6, num = -44, unum = 44, pre = oct }, 6)
test_vim_str2nr('-0o054', flags, { len = 6, num = -44, unum = 44, pre = oct }, 7)
test_vim_str2nr('-0o054x', flags, {len = 0}, 7)
test_vim_str2nr('-0o054x', flags, {len = 0}, 0)
test_vim_str2nr('-0o054x', flags, {len = 6, num = -44, unum = 44, pre = oct}, 7, false)
test_vim_str2nr('-0o054x', flags, {len = 6, num = -44, unum = 44, pre = oct}, 0, false)
test_vim_str2nr('-0o054x', flags, { len = 0 }, 7)
test_vim_str2nr('-0o054x', flags, { len = 0 }, 0)
test_vim_str2nr('-0o054x', flags, { len = 6, num = -44, unum = 44, pre = oct }, 7, false)
test_vim_str2nr('-0o054x', flags, { len = 6, num = -44, unum = 44, pre = oct }, 0, false)
test_vim_str2nr( '0O054', flags, {len = 5, num = 44, unum = 44, pre = OCT}, 0)
test_vim_str2nr( '0O054', flags, {len = 1, num = 0, unum = 0, pre = 0 }, 1)
test_vim_str2nr( '0O054', flags, {len = 0}, 2)
test_vim_str2nr( '0O054', flags, {len = 3, num = 0, unum = 0, pre = OCT}, 3)
test_vim_str2nr( '0O054', flags, {len = 4, num = 5, unum = 5, pre = OCT}, 4)
test_vim_str2nr( '0O054', flags, {len = 5, num = 44, unum = 44, pre = OCT}, 5)
test_vim_str2nr( '0O0548', flags, {len = 5, num = 44, unum = 44, pre = OCT}, 5)
test_vim_str2nr( '0O054', flags, {len = 5, num = 44, unum = 44, pre = OCT}, 6)
test_vim_str2nr('0O054', flags, { len = 5, num = 44, unum = 44, pre = OCT }, 0)
test_vim_str2nr('0O054', flags, { len = 1, num = 0, unum = 0, pre = 0 }, 1)
test_vim_str2nr('0O054', flags, { len = 0 }, 2)
test_vim_str2nr('0O054', flags, { len = 3, num = 0, unum = 0, pre = OCT }, 3)
test_vim_str2nr('0O054', flags, { len = 4, num = 5, unum = 5, pre = OCT }, 4)
test_vim_str2nr('0O054', flags, { len = 5, num = 44, unum = 44, pre = OCT }, 5)
test_vim_str2nr('0O0548', flags, { len = 5, num = 44, unum = 44, pre = OCT }, 5)
test_vim_str2nr('0O054', flags, { len = 5, num = 44, unum = 44, pre = OCT }, 6)
test_vim_str2nr( '0O054x', flags, {len = 0}, 6)
test_vim_str2nr( '0O054x', flags, {len = 0}, 0)
test_vim_str2nr( '0O054x', flags, {len = 5, num = 44, unum = 44, pre = OCT}, 6, false)
test_vim_str2nr( '0O054x', flags, {len = 5, num = 44, unum = 44, pre = OCT}, 0, false)
test_vim_str2nr('0O054x', flags, { len = 0 }, 6)
test_vim_str2nr('0O054x', flags, { len = 0 }, 0)
test_vim_str2nr('0O054x', flags, { len = 5, num = 44, unum = 44, pre = OCT }, 6, false)
test_vim_str2nr('0O054x', flags, { len = 5, num = 44, unum = 44, pre = OCT }, 0, false)
test_vim_str2nr('-0O054', flags, {len = 6, num = -44, unum = 44, pre = OCT}, 0)
test_vim_str2nr('-0O054', flags, {len = 1, num = 0, unum = 0, pre = 0 }, 1)
test_vim_str2nr('-0O054', flags, {len = 2, num = 0, unum = 0, pre = 0 }, 2)
test_vim_str2nr('-0O054', flags, {len = 0}, 3)
test_vim_str2nr('-0O054', flags, {len = 4, num = 0, unum = 0, pre = OCT}, 4)
test_vim_str2nr('-0O054', flags, {len = 5, num = -5, unum = 5, pre = OCT}, 5)
test_vim_str2nr('-0O054', flags, {len = 6, num = -44, unum = 44, pre = OCT}, 6)
test_vim_str2nr('-0O0548', flags, {len = 6, num = -44, unum = 44, pre = OCT}, 6)
test_vim_str2nr('-0O054', flags, {len = 6, num = -44, unum = 44, pre = OCT}, 7)
test_vim_str2nr('-0O054', flags, { len = 6, num = -44, unum = 44, pre = OCT }, 0)
test_vim_str2nr('-0O054', flags, { len = 1, num = 0, unum = 0, pre = 0 }, 1)
test_vim_str2nr('-0O054', flags, { len = 2, num = 0, unum = 0, pre = 0 }, 2)
test_vim_str2nr('-0O054', flags, { len = 0 }, 3)
test_vim_str2nr('-0O054', flags, { len = 4, num = 0, unum = 0, pre = OCT }, 4)
test_vim_str2nr('-0O054', flags, { len = 5, num = -5, unum = 5, pre = OCT }, 5)
test_vim_str2nr('-0O054', flags, { len = 6, num = -44, unum = 44, pre = OCT }, 6)
test_vim_str2nr('-0O0548', flags, { len = 6, num = -44, unum = 44, pre = OCT }, 6)
test_vim_str2nr('-0O054', flags, { len = 6, num = -44, unum = 44, pre = OCT }, 7)
test_vim_str2nr('-0O054x', flags, {len = 0}, 7)
test_vim_str2nr('-0O054x', flags, {len = 0}, 0)
test_vim_str2nr('-0O054x', flags, {len = 6, num = -44, unum = 44, pre = OCT}, 7, false)
test_vim_str2nr('-0O054x', flags, {len = 6, num = -44, unum = 44, pre = OCT}, 0, false)
test_vim_str2nr('-0O054x', flags, { len = 0 }, 7)
test_vim_str2nr('-0O054x', flags, { len = 0 }, 0)
test_vim_str2nr('-0O054x', flags, { len = 6, num = -44, unum = 44, pre = OCT }, 7, false)
test_vim_str2nr('-0O054x', flags, { len = 6, num = -44, unum = 44, pre = OCT }, 0, false)
if flags > lib.STR2NR_FORCE then
test_vim_str2nr('-0548', flags, {len = 0}, 5)
test_vim_str2nr('-0548', flags, {len = 0}, 0)
test_vim_str2nr('-0548', flags, {len = 4, num = -44, unum = 44, pre = 0}, 5, false)
test_vim_str2nr('-0548', flags, {len = 4, num = -44, unum = 44, pre = 0}, 0, false)
test_vim_str2nr('-055', flags, {len = 4, num = -45, unum = 45, pre = 0}, 0)
test_vim_str2nr('-0548', flags, { len = 0 }, 5)
test_vim_str2nr('-0548', flags, { len = 0 }, 0)
test_vim_str2nr('-0548', flags, { len = 4, num = -44, unum = 44, pre = 0 }, 5, false)
test_vim_str2nr('-0548', flags, { len = 4, num = -44, unum = 44, pre = 0 }, 0, false)
test_vim_str2nr('-055', flags, { len = 4, num = -45, unum = 45, pre = 0 }, 0)
else
test_vim_str2nr('-0548', flags, {len = 5, num = -548, unum = 548, pre = 0}, 5)
test_vim_str2nr('-0548', flags, {len = 5, num = -548, unum = 548, pre = 0}, 0)
test_vim_str2nr('-0548', flags, { len = 5, num = -548, unum = 548, pre = 0 }, 5)
test_vim_str2nr('-0548', flags, { len = 5, num = -548, unum = 548, pre = 0 }, 0)
end
end
end)
@ -387,92 +427,92 @@ describe('vim_str2nr()', function()
end
-- Check that all digits are recognized
test_vim_str2nr('0x12345', flags, {len = 7, num = 74565, unum = 74565, pre = hex}, 0)
test_vim_str2nr('0x67890', flags, {len = 7, num = 424080, unum = 424080, pre = hex}, 0)
test_vim_str2nr('0xABCDEF', flags, {len = 8, num = 11259375, unum = 11259375, pre = hex}, 0)
test_vim_str2nr('0xabcdef', flags, {len = 8, num = 11259375, unum = 11259375, pre = hex}, 0)
test_vim_str2nr('0x12345', flags, { len = 7, num = 74565, unum = 74565, pre = hex }, 0)
test_vim_str2nr('0x67890', flags, { len = 7, num = 424080, unum = 424080, pre = hex }, 0)
test_vim_str2nr('0xABCDEF', flags, { len = 8, num = 11259375, unum = 11259375, pre = hex }, 0)
test_vim_str2nr('0xabcdef', flags, { len = 8, num = 11259375, unum = 11259375, pre = hex }, 0)
test_vim_str2nr( '0x101', flags, {len = 5, num = 257, unum =257, pre = hex}, 0)
test_vim_str2nr( '0x101', flags, {len = 1, num = 0, unum = 0, pre = 0 }, 1)
test_vim_str2nr( '0x101', flags, {len = 0}, 2)
test_vim_str2nr( '0x101', flags, {len = 1, num = 0, unum = 0, pre = 0 }, 2, false)
test_vim_str2nr( '0x101', flags, {len = 3, num = 1, unum = 1, pre = hex}, 3)
test_vim_str2nr( '0x101', flags, {len = 4, num = 16, unum = 16, pre = hex}, 4)
test_vim_str2nr( '0x101', flags, {len = 5, num = 257, unum =257, pre = hex}, 5)
test_vim_str2nr( '0x101', flags, {len = 5, num = 257, unum =257, pre = hex}, 6)
test_vim_str2nr('0x101', flags, { len = 5, num = 257, unum = 257, pre = hex }, 0)
test_vim_str2nr('0x101', flags, { len = 1, num = 0, unum = 0, pre = 0 }, 1)
test_vim_str2nr('0x101', flags, { len = 0 }, 2)
test_vim_str2nr('0x101', flags, { len = 1, num = 0, unum = 0, pre = 0 }, 2, false)
test_vim_str2nr('0x101', flags, { len = 3, num = 1, unum = 1, pre = hex }, 3)
test_vim_str2nr('0x101', flags, { len = 4, num = 16, unum = 16, pre = hex }, 4)
test_vim_str2nr('0x101', flags, { len = 5, num = 257, unum = 257, pre = hex }, 5)
test_vim_str2nr('0x101', flags, { len = 5, num = 257, unum = 257, pre = hex }, 6)
test_vim_str2nr( '0x101G', flags, {len = 0}, 0)
test_vim_str2nr( '0x101G', flags, {len = 0}, 6)
test_vim_str2nr( '0x101G', flags, {len = 5, num = 257, unum =257, pre = hex}, 0, false)
test_vim_str2nr( '0x101G', flags, {len = 5, num = 257, unum =257, pre = hex}, 6, false)
test_vim_str2nr('0x101G', flags, { len = 0 }, 0)
test_vim_str2nr('0x101G', flags, { len = 0 }, 6)
test_vim_str2nr('0x101G', flags, { len = 5, num = 257, unum = 257, pre = hex }, 0, false)
test_vim_str2nr('0x101G', flags, { len = 5, num = 257, unum = 257, pre = hex }, 6, false)
test_vim_str2nr('-0x101', flags, {len = 6, num =-257, unum =257, pre = hex}, 0)
test_vim_str2nr('-0x101', flags, {len = 1, num = 0, unum = 0, pre = 0 }, 1)
test_vim_str2nr('-0x101', flags, {len = 2, num = 0, unum = 0, pre = 0 }, 2)
test_vim_str2nr('-0x101', flags, {len = 0}, 3)
test_vim_str2nr('-0x101', flags, {len = 2, num = 0, unum = 0, pre = 0 }, 3, false)
test_vim_str2nr('-0x101', flags, {len = 4, num = -1, unum = 1, pre = hex}, 4)
test_vim_str2nr('-0x101', flags, {len = 5, num = -16, unum = 16, pre = hex}, 5)
test_vim_str2nr('-0x101', flags, {len = 6, num =-257, unum =257, pre = hex}, 6)
test_vim_str2nr('-0x101', flags, {len = 6, num =-257, unum =257, pre = hex}, 7)
test_vim_str2nr('-0x101', flags, { len = 6, num = -257, unum = 257, pre = hex }, 0)
test_vim_str2nr('-0x101', flags, { len = 1, num = 0, unum = 0, pre = 0 }, 1)
test_vim_str2nr('-0x101', flags, { len = 2, num = 0, unum = 0, pre = 0 }, 2)
test_vim_str2nr('-0x101', flags, { len = 0 }, 3)
test_vim_str2nr('-0x101', flags, { len = 2, num = 0, unum = 0, pre = 0 }, 3, false)
test_vim_str2nr('-0x101', flags, { len = 4, num = -1, unum = 1, pre = hex }, 4)
test_vim_str2nr('-0x101', flags, { len = 5, num = -16, unum = 16, pre = hex }, 5)
test_vim_str2nr('-0x101', flags, { len = 6, num = -257, unum = 257, pre = hex }, 6)
test_vim_str2nr('-0x101', flags, { len = 6, num = -257, unum = 257, pre = hex }, 7)
test_vim_str2nr('-0x101G', flags, {len = 0}, 0)
test_vim_str2nr('-0x101G', flags, {len = 0}, 7)
test_vim_str2nr('-0x101G', flags, {len = 6, num =-257, unum =257, pre = hex}, 0, false)
test_vim_str2nr('-0x101G', flags, {len = 6, num =-257, unum =257, pre = hex}, 7, false)
test_vim_str2nr('-0x101G', flags, { len = 0 }, 0)
test_vim_str2nr('-0x101G', flags, { len = 0 }, 7)
test_vim_str2nr('-0x101G', flags, { len = 6, num = -257, unum = 257, pre = hex }, 0, false)
test_vim_str2nr('-0x101G', flags, { len = 6, num = -257, unum = 257, pre = hex }, 7, false)
test_vim_str2nr( '0X101', flags, {len = 5, num = 257, unum =257, pre = HEX}, 0)
test_vim_str2nr( '0X101', flags, {len = 1, num = 0, unum = 0, pre = 0 }, 1)
test_vim_str2nr( '0X101', flags, {len = 0}, 2)
test_vim_str2nr( '0X101', flags, {len = 1, num = 0, unum = 0, pre = 0 }, 2, false)
test_vim_str2nr( '0X101', flags, {len = 3, num = 1, unum = 1, pre = HEX}, 3)
test_vim_str2nr( '0X101', flags, {len = 4, num = 16, unum = 16, pre = HEX}, 4)
test_vim_str2nr( '0X101', flags, {len = 5, num = 257, unum =257, pre = HEX}, 5)
test_vim_str2nr( '0X101', flags, {len = 5, num = 257, unum =257, pre = HEX}, 6)
test_vim_str2nr('0X101', flags, { len = 5, num = 257, unum = 257, pre = HEX }, 0)
test_vim_str2nr('0X101', flags, { len = 1, num = 0, unum = 0, pre = 0 }, 1)
test_vim_str2nr('0X101', flags, { len = 0 }, 2)
test_vim_str2nr('0X101', flags, { len = 1, num = 0, unum = 0, pre = 0 }, 2, false)
test_vim_str2nr('0X101', flags, { len = 3, num = 1, unum = 1, pre = HEX }, 3)
test_vim_str2nr('0X101', flags, { len = 4, num = 16, unum = 16, pre = HEX }, 4)
test_vim_str2nr('0X101', flags, { len = 5, num = 257, unum = 257, pre = HEX }, 5)
test_vim_str2nr('0X101', flags, { len = 5, num = 257, unum = 257, pre = HEX }, 6)
test_vim_str2nr( '0X101G', flags, {len = 0}, 0)
test_vim_str2nr( '0X101G', flags, {len = 0}, 6)
test_vim_str2nr( '0X101G', flags, {len = 5, num = 257, unum =257, pre = HEX}, 0, false)
test_vim_str2nr( '0X101G', flags, {len = 5, num = 257, unum =257, pre = HEX}, 6, false)
test_vim_str2nr('0X101G', flags, { len = 0 }, 0)
test_vim_str2nr('0X101G', flags, { len = 0 }, 6)
test_vim_str2nr('0X101G', flags, { len = 5, num = 257, unum = 257, pre = HEX }, 0, false)
test_vim_str2nr('0X101G', flags, { len = 5, num = 257, unum = 257, pre = HEX }, 6, false)
test_vim_str2nr('-0X101', flags, {len = 6, num =-257, unum =257, pre = HEX}, 0)
test_vim_str2nr('-0X101', flags, {len = 1, num = 0, unum = 0, pre = 0 }, 1)
test_vim_str2nr('-0X101', flags, {len = 2, num = 0, unum = 0, pre = 0 }, 2)
test_vim_str2nr('-0X101', flags, {len = 0}, 3)
test_vim_str2nr('-0X101', flags, {len = 2, num = 0, unum = 0, pre = 0 }, 3, false)
test_vim_str2nr('-0X101', flags, {len = 4, num = -1, unum = 1, pre = HEX}, 4)
test_vim_str2nr('-0X101', flags, {len = 5, num = -16, unum = 16, pre = HEX}, 5)
test_vim_str2nr('-0X101', flags, {len = 6, num =-257, unum =257, pre = HEX}, 6)
test_vim_str2nr('-0X101', flags, {len = 6, num =-257, unum =257, pre = HEX}, 7)
test_vim_str2nr('-0X101', flags, { len = 6, num = -257, unum = 257, pre = HEX }, 0)
test_vim_str2nr('-0X101', flags, { len = 1, num = 0, unum = 0, pre = 0 }, 1)
test_vim_str2nr('-0X101', flags, { len = 2, num = 0, unum = 0, pre = 0 }, 2)
test_vim_str2nr('-0X101', flags, { len = 0 }, 3)
test_vim_str2nr('-0X101', flags, { len = 2, num = 0, unum = 0, pre = 0 }, 3, false)
test_vim_str2nr('-0X101', flags, { len = 4, num = -1, unum = 1, pre = HEX }, 4)
test_vim_str2nr('-0X101', flags, { len = 5, num = -16, unum = 16, pre = HEX }, 5)
test_vim_str2nr('-0X101', flags, { len = 6, num = -257, unum = 257, pre = HEX }, 6)
test_vim_str2nr('-0X101', flags, { len = 6, num = -257, unum = 257, pre = HEX }, 7)
test_vim_str2nr('-0X101G', flags, {len = 0}, 0)
test_vim_str2nr('-0X101G', flags, {len = 0}, 7)
test_vim_str2nr('-0X101G', flags, {len = 6, num =-257, unum =257, pre = HEX}, 0, false)
test_vim_str2nr('-0X101G', flags, {len = 6, num =-257, unum =257, pre = HEX}, 7, false)
test_vim_str2nr('-0X101G', flags, { len = 0 }, 0)
test_vim_str2nr('-0X101G', flags, { len = 0 }, 7)
test_vim_str2nr('-0X101G', flags, { len = 6, num = -257, unum = 257, pre = HEX }, 0, false)
test_vim_str2nr('-0X101G', flags, { len = 6, num = -257, unum = 257, pre = HEX }, 7, false)
if flags > lib.STR2NR_FORCE then
test_vim_str2nr('-101', flags, {len = 4, num = -257, unum = 257, pre = 0}, 0)
test_vim_str2nr('-101', flags, { len = 4, num = -257, unum = 257, pre = 0 }, 0)
end
end
end)
-- Test_str2nr() in test_functions.vim already tests normal usage
itp('works with weirdly quoted numbers', function()
local flags = lib.STR2NR_DEC + lib.STR2NR_QUOTE
test_vim_str2nr("'027", flags, {len = 0}, 0)
test_vim_str2nr("'027", flags, {len = 0}, 0, false)
test_vim_str2nr("1'2'3'4", flags, {len = 7, num = 1234, unum = 1234, pre = 0}, 0)
test_vim_str2nr("'027", flags, { len = 0 }, 0)
test_vim_str2nr("'027", flags, { len = 0 }, 0, false)
test_vim_str2nr("1'2'3'4", flags, { len = 7, num = 1234, unum = 1234, pre = 0 }, 0)
-- counter-intuitive, but like Vim, strict=true should partially accept
-- these: (' and - are not alphanumeric)
test_vim_str2nr("7''331", flags, {len = 1, num = 7, unum = 7, pre = 0}, 0)
test_vim_str2nr("123'x4", flags, {len = 3, num = 123, unum = 123, pre = 0}, 0)
test_vim_str2nr("1337'", flags, {len = 4, num = 1337, unum = 1337, pre = 0}, 0)
test_vim_str2nr("-'", flags, {len = 1, num = 0, unum = 0, pre = 0}, 0)
test_vim_str2nr("7''331", flags, { len = 1, num = 7, unum = 7, pre = 0 }, 0)
test_vim_str2nr("123'x4", flags, { len = 3, num = 123, unum = 123, pre = 0 }, 0)
test_vim_str2nr("1337'", flags, { len = 4, num = 1337, unum = 1337, pre = 0 }, 0)
test_vim_str2nr("-'", flags, { len = 1, num = 0, unum = 0, pre = 0 }, 0)
flags = lib.STR2NR_HEX + lib.STR2NR_QUOTE
local hex = ('x'):byte()
test_vim_str2nr("0x'abcd", flags, {len = 0}, 0)
test_vim_str2nr("0x'abcd", flags, {len = 1, num = 0, unum = 0, pre = 0}, 0, false)
test_vim_str2nr("0xab''cd", flags, {len = 4, num = 171, unum = 171, pre = hex}, 0)
test_vim_str2nr("0x'abcd", flags, { len = 0 }, 0)
test_vim_str2nr("0x'abcd", flags, { len = 1, num = 0, unum = 0, pre = 0 }, 0, false)
test_vim_str2nr("0xab''cd", flags, { len = 4, num = 171, unum = 171, pre = hex }, 0)
end)
end)

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)
@ -16,7 +20,7 @@ describe('json_decode_string()', function()
end
itp('does not overflow when running with `n…`, `t…`, `f…`', function()
local rettv = ffi.new('typval_T', {v_type=decode.VAR_UNKNOWN})
local rettv = ffi.new('typval_T', { v_type = decode.VAR_UNKNOWN })
decode.emsg_silent = 1
-- This will not crash, but if `len` argument will be ignored it will parse
-- `null` as `null` and if not it will parse `null` as `n`.
@ -43,7 +47,7 @@ describe('json_decode_string()', function()
end)
itp('does not overflow and crash when running with `n`, `t`, `f`', function()
local rettv = ffi.new('typval_T', {v_type=decode.VAR_UNKNOWN})
local rettv = ffi.new('typval_T', { v_type = decode.VAR_UNKNOWN })
decode.emsg_silent = 1
eq(0, decode.json_decode_string(char('n'), 1, rettv))
eq(decode.VAR_UNKNOWN, rettv.v_type)
@ -54,7 +58,7 @@ describe('json_decode_string()', function()
end)
itp('does not overflow when running with `"…`', function()
local rettv = ffi.new('typval_T', {v_type=decode.VAR_UNKNOWN})
local rettv = ffi.new('typval_T', { v_type = decode.VAR_UNKNOWN })
decode.emsg_silent = 1
eq(0, decode.json_decode_string('"t"', 2, rettv))
eq(decode.VAR_UNKNOWN, rettv.v_type)
@ -63,7 +67,7 @@ describe('json_decode_string()', function()
end)
local check_failure = function(s, len, msg)
local rettv = ffi.new('typval_T', {v_type=decode.VAR_UNKNOWN})
local rettv = ffi.new('typval_T', { v_type = decode.VAR_UNKNOWN })
eq(0, decode.json_decode_string(s, len, rettv))
eq(decode.VAR_UNKNOWN, rettv.v_type)
neq(nil, decode.last_msg_hist)
@ -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.')
@ -117,7 +124,7 @@ describe('json_decode_string()', function()
end)
itp('does not overflow and crash when running with `"`', function()
local rettv = ffi.new('typval_T', {v_type=decode.VAR_UNKNOWN})
local rettv = ffi.new('typval_T', { v_type = decode.VAR_UNKNOWN })
decode.emsg_silent = 1
eq(0, decode.json_decode_string(char('"'), 1, rettv))
eq(decode.VAR_UNKNOWN, rettv.v_type)

View File

@ -22,80 +22,83 @@ describe('encode_list_write()', function()
itp('writes empty string', function()
local l = list()
eq(0, encode_list_write(l, ''))
eq({[type_key]=list_type}, lst2tbl(l))
eq({ [type_key] = list_type }, lst2tbl(l))
end)
itp('writes ASCII string literal with printable characters', function()
local l = list()
eq(0, encode_list_write(l, 'abc'))
eq({'abc'}, lst2tbl(l))
eq({ 'abc' }, lst2tbl(l))
end)
itp('writes string starting with NL', function()
local l = list()
eq(0, encode_list_write(l, '\nabc'))
eq({null_string, 'abc'}, lst2tbl(l))
eq({ null_string, 'abc' }, lst2tbl(l))
end)
itp('writes string starting with NL twice', function()
local l = list()
eq(0, encode_list_write(l, '\nabc'))
eq({null_string, 'abc'}, lst2tbl(l))
eq({ null_string, 'abc' }, lst2tbl(l))
eq(0, encode_list_write(l, '\nabc'))
eq({null_string, 'abc', 'abc'}, lst2tbl(l))
eq({ null_string, 'abc', 'abc' }, lst2tbl(l))
end)
itp('writes string ending with NL', function()
local l = list()
eq(0, encode_list_write(l, 'abc\n'))
eq({'abc', null_string}, lst2tbl(l))
eq({ 'abc', null_string }, lst2tbl(l))
end)
itp('writes string ending with NL twice', function()
local l = list()
eq(0, encode_list_write(l, 'abc\n'))
eq({'abc', null_string}, lst2tbl(l))
eq({ 'abc', null_string }, lst2tbl(l))
eq(0, encode_list_write(l, 'abc\n'))
eq({'abc', 'abc', null_string}, lst2tbl(l))
eq({ 'abc', 'abc', null_string }, lst2tbl(l))
end)
itp('writes string starting, ending and containing NL twice', function()
local l = list()
eq(0, encode_list_write(l, '\na\nb\n'))
eq({null_string, 'a', 'b', null_string}, lst2tbl(l))
eq({ null_string, 'a', 'b', null_string }, lst2tbl(l))
eq(0, encode_list_write(l, '\na\nb\n'))
eq({null_string, 'a', 'b', null_string, 'a', 'b', null_string}, lst2tbl(l))
eq({ null_string, 'a', 'b', null_string, 'a', 'b', null_string }, lst2tbl(l))
end)
itp('writes string starting, ending and containing NUL with NL between twice', function()
local l = list()
eq(0, encode_list_write(l, '\0\n\0\n\0'))
eq({'\n', '\n', '\n'}, lst2tbl(l))
eq({ '\n', '\n', '\n' }, lst2tbl(l))
eq(0, encode_list_write(l, '\0\n\0\n\0'))
eq({'\n', '\n', '\n\n', '\n', '\n'}, lst2tbl(l))
eq({ '\n', '\n', '\n\n', '\n', '\n' }, lst2tbl(l))
end)
itp('writes string starting, ending and containing NL with NUL between twice', function()
local l = list()
eq(0, encode_list_write(l, '\n\0\n\0\n'))
eq({null_string, '\n', '\n', null_string}, lst2tbl(l))
eq({ null_string, '\n', '\n', null_string }, lst2tbl(l))
eq(0, encode_list_write(l, '\n\0\n\0\n'))
eq({null_string, '\n', '\n', null_string, '\n', '\n', null_string}, lst2tbl(l))
eq({ null_string, '\n', '\n', null_string, '\n', '\n', null_string }, lst2tbl(l))
end)
itp('writes string containing a single NL twice', function()
local l = list()
eq(0, encode_list_write(l, '\n'))
eq({null_string, null_string}, lst2tbl(l))
eq({ null_string, null_string }, lst2tbl(l))
eq(0, encode_list_write(l, '\n'))
eq({null_string, null_string, null_string}, lst2tbl(l))
eq({ null_string, null_string, null_string }, lst2tbl(l))
end)
itp('writes string containing a few NLs twice', function()
local l = list()
eq(0, encode_list_write(l, '\n\n\n'))
eq({null_string, null_string, null_string, null_string}, lst2tbl(l))
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,21 +6,25 @@ 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'}
local null_dict = {[true]='NULL dict'}
local type_key = {[true]='type key'}
local locks_key = {[true]='locks key'}
local list_type = {[true]='list type'}
local dict_type = {[true]='dict type'}
local func_type = {[true]='func type'}
local int_type = {[true]='int type'}
local flt_type = {[true]='flt type'}
local null_string = { [true] = 'NULL string' }
local null_list = { [true] = 'NULL list' }
local null_dict = { [true] = 'NULL dict' }
local type_key = { [true] = 'type key' }
local locks_key = { [true] = 'locks key' }
local list_type = { [true] = 'list type' }
local dict_type = { [true] = 'dict type' }
local func_type = { [true] = 'func type' }
local int_type = { [true] = 'int type' }
local flt_type = { [true] = 'flt type' }
local nil_value = {[true]='nil'}
local nil_value = { [true] = 'nil' }
local lua2typvalt
@ -35,11 +39,13 @@ 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
li.li_tv = {v_type=eval.VAR_UNKNOWN, v_lock=eval.VAR_UNLOCKED}
li.li_tv = { v_type = eval.VAR_UNKNOWN, v_lock = eval.VAR_UNLOCKED }
return li
end
@ -121,11 +127,11 @@ local function partial2lua(pt, processed)
end
end
return {
[type_key]=func_type,
value=value,
auto=auto,
args=argv,
dict=dict,
[type_key] = func_type,
value = value,
auto = auto,
args = argv,
dict = dict,
}
end
@ -148,7 +154,7 @@ local function typvalt2lua_tab_init()
})[tonumber(t.vval.v_special)]
end,
[tonumber(eval.VAR_NUMBER)] = function(t)
return {[type_key]=int_type, value=tonumber(t.vval.v_number)}
return { [type_key] = int_type, value = tonumber(t.vval.v_number) }
end,
[tonumber(eval.VAR_FLOAT)] = function(t)
return tonumber(t.vval.v_float)
@ -168,7 +174,7 @@ local function typvalt2lua_tab_init()
return dct2tbl(t.vval.v_dict, processed)
end,
[tonumber(eval.VAR_FUNC)] = function(t, processed)
return {[type_key]=func_type, value=typvalt2lua_tab[eval.VAR_STRING](t, processed or {})}
return { [type_key] = func_type, value = typvalt2lua_tab[eval.VAR_STRING](t, processed or {}) }
end,
[tonumber(eval.VAR_PARTIAL)] = function(t, processed)
local p_key = ptr2key(t)
@ -182,15 +188,17 @@ end
typvalt2lua = function(t, processed)
typvalt2lua_tab_init()
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 {}))
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
local function list_iter(l)
local init_s = {
idx=0,
li=l.lv_first,
idx = 0,
li = l.lv_first,
}
local function f(s, _)
-- (listitem_T *) NULL is equal to nil, but yet it is not false.
@ -222,7 +230,7 @@ lst2tbl = function(l, processed)
if processed[p_key] then
return processed[p_key]
end
local ret = {[type_key]=list_type}
local ret = { [type_key] = list_type }
processed[p_key] = ret
for i, li in list_iter(l) do
ret[i] = typvalt2lua(li.li_tv, processed)
@ -238,11 +246,13 @@ local hi_key_removed = nil
local function dict_iter(d, return_hi)
hi_key_removed = hi_key_removed or eval._hash_key_removed()
local init_s = {
todo=d.dv_hashtab.ht_used,
hi=d.dv_hashtab.ht_array,
todo = d.dv_hashtab.ht_used,
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
@ -269,7 +278,7 @@ local function first_di(d)
end
local function dict_items(d)
local ret = {[0]=0}
local ret = { [0] = 0 }
for k, hi in dict_iter(d) do
ret[k] = hi
ret[0] = ret[0] + 1
@ -301,12 +310,12 @@ local typvalt = function(typ, vval)
elseif type(typ) == 'string' then
typ = eval[typ]
end
return ffi.gc(ffi.new('typval_T', {v_type=typ, vval=vval}), eval.tv_clear)
return ffi.gc(ffi.new('typval_T', { v_type = typ, vval = vval }), eval.tv_clear)
end
local lua2typvalt_type_tab = {
[int_type] = function(l, _)
return typvalt(eval.VAR_NUMBER, {v_number=l.value})
return typvalt(eval.VAR_NUMBER, { v_number = l.value })
end,
[flt_type] = function(l, processed)
return lua2typvalt(l.value, processed)
@ -314,31 +323,34 @@ local lua2typvalt_type_tab = {
[list_type] = function(l, processed)
if processed[l] then
processed[l].lv_refcount = processed[l].lv_refcount + 1
return typvalt(eval.VAR_LIST, {v_list=processed[l]})
return typvalt(eval.VAR_LIST, { v_list = processed[l] })
end
local lst = populate_list(eval.tv_list_alloc(#l), l, processed)
return typvalt(eval.VAR_LIST, {v_list=lst})
return typvalt(eval.VAR_LIST, { v_list = lst })
end,
[dict_type] = function(l, processed)
if processed[l] then
processed[l].dv_refcount = processed[l].dv_refcount + 1
return typvalt(eval.VAR_DICT, {v_dict=processed[l]})
return typvalt(eval.VAR_DICT, { v_dict = processed[l] })
end
local dct = populate_dict(eval.tv_dict_alloc(), l, processed)
return typvalt(eval.VAR_DICT, {v_dict=dct})
return typvalt(eval.VAR_DICT, { v_dict = dct })
end,
[func_type] = function(l, processed)
if processed[l] then
processed[l].pt_refcount = processed[l].pt_refcount + 1
return typvalt(eval.VAR_PARTIAL, {v_partial=processed[l]})
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)
return typvalt(eval.VAR_PARTIAL, {v_partial=pt})
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,
@ -349,12 +361,12 @@ local special_vals = nil
lua2typvalt = function(l, processed)
if not special_vals then
special_vals = {
[null_string] = {'VAR_STRING', {v_string=ffi.cast('char*', nil)}},
[null_list] = {'VAR_LIST', {v_list=ffi.cast('list_T*', nil)}},
[null_dict] = {'VAR_DICT', {v_dict=ffi.cast('dict_T*', nil)}},
[nil_value] = {'VAR_SPECIAL', {v_special=eval.kSpecialVarNull}},
[true] = {'VAR_BOOL', {v_bool=eval.kBoolVarTrue}},
[false] = {'VAR_BOOL', {v_bool=eval.kBoolVarFalse}},
[null_string] = { 'VAR_STRING', { v_string = ffi.cast('char*', nil) } },
[null_list] = { 'VAR_LIST', { v_list = ffi.cast('list_T*', nil) } },
[null_dict] = { 'VAR_DICT', { v_dict = ffi.cast('dict_T*', nil) } },
[nil_value] = { 'VAR_SPECIAL', { v_special = eval.kSpecialVarNull } },
[true] = { 'VAR_BOOL', { v_bool = eval.kBoolVarTrue } },
[false] = { 'VAR_BOOL', { v_bool = eval.kBoolVarFalse } },
}
for k, v in pairs(special_vals) do
@ -382,9 +394,9 @@ lua2typvalt = function(l, processed)
end
end
elseif type(l) == 'number' then
return typvalt(eval.VAR_FLOAT, {v_float=l})
return typvalt(eval.VAR_FLOAT, { v_float = l })
elseif type(l) == 'string' then
return typvalt(eval.VAR_STRING, {v_string=eval.xmemdupz(to_cstr(l), #l)})
return typvalt(eval.VAR_STRING, { v_string = eval.xmemdupz(to_cstr(l), #l) })
elseif type(l) == 'cdata' then
local tv = typvalt(eval.VAR_UNKNOWN)
eval.tv_copy(l, tv)
@ -408,43 +420,64 @@ 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)
return {func='malloc', args={size + 1}, ret=void(s)}
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)}
return { func = 'malloc', args = { ffi.sizeof('typval_T') * argc }, ret = void(argv) }
end,
}
local function int(n)
return {[type_key]=int_type, value=n}
return { [type_key] = int_type, value = 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)}
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
return { type = 'pt', fref = ffi.string(lua_pt.value), pt = lua_pt }
end,
}
end
@ -473,15 +508,18 @@ end
local function tbl2callback(tbl)
local ret = nil
if tbl.type == 'none' then
ret = ffi.new('Callback[1]', {{type=eval.kCallbackNone}})
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,24 +533,23 @@ 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),
busy=qitem.busy,
cb = callback2tbl(qitem.callback),
pat = ffi.string(qitem.key_pattern, qitem.key_pattern_len),
busy = qitem.busy,
}
qs[#qs + 1] = qitem
key_patterns[#key_patterns + 1] = {qitem.key_pattern, qitem.key_pattern_len}
key_patterns[#key_patterns + 1] = { qitem.key_pattern, qitem.key_pattern_len }
q = q.next
end
return ret, qs, key_patterns
end
local function eval0(expr)
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})
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
else
@ -521,49 +558,49 @@ local function eval0(expr)
end
return {
int=int,
int = int,
null_string=null_string,
null_list=null_list,
null_dict=null_dict,
list_type=list_type,
dict_type=dict_type,
func_type=func_type,
int_type=int_type,
flt_type=flt_type,
null_string = null_string,
null_list = null_list,
null_dict = null_dict,
list_type = list_type,
dict_type = dict_type,
func_type = func_type,
int_type = int_type,
flt_type = flt_type,
nil_value=nil_value,
nil_value = nil_value,
type_key=type_key,
locks_key=locks_key,
type_key = type_key,
locks_key = locks_key,
list=list,
dict=dict,
lst2tbl=lst2tbl,
dct2tbl=dct2tbl,
list = list,
dict = dict,
lst2tbl = lst2tbl,
dct2tbl = dct2tbl,
lua2typvalt=lua2typvalt,
typvalt2lua=typvalt2lua,
lua2typvalt = lua2typvalt,
typvalt2lua = typvalt2lua,
typvalt=typvalt,
typvalt = typvalt,
li_alloc=li_alloc,
tv_list_item_free=tv_list_item_free,
li_alloc = li_alloc,
tv_list_item_free = tv_list_item_free,
dict_iter=dict_iter,
list_iter=list_iter,
first_di=first_di,
dict_iter = dict_iter,
list_iter = list_iter,
first_di = first_di,
alloc_logging_helpers=alloc_logging_helpers,
alloc_logging_helpers = alloc_logging_helpers,
list_items=list_items,
dict_items=dict_items,
list_items = list_items,
dict_items = dict_items,
dict_watchers=dict_watchers,
tbl2callback=tbl2callback,
callback2tbl=callback2tbl,
dict_watchers = dict_watchers,
tbl2callback = tbl2callback,
callback2tbl = callback2tbl,
eval0=eval0,
eval0 = eval0,
empty_list = {[type_key]=list_type},
empty_list = { [type_key] = list_type },
}

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()

View File

@ -28,8 +28,8 @@ end)
describe('tv_clear()', function()
itp('successfully frees all lists in [&l [1], *l, *l]', function()
local l_inner = {1}
local list = {l_inner, l_inner, l_inner}
local l_inner = { 1 }
local list = { l_inner, l_inner, l_inner }
local list_tv = ffi.gc(lua2typvalt(list), nil)
local list_p = list_tv.vval.v_list
local lis = list_items(list_p)
@ -55,8 +55,8 @@ describe('tv_clear()', function()
})
end)
itp('successfully frees all lists in [&l [], *l, *l]', function()
local l_inner = {[type_key]=list_type}
local list = {l_inner, l_inner, l_inner}
local l_inner = { [type_key] = list_type }
local list = { l_inner, l_inner, l_inner }
local list_tv = ffi.gc(lua2typvalt(list), nil)
local list_p = list_tv.vval.v_list
local lis = list_items(list_p)
@ -80,7 +80,7 @@ describe('tv_clear()', function()
end)
itp('successfully frees all dictionaries in [&d {}, *d]', function()
local d_inner = {}
local list = {d_inner, d_inner}
local list = { d_inner, d_inner }
local list_tv = ffi.gc(lua2typvalt(list), nil)
local list_p = list_tv.vval.v_list
local lis = list_items(list_p)
@ -101,8 +101,8 @@ describe('tv_clear()', function()
})
end)
itp('successfully frees all dictionaries in [&d {a: 1}, *d]', function()
local d_inner = {a=1}
local list = {d_inner, d_inner}
local d_inner = { a = 1 }
local list = { d_inner, d_inner }
local list_tv = ffi.gc(lua2typvalt(list), nil)
local list_p = list_tv.vval.v_list
local lis = list_items(list_p)

File diff suppressed because it is too large Load Diff

View File

@ -1,24 +1,23 @@
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'
local eq = helpers.eq
local ffi = helpers.ffi
local eq = helpers.eq
local ffi = helpers.ffi
local to_cstr = helpers.to_cstr
local NULL = helpers.NULL
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)
end
itp('returns ^path$ regex for literal path input', function()
eq( '^path$', file_pat_to_reg_pat('path'))
eq('^path$', file_pat_to_reg_pat('path'))
end)
itp('does not prepend ^ when there is a starting glob (*)', function()
@ -34,13 +33,15 @@ describe('file_pat functions', function()
end)
itp('replaces the bash any character (?) with the regex any character (.)', function()
eq('^foo.bar$', file_pat_to_reg_pat('foo?bar'))
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 (.*)',
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 (.*)',
function()
eq('^foo.*bar$', file_pat_to_reg_pat('foo*bar'))
end
)
itp([[unescapes \? to ?]], function()
eq('^foo?bar$', file_pat_to_reg_pat([[foo\?bar]]))

View File

@ -24,103 +24,145 @@ 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)
return tokens:match(str, 1, {line = 1, line_start = 1})
return tokens:match(str, 1, { line = 1, line_start = 1 })
end
local function set(t)
@ -131,11 +173,38 @@ local function set(t)
return s
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",
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',
}
-- 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
@ -216,8 +285,8 @@ local function formatc(str)
end
-- standalone operation (very handy for debugging)
local function standalone(...) -- luacheck: ignore
local Preprocess = require("preprocess")
local function standalone(...) -- luacheck: ignore
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')
@ -226,9 +295,9 @@ local function standalone(...) -- luacheck: ignore
local formatted
if #arg == 2 and arg[2] == 'no' then
formatted = raw
formatted = raw
else
formatted = formatc(raw)
formatted = formatc(raw)
end
print(formatted)

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
@ -47,7 +47,7 @@ local ga_size = function(garr)
return ga_len(garr) * ga_itemsize(garr)
end
local ga_maxsize = function(garr) -- luacheck: ignore
local ga_maxsize = function(garr) -- luacheck: ignore
return ga_maxlen(garr) * ga_itemsize(garr)
end
@ -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()
@ -199,9 +200,9 @@ describe('garray', function()
local function new_and_grow(itemsize_, growsize_, req)
local garr = new_garray()
ga_init(garr, itemsize_, growsize_)
eq(0, ga_size(garr)) -- should be 0 at first
eq(NULL, ga_data(garr)) -- should be NULL
ga_grow(garr, req) -- add space for `req` items
eq(0, ga_size(garr)) -- should be 0 at first
eq(NULL, ga_data(garr)) -- should be NULL
ga_grow(garr, req) -- add space for `req` items
return garr
end
@ -210,8 +211,8 @@ describe('garray', function()
growsize = 4
local grow_by = growsize - 1
local garr = new_and_grow(itemsize, growsize, grow_by)
neq(NULL, ga_data(garr)) -- data should be a ptr to memory
eq(growsize, ga_maxlen(garr)) -- we requested LESS than growsize, so...
neq(NULL, ga_data(garr)) -- data should be a ptr to memory
eq(growsize, ga_maxlen(garr)) -- we requested LESS than growsize, so...
end)
itp('grows by num items if num > growsize', function()
@ -219,8 +220,8 @@ describe('garray', function()
growsize = 4
local grow_by = growsize + 1
local garr = new_and_grow(itemsize, growsize, grow_by)
neq(NULL, ga_data(garr)) -- data should be a ptr to memory
eq(grow_by, ga_maxlen(garr)) -- we requested MORE than growsize, so...
neq(NULL, ga_data(garr)) -- data should be a ptr to memory
eq(grow_by, ga_maxlen(garr)) -- we requested MORE than growsize, so...
end)
itp('does not grow when nothing is requested', function()
@ -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)
@ -331,21 +332,21 @@ describe('garray', function()
describe('ga_concat_strings', function()
itp('returns an empty string when concatenating an empty array', function()
test_concat_fn({ }, ga_concat_strings)
test_concat_fn({}, ga_concat_strings)
end)
itp('can concatenate a non-empty array', function()
test_concat_fn({
'oh',
'my',
'neovim'
'neovim',
}, ga_concat_strings)
end)
end)
describe('ga_concat_strings_sep', function()
itp('returns an empty string when concatenating an empty array', function()
test_concat_fn({ }, ga_concat_strings_sep, '---')
test_concat_fn({}, ga_concat_strings_sep, '---')
end)
itp('can concatenate a non-empty array', function()
@ -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

@ -49,7 +49,7 @@ local function child_call(func, ret)
return function(...)
local child_calls = child_calls_mod or child_calls_init
if child_pid ~= 0 then
child_calls[#child_calls + 1] = {func=func, args={...}}
child_calls[#child_calls + 1] = { func = func, args = { ... } }
return ret
else
return func(...)
@ -62,7 +62,7 @@ end
--- @param func function
local function child_call_once(func, ...)
if child_pid ~= 0 then
child_calls_mod_once[#child_calls_mod_once + 1] = { func = func, args = {...} }
child_calls_mod_once[#child_calls_mod_once + 1] = { func = func, args = { ... } }
else
func(...)
end
@ -75,7 +75,7 @@ local child_cleanups_mod_once = nil --- @type ChildCall[]?
local function child_cleanup_once(func, ...)
local child_cleanups = child_cleanups_mod_once
if child_pid ~= 0 then
child_cleanups[#child_cleanups + 1] = {func=func, args={...}}
child_cleanups[#child_cleanups + 1] = { func = func, args = { ... } }
else
func(...)
end
@ -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
@ -184,9 +187,8 @@ local function cimport(...)
previous_defines = previous_defines_init
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
for _, path in ipairs({ ... }) do
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)
@ -277,13 +279,13 @@ end
local function alloc_log_new()
local log = {
log={}, --- @type ChildCallLog[]
lib=cimport('./src/nvim/memory.h'), --- @type table<string,function>
original_functions={}, --- @type table<string,function>
null={['\0:is_null']=true},
log = {}, --- @type ChildCallLog[]
lib = cimport('./src/nvim/memory.h'), --- @type table<string,function>
original_functions = {}, --- @type table<string,function>
null = { ['\0:is_null'] = true },
}
local allocator_functions = {'malloc', 'free', 'calloc', 'realloc'}
local allocator_functions = { 'malloc', 'free', 'calloc', 'realloc' }
function log:save_original_functions()
for _, funcname in ipairs(allocator_functions) do
@ -301,7 +303,7 @@ local function alloc_log_new()
local kk = k
self.lib['mem_' .. k] = function(...)
--- @type ChildCallLog
local log_entry = { func = kk, args = {...} }
local log_entry = { func = kk, args = { ... } }
self.log[#self.log + 1] = log_entry
if kk == 'free' then
self.original_functions[kk](...)
@ -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
@ -355,7 +359,7 @@ local function alloc_log_new()
end
end
table.sort(toremove)
for i = #toremove,1,-1 do
for i = #toremove, 1, -1 do
table.remove(self.log, toremove[i])
end
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()
@ -397,13 +399,12 @@ function sc.fork()
end
function sc.pipe()
local ret = ffi.new('int[2]', {-1, -1})
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]
@ -411,19 +412,16 @@ end
--- @return string
function sc.read(rd, len)
local ret = ffi.new('char[?]', len, {0})
local ret = ffi.new('char[?]', len, { 0 })
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
@ -464,7 +463,7 @@ sc.close = ffi.C.close
--- @return integer
function sc.wait(pid)
ffi.errno(0)
local stat_loc = ffi.new('int[1]', {0})
local stat_loc = ffi.new('int[1]', { 0 })
while true do
local r = ffi.C.waitpid(pid, stat_loc, ffi.C.kPOSIXWaitWUNTRACED)
if r == -1 then
@ -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)
@ -489,7 +487,7 @@ sc.exit = ffi.C._exit
local function format_list(lst)
local ret = {} --- @type string[]
for _, v in ipairs(lst) do
ret[#ret+1] = assert:format({v, n=1})[1]
ret[#ret + 1] = assert:format({ v, n = 1 })[1]
end
return table.concat(ret, ', ')
end
@ -498,9 +496,8 @@ if os.getenv('NVIM_TEST_PRINT_SYSCALLS') == '1' then
for k_, v_ in pairs(sc) do
(function(k, v)
sc[k] = function(...)
local rets = {v(...)}
io.stderr:write(('%s(%s) = %s\n'):format(k, format_list({...}),
format_list(rets)))
local rets = { v(...) }
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,
'assertion.just_fail.positive',
'assertion.just_fail.negative')
assert:register(
'assertion',
'just_fail',
just_fail,
'assertion.just_fail.positive',
'assertion.just_fail.negative'
)
local hook_fnamelen = 30
local hook_sfnamelen = 30
@ -561,7 +562,7 @@ local function child_sethook(wr)
local info = nil --- @type debuginfo?
if use_prev then
info = prev_info
elseif reason ~= 'tail return' then -- tail return
elseif reason ~= 'tail return' then -- tail return
info = debug.getinfo(2, 'nSl')
end
@ -609,17 +610,20 @@ local function child_sethook(wr)
-- assert(-1 <= lnum and lnum <= 99999)
local lnum_s = lnum == -1 and 'nknwn' or ('%u'):format(lnum)
--- @type string
local msg = ( -- lua does not support %*
local msg = ( -- lua does not support %*
''
.. msgchar
.. 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)
@ -742,16 +746,16 @@ local function itp_parent(rd, pid, allow_failure, location)
sc.close(rd)
if not ok then
if allow_failure then
io.stderr:write('Errorred out ('..status..'):\n' .. tostring(emsg) .. '\n')
io.stderr:write('Errorred out (' .. status .. '):\n' .. tostring(emsg) .. '\n')
os.execute([[
sh -c "source ci/common/test.sh
check_core_dumps --delete \"]] .. Paths.test_luajit_prg .. [[\""]])
else
error(tostring(emsg)..'\nexit code: '..status)
error(tostring(emsg) .. '\nexit code: ' .. status)
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)
@ -844,7 +849,7 @@ local function ptr2addr(ptr)
return tonumber(ffi.cast('intptr_t', ffi.cast('void *', ptr)))
end
local s = ffi.new('char[64]', {0})
local s = ffi.new('char[64]', { 0 })
local function ptr2key(ptr)
ffi.C.snprintf(s, ffi.sizeof(s), '%p', ffi.cast('void *', ptr))
@ -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 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,15 +1,14 @@
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 neq = helpers.neq
local ffi = helpers.ffi
local eq = helpers.eq
local neq = helpers.neq
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 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,17 +66,21 @@ 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 delta = {new_end[1] - old_end[1], new_end[2] - old_end[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
if pos_leq(pos, old_end) 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,18 +134,18 @@ 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
local gravitate = (i%2) > 0
for i = 1, 100 do
for j = 1, 100 do
local gravitate = (i % 2) > 0
local id = put(tree, j, i, gravitate)
ok(id > 0)
eq(nil, shadow[id])
shadow[id] = {j,i,gravitate}
shadow[id] = { j, i, gravitate }
end
-- checking every insert is too slow, but this is ok
lib.marktree_check(tree)
@ -133,7 +159,7 @@ describe('marktree', function()
eq({}, pos2id) -- not set if not requested
eq({}, id2pos)
for i,ipos in pairs(shadow) do
for i, ipos in pairs(shadow) do
local p = lib.marktree_lookup_ns(tree, ns, i, false, iter)
eq(ipos[1], p.pos.row)
eq(ipos[2], p.pos.col)
@ -145,7 +171,7 @@ describe('marktree', function()
-- local k2 = lib.marktree_itr_current(iter)
end
for i,ipos in pairs(shadow) do
for i, ipos in pairs(shadow) do
lib.marktree_itr_get(tree, ipos[1], ipos[2], iter)
local k = lib.marktree_itr_current(iter)
eq(i, tonumber(k.id))
@ -160,9 +186,9 @@ describe('marktree', function()
shadow[tonumber(del.id)] = nil
shadoworder(tree, shadow, iter)
for _, ci in ipairs({0,-1,1,-2,2,-10,10}) do
for i = 1,100 do
lib.marktree_itr_get(tree, i, 50+ci, iter)
for _, ci in ipairs({ 0, -1, 1, -2, 2, -10, 10 }) do
for i = 1, 100 do
lib.marktree_itr_get(tree, i, 50 + ci, iter)
local k = lib.marktree_itr_current(iter)
local id = tonumber(k.id)
eq(shadow[id][1], k.pos.row)
@ -177,14 +203,14 @@ describe('marktree', function()
-- NB: this is quite rudimentary. We rely on
-- functional tests exercising splicing quite a bit
lib.marktree_check(tree)
dosplice(tree, shadow, {2,2}, {0,5}, {1, 2})
dosplice(tree, shadow, { 2, 2 }, { 0, 5 }, { 1, 2 })
lib.marktree_check(tree)
shadoworder(tree, shadow, iter)
dosplice(tree, shadow, {30,2}, {30,5}, {1, 2})
dosplice(tree, shadow, { 30, 2 }, { 30, 5 }, { 1, 2 })
lib.marktree_check(tree)
shadoworder(tree, shadow, iter)
dosplice(tree, shadow, {5,3}, {0,2}, {0, 5})
dosplice(tree, shadow, { 5, 3 }, { 0, 2 }, { 0, 5 })
shadoworder(tree, shadow, iter)
lib.marktree_check(tree)
@ -209,7 +235,7 @@ describe('marktree', function()
-- Check iterator validity for 2 specific edge cases:
-- https://github.com/neovim/neovim/pull/14719
lib.marktree_clear(tree)
for i = 1,20 do
for i = 1, 20 do
put(tree, i, i, false)
end
@ -224,46 +250,60 @@ 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
return {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
return { wout, dout }
end
eq({{}, {}}, mov({}, {2, 3}, {2, 3}))
eq({{2, 3}, {}}, mov({}, {}, {2, 3}))
eq({{2, 3}, {}}, mov({2, 3}, {}, {}))
eq({{}, {2,3}}, mov({}, {2,3}, {}))
eq({ {}, {} }, mov({}, { 2, 3 }, { 2, 3 }))
eq({ { 2, 3 }, {} }, mov({}, {}, { 2, 3 }))
eq({ { 2, 3 }, {} }, mov({ 2, 3 }, {}, {}))
eq({ {}, { 2, 3 } }, mov({}, { 2, 3 }, {}))
eq({{1, 5}, {}}, mov({1,2,5}, {2, 3}, {3}))
eq({{1, 2}, {}}, mov({1,2,5}, {5, 10}, {10}))
eq({{1, 2}, {5}}, mov({1,2}, {5, 10}, {10}))
eq({{1,3,5,7,9}, {2,4,6,8,10}}, mov({1,3,5,7,9}, {2,4,6,8,10}, {}))
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({ { 1, 5 }, {} }, mov({ 1, 2, 5 }, { 2, 3 }, { 3 }))
eq({ { 1, 2 }, {} }, mov({ 1, 2, 5 }, { 5, 10 }, { 10 }))
eq({ { 1, 2 }, { 5 } }, mov({ 1, 2 }, { 5, 10 }, { 10 }))
eq({ { 1, 3, 5, 7, 9 }, { 2, 4, 6, 8, 10 } }, mov({ 1, 3, 5, 7, 9 }, { 2, 4, 6, 8, 10 }, {}))
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 })
)
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,28 +335,28 @@ 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 = {}
for i = 1,80 do
table.insert(ids, put(tree, 1, i, false, 2, 100-i, false))
for i = 1, 80 do
table.insert(ids, put(tree, 1, i, false, 2, 100 - i, false))
check_intersections(tree)
end
for i = 1,80 do
for i = 1, 80 do
lib.marktree_del_pair_test(tree, ns, ids[i])
check_intersections(tree)
end
ids = {}
for i = 1,80 do
table.insert(ids, put(tree, 1, i, false, 2, 100-i, false))
for i = 1, 80 do
table.insert(ids, put(tree, 1, i, false, 2, 100 - i, false))
check_intersections(tree)
end
for i = 1,10 do
for j = 1,8 do
local ival = (j-1)*10+i
for i = 1, 10 do
for j = 1, 8 do
local ival = (j - 1) * 10 + i
lib.marktree_del_pair_test(tree, ns, ids[ival])
check_intersections(tree)
end
@ -324,12 +364,12 @@ 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 = {}
for i = 1,1000 do
table.insert(ids, put(tree, 1, i, false, 2, 1000-i, false))
for i = 1, 1000 do
table.insert(ids, put(tree, 1, i, false, 2, 1000 - i, false))
if i % 10 == 1 then
check_intersections(tree)
end
@ -339,13 +379,13 @@ 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
for j = 1,50 do
for i = 1, 20 do
for j = 1, 50 do
k = k + 1
local ival = (j-1)*20+i
local ival = (j - 1) * 20 + i
if false == true then -- if there actually is a failure, this branch will fail out at the actual spot of the error
lib.marktree_lookup_ns(tree, ns, ids[ival], false, iter)
lib.marktree_del_itr(tree, iter, false)
@ -367,10 +407,10 @@ 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)
for i = 1, 1000 do
put(tree, 1, i, false, 2, 1000 - i, false)
if i % 10 == 1 then
check_intersections(tree)
end
@ -380,15 +420,15 @@ describe('marktree', function()
eq(2000, tree[0].n_keys)
ok(tree[0].root.level >= 2)
for _ = 1,10 do
for _ = 1, 10 do
lib.marktree_splice(tree, 0, 0, 0, 100, 0, 0)
check_intersections(tree)
end
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,31 +445,30 @@ 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 = {}
for i = 1,1000 do
table.insert(ids, put(tree, 1, i, false, 2, 1000-i, false))
for i = 1, 1000 do
table.insert(ids, put(tree, 1, i, false, 2, 1000 - i, false))
if i % 10 == 1 then
check_intersections(tree)
end
end
local iter = ffi.new("MarkTreeIter[1]")
for i = 1,1000 do
local which = i%2
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)
lib.marktree_move(tree, iter, 1+which, 500+i)
lib.marktree_move(tree, iter, 1 + which, 500 + i)
if i % 10 == 1 then
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 = {}
@ -441,21 +480,21 @@ describe('marktree', function()
at_row[i] = {}
end
local size = 1000*size_factor
local size = 1000 * size_factor
local k = 1
while k <= size do
for row1 = 1,9 do
for row2 = row1,10 do -- note row2 can be == row1, leads to empty ranges being tested when k > size/2
for row1 = 1, 9 do
for row2 = row1, 10 do -- note row2 can be == row1, leads to empty ranges being tested when k > size/2
if k > size then
break
end
local id = put(tree, row1, k, false, row2, size-k, false)
local id = put(tree, row1, k, false, row2, size - k, false)
table.insert(ids, id)
for i = row1+1, row2 do
for i = row1 + 1, row2 do
table.insert(at_row[i], id)
end
--if tree[0].root.level == 4 then error("kk"..k) end
if k % 100*size_factor == 1 or (k < 2000 and k%100 == 1) then
if k % 100 * size_factor == 1 or (k < 2000 and k % 100 == 1) then
check_intersections(tree)
end
k = k + 1
@ -463,13 +502,13 @@ describe('marktree', function()
end
end
eq(2*size, tree[0].n_keys)
eq(2 * size, tree[0].n_keys)
ok(tree[0].root.level >= 3)
check_intersections(tree)
local iter = ffi.new("MarkTreeIter[1]")
local pair = ffi.new("MTPair[1]")
for i = 1,10 do
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 = {}
eq(true, ffi.C.marktree_itr_get_overlap(tree, i, 0, iter))
@ -482,14 +521,14 @@ describe('marktree', function()
end
k = 0
for i = 1,100 do
for j = 1,(10*size_factor) do
for i = 1, 100 do
for j = 1, (10 * size_factor) do
k = k + 1
local ival = (j-1)*100+i
local ival = (j - 1) * 100 + i
lib.marktree_del_pair_test(tree, ns, ids[ival])
-- just a few stickprov, if there is trouble we need to check
-- everyone using the code in the "big tree" case above
if k % 100*size_factor == 0 or (k > 3000 and k % 200 == 0) then
if k % 100 * size_factor == 0 or (k > 3000 and k % 200 == 0) then
check_intersections(tree)
end
end
@ -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
@ -509,20 +548,20 @@ describe('marktree', function()
at_row[i] = {}
end
local size = 1000*size_factor
local size = 1000 * size_factor
local k = 1
while k <= size do
for row1 = 1,9 do
for row2 = row1,10 do -- note row2 can be == row1, leads to empty ranges being tested when k > size/2
for row1 = 1, 9 do
for row2 = row1, 10 do -- note row2 can be == row1, leads to empty ranges being tested when k > size/2
if k > size then
break
end
local id = put(tree, row1, k, false, row2, size-k, false)
for i = row1+1, row2 do
local id = put(tree, row1, k, false, row2, size - k, false)
for i = row1 + 1, row2 do
table.insert(at_row[i], id)
end
--if tree[0].root.level == 4 then error("kk"..k) end
if k % 100*size_factor == 1 or (k < 2000 and k%100 == 1) then
if k % 100 * size_factor == 1 or (k < 2000 and k % 100 == 1) then
check_intersections(tree)
end
k = k + 1
@ -530,11 +569,11 @@ describe('marktree', function()
end
end
eq(2*size, tree[0].n_keys)
eq(2 * size, tree[0].n_keys)
ok(tree[0].root.level >= 3)
check_intersections(tree)
for _ = 1,10 do
for _ = 1, 10 do
for j = 3, 8 do
lib.marktree_splice(tree, j, 0, 0, 200, 0, 0)
check_intersections(tree)

View File

@ -1,8 +1,8 @@
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 ffi = helpers.ffi
local eq = helpers.eq
local lib = helpers.cimport('./src/nvim/mbyte.h', './src/nvim/charset.h', './src/nvim/grid.h')
@ -16,13 +16,12 @@ 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.
for c = 0, 255 do
eq(c, lib.utf_ptr2char(to_string({c, 0})))
eq(c, lib.utf_ptr2char(to_string({ c, 0 })))
end
-- Some ill formed byte sequences that should not be recognized as UTF-8
@ -48,126 +47,160 @@ 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]}
return { ffi.string(buf), firstc[0] }
end
local function byte(val)
return {string.char(val), val}
return { string.char(val), val }
end
itp('1-byte sequences', function()
eq({'', 0}, test_seq{0})
eq({ '', 0 }, test_seq { 0 })
for c = 1, 127 do
eq(byte(c), test_seq{c})
eq(byte(c), test_seq { c })
end
for c = 128, 255 do
eq({'', c}, test_seq{c})
eq({ '', c }, test_seq { c })
end
end)
itp('2-byte sequences', function()
-- No combining characters
eq(byte(0x7f), test_seq{0x7f, 0x7f})
eq(byte(0x7f), test_seq { 0x7f, 0x7f })
-- No combining characters
eq(byte(0x7f), test_seq{0x7f, 0x80})
eq(byte(0x7f), test_seq { 0x7f, 0x80 })
-- No UTF-8 sequence
eq({'', 0xc2}, test_seq{0xc2, 0x7f})
eq({ '', 0xc2 }, test_seq { 0xc2, 0x7f })
-- One UTF-8 character
eq({'\xc2\x80', 0x80}, test_seq{0xc2, 0x80})
eq({ '\xc2\x80', 0x80 }, test_seq { 0xc2, 0x80 })
-- No UTF-8 sequence
eq({'', 0xc2}, test_seq{0xc2, 0xc0})
eq({ '', 0xc2 }, test_seq { 0xc2, 0xc0 })
end)
itp('3-byte sequences', function()
-- No second UTF-8 character
eq(byte(0x7f), test_seq{0x7f, 0x80, 0x80})
eq(byte(0x7f), test_seq { 0x7f, 0x80, 0x80 })
-- No combining character
eq(byte(0x7f), test_seq{0x7f, 0xc2, 0x80})
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})
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})
eq(byte(0x7f), test_seq { 0x7f, 0x7f, 0xcc, 0x80 })
-- No second UTF-8 character
eq(byte(0x7f), test_seq{0x7f, 0xc2, 0xcc, 0x80})
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})
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()
-- No following combining character
eq(byte(0x7f), test_seq{0x7f, 0x7f, 0xcc, 0x80, 0x80})
eq(byte(0x7f), test_seq { 0x7f, 0x7f, 0xcc, 0x80, 0x80 })
-- No second UTF-8 character
eq(byte(0x7f), test_seq{0x7f, 0xc2, 0xcc, 0x80, 0x80})
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})
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
@ -11,7 +11,7 @@ local cimp = cimport('stdlib.h', './src/nvim/memory.h')
describe('xstrlcat()', function()
local function test_xstrlcat(dst, src, dsize)
assert.is_true(dsize >= 1 + string.len(dst)) -- sanity check for tests
assert.is_true(dsize >= 1 + string.len(dst)) -- sanity check for tests
local dst_cstr = cstr(dsize, dst)
local src_cstr = to_cstr(src)
eq(string.len(dst .. src), cimp.xstrlcat(dst_cstr, src_cstr, dsize))
@ -19,34 +19,32 @@ describe('xstrlcat()', function()
end
local function test_xstrlcat_overlap(dst, src_idx, dsize)
assert.is_true(dsize >= 1 + string.len(dst)) -- sanity check for tests
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))
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))
return ffi.string(dst_cstr)
end
itp('concatenates strings', function()
eq('ab', test_xstrlcat('a', 'b', 3))
eq('ab', test_xstrlcat('a', 'b', 4096))
eq('ABCיהZdefgiיהZ', test_xstrlcat('ABCיהZ', 'defgiיהZ', 4096))
eq('b', test_xstrlcat('', 'b', 4096))
eq('a', test_xstrlcat('a', '', 4096))
eq('ABCיהZdefgiיהZ', test_xstrlcat('ABCיהZ', 'defgiיהZ', 4096))
eq('b', test_xstrlcat('', 'b', 4096))
eq('a', test_xstrlcat('a', '', 4096))
end)
itp('concatenates overlapping strings', function()
eq('abcabc', test_xstrlcat_overlap('abc', 0, 7))
eq('abca', test_xstrlcat_overlap('abc', 0, 5))
eq('abcb', test_xstrlcat_overlap('abc', 1, 5))
eq('abcc', test_xstrlcat_overlap('abc', 2, 10))
eq('abcabc', test_xstrlcat_overlap('abc', 0, 2343))
eq('abcabc', test_xstrlcat_overlap('abc', 0, 7))
eq('abca', test_xstrlcat_overlap('abc', 0, 5))
eq('abcb', test_xstrlcat_overlap('abc', 1, 5))
eq('abcc', test_xstrlcat_overlap('abc', 2, 10))
eq('abcabc', test_xstrlcat_overlap('abc', 0, 2343))
end)
itp('truncates if `dsize` is too small', function()
eq('a', test_xstrlcat('a', 'b', 2))
eq('', test_xstrlcat('', 'b', 1))
eq('ABCיהZd', test_xstrlcat('ABCיהZ', 'defgiיהZ', 10))
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
@ -34,8 +33,8 @@ describe('trunc_string', function()
{ ['desc'] = 'by copy', ['func'] = test_copy },
}
for _,t in ipairs(permutations) do
describe('populates buf '..t.desc, function()
for _, t in ipairs(permutations) do
describe('populates buf ' .. t.desc, function()
itp('with a small string', function()
t.func('text', 'text')
end)

View File

@ -35,32 +35,36 @@ end
describe('msgpack', function()
describe('unpacker', 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]
-- ]
-- ]]
local payload =
'\x93\x02\xa6\x72\x65\x64\x72\x61\x77\x91\x92\xa9\x67\x72\x69\x64\x5f\x6c\x69\x6e\x65\x95\x02\x00\x00\x91\x93\xa1\x20\x00\x4d\xc2'
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]
-- ]
-- ]]
local payload =
'\x93\x02\xa6\x72\x65\x64\x72\x61\x77\x91\x92\xa9\x67\x72\x69\x64\x5f\x6c\x69\x6e\x65\x95\x02\x00\x00\x91\x93\xa1\x20\x00\x4d\xc2'
local unpacker = make_unpacker()
lib.unpacker_init(unpacker)
local unpacker = make_unpacker()
lib.unpacker_init(unpacker)
unpacker_goto(unpacker, payload, payload:len() - 1)
local finished = unpacker_advance(unpacker)
eq(finished, false)
unpacker_goto(unpacker, payload, payload:len() - 1)
local finished = unpacker_advance(unpacker)
eq(finished, false)
unpacker[0].read_size = unpacker[0].read_size + 1
finished = unpacker_advance(unpacker)
eq(finished, true)
end)
unpacker[0].read_size = unpacker[0].read_size + 1
finished = unpacker_advance(unpacker)
eq(finished, true)
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 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'
@ -79,7 +79,7 @@ describe('env.c', function()
itp('appends :/foo/bar to $PATH', function()
local original_path = os.getenv('PATH')
eq(true, cimp.os_setenv_append_path(to_cstr('/foo/bar/baz.exe')))
eq(original_path..':/foo/bar', os.getenv('PATH'))
eq(original_path .. ':/foo/bar', os.getenv('PATH'))
end)
itp('avoids redundant separator when appending to $PATH #7377', function()
@ -166,7 +166,7 @@ describe('env.c', function()
local test_value = 'NVIM_UNIT_TEST_GETENVNAME_AT_INDEX_1V'
os_setenv(test_name, test_value, 1)
local i = 0
local names = { }
local names = {}
local found_name = false
local name = cimp.os_getenvname_at_index(i)
while name ~= NULL do
@ -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)
@ -283,7 +284,7 @@ describe('env.c', function()
cimp.expand_env_esc(input, output, 5, false, true, NULL)
-- Make sure the first few characters are copied properly and that there is a
-- terminating null character
for i=0,3 do
for i = 0, 3 do
eq(input[i], output[i])
end
eq(0, output[4])
@ -304,7 +305,7 @@ describe('env.c', function()
-- terminating null character
-- expand_env_esc SHOULD NOT expand the variable if there is not enough space to
-- contain the result
for i=0,3 do
for i = 0, 3 do
eq(output[i], input[i])
end
eq(output[4], 0)

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)
@ -56,7 +56,7 @@ local function file_open(fname, flags, mode)
end
local function file_open_new(fname, flags, mode)
local ret1 = ffi.new('int[?]', 1, {0})
local ret1 = ffi.new('int[?]', 1, { 0 })
local ret2 = ffi.gc(m.file_open_new(ret1, fname, flags, mode), nil)
return ret1[0], ret2
end
@ -68,7 +68,7 @@ local function file_open_fd(fd, flags)
end
local function file_open_fd_new(fd, flags)
local ret1 = ffi.new('int[?]', 1, {0})
local ret1 = ffi.new('int[?]', 1, { 0 })
local ret2 = ffi.gc(m.file_open_fd_new(ret1, fd, flags), nil)
return ret1[0], ret2
end
@ -116,7 +116,7 @@ describe('file_open_fd', function()
local fd = m.os_open(file1, m.kO_RDONLY, 0)
local err, fp = file_open_fd(fd, m.kFileReadOnly)
eq(0, err)
eq({#fcontents, fcontents}, {file_read(fp, #fcontents)})
eq({ #fcontents, fcontents }, { file_read(fp, #fcontents) })
eq(0, m.file_close(fp, false))
end)
itp('can use file descriptor returned by os_open for writing', function()
@ -136,7 +136,7 @@ describe('file_open_fd_new', function()
local fd = m.os_open(file1, m.kO_RDONLY, 0)
local err, fp = file_open_fd_new(fd, m.kFileReadOnly)
eq(0, err)
eq({#fcontents, fcontents}, {file_read(fp, #fcontents)})
eq({ #fcontents, fcontents }, { file_read(fp, #fcontents) })
eq(0, m.file_free(fp, false))
end)
itp('can use file descriptor returned by os_open for writing', function()
@ -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,10 +357,9 @@ 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)})
eq({ exp_err, exp_s }, { file_read(fp, size) })
shift = shift + size
end
eq(0, m.file_close(fp, false))
@ -369,8 +369,8 @@ describe('file_read', function()
local err, fp = file_open(file1, 0, 384)
eq(0, err)
eq(false, fp.wr)
eq({#fcontents, fcontents}, {file_read(fp, #fcontents)})
eq({0, ('\0'):rep(#fcontents)}, {file_read(fp, #fcontents)})
eq({ #fcontents, fcontents }, { file_read(fp, #fcontents) })
eq({ 0, ('\0'):rep(#fcontents) }, { file_read(fp, #fcontents) })
eq(0, m.file_close(fp, false))
end)
@ -378,9 +378,8 @@ describe('file_read', function()
local err, fp = file_open(file1, 0, 384)
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({ 5, fcontents:sub(1, 5) }, { file_read(fp, 5) })
eq({ #fcontents - 5, fcontents:sub(6) .. (('\0'):rep(5)) }, { file_read(fp, #fcontents) })
eq(0, m.file_close(fp, false))
end)
@ -395,10 +394,9 @@ 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)})
eq({ exp_err, exp_s }, { file_read(fp, size) })
shift = shift + size
end
eq(0, m.file_close(fp, false))

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()
@ -115,8 +115,8 @@ describe('fs.c', function()
eq(OK, fs.os_dirname(expected_cwd, length))
-- os_chdir returns 0 for success, not OK (1).
neq(0, fs.os_chdir('~')) -- fail
neq(0, fs.os_chdir('~/')) -- fail
neq(0, fs.os_chdir('~')) -- fail
neq(0, fs.os_chdir('~/')) -- fail
eq(OK, fs.os_dirname(cwd, length))
-- CWD did not change.
@ -284,31 +284,34 @@ 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()
local file_gid = luv.fs_stat(filename).gid
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
new_gid = id_fd:read('*n')
end
id_fd:close()
-- 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
new_gid = id_fd:read('*n')
end
id_fd:close()
-- User can be a member of only one group.
-- In that case we can not perform this test.
if new_gid then
eq(0, (os_fchown(filename, -1, new_gid)))
eq(new_gid, luv.fs_stat(filename).gid)
-- User can be a member of only one group.
-- In that case we can not perform this test.
if new_gid then
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)
@ -387,7 +387,7 @@ describe('fs.c', function()
else
buf = ffi.new('char[?]', size + 1, ('\0'):rep(size))
end
local eof = ffi.new('bool[?]', 1, {true})
local eof = ffi.new('bool[?]', 1, { true })
local ret2 = fs.os_read(fd, eof, buf, size, false)
local ret1 = eof[0]
local ret3 = ''
@ -400,16 +400,16 @@ describe('fs.c', function()
local bufs = {}
for i, size in ipairs(sizes) do
bufs[i] = {
iov_base=ffi.new('char[?]', size + 1, ('\0'):rep(size)),
iov_len=size,
iov_base = ffi.new('char[?]', size + 1, ('\0'):rep(size)),
iov_len = size,
}
end
local iov = ffi.new('struct iovec[?]', #sizes, bufs)
local eof = ffi.new('bool[?]', 1, {true})
local eof = ffi.new('bool[?]', 1, { true })
local ret2 = fs.os_readv(fd, eof, iov, #sizes, false)
local ret1 = eof[0]
local ret3 = {}
for i = 1,#sizes do
for i = 1, #sizes do
-- Warning: iov may not be used.
ret3[i] = ffi.string(bufs[i].iov_base, bufs[i].iov_len)
end
@ -445,7 +445,7 @@ describe('fs.c', function()
eq(OK, (os_rename(test, not_exist)))
eq(false, (os_path_exists(test)))
eq(true, (os_path_exists(not_exist)))
eq(OK, (os_rename(not_exist, test))) -- restore test file
eq(OK, (os_rename(not_exist, test))) -- restore test file
end)
itp('fail if source file does not exist', function()
@ -494,14 +494,19 @@ 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
end
eq(i, 6) -- All fds must be unique
eq(i, 6) -- All fds must be unique
end)
end)
@ -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()
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)
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
)
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()
local fd = os_open(existing_file, ffi.C.kO_RDWR, 0)
assert.is_true(0 <= fd)
eq(0, os_close(fd))
end)
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)
describe('os_close', function()
@ -589,43 +600,48 @@ describe('fs.c', function()
itp('can read zero bytes from a file', function()
local fd = os_open(file, ffi.C.kO_RDONLY, 0)
ok(fd >= 0)
eq({false, 0, ''}, {os_read(fd, nil)})
eq({false, 0, ''}, {os_read(fd, 0)})
eq({ false, 0, '' }, { os_read(fd, nil) })
eq({ false, 0, '' }, { os_read(fd, 0) })
eq(0, os_close(fd))
end)
itp('can read from a file multiple times', function()
local fd = os_open(file, ffi.C.kO_RDONLY, 0)
ok(fd >= 0)
eq({false, 2, '\000\001'}, {os_read(fd, 2)})
eq({false, 2, '\002\003'}, {os_read(fd, 2)})
eq({ false, 2, '\000\001' }, { os_read(fd, 2) })
eq({ false, 2, '\002\003' }, { os_read(fd, 2) })
eq(0, os_close(fd))
end)
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, #fcontents, fcontents}, {os_read(fd, #fcontents)})
eq({true, 0, ('\0'):rep(#fcontents)}, {os_read(fd, #fcontents)})
eq({ false, #fcontents, fcontents }, { os_read(fd, #fcontents) })
eq({ true, 0, ('\0'):rep(#fcontents) }, { os_read(fd, #fcontents) })
eq(0, os_close(fd))
end)
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,
(#fcontents * 1/4),
fcontents:sub(#fcontents * 3/4 + 1) .. ('\0'):rep(#fcontents * 2/4)},
{os_read(fd, #fcontents * 3/4)})
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) })
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'
@ -643,45 +659,53 @@ describe('fs.c', function()
itp('can read zero bytes from a file', function()
local fd = os_open(file, ffi.C.kO_RDONLY, 0)
ok(fd >= 0)
eq({false, 0, {}}, {os_readv(fd, {})})
eq({false, 0, {'', '', ''}}, {os_readv(fd, {0, 0, 0})})
eq({ false, 0, {} }, { os_readv(fd, {}) })
eq({ false, 0, { '', '', '' } }, { os_readv(fd, { 0, 0, 0 }) })
eq(0, os_close(fd))
end)
itp('can read from a file multiple times to a differently-sized buffers', function()
local fd = os_open(file, ffi.C.kO_RDONLY, 0)
ok(fd >= 0)
eq({false, 2, {'\000\001'}}, {os_readv(fd, {2})})
eq({false, 5, {'\002\003', '\004\005\006'}}, {os_readv(fd, {2, 3})})
eq({ false, 2, { '\000\001' } }, { os_readv(fd, { 2 }) })
eq({ false, 5, { '\002\003', '\004\005\006' } }, { os_readv(fd, { 2, 3 }) })
eq(0, os_close(fd))
end)
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,
#fcontents,
{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})})
eq({true, 0, {'\0'}}, {os_readv(fd, {1})})
eq({
false,
#fcontents,
{
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 }
),
})
eq({ true, 0, { '\0' } }, { os_readv(fd, { 1 }) })
eq(0, os_close(fd))
end)
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,
(#fcontents * 1/4),
{fcontents:sub(#fcontents * 3/4 + 1) .. ('\0'):rep(#fcontents * 2/4)}},
{os_readv(fd, {#fcontents * 3/4})})
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 }) })
eq(0, os_close(fd))
end)
end)
@ -744,8 +768,8 @@ describe('fs.c', function()
end
local function os_mkdir_recurse(path, mode)
local failed_str = ffi.new('char *[1]', {nil})
local created_str = ffi.new('char *[1]', {nil})
local failed_str = ffi.new('char *[1]', { nil })
local created_str = ffi.new('char *[1]', { nil })
local ret = fs.os_mkdir_recurse(path, mode, failed_str, created_str)
local failed_dir = failed_str[0]
if failed_dir ~= nil then
@ -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])
@ -101,37 +96,35 @@ describe('shell functions', function()
describe('shell_build_argv', function()
itp('works with NULL arguments', function()
eq({'/bin/sh'}, shell_build_argv(nil, nil))
eq({ '/bin/sh' }, shell_build_argv(nil, nil))
end)
itp('works with cmd', function()
eq({'/bin/sh', '-c', 'abc def'}, shell_build_argv('abc def', nil))
eq({ '/bin/sh', '-c', 'abc def' }, shell_build_argv('abc def', nil))
end)
itp('works with extra_args', function()
eq({'/bin/sh', 'ghi jkl'}, shell_build_argv(nil, 'ghi jkl'))
eq({ '/bin/sh', 'ghi jkl' }, shell_build_argv(nil, 'ghi jkl'))
end)
itp('works with cmd and extra_args', function()
eq({'/bin/sh', 'ghi jkl', '-c', 'abc def'}, shell_build_argv('abc def', 'ghi jkl'))
eq({ '/bin/sh', 'ghi jkl', '-c', 'abc def' }, shell_build_argv('abc def', 'ghi jkl'))
end)
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')
@ -176,9 +166,11 @@ describe('shell functions', function()
eq('', shell_argv_to_str({ nil }))
eq("''", shell_argv_to_str({ '' }))
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'", 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) })
)
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)
@ -304,12 +304,12 @@ end)
describe('path.c path_guess_exepath', function()
local cwd = luv.cwd()
for _,name in ipairs({'./nvim', '.nvim', 'foo/nvim'}) do
itp('"'..name..'" returns name catenated with CWD', function()
for _, name in ipairs({ './nvim', '.nvim', 'foo/nvim' }) do
itp('"' .. name .. '" returns name catenated with CWD', function()
local bufsize = 255
local buf = cstr(bufsize, '')
cimp.path_guess_exepath(name, buf, bufsize)
eq(cwd..'/'..name, ffi.string(buf))
eq(cwd .. '/' .. name, ffi.string(buf))
end)
end
@ -331,10 +331,10 @@ describe('path.c path_guess_exepath', function()
itp('does not crash if $PATH item exceeds MAXPATHL', function()
local orig_path_env = os.getenv('PATH')
local name = 'cat' -- Some executable in $PATH.
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)
@ -345,7 +345,7 @@ describe('path.c path_guess_exepath', function()
end)
itp('returns full path found in $PATH', function()
local name = 'cat' -- Some executable in $PATH.
local name = 'cat' -- Some executable in $PATH.
local bufsize = 255
local buf = cstr(bufsize, '')
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
@ -365,7 +365,7 @@ describe('path.c', function()
-- Split absolute_executable into a directory and the actual file name for
-- later usage.
local directory, executable_name = string.match(absolute_executable, '^(.*)/(.*)$') -- luacheck: ignore
local directory, executable_name = string.match(absolute_executable, '^(.*)/(.*)$') -- luacheck: ignore
end)
teardown(function()
@ -441,18 +441,21 @@ 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()
local old_dir = luv.cwd()
luv.chdir('..')
local expected = luv.cwd() .. '/test.file'
luv.chdir(old_dir)
local filename = '../test.file'
local buflen = get_buf_len(expected, filename)
local do_expand = 1
local buf, result = vim_FullName(filename, buflen, do_expand)
eq(expected, ffi.string(buf))
eq(OK, result)
end)
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'
luv.chdir(old_dir)
local filename = '../test.file'
local buflen = get_buf_len(expected, filename)
local do_expand = 1
local buf, result = vim_FullName(filename, buflen, do_expand)
eq(expected, ffi.string(buf))
eq(OK, result)
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
@ -90,8 +90,8 @@ end
--- @field get_declarations_extra_flags string[]
local Gcc = {
preprocessor_extra_flags = {},
get_defines_extra_flags = {'-std=c99', '-dM', '-E'},
get_declarations_extra_flags = {'-std=c99', '-P', '-E'},
get_defines_extra_flags = { '-std=c99', '-dM', '-E' },
get_declarations_extra_flags = { '-std=c99', '-P', '-E' },
}
--- @param name string
@ -115,13 +115,13 @@ end
function Gcc:init_defines()
-- preprocessor flags that will hopefully make the compiler produce C
-- declarations that the LuaJIT ffi understands.
self:define('aligned', {'ARGS'}, '')
self:define('__attribute__', {'ARGS'}, '')
self:define('__asm', {'ARGS'}, '')
self:define('__asm__', {'ARGS'}, '')
self:define('aligned', { 'ARGS' }, '')
self:define('__attribute__', { 'ARGS' }, '')
self:define('__asm', { 'ARGS' }, '')
self:define('__asm__', { 'ARGS' }, '')
self:define('__inline__', nil, '')
self:define('EXTERN', nil, 'extern')
self:define('INIT', {'...'}, '')
self:define('INIT', { '...' }, '')
self:define('_GNU_SOURCE')
self:define('INCLUDE_GENERATED_DECLARATIONS')
self:define('UNIT_TESTING')
@ -158,9 +158,9 @@ end
--- @return string[]?
function Gcc:dependencies(hdr)
--- @type string
local cmd = argss_to_cmd(self.path, {'-M', hdr}) .. ' 2>&1'
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,
self.preprocessor_extra_flags,
self.get_defines_extra_flags,
{pseudoheader_fname}))
local standard_defines = assert(
repeated_read_cmd(
self.path,
self.preprocessor_extra_flags,
self.get_defines_extra_flags,
{ 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.
@ -202,24 +206,33 @@ end
--- @return string, string
function Gcc:preprocess(previous_defines, ...)
-- create pseudo-header
local pseudoheader = headerize({...}, false)
local pseudoheader = headerize({ ... }, false)
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,
self.get_defines_extra_flags,
{pseudoheader_fname}))
local defines = assert(
repeated_read_cmd(
self.path,
self.preprocessor_extra_flags,
self.get_defines_extra_flags,
{ pseudoheader_fname }
)
)
defines = self:filter_standard_defines(defines)
local declarations = assert(repeated_read_cmd(self.path,
self.preprocessor_extra_flags,
self.get_declarations_extra_flags,
{pseudoheader_fname}))
local declarations = assert(
repeated_read_cmd(
self.path,
self.preprocessor_extra_flags,
self.get_declarations_extra_flags,
{ pseudoheader_fname }
)
)
os.remove(pseudoheader_fname)
@ -233,10 +246,10 @@ 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})
return Gcc:new({ path = meta.path })
end
end
end

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,36 +23,44 @@ 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)
return string.sub(str, 1, string.len(start)) == start
return string.sub(str, 1, string.len(start)) == start
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, "<")
local function lt(a, b) -- luacheck: ignore
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, "<=")
local function lte(a, b) -- luacheck: ignore
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, ">")
local function gt(a, b) -- luacheck: ignore
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 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
@ -56,7 +56,7 @@ describe('rbuffer functions', function()
describe('with empty buffer in one contiguous chunk', function()
itp('is called once with the empty chunk', function()
collect_write_chunks()
eq({'0000000000000000'}, chunks)
eq({ '0000000000000000' }, chunks)
end)
end)
@ -64,7 +64,7 @@ describe('rbuffer functions', function()
itp('is called once with the empty chunk', function()
write('string')
collect_write_chunks()
eq({'0000000000'}, chunks)
eq({ '0000000000' }, chunks)
end)
end)
@ -81,7 +81,7 @@ describe('rbuffer functions', function()
write('1234567890')
read(8)
collect_write_chunks()
eq({'000000', '12345678'}, chunks)
eq({ '000000', '12345678' }, chunks)
end)
end)
@ -90,7 +90,7 @@ describe('rbuffer functions', function()
write('12345678')
read(8)
collect_write_chunks()
eq({'00000000', '12345678'}, chunks)
eq({ '00000000', '12345678' }, chunks)
end)
end)
@ -129,7 +129,7 @@ describe('rbuffer functions', function()
itp('is called once with the filled chunk', function()
write('string')
collect_read_chunks()
eq({'string'}, chunks)
eq({ 'string' }, chunks)
end)
end)
@ -137,7 +137,7 @@ describe('rbuffer functions', function()
itp('is called once with the filled chunk', function()
write('abcdefghijklmnopq')
collect_read_chunks()
eq({'abcdefghijklmnop'}, chunks)
eq({ 'abcdefghijklmnop' }, chunks)
end)
end)
@ -147,7 +147,7 @@ describe('rbuffer functions', function()
read(10)
write('long string')
collect_read_chunks()
eq({'long s', 'tring'}, chunks)
eq({ 'long s', 'tring' }, chunks)
end)
end)
@ -157,7 +157,7 @@ describe('rbuffer functions', function()
read(8)
write('abcdefghijklmnopq')
collect_read_chunks()
eq({'abcdefgh', 'ijklmnop'}, chunks)
eq({ 'abcdefgh', 'ijklmnop' }, chunks)
end)
end)
end)
@ -167,7 +167,7 @@ describe('rbuffer functions', function()
local function collect_chars()
rbuffer.ut_rbuffer_each(rbuf, function(c, i)
table.insert(chars, {string.char(c), tonumber(i)})
table.insert(chars, { string.char(c), tonumber(i) })
end)
end
before_each(function()
@ -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)
@ -198,7 +209,7 @@ describe('rbuffer functions', function()
local function collect_chars()
rbuffer.ut_rbuffer_each_reverse(rbuf, function(c, i)
table.insert(chars, {string.char(c), tonumber(i)})
table.insert(chars, { string.char(c), tonumber(i) })
end)
end
before_each(function()
@ -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 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 search_regcomp = function(pat, pat_save, pat_use, options)
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

@ -33,7 +33,7 @@ end
--- @return Set
function Set:copy()
local obj = {nelem = self.nelem, tbl = {}, items = {}} --- @type Set
local obj = { nelem = self.nelem, tbl = {}, items = {} } --- @type Set
for k, v in pairs(self.tbl) do
obj.tbl[k] = v
end
@ -128,13 +128,13 @@ function Set:to_table()
-- there might be gaps in @tbl, so we have to be careful and sort first
local keys = {} --- @type string[]
for idx, _ in pairs(self.tbl) do
keys[#keys+1] = idx
keys[#keys + 1] = idx
end
table.sort(keys)
local copy = {} --- @type string[]
for _, idx in ipairs(keys) do
copy[#copy+1] = self.tbl[idx]
copy[#copy + 1] = self.tbl[idx]
end
return copy
end

View File

@ -1,14 +1,14 @@
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 get_str = helpers.ffi.string
local eq = helpers.eq
local NULL = helpers.NULL
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,23 +22,25 @@ 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,
output_buffer,
buffer_byte_size,
to_cstr(pat),
NULL,
0,
fillchar,
maximum_cell_count,
NULL,
NULL,
NULL)
return stl.build_stl_str_hl(
globals.curwin,
output_buffer,
buffer_byte_size,
to_cstr(pat),
NULL,
0,
fillchar,
maximum_cell_count,
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,
maximum_cell_count=statusline_cell_count,
fillchar=fillchar}
local result_cell_count = build_stl_str_hl {
pat = input_stl,
maximum_cell_count = statusline_cell_count,
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,
statusline_cell_count,
input_stl,
expected_stl,
arg)
local function statusline_test_align(
description,
statusline_cell_count,
input_stl,
expected_stl,
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)
@ -21,19 +20,19 @@ describe('vim_strsave_escaped()', function()
end
itp('precedes by a backslash all chars from second argument', function()
eq([[\a\b\c\d]], vim_strsave_escaped('abcd','abcd'))
eq([[\a\b\c\d]], vim_strsave_escaped('abcd', 'abcd'))
end)
itp('precedes by a backslash chars only from second argument', function()
eq([[\a\bcd]], vim_strsave_escaped('abcd','ab'))
eq([[\a\bcd]], vim_strsave_escaped('abcd', 'ab'))
end)
itp('returns a copy of passed string if second argument is empty', function()
eq('text \n text', vim_strsave_escaped('text \n text',''))
eq('text \n text', vim_strsave_escaped('text \n text', ''))
end)
itp('returns an empty string if first argument is empty string', function()
eq('', vim_strsave_escaped('','\r'))
eq('', vim_strsave_escaped('', '\r'))
end)
itp('returns a copy of passed string if it does not contain chars from 2nd argument', function()
@ -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
@ -232,49 +247,51 @@ describe('vim_snprintf()', function()
end)
end)
describe('strcase_save()' , function()
describe('strcase_save()', function()
local strcase_save = function(input_string, upper)
local res = strings.strcase_save(to_cstr(input_string), upper)
return ffi.string(res)
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

@ -23,7 +23,7 @@ local buffer_hash = nil
child_call_once(function()
if old_p_udir == nil then
old_p_udir = options.p_udir -- save the old value of p_udir (undodir)
old_p_udir = options.p_udir -- save the old value of p_udir (undodir)
end
-- create a new buffer
@ -39,21 +39,20 @@ child_call_once(function()
undo.u_compute_hash(file_buffer, buffer_hash)
end)
describe('u_write_undo', function()
setup(function()
mkdir('unit-test-directory')
luv.chdir('unit-test-directory')
options.p_udir = to_cstr(luv.cwd()) -- set p_udir to be the test dir
options.p_udir = to_cstr(luv.cwd()) -- set p_udir to be the test dir
end)
teardown(function()
luv.chdir('..')
local success, err = luv.fs_rmdir('unit-test-directory')
if not success then
print(err) -- inform tester if directory fails to delete
print(err) -- inform tester if directory fails to delete
end
options.p_udir = old_p_udir --restore old p_udir
options.p_udir = old_p_udir --restore old p_udir
end)
-- Lua wrapper for u_write_undo
@ -68,24 +67,24 @@ 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.
local success, err = os.remove(correct_name) -- delete the file now that we're done with it.
if not success then
print(err) -- inform tester if undofile fails to delete
print(err) -- inform tester if undofile fails to delete
end
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.
local success, err = os.remove(correct_name) -- delete the file now that we're done with it.
if not success then
print(err) -- inform tester if undofile fails to delete
print(err) -- inform tester if undofile fails to delete
end
end)
@ -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
@ -119,17 +118,17 @@ describe('u_write_undo', function()
-- delete the file now that we're done with it.
local success, err = os.remove(test_file_name)
if not success then
print(err) -- inform tester if undofile fails to delete
print(err) -- inform tester if undofile fails to delete
end
success, err = os.remove(undo_file_name)
if not success then
print(err) -- inform tester if undofile fails to delete
print(err) -- inform tester if undofile fails to delete
end
end)
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)
@ -144,12 +143,12 @@ describe('u_write_undo', function()
-- delete the file now that we're done with it.
local success, err = os.remove(undo_file_name)
if not success then
print(err) -- inform tester if undofile fails to delete
print(err) -- inform tester if undofile fails to delete
end
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)
@ -160,9 +159,9 @@ describe('u_write_undo', function()
local undo_file_contents = helpers.read_file(correct_name)
neq(file_contents, undo_file_contents)
local success, deletion_err = os.remove(correct_name) -- delete the file now that we're done with it.
local success, deletion_err = os.remove(correct_name) -- delete the file now that we're done with it.
if not success then
print(deletion_err) -- inform tester if undofile fails to delete
print(deletion_err) -- inform tester if undofile fails to delete
end
end)
@ -172,17 +171,17 @@ describe('u_write_undo', function()
local file_last_modified = luv.fs_stat(correct_name).mtime.sec
sleep(1000) -- Ensure difference in timestamps.
file_buffer.b_u_numhead = 1 -- Mark it as if there are changes
sleep(1000) -- Ensure difference in timestamps.
file_buffer.b_u_numhead = 1 -- Mark it as if there are changes
u_write_undo(nil, false, file_buffer, buffer_hash)
local file_last_modified_2 = luv.fs_stat(correct_name).mtime.sec
-- print(file_last_modified, file_last_modified_2)
neq(file_last_modified, file_last_modified_2)
local success, err = os.remove(correct_name) -- delete the file now that we're done with it.
local success, err = os.remove(correct_name) -- delete the file now that we're done with it.
if not success then
print(err) -- inform tester if undofile fails to delete
print(err) -- inform tester if undofile fails to delete
end
end)
@ -195,16 +194,16 @@ describe('u_write_undo', function()
end)
itp('does not write an undo file if there is no undo information for the buffer', function()
file_buffer.b_u_numhead = 0 -- Mark it as if there is no undo information
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
@ -150,156 +148,263 @@ describe('Expressions lexer', function()
end
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))
local pstate = new_pstate({ str })
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
pstate = new_pstate({str .. ' '})
eq({data=data, len=#str, start={col=0, line=0}, str=str, type=typ},
next_eltkn(pstate, flags))
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)
)
check_advance(pstate, #str, 0)
end
pstate = new_pstate({'x' .. str})
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)
singl_eltkn_test('PlainIdentifier', scope .. ':test#var', {autoload=true, scope=scope})
singl_eltkn_test('PlainIdentifier', scope .. ':', {autoload=false, scope=scope})
singl_eltkn_test('PlainIdentifier', scope .. ':test#var', { autoload = true, scope = scope })
singl_eltkn_test('PlainIdentifier', scope .. ':', { autoload = false, scope = scope })
end
local function comparison_test(op, inv_op, cmp_type)
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', 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', 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', op .. '?', { type = cmp_type, inv = false, 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
local function stable_tests()
singl_eltkn_test('Parenthesis', '(', {closing=false})
singl_eltkn_test('Parenthesis', ')', {closing=true})
singl_eltkn_test('Bracket', '[', {closing=false})
singl_eltkn_test('Bracket', ']', {closing=true})
singl_eltkn_test('FigureBrace', '{', {closing=false})
singl_eltkn_test('FigureBrace', '}', {closing=true})
singl_eltkn_test('Parenthesis', '(', { closing = false })
singl_eltkn_test('Parenthesis', ')', { closing = true })
singl_eltkn_test('Bracket', '[', { closing = false })
singl_eltkn_test('Bracket', ']', { closing = true })
singl_eltkn_test('FigureBrace', '{', { closing = false })
singl_eltkn_test('FigureBrace', '}', { closing = true })
singl_eltkn_test('Question', '?')
singl_eltkn_test('Colon', ':')
singl_eltkn_test('Dot', '.')
singl_eltkn_test('Assignment', '.=', {type='Concat'})
singl_eltkn_test('Assignment', '.=', { type = 'Concat' })
singl_eltkn_test('Plus', '+')
singl_eltkn_test('Assignment', '+=', {type='Add'})
singl_eltkn_test('Assignment', '+=', { type = 'Add' })
singl_eltkn_test('Comma', ',')
singl_eltkn_test('Multiplication', '*', {type='Mul'})
singl_eltkn_test('Multiplication', '/', {type='Div'})
singl_eltkn_test('Multiplication', '%', {type='Mod'})
singl_eltkn_test('Multiplication', '*', { type = 'Mul' })
singl_eltkn_test('Multiplication', '/', { type = 'Div' })
singl_eltkn_test('Multiplication', '%', { type = 'Mod' })
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('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})
singl_eltkn_test('Number', '0x123', {is_float=false, base=16, val=291})
singl_eltkn_test('Number', '0x56FF', {is_float=false, base=16, val=22271})
singl_eltkn_test('Number', '0xabcdef', {is_float=false, base=16, val=11259375})
singl_eltkn_test('Number', '0xABCDEF', {is_float=false, base=16, val=11259375})
singl_eltkn_test('Number', '0x0', {is_float=false, base=16, val=0})
singl_eltkn_test('Number', '00', {is_float=false, base=8, val=0})
singl_eltkn_test('Number', '0b0', {is_float=false, base=2, val=0})
singl_eltkn_test('Number', '0b010111', {is_float=false, base=2, val=23})
singl_eltkn_test('Number', '0b100111', {is_float=false, base=2, val=39})
singl_eltkn_test('Number', '0', {is_float=false, base=10, val=0})
singl_eltkn_test('Number', '9', {is_float=false, base=10, val=9})
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 })
singl_eltkn_test('Number', '0x123', { is_float = false, base = 16, val = 291 })
singl_eltkn_test('Number', '0x56FF', { is_float = false, base = 16, val = 22271 })
singl_eltkn_test('Number', '0xabcdef', { is_float = false, base = 16, val = 11259375 })
singl_eltkn_test('Number', '0xABCDEF', { is_float = false, base = 16, val = 11259375 })
singl_eltkn_test('Number', '0x0', { is_float = false, base = 16, val = 0 })
singl_eltkn_test('Number', '00', { is_float = false, base = 8, val = 0 })
singl_eltkn_test('Number', '0b0', { is_float = false, base = 2, val = 0 })
singl_eltkn_test('Number', '0b010111', { is_float = false, base = 2, val = 23 })
singl_eltkn_test('Number', '0b100111', { is_float = false, base = 2, val = 39 })
singl_eltkn_test('Number', '0', { is_float = false, base = 10, val = 0 })
singl_eltkn_test('Number', '9', { is_float = false, base = 10, val = 9 })
singl_eltkn_test('Env', '$abc')
singl_eltkn_test('Env', '$')
singl_eltkn_test('PlainIdentifier', 'test', {autoload=false, scope=0})
singl_eltkn_test('PlainIdentifier', '_test', {autoload=false, scope=0})
singl_eltkn_test('PlainIdentifier', '_test_foo', {autoload=false, scope=0})
singl_eltkn_test('PlainIdentifier', 't', {autoload=false, scope=0})
singl_eltkn_test('PlainIdentifier', 'test5', {autoload=false, scope=0})
singl_eltkn_test('PlainIdentifier', 't0', {autoload=false, scope=0})
singl_eltkn_test('PlainIdentifier', 'test#var', {autoload=true, scope=0})
singl_eltkn_test('PlainIdentifier', 'test#var#val###', {autoload=true, scope=0})
singl_eltkn_test('PlainIdentifier', 't#####', {autoload=true, scope=0})
singl_eltkn_test('PlainIdentifier', 'test', { autoload = false, scope = 0 })
singl_eltkn_test('PlainIdentifier', '_test', { autoload = false, scope = 0 })
singl_eltkn_test('PlainIdentifier', '_test_foo', { autoload = false, scope = 0 })
singl_eltkn_test('PlainIdentifier', 't', { autoload = false, scope = 0 })
singl_eltkn_test('PlainIdentifier', 'test5', { autoload = false, scope = 0 })
singl_eltkn_test('PlainIdentifier', 't0', { autoload = false, scope = 0 })
singl_eltkn_test('PlainIdentifier', 'test#var', { autoload = true, scope = 0 })
singl_eltkn_test('PlainIdentifier', 'test#var#val###', { autoload = true, scope = 0 })
singl_eltkn_test('PlainIdentifier', 't#####', { autoload = true, scope = 0 })
singl_eltkn_test('And', '&&')
singl_eltkn_test('Or', '||')
singl_eltkn_test('Invalid', '&', {error='E112: Option name missing: %.*s'})
singl_eltkn_test('Option', '&opt', {scope='Unspecified', name='opt'})
singl_eltkn_test('Option', '&t_xx', {scope='Unspecified', name='t_xx'})
singl_eltkn_test('Option', '&t_\r\r', {scope='Unspecified', name='t_\r\r'})
singl_eltkn_test('Option', '&t_\t\t', {scope='Unspecified', name='t_\t\t'})
singl_eltkn_test('Option', '&t_ ', {scope='Unspecified', name='t_ '})
singl_eltkn_test('Option', '&g:opt', {scope='Global', name='opt'})
singl_eltkn_test('Option', '&l:opt', {scope='Local', name='opt'})
singl_eltkn_test('Invalid', '&l:', {error='E112: Option name missing: %.*s'})
singl_eltkn_test('Invalid', '&g:', {error='E112: Option name missing: %.*s'})
singl_eltkn_test('Register', '@', {name=-1})
singl_eltkn_test('Register', '@a', {name='a'})
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('DoubleQuotedString', '"test', {closed=false})
singl_eltkn_test('DoubleQuotedString', '"test"', {closed=true})
singl_eltkn_test('DoubleQuotedString', '"\\""', {closed=true})
singl_eltkn_test('DoubleQuotedString', '"x\\""', {closed=true})
singl_eltkn_test('DoubleQuotedString', '"\\"x"', {closed=true})
singl_eltkn_test('DoubleQuotedString', '"\\"', {closed=false})
singl_eltkn_test('DoubleQuotedString', '"x\\"', {closed=false})
singl_eltkn_test('DoubleQuotedString', '"\\"x', {closed=false})
singl_eltkn_test('Invalid', '&', { error = 'E112: Option name missing: %.*s' })
singl_eltkn_test('Option', '&opt', { scope = 'Unspecified', name = 'opt' })
singl_eltkn_test('Option', '&t_xx', { scope = 'Unspecified', name = 't_xx' })
singl_eltkn_test('Option', '&t_\r\r', { scope = 'Unspecified', name = 't_\r\r' })
singl_eltkn_test('Option', '&t_\t\t', { scope = 'Unspecified', name = 't_\t\t' })
singl_eltkn_test('Option', '&t_ ', { scope = 'Unspecified', name = 't_ ' })
singl_eltkn_test('Option', '&g:opt', { scope = 'Global', name = 'opt' })
singl_eltkn_test('Option', '&l:opt', { scope = 'Local', name = 'opt' })
singl_eltkn_test('Invalid', '&l:', { error = 'E112: Option name missing: %.*s' })
singl_eltkn_test('Invalid', '&g:', { error = 'E112: Option name missing: %.*s' })
singl_eltkn_test('Register', '@', { name = -1 })
singl_eltkn_test('Register', '@a', { name = 'a' })
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('DoubleQuotedString', '"test', { closed = false })
singl_eltkn_test('DoubleQuotedString', '"test"', { closed = true })
singl_eltkn_test('DoubleQuotedString', '"\\""', { closed = true })
singl_eltkn_test('DoubleQuotedString', '"x\\""', { closed = true })
singl_eltkn_test('DoubleQuotedString', '"\\"x"', { closed = true })
singl_eltkn_test('DoubleQuotedString', '"\\"', { closed = false })
singl_eltkn_test('DoubleQuotedString', '"x\\"', { closed = false })
singl_eltkn_test('DoubleQuotedString', '"\\"x', { closed = false })
singl_eltkn_test('Not', '!')
singl_eltkn_test('Assignment', '=', {type='Plain'})
singl_eltkn_test('Assignment', '=', { type = 'Plain' })
comparison_test('==', '!=', 'Equal')
comparison_test('=~', '!~', 'Matches')
comparison_test('>', '<=', 'Greater')
comparison_test('>=', '<', 'GreaterOrEqual')
singl_eltkn_test('Minus', '-')
singl_eltkn_test('Assignment', '-=', {type='Subtract'})
singl_eltkn_test('Assignment', '-=', { type = 'Subtract' })
singl_eltkn_test('Arrow', '->')
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'})
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' }
)
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)
@ -419,8 +696,8 @@ describe('Expressions lexer', function()
regular_is_tests()
regular_number_tests()
singl_eltkn_test('Invalid', '|', {error='E15: Unexpected EOC character: %.*s'})
singl_eltkn_test('Invalid', '\0', {error='E15: Unexpected EOC character: %.*s'})
singl_eltkn_test('Invalid', '\n', {error='E15: Unexpected EOC character: %.*s'})
singl_eltkn_test('Invalid', '|', { error = 'E15: Unexpected EOC character: %.*s' })
singl_eltkn_test('Invalid', '\0', { error = 'E15: Unexpected EOC character: %.*s' })
singl_eltkn_test('Invalid', '\n', { error = 'E15: Unexpected EOC character: %.*s' })
end)
end)

View File

@ -25,100 +25,99 @@ 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()
local predefined_hl_defs = {
-- From highlight_init_both
Conceal=true,
Cursor=true,
lCursor=true,
DiffText=true,
ErrorMsg=true,
IncSearch=true,
ModeMsg=true,
NonText=true,
PmenuSbar=true,
StatusLine=true,
StatusLineNC=true,
TabLineFill=true,
TabLineSel=true,
TermCursor=true,
VertSplit=true,
WildMenu=true,
WinSeparator=true,
EndOfBuffer=true,
QuickFixLine=true,
Substitute=true,
Whitespace=true,
Error=true,
Todo=true,
String=true,
Character=true,
Number=true,
Boolean=true,
Float=true,
Function=true,
Conditional=true,
Repeat=true,
Label=true,
Operator=true,
Keyword=true,
Exception=true,
Include=true,
Define=true,
Macro=true,
PreCondit=true,
StorageClass=true,
Structure=true,
Typedef=true,
Tag=true,
SpecialChar=true,
Delimiter=true,
SpecialComment=true,
Debug=true,
Conceal = true,
Cursor = true,
lCursor = true,
DiffText = true,
ErrorMsg = true,
IncSearch = true,
ModeMsg = true,
NonText = true,
PmenuSbar = true,
StatusLine = true,
StatusLineNC = true,
TabLineFill = true,
TabLineSel = true,
TermCursor = true,
VertSplit = true,
WildMenu = true,
WinSeparator = true,
EndOfBuffer = true,
QuickFixLine = true,
Substitute = true,
Whitespace = true,
Error = true,
Todo = true,
String = true,
Character = true,
Number = true,
Boolean = true,
Float = true,
Function = true,
Conditional = true,
Repeat = true,
Label = true,
Operator = true,
Keyword = true,
Exception = true,
Include = true,
Define = true,
Macro = true,
PreCondit = true,
StorageClass = true,
Structure = true,
Typedef = true,
Tag = true,
SpecialChar = true,
Delimiter = true,
SpecialComment = true,
Debug = true,
-- From highlight_init_(dark|light)
ColorColumn=true,
CursorColumn=true,
CursorLine=true,
CursorLineNr=true,
DiffAdd=true,
DiffChange=true,
DiffDelete=true,
Directory=true,
FoldColumn=true,
Folded=true,
LineNr=true,
MatchParen=true,
MoreMsg=true,
Pmenu=true,
PmenuSel=true,
PmenuThumb=true,
Question=true,
Search=true,
SignColumn=true,
SpecialKey=true,
SpellBad=true,
SpellCap=true,
SpellLocal=true,
SpellRare=true,
TabLine=true,
Title=true,
Visual=true,
WarningMsg=true,
Normal=true,
Comment=true,
Constant=true,
Special=true,
Identifier=true,
Statement=true,
PreProc=true,
Type=true,
Underlined=true,
Ignore=true,
ColorColumn = true,
CursorColumn = true,
CursorLine = true,
CursorLineNr = true,
DiffAdd = true,
DiffChange = true,
DiffDelete = true,
Directory = true,
FoldColumn = true,
Folded = true,
LineNr = true,
MatchParen = true,
MoreMsg = true,
Pmenu = true,
PmenuSel = true,
PmenuThumb = true,
Question = true,
Search = true,
SignColumn = true,
SpecialKey = true,
SpellBad = true,
SpellCap = true,
SpellLocal = true,
SpellRare = true,
TabLine = true,
Title = true,
Visual = true,
WarningMsg = true,
Normal = true,
Comment = true,
Constant = true,
Special = true,
Identifier = true,
Statement = true,
PreProc = true,
Type = true,
Underlined = true,
Ignore = true,
}
local nvim_hl_defs = {}
@ -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]))
nvim_hl_defs[new_grp] = {'link', grp_link}
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]))
nvim_hl_defs[new_grp] = {'definition', grp_args}
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)',
group,
str,
(col_shift == 0
and ''
or (', %u'):format(col_shift)))
ret[i] = format_string(
'hl(%r, %r%s)',
group,
str,
(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,47 +274,54 @@ local function format_check(expr, format_check_data, opts)
end
local east_node_type_tab
make_enum_conv_tab(lib, {
'kExprNodeMissing',
'kExprNodeOpMissing',
'kExprNodeTernary',
'kExprNodeTernaryValue',
'kExprNodeRegister',
'kExprNodeSubscript',
'kExprNodeListLiteral',
'kExprNodeUnaryPlus',
'kExprNodeBinaryPlus',
'kExprNodeNested',
'kExprNodeCall',
'kExprNodePlainIdentifier',
'kExprNodePlainKey',
'kExprNodeComplexIdentifier',
'kExprNodeUnknownFigure',
'kExprNodeLambda',
'kExprNodeDictLiteral',
'kExprNodeCurlyBracesIdentifier',
'kExprNodeComma',
'kExprNodeColon',
'kExprNodeArrow',
'kExprNodeComparison',
'kExprNodeConcat',
'kExprNodeConcatOrSubscript',
'kExprNodeInteger',
'kExprNodeFloat',
'kExprNodeSingleQuotedString',
'kExprNodeDoubleQuotedString',
'kExprNodeOr',
'kExprNodeAnd',
'kExprNodeUnaryMinus',
'kExprNodeBinaryMinus',
'kExprNodeNot',
'kExprNodeMultiplication',
'kExprNodeDivision',
'kExprNodeMod',
'kExprNodeOption',
'kExprNodeEnvironment',
'kExprNodeAssignment',
}, 'kExprNode', function(ret) east_node_type_tab = ret end)
make_enum_conv_tab(
lib,
{
'kExprNodeMissing',
'kExprNodeOpMissing',
'kExprNodeTernary',
'kExprNodeTernaryValue',
'kExprNodeRegister',
'kExprNodeSubscript',
'kExprNodeListLiteral',
'kExprNodeUnaryPlus',
'kExprNodeBinaryPlus',
'kExprNodeNested',
'kExprNodeCall',
'kExprNodePlainIdentifier',
'kExprNodePlainKey',
'kExprNodeComplexIdentifier',
'kExprNodeUnknownFigure',
'kExprNodeLambda',
'kExprNodeDictLiteral',
'kExprNodeCurlyBracesIdentifier',
'kExprNodeComma',
'kExprNodeColon',
'kExprNodeArrow',
'kExprNodeComparison',
'kExprNodeConcat',
'kExprNodeConcatOrSubscript',
'kExprNodeInteger',
'kExprNodeFloat',
'kExprNodeSingleQuotedString',
'kExprNodeDoubleQuotedString',
'kExprNodeOr',
'kExprNodeAnd',
'kExprNodeUnaryMinus',
'kExprNodeBinaryMinus',
'kExprNodeNot',
'kExprNodeMultiplication',
'kExprNodeDivision',
'kExprNodeMod',
'kExprNodeOption',
'kExprNodeEnvironment',
'kExprNodeAssignment',
},
'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(
tostring(intchar2lua(eastnode.data.var.scope)),
ffi.string(eastnode.data.var.ident, eastnode.data.var.ident_len))
typ = typ
.. ('(scope=%s,ident=%s)'):format(
tostring(intchar2lua(eastnode.data.var.scope)),
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(
(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 '-'))
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 '-')
)
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, {
group = ffi.string(chunk.group),
})
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 = {}
@ -460,12 +472,12 @@ describe('Expressions parser', function()
end
alloc_log:check({})
local pstate = new_pstate({str})
local pstate = new_pstate({ str })
local east = lib.viml_pexpr_parse(pstate, flags)
local ast = east2lua(str, pstate, east)
local hls = phl2lua(pstate)
if exp_ast == nil then
format_check_data[flags] = {ast=ast, hl_fs=hls_to_hl_fs(hls)}
format_check_data[flags] = { ast = ast, hl_fs = hls_to_hl_fs(hls) }
else
local exps = {
ast = exp_ast,
@ -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

@ -4,12 +4,12 @@ local REMOVE_THIS = global_helpers.REMOVE_THIS
return function(itp, _check_parsing, hl, fmtn)
local function check_parsing(...)
return _check_parsing({flags={0, 1, 2, 3}, funcname='check_parsing'}, ...)
return _check_parsing({ flags = { 0, 1, 2, 3 }, funcname = 'check_parsing' }, ...)
end
local function check_asgn_parsing(...)
return _check_parsing({
flags={4, 5, 6, 7},
funcname='check_asgn_parsing',
flags = { 4, 5, 6, 7 },
funcname = 'check_asgn_parsing',
}, ...)
end
itp('works with + and @a', function()
@ -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,45 +696,46 @@ return function(itp, _check_parsing, hl, fmtn)
},
},
},
}},
}, {
hl('Register', '@a'),
hl('BinaryPlus', '+', 1),
hl('NestingParenthesis', '(', 1),
hl('Register', '@b'),
hl('BinaryPlus', '+', 1),
hl('Register', '@c', 1),
hl('NestingParenthesis', ')'),
hl('BinaryPlus', '+', 1),
hl('Register', '@d', 1),
hl('CallingParenthesis', '('),
hl('Register', '@e'),
hl('CallingParenthesis', ')'),
hl('BinaryPlus', '+', 1),
hl('NestingParenthesis', '(', 1),
hl('UnaryPlus', '+'),
hl('Register', '@f'),
hl('NestingParenthesis', ')'),
hl('BinaryPlus', '+', 1),
hl('NestingParenthesis', '(', 1),
hl('NestingParenthesis', '('),
hl('UnaryPlus', '+'),
hl('Register', '@g'),
hl('CallingParenthesis', '('),
hl('Register', '@h'),
hl('CallingParenthesis', ')'),
hl('NestingParenthesis', ')'),
hl('CallingParenthesis', '('),
hl('Register', '@j'),
hl('CallingParenthesis', ')'),
hl('CallingParenthesis', '('),
hl('Register', '@k'),
hl('CallingParenthesis', ')'),
hl('NestingParenthesis', ')'),
hl('CallingParenthesis', '('),
hl('Register', '@l'),
hl('CallingParenthesis', ')'),
})
},
},
}, {
hl('Register', '@a'),
hl('BinaryPlus', '+', 1),
hl('NestingParenthesis', '(', 1),
hl('Register', '@b'),
hl('BinaryPlus', '+', 1),
hl('Register', '@c', 1),
hl('NestingParenthesis', ')'),
hl('BinaryPlus', '+', 1),
hl('Register', '@d', 1),
hl('CallingParenthesis', '('),
hl('Register', '@e'),
hl('CallingParenthesis', ')'),
hl('BinaryPlus', '+', 1),
hl('NestingParenthesis', '(', 1),
hl('UnaryPlus', '+'),
hl('Register', '@f'),
hl('NestingParenthesis', ')'),
hl('BinaryPlus', '+', 1),
hl('NestingParenthesis', '(', 1),
hl('NestingParenthesis', '('),
hl('UnaryPlus', '+'),
hl('Register', '@g'),
hl('CallingParenthesis', '('),
hl('Register', '@h'),
hl('CallingParenthesis', ')'),
hl('NestingParenthesis', ')'),
hl('CallingParenthesis', '('),
hl('Register', '@j'),
hl('CallingParenthesis', ')'),
hl('CallingParenthesis', '('),
hl('Register', '@k'),
hl('CallingParenthesis', ')'),
hl('NestingParenthesis', ')'),
hl('CallingParenthesis', '('),
hl('Register', '@l'),
hl('CallingParenthesis', ')'),
})
check_parsing('@a)', {
-- 012
ast = {
@ -1078,25 +1079,25 @@ return function(itp, _check_parsing, hl, fmtn)
end)
itp('works with variable names, including curly braces ones', function()
check_parsing('var', {
ast = {
'PlainIdentifier(scope=0,ident=var):0:0:var',
},
ast = {
'PlainIdentifier(scope=0,ident=var):0:0:var',
},
}, {
hl('IdentifierName', 'var'),
})
check_parsing('g:var', {
ast = {
'PlainIdentifier(scope=g,ident=var):0:0:g:var',
},
ast = {
'PlainIdentifier(scope=g,ident=var):0:0:g:var',
},
}, {
hl('IdentifierScope', 'g'),
hl('IdentifierScopeDelimiter', ':'),
hl('IdentifierName', 'var'),
})
check_parsing('g:', {
ast = {
'PlainIdentifier(scope=g,ident=):0:0:g:',
},
ast = {
'PlainIdentifier(scope=g,ident=):0:0:g:',
},
}, {
hl('IdentifierScope', 'g'),
hl('IdentifierScopeDelimiter', ':'),
@ -1141,7 +1142,7 @@ return function(itp, _check_parsing, hl, fmtn)
children = {
{
'OpMissing:0:3:',
children={
children = {
'PlainIdentifier(scope=a,ident=):0:1:a:',
'Register(name=b):0:3:@b',
},
@ -1783,7 +1784,7 @@ return function(itp, _check_parsing, hl, fmtn)
{
'Comma:0:3:,',
children = {
'PlainIdentifier(scope=0,ident=b):0:2:b',
'PlainIdentifier(scope=0,ident=b):0:2:b',
{
'Comma:0:5:,',
children = {
@ -1819,7 +1820,7 @@ return function(itp, _check_parsing, hl, fmtn)
{
'Comma:0:3:,',
children = {
'PlainIdentifier(scope=0,ident=b):0:2:b',
'PlainIdentifier(scope=0,ident=b):0:2:b',
{
'Comma:0:5:,',
children = {
@ -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,
@ -7025,7 +7029,7 @@ return function(itp, _check_parsing, hl, fmtn)
},
},
})
check_parsing({data='01', size=1}, {
check_parsing({ data = '01', size = 1 }, {
len = 1,
ast = {
'Integer(val=0):0:0:0',
@ -7033,7 +7037,7 @@ return function(itp, _check_parsing, hl, fmtn)
}, {
hl('Number', '0'),
})
check_parsing({data='001', size=2}, {
check_parsing({ data = '001', size = 2 }, {
len = 2,
ast = {
'Integer(val=0):0:0:00',
@ -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, {
'kExprCmpEqual',
'kExprCmpMatches',
'kExprCmpGreater',
'kExprCmpGreaterOrEqual',
'kExprCmpIdentical',
}, 'kExprCmp', function(ret) eltkn_cmp_type_tab = ret end)
make_enum_conv_tab(
lib,
{
'kExprCmpEqual',
'kExprCmpMatches',
'kExprCmpGreater',
'kExprCmpGreaterOrEqual',
'kExprCmpIdentical',
},
'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, {
'kCCStrategyUseOption',
'kCCStrategyMatchCase',
'kCCStrategyIgnoreCase',
}, 'kCCStrategy', function(ret) ccs_tab = ret end)
make_enum_conv_tab(
lib,
{
'kCCStrategyUseOption',
'kCCStrategyMatchCase',
'kCCStrategyIgnoreCase',
},
'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, {
'kExprAsgnPlain',
'kExprAsgnAdd',
'kExprAsgnSubtract',
'kExprAsgnConcat',
}, 'kExprAsgn', function(ret) expr_asgn_type_tab = ret end)
make_enum_conv_tab(
lib,
{
'kExprAsgnPlain',
'kExprAsgnAdd',
'kExprAsgnSubtract',
'kExprAsgnConcat',
},
'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)