aboutsummaryrefslogtreecommitdiff
path: root/test/unit
diff options
context:
space:
mode:
authorJosh Rahm <joshuarahm@gmail.com>2023-11-29 22:39:54 +0000
committerJosh Rahm <joshuarahm@gmail.com>2023-11-29 22:39:54 +0000
commit21cb7d04c387e4198ca8098a884c78b56ffcf4c2 (patch)
tree84fe5690df1551f0bb2bdfe1a13aacd29ebc1de7 /test/unit
parentd9c904f85a23a496df4eb6be42aa43f007b22d50 (diff)
parent4a8bf24ac690004aedf5540fa440e788459e5e34 (diff)
downloadrneovim-colorcolchar.tar.gz
rneovim-colorcolchar.tar.bz2
rneovim-colorcolchar.zip
Merge remote-tracking branch 'upstream/master' into colorcolcharcolorcolchar
Diffstat (limited to 'test/unit')
-rw-r--r--test/unit/buffer_spec.lua276
-rw-r--r--test/unit/charset/vim_str2nr_spec.lua2
-rw-r--r--test/unit/eval/helpers.lua5
-rw-r--r--test/unit/eval/typval_spec.lua318
-rw-r--r--test/unit/fixtures/multiqueue.c11
-rw-r--r--test/unit/fixtures/rbuffer.c5
-rw-r--r--test/unit/formatc.lua2
-rw-r--r--test/unit/helpers.lua344
-rw-r--r--test/unit/keycodes_spec.lua22
-rw-r--r--test/unit/marktree_spec.lua339
-rw-r--r--test/unit/mbyte_spec.lua243
-rw-r--r--test/unit/message_spec.lua4
-rw-r--r--test/unit/msgpack_spec.lua75
-rw-r--r--test/unit/optionstr_spec.lua4
-rw-r--r--test/unit/os/env_spec.lua2
-rw-r--r--test/unit/os/fileio_spec.lua69
-rw-r--r--test/unit/os/fs_spec.lua128
-rw-r--r--test/unit/os/shell_spec.lua2
-rw-r--r--test/unit/path_spec.lua81
-rw-r--r--test/unit/preload.lua1
-rw-r--r--test/unit/preprocess.lua178
-rw-r--r--test/unit/set.lua47
-rw-r--r--test/unit/statusline_spec.lua282
-rw-r--r--test/unit/strings_spec.lua93
-rw-r--r--test/unit/tempfile_spec.lua3
-rw-r--r--test/unit/tui_spec.lua162
-rw-r--r--test/unit/undo_spec.lua32
27 files changed, 1486 insertions, 1244 deletions
diff --git a/test/unit/buffer_spec.lua b/test/unit/buffer_spec.lua
index a54ea8c656..6e08a09295 100644
--- a/test/unit/buffer_spec.lua
+++ b/test/unit/buffer_spec.lua
@@ -1,15 +1,11 @@
-
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 globals = helpers.cimport("./src/nvim/globals.h")
local buffer = helpers.cimport("./src/nvim/buffer.h")
-local stl = helpers.cimport("./src/nvim/statusline.h")
describe('buffer functions', function()
@@ -210,276 +206,4 @@ describe('buffer functions', function()
close_buffer(NULL, buf2, buffer.DOBUF_WIPE, 0, 0)
end)
end)
-
- describe('build_stl_str_hl', function()
- local buffer_byte_size = 100
- local STL_INITIAL_ITEMS = 20
- local output_buffer = ''
-
- -- This function builds the statusline
- --
- -- @param arg Optional arguments are:
- -- .pat The statusline format string
- -- .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))
-
- 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)
- end
-
- -- Use this function to simplify testing the comparison between
- -- the format string and the resulting statusline.
- --
- -- @param description The description of what the test should be doing
- -- @param statusline_cell_count The number of cells available in the statusline
- -- @param input_stl The format string for the statusline
- -- @param expected_stl The expected result string for the statusline
- --
- -- @param arg Options can be placed in an optional dictionary as the last parameter
- -- .expected_cell_count The expected number of cells build_stl_str_hl will return
- -- .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)
-
- -- arg is the optional parameter
- -- so we either fill in option with arg or an empty dictionary
- local option = arg or {}
-
- local fillchar = option.fillchar or (' '):byte()
- local expected_cell_count = option.expected_cell_count or statusline_cell_count
- local expected_byte_length = option.expected_byte_length or #expected_stl
-
- itp(description, function()
- if option.file_name then
- buffer.setfname(globals.curbuf, to_cstr(option.file_name), NULL, 1)
- else
- 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}
-
- eq(expected_stl, get_str(output_buffer, expected_byte_length))
- eq(expected_cell_count, result_cell_count)
- end)
- 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')
-
- -- 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})
-
- -- 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})
-
- -- standard text testing
- 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})
-
- -- 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 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 ignore trailing %', 3, 'abc%', 'abc')
-
- -- alignment testing with fillchar
- 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)
- arg.fillchar = ('!'):byte()
- 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)
- 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 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 %=', 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,
- '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,
- ('%='):rep(STL_INITIAL_ITEMS * 5),
- ' ') -- 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,
- 'a' .. ('%=a'):rep(STL_INITIAL_ITEMS * 2),
- '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()})
-
- -- 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)
end)
diff --git a/test/unit/charset/vim_str2nr_spec.lua b/test/unit/charset/vim_str2nr_spec.lua
index caf330c378..fc40fa39d4 100644
--- a/test/unit/charset/vim_str2nr_spec.lua
+++ b/test/unit/charset/vim_str2nr_spec.lua
@@ -63,7 +63,7 @@ local function test_vim_str2nr(s, what, exp, maxlen, strict)
cv[k] = args[k]
end
end
- lib.vim_str2nr(s, cv.pre, cv.len, what, cv.num, cv.unum, 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(
diff --git a/test/unit/eval/helpers.lua b/test/unit/eval/helpers.lua
index b600f01ab2..883f01bd84 100644
--- a/test/unit/eval/helpers.lua
+++ b/test/unit/eval/helpers.lua
@@ -349,7 +349,7 @@ local special_vals = nil
lua2typvalt = function(l, processed)
if not special_vals then
special_vals = {
- [null_string] = {'VAR_STRING', {v_string=ffi.cast('char_u*', nil)}},
+ [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}},
@@ -512,7 +512,8 @@ end
local function eval0(expr)
local tv = ffi.gc(ffi.new('typval_T', {v_type=eval.VAR_UNKNOWN}),
eval.tv_clear)
- if eval.eval0(to_cstr(expr), tv, nil, true) == 0 then
+ 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
return tv
diff --git a/test/unit/eval/typval_spec.lua b/test/unit/eval/typval_spec.lua
index 128625374e..34a1299725 100644
--- a/test/unit/eval/typval_spec.lua
+++ b/test/unit/eval/typval_spec.lua
@@ -43,7 +43,7 @@ local dict_watchers = eval_helpers.dict_watchers
local lib = cimport('./src/nvim/eval/typval.h', './src/nvim/memory.h',
'./src/nvim/mbyte.h', './src/nvim/garray.h',
- './src/nvim/eval.h', './src/nvim/vim.h',
+ './src/nvim/eval.h', './src/nvim/vim_defs.h',
'./src/nvim/globals.h')
local function vimconv_alloc()
@@ -101,12 +101,13 @@ local function check_emsg(f, msg)
saved_last_msg_hist = nil
end
local ret = {f()}
+ local last_msg = lib.last_msg_hist ~= nil and ffi.string(lib.last_msg_hist.msg) or nil
if msg ~= nil then
- eq(msg, ffi.string(lib.last_msg_hist.msg))
+ eq(msg, last_msg)
neq(saved_last_msg_hist, lib.last_msg_hist)
else
if saved_last_msg_hist ~= lib.last_msg_hist then
- eq(nil, ffi.string(lib.last_msg_hist.msg))
+ eq(nil, last_msg)
else
eq(saved_last_msg_hist, lib.last_msg_hist)
end
@@ -1429,15 +1430,16 @@ describe('typval.c', function()
end
describe('str()', function()
itp('returns correct string', function()
- local l = list(int(1), int(2), int(3), int(4), int(5))
+ local l = list(int(1), 2.5, int(3), int(4), int(5))
alloc_log:clear()
eq('1', tv_list_find_str(l, -5))
+ eq('2.5', tv_list_find_str(l, 1))
eq('5', tv_list_find_str(l, 4))
eq('3', tv_list_find_str(l, 2))
eq('3', tv_list_find_str(l, -3))
- alloc_log:check({})
+ alloc_log:check({a.freed(alloc_log.null), a.freed(alloc_log.null)})
end)
itp('returns string when used with VAR_STRING items', function()
local l = list('1', '2', '3', '4', '5')
@@ -1461,18 +1463,16 @@ describe('typval.c', function()
itp('fails with error message when index is out of range', function()
local l = list(int(1), int(2), int(3), int(4), int(5))
- eq(nil, tv_list_find_str(l, -6, 'E684: list index out of range: -6'))
- eq(nil, tv_list_find_str(l, 5, 'E684: list index out of range: 5'))
+ eq(nil, tv_list_find_str(l, -6, 'E684: List index out of range: -6'))
+ eq(nil, tv_list_find_str(l, 5, 'E684: List index out of range: 5'))
end)
itp('fails with error message on invalid types', function()
- local l = list(1, empty_list, {})
+ local l = list(empty_list, {})
- eq('', tv_list_find_str(l, 0, 'E806: using Float as a String'))
- eq('', tv_list_find_str(l, 1, 'E730: using List as a String'))
- eq('', tv_list_find_str(l, 2, 'E731: using Dictionary as a String'))
- eq('', tv_list_find_str(l, -1, 'E731: using Dictionary as a String'))
- eq('', tv_list_find_str(l, -2, 'E730: using List as a String'))
- eq('', tv_list_find_str(l, -3, 'E806: using Float as a String'))
+ eq('', tv_list_find_str(l, 0, 'E730: Using a List as a String'))
+ eq('', tv_list_find_str(l, 1, 'E731: Using a Dictionary as a String'))
+ eq('', tv_list_find_str(l, -1, 'E731: Using a Dictionary as a String'))
+ eq('', tv_list_find_str(l, -2, 'E730: Using a List as a String'))
end)
end)
end)
@@ -1653,7 +1653,7 @@ describe('typval.c', function()
eq(OK, lib.tv_dict_add(d, di))
alloc_log:check({})
eq(FAIL, check_emsg(function() return lib.tv_dict_add(d, di) end,
- 'E685: Internal error: hash_add()'))
+ 'E685: Internal error: hash_add(): duplicate key ""'))
alloc_log:clear()
lib.tv_dict_item_remove(d, di)
alloc_log:check({
@@ -1677,7 +1677,7 @@ describe('typval.c', function()
eq(nil, lib.tv_dict_find(nil, 'test', -1))
eq(nil, lib.tv_dict_find(nil, nil, 0))
end)
- itp('works with NULL key', function()
+ itp('works with empty key', function()
local lua_d = {
['']=0,
t=1,
@@ -1692,7 +1692,6 @@ describe('typval.c', function()
alloc_log:check({})
local dis = dict_items(d)
eq({0, '', dis['']}, {tv_dict_find(d, '', 0)})
- eq({0, '', dis['']}, {tv_dict_find(d, nil, 0)})
end)
itp('works with len properly', function()
local lua_d = {
@@ -1746,7 +1745,7 @@ describe('typval.c', function()
itp('works', function()
local d = ffi.gc(dict({test={}}), nil)
eq('', ffi.string(check_emsg(function() return lib.tv_dict_get_string(d, 'test', false) end,
- 'E731: using Dictionary as a String')))
+ 'E731: Using a Dictionary as a String')))
d = ffi.gc(dict({tes=int(42), t=44, te='43', xx=int(45)}), nil)
alloc_log:clear()
local dis = dict_items(d)
@@ -1766,18 +1765,24 @@ describe('typval.c', function()
neq(s42, s43)
eq(s43, dis.te.di_tv.vval.v_string)
alloc_log:check({})
- eq('', ffi.string(check_emsg(function() return lib.tv_dict_get_string(d, 't', false) end,
- 'E806: using Float as a String')))
+ local s44 = check_emsg(function() return lib.tv_dict_get_string(d, 't', false) end,
+ nil)
+ eq('44.0', ffi.string(s44))
+ alloc_log:check({a.freed(alloc_log.null), a.freed(alloc_log.null)})
end)
itp('allocates a string copy when requested', function()
- local function tv_dict_get_string_alloc(d, key, emsg)
+ local function tv_dict_get_string_alloc(d, key, emsg, is_float)
alloc_log:clear()
local ret = check_emsg(function() return lib.tv_dict_get_string(d, key, true) end,
emsg)
local s_ret = (ret ~= nil) and ffi.string(ret) or nil
if not emsg then
if s_ret then
- alloc_log:check({a.str(ret, s_ret)})
+ if is_float then
+ alloc_log:check({a.freed(alloc_log.null), a.freed(alloc_log.null), a.str(ret, s_ret)})
+ else
+ alloc_log:check({a.str(ret, s_ret)})
+ end
else
alloc_log:check({})
end
@@ -1786,25 +1791,29 @@ describe('typval.c', function()
return s_ret
end
local d = ffi.gc(dict({test={}}), nil)
- eq('', tv_dict_get_string_alloc(d, 'test', 'E731: using Dictionary as a String'))
+ eq('', tv_dict_get_string_alloc(d, 'test', 'E731: Using a Dictionary as a String'))
d = ffi.gc(dict({tes=int(42), t=44, te='43', xx=int(45)}), nil)
alloc_log:clear()
eq(nil, tv_dict_get_string_alloc(d, 'test'))
eq('42', tv_dict_get_string_alloc(d, 'tes'))
eq('45', tv_dict_get_string_alloc(d, 'xx'))
eq('43', tv_dict_get_string_alloc(d, 'te'))
- eq('', tv_dict_get_string_alloc(d, 't', 'E806: using Float as a String'))
+ eq('44.0', tv_dict_get_string_alloc(d, 't', nil, true))
end)
end)
describe('get_string_buf()', function()
- local function tv_dict_get_string_buf(d, key, buf, emsg)
+ local function tv_dict_get_string_buf(d, key, is_float, buf, emsg)
buf = buf or ffi.gc(lib.xmalloc(lib.NUMBUFLEN), lib.xfree)
alloc_log:clear()
local ret = check_emsg(function() return lib.tv_dict_get_string_buf(d, key, buf) end,
emsg)
local s_ret = (ret ~= nil) and ffi.string(ret) or nil
if not emsg then
- alloc_log:check({})
+ if is_float then
+ alloc_log:check({a.freed(alloc_log.null), a.freed(alloc_log.null)})
+ else
+ alloc_log:check({})
+ end
end
return s_ret, ret, buf
end
@@ -1828,16 +1837,16 @@ describe('typval.c', function()
s, r, b = tv_dict_get_string_buf(d, 'test')
neq(r, b)
eq('tset', s)
- s, r, b = tv_dict_get_string_buf(d, 't', nil, 'E806: using Float as a String')
- neq(r, b)
- eq('', s)
+ s, r, b = tv_dict_get_string_buf(d, 't', true)
+ eq(r, b)
+ eq('1.0', s)
s, r, b = tv_dict_get_string_buf(d, 'te')
eq(r, b)
eq('2', s)
end)
end)
describe('get_string_buf_chk()', function()
- local function tv_dict_get_string_buf_chk(d, key, len, buf, def, emsg)
+ local function tv_dict_get_string_buf_chk(d, key, is_float, len, buf, def, emsg)
buf = buf or ffi.gc(lib.xmalloc(lib.NUMBUFLEN), lib.xfree)
def = def or ffi.gc(lib.xstrdup('DEFAULT'), lib.xfree)
len = len or #key
@@ -1846,7 +1855,11 @@ describe('typval.c', function()
emsg)
local s_ret = (ret ~= nil) and ffi.string(ret) or nil
if not emsg then
- alloc_log:check({})
+ if is_float then
+ alloc_log:check({a.freed(alloc_log.null), a.freed(alloc_log.null)})
+ else
+ alloc_log:check({})
+ end
end
return s_ret, ret, buf, def
end
@@ -1871,10 +1884,10 @@ describe('typval.c', function()
neq(r, b)
neq(r, def)
eq('tset', s)
- s, r, b, def = tv_dict_get_string_buf_chk(d, 'test', 1, nil, nil, 'E806: using Float as a String')
- neq(r, b)
+ s, r, b, def = tv_dict_get_string_buf_chk(d, 'test', true, 1)
+ eq(r, b)
neq(r, def)
- eq(nil, s)
+ eq('1.0', s)
s, r, b, def = tv_dict_get_string_buf_chk(d, 'te')
eq(r, b)
neq(r, def)
@@ -1911,8 +1924,6 @@ describe('typval.c', function()
local d = dict(lua_d)
eq(lua_d, dct2tbl(d))
eq({{type='fref', fref='tr'}, true},
- {tv_dict_get_callback(d, nil, 0)})
- eq({{type='fref', fref='tr'}, true},
{tv_dict_get_callback(d, '', -1)})
eq({{type='none'}, true},
{tv_dict_get_callback(d, 'x', -1)})
@@ -1950,7 +1961,7 @@ describe('typval.c', function()
alloc_log:check({})
eq({test=10, ['t-est']=int(42)}, dct2tbl(d))
eq(FAIL, check_emsg(function() return lib.tv_dict_add(d, di) end,
- 'E685: Internal error: hash_add()'))
+ 'E685: Internal error: hash_add(): duplicate key "t-est"'))
end)
end)
describe('list()', function()
@@ -1967,7 +1978,7 @@ describe('typval.c', function()
eq({test=10, tes={1, 2, 3}}, dct2tbl(d))
eq(2, l.lv_refcount)
eq(FAIL, check_emsg(function() return lib.tv_dict_add_list(d, 'testt', 3, l) end,
- 'E685: Internal error: hash_add()'))
+ 'E685: Internal error: hash_add(): duplicate key "tes"'))
eq(2, l.lv_refcount)
alloc_log:clear()
lib.emsg_skip = lib.emsg_skip + 1
@@ -1993,7 +2004,7 @@ describe('typval.c', function()
eq({test=10, tes={foo=42}}, dct2tbl(d))
eq(2, d2.dv_refcount)
eq(FAIL, check_emsg(function() return lib.tv_dict_add_dict(d, 'testt', 3, d2) end,
- 'E685: Internal error: hash_add()'))
+ 'E685: Internal error: hash_add(): duplicate key "tes"'))
eq(2, d2.dv_refcount)
alloc_log:clear()
lib.emsg_skip = lib.emsg_skip + 1
@@ -2015,7 +2026,7 @@ describe('typval.c', function()
alloc_log:check({a.di(dis.tes, 'tes')})
eq({test=10, tes=int(2)}, dct2tbl(d))
eq(FAIL, check_emsg(function() return lib.tv_dict_add_nr(d, 'testt', 3, 2) end,
- 'E685: Internal error: hash_add()'))
+ 'E685: Internal error: hash_add(): duplicate key "tes"'))
alloc_log:clear()
lib.emsg_skip = lib.emsg_skip + 1
eq(FAIL, check_emsg(function() return lib.tv_dict_add_nr(d, 'testt', 3, 2) end,
@@ -2035,7 +2046,7 @@ describe('typval.c', function()
alloc_log:check({a.di(dis.tes, 'tes')})
eq({test=10, tes=1.5}, dct2tbl(d))
eq(FAIL, check_emsg(function() return lib.tv_dict_add_float(d, 'testt', 3, 1.5) end,
- 'E685: Internal error: hash_add()'))
+ 'E685: Internal error: hash_add(): duplicate key "tes"'))
alloc_log:clear()
lib.emsg_skip = lib.emsg_skip + 1
eq(FAIL, check_emsg(function() return lib.tv_dict_add_float(d, 'testt', 3, 1.5) end,
@@ -2058,7 +2069,7 @@ describe('typval.c', function()
})
eq({test=10, tes='TEST'}, dct2tbl(d))
eq(FAIL, check_emsg(function() return lib.tv_dict_add_str(d, 'testt', 3, 'TEST') end,
- 'E685: Internal error: hash_add()'))
+ 'E685: Internal error: hash_add(): duplicate key "tes"'))
alloc_log:clear()
lib.emsg_skip = lib.emsg_skip + 1
eq(FAIL, check_emsg(function() return lib.tv_dict_add_str(d, 'testt', 3, 'TEST') end,
@@ -2088,7 +2099,7 @@ describe('typval.c', function()
})
eq({test=10, tes='TEST'}, dct2tbl(d))
eq(FAIL, check_emsg(function() return lib.tv_dict_add_allocated_str(d, 'testt', 3, s2) end,
- 'E685: Internal error: hash_add()'))
+ 'E685: Internal error: hash_add(): duplicate key "tes"'))
alloc_log:clear()
lib.emsg_skip = lib.emsg_skip + 1
eq(FAIL, check_emsg(function() return lib.tv_dict_add_allocated_str(d, 'testt', 3, s3) end,
@@ -2834,14 +2845,14 @@ describe('typval.c', function()
alloc_log:clear()
for _, v in ipairs({
{lib.VAR_NUMBER, nil},
- {lib.VAR_FLOAT, 'E806: using Float as a String'},
- {lib.VAR_PARTIAL, 'E729: using Funcref as a String'},
- {lib.VAR_FUNC, 'E729: using Funcref as a String'},
- {lib.VAR_LIST, 'E730: using List as a String'},
- {lib.VAR_DICT, 'E731: using Dictionary as a String'},
+ {lib.VAR_FLOAT, nil},
+ {lib.VAR_PARTIAL, 'E729: Using a Funcref as a String'},
+ {lib.VAR_FUNC, 'E729: Using a Funcref as a String'},
+ {lib.VAR_LIST, 'E730: Using a List as a String'},
+ {lib.VAR_DICT, 'E731: Using a Dictionary as a String'},
{lib.VAR_BOOL, nil},
{lib.VAR_SPECIAL, nil},
- {lib.VAR_UNKNOWN, 'E908: using an invalid value as a String'},
+ {lib.VAR_UNKNOWN, 'E908: Using an invalid value as a String'},
}) do
local typ = v[1]
local emsg = v[2]
@@ -2981,179 +2992,118 @@ describe('typval.c', function()
end
end)
end)
+
+ local function test_string_fn(input, fn)
+ for _, v in ipairs(input) do
+ -- Using to_cstr in place of Neovim allocated string, cannot
+ -- tv_clear() that.
+ local tv = ffi.gc(typvalt(v[1], v[2]), nil)
+ alloc_log:check({})
+ local emsg = v[3]
+ local ret = v[4]
+ eq(ret, check_emsg(function()
+ local res, buf = fn(tv)
+ if tv.v_type == lib.VAR_NUMBER or tv.v_type == lib.VAR_FLOAT
+ or tv.v_type == lib.VAR_SPECIAL or tv.v_type == lib.VAR_BOOL then
+ eq(buf, res)
+ else
+ neq(buf, res)
+ end
+ if res ~= nil then
+ return ffi.string(res)
+ else
+ return nil
+ end
+ end, emsg))
+ if emsg then
+ alloc_log:clear()
+ elseif tv.v_type == lib.VAR_FLOAT then
+ alloc_log:check({a.freed(alloc_log.null), a.freed(alloc_log.null)})
+ else
+ alloc_log:check({})
+ end
+ end
+ end
describe('string()', function()
itp('works', function()
local buf = lib.tv_get_string(lua2typvalt(int(1)))
local buf_chk = lib.tv_get_string_chk(lua2typvalt(int(1)))
neq(buf, buf_chk)
- for _, v in ipairs({
+ test_string_fn({
{lib.VAR_NUMBER, {v_number=42}, nil, '42'},
{lib.VAR_STRING, {v_string=to_cstr('100500')}, nil, '100500'},
- {lib.VAR_FLOAT, {v_float=42.53}, 'E806: using Float as a String', ''},
- {lib.VAR_PARTIAL, {v_partial=NULL}, 'E729: using Funcref as a String', ''},
- {lib.VAR_FUNC, {v_string=NULL}, 'E729: using Funcref as a String', ''},
- {lib.VAR_LIST, {v_list=NULL}, 'E730: using List as a String', ''},
- {lib.VAR_DICT, {v_dict=NULL}, 'E731: using Dictionary as a String', ''},
+ {lib.VAR_FLOAT, {v_float=42.53}, nil, '42.53'},
+ {lib.VAR_PARTIAL, {v_partial=NULL}, 'E729: Using a Funcref as a String', ''},
+ {lib.VAR_FUNC, {v_string=NULL}, 'E729: Using a Funcref as a String', ''},
+ {lib.VAR_LIST, {v_list=NULL}, 'E730: Using a List as a String', ''},
+ {lib.VAR_DICT, {v_dict=NULL}, 'E731: Using a Dictionary as a String', ''},
{lib.VAR_SPECIAL, {v_special=lib.kSpecialVarNull}, nil, 'v:null'},
{lib.VAR_BOOL, {v_bool=lib.kBoolVarTrue}, nil, 'v:true'},
{lib.VAR_BOOL, {v_bool=lib.kBoolVarFalse}, nil, 'v:false'},
- {lib.VAR_UNKNOWN, nil, 'E908: using an invalid value as a String', ''},
- }) do
- -- Using to_cstr in place of Neovim allocated string, cannot
- -- tv_clear() that.
- local tv = ffi.gc(typvalt(v[1], v[2]), nil)
- alloc_log:check({})
- local emsg = v[3]
- local ret = v[4]
- eq(ret, check_emsg(function()
- local res = lib.tv_get_string(tv)
- if tv.v_type == lib.VAR_NUMBER or tv.v_type == lib.VAR_SPECIAL
- or tv.v_type == lib.VAR_BOOL then
- eq(buf, res)
- else
- neq(buf, res)
- end
- if res ~= nil then
- return ffi.string(res)
- else
- return nil
- end
- end, emsg))
- if emsg then
- alloc_log:clear()
- else
- alloc_log:check({})
- end
- end
+ {lib.VAR_UNKNOWN, nil, 'E908: Using an invalid value as a String', ''},
+ }, function(tv)
+ return lib.tv_get_string(tv), buf
+ end)
end)
end)
describe('string_chk()', function()
itp('works', function()
local buf = lib.tv_get_string_chk(lua2typvalt(int(1)))
- for _, v in ipairs({
+ test_string_fn({
{lib.VAR_NUMBER, {v_number=42}, nil, '42'},
{lib.VAR_STRING, {v_string=to_cstr('100500')}, nil, '100500'},
- {lib.VAR_FLOAT, {v_float=42.53}, 'E806: using Float as a String', nil},
- {lib.VAR_PARTIAL, {v_partial=NULL}, 'E729: using Funcref as a String', nil},
- {lib.VAR_FUNC, {v_string=NULL}, 'E729: using Funcref as a String', nil},
- {lib.VAR_LIST, {v_list=NULL}, 'E730: using List as a String', nil},
- {lib.VAR_DICT, {v_dict=NULL}, 'E731: using Dictionary as a String', nil},
+ {lib.VAR_FLOAT, {v_float=42.53}, nil, '42.53'},
+ {lib.VAR_PARTIAL, {v_partial=NULL}, 'E729: Using a Funcref as a String', nil},
+ {lib.VAR_FUNC, {v_string=NULL}, 'E729: Using a Funcref as a String', nil},
+ {lib.VAR_LIST, {v_list=NULL}, 'E730: Using a List as a String', nil},
+ {lib.VAR_DICT, {v_dict=NULL}, 'E731: Using a Dictionary as a String', nil},
{lib.VAR_SPECIAL, {v_special=lib.kSpecialVarNull}, nil, 'v:null'},
{lib.VAR_BOOL, {v_bool=lib.kBoolVarTrue}, nil, 'v:true'},
{lib.VAR_BOOL, {v_bool=lib.kBoolVarFalse}, nil, 'v:false'},
- {lib.VAR_UNKNOWN, nil, 'E908: using an invalid value as a String', nil},
- }) do
- -- Using to_cstr, cannot free with tv_clear
- local tv = ffi.gc(typvalt(v[1], v[2]), nil)
- alloc_log:check({})
- local emsg = v[3]
- local ret = v[4]
- eq(ret, check_emsg(function()
- local res = lib.tv_get_string_chk(tv)
- if tv.v_type == lib.VAR_NUMBER or tv.v_type == lib.VAR_SPECIAL
- or tv.v_type == lib.VAR_BOOL then
- eq(buf, res)
- else
- neq(buf, res)
- end
- if res ~= nil then
- return ffi.string(res)
- else
- return nil
- end
- end, emsg))
- if emsg then
- alloc_log:clear()
- else
- alloc_log:check({})
- end
- end
+ {lib.VAR_UNKNOWN, nil, 'E908: Using an invalid value as a String', nil},
+ }, function(tv)
+ return lib.tv_get_string_chk(tv), buf
+ end)
end)
end)
describe('string_buf()', function()
itp('works', function()
- for _, v in ipairs({
+ test_string_fn({
{lib.VAR_NUMBER, {v_number=42}, nil, '42'},
{lib.VAR_STRING, {v_string=to_cstr('100500')}, nil, '100500'},
- {lib.VAR_FLOAT, {v_float=42.53}, 'E806: using Float as a String', ''},
- {lib.VAR_PARTIAL, {v_partial=NULL}, 'E729: using Funcref as a String', ''},
- {lib.VAR_FUNC, {v_string=NULL}, 'E729: using Funcref as a String', ''},
- {lib.VAR_LIST, {v_list=NULL}, 'E730: using List as a String', ''},
- {lib.VAR_DICT, {v_dict=NULL}, 'E731: using Dictionary as a String', ''},
+ {lib.VAR_FLOAT, {v_float=42.53}, nil, '42.53'},
+ {lib.VAR_PARTIAL, {v_partial=NULL}, 'E729: Using a Funcref as a String', ''},
+ {lib.VAR_FUNC, {v_string=NULL}, 'E729: Using a Funcref as a String', ''},
+ {lib.VAR_LIST, {v_list=NULL}, 'E730: Using a List as a String', ''},
+ {lib.VAR_DICT, {v_dict=NULL}, 'E731: Using a Dictionary as a String', ''},
{lib.VAR_SPECIAL, {v_special=lib.kSpecialVarNull}, nil, 'v:null'},
{lib.VAR_BOOL, {v_bool=lib.kBoolVarTrue}, nil, 'v:true'},
{lib.VAR_BOOL, {v_bool=lib.kBoolVarFalse}, nil, 'v:false'},
- {lib.VAR_UNKNOWN, nil, 'E908: using an invalid value as a String', ''},
- }) do
- -- Using to_cstr, cannot free with tv_clear
- local tv = ffi.gc(typvalt(v[1], v[2]), nil)
- alloc_log:check({})
- local emsg = v[3]
- local ret = v[4]
- eq(ret, check_emsg(function()
- local buf = ffi.new('char[?]', lib.NUMBUFLEN, {0})
- local res = lib.tv_get_string_buf(tv, buf)
- if tv.v_type == lib.VAR_NUMBER or tv.v_type == lib.VAR_SPECIAL
- or tv.v_type == lib.VAR_BOOL then
- eq(buf, res)
- else
- neq(buf, res)
- end
- if res ~= nil then
- return ffi.string(res)
- else
- return nil
- end
- end, emsg))
- if emsg then
- alloc_log:clear()
- else
- alloc_log:check({})
- end
- end
+ {lib.VAR_UNKNOWN, nil, 'E908: Using an invalid value as a String', ''},
+ }, function(tv)
+ local buf = ffi.new('char[?]', lib.NUMBUFLEN, {0})
+ return lib.tv_get_string_buf(tv, buf), buf
+ end)
end)
end)
describe('string_buf_chk()', function()
itp('works', function()
- for _, v in ipairs({
+ test_string_fn({
{lib.VAR_NUMBER, {v_number=42}, nil, '42'},
{lib.VAR_STRING, {v_string=to_cstr('100500')}, nil, '100500'},
- {lib.VAR_FLOAT, {v_float=42.53}, 'E806: using Float as a String', nil},
- {lib.VAR_PARTIAL, {v_partial=NULL}, 'E729: using Funcref as a String', nil},
- {lib.VAR_FUNC, {v_string=NULL}, 'E729: using Funcref as a String', nil},
- {lib.VAR_LIST, {v_list=NULL}, 'E730: using List as a String', nil},
- {lib.VAR_DICT, {v_dict=NULL}, 'E731: using Dictionary as a String', nil},
+ {lib.VAR_FLOAT, {v_float=42.53}, nil, '42.53'},
+ {lib.VAR_PARTIAL, {v_partial=NULL}, 'E729: Using a Funcref as a String', nil},
+ {lib.VAR_FUNC, {v_string=NULL}, 'E729: Using a Funcref as a String', nil},
+ {lib.VAR_LIST, {v_list=NULL}, 'E730: Using a List as a String', nil},
+ {lib.VAR_DICT, {v_dict=NULL}, 'E731: Using a Dictionary as a String', nil},
{lib.VAR_SPECIAL, {v_special=lib.kSpecialVarNull}, nil, 'v:null'},
{lib.VAR_BOOL, {v_bool=lib.kBoolVarTrue}, nil, 'v:true'},
{lib.VAR_BOOL, {v_bool=lib.kBoolVarFalse}, nil, 'v:false'},
- {lib.VAR_UNKNOWN, nil, 'E908: using an invalid value as a String', nil},
- }) do
- -- Using to_cstr, cannot free with tv_clear
- local tv = ffi.gc(typvalt(v[1], v[2]), nil)
- alloc_log:check({})
- local emsg = v[3]
- local ret = v[4]
- eq(ret, check_emsg(function()
- local buf = ffi.new('char[?]', lib.NUMBUFLEN, {0})
- local res = lib.tv_get_string_buf_chk(tv, buf)
- if tv.v_type == lib.VAR_NUMBER or tv.v_type == lib.VAR_SPECIAL
- or tv.v_type == lib.VAR_BOOL then
- eq(buf, res)
- else
- neq(buf, res)
- end
- if res ~= nil then
- return ffi.string(res)
- else
- return nil
- end
- end, emsg))
- if emsg then
- alloc_log:clear()
- else
- alloc_log:check({})
- end
- end
+ {lib.VAR_UNKNOWN, nil, 'E908: Using an invalid value as a String', nil},
+ }, function(tv)
+ local buf = ffi.new('char[?]', lib.NUMBUFLEN, {0})
+ return lib.tv_get_string_buf_chk(tv, buf), buf
+ end)
end)
end)
end)
diff --git a/test/unit/fixtures/multiqueue.c b/test/unit/fixtures/multiqueue.c
index a8dca0a844..3a5ddab4b8 100644
--- a/test/unit/fixtures/multiqueue.c
+++ b/test/unit/fixtures/multiqueue.c
@@ -1,19 +1,16 @@
-// This is an open source non-commercial project. Dear PVS-Studio, please check
-// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
-
#include <string.h>
#include <stdlib.h>
#include "nvim/event/multiqueue.h"
#include "multiqueue.h"
-void ut_multiqueue_put(MultiQueue *this, const char *str)
+void ut_multiqueue_put(MultiQueue *self, const char *str)
{
- multiqueue_put(this, NULL, 1, str);
+ multiqueue_put(self, NULL, 1, str);
}
-const char *ut_multiqueue_get(MultiQueue *this)
+const char *ut_multiqueue_get(MultiQueue *self)
{
- Event event = multiqueue_get(this);
+ Event event = multiqueue_get(self);
return event.argv[0];
}
diff --git a/test/unit/fixtures/rbuffer.c b/test/unit/fixtures/rbuffer.c
index efa7ab1986..d587d6b054 100644
--- a/test/unit/fixtures/rbuffer.c
+++ b/test/unit/fixtures/rbuffer.c
@@ -1,6 +1,3 @@
-// This is an open source non-commercial project. Dear PVS-Studio, please check
-// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
-
#include "nvim/rbuffer.h"
#include "rbuffer.h"
@@ -15,7 +12,7 @@ void ut_rbuffer_each_read_chunk(RBuffer *buf, each_ptr_cb cb)
void ut_rbuffer_each_write_chunk(RBuffer *buf, each_ptr_cb cb)
{
- RBUFFER_UNTIL_FULL(buf, wptr, wcnt) { // -V1044
+ RBUFFER_UNTIL_FULL(buf, wptr, wcnt) {
cb(wptr, wcnt);
rbuffer_produced(buf, wcnt);
}
diff --git a/test/unit/formatc.lua b/test/unit/formatc.lua
index 2fd37c599a..c94f0d88f7 100644
--- a/test/unit/formatc.lua
+++ b/test/unit/formatc.lua
@@ -154,6 +154,8 @@ local C_keywords = set { -- luacheck: ignore
--
-- The first one will have a lot of false positives (the line '{' for
-- example), the second one is more unique.
+--- @param string
+--- @return string
local function formatc(str)
local toks = TokeniseC(str)
local result = {}
diff --git a/test/unit/helpers.lua b/test/unit/helpers.lua
index 14d8eda357..8d581dac49 100644
--- a/test/unit/helpers.lua
+++ b/test/unit/helpers.lua
@@ -14,20 +14,15 @@ local map = global_helpers.tbl_map
local eq = global_helpers.eq
local trim = global_helpers.trim
--- C constants.
-local NULL = ffi.cast('void*', 0)
-
-local OK = 1
-local FAIL = 0
-
-local cimport
-
-- add some standard header locations
for _, p in ipairs(Paths.include_paths) do
Preprocess.add_to_include_path(p)
end
-local child_pid = nil
+local child_pid = nil --- @type integer
+--- @generic F: function
+--- @param func F
+--- @return F
local function only_separate(func)
return function(...)
if child_pid ~= 0 then
@@ -36,9 +31,20 @@ local function only_separate(func)
return func(...)
end
end
-local child_calls_init = {}
-local child_calls_mod = nil
-local child_calls_mod_once = nil
+
+--- @class ChildCall
+--- @field func function
+--- @field args any[]
+
+--- @class ChildCallLog
+--- @field func string
+--- @field args any[]
+--- @field ret any?
+
+local child_calls_init = {} --- @type ChildCall[]
+local child_calls_mod = nil --- @type ChildCall[]
+local child_calls_mod_once = nil --- @type ChildCall[]?
+
local function child_call(func, ret)
return function(...)
local child_calls = child_calls_mod or child_calls_init
@@ -53,16 +59,16 @@ end
-- Run some code at the start of the child process, before running the test
-- itself. Is supposed to be run in `before_each`.
+--- @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
end
-local child_cleanups_mod_once = nil
+local child_cleanups_mod_once = nil --- @type ChildCall[]?
-- Run some code at the end of the child process, before exiting. Is supposed to
-- be run in `before_each` because `after_each` is run after child has exited.
@@ -75,7 +81,8 @@ local function child_cleanup_once(func, ...)
end
end
-local libnvim = nil
+-- Unittests are run from debug nvim binary in lua interpreter mode.
+local libnvim = ffi.C
local lib = setmetatable({}, {
__index = only_separate(function(_, idx)
@@ -87,13 +94,9 @@ local lib = setmetatable({}, {
})
local init = only_separate(function()
- -- load neovim shared library
- libnvim = ffi.load(Paths.test_libnvim_path)
for _, c in ipairs(child_calls_init) do
c.func(unpack(c.args))
end
- libnvim.time_init()
- libnvim.fs_init()
libnvim.event_init()
libnvim.early_init(nil)
if child_calls_mod then
@@ -126,15 +129,19 @@ local pragma_pack_id = 1
-- some things are just too complex for the LuaJIT C parser to digest. We
-- usually don't need them anyway.
+--- @param body string
local function filter_complex_blocks(body)
- local result = {}
+ 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
result[#result + 1] = line
@@ -149,19 +156,25 @@ local cdef = ffi.cdef
local cimportstr
-local previous_defines_init = ''
-local preprocess_cache_init = {}
+local previous_defines_init = [[
+typedef struct { char bytes[16]; } __attribute__((aligned(16))) __uint128_t;
+typedef struct { char bytes[16]; } __attribute__((aligned(16))) __float128;
+]]
+
+local preprocess_cache_init = {} --- @type table<string,string>
local previous_defines_mod = ''
-local preprocess_cache_mod = nil
+local preprocess_cache_mod = nil --- @type table<string,string>
local function is_child_cdefs()
- return (os.getenv('NVIM_TEST_MAIN_CDEFS') ~= '1')
+ return os.getenv('NVIM_TEST_MAIN_CDEFS') ~= '1'
end
-- use this helper to import C files, you can pass multiple paths at once,
-- this helper will return the C namespace of the nvim library.
-cimport = function(...)
- local previous_defines, preprocess_cache, cdefs
+local function cimport(...)
+ local previous_defines --- @type string
+ local preprocess_cache --- @type table<string,string>
+ local cdefs
if is_child_cdefs() and preprocess_cache_mod then
preprocess_cache = preprocess_cache_mod
previous_defines = previous_defines_mod
@@ -177,7 +190,7 @@ cimport = function(...)
path = './' .. path
end
if not preprocess_cache[path] then
- local body
+ local body --- @type string
body, previous_defines = Preprocess.preprocess(previous_defines, path)
-- format it (so that the lines are "unique" statements), also filter out
-- Objective-C blocks
@@ -199,6 +212,7 @@ cimport = function(...)
-- (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
+ --- @type string
line = line .. " // " .. pragma_pack_id
pragma_pack_id = pragma_pack_id + 1
end
@@ -226,20 +240,21 @@ cimport = function(...)
return lib
end
-local cimport_immediate = function(...)
+local function cimport_immediate(...)
local saved_pid = child_pid
child_pid = 0
local err, emsg = pcall(cimport, ...)
child_pid = saved_pid
if not err then
- emsg = tostring(emsg)
- io.stderr:write(emsg .. '\n')
+ io.stderr:write(tostring(emsg) .. '\n')
assert(false)
else
return lib
end
end
+--- @param preprocess_cache table<string,string[]>
+--- @param path string
local function _cimportstr(preprocess_cache, path)
if imported:contains(path) then
return lib
@@ -262,12 +277,14 @@ end
local function alloc_log_new()
local log = {
- log={},
- lib=cimport('./src/nvim/memory.h'),
- original_functions={},
+ 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'}
+
function log:save_original_functions()
for _, funcname in ipairs(allocator_functions) do
if not self.original_functions[funcname] then
@@ -275,13 +292,16 @@ local function alloc_log_new()
end
end
end
+
log.save_original_functions = child_call(log.save_original_functions)
+
function log:set_mocks()
for _, k in ipairs(allocator_functions) do
do
local kk = k
self.lib['mem_' .. k] = function(...)
- local log_entry = {func=kk, args={...}}
+ --- @type ChildCallLog
+ local log_entry = { func = kk, args = {...} }
self.log[#self.log + 1] = log_entry
if kk == 'free' then
self.original_functions[kk](...)
@@ -302,17 +322,21 @@ local function alloc_log_new()
end
end
end
+
log.set_mocks = child_call(log.set_mocks)
+
function log:clear()
self.log = {}
end
+
function log:check(exp)
eq(exp, self.log)
self:clear()
end
+
function log:clear_tmp_allocs(clear_null_frees)
- local toremove = {}
- local allocs = {}
+ local toremove = {} --- @type integer[]
+ local allocs = {} --- @type table<string,integer>
for i, v in ipairs(self.log) do
if v.func == 'malloc' or v.func == 'calloc' then
allocs[tostring(v.ret)] = i
@@ -335,26 +359,20 @@ local function alloc_log_new()
table.remove(self.log, toremove[i])
end
end
- function log:restore_original_functions()
- -- Do nothing: set mocks live in a separate process
- return
- --[[
- [ for k, v in pairs(self.original_functions) do
- [ self.lib['mem_' .. k] = v
- [ end
- ]]
- end
+
function log:setup()
log:save_original_functions()
log:set_mocks()
end
+
function log:before_each()
- return
end
+
function log:after_each()
- log:restore_original_functions()
end
+
log:setup()
+
return log
end
@@ -371,98 +389,109 @@ local function to_cstr(string)
end
cimport_immediate('./test/unit/fixtures/posix.h')
-local sc = {
- fork = function()
- return tonumber(ffi.C.fork())
- end,
- pipe = function()
- local ret = ffi.new('int[2]', {-1, -1})
- ffi.errno(0)
- local res = ffi.C.pipe(ret)
- if (res ~= 0) then
+
+local sc = {}
+
+function sc.fork()
+ return tonumber(ffi.C.fork())
+end
+
+function sc.pipe()
+ local ret = ffi.new('int[2]', {-1, -1})
+ ffi.errno(0)
+ local res = ffi.C.pipe(ret)
+ if (res ~= 0) then
+ local err = ffi.errno(0)
+ 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]
+end
+
+--- @return string
+function sc.read(rd, len)
+ 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))
+ if bytes_read == -1 then
local err = ffi.errno(0)
- 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]
- end,
- read = function(rd, len)
- 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))
- 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))))
- end
- elseif bytes_read == 0 then
- break
- else
- total_bytes_read = total_bytes_read + bytes_read
+ if err ~= ffi.C.kPOSIXErrnoEINTR then
+ assert(false, ("read() error: %u: %s"):format(
+ err, ffi.string(ffi.C.strerror(err))))
end
+ elseif bytes_read == 0 then
+ break
+ else
+ total_bytes_read = total_bytes_read + bytes_read
end
- return ffi.string(ret, total_bytes_read)
- end,
- write = function(wr, s)
- local wbuf = to_cstr(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))
- 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))
- end
- elseif bytes_written == 0 then
- break
- else
- total_bytes_written = total_bytes_written + bytes_written
+ end
+ return ffi.string(ret, total_bytes_read)
+end
+
+function sc.write(wr, s)
+ local wbuf = to_cstr(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))
+ 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))
end
+ elseif bytes_written == 0 then
+ break
+ else
+ total_bytes_written = total_bytes_written + bytes_written
end
- return total_bytes_written
- end,
- close = ffi.C.close,
- wait = function(pid)
- ffi.errno(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
- local err = ffi.errno(0)
- 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))))
- end
- else
- assert(r == pid)
+ end
+ return total_bytes_written
+end
+
+sc.close = ffi.C.close
+
+--- @param pid integer
+--- @return integer
+function sc.wait(pid)
+ ffi.errno(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
+ local err = ffi.errno(0)
+ 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))))
end
+ else
+ assert(r == pid)
end
- return stat_loc[0]
- end,
- exit = ffi.C._exit,
-}
+ end
+ return stat_loc[0]
+end
+sc.exit = ffi.C._exit
+
+--- @param lst string[]
+--- @return string
local function format_list(lst)
- local ret = ''
+ local ret = {} --- @type string[]
for _, v in ipairs(lst) do
- if ret ~= '' then ret = ret .. ', ' end
- ret = ret .. assert:format({v, n=1})[1]
+ ret[#ret+1] = assert:format({v, n=1})[1]
end
- return ret
+ return table.concat(ret, ', ')
end
if os.getenv('NVIM_TEST_PRINT_SYSCALLS') == '1' then
@@ -510,19 +539,26 @@ local tracehelp = dedent([[
]])
local function child_sethook(wr)
- local trace_level = os.getenv('NVIM_TEST_TRACE_LEVEL')
- if not trace_level or trace_level == '' then
- trace_level = 0
- else
- trace_level = tonumber(trace_level)
+ local trace_level_str = os.getenv('NVIM_TEST_TRACE_LEVEL')
+ local trace_level = 0
+ if trace_level_str and trace_level_str ~= '' then
+ --- @type number
+ trace_level = assert(tonumber(trace_level_str))
end
+
if trace_level <= 0 then
return
end
+
local trace_only_c = trace_level <= 1
+ --- @type debuginfo?, string?, integer
local prev_info, prev_reason, prev_lnum
+
+ --- @param reason string
+ --- @param lnum integer
+ --- @param use_prev boolean
local function hook(reason, lnum, use_prev)
- local info = nil
+ local info = nil --- @type debuginfo?
if use_prev then
info = prev_info
elseif reason ~= 'tail return' then -- tail return
@@ -530,6 +566,7 @@ local function child_sethook(wr)
end
if trace_only_c and (not info or info.what ~= 'C') and not use_prev then
+ --- @cast info -nil
if info.source:sub(-9) == '_spec.lua' then
prev_info = info
prev_reason = 'saved'
@@ -570,12 +607,8 @@ local function child_sethook(wr)
end
-- assert(-1 <= lnum and lnum <= 99999)
- local lnum_s
- if lnum == -1 then
- lnum_s = 'nknwn'
- else
- lnum_s = ('%u'):format(lnum)
- end
+ local lnum_s = lnum == -1 and 'nknwn' or ('%u'):format(lnum)
+ --- @type string
local msg = ( -- lua does not support %*
''
.. msgchar
@@ -597,6 +630,7 @@ end
local trace_end_msg = ('E%s\n'):format((' '):rep(hook_msglen - 2))
+--- @type function
local _debug_log
local debug_log = only_separate(function(...)
@@ -604,6 +638,7 @@ local debug_log = only_separate(function(...)
end)
local function itp_child(wr, func)
+ --- @param s string
_debug_log = function(s)
s = s:sub(1, hook_msglen - 2)
sc.write(wr, '>' .. s .. (' '):rep(hook_msglen - 2 - #s) .. '\n')
@@ -635,7 +670,7 @@ local function itp_child(wr, func)
end
local function check_child_err(rd)
- local trace = {}
+ local trace = {} --- @type string[]
local did_traceline = false
local maxtrace = tonumber(os.getenv('NVIM_TEST_MAXTRACE')) or 1024
while true do
@@ -665,11 +700,14 @@ local function check_child_err(rd)
local len = tonumber(len_s)
neq(0, len)
if os.getenv('NVIM_TEST_TRACE_ON_ERROR') == '1' and #trace ~= 0 then
+ --- @type string
err = '\nTest failed, trace:\n' .. tracehelp
for _, traceline in ipairs(trace) do
+ --- @type string
err = err .. traceline
end
end
+ --- @type string
err = err .. sc.read(rd, len + 1)
end
local eres = sc.read(rd, 2)
@@ -683,10 +721,12 @@ local function check_child_err(rd)
end
end
if not did_traceline then
+ --- @type string
err = err .. '\nNo end of trace occurred'
end
local cc_err, cc_emsg = pcall(check_cores, Paths.test_luajit_prg, true)
if not cc_err then
+ --- @type string
err = err .. '\ncheck_cores failed: ' .. cc_emsg
end
end
@@ -811,6 +851,17 @@ local function ptr2key(ptr)
return ffi.string(s)
end
+local function is_asan()
+ cimport('./src/nvim/version.h')
+ local status, res = pcall(function() return lib.version_cflags end)
+ if status then
+ return ffi.string(res):match('-fsanitize=[a-z,]*address')
+ else
+ return false
+ end
+end
+
+--- @class test.unit.helpers.module
local module = {
cimport = cimport,
cppimport = cppimport,
@@ -819,9 +870,9 @@ local module = {
lib = lib,
cstr = cstr,
to_cstr = to_cstr,
- NULL = NULL,
- OK = OK,
- FAIL = FAIL,
+ NULL = ffi.cast('void*', 0),
+ OK = 1,
+ FAIL = 0,
alloc_log_new = alloc_log_new,
gen_itp = gen_itp,
only_separate = only_separate,
@@ -838,8 +889,11 @@ local module = {
ptr2addr = ptr2addr,
ptr2key = ptr2key,
debug_log = debug_log,
+ is_asan = is_asan,
}
+--- @class test.unit.helpers: test.unit.helpers.module, test.helpers
module = global_helpers.tbl_extend('error', module, global_helpers)
+
return function()
return module
end
diff --git a/test/unit/keycodes_spec.lua b/test/unit/keycodes_spec.lua
index 5bf27c9232..4da3d37aaa 100644
--- a/test/unit/keycodes_spec.lua
+++ b/test/unit/keycodes_spec.lua
@@ -5,7 +5,7 @@ local ffi = helpers.ffi
local eq = helpers.eq
local neq = helpers.neq
-local keymap = helpers.cimport('./src/nvim/keycodes.h')
+local keycodes = helpers.cimport('./src/nvim/keycodes.h')
local NULL = helpers.NULL
describe('keycodes.c', function()
@@ -16,12 +16,12 @@ describe('keycodes.c', function()
itp('no keycode', function()
srcp[0] = 'abc'
- eq(0, keymap.find_special_key(srcp, 3, modp, 0, NULL))
+ eq(0, keycodes.find_special_key(srcp, 3, modp, 0, NULL))
end)
itp('keycode with multiple modifiers', function()
srcp[0] = '<C-M-S-A>'
- neq(0, keymap.find_special_key(srcp, 9, modp, 0, NULL))
+ neq(0, keycodes.find_special_key(srcp, 9, modp, 0, NULL))
neq(0, modp[0])
end)
@@ -29,22 +29,22 @@ describe('keycodes.c', function()
-- Compare other capitalizations to this.
srcp[0] = '<C-A>'
local all_caps_key =
- keymap.find_special_key(srcp, 5, modp, 0, NULL)
+ keycodes.find_special_key(srcp, 5, modp, 0, NULL)
local all_caps_mod = modp[0]
srcp[0] = '<C-a>'
eq(all_caps_key,
- keymap.find_special_key(srcp, 5, modp, 0, NULL))
+ keycodes.find_special_key(srcp, 5, modp, 0, NULL))
eq(all_caps_mod, modp[0])
srcp[0] = '<c-A>'
eq(all_caps_key,
- keymap.find_special_key(srcp, 5, modp, 0, NULL))
+ keycodes.find_special_key(srcp, 5, modp, 0, NULL))
eq(all_caps_mod, modp[0])
srcp[0] = '<c-a>'
eq(all_caps_key,
- keymap.find_special_key(srcp, 5, modp, 0, NULL))
+ keycodes.find_special_key(srcp, 5, modp, 0, NULL))
eq(all_caps_mod, modp[0])
end)
@@ -52,20 +52,20 @@ describe('keycodes.c', function()
-- Unescaped with in_string=false
srcp[0] = '<C-">'
eq(string.byte('"'),
- keymap.find_special_key(srcp, 5, modp, 0, NULL))
+ keycodes.find_special_key(srcp, 5, modp, 0, NULL))
-- Unescaped with in_string=true
- eq(0, keymap.find_special_key(srcp, 5, modp, keymap.FSK_IN_STRING, NULL))
+ eq(0, keycodes.find_special_key(srcp, 5, modp, keycodes.FSK_IN_STRING, NULL))
-- Escaped with in_string=false
srcp[0] = '<C-\\">'
-- Should fail because the key is invalid
-- (more than 1 non-modifier character).
- eq(0, keymap.find_special_key(srcp, 6, modp, 0, NULL))
+ eq(0, keycodes.find_special_key(srcp, 6, modp, 0, NULL))
-- Escaped with in_string=true
eq(string.byte('"'),
- keymap.find_special_key(srcp, 6, modp, keymap.FSK_IN_STRING, NULL))
+ keycodes.find_special_key(srcp, 6, modp, keycodes.FSK_IN_STRING, NULL))
end)
end)
diff --git a/test/unit/marktree_spec.lua b/test/unit/marktree_spec.lua
index 3c96bc5f58..3f9dd4df12 100644
--- a/test/unit/marktree_spec.lua
+++ b/test/unit/marktree_spec.lua
@@ -87,13 +87,18 @@ local function dosplice(tree, shadow, start, old_extent, new_extent)
shadowsplice(shadow, start, old_extent, new_extent)
end
+local ns = 10
local last_id = nil
-local function put(tree, row, col, gravitate)
+local function put(tree, row, col, gravitate, end_row, end_col, end_gravitate)
last_id = last_id + 1
local my_id = last_id
- lib.marktree_put_test(tree, my_id, row, col, gravitate);
+ end_row = end_row or -1
+ 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);
return my_id
end
@@ -102,7 +107,7 @@ describe('marktree', function()
last_id = 0
end)
- itp('works', function()
+ itp('works', function()
local tree = ffi.new("MarkTree[1]") -- zero initialized by luajit
local shadow = {}
local iter = ffi.new("MarkTreeIter[1]")
@@ -129,7 +134,7 @@ describe('marktree', function()
eq({}, id2pos)
for i,ipos in pairs(shadow) do
- local p = lib.marktree_lookup_ns(tree, -1, i, false, iter)
+ local p = lib.marktree_lookup_ns(tree, ns, i, false, iter)
eq(ipos[1], p.pos.row)
eq(ipos[2], p.pos.col)
local k = lib.marktree_itr_current(iter)
@@ -210,10 +215,330 @@ describe('marktree', function()
lib.marktree_itr_get(tree, 10, 10, iter)
lib.marktree_del_itr(tree, iter, false)
- eq(11, iter[0].node.key[iter[0].i].pos.col)
+ eq(11, iter[0].x.key[iter[0].i].pos.col)
lib.marktree_itr_get(tree, 11, 11, iter)
lib.marktree_del_itr(tree, iter, false)
- eq(12, iter[0].node.key[iter[0].i].pos.col)
- end)
+ eq(12, iter[0].x.key[iter[0].i].pos.col)
+ end)
+
+ 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 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]")
+ wsize[0] = dummy_size
+ 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
+
+ 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}
+ 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({{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
+ if true == true then
+ ok(lib.marktree_check_intersections(tree))
+ return
+ end
+
+ local str1 = lib.mt_inspect(tree, true, true)
+ local dot1 = ffi.string(str1.data, str1.size)
+
+ local val = lib.marktree_check_intersections(tree)
+ 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);
+ io.stdout:flush()
+ local afil = io.open("Xafile.dot", "wb")
+ afil:write(dot1)
+ afil:close()
+ local efil = io.open("Xefile.dot", "wb")
+ efil:write(dot2)
+ efil:close()
+ ok(false)
+ else
+ ffi.C.xfree(str1.data)
+ end
+ end
+
+ itp('works with intersections', function()
+ 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))
+ check_intersections(tree)
+ end
+ 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))
+ check_intersections(tree)
+ end
+
+ 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
+ end
+ end)
+
+ itp('works with intersections with a big tree', function()
+ 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))
+ if i % 10 == 1 then
+ check_intersections(tree)
+ end
+ end
+
+ check_intersections(tree)
+ eq(2000, tree[0].n_keys)
+ ok(tree[0].root.level >= 2)
+
+ local iter = ffi.new("MarkTreeIter[1]")
+
+ local k = 0
+ for i = 1,20 do
+ for j = 1,50 do
+ k = k + 1
+ 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)
+ check_intersections(tree)
+
+ lib.marktree_lookup_ns(tree, ns, ids[ival], true, iter)
+ lib.marktree_del_itr(tree, iter, false)
+ check_intersections(tree)
+ else
+ lib.marktree_del_pair_test(tree, ns, ids[ival])
+ if k % 5 == 1 then
+ check_intersections(tree)
+ end
+ end
+ end
+ end
+
+ eq(0, tree[0].n_keys)
+ end)
+
+ itp('works with intersections and marktree_splice', function()
+ local tree = ffi.new("MarkTree[1]") -- zero initialized by luajit
+
+ for i = 1,1000 do
+ put(tree, 1, i, false, 2, 1000-i, false)
+ if i % 10 == 1 then
+ check_intersections(tree)
+ end
+ end
+
+ check_intersections(tree)
+ eq(2000, tree[0].n_keys)
+ ok(tree[0].root.level >= 2)
+
+ 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 ids = {}
+
+ -- new index and old index look the same, but still have to move because
+ -- pos will get updated
+ table.insert(ids, put(tree, 1, 1, false, 1, 3, false))
+ table.insert(ids, put(tree, 1, 3, false, 1, 3, false))
+ table.insert(ids, put(tree, 1, 3, false, 1, 3, false))
+ table.insert(ids, put(tree, 1, 3, false, 1, 3, false))
+
+ lib.marktree_lookup_ns(tree, ns, ids[3], false, iter)
+ lib.marktree_move(tree, iter, 1, 2)
+
+ check_intersections(tree)
+ end)
+
+ itp('works with intersections and marktree_move', function()
+ 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))
+ 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
+ lib.marktree_lookup_ns(tree, ns, ids[i], which, iter)
+ 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 ids = {}
+
+ -- too much overhead on ASAN
+ local size_factor = helpers.is_asan() and 3 or 10
+
+ local at_row = {}
+ for i = 1, 10 do
+ at_row[i] = {}
+ end
+
+ 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
+ if k > size then
+ break
+ end
+ local id = put(tree, row1, k, false, row2, size-k, false)
+ table.insert(ids, id)
+ 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
+ check_intersections(tree)
+ end
+ k = k + 1
+ end
+ end
+ end
+
+ 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
+ -- 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))
+ while ffi.C.marktree_itr_step_overlap(tree, iter, pair) do
+ local id = tonumber(pair[0].start.id)
+ table.insert(set, id)
+ end
+ table.sort(set)
+ eq(at_row[i], set)
+ end
+
+ k = 0
+ for i = 1,100 do
+ for j = 1,(10*size_factor) do
+ k = k + 1
+ 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
+ check_intersections(tree)
+ end
+ end
+ end
+
+ eq(0, tree[0].n_keys)
+ end)
+
+ itp('works with intersections with a even bigger tree and splice', function()
+ 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
+
+ local at_row = {}
+ for i = 1, 10 do
+ at_row[i] = {}
+ end
+
+ 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
+ if k > size then
+ break
+ end
+ 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
+ check_intersections(tree)
+ end
+ k = k + 1
+ end
+ end
+ end
+
+ eq(2*size, tree[0].n_keys)
+ ok(tree[0].root.level >= 3)
+ check_intersections(tree)
+
+ for _ = 1,10 do
+ for j = 3, 8 do
+ lib.marktree_splice(tree, j, 0, 0, 200, 0, 0)
+ check_intersections(tree)
+ end
+ end
+ end)
end)
diff --git a/test/unit/mbyte_spec.lua b/test/unit/mbyte_spec.lua
index fdb1bceab0..cd94624570 100644
--- a/test/unit/mbyte_spec.lua
+++ b/test/unit/mbyte_spec.lua
@@ -4,17 +4,9 @@ local itp = helpers.gen_itp(it)
local ffi = helpers.ffi
local eq = helpers.eq
-local mbyte = helpers.cimport("./src/nvim/mbyte.h")
-local charset = helpers.cimport('./src/nvim/charset.h')
+local lib = helpers.cimport('./src/nvim/mbyte.h', './src/nvim/charset.h', './src/nvim/grid.h')
describe('mbyte', function()
- -- Array for composing characters
- local intp = ffi.typeof('int[?]')
- local function to_intp()
- -- how to get MAX_MCO from globals.h?
- return intp(7, 1)
- end
-
-- Convert from bytes to string
local function to_string(bytes)
local s = {}
@@ -30,14 +22,14 @@ describe('mbyte', function()
itp('utf_ptr2char', function()
-- For strings with length 1 the first byte is returned.
for c = 0, 255 do
- eq(c, mbyte.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
-- First byte: 0xc0 or 0xc1
-- Second byte: 0x80 .. 0xbf
- --eq(0x00c0, mbyte.utf_ptr2char(to_string({0xc0, 0x80})))
- --eq(0x00c1, mbyte.utf_ptr2char(to_string({0xc1, 0xbf})))
+ --eq(0x00c0, lib.utf_ptr2char(to_string({0xc0, 0x80})))
+ --eq(0x00c1, lib.utf_ptr2char(to_string({0xc1, 0xbf})))
--
-- Sequences with more than four bytes
end)
@@ -47,240 +39,133 @@ describe('mbyte', function()
local char_p = ffi.typeof('char[?]')
for c = n * 0x1000, n * 0x1000 + 0xFFF do
local p = char_p(4, 0)
- mbyte.utf_char2bytes(c, p)
- eq(c, mbyte.utf_ptr2char(p))
- eq(charset.vim_iswordc(c), charset.vim_iswordp(p))
+ lib.utf_char2bytes(c, p)
+ eq(c, lib.utf_ptr2char(p))
+ eq(lib.vim_iswordc(c), lib.vim_iswordp(p))
end
end)
end
- describe('utfc_ptr2char_len', function()
+ describe('utfc_ptr2schar_len', function()
+ local function test_seq(seq)
+ local firstc = ffi.new("int[1]")
+ local buf = ffi.new("char[32]")
+ lib.schar_get(buf, lib.utfc_ptr2schar_len(to_string(seq), #seq, firstc))
+ return {ffi.string(buf), firstc[0]}
+ end
+
+ local function byte(val)
+ return {string.char(val), val}
+ end
itp('1-byte sequences', function()
- local pcc = to_intp()
- for c = 0, 255 do
- eq(c, mbyte.utfc_ptr2char_len(to_string({c}), pcc, 1))
- eq(0, pcc[0])
+ eq({'', 0}, test_seq{0})
+ for c = 1, 127 do
+ eq(byte(c), test_seq{c})
+ end
+ for c = 128, 255 do
+ eq({'', c}, test_seq{c})
end
end)
itp('2-byte sequences', function()
- local pcc = to_intp()
-- No combining characters
- eq(0x007f, mbyte.utfc_ptr2char_len(to_string({0x7f, 0x7f}), pcc, 2))
- eq(0, pcc[0])
+ eq(byte(0x7f), test_seq{0x7f, 0x7f})
-- No combining characters
- pcc = to_intp()
- eq(0x007f, mbyte.utfc_ptr2char_len(to_string({0x7f, 0x80}), pcc, 2))
- eq(0, pcc[0])
+ eq(byte(0x7f), test_seq{0x7f, 0x80})
-- No UTF-8 sequence
- pcc = to_intp()
- eq(0x00c2, mbyte.utfc_ptr2char_len(to_string({0xc2, 0x7f}), pcc, 2))
- eq(0, pcc[0])
+ eq({'', 0xc2}, test_seq{0xc2, 0x7f})
-- One UTF-8 character
- pcc = to_intp()
- eq(0x0080, mbyte.utfc_ptr2char_len(to_string({0xc2, 0x80}), pcc, 2))
- eq(0, pcc[0])
+ eq({'\xc2\x80', 0x80}, test_seq{0xc2, 0x80})
-- No UTF-8 sequence
- pcc = to_intp()
- eq(0x00c2, mbyte.utfc_ptr2char_len(to_string({0xc2, 0xc0}), pcc, 2))
- eq(0, pcc[0])
+ eq({'', 0xc2}, test_seq{0xc2, 0xc0})
end)
itp('3-byte sequences', function()
- local pcc = to_intp()
-
-- No second UTF-8 character
- eq(0x007f, mbyte.utfc_ptr2char_len(to_string({0x7f, 0x80, 0x80}), pcc, 3))
- eq(0, pcc[0])
+ eq(byte(0x7f), test_seq{0x7f, 0x80, 0x80})
-- No combining character
- pcc = to_intp()
- eq(0x007f, mbyte.utfc_ptr2char_len(to_string({0x7f, 0xc2, 0x80}), pcc, 3))
- eq(0, pcc[0])
+ eq(byte(0x7f), test_seq{0x7f, 0xc2, 0x80})
-- Combining character is U+0300
- pcc = to_intp()
- eq(0x007f, mbyte.utfc_ptr2char_len(to_string({0x7f, 0xcc, 0x80}), pcc, 3))
- eq(0x0300, pcc[0])
- eq(0x0000, pcc[1])
+ eq({"\x7f\xcc\x80", 0x7f}, test_seq{0x7f, 0xcc, 0x80})
-- No UTF-8 sequence
- pcc = to_intp()
- eq(0x00c2, mbyte.utfc_ptr2char_len(to_string({0xc2, 0x7f, 0xcc}), pcc, 3))
- eq(0, pcc[0])
+ eq({'', 0xc2}, test_seq{0xc2, 0x7f, 0xcc})
-- Incomplete combining character
- pcc = to_intp()
- eq(0x0080, mbyte.utfc_ptr2char_len(to_string({0xc2, 0x80, 0xcc}), pcc, 3))
- eq(0, pcc[0])
+ eq({"\xc2\x80", 0x80}, test_seq{0xc2, 0x80, 0xcc})
- -- One UTF-8 character
- pcc = to_intp()
- eq(0x20d0, mbyte.utfc_ptr2char_len(to_string({0xe2, 0x83, 0x90}), pcc, 3))
- eq(0, pcc[0])
+ -- One UTF-8 character (composing only)
+ eq({" \xe2\x83\x90", 0x20d0}, test_seq{0xe2, 0x83, 0x90})
end)
itp('4-byte sequences', function()
- local pcc = to_intp()
-- No following combining character
- eq(0x007f, mbyte.utfc_ptr2char_len(to_string({0x7f, 0x7f, 0xcc, 0x80}), pcc, 4))
- eq(0, pcc[0])
+ eq(byte(0x7f), test_seq{0x7f, 0x7f, 0xcc, 0x80})
-- No second UTF-8 character
- pcc = to_intp()
- eq(0x007f, mbyte.utfc_ptr2char_len(to_string({0x7f, 0xc2, 0xcc, 0x80}), pcc, 4))
- eq(0, pcc[0])
+ eq(byte(0x7f), test_seq{0x7f, 0xc2, 0xcc, 0x80})
-- Combining character U+0300
- pcc = to_intp()
- eq(0x007f, mbyte.utfc_ptr2char_len(to_string({0x7f, 0xcc, 0x80, 0xcc}), pcc, 4))
- eq(0x0300, pcc[0])
- eq(0x0000, pcc[1])
+ eq({"\x7f\xcc\x80", 0x7f}, test_seq{0x7f, 0xcc, 0x80, 0xcc})
-- No UTF-8 sequence
- pcc = to_intp()
- eq(0x00c2, mbyte.utfc_ptr2char_len(to_string({0xc2, 0x7f, 0xcc, 0x80}), pcc, 4))
- eq(0, pcc[0])
+ eq({'', 0xc2}, test_seq{0xc2, 0x7f, 0xcc, 0x80})
-- No following UTF-8 character
- pcc = to_intp()
- eq(0x0080, mbyte.utfc_ptr2char_len(to_string({0xc2, 0x80, 0xcc, 0xcc}), pcc, 4))
- eq(0, pcc[0])
+ eq({"\xc2\x80", 0x80}, test_seq{0xc2, 0x80, 0xcc, 0xcc})
-- Combining character U+0301
- pcc = to_intp()
- eq(0x0080, mbyte.utfc_ptr2char_len(to_string({0xc2, 0x80, 0xcc, 0x81}), pcc, 4))
- eq(0x0301, pcc[0])
- eq(0x0000, pcc[1])
+ eq({"\xc2\x80\xcc\x81", 0x80}, test_seq{0xc2, 0x80, 0xcc, 0x81})
-- One UTF-8 character
- pcc = to_intp()
- eq(0x100000, mbyte.utfc_ptr2char_len(to_string({0xf4, 0x80, 0x80, 0x80}), pcc, 4))
- eq(0, pcc[0])
+ eq({"\xf4\x80\x80\x80", 0x100000}, test_seq{0xf4, 0x80, 0x80, 0x80})
end)
itp('5+-byte sequences', function()
- local pcc = to_intp()
-
-- No following combining character
- eq(0x007f, mbyte.utfc_ptr2char_len(to_string({0x7f, 0x7f, 0xcc, 0x80, 0x80}), pcc, 5))
- eq(0, pcc[0])
+ eq(byte(0x7f), test_seq{0x7f, 0x7f, 0xcc, 0x80, 0x80})
-- No second UTF-8 character
- pcc = to_intp()
- eq(0x007f, mbyte.utfc_ptr2char_len(to_string({0x7f, 0xc2, 0xcc, 0x80, 0x80}), pcc, 5))
- eq(0, pcc[0])
+ eq(byte(0x7f), test_seq{0x7f, 0xc2, 0xcc, 0x80, 0x80})
-- Combining character U+0300
- pcc = to_intp()
- eq(0x007f, mbyte.utfc_ptr2char_len(to_string({0x7f, 0xcc, 0x80, 0xcc}), pcc, 5))
- eq(0x0300, pcc[0])
- eq(0x0000, pcc[1])
+ eq({"\x7f\xcc\x80", 0x7f}, test_seq{0x7f, 0xcc, 0x80, 0xcc, 0x00})
-- Combining characters U+0300 and U+0301
- pcc = to_intp()
- eq(0x007f, mbyte.utfc_ptr2char_len(to_string({0x7f, 0xcc, 0x80, 0xcc, 0x81}), pcc, 5))
- eq(0x0300, pcc[0])
- eq(0x0301, pcc[1])
- eq(0x0000, pcc[2])
+ eq({"\x7f\xcc\x80\xcc\x81", 0x7f}, test_seq{0x7f, 0xcc, 0x80, 0xcc, 0x81})
-- Combining characters U+0300, U+0301, U+0302
- pcc = to_intp()
- eq(0x007f, mbyte.utfc_ptr2char_len(to_string({0x7f, 0xcc, 0x80, 0xcc, 0x81, 0xcc, 0x82}), pcc, 7))
- eq(0x0300, pcc[0])
- eq(0x0301, pcc[1])
- eq(0x0302, pcc[2])
- eq(0x0000, pcc[3])
+ 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
- pcc = to_intp()
- eq(0x007f, mbyte.utfc_ptr2char_len(to_string({0x7f, 0xcc, 0x80, 0xcc, 0x81, 0xcc, 0x82, 0xcc, 0x83}), pcc, 9))
- eq(0x0300, pcc[0])
- eq(0x0301, pcc[1])
- eq(0x0302, pcc[2])
- eq(0x0303, pcc[3])
- eq(0x0000, pcc[4])
+ 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
- pcc = to_intp()
- eq(0x007f, mbyte.utfc_ptr2char_len(to_string(
- {0x7f, 0xcc, 0x80, 0xcc, 0x81, 0xcc, 0x82, 0xcc, 0x83, 0xcc, 0x84}), pcc, 11))
- eq(0x0300, pcc[0])
- eq(0x0301, pcc[1])
- eq(0x0302, pcc[2])
- eq(0x0303, pcc[3])
- eq(0x0304, pcc[4])
- eq(0x0000, pcc[5])
- -- Combining characters U+0300, U+0301, U+0302, U+0303, U+0304,
- -- U+0305
- pcc = to_intp()
- eq(0x007f, mbyte.utfc_ptr2char_len(to_string(
- {0x7f, 0xcc, 0x80, 0xcc, 0x81, 0xcc, 0x82, 0xcc, 0x83, 0xcc, 0x84, 0xcc, 0x85}), pcc, 13))
- eq(0x0300, pcc[0])
- eq(0x0301, pcc[1])
- eq(0x0302, pcc[2])
- eq(0x0303, pcc[3])
- eq(0x0304, pcc[4])
- eq(0x0305, pcc[5])
- eq(1, pcc[6])
-
- -- Combining characters U+0300, U+0301, U+0302, U+0303, U+0304,
- -- U+0305, U+0306, but only save six (= MAX_MCO).
- pcc = to_intp()
- eq(0x007f, mbyte.utfc_ptr2char_len(to_string(
- {0x7f, 0xcc, 0x80, 0xcc, 0x81, 0xcc, 0x82, 0xcc, 0x83, 0xcc, 0x84, 0xcc, 0x85, 0xcc, 0x86}), pcc, 15))
- eq(0x0300, pcc[0])
- eq(0x0301, pcc[1])
- eq(0x0302, pcc[2])
- eq(0x0303, pcc[3])
- eq(0x0304, pcc[4])
- eq(0x0305, pcc[5])
- eq(0x0001, pcc[6])
+ 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})
- -- Only three following combining characters U+0300, U+0301, U+0302
- pcc = to_intp()
- eq(0x007f, mbyte.utfc_ptr2char_len(to_string(
- {0x7f, 0xcc, 0x80, 0xcc, 0x81, 0xcc, 0x82, 0xc2, 0x80, 0xcc, 0x84, 0xcc, 0x85}), pcc, 13))
- eq(0x0300, pcc[0])
- eq(0x0301, pcc[1])
- eq(0x0302, pcc[2])
- eq(0x0000, pcc[3])
+ -- 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})
+ -- 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})
-- No UTF-8 sequence
- pcc = to_intp()
- eq(0x00c2, mbyte.utfc_ptr2char_len(to_string({0xc2, 0x7f, 0xcc, 0x80, 0x80}), pcc, 5))
- eq(0, pcc[0])
+ eq({'', 0xc2}, test_seq{0xc2, 0x7f, 0xcc, 0x80, 0x80})
-- No following UTF-8 character
- pcc = to_intp()
- eq(0x0080, mbyte.utfc_ptr2char_len(to_string({0xc2, 0x80, 0xcc, 0xcc, 0x80}), pcc, 5))
- eq(0, pcc[0])
+ eq({"\xc2\x80", 0x80}, test_seq{0xc2, 0x80, 0xcc, 0xcc, 0x80})
-- Combining character U+0301
- pcc = to_intp()
- eq(0x0080, mbyte.utfc_ptr2char_len(to_string({0xc2, 0x80, 0xcc, 0x81, 0x7f}), pcc, 5))
- eq(0x0301, pcc[0])
- eq(0x0000, pcc[1])
+ eq({"\xc2\x80\xcc\x81", 0x80}, test_seq{0xc2, 0x80, 0xcc, 0x81, 0x7f})
-- Combining character U+0301
- pcc = to_intp()
- eq(0x0080, mbyte.utfc_ptr2char_len(to_string({0xc2, 0x80, 0xcc, 0x81, 0xcc}), pcc, 5))
- eq(0x0301, pcc[0])
- eq(0x0000, pcc[1])
+ eq({"\xc2\x80\xcc\x81", 0x80}, test_seq{0xc2, 0x80, 0xcc, 0x81, 0xcc})
-- One UTF-8 character
- pcc = to_intp()
- eq(0x100000, mbyte.utfc_ptr2char_len(to_string({0xf4, 0x80, 0x80, 0x80, 0x7f}), pcc, 5))
- eq(0, pcc[0])
+ eq({"\xf4\x80\x80\x80", 0x100000}, test_seq{0xf4, 0x80, 0x80, 0x80, 0x7f})
-- One UTF-8 character
- pcc = to_intp()
- eq(0x100000, mbyte.utfc_ptr2char_len(to_string({0xf4, 0x80, 0x80, 0x80, 0x80}), pcc, 5))
- eq(0, pcc[0])
+ eq({"\xf4\x80\x80\x80", 0x100000}, test_seq{0xf4, 0x80, 0x80, 0x80, 0x80})
-- One UTF-8 character
- pcc = to_intp()
- eq(0x100000, mbyte.utfc_ptr2char_len(to_string({0xf4, 0x80, 0x80, 0x80, 0xcc}), pcc, 5))
- eq(0, pcc[0])
+ eq({"\xf4\x80\x80\x80", 0x100000}, test_seq{0xf4, 0x80, 0x80, 0x80, 0xcc})
-- Combining characters U+1AB0 and U+0301
- pcc = to_intp()
- eq(0x100000, mbyte.utfc_ptr2char_len(to_string(
- {0xf4, 0x80, 0x80, 0x80, 0xe1, 0xaa, 0xb0, 0xcc, 0x81}), pcc, 9))
- eq(0x1ab0, pcc[0])
- eq(0x0301, pcc[1])
- eq(0x0000, pcc[2])
+ eq({"\xf4\x80\x80\x80\xe1\xaa\xb0\xcc\x81", 0x100000}, test_seq{0xf4, 0x80, 0x80, 0x80, 0xe1, 0xaa, 0xb0, 0xcc, 0x81})
end)
end)
diff --git a/test/unit/message_spec.lua b/test/unit/message_spec.lua
index 549eff6e03..0d5268d199 100644
--- a/test/unit/message_spec.lua
+++ b/test/unit/message_spec.lua
@@ -12,7 +12,7 @@ describe('trunc_string', function()
local buflen = 40
local function test_inplace(s, expected, room)
room = room and room or 20
- local buf = cimp.xmalloc(ffi.sizeof('char_u') * buflen)
+ local buf = cimp.xmalloc(ffi.sizeof('char') * buflen)
ffi.C.strcpy(buf, s)
cimp.trunc_string(buf, buf, room, buflen)
eq(expected, ffi.string(buf))
@@ -21,7 +21,7 @@ describe('trunc_string', function()
local function test_copy(s, expected, room)
room = room and room or 20
- local buf = cimp.xmalloc(ffi.sizeof('char_u') * buflen)
+ local buf = cimp.xmalloc(ffi.sizeof('char') * buflen)
local str = cimp.xstrdup(to_cstr(s))
cimp.trunc_string(str, buf, room, buflen)
eq(expected, ffi.string(buf))
diff --git a/test/unit/msgpack_spec.lua b/test/unit/msgpack_spec.lua
new file mode 100644
index 0000000000..c573714714
--- /dev/null
+++ b/test/unit/msgpack_spec.lua
@@ -0,0 +1,75 @@
+local helpers = require('test.unit.helpers')(after_each)
+local cimport = helpers.cimport
+local itp = helpers.gen_itp(it)
+local lib = cimport('./src/nvim/msgpack_rpc/unpacker.h', './src/nvim/memory.h')
+local ffi = helpers.ffi
+local eq = helpers.eq
+local to_cstr = helpers.to_cstr
+
+--- @class Unpacker
+--- @field read_ptr ffi.cdata*
+--- @field read_size number
+
+--- @alias Unpacker* table<number, Unpacker>
+--- @return Unpacker* unpacker `unpacker[0]` to dereference
+local function make_unpacker()
+ return ffi.gc(ffi.cast('Unpacker*', lib.xcalloc(1, ffi.sizeof('Unpacker'))), function(unpacker)
+ lib.unpacker_teardown(unpacker, nil, nil)
+ lib.xfree(unpacker)
+ end)
+end
+
+--- @param unpacker Unpacker*
+--- @param data string
+--- @param size number? *default: data:len()*
+local function unpacker_goto(unpacker, data, size)
+ unpacker[0].read_ptr = to_cstr(data)
+ unpacker[0].read_size = size or data:len()
+end
+
+--- @param unpacker Unpacker*
+--- @return boolean
+local function unpacker_advance(unpacker)
+ return lib.unpacker_advance(unpacker)
+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'
+
+ local unpacker = make_unpacker()
+ lib.unpacker_init(unpacker)
+
+ 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)
+
+ 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,
+ -- [kMessageTypeNotification, "redraw", [
+ -- ["grid_line",
+ -- [2, 0, 0, [], false]
+ -- ]
+ -- ]]
+ '\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\x90\xc2'
+ )
+ local finished = unpacker_advance(unpacker)
+ eq(finished, true)
+ end)
+ end)
+end)
diff --git a/test/unit/optionstr_spec.lua b/test/unit/optionstr_spec.lua
index f8122f4fe0..2e7198a63a 100644
--- a/test/unit/optionstr_spec.lua
+++ b/test/unit/optionstr_spec.lua
@@ -4,10 +4,10 @@ local itp = helpers.gen_itp(it)
local to_cstr = helpers.to_cstr
local eq = helpers.eq
-local option = helpers.cimport("./src/nvim/optionstr.h")
+local optionstr = helpers.cimport("./src/nvim/optionstr.h")
local check_ff_value = function(ff)
- return option.check_ff_value(to_cstr(ff))
+ return optionstr.check_ff_value(to_cstr(ff))
end
describe('check_ff_value', function()
diff --git a/test/unit/os/env_spec.lua b/test/unit/os/env_spec.lua
index 71177f4c65..24b92edee5 100644
--- a/test/unit/os/env_spec.lua
+++ b/test/unit/os/env_spec.lua
@@ -10,8 +10,6 @@ local to_cstr = helpers.to_cstr
local NULL = helpers.NULL
local OK = 0
-require('lfs')
-
local cimp = cimport('./src/nvim/os/os.h')
describe('env.c', function()
diff --git a/test/unit/os/fileio_spec.lua b/test/unit/os/fileio_spec.lua
index 4d58a8934e..fd30ca70da 100644
--- a/test/unit/os/fileio_spec.lua
+++ b/test/unit/os/fileio_spec.lua
@@ -1,4 +1,4 @@
-local lfs = require('lfs')
+local luv = require('luv')
local helpers = require('test.unit.helpers')(after_each)
local itp = helpers.gen_itp(it)
@@ -7,6 +7,7 @@ local eq = helpers.eq
local ffi = helpers.ffi
local cimport = helpers.cimport
local cppimport = helpers.cppimport
+local mkdir = helpers.mkdir
local m = cimport('./src/nvim/os/os.h', './src/nvim/os/fileio.h')
cppimport('fcntl.h')
@@ -25,7 +26,7 @@ local linkb = dir .. '/broken.lnk'
local filec = dir .. '/created-file.dat'
before_each(function()
- lfs.mkdir(dir);
+ mkdir(dir);
local f1 = io.open(file1, 'w')
f1:write(fcontents)
@@ -35,8 +36,8 @@ before_each(function()
f2:write(fcontents)
f2:close()
- lfs.link('file1.dat', linkf, true)
- lfs.link('broken.dat', linkb, true)
+ luv.fs_symlink('file1.dat', linkf)
+ luv.fs_symlink('broken.dat', linkb)
end)
after_each(function()
@@ -45,7 +46,7 @@ after_each(function()
os.remove(linkf)
os.remove(linkb)
os.remove(filec)
- lfs.rmdir(dir)
+ luv.fs_rmdir(dir)
end)
local function file_open(fname, flags, mode)
@@ -119,13 +120,13 @@ describe('file_open_fd', function()
eq(0, m.file_close(fp, false))
end)
itp('can use file descriptor returned by os_open for writing', function()
- eq(nil, lfs.attributes(filec))
+ eq(nil, luv.fs_stat(filec))
local fd = m.os_open(filec, m.kO_WRONLY + m.kO_CREAT, 384)
local err, fp = file_open_fd(fd, m.kFileWriteOnly)
eq(0, err)
eq(4, file_write(fp, 'test'))
eq(0, m.file_close(fp, false))
- eq(4, lfs.attributes(filec).size)
+ eq(4, luv.fs_stat(filec).size)
eq('test', io.open(filec):read('*a'))
end)
end)
@@ -139,13 +140,13 @@ describe('file_open_fd_new', function()
eq(0, m.file_free(fp, false))
end)
itp('can use file descriptor returned by os_open for writing', function()
- eq(nil, lfs.attributes(filec))
+ eq(nil, luv.fs_stat(filec))
local fd = m.os_open(filec, m.kO_WRONLY + m.kO_CREAT, 384)
local err, fp = file_open_fd_new(fd, m.kFileWriteOnly)
eq(0, err)
eq(4, file_write(fp, 'test'))
eq(0, m.file_free(fp, false))
- eq(4, lfs.attributes(filec).size)
+ eq(4, luv.fs_stat(filec).size)
eq('test', io.open(filec):read('*a'))
end)
end)
@@ -154,32 +155,32 @@ describe('file_open', function()
itp('can create a rwx------ file with kFileCreate', function()
local err, fp = file_open(filec, m.kFileCreate, 448)
eq(0, err)
- local attrs = lfs.attributes(filec)
- eq('rwx------', attrs.permissions)
+ local attrs = luv.fs_stat(filec)
+ eq(33216, attrs.mode)
eq(0, m.file_close(fp, false))
end)
itp('can create a rw------- file with kFileCreate', function()
local err, fp = file_open(filec, m.kFileCreate, 384)
eq(0, err)
- local attrs = lfs.attributes(filec)
- eq('rw-------', attrs.permissions)
+ local attrs = luv.fs_stat(filec)
+ eq(33152, attrs.mode)
eq(0, m.file_close(fp, false))
end)
itp('can create a rwx------ file with kFileCreateOnly', function()
local err, fp = file_open(filec, m.kFileCreateOnly, 448)
eq(0, err)
- local attrs = lfs.attributes(filec)
- eq('rwx------', attrs.permissions)
+ local attrs = luv.fs_stat(filec)
+ eq(33216, attrs.mode)
eq(0, m.file_close(fp, false))
end)
itp('can create a rw------- file with kFileCreateOnly', function()
local err, fp = file_open(filec, m.kFileCreateOnly, 384)
eq(0, err)
- local attrs = lfs.attributes(filec)
- eq('rw-------', attrs.permissions)
+ local attrs = luv.fs_stat(filec)
+ eq(33152, attrs.mode)
eq(0, m.file_close(fp, false))
end)
@@ -228,7 +229,7 @@ describe('file_open', function()
eq(0, err)
eq(true, fp.wr)
eq(0, m.file_close(fp, false))
- local attrs = lfs.attributes(file1)
+ local attrs = luv.fs_stat(file1)
eq(0, attrs.size)
end)
@@ -237,14 +238,14 @@ describe('file_open', function()
eq(0, err)
eq(true, fp.wr)
eq(0, m.file_close(fp, false))
- local attrs = lfs.attributes(file1)
+ local attrs = luv.fs_stat(file1)
eq(4096, attrs.size)
end)
itp('fails to create a file with just kFileWriteOnly', function()
local err, _ = file_open(filec, m.kFileWriteOnly, 384)
eq(m.UV_ENOENT, err)
- local attrs = lfs.attributes(filec)
+ local attrs = luv.fs_stat(filec)
eq(nil, attrs)
end)
@@ -254,7 +255,7 @@ describe('file_open', function()
eq(0, err)
eq(true, fp.wr)
eq(0, m.file_close(fp, false))
- local attrs = lfs.attributes(file1)
+ local attrs = luv.fs_stat(file1)
eq(0, attrs.size)
end)
@@ -295,9 +296,9 @@ describe('file_close', function()
eq(0, err)
local wsize = file_write(fp, 'test')
eq(4, wsize)
- eq(0, lfs.attributes(filec).size)
+ eq(0, luv.fs_stat(filec).size)
eq(0, m.file_close(fp, true))
- eq(wsize, lfs.attributes(filec).size)
+ eq(wsize, luv.fs_stat(filec).size)
end)
end)
@@ -307,9 +308,9 @@ describe('file_free', function()
eq(0, err)
local wsize = file_write(fp, 'test')
eq(4, wsize)
- eq(0, lfs.attributes(filec).size)
+ eq(0, luv.fs_stat(filec).size)
eq(0, m.file_free(fp, true))
- eq(wsize, lfs.attributes(filec).size)
+ eq(wsize, luv.fs_stat(filec).size)
end)
end)
@@ -318,12 +319,12 @@ describe('file_fsync', function()
local err, fp = file_open(filec, m.kFileCreateOnly, 384)
eq(0, file_fsync(fp))
eq(0, err)
- eq(0, lfs.attributes(filec).size)
+ eq(0, luv.fs_stat(filec).size)
local wsize = file_write(fp, 'test')
eq(4, wsize)
- eq(0, lfs.attributes(filec).size)
+ eq(0, luv.fs_stat(filec).size)
eq(0, file_fsync(fp))
- eq(wsize, lfs.attributes(filec).size)
+ eq(wsize, luv.fs_stat(filec).size)
eq(0, m.file_close(fp, false))
end)
end)
@@ -333,12 +334,12 @@ describe('file_flush', function()
local err, fp = file_open(filec, m.kFileCreateOnly, 384)
eq(0, file_flush(fp))
eq(0, err)
- eq(0, lfs.attributes(filec).size)
+ eq(0, luv.fs_stat(filec).size)
local wsize = file_write(fp, 'test')
eq(4, wsize)
- eq(0, lfs.attributes(filec).size)
+ eq(0, luv.fs_stat(filec).size)
eq(0, file_flush(fp))
- eq(wsize, lfs.attributes(filec).size)
+ eq(wsize, luv.fs_stat(filec).size)
eq(0, m.file_close(fp, false))
end)
end)
@@ -412,7 +413,7 @@ describe('file_write', function()
local wr = file_write(fp, fcontents)
eq(#fcontents, wr)
eq(0, m.file_close(fp, false))
- eq(wr, lfs.attributes(filec).size)
+ eq(wr, luv.fs_stat(filec).size)
eq(fcontents, io.open(filec):read('*a'))
end)
@@ -429,7 +430,7 @@ describe('file_write', function()
shift = shift + size
end
eq(0, m.file_close(fp, false))
- eq(#fcontents, lfs.attributes(filec).size)
+ eq(#fcontents, luv.fs_stat(filec).size)
eq(fcontents, io.open(filec):read('*a'))
end)
@@ -446,7 +447,7 @@ describe('file_write', function()
shift = shift + size
end
eq(0, m.file_close(fp, false))
- eq(#fcontents, lfs.attributes(filec).size)
+ eq(#fcontents, luv.fs_stat(filec).size)
eq(fcontents, io.open(filec):read('*a'))
end)
end)
diff --git a/test/unit/os/fs_spec.lua b/test/unit/os/fs_spec.lua
index c718244ea4..8f45d2b0c7 100644
--- a/test/unit/os/fs_spec.lua
+++ b/test/unit/os/fs_spec.lua
@@ -1,4 +1,4 @@
-local lfs = require('lfs')
+local luv = require('luv')
local bit = require('bit')
local helpers = require('test.unit.helpers')(after_each)
@@ -16,14 +16,12 @@ local to_cstr = helpers.to_cstr
local OK = helpers.OK
local FAIL = helpers.FAIL
local NULL = helpers.NULL
+local mkdir = helpers.mkdir
+local endswith = helpers.endswith
local NODE_NORMAL = 0
local NODE_WRITABLE = 1
-cimport('./src/nvim/os/shell.h')
-cimport('./src/nvim/option_defs.h')
-cimport('./src/nvim/main.h')
-cimport('./src/nvim/fileio.h')
local fs = cimport('./src/nvim/os/os.h', './src/nvim/path.h')
cppimport('sys/stat.h')
cppimport('fcntl.h')
@@ -48,11 +46,11 @@ local function unset_bit(number, to_unset)
end
local function assert_file_exists(filepath)
- neq(nil, lfs.attributes(filepath))
+ neq(nil, luv.fs_stat(filepath))
end
local function assert_file_does_not_exist(filepath)
- eq(nil, lfs.attributes(filepath))
+ eq(nil, luv.fs_stat(filepath))
end
local function os_setperm(filename, perm)
@@ -70,14 +68,14 @@ describe('fs.c', function()
end
before_each(function()
- lfs.mkdir('unit-test-directory');
+ mkdir('unit-test-directory');
io.open('unit-test-directory/test.file', 'w'):close()
io.open('unit-test-directory/test_2.file', 'w'):close()
- lfs.link('test.file', 'unit-test-directory/test_link.file', true)
+ luv.fs_symlink('test.file', 'unit-test-directory/test_link.file')
- lfs.link('non_existing_file.file', 'unit-test-directory/test_broken_link.file', true)
+ luv.fs_symlink('non_existing_file.file', 'unit-test-directory/test_broken_link.file')
-- The tests are invoked with an absolute path to `busted` executable.
absolute_executable = arg[0]
-- Split the absolute_executable path into a directory and filename.
@@ -90,19 +88,19 @@ describe('fs.c', function()
os.remove('unit-test-directory/test_link.file')
os.remove('unit-test-directory/test_hlink.file')
os.remove('unit-test-directory/test_broken_link.file')
- lfs.rmdir('unit-test-directory')
+ luv.fs_rmdir('unit-test-directory')
end)
describe('os_dirname', function()
itp('returns OK and writes current directory to the buffer', function()
- local length = string.len(lfs.currentdir()) + 1
+ local length = string.len(luv.cwd()) + 1
local buf = cstr(length, '')
eq(OK, fs.os_dirname(buf, length))
- eq(lfs.currentdir(), ffi.string(buf))
+ eq(luv.cwd(), ffi.string(buf))
end)
itp('returns FAIL if the buffer is too small', function()
- local length = string.len(lfs.currentdir()) + 1
+ local length = string.len(luv.cwd()) + 1
local buf = cstr(length - 1, '')
eq(FAIL, fs.os_dirname(buf, length - 1))
end)
@@ -203,20 +201,20 @@ describe('fs.c', function()
end)
itp('returns the absolute path when given an executable relative to the current dir', function()
- local old_dir = lfs.currentdir()
+ local old_dir = luv.cwd()
- lfs.chdir(directory)
+ luv.chdir(directory)
-- Rely on currentdir to resolve symlinks, if any. Testing against
-- the absolute path taken from arg[0] may result in failure where
-- the path has a symlink in it.
- local canonical = lfs.currentdir() .. '/' .. executable_name
+ local canonical = luv.cwd() .. '/' .. executable_name
local expected = exe(canonical)
local relative_executable = './' .. executable_name
local res = exe(relative_executable)
-- Don't test yet; we need to chdir back first.
- lfs.chdir(old_dir)
+ luv.chdir(old_dir)
eq(expected, res)
end)
end)
@@ -278,11 +276,11 @@ describe('fs.c', function()
describe('os_fchown', function()
local filename = 'unit-test-directory/test.file'
itp('does not change owner and group if respective IDs are equal to -1', function()
- local uid = lfs.attributes(filename, 'uid')
- local gid = lfs.attributes(filename, 'gid')
+ local uid = luv.fs_stat(filename).uid
+ local gid = luv.fs_stat(filename).gid
eq(0, os_fchown(filename, -1, -1))
- eq(uid, lfs.attributes(filename, 'uid'))
- return eq(gid, lfs.attributes(filename, 'gid'))
+ eq(uid, luv.fs_stat(filename).uid)
+ return eq(gid, luv.fs_stat(filename).gid)
end)
-- Some systems may not have `id` utility.
@@ -290,7 +288,7 @@ describe('fs.c', function()
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 = lfs.attributes(filename, 'gid')
+ 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.
@@ -305,7 +303,7 @@ describe('fs.c', function()
-- In that case we can not perform this test.
if new_gid then
eq(0, (os_fchown(filename, -1, new_gid)))
- eq(new_gid, (lfs.attributes(filename, 'gid')))
+ eq(new_gid, luv.fs_stat(filename).gid)
end
end)
end
@@ -548,7 +546,7 @@ describe('fs.c', function()
--create the file
local fd = os_open(new_file, ffi.C.kO_CREAT, tonumber("700", 8))
--verify permissions
- eq('rwx------', lfs.attributes(new_file)['permissions'])
+ eq(33216, luv.fs_stat(new_file).mode)
eq(0, os_close(fd))
end)
@@ -557,7 +555,7 @@ describe('fs.c', function()
--create the file
local fd = os_open(new_file, ffi.C.kO_CREAT, tonumber("600", 8))
--verify permissions
- eq('rw-------', lfs.attributes(new_file)['permissions'])
+ eq(33152, luv.fs_stat(new_file).mode)
eq(0, os_close(fd))
end)
@@ -747,12 +745,17 @@ describe('fs.c', function()
local function os_mkdir_recurse(path, mode)
local failed_str = ffi.new('char *[1]', {nil})
- local ret = fs.os_mkdir_recurse(path, mode, failed_str)
- local str = failed_str[0]
- if str ~= nil then
- str = ffi.string(str)
+ 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
+ failed_dir = ffi.string(failed_dir)
end
- return ret, str
+ local created_dir = created_str[0]
+ if created_dir ~= nil then
+ created_dir = ffi.string(created_dir)
+ end
+ return ret, failed_dir, created_dir
end
describe('os_mkdir', function()
@@ -766,81 +769,88 @@ describe('fs.c', function()
eq(false, (os_isdir('unit-test-directory/new-dir')))
eq(0, (os_mkdir('unit-test-directory/new-dir', mode)))
eq(true, (os_isdir('unit-test-directory/new-dir')))
- lfs.rmdir('unit-test-directory/new-dir')
+ luv.fs_rmdir('unit-test-directory/new-dir')
end)
end)
describe('os_mkdir_recurse', function()
itp('returns zero when given an already existing directory', function()
local mode = ffi.C.kS_IRUSR + ffi.C.kS_IWUSR + ffi.C.kS_IXUSR
- local ret, failed_str = os_mkdir_recurse('unit-test-directory', mode)
+ local ret, failed_dir, created_dir = os_mkdir_recurse('unit-test-directory', mode)
eq(0, ret)
- eq(nil, failed_str)
+ eq(nil, failed_dir)
+ eq(nil, created_dir)
end)
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_str = os_mkdir_recurse(
+ 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_str)
+ eq('unit-test-directory/test.file', failed_dir)
+ eq(nil, created_dir)
end)
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_str = os_mkdir_recurse(
+ 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_str)
+ eq('unit-test-directory/test.file', failed_dir)
+ eq(nil, created_dir)
end)
itp('succeeds to create a directory', function()
local mode = ffi.C.kS_IRUSR + ffi.C.kS_IWUSR + ffi.C.kS_IXUSR
- local ret, failed_str = os_mkdir_recurse(
+ local ret, failed_dir, created_dir = os_mkdir_recurse(
'unit-test-directory/new-dir-recurse', mode)
eq(0, ret)
- eq(nil, failed_str)
+ eq(nil, failed_dir)
+ ok(endswith(created_dir, 'unit-test-directory/new-dir-recurse'))
eq(true, os_isdir('unit-test-directory/new-dir-recurse'))
- lfs.rmdir('unit-test-directory/new-dir-recurse')
+ luv.fs_rmdir('unit-test-directory/new-dir-recurse')
eq(false, os_isdir('unit-test-directory/new-dir-recurse'))
end)
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_str = os_mkdir_recurse(
+ local ret, failed_dir, created_dir = os_mkdir_recurse(
'unit-test-directory/new-dir-recurse///', mode)
eq(0, ret)
- eq(nil, failed_str)
+ eq(nil, failed_dir)
+ ok(endswith(created_dir, 'unit-test-directory/new-dir-recurse'))
eq(true, os_isdir('unit-test-directory/new-dir-recurse'))
- lfs.rmdir('unit-test-directory/new-dir-recurse')
+ luv.fs_rmdir('unit-test-directory/new-dir-recurse')
eq(false, os_isdir('unit-test-directory/new-dir-recurse'))
end)
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_str = os_mkdir_recurse(
+ local ret, failed_dir, created_dir = os_mkdir_recurse(
'unit-test-directory/new-dir-recurse/', mode)
eq(0, ret)
- eq(nil, failed_str)
+ eq(nil, failed_dir)
+ ok(endswith(created_dir, 'unit-test-directory/new-dir-recurse'))
eq(true, os_isdir('unit-test-directory/new-dir-recurse'))
- lfs.rmdir('unit-test-directory/new-dir-recurse')
+ luv.fs_rmdir('unit-test-directory/new-dir-recurse')
eq(false, os_isdir('unit-test-directory/new-dir-recurse'))
end)
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_str = os_mkdir_recurse(
+ 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_str)
+ eq(nil, failed_dir)
+ ok(endswith(created_dir, 'unit-test-directory/new-dir-recurse'))
eq(true, os_isdir('unit-test-directory/new-dir-recurse'))
eq(true, os_isdir('unit-test-directory/new-dir-recurse/1'))
eq(true, os_isdir('unit-test-directory/new-dir-recurse/1/2'))
eq(true, os_isdir('unit-test-directory/new-dir-recurse/1/2/3'))
- lfs.rmdir('unit-test-directory/new-dir-recurse/1/2/3')
- lfs.rmdir('unit-test-directory/new-dir-recurse/1/2')
- lfs.rmdir('unit-test-directory/new-dir-recurse/1')
- lfs.rmdir('unit-test-directory/new-dir-recurse')
+ luv.fs_rmdir('unit-test-directory/new-dir-recurse/1/2/3')
+ luv.fs_rmdir('unit-test-directory/new-dir-recurse/1/2')
+ luv.fs_rmdir('unit-test-directory/new-dir-recurse/1')
+ luv.fs_rmdir('unit-test-directory/new-dir-recurse')
eq(false, os_isdir('unit-test-directory/new-dir-recurse'))
end)
end)
@@ -851,7 +861,7 @@ describe('fs.c', function()
end)
itp('removes the given directory and returns 0', function()
- lfs.mkdir('unit-test-directory/new-dir')
+ mkdir('unit-test-directory/new-dir')
eq(0, os_rmdir('unit-test-directory/new-dir'))
eq(false, (os_isdir('unit-test-directory/new-dir')))
end)
@@ -1005,7 +1015,7 @@ describe('fs.c', function()
file:write('some bytes to get filesize != 0')
file:flush()
file:close()
- local size = lfs.attributes(path, 'size')
+ local size = luv.fs_stat(path).size
local info = file_info_new()
assert.is_true(fs.os_fileinfo(path, info))
eq(size, fs.os_fileinfo_size(info))
@@ -1019,7 +1029,7 @@ describe('fs.c', function()
local info = file_info_new()
assert.is_true(fs.os_fileinfo(path, info))
eq(1, fs.os_fileinfo_hardlinks(info))
- lfs.link(path, path_link)
+ luv.fs_link(path, path_link)
assert.is_true(fs.os_fileinfo(path, info))
eq(2, fs.os_fileinfo_hardlinks(info))
end)
@@ -1028,11 +1038,7 @@ describe('fs.c', function()
describe('os_fileinfo_blocksize', function()
itp('returns the correct blocksize of a file', function()
local path = 'unit-test-directory/test.file'
- -- there is a bug in luafilesystem where
- -- `lfs.attributes path, 'blksize'` returns the wrong value:
- -- https://github.com/keplerproject/luafilesystem/pull/44
- -- using this workaround for now:
- local blksize = lfs.attributes(path).blksize
+ local blksize = luv.fs_stat(path).blksize
local info = file_info_new()
assert.is_true(fs.os_fileinfo(path, info))
if blksize then
diff --git a/test/unit/os/shell_spec.lua b/test/unit/os/shell_spec.lua
index 29a2b78491..3fb1afed44 100644
--- a/test/unit/os/shell_spec.lua
+++ b/test/unit/os/shell_spec.lua
@@ -2,7 +2,7 @@ local helpers = require('test.unit.helpers')(after_each)
local itp = helpers.gen_itp(it)
local cimported = helpers.cimport(
'./src/nvim/os/shell.h',
- './src/nvim/option_defs.h',
+ './src/nvim/option_vars.h',
'./src/nvim/main.h',
'./src/nvim/memory.h'
)
diff --git a/test/unit/path_spec.lua b/test/unit/path_spec.lua
index 1fc4e2496e..23f71cfe78 100644
--- a/test/unit/path_spec.lua
+++ b/test/unit/path_spec.lua
@@ -1,4 +1,4 @@
-local lfs = require('lfs')
+local luv = require('luv')
local helpers = require('test.unit.helpers')(after_each)
local itp = helpers.gen_itp(it)
@@ -11,9 +11,11 @@ local to_cstr = helpers.to_cstr
local NULL = helpers.NULL
local OK = helpers.OK
local FAIL = helpers.FAIL
+local mkdir = helpers.mkdir
cimport('string.h')
local cimp = cimport('./src/nvim/os/os.h', './src/nvim/path.h')
+local options = cimport('./src/nvim/option_vars.h')
local length = 0
local buffer = nil
@@ -21,11 +23,11 @@ local buffer = nil
describe('path.c', function()
describe('path_full_dir_name', function()
setup(function()
- lfs.mkdir('unit-test-directory')
+ mkdir('unit-test-directory')
end)
teardown(function()
- lfs.rmdir('unit-test-directory')
+ luv.fs_rmdir('unit-test-directory')
end)
local function path_full_dir_name(directory, buf, len)
@@ -35,34 +37,34 @@ describe('path.c', function()
before_each(function()
-- Create empty string buffer which will contain the resulting path.
- length = string.len(lfs.currentdir()) + 22
+ length = string.len(luv.cwd()) + 22
buffer = cstr(length, '')
end)
itp('returns the absolute directory name of a given relative one', function()
local result = path_full_dir_name('..', buffer, length)
eq(OK, result)
- local old_dir = lfs.currentdir()
- lfs.chdir('..')
- local expected = lfs.currentdir()
- lfs.chdir(old_dir)
+ local old_dir = luv.cwd()
+ luv.chdir('..')
+ local expected = luv.cwd()
+ luv.chdir(old_dir)
eq(expected, (ffi.string(buffer)))
end)
itp('returns the current directory name if the given string is empty', function()
eq(OK, (path_full_dir_name('', buffer, length)))
- eq(lfs.currentdir(), (ffi.string(buffer)))
+ eq(luv.cwd(), (ffi.string(buffer)))
end)
itp('works with a normal relative dir', function()
local result = path_full_dir_name('unit-test-directory', buffer, length)
- eq(lfs.currentdir() .. '/unit-test-directory', (ffi.string(buffer)))
+ eq(luv.cwd() .. '/unit-test-directory', (ffi.string(buffer)))
eq(OK, result)
end)
itp('works with a non-existing relative dir', function()
local result = path_full_dir_name('does-not-exist', buffer, length)
- eq(lfs.currentdir() .. '/does-not-exist', (ffi.string(buffer)))
+ eq(luv.cwd() .. '/does-not-exist', (ffi.string(buffer)))
eq(OK, result)
end)
@@ -268,27 +270,27 @@ describe('path.c', function()
end)
describe('path_try_shorten_fname', function()
- local cwd = lfs.currentdir()
+ local cwd = luv.cwd()
before_each(function()
- lfs.mkdir('ut_directory')
+ mkdir('ut_directory')
end)
after_each(function()
- lfs.chdir(cwd)
- lfs.rmdir('ut_directory')
+ luv.chdir(cwd)
+ luv.fs_rmdir('ut_directory')
end)
describe('path_try_shorten_fname', function()
itp('returns shortened path if possible', function()
- lfs.chdir('ut_directory')
- local full = to_cstr(lfs.currentdir() .. '/subdir/file.txt')
+ luv.chdir('ut_directory')
+ local full = to_cstr(luv.cwd() .. '/subdir/file.txt')
eq('subdir/file.txt', (ffi.string(cimp.path_try_shorten_fname(full))))
end)
itp('returns `full_path` if a shorter version is not possible', function()
- local old = lfs.currentdir()
- lfs.chdir('ut_directory')
+ local old = luv.cwd()
+ luv.chdir('ut_directory')
local full = old .. '/subdir/file.txt'
eq(full, (ffi.string(cimp.path_try_shorten_fname(to_cstr(full)))))
end)
@@ -300,7 +302,7 @@ describe('path_try_shorten_fname', function()
end)
describe('path.c path_guess_exepath', function()
- local cwd = lfs.currentdir()
+ local cwd = luv.cwd()
for _,name in ipairs({'./nvim', '.nvim', 'foo/nvim'}) do
itp('"'..name..'" returns name catenated with CWD', function()
@@ -354,7 +356,7 @@ end)
describe('path.c', function()
setup(function()
- lfs.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
@@ -368,7 +370,7 @@ describe('path.c', function()
teardown(function()
os.remove('unit-test-directory/test.file')
- lfs.rmdir('unit-test-directory')
+ luv.fs_rmdir('unit-test-directory')
end)
describe('vim_FullName', function()
@@ -420,7 +422,7 @@ describe('path.c', function()
end)
itp('concatenates filename if it does not contain a slash', function()
- local expected = lfs.currentdir() .. '/test.file'
+ local expected = luv.cwd() .. '/test.file'
local filename = 'test.file'
local buflen = get_buf_len(expected, filename)
local do_expand = 1
@@ -430,7 +432,7 @@ describe('path.c', function()
end)
itp('concatenates directory name if it does not contain a slash', function()
- local expected = lfs.currentdir() .. '/..'
+ local expected = luv.cwd() .. '/..'
local filename = '..'
local buflen = get_buf_len(expected, filename)
local do_expand = 1
@@ -440,10 +442,10 @@ describe('path.c', function()
end)
itp('enters given directory (instead of just concatenating the strings) if possible and if path contains a slash', function()
- local old_dir = lfs.currentdir()
- lfs.chdir('..')
- local expected = lfs.currentdir() .. '/test.file'
- lfs.chdir(old_dir)
+ 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
@@ -472,7 +474,7 @@ describe('path.c', function()
end)
itp('works with some "normal" relative path with directories', function()
- local expected = lfs.currentdir() .. '/unit-test-directory/test.file'
+ local expected = luv.cwd() .. '/unit-test-directory/test.file'
local filename = 'unit-test-directory/test.file'
local buflen = get_buf_len(expected, filename)
local do_expand = 1
@@ -482,7 +484,7 @@ describe('path.c', function()
end)
itp('does not modify the given filename', function()
- local expected = lfs.currentdir() .. '/unit-test-directory/test.file'
+ local expected = luv.cwd() .. '/unit-test-directory/test.file'
local filename = to_cstr('unit-test-directory/test.file')
local buflen = string.len(expected) + 1
local buf = cstr(buflen, '')
@@ -505,7 +507,7 @@ describe('path.c', function()
end)
itp('does not remove trailing slash from non-existing relative directory #20847', function()
- local expected = lfs.currentdir() .. '/non_existing_dir/'
+ local expected = luv.cwd() .. '/non_existing_dir/'
local filename = 'non_existing_dir/'
local buflen = get_buf_len(expected, filename)
local do_expand = 1
@@ -515,7 +517,7 @@ describe('path.c', function()
end)
itp('expands "./" to the current directory #7117', function()
- local expected = lfs.currentdir() .. '/unit-test-directory/test.file'
+ local expected = luv.cwd() .. '/unit-test-directory/test.file'
local filename = './unit-test-directory/test.file'
local buflen = get_buf_len(expected, filename)
local do_expand = 1
@@ -525,7 +527,7 @@ describe('path.c', function()
end)
itp('collapses "foo/../foo" to "foo" #7117', function()
- local expected = lfs.currentdir() .. '/unit-test-directory/test.file'
+ local expected = luv.cwd() .. '/unit-test-directory/test.file'
local filename = 'unit-test-directory/../unit-test-directory/test.file'
local buflen = get_buf_len(expected, filename)
local do_expand = 1
@@ -542,8 +544,8 @@ describe('path.c', function()
return ffi.string(c_file)
end
- before_each(function() lfs.mkdir('CamelCase') end)
- after_each(function() lfs.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()
@@ -635,6 +637,15 @@ describe('path.c', function()
eq(false, path_with_extension('/some/path/file.vim', 'lua'))
eq(false, path_with_extension('/some/path/file', 'lua'))
end)
+
+ itp("respects 'fileignorecase' option", function()
+ options.p_fic = false
+ eq(false, path_with_extension('/some/path/file.VIM', 'vim'))
+ eq(false, path_with_extension('/some/path/file.LUA', 'lua'))
+ options.p_fic = true
+ eq(true, path_with_extension('/some/path/file.VIM', 'vim'))
+ eq(true, path_with_extension('/some/path/file.LUA', 'lua'))
+ end)
end)
describe('path_with_url', function()
diff --git a/test/unit/preload.lua b/test/unit/preload.lua
index 841e19b878..c2d051d98a 100644
--- a/test/unit/preload.lua
+++ b/test/unit/preload.lua
@@ -3,5 +3,4 @@
-- for more information about this.
local ffi = require('ffi')
local helpers = require('test.unit.helpers')(nil)
-local lfs = require('lfs')
local preprocess = require('test.unit.preprocess')
diff --git a/test/unit/preprocess.lua b/test/unit/preprocess.lua
index 1073855a7d..e356695c14 100644
--- a/test/unit/preprocess.lua
+++ b/test/unit/preprocess.lua
@@ -7,6 +7,9 @@ local global_helpers = require('test.helpers')
local argss_to_cmd = global_helpers.argss_to_cmd
local repeated_read_cmd = global_helpers.repeated_read_cmd
+--- @alias Compiler {path: string[], type: string}
+
+--- @type Compiler[]
local ccs = {}
local env_cc = os.getenv("CC")
@@ -27,6 +30,8 @@ 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("\\", "")
@@ -36,7 +41,7 @@ local function parse_make_deps(deps)
deps = deps:gsub(" +", " ")
-- split according to token (space in this case)
- local headers = {}
+ local headers = {} --- @type string[]
for token in deps:gmatch("[^%s]+") do
-- headers[token] = true
headers[#headers + 1] = token
@@ -53,57 +58,58 @@ local function parse_make_deps(deps)
return headers
end
--- will produce a string that represents a meta C header file that includes
--- all the passed in headers. I.e.:
---
--- headerize({"stdio.h", "math.h"}, true)
--- produces:
--- #include <stdio.h>
--- #include <math.h>
---
--- headerize({"vim.h", "memory.h"}, false)
--- produces:
--- #include "vim.h"
--- #include "memory.h"
+--- will produce a string that represents a meta C header file that includes
+--- all the passed in headers. I.e.:
+---
+--- headerize({"stdio.h", "math.h"}, true)
+--- produces:
+--- #include <stdio.h>
+--- #include <math.h>
+---
+--- headerize({"vim_defs.h", "memory.h"}, false)
+--- produces:
+--- #include "vim_defs.h"
+--- #include "memory.h"
+--- @param headers string[]
+--- @param global? boolean
+--- @return string
local function headerize(headers, global)
- local pre = '"'
- local post = pre
- if global then
- pre = "<"
- post = ">"
- end
-
- local formatted = {}
+ local fmt = global and '#include <%s>' or '#include "%s"'
+ local formatted = {} --- @type string[]
for _, hdr in ipairs(headers) do
- formatted[#formatted + 1] = "#include " ..
- tostring(pre) ..
- tostring(hdr) ..
- tostring(post)
+ formatted[#formatted + 1] = string.format(fmt, hdr)
end
return table.concat(formatted, "\n")
end
+--- @class Gcc
+--- @field path string
+--- @field preprocessor_extra_flags string[]
+--- @field get_defines_extra_flags string[]
+--- @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'},
}
+--- @param name string
+--- @param args string[]?
+--- @param val string?
function Gcc:define(name, args, val)
- local define = '-D' .. name
- if args ~= nil then
- define = define .. '(' .. table.concat(args, ',') .. ')'
+ local define = string.format('-D%s', name)
+ if args then
+ define = string.format('%s(%s)', define, table.concat(args, ','))
end
- if val ~= nil then
- define = define .. '=' .. val
+ if val then
+ define = string.format('%s=%s', define, val)
end
self.preprocessor_extra_flags[#self.preprocessor_extra_flags + 1] = define
end
function Gcc:undefine(name)
- self.preprocessor_extra_flags[#self.preprocessor_extra_flags + 1] = (
- '-U' .. name)
+ self.preprocessor_extra_flags[#self.preprocessor_extra_flags + 1] = '-U' .. name
end
function Gcc:init_defines()
@@ -128,6 +134,8 @@ function Gcc:init_defines()
self:undefine('__BLOCKS__')
end
+--- @param obj? Compiler
+--- @return Gcc
function Gcc:new(obj)
obj = obj or {}
setmetatable(obj, self)
@@ -136,6 +144,7 @@ function Gcc:new(obj)
return obj
end
+--- @param ... string
function Gcc:add_to_include_path(...)
for i = 1, select('#', ...) do
local path = select(i, ...)
@@ -145,116 +154,115 @@ function Gcc:add_to_include_path(...)
end
-- returns a list of the headers files upon which this file relies
+--- @param hdr string
+--- @return string[]?
function Gcc:dependencies(hdr)
+ --- @type string
local cmd = argss_to_cmd(self.path, {'-M', hdr}) .. ' 2>&1'
- local out = io.popen(cmd)
+ local out = assert(io.popen(cmd))
local deps = out:read("*a")
out:close()
if deps then
return parse_make_deps(deps)
- else
- return nil
end
end
+--- @param defines string
+--- @return string
function Gcc:filter_standard_defines(defines)
if not self.standard_defines then
local pseudoheader_fname = 'tmp_empty_pseudoheader.h'
- local pseudoheader_file = io.open(pseudoheader_fname, 'w')
+ local pseudoheader_file = assert(io.open(pseudoheader_fname, 'w'))
pseudoheader_file:close()
- local standard_defines = 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 = {}
+ self.standard_defines = {} --- @type table<string,true>
for line in standard_defines:gmatch('[^\n]+') do
self.standard_defines[line] = true
end
end
- local ret = {}
+
+ local ret = {} --- @type string[]
for line in defines:gmatch('[^\n]+') do
if not self.standard_defines[line] then
ret[#ret + 1] = line
end
end
+
return table.concat(ret, "\n")
end
--- returns a stream representing a preprocessed form of the passed-in headers.
--- Don't forget to close the stream by calling the close() method on it.
+--- returns a stream representing a preprocessed form of the passed-in headers.
+--- Don't forget to close the stream by calling the close() method on it.
+--- @param previous_defines string
+--- @param ... string
+--- @return string, string
function Gcc:preprocess(previous_defines, ...)
-- create pseudo-header
local pseudoheader = headerize({...}, false)
local pseudoheader_fname = 'tmp_pseudoheader.h'
- local pseudoheader_file = io.open(pseudoheader_fname, 'w')
+ local pseudoheader_file = assert(io.open(pseudoheader_fname, 'w'))
pseudoheader_file:write(previous_defines)
pseudoheader_file:write("\n")
pseudoheader_file:write(pseudoheader)
pseudoheader_file:flush()
pseudoheader_file:close()
- local defines = 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)
- -- lfs = require("lfs")
- -- print("CWD: #{lfs.currentdir!}")
- -- print("CMD: #{cmd}")
- -- io.stderr\write("CWD: #{lfs.currentdir!}\n")
- -- io.stderr\write("CMD: #{cmd}\n")
-
- local declarations = 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)
- assert(declarations and defines)
return declarations, defines
end
-local Clang = Gcc:new()
-local Msvc = Gcc:new()
-
-local type_to_class = {
- ["gcc"] = Gcc,
- ["clang"] = Clang,
- ["msvc"] = Msvc
-}
-
-- find the best cc. If os.exec causes problems on windows (like popping up
-- a console window) we might consider using something like this:
-- http://scite-ru.googlecode.com/svn/trunk/pack/tools/LuaLib/shell.html#exec
+--- @param compilers Compiler[]
+--- @return Gcc?
local function find_best_cc(compilers)
for _, meta in pairs(compilers) do
- local version = 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 type_to_class[meta.type]:new({path = meta.path})
+ return Gcc:new({path = meta.path})
end
end
- return nil
end
-- find the best cc. If os.exec causes problems on windows (like popping up
-- a console window) we might consider using something like this:
-- http://scite-ru.googlecode.com/svn/trunk/pack/tools/LuaLib/shell.html#exec
-local cc = nil
-if cc == nil then
- cc = find_best_cc(ccs)
+local cc = assert(find_best_cc(ccs))
+
+local M = {}
+
+--- @param hdr string
+--- @return string[]?
+function M.includes(hdr)
+ return cc:dependencies(hdr)
end
-return {
- includes = function(hdr)
- return cc:dependencies(hdr)
- end,
- preprocess = function(...)
- return cc:preprocess(...)
- end,
- add_to_include_path = function(...)
- return cc:add_to_include_path(...)
- end
-}
+--- @param ... string
+--- @return string, string
+function M.preprocess(...)
+ return cc:preprocess(...)
+end
+
+--- @param ... string
+function M.add_to_include_path(...)
+ return cc:add_to_include_path(...)
+end
+
+return M
diff --git a/test/unit/set.lua b/test/unit/set.lua
index f3d68c3042..7c30be32aa 100644
--- a/test/unit/set.lua
+++ b/test/unit/set.lua
@@ -4,10 +4,15 @@
-- other:
-- 1) index => item
-- 2) item => index
+--- @class Set
+--- @field nelem integer
+--- @field items string[]
+--- @field tbl table
local Set = {}
+--- @param items? string[]
function Set:new(items)
- local obj = {}
+ local obj = {} --- @type Set
setmetatable(obj, self)
self.__index = self
@@ -26,11 +31,9 @@ function Set:new(items)
return obj
end
+--- @return Set
function Set:copy()
- local obj = {}
- obj.nelem = self.nelem
- obj.tbl = {}
- obj.items = {}
+ local obj = {nelem = self.nelem, tbl = {}, items = {}} --- @type Set
for k, v in pairs(self.tbl) do
obj.tbl[k] = v
end
@@ -43,6 +46,7 @@ function Set:copy()
end
-- adds the argument Set to this Set
+--- @param other Set
function Set:union(other)
for e in other:iterator() do
self:add(e)
@@ -57,6 +61,7 @@ function Set:union_table(t)
end
-- subtracts the argument Set from this Set
+--- @param other Set
function Set:diff(other)
if other:size() > self:size() then
-- this set is smaller than the other set
@@ -75,6 +80,7 @@ function Set:diff(other)
end
end
+--- @param it string
function Set:add(it)
if not self:contains(it) then
local idx = #self.tbl + 1
@@ -84,6 +90,7 @@ function Set:add(it)
end
end
+--- @param it string
function Set:remove(it)
if self:contains(it) then
local idx = self.items[it]
@@ -93,10 +100,13 @@ function Set:remove(it)
end
end
+--- @param it string
+--- @return boolean
function Set:contains(it)
return self.items[it] or false
end
+--- @return integer
function Set:size()
return self.nelem
end
@@ -113,29 +123,18 @@ function Set:iterator()
return pairs(self.items)
end
+--- @return string[]
function Set:to_table()
-- there might be gaps in @tbl, so we have to be careful and sort first
- local keys
- do
- local _accum_0 = { }
- local _len_0 = 1
- for idx, _ in pairs(self.tbl) do
- _accum_0[_len_0] = idx
- _len_0 = _len_0 + 1
- end
- keys = _accum_0
+ local keys = {} --- @type string[]
+ for idx, _ in pairs(self.tbl) do
+ keys[#keys+1] = idx
end
+
table.sort(keys)
- local copy
- do
- local _accum_0 = { }
- local _len_0 = 1
- for _index_0 = 1, #keys do
- local idx = keys[_index_0]
- _accum_0[_len_0] = self.tbl[idx]
- _len_0 = _len_0 + 1
- end
- copy = _accum_0
+ local copy = {} --- @type string[]
+ for _, idx in ipairs(keys) do
+ copy[#copy+1] = self.tbl[idx]
end
return copy
end
diff --git a/test/unit/statusline_spec.lua b/test/unit/statusline_spec.lua
new file mode 100644
index 0000000000..a124a588e9
--- /dev/null
+++ b/test/unit/statusline_spec.lua
@@ -0,0 +1,282 @@
+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 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
+ local STL_INITIAL_ITEMS = 20
+ local output_buffer = ''
+
+ -- This function builds the statusline
+ --
+ -- @param arg Optional arguments are:
+ -- .pat The statusline format string
+ -- .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))
+
+ 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)
+ end
+
+ -- Use this function to simplify testing the comparison between
+ -- the format string and the resulting statusline.
+ --
+ -- @param description The description of what the test should be doing
+ -- @param statusline_cell_count The number of cells available in the statusline
+ -- @param input_stl The format string for the statusline
+ -- @param expected_stl The expected result string for the statusline
+ --
+ -- @param arg Options can be placed in an optional dictionary as the last parameter
+ -- .expected_cell_count The expected number of cells build_stl_str_hl will return
+ -- .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)
+
+ -- arg is the optional parameter
+ -- so we either fill in option with arg or an empty dictionary
+ local option = arg or {}
+
+ local fillchar = option.fillchar or (' '):byte()
+ local expected_cell_count = option.expected_cell_count or statusline_cell_count
+ local expected_byte_length = option.expected_byte_length or #expected_stl
+
+ itp(description, function()
+ if option.file_name then
+ buffer.setfname(globals.curbuf, to_cstr(option.file_name), NULL, 1)
+ else
+ 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}
+
+ eq(expected_stl, get_str(output_buffer, expected_byte_length))
+ eq(expected_cell_count, result_cell_count)
+ end)
+ 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')
+
+ -- 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})
+
+ -- 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})
+
+ -- standard text testing
+ 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})
+
+ -- 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 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 ignore trailing %', 3, 'abc%', 'abc')
+
+ -- alignment testing with fillchar
+ 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)
+ arg.fillchar = ('!'):byte()
+ 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)
+ 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 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 %=', 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,
+ '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,
+ ('%='):rep(STL_INITIAL_ITEMS * 5),
+ ' ') -- 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,
+ 'a' .. ('%=a'):rep(STL_INITIAL_ITEMS * 2),
+ '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()})
+
+ -- 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)
diff --git a/test/unit/strings_spec.lua b/test/unit/strings_spec.lua
index b2c839f25c..6d7aceb4b2 100644
--- a/test/unit/strings_spec.lua
+++ b/test/unit/strings_spec.lua
@@ -139,6 +139,99 @@ describe('vim_strchr()', function()
end)
end)
+describe('vim_snprintf()', function()
+ local function a(expected, buf, bsize, fmt, ...)
+ eq(#expected, strings.vim_snprintf(buf, bsize, fmt, ...))
+ if bsize > 0 then
+ local actual = ffi.string(buf, math.min(#expected + 1, bsize))
+ eq(expected:sub(1, bsize - 1) .. '\0', actual)
+ 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
+
+ itp('truncation', function()
+ for bsize = 0, 14 do
+ local buf = ffi.gc(strings.xmalloc(bsize), strings.xfree)
+ a('1.00000001e7', buf, bsize, '%.8g', 10000000.1)
+ a('1234567', buf, bsize, '%d', i(1234567))
+ a('1234567', buf, bsize, '%ld', l(1234567))
+ a(' 1234567', buf, bsize, '%9ld', l(1234567))
+ a('1234567 ', buf, bsize, '%-9ld', l(1234567))
+ a('deadbeef', buf, bsize, '%x', u(0xdeadbeef))
+ a('001100', buf, bsize, '%06b', u(12))
+ a('one two', buf, bsize, '%s %s', 'one', 'two')
+ a('1.234000', buf, bsize, '%f', 1.234)
+ a('1.234000e+00', buf, bsize, '%e', 1.234)
+ a('nan', buf, bsize, '%f', 0.0 / 0.0)
+ a('inf', buf, bsize, '%f', 1.0 / 0.0)
+ a('-inf', buf, bsize, '%f', -1.0 / 0.0)
+ a('-0.000000', buf, bsize, '%f', -0.0)
+ a('漢語', buf, bsize, '%s', '漢語')
+ a(' 漢語', buf, bsize, '%8s', '漢語')
+ a('漢語 ', buf, bsize, '%-8s', '漢語')
+ a('漢', buf, bsize, '%.3s', '漢語')
+ a(' foo', buf, bsize, '%5S', 'foo')
+ a('%%%', buf, bsize, '%%%%%%')
+ a('0x87654321', buf, bsize, '%p', ffi.cast('char *', 0x87654321))
+ a('0x0087654321', buf, bsize, '%012p', ffi.cast('char *', 0x87654321))
+ end
+ end)
+
+ itp('positional arguments', function()
+ for bsize = 0, 24 do
+ local buf = ffi.gc(strings.xmalloc(bsize), strings.xfree)
+ a('1234567 ', buf, bsize, '%1$*2$ld', l(1234567), i(-9))
+ a('1234567 ', buf, bsize, '%1$*2$.*3$ld', l(1234567), i(-9), i(5))
+ a('1234567 ', buf, bsize, '%1$*3$.*2$ld', l(1234567), i(5), i(-9))
+ a('1234567 ', buf, bsize, '%3$*1$.*2$ld', i(-9), i(5), l(1234567))
+ a('1234567', buf, bsize, '%1$ld', l(1234567))
+ a(' 1234567', buf, bsize, '%1$*2$ld', l(1234567), i(9))
+ a('9 12345 7654321', buf, bsize, '%2$ld %1$d %3$lu', i(12345), l(9), ul(7654321))
+ a('9 1234567 7654321', buf, bsize, '%2$d %1$ld %3$lu', l(1234567), i(9), ul(7654321))
+ a('9 1234567 7654321', buf, bsize, '%2$d %1$lld %3$lu', ll(1234567), i(9), ul(7654321))
+ a('9 12345 7654321', buf, bsize, '%2$ld %1$u %3$lu', u(12345), l(9), ul(7654321))
+ a('9 1234567 7654321', buf, bsize, '%2$d %1$lu %3$lu', ul(1234567), i(9), ul(7654321))
+ a('9 1234567 7654321', buf, bsize, '%2$d %1$llu %3$lu', ull(1234567), i(9), ul(7654321))
+ a('9 deadbeef 7654321', buf, bsize, '%2$d %1$x %3$lu', u(0xdeadbeef), i(9), ul(7654321))
+ a('9 c 7654321', buf, bsize, '%2$ld %1$c %3$lu', i(('c'):byte()), l(9), ul(7654321))
+ a('9 hi 7654321', buf, bsize, '%2$ld %1$s %3$lu', 'hi', l(9), ul(7654321))
+ a('9 0.000000e+00 7654321', buf, bsize, '%2$ld %1$e %3$lu', 0.0, l(9), ul(7654321))
+ a('two one two', buf, bsize, '%2$s %1$s %2$s', 'one', 'two', 'three')
+ a('three one two', buf, bsize, '%3$s %1$s %2$s', 'one', 'two', 'three')
+ a('1234567', buf, bsize, '%1$d', i(1234567))
+ a('deadbeef', buf, bsize, '%1$x', u(0xdeadbeef))
+ a('001100', buf, bsize, '%2$0*1$b', i(6), u(12))
+ a('001100', buf, bsize, '%1$0.*2$b', u(12), i(6))
+ a('one two', buf, bsize, '%1$s %2$s', 'one', 'two')
+ a('001100', buf, bsize, '%06b', u(12))
+ a('two one', buf, bsize, '%2$s %1$s', 'one', 'two')
+ a('1.234000', buf, bsize, '%1$f', 1.234)
+ a('1.234000e+00', buf, bsize, '%1$e', 1.234)
+ a('nan', buf, bsize, '%1$f', 0.0 / 0.0)
+ a('inf', buf, bsize, '%1$f', 1.0 / 0.0)
+ a('-inf', buf, bsize, '%1$f', -1.0 / 0.0)
+ a('-0.000000', buf, bsize, '%1$f', -0.0)
+ end
+ end)
+
+ itp('%zd and %zu', function()
+ local bsize = 20
+ local buf = ffi.gc(strings.xmalloc(bsize), strings.xfree)
+ a('-1234567 -7654321', buf, bsize, '%zd %zd', z(-1234567), z(-7654321))
+ a('-7654321 -1234567', buf, bsize, '%2$zd %1$zd', z(-1234567), z(-7654321))
+ a('1234567 7654321', buf, bsize, '%zu %zu', uz(1234567), uz(7654321))
+ a('7654321 1234567', buf, bsize, '%2$zu %1$zu', uz(1234567), uz(7654321))
+ end)
+end)
+
describe('strcase_save()' , function()
local strcase_save = function(input_string, upper)
local res = strings.strcase_save(to_cstr(input_string), upper)
diff --git a/test/unit/tempfile_spec.lua b/test/unit/tempfile_spec.lua
index 44bd19c1d2..e35490a561 100644
--- a/test/unit/tempfile_spec.lua
+++ b/test/unit/tempfile_spec.lua
@@ -1,4 +1,3 @@
-local lfs = require('lfs')
local helpers = require('test.unit.helpers')(after_each)
local itp = helpers.gen_itp(it)
@@ -30,7 +29,7 @@ describe('tempfile related functions', function()
-- os_file_is_writable returns 2 for a directory which we have rights
-- to write into.
eq(lib.os_file_is_writable(helpers.to_cstr(dir)), 2)
- for entry in lfs.dir(dir) do
+ for entry in vim.fs.dir(dir) do
assert.True(entry == '.' or entry == '..')
end
end)
diff --git a/test/unit/tui_spec.lua b/test/unit/tui_spec.lua
deleted file mode 100644
index 25b70a17c2..0000000000
--- a/test/unit/tui_spec.lua
+++ /dev/null
@@ -1,162 +0,0 @@
-local helpers = require("test.unit.helpers")(after_each)
-local cimport = helpers.cimport
-local eq = helpers.eq
-local ffi = helpers.ffi
-local itp = helpers.gen_itp(it)
-local to_cstr = helpers.to_cstr
-
-local cinput = cimport("./src/nvim/tui/input.h")
-local rbuffer = cimport("./test/unit/fixtures/rbuffer.h")
-local globals = cimport("./src/nvim/globals.h")
-local multiqueue = cimport("./test/unit/fixtures/multiqueue.h")
-local ui_client = cimport("./src/nvim/ui_client.h")
-
-itp('handle_background_color', function()
- local handle_background_color = cinput.ut_handle_background_color
- local term_input = ffi.new('TermInput', {})
- local events = globals.main_loop.thread_events
- local kIncomplete = cinput.kIncomplete
- local kNotApplicable = cinput.kNotApplicable
- local kComplete = cinput.kComplete
-
- -- Short-circuit when not waiting for response.
- term_input.waiting_for_bg_response = 0
- eq(kNotApplicable, handle_background_color(term_input))
-
- local capacity = 100
- local rbuf = ffi.gc(rbuffer.rbuffer_new(capacity), rbuffer.rbuffer_free)
- term_input.read_stream.buffer = rbuf
-
- local function assert_bg(colorspace, color, bg)
- local term_response = '\027]11;'..colorspace..':'..color..'\007'
- rbuffer.rbuffer_write(rbuf, to_cstr(term_response), #term_response)
-
- term_input.waiting_for_bg_response = 1
- eq(kComplete, handle_background_color(term_input))
- eq(0, term_input.waiting_for_bg_response)
- eq(0, multiqueue.multiqueue_size(events))
- eq(bg, ({[0]="light", [1] = "dark", [-1] = "none"})
- [tonumber(ui_client.ui_client_bg_response)])
-
- -- Buffer has been consumed.
- eq(0, rbuf.size)
- end
-
- assert_bg('rgb', '0000/0000/0000', 'dark')
- assert_bg('rgb', 'ffff/ffff/ffff', 'light')
- assert_bg('rgb', '000/000/000', 'dark')
- assert_bg('rgb', 'fff/fff/fff', 'light')
- assert_bg('rgb', '00/00/00', 'dark')
- assert_bg('rgb', 'ff/ff/ff', 'light')
- assert_bg('rgb', '0/0/0', 'dark')
- assert_bg('rgb', 'f/f/f', 'light')
-
- assert_bg('rgb', 'f/0/0', 'dark')
- assert_bg('rgb', '0/f/0', 'light')
- assert_bg('rgb', '0/0/f', 'dark')
-
- assert_bg('rgb', '1/1/1', 'dark')
- assert_bg('rgb', '2/2/2', 'dark')
- assert_bg('rgb', '3/3/3', 'dark')
- assert_bg('rgb', '4/4/4', 'dark')
- assert_bg('rgb', '5/5/5', 'dark')
- assert_bg('rgb', '6/6/6', 'dark')
- assert_bg('rgb', '7/7/7', 'dark')
- assert_bg('rgb', '8/8/8', 'light')
- assert_bg('rgb', '9/9/9', 'light')
- assert_bg('rgb', 'a/a/a', 'light')
- assert_bg('rgb', 'b/b/b', 'light')
- assert_bg('rgb', 'c/c/c', 'light')
- assert_bg('rgb', 'd/d/d', 'light')
- assert_bg('rgb', 'e/e/e', 'light')
-
- assert_bg('rgb', '0/e/0', 'light')
- assert_bg('rgb', '0/d/0', 'light')
- assert_bg('rgb', '0/c/0', 'dark')
- assert_bg('rgb', '0/b/0', 'dark')
-
- assert_bg('rgb', 'f/0/f', 'dark')
- assert_bg('rgb', 'f/1/f', 'dark')
- assert_bg('rgb', 'f/2/f', 'dark')
- assert_bg('rgb', 'f/3/f', 'light')
- assert_bg('rgb', 'f/4/f', 'light')
-
- assert_bg('rgba', '0000/0000/0000/0000', 'dark')
- assert_bg('rgba', '0000/0000/0000/ffff', 'dark')
- assert_bg('rgba', 'ffff/ffff/ffff/0000', 'light')
- assert_bg('rgba', 'ffff/ffff/ffff/ffff', 'light')
- assert_bg('rgba', '000/000/000/000', 'dark')
- assert_bg('rgba', '000/000/000/fff', 'dark')
- assert_bg('rgba', 'fff/fff/fff/000', 'light')
- assert_bg('rgba', 'fff/fff/fff/fff', 'light')
- assert_bg('rgba', '00/00/00/00', 'dark')
- assert_bg('rgba', '00/00/00/ff', 'dark')
- assert_bg('rgba', 'ff/ff/ff/00', 'light')
- assert_bg('rgba', 'ff/ff/ff/ff', 'light')
- assert_bg('rgba', '0/0/0/0', 'dark')
- assert_bg('rgba', '0/0/0/f', 'dark')
- assert_bg('rgba', 'f/f/f/0', 'light')
- assert_bg('rgba', 'f/f/f/f', 'light')
-
-
- -- Incomplete sequence: necessarily correct behavior.
- local term_response = '\027]11;rgba:f/f/f/f' -- missing '\007
- rbuffer.rbuffer_write(rbuf, to_cstr(term_response), #term_response)
-
- term_input.waiting_for_bg_response = 1
- eq(kIncomplete, handle_background_color(term_input))
- eq(1, term_input.waiting_for_bg_response)
- eq(#term_response, rbuf.size)
-
- term_response = '\007'
- rbuffer.rbuffer_write(rbuf, to_cstr(term_response), #term_response)
- eq(kComplete, handle_background_color(term_input))
- eq(0, term_input.waiting_for_bg_response)
-
- eq(0, tonumber(ui_client.ui_client_bg_response))
- eq(0, multiqueue.multiqueue_size(events))
- eq(0, rbuf.size)
-
- term_response = '\027]11;rg'
- rbuffer.rbuffer_write(rbuf, to_cstr(term_response), #term_response)
-
- term_input.waiting_for_bg_response = 1
- eq(kIncomplete, handle_background_color(term_input))
- eq(1, term_input.waiting_for_bg_response)
- eq(#term_response, rbuf.size)
-
- term_response = 'ba:f/f/f/f\007'
- rbuffer.rbuffer_write(rbuf, to_cstr(term_response), #term_response)
- eq(kComplete, handle_background_color(term_input))
- eq(0, term_input.waiting_for_bg_response)
-
- eq(0, tonumber(ui_client.ui_client_bg_response))
- eq(0, multiqueue.multiqueue_size(events))
- eq(0, rbuf.size)
-
-
- -- Does nothing when not at start of buffer.
- term_response = '123\027]11;rgba:f/f/f/f\007456'
- rbuffer.rbuffer_write(rbuf, to_cstr(term_response), #term_response)
-
- term_input.waiting_for_bg_response = 3
- eq(kNotApplicable, handle_background_color(term_input))
- eq(2, term_input.waiting_for_bg_response)
-
- eq(0, multiqueue.multiqueue_size(events))
- eq(#term_response, rbuf.size)
- rbuffer.rbuffer_consumed(rbuf, #term_response)
-
-
- -- Keeps trailing buffer.
- term_response = '\027]11;rgba:f/f/f/f\007456'
- rbuffer.rbuffer_write(rbuf, to_cstr(term_response), #term_response)
-
- term_input.waiting_for_bg_response = 1
- eq(kComplete, handle_background_color(term_input))
- eq(0, term_input.waiting_for_bg_response)
-
- eq(0, multiqueue.multiqueue_size(events))
- eq(3, rbuf.size)
- rbuffer.rbuffer_consumed(rbuf, rbuf.size)
-end)
diff --git a/test/unit/undo_spec.lua b/test/unit/undo_spec.lua
index f7f8d26d58..ee4203b94c 100644
--- a/test/unit/undo_spec.lua
+++ b/test/unit/undo_spec.lua
@@ -1,6 +1,6 @@
local helpers = require('test.unit.helpers')(after_each)
local itp = helpers.gen_itp(it)
-local lfs = require('lfs')
+local luv = require('luv')
local child_call_once = helpers.child_call_once
local sleep = helpers.sleep
@@ -9,11 +9,9 @@ local cimport = helpers.cimport
local to_cstr = helpers.to_cstr
local neq = helpers.neq
local eq = helpers.eq
+local mkdir = helpers.mkdir
-cimport('./src/nvim/ex_cmds_defs.h')
-cimport('./src/nvim/buffer_defs.h')
-local options = cimport('./src/nvim/option_defs.h')
--- TODO: remove: local vim = cimport('./src/nvim/vim.h')
+local options = cimport('./src/nvim/option_vars.h')
local undo = cimport('./src/nvim/undo.h')
local buffer = cimport('./src/nvim/buffer.h')
@@ -37,21 +35,21 @@ child_call_once(function()
-- requires refactor of UNDO_HASH_SIZE into constant/enum for ffi
--
-- compute a hash for this undofile
- buffer_hash = ffi.new('char_u[32]')
+ buffer_hash = ffi.new('char[32]')
undo.u_compute_hash(file_buffer, buffer_hash)
end)
describe('u_write_undo', function()
setup(function()
- lfs.mkdir('unit-test-directory')
- lfs.chdir('unit-test-directory')
- options.p_udir = to_cstr(lfs.currentdir()) -- set p_udir to be the test dir
+ mkdir('unit-test-directory')
+ luv.chdir('unit-test-directory')
+ options.p_udir = to_cstr(luv.cwd()) -- set p_udir to be the test dir
end)
teardown(function()
- lfs.chdir('..')
- local success, err = lfs.rmdir('unit-test-directory')
+ luv.chdir('..')
+ local success, err = luv.fs_rmdir('unit-test-directory')
if not success then
print(err) -- inform tester if directory fails to delete
end
@@ -102,7 +100,7 @@ describe('u_write_undo', function()
local test_permission_file = io.open(test_file_name, "w")
test_permission_file:write("testing permissions")
test_permission_file:close()
- local test_permissions = lfs.attributes(test_file_name).permissions
+ local test_permissions = luv.fs_stat(test_file_name).mode
-- Create vim buffer
local c_file = to_cstr(test_file_name)
@@ -115,7 +113,7 @@ describe('u_write_undo', function()
local undo_file_name = ffi.string(undo.u_get_undo_file_name(file_buffer.b_ffname, false))
-- Find out the permissions of the new file
- local permissions = lfs.attributes(undo_file_name).permissions
+ local permissions = luv.fs_stat(undo_file_name).mode
eq(test_permissions, permissions)
-- delete the file now that we're done with it.
@@ -130,7 +128,7 @@ describe('u_write_undo', function()
end)
itp('writes an undofile only readable by the user if the buffer is unnamed', function()
- local correct_permissions = "rw-------"
+ local correct_permissions = 33152
local undo_file_name = "test.undo"
-- Create vim buffer
@@ -140,7 +138,7 @@ describe('u_write_undo', function()
u_write_undo(undo_file_name, false, file_buffer, buffer_hash)
-- Find out the permissions of the new file
- local permissions = lfs.attributes(undo_file_name).permissions
+ local permissions = luv.fs_stat(undo_file_name).mode
eq(correct_permissions, permissions)
-- delete the file now that we're done with it.
@@ -172,13 +170,13 @@ describe('u_write_undo', 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 file_last_modified = lfs.attributes(correct_name).modification
+ 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
u_write_undo(nil, false, file_buffer, buffer_hash)
- local file_last_modified_2 = lfs.attributes(correct_name).modification
+ 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)