mirror of
https://github.com/neovim/neovim.git
synced 2025-09-07 03:48:18 +00:00
Merge #6214 from ZyX-I/split-eval'/isolated-unittests
Run all unit tests in separate processes
This commit is contained in:
101
test/README.md
Normal file
101
test/README.md
Normal file
@@ -0,0 +1,101 @@
|
||||
# Tests
|
||||
|
||||
Tests are run by `/cmake/RunTests.cmake` file, using busted.
|
||||
|
||||
## Directory structure
|
||||
|
||||
Directories with tests: `/test/benchmark` for benchmarks, `/test/functional` for
|
||||
functional tests, `/test/unit` for unit tests. `/test/config` contains `*.in`
|
||||
files (currently a single one) which are transformed into `*.lua` files using
|
||||
`configure_file` CMake command: this is for acessing CMake variables in lua
|
||||
tests. `/test/includes` contains include files for use by luajit `ffi.cdef`
|
||||
C definitions parser: normally used to make macros not accessible via this
|
||||
mechanism accessible the other way.
|
||||
|
||||
Files `/test/*/preload.lua` contain modules which will be preloaded by busted,
|
||||
via `--helper` option. `/test/**/helpers.lua` contain various “library”
|
||||
functions, (intended to be) used by a number of tests and not just a single one.
|
||||
|
||||
`/test/*/**/*_spec.lua` are files containing actual tests. Files that do not end
|
||||
with a `_spec.lua` are libraries like `/test/**/helpers.lua`, except that they
|
||||
have some common topic.
|
||||
|
||||
Tests inside `/test/unit` and `/test/functional` are normally divided into
|
||||
groups by the semantic component they are testing.
|
||||
|
||||
## Environment variables
|
||||
|
||||
Test behaviour is affected by environment variables. Currently supported
|
||||
(Functional, Unit, Benchmarks) (when Defined; when set to _1_; when defined,
|
||||
treated as Integer; when defined, treated as String; !must be defined to
|
||||
function properly):
|
||||
|
||||
`GDB` (F) (D): makes nvim instances to be run under `gdbserver`. It will be
|
||||
accessible on `localhost:7777`: use `gdb build/bin/nvim`, type `target remote
|
||||
:7777` inside.
|
||||
|
||||
`GDBSERVER_PORT` (F) (I): overrides port used for `GDB`.
|
||||
|
||||
`VALGRIND` (F) (D): makes nvim instances to be run under `valgrind`. Log files
|
||||
are named `valgrind-%p.log` in this case. Note that non-empty valgrind log may
|
||||
fail tests. Valgrind arguments may be seen in `/test/functional/helpers.lua`.
|
||||
May be used in conjunction with `GDB`.
|
||||
|
||||
`VALGRIND_LOG` (F) (S): overrides valgrind log file name used for `VALGRIND`.
|
||||
|
||||
`TEST_SKIP_FRAGILE` (F) (D): makes test suite skip some fragile tests.
|
||||
|
||||
`NVIM_PROG`, `NVIM_PRG` (F) (S): override path to Neovim executable (default to
|
||||
`build/bin/nvim`).
|
||||
|
||||
`CC` (U) (S): specifies which C compiler to use to preprocess files. Currently
|
||||
only compilers with gcc-compatible arguments are supported.
|
||||
|
||||
`NVIM_TEST_MAIN_CDEFS` (U) (1): makes `ffi.cdef` run in main process. This
|
||||
raises a possibility of bugs due to conflicts in header definitions, despite the
|
||||
counters, but greatly speeds up unit tests by not requiring `ffi.cdef` to do
|
||||
parsing of big strings with C definitions.
|
||||
|
||||
`NVIM_TEST_PRINT_I` (U) (1): makes `cimport` print preprocessed, but not yet
|
||||
filtered through `formatc` headers. Used to debug `formatc`. Printing is done
|
||||
with the line numbers.
|
||||
|
||||
`NVIM_TEST_PRINT_CDEF` (U) (1): makes `cimport` print final lines which will be
|
||||
then passed to `ffi.cdef`. Used to debug errors `ffi.cdef` happens to throw
|
||||
sometimes.
|
||||
|
||||
`NVIM_TEST_PRINT_SYSCALLS` (U) (1): makes it print to stderr when syscall
|
||||
wrappers are called and what they returned. Used to debug code which makes unit
|
||||
tests be executed in separate processes.
|
||||
|
||||
`NVIM_TEST_RUN_FAILING_TESTS` (U) (1): makes `itp` run tests which are known to
|
||||
fail (marked by setting third argument to `true`).
|
||||
|
||||
`LOG_DIR` (FU) (S!): specifies where to seek for valgrind and ASAN log files.
|
||||
|
||||
`NVIM_TEST_CORE_*` (FU) (S): a set of environment variables which specify where
|
||||
to search for core files. Are supposed to be defined all at once.
|
||||
|
||||
`NVIM_TEST_CORE_GLOB_DIRECTORY` (FU) (S): directory where core files are
|
||||
located. May be `.`. This directory is then recursively searched for core files.
|
||||
Note: this variable must be defined for any of the following to have any effect.
|
||||
|
||||
`NVIM_TEST_CORE_GLOB_RE` (FU) (S): regular expression which must be matched by
|
||||
core files. E.g. `/core[^/]*$`. May be absent, in which case any file is
|
||||
considered to be matched.
|
||||
|
||||
`NVIM_TEST_CORE_EXC_RE` (FU) (S): regular expression which excludes certain
|
||||
directories from searching for core files inside. E.g. use `^/%.deps$` to not
|
||||
search inside `/.deps`. If absent, nothing is excluded.
|
||||
|
||||
`NVIM_TEST_CORE_DB_CMD` (FU) (S): command to get backtrace out of the debugger.
|
||||
E.g. `gdb -n -batch -ex "thread apply all bt full" "$_NVIM_TEST_APP" -c
|
||||
"$_NVIM_TEST_CORE"`. Defaults to the example command. This debug command may use
|
||||
environment variables `_NVIM_TEST_APP` (path to application which is being
|
||||
debugged: normally either nvim or luajit) and `_NVIM_TEST_CORE` (core file to
|
||||
get backtrace from).
|
||||
|
||||
`NVIM_TEST_CORE_RANDOM_SKIP` (FU) (D): makes `check_cores` not check cores after
|
||||
approximately 90% of the tests. Should be used when finding cores is too hard
|
||||
for some reason. Normally (on OS X or when `NVIM_TEST_CORE_GLOB_DIRECTORY` is
|
||||
defined and this variable is not) cores are checked for after each test.
|
@@ -8,6 +8,15 @@ end
|
||||
module.test_include_path = "${CMAKE_BINARY_DIR}/test/includes/post"
|
||||
module.test_libnvim_path = "${TEST_LIBNVIM_PATH}"
|
||||
module.test_source_path = "${CMAKE_SOURCE_DIR}"
|
||||
module.test_lua_prg = "${LUA_PRG}"
|
||||
module.test_luajit_prg = ""
|
||||
if module.test_luajit_prg == '' then
|
||||
if module.test_lua_prg:sub(-6) == 'luajit' then
|
||||
module.test_luajit_prg = module.test_lua_prg
|
||||
else
|
||||
module.test_luajit_prg = nil
|
||||
end
|
||||
end
|
||||
table.insert(module.include_paths, "${CMAKE_BINARY_DIR}/include")
|
||||
|
||||
return module
|
||||
|
@@ -30,13 +30,15 @@ local function glob(initial_path, re, exc_re)
|
||||
if ((not exc_re or not checked_path:match(exc_re))
|
||||
and e:sub(1, 1) ~= '.') then
|
||||
local attrs = lfs.attributes(full_path)
|
||||
local check_key = attrs.dev .. ':' .. tostring(attrs.ino)
|
||||
if not checked_files[check_key] then
|
||||
checked_files[check_key] = true
|
||||
if attrs.mode == 'directory' then
|
||||
paths_to_check[#paths_to_check + 1] = full_path
|
||||
elseif not re or checked_path:match(re) then
|
||||
ret[#ret + 1] = full_path
|
||||
if attrs then
|
||||
local check_key = attrs.dev .. ':' .. tostring(attrs.ino)
|
||||
if not checked_files[check_key] then
|
||||
checked_files[check_key] = true
|
||||
if attrs.mode == 'directory' then
|
||||
paths_to_check[#paths_to_check + 1] = full_path
|
||||
elseif not re or checked_path:match(re) then
|
||||
ret[#ret + 1] = full_path
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -212,6 +214,17 @@ local function check_cores(app)
|
||||
end
|
||||
end
|
||||
|
||||
local function which(exe)
|
||||
local pipe = io.popen('which ' .. exe, 'r')
|
||||
local ret = pipe:read('*a')
|
||||
pipe:close()
|
||||
if ret == '' then
|
||||
return nil
|
||||
else
|
||||
return ret:sub(1, -2)
|
||||
end
|
||||
end
|
||||
|
||||
return {
|
||||
eq = eq,
|
||||
neq = neq,
|
||||
@@ -224,4 +237,5 @@ return {
|
||||
glob = glob,
|
||||
check_cores = check_cores,
|
||||
hasenv = hasenv,
|
||||
which = which,
|
||||
}
|
||||
|
@@ -1,4 +1,4 @@
|
||||
local helpers = require('test.unit.helpers')
|
||||
local helpers = require('test.unit.helpers')(nil)
|
||||
local eval_helpers = require('test.unit.eval.helpers')
|
||||
|
||||
local cimport = helpers.cimport
|
||||
@@ -19,47 +19,55 @@ local api = cimport('./src/nvim/api/private/defs.h',
|
||||
|
||||
local obj2lua
|
||||
|
||||
local obj2lua_tab = {
|
||||
[tonumber(api.kObjectTypeArray)] = function(obj)
|
||||
local ret = {[type_key]=list_type}
|
||||
for i = 1,tonumber(obj.data.array.size) do
|
||||
ret[i] = obj2lua(obj.data.array.items[i - 1])
|
||||
end
|
||||
if ret[1] then
|
||||
ret[type_key] = nil
|
||||
end
|
||||
return ret
|
||||
end,
|
||||
[tonumber(api.kObjectTypeDictionary)] = function(obj)
|
||||
local ret = {}
|
||||
for i = 1,tonumber(obj.data.dictionary.size) do
|
||||
local kv_pair = obj.data.dictionary.items[i - 1]
|
||||
ret[ffi.string(kv_pair.key.data, kv_pair.key.size)] = obj2lua(kv_pair.value)
|
||||
end
|
||||
return ret
|
||||
end,
|
||||
[tonumber(api.kObjectTypeBoolean)] = function(obj)
|
||||
if obj.data.boolean == false then
|
||||
return false
|
||||
else
|
||||
return true
|
||||
end
|
||||
end,
|
||||
[tonumber(api.kObjectTypeNil)] = function(_)
|
||||
return nil_value
|
||||
end,
|
||||
[tonumber(api.kObjectTypeFloat)] = function(obj)
|
||||
return tonumber(obj.data.floating)
|
||||
end,
|
||||
[tonumber(api.kObjectTypeInteger)] = function(obj)
|
||||
return {[type_key]=int_type, value=tonumber(obj.data.integer)}
|
||||
end,
|
||||
[tonumber(api.kObjectTypeString)] = function(obj)
|
||||
return ffi.string(obj.data.string.data, obj.data.string.size)
|
||||
end,
|
||||
}
|
||||
local obj2lua_tab = nil
|
||||
|
||||
local function init_obj2lua_tab()
|
||||
if obj2lua_tab then
|
||||
return
|
||||
end
|
||||
obj2lua_tab = {
|
||||
[tonumber(api.kObjectTypeArray)] = function(obj)
|
||||
local ret = {[type_key]=list_type}
|
||||
for i = 1,tonumber(obj.data.array.size) do
|
||||
ret[i] = obj2lua(obj.data.array.items[i - 1])
|
||||
end
|
||||
if ret[1] then
|
||||
ret[type_key] = nil
|
||||
end
|
||||
return ret
|
||||
end,
|
||||
[tonumber(api.kObjectTypeDictionary)] = function(obj)
|
||||
local ret = {}
|
||||
for i = 1,tonumber(obj.data.dictionary.size) do
|
||||
local kv_pair = obj.data.dictionary.items[i - 1]
|
||||
ret[ffi.string(kv_pair.key.data, kv_pair.key.size)] = obj2lua(kv_pair.value)
|
||||
end
|
||||
return ret
|
||||
end,
|
||||
[tonumber(api.kObjectTypeBoolean)] = function(obj)
|
||||
if obj.data.boolean == false then
|
||||
return false
|
||||
else
|
||||
return true
|
||||
end
|
||||
end,
|
||||
[tonumber(api.kObjectTypeNil)] = function(_)
|
||||
return nil_value
|
||||
end,
|
||||
[tonumber(api.kObjectTypeFloat)] = function(obj)
|
||||
return tonumber(obj.data.floating)
|
||||
end,
|
||||
[tonumber(api.kObjectTypeInteger)] = function(obj)
|
||||
return {[type_key]=int_type, value=tonumber(obj.data.integer)}
|
||||
end,
|
||||
[tonumber(api.kObjectTypeString)] = function(obj)
|
||||
return ffi.string(obj.data.string.data, obj.data.string.size)
|
||||
end,
|
||||
}
|
||||
end
|
||||
|
||||
obj2lua = function(obj)
|
||||
init_obj2lua_tab()
|
||||
return ((obj2lua_tab[tonumber(obj['type'])] or function(obj_inner)
|
||||
assert(false, 'Converting ' .. tostring(tonumber(obj_inner['type'])) .. ' is not implementing yet')
|
||||
end)(obj))
|
||||
|
@@ -1,4 +1,5 @@
|
||||
local helpers = require('test.unit.helpers')
|
||||
local helpers = require('test.unit.helpers')(after_each)
|
||||
local itp = helpers.gen_itp(it)
|
||||
local eval_helpers = require('test.unit.eval.helpers')
|
||||
local api_helpers = require('test.unit.api.helpers')
|
||||
|
||||
@@ -25,7 +26,7 @@ describe('vim_to_object', function()
|
||||
end
|
||||
|
||||
local different_output_test = function(name, input, output)
|
||||
it(name, function()
|
||||
itp(name, function()
|
||||
eq(output, vim_to_object(input))
|
||||
end)
|
||||
end
|
||||
@@ -76,19 +77,19 @@ describe('vim_to_object', function()
|
||||
different_output_test('outputs nil for nested lists (2 level, in dict)',
|
||||
lst3, {{lst=nil_value}, true, false, 'ttest'})
|
||||
|
||||
it('outputs empty list for NULL list', function()
|
||||
itp('outputs empty list for NULL list', function()
|
||||
local tt = typvalt('VAR_LIST', {v_list=NULL})
|
||||
eq(nil, tt.vval.v_list)
|
||||
eq({[type_key]=list_type}, obj2lua(api.vim_to_object(tt)))
|
||||
end)
|
||||
|
||||
it('outputs empty dict for NULL dict', function()
|
||||
itp('outputs empty dict for NULL dict', function()
|
||||
local tt = typvalt('VAR_DICT', {v_dict=NULL})
|
||||
eq(nil, tt.vval.v_dict)
|
||||
eq({}, obj2lua(api.vim_to_object(tt)))
|
||||
end)
|
||||
|
||||
it('regression: partials in a list', function()
|
||||
itp('regression: partials in a list', function()
|
||||
local llist = {
|
||||
{
|
||||
[type_key]=func_type,
|
||||
|
@@ -1,5 +1,6 @@
|
||||
|
||||
local helpers = require("test.unit.helpers")
|
||||
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
|
||||
@@ -39,17 +40,17 @@ describe('buffer functions', function()
|
||||
|
||||
describe('buf_valid', function()
|
||||
|
||||
it('should view NULL as an invalid buffer', function()
|
||||
itp('should view NULL as an invalid buffer', function()
|
||||
eq(false, buffer.buf_valid(NULL))
|
||||
end)
|
||||
|
||||
it('should view an open buffer as valid', function()
|
||||
itp('should view an open buffer as valid', function()
|
||||
local buf = buflist_new(path1, buffer.BLN_LISTED)
|
||||
|
||||
eq(true, buffer.buf_valid(buf))
|
||||
end)
|
||||
|
||||
it('should view a closed and hidden buffer as valid', function()
|
||||
itp('should view a closed and hidden buffer as valid', function()
|
||||
local buf = buflist_new(path1, buffer.BLN_LISTED)
|
||||
|
||||
close_buffer(NULL, buf, 0, 0)
|
||||
@@ -57,7 +58,7 @@ describe('buffer functions', function()
|
||||
eq(true, buffer.buf_valid(buf))
|
||||
end)
|
||||
|
||||
it('should view a closed and unloaded buffer as valid', function()
|
||||
itp('should view a closed and unloaded buffer as valid', function()
|
||||
local buf = buflist_new(path1, buffer.BLN_LISTED)
|
||||
|
||||
close_buffer(NULL, buf, buffer.DOBUF_UNLOAD, 0)
|
||||
@@ -65,7 +66,7 @@ describe('buffer functions', function()
|
||||
eq(true, buffer.buf_valid(buf))
|
||||
end)
|
||||
|
||||
it('should view a closed and wiped buffer as invalid', function()
|
||||
itp('should view a closed and wiped buffer as invalid', function()
|
||||
local buf = buflist_new(path1, buffer.BLN_LISTED)
|
||||
|
||||
close_buffer(NULL, buf, buffer.DOBUF_WIPE, 0)
|
||||
@@ -84,7 +85,7 @@ describe('buffer functions', function()
|
||||
return buffer.buflist_findpat(to_cstr(pat), NULL, allow_unlisted, 0, 0)
|
||||
end
|
||||
|
||||
it('should find exact matches', function()
|
||||
itp('should find exact matches', function()
|
||||
local buf = buflist_new(path1, buffer.BLN_LISTED)
|
||||
|
||||
eq(buf.handle, buflist_findpat(path1, ONLY_LISTED))
|
||||
@@ -92,7 +93,7 @@ describe('buffer functions', function()
|
||||
close_buffer(NULL, buf, buffer.DOBUF_WIPE, 0)
|
||||
end)
|
||||
|
||||
it('should prefer to match the start of a file path', function()
|
||||
itp('should prefer to match the start of a file path', function()
|
||||
local buf1 = buflist_new(path1, buffer.BLN_LISTED)
|
||||
local buf2 = buflist_new(path2, buffer.BLN_LISTED)
|
||||
local buf3 = buflist_new(path3, buffer.BLN_LISTED)
|
||||
@@ -106,7 +107,7 @@ describe('buffer functions', function()
|
||||
close_buffer(NULL, buf3, buffer.DOBUF_WIPE, 0)
|
||||
end)
|
||||
|
||||
it('should prefer to match the end of a file over the middle', function()
|
||||
itp('should prefer to match the end of a file over the middle', function()
|
||||
--{ Given: Two buffers, where 'test' appears in both
|
||||
-- And: 'test' appears at the end of buf3 but in the middle of buf2
|
||||
local buf2 = buflist_new(path2, buffer.BLN_LISTED)
|
||||
@@ -130,7 +131,7 @@ describe('buffer functions', function()
|
||||
close_buffer(NULL, buf3, buffer.DOBUF_WIPE, 0)
|
||||
end)
|
||||
|
||||
it('should match a unique fragment of a file path', function()
|
||||
itp('should match a unique fragment of a file path', function()
|
||||
local buf1 = buflist_new(path1, buffer.BLN_LISTED)
|
||||
local buf2 = buflist_new(path2, buffer.BLN_LISTED)
|
||||
local buf3 = buflist_new(path3, buffer.BLN_LISTED)
|
||||
@@ -142,7 +143,7 @@ describe('buffer functions', function()
|
||||
close_buffer(NULL, buf3, buffer.DOBUF_WIPE, 0)
|
||||
end)
|
||||
|
||||
it('should include / ignore unlisted buffers based on the flag.', function()
|
||||
itp('should include / ignore unlisted buffers based on the flag.', function()
|
||||
--{ Given: A buffer
|
||||
local buf3 = buflist_new(path3, buffer.BLN_LISTED)
|
||||
|
||||
@@ -169,7 +170,7 @@ describe('buffer functions', function()
|
||||
--}
|
||||
end)
|
||||
|
||||
it('should prefer listed buffers to unlisted buffers.', function()
|
||||
itp('should prefer listed buffers to unlisted buffers.', function()
|
||||
--{ Given: Two buffers that match a pattern
|
||||
local buf1 = buflist_new(path1, buffer.BLN_LISTED)
|
||||
local buf2 = buflist_new(path2, buffer.BLN_LISTED)
|
||||
@@ -265,7 +266,7 @@ describe('buffer functions', function()
|
||||
local expected_cell_count = option.expected_cell_count or statusline_cell_count
|
||||
local expected_byte_length = option.expected_byte_length or expected_cell_count
|
||||
|
||||
it(description, function()
|
||||
itp(description, function()
|
||||
if option.file_name then
|
||||
buffer.setfname(globals.curbuf, to_cstr(option.file_name), NULL, 1)
|
||||
else
|
||||
|
@@ -1,4 +1,5 @@
|
||||
local helpers = require('test.unit.helpers')
|
||||
local helpers = require('test.unit.helpers')(after_each)
|
||||
local itp = helpers.gen_itp(it)
|
||||
|
||||
local cimport = helpers.cimport
|
||||
local to_cstr = helpers.to_cstr
|
||||
@@ -11,25 +12,11 @@ local decode = cimport('./src/nvim/eval/decode.h', './src/nvim/eval_defs.h',
|
||||
'./src/nvim/message.h')
|
||||
|
||||
describe('json_decode_string()', function()
|
||||
local saved_p_enc = nil
|
||||
|
||||
before_each(function()
|
||||
saved_p_enc = decode.p_enc
|
||||
end)
|
||||
|
||||
after_each(function()
|
||||
decode.emsg_silent = 0
|
||||
decode.p_enc = saved_p_enc
|
||||
while decode.delete_first_msg() == 1 do
|
||||
-- Delete all messages
|
||||
end
|
||||
end)
|
||||
|
||||
local char = function(c)
|
||||
return ffi.gc(decode.xmemdup(c, 1), decode.xfree)
|
||||
end
|
||||
|
||||
it('does not overflow when running with `n…`, `t…`, `f…`', function()
|
||||
itp('does not overflow when running with `n…`, `t…`, `f…`', function()
|
||||
local rettv = ffi.new('typval_T', {v_type=decode.VAR_UNKNOWN})
|
||||
decode.emsg_silent = 1
|
||||
-- This will not crash, but if `len` argument will be ignored it will parse
|
||||
@@ -56,7 +43,7 @@ describe('json_decode_string()', function()
|
||||
eq(decode.VAR_UNKNOWN, rettv.v_type)
|
||||
end)
|
||||
|
||||
it('does not overflow and crash when running with `n`, `t`, `f`', function()
|
||||
itp('does not overflow and crash when running with `n`, `t`, `f`', function()
|
||||
local rettv = ffi.new('typval_T', {v_type=decode.VAR_UNKNOWN})
|
||||
decode.emsg_silent = 1
|
||||
eq(0, decode.json_decode_string(char('n'), 1, rettv))
|
||||
@@ -67,7 +54,7 @@ describe('json_decode_string()', function()
|
||||
eq(decode.VAR_UNKNOWN, rettv.v_type)
|
||||
end)
|
||||
|
||||
it('does not overflow when running with `"…`', function()
|
||||
itp('does not overflow when running with `"…`', function()
|
||||
local rettv = ffi.new('typval_T', {v_type=decode.VAR_UNKNOWN})
|
||||
decode.emsg_silent = 1
|
||||
eq(0, decode.json_decode_string('"t"', 2, rettv))
|
||||
@@ -84,7 +71,8 @@ describe('json_decode_string()', function()
|
||||
eq(msg, ffi.string(decode.last_msg_hist.msg))
|
||||
end
|
||||
|
||||
it('does not overflow in error messages', function()
|
||||
itp('does not overflow in error messages', function()
|
||||
local saved_p_enc = decode.p_enc
|
||||
check_failure(']test', 1, 'E474: No container to close: ]')
|
||||
check_failure('[}test', 2, 'E474: Closing list with curly bracket: }')
|
||||
check_failure('{]test', 2,
|
||||
@@ -129,11 +117,11 @@ describe('json_decode_string()', function()
|
||||
check_failure('[1test', 2, 'E474: Unexpected end of input: [1')
|
||||
end)
|
||||
|
||||
it('does not overflow with `-`', function()
|
||||
itp('does not overflow with `-`', function()
|
||||
check_failure('-0', 1, 'E474: Missing number after minus sign: -')
|
||||
end)
|
||||
|
||||
it('does not overflow and crash when running with `"`', function()
|
||||
itp('does not overflow and crash when running with `"`', function()
|
||||
local rettv = ffi.new('typval_T', {v_type=decode.VAR_UNKNOWN})
|
||||
decode.emsg_silent = 1
|
||||
eq(0, decode.json_decode_string(char('"'), 1, rettv))
|
||||
|
@@ -1,4 +1,5 @@
|
||||
local helpers = require('test.unit.helpers')
|
||||
local helpers = require('test.unit.helpers')(after_each)
|
||||
local itp = helpers.gen_itp(it)
|
||||
local eval_helpers = require('test.unit.eval.helpers')
|
||||
|
||||
local cimport = helpers.cimport
|
||||
@@ -18,25 +19,25 @@ describe('encode_list_write()', function()
|
||||
return encode.encode_list_write(l, to_cstr(s), #s)
|
||||
end
|
||||
|
||||
it('writes empty string', function()
|
||||
itp('writes empty string', function()
|
||||
local l = list()
|
||||
eq(0, encode_list_write(l, ''))
|
||||
eq({[type_key]=list_type}, lst2tbl(l))
|
||||
end)
|
||||
|
||||
it('writes ASCII string literal with printable characters', function()
|
||||
itp('writes ASCII string literal with printable characters', function()
|
||||
local l = list()
|
||||
eq(0, encode_list_write(l, 'abc'))
|
||||
eq({'abc'}, lst2tbl(l))
|
||||
end)
|
||||
|
||||
it('writes string starting with NL', function()
|
||||
itp('writes string starting with NL', function()
|
||||
local l = list()
|
||||
eq(0, encode_list_write(l, '\nabc'))
|
||||
eq({null_string, 'abc'}, lst2tbl(l))
|
||||
end)
|
||||
|
||||
it('writes string starting with NL twice', function()
|
||||
itp('writes string starting with NL twice', function()
|
||||
local l = list()
|
||||
eq(0, encode_list_write(l, '\nabc'))
|
||||
eq({null_string, 'abc'}, lst2tbl(l))
|
||||
@@ -44,13 +45,13 @@ describe('encode_list_write()', function()
|
||||
eq({null_string, 'abc', 'abc'}, lst2tbl(l))
|
||||
end)
|
||||
|
||||
it('writes string ending with NL', function()
|
||||
itp('writes string ending with NL', function()
|
||||
local l = list()
|
||||
eq(0, encode_list_write(l, 'abc\n'))
|
||||
eq({'abc', null_string}, lst2tbl(l))
|
||||
end)
|
||||
|
||||
it('writes string ending with NL twice', function()
|
||||
itp('writes string ending with NL twice', function()
|
||||
local l = list()
|
||||
eq(0, encode_list_write(l, 'abc\n'))
|
||||
eq({'abc', null_string}, lst2tbl(l))
|
||||
@@ -58,7 +59,7 @@ describe('encode_list_write()', function()
|
||||
eq({'abc', 'abc', null_string}, lst2tbl(l))
|
||||
end)
|
||||
|
||||
it('writes string starting, ending and containing NL twice', function()
|
||||
itp('writes string starting, ending and containing NL twice', function()
|
||||
local l = list()
|
||||
eq(0, encode_list_write(l, '\na\nb\n'))
|
||||
eq({null_string, 'a', 'b', null_string}, lst2tbl(l))
|
||||
@@ -66,7 +67,7 @@ describe('encode_list_write()', function()
|
||||
eq({null_string, 'a', 'b', null_string, 'a', 'b', null_string}, lst2tbl(l))
|
||||
end)
|
||||
|
||||
it('writes string starting, ending and containing NUL with NL between twice', function()
|
||||
itp('writes string starting, ending and containing NUL with NL between twice', function()
|
||||
local l = list()
|
||||
eq(0, encode_list_write(l, '\0\n\0\n\0'))
|
||||
eq({'\n', '\n', '\n'}, lst2tbl(l))
|
||||
@@ -74,7 +75,7 @@ describe('encode_list_write()', function()
|
||||
eq({'\n', '\n', '\n\n', '\n', '\n'}, lst2tbl(l))
|
||||
end)
|
||||
|
||||
it('writes string starting, ending and containing NL with NUL between twice', function()
|
||||
itp('writes string starting, ending and containing NL with NUL between twice', function()
|
||||
local l = list()
|
||||
eq(0, encode_list_write(l, '\n\0\n\0\n'))
|
||||
eq({null_string, '\n', '\n', null_string}, lst2tbl(l))
|
||||
@@ -82,7 +83,7 @@ describe('encode_list_write()', function()
|
||||
eq({null_string, '\n', '\n', null_string, '\n', '\n', null_string}, lst2tbl(l))
|
||||
end)
|
||||
|
||||
it('writes string containing a single NL twice', function()
|
||||
itp('writes string containing a single NL twice', function()
|
||||
local l = list()
|
||||
eq(0, encode_list_write(l, '\n'))
|
||||
eq({null_string, null_string}, lst2tbl(l))
|
||||
@@ -90,7 +91,7 @@ describe('encode_list_write()', function()
|
||||
eq({null_string, null_string, null_string}, lst2tbl(l))
|
||||
end)
|
||||
|
||||
it('writes string containing a few NLs twice', function()
|
||||
itp('writes string containing a few NLs twice', function()
|
||||
local l = list()
|
||||
eq(0, encode_list_write(l, '\n\n\n'))
|
||||
eq({null_string, null_string, null_string, null_string}, lst2tbl(l))
|
||||
|
@@ -1,4 +1,4 @@
|
||||
local helpers = require('test.unit.helpers')
|
||||
local helpers = require('test.unit.helpers')(nil)
|
||||
|
||||
local cimport = helpers.cimport
|
||||
local to_cstr = helpers.to_cstr
|
||||
@@ -46,12 +46,6 @@ local function list(...)
|
||||
return ret
|
||||
end
|
||||
|
||||
local special_tab = {
|
||||
[eval.kSpecialVarFalse] = false,
|
||||
[eval.kSpecialVarNull] = nil_value,
|
||||
[eval.kSpecialVarTrue] = true,
|
||||
}
|
||||
|
||||
local ptr2key = function(ptr)
|
||||
return tostring(ptr)
|
||||
end
|
||||
@@ -60,64 +54,74 @@ local lst2tbl
|
||||
local dct2tbl
|
||||
|
||||
local typvalt2lua
|
||||
local typvalt2lua_tab
|
||||
local typvalt2lua_tab = nil
|
||||
|
||||
typvalt2lua_tab = {
|
||||
[tonumber(eval.VAR_SPECIAL)] = function(t)
|
||||
return special_tab[t.vval.v_special]
|
||||
end,
|
||||
[tonumber(eval.VAR_NUMBER)] = function(t)
|
||||
return {[type_key]=int_type, value=tonumber(t.vval.v_number)}
|
||||
end,
|
||||
[tonumber(eval.VAR_FLOAT)] = function(t)
|
||||
return tonumber(t.vval.v_float)
|
||||
end,
|
||||
[tonumber(eval.VAR_STRING)] = function(t)
|
||||
local str = t.vval.v_string
|
||||
if str == nil then
|
||||
return null_string
|
||||
else
|
||||
return ffi.string(str)
|
||||
end
|
||||
end,
|
||||
[tonumber(eval.VAR_LIST)] = function(t, processed)
|
||||
return lst2tbl(t.vval.v_list, processed)
|
||||
end,
|
||||
[tonumber(eval.VAR_DICT)] = function(t, processed)
|
||||
return dct2tbl(t.vval.v_dict, processed)
|
||||
end,
|
||||
[tonumber(eval.VAR_FUNC)] = function(t, processed)
|
||||
return {[type_key]=func_type, value=typvalt2lua_tab[eval.VAR_STRING](t, processed or {})}
|
||||
end,
|
||||
[tonumber(eval.VAR_PARTIAL)] = function(t, processed)
|
||||
local p_key = ptr2key(t)
|
||||
if processed[p_key] then
|
||||
return processed[p_key]
|
||||
end
|
||||
local pt = t.vval.v_partial
|
||||
local value, auto, dict, argv = nil, nil, nil, nil
|
||||
if pt ~= nil then
|
||||
value = ffi.string(pt.pt_name)
|
||||
auto = pt.pt_auto and true or nil
|
||||
argv = {}
|
||||
for i = 1, pt.pt_argc do
|
||||
argv[i] = typvalt2lua(pt.pt_argv[i - 1], processed)
|
||||
local function typvalt2lua_tab_init()
|
||||
if typvalt2lua_tab then
|
||||
return
|
||||
end
|
||||
typvalt2lua_tab = {
|
||||
[tonumber(eval.VAR_SPECIAL)] = function(t)
|
||||
return ({
|
||||
[eval.kSpecialVarFalse] = false,
|
||||
[eval.kSpecialVarNull] = nil_value,
|
||||
[eval.kSpecialVarTrue] = true,
|
||||
})[t.vval.v_special]
|
||||
end,
|
||||
[tonumber(eval.VAR_NUMBER)] = function(t)
|
||||
return {[type_key]=int_type, value=tonumber(t.vval.v_number)}
|
||||
end,
|
||||
[tonumber(eval.VAR_FLOAT)] = function(t)
|
||||
return tonumber(t.vval.v_float)
|
||||
end,
|
||||
[tonumber(eval.VAR_STRING)] = function(t)
|
||||
local str = t.vval.v_string
|
||||
if str == nil then
|
||||
return null_string
|
||||
else
|
||||
return ffi.string(str)
|
||||
end
|
||||
if pt.pt_dict ~= nil then
|
||||
dict = dct2tbl(pt.pt_dict)
|
||||
end,
|
||||
[tonumber(eval.VAR_LIST)] = function(t, processed)
|
||||
return lst2tbl(t.vval.v_list, processed)
|
||||
end,
|
||||
[tonumber(eval.VAR_DICT)] = function(t, processed)
|
||||
return dct2tbl(t.vval.v_dict, processed)
|
||||
end,
|
||||
[tonumber(eval.VAR_FUNC)] = function(t, processed)
|
||||
return {[type_key]=func_type, value=typvalt2lua_tab[eval.VAR_STRING](t, processed or {})}
|
||||
end,
|
||||
[tonumber(eval.VAR_PARTIAL)] = function(t, processed)
|
||||
local p_key = ptr2key(t)
|
||||
if processed[p_key] then
|
||||
return processed[p_key]
|
||||
end
|
||||
end
|
||||
return {
|
||||
[type_key]=func_type,
|
||||
value=value,
|
||||
auto=auto,
|
||||
args=argv,
|
||||
dict=dict,
|
||||
}
|
||||
end,
|
||||
}
|
||||
local pt = t.vval.v_partial
|
||||
local value, auto, dict, argv = nil, nil, nil, nil
|
||||
if pt ~= nil then
|
||||
value = ffi.string(pt.pt_name)
|
||||
auto = pt.pt_auto and true or nil
|
||||
argv = {}
|
||||
for i = 1, pt.pt_argc do
|
||||
argv[i] = typvalt2lua(pt.pt_argv[i - 1], processed)
|
||||
end
|
||||
if pt.pt_dict ~= nil then
|
||||
dict = dct2tbl(pt.pt_dict)
|
||||
end
|
||||
end
|
||||
return {
|
||||
[type_key]=func_type,
|
||||
value=value,
|
||||
auto=auto,
|
||||
args=argv,
|
||||
dict=dict,
|
||||
}
|
||||
end,
|
||||
}
|
||||
end
|
||||
|
||||
typvalt2lua = function(t, processed)
|
||||
typvalt2lua_tab_init()
|
||||
return ((typvalt2lua_tab[tonumber(t.v_type)] or function(t_inner)
|
||||
assert(false, 'Converting ' .. tonumber(t_inner.v_type) .. ' was not implemented yet')
|
||||
end)(t, processed or {}))
|
||||
@@ -169,9 +173,10 @@ lst2tbl = function(l, processed)
|
||||
return ret
|
||||
end
|
||||
|
||||
local hi_key_removed = eval._hash_key_removed()
|
||||
local hi_key_removed = nil
|
||||
|
||||
local function dict_iter(d, return_hi)
|
||||
hi_key_removed = hi_key_removed or eval._hash_key_removed()
|
||||
local init_s = {
|
||||
todo=d.dv_hashtab.ht_used,
|
||||
hi=d.dv_hashtab.ht_array,
|
||||
@@ -320,25 +325,28 @@ local lua2typvalt_type_tab = {
|
||||
end,
|
||||
}
|
||||
|
||||
local special_vals = {
|
||||
[null_string] = {eval.VAR_STRING, {v_string=ffi.cast('char_u*', nil)}},
|
||||
[null_list] = {eval.VAR_LIST, {v_list=ffi.cast('list_T*', nil)}},
|
||||
[null_dict] = {eval.VAR_DICT, {v_dict=ffi.cast('dict_T*', nil)}},
|
||||
[nil_value] = {eval.VAR_SPECIAL, {v_special=eval.kSpecialVarNull}},
|
||||
[true] = {eval.VAR_SPECIAL, {v_special=eval.kSpecialVarTrue}},
|
||||
[false] = {eval.VAR_SPECIAL, {v_special=eval.kSpecialVarFalse}},
|
||||
}
|
||||
|
||||
for k, v in pairs(special_vals) do
|
||||
local tmp = function(typ, vval)
|
||||
special_vals[k] = function()
|
||||
return typvalt(typ, vval)
|
||||
end
|
||||
end
|
||||
tmp(v[1], v[2])
|
||||
end
|
||||
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_list] = {'VAR_LIST', {v_list=ffi.cast('list_T*', nil)}},
|
||||
[null_dict] = {'VAR_DICT', {v_dict=ffi.cast('dict_T*', nil)}},
|
||||
[nil_value] = {'VAR_SPECIAL', {v_special=eval.kSpecialVarNull}},
|
||||
[true] = {'VAR_SPECIAL', {v_special=eval.kSpecialVarTrue}},
|
||||
[false] = {'VAR_SPECIAL', {v_special=eval.kSpecialVarFalse}},
|
||||
}
|
||||
|
||||
for k, v in pairs(special_vals) do
|
||||
local tmp = function(typ, vval)
|
||||
special_vals[k] = function()
|
||||
return typvalt(eval[typ], vval)
|
||||
end
|
||||
end
|
||||
tmp(v[1], v[2])
|
||||
end
|
||||
end
|
||||
processed = processed or {}
|
||||
if l == nil or l == nil_value then
|
||||
return special_vals[nil_value]()
|
||||
@@ -360,7 +368,7 @@ lua2typvalt = function(l, processed)
|
||||
return typvalt(eval.VAR_STRING, {v_string=eval.xmemdupz(to_cstr(l), #l)})
|
||||
elseif type(l) == 'cdata' then
|
||||
local tv = typvalt(eval.VAR_UNKNOWN)
|
||||
eval.tv_copy(l, tv)
|
||||
eval.copy_tv(l, tv)
|
||||
return tv
|
||||
end
|
||||
end
|
||||
|
@@ -1,4 +1,5 @@
|
||||
local helpers = require('test.unit.helpers')
|
||||
local helpers = require('test.unit.helpers')(after_each)
|
||||
local itp = helpers.gen_itp(it)
|
||||
|
||||
local cimport = helpers.cimport
|
||||
local to_cstr = helpers.to_cstr
|
||||
@@ -15,7 +16,7 @@ local eval_expr = function(expr)
|
||||
end
|
||||
|
||||
describe('NULL typval_T', function()
|
||||
it('is produced by $XXX_UNEXISTENT_VAR_XXX', function()
|
||||
itp('is produced by $XXX_UNEXISTENT_VAR_XXX', function()
|
||||
-- Required for various tests which need to check whether typval_T with NULL
|
||||
-- string works correctly. This test checks that unexistent environment
|
||||
-- variable produces NULL string, not that some specific environment
|
||||
@@ -29,13 +30,13 @@ describe('NULL typval_T', function()
|
||||
eq(nil, rettv.vval.v_string)
|
||||
end)
|
||||
|
||||
it('is produced by v:_null_list', function()
|
||||
itp('is produced by v:_null_list', function()
|
||||
local rettv = eval_expr('v:_null_list')
|
||||
eq(eval.VAR_LIST, rettv.v_type)
|
||||
eq(nil, rettv.vval.v_list)
|
||||
end)
|
||||
|
||||
it('is produced by v:_null_dict', function()
|
||||
itp('is produced by v:_null_dict', function()
|
||||
local rettv = eval_expr('v:_null_dict')
|
||||
eq(eval.VAR_DICT, rettv.v_type)
|
||||
eq(nil, rettv.vval.v_dict)
|
||||
|
@@ -1,4 +1,5 @@
|
||||
local helpers = require('test.unit.helpers')
|
||||
local helpers = require('test.unit.helpers')(after_each)
|
||||
local itp = helpers.gen_itp(it)
|
||||
local eval_helpers = require('test.unit.eval.helpers')
|
||||
|
||||
local alloc_log_new = helpers.alloc_log_new
|
||||
@@ -26,7 +27,7 @@ after_each(function()
|
||||
end)
|
||||
|
||||
describe('clear_tv()', function()
|
||||
it('successfully frees all lists in [&l [1], *l, *l]', function()
|
||||
itp('successfully frees all lists in [&l [1], *l, *l]', function()
|
||||
local l_inner = {1}
|
||||
local list = {l_inner, l_inner, l_inner}
|
||||
local list_tv = ffi.gc(lua2typvalt(list), nil)
|
||||
@@ -53,7 +54,7 @@ describe('clear_tv()', function()
|
||||
a.freed(list_p),
|
||||
})
|
||||
end)
|
||||
it('successfully frees all lists in [&l [], *l, *l]', function()
|
||||
itp('successfully frees all lists in [&l [], *l, *l]', function()
|
||||
local l_inner = {[type_key]=list_type}
|
||||
local list = {l_inner, l_inner, l_inner}
|
||||
local list_tv = ffi.gc(lua2typvalt(list), nil)
|
||||
@@ -77,7 +78,7 @@ describe('clear_tv()', function()
|
||||
a.freed(list_p),
|
||||
})
|
||||
end)
|
||||
it('successfully frees all dictionaries in [&d {}, *d]', function()
|
||||
itp('successfully frees all dictionaries in [&d {}, *d]', function()
|
||||
local d_inner = {}
|
||||
local list = {d_inner, d_inner}
|
||||
local list_tv = ffi.gc(lua2typvalt(list), nil)
|
||||
@@ -99,7 +100,7 @@ describe('clear_tv()', function()
|
||||
a.freed(list_p),
|
||||
})
|
||||
end)
|
||||
it('successfully frees all dictionaries in [&d {a: 1}, *d]', function()
|
||||
itp('successfully frees all dictionaries in [&d {a: 1}, *d]', function()
|
||||
local d_inner = {a=1}
|
||||
local list = {d_inner, d_inner}
|
||||
local list_tv = ffi.gc(lua2typvalt(list), nil)
|
||||
|
@@ -1,4 +1,5 @@
|
||||
local helpers = require("test.unit.helpers")
|
||||
local helpers = require("test.unit.helpers")(after_each)
|
||||
local itp = helpers.gen_itp(it)
|
||||
--{:cimport, :internalize, :eq, :neq, :ffi, :lib, :cstr, :to_cstr} = require 'test.unit.helpers'
|
||||
|
||||
local eq = helpers.eq
|
||||
@@ -16,67 +17,67 @@ describe('file_pat functions', function()
|
||||
return ffi.string(res)
|
||||
end
|
||||
|
||||
it('returns ^path$ regex for literal path input', function()
|
||||
itp('returns ^path$ regex for literal path input', function()
|
||||
eq( '^path$', file_pat_to_reg_pat('path'))
|
||||
end)
|
||||
|
||||
it('does not prepend ^ when there is a starting glob (*)', function()
|
||||
itp('does not prepend ^ when there is a starting glob (*)', function()
|
||||
eq('path$', file_pat_to_reg_pat('*path'))
|
||||
end)
|
||||
|
||||
it('does not append $ when there is an ending glob (*)', function()
|
||||
itp('does not append $ when there is an ending glob (*)', function()
|
||||
eq('^path', file_pat_to_reg_pat('path*'))
|
||||
end)
|
||||
|
||||
it('does not include ^ or $ when surrounded by globs (*)', function()
|
||||
itp('does not include ^ or $ when surrounded by globs (*)', function()
|
||||
eq('path', file_pat_to_reg_pat('*path*'))
|
||||
end)
|
||||
|
||||
it('replaces the bash any character (?) with the regex any character (.)', function()
|
||||
itp('replaces the bash any character (?) with the regex any character (.)', function()
|
||||
eq('^foo.bar$', file_pat_to_reg_pat('foo?bar'))
|
||||
end)
|
||||
|
||||
it('replaces a glob (*) in the middle of a path with regex multiple any character (.*)',
|
||||
itp('replaces a glob (*) in the middle of a path with regex multiple any character (.*)',
|
||||
function()
|
||||
eq('^foo.*bar$', file_pat_to_reg_pat('foo*bar'))
|
||||
end)
|
||||
|
||||
it([[unescapes \? to ?]], function()
|
||||
itp([[unescapes \? to ?]], function()
|
||||
eq('^foo?bar$', file_pat_to_reg_pat([[foo\?bar]]))
|
||||
end)
|
||||
|
||||
it([[unescapes \% to %]], function()
|
||||
itp([[unescapes \% to %]], function()
|
||||
eq('^foo%bar$', file_pat_to_reg_pat([[foo\%bar]]))
|
||||
end)
|
||||
|
||||
it([[unescapes \, to ,]], function()
|
||||
itp([[unescapes \, to ,]], function()
|
||||
eq('^foo,bar$', file_pat_to_reg_pat([[foo\,bar]]))
|
||||
end)
|
||||
|
||||
it([[unescapes '\ ' to ' ']], function()
|
||||
itp([[unescapes '\ ' to ' ']], function()
|
||||
eq('^foo bar$', file_pat_to_reg_pat([[foo\ bar]]))
|
||||
end)
|
||||
|
||||
it([[escapes . to \.]], function()
|
||||
itp([[escapes . to \.]], function()
|
||||
eq([[^foo\.bar$]], file_pat_to_reg_pat('foo.bar'))
|
||||
end)
|
||||
|
||||
it('Converts bash brace expansion {a,b} to regex options (a|b)', function()
|
||||
itp('Converts bash brace expansion {a,b} to regex options (a|b)', function()
|
||||
eq([[^foo\(bar\|baz\)$]], file_pat_to_reg_pat('foo{bar,baz}'))
|
||||
end)
|
||||
|
||||
it('Collapses multiple consecutive * into a single character', function()
|
||||
itp('Collapses multiple consecutive * into a single character', function()
|
||||
eq([[^foo.*bar$]], file_pat_to_reg_pat('foo*******bar'))
|
||||
eq([[foobar$]], file_pat_to_reg_pat('********foobar'))
|
||||
eq([[^foobar]], file_pat_to_reg_pat('foobar********'))
|
||||
end)
|
||||
|
||||
it('Does not escape ^', function()
|
||||
itp('Does not escape ^', function()
|
||||
eq([[^^blah$]], file_pat_to_reg_pat('^blah'))
|
||||
eq([[^foo^bar$]], file_pat_to_reg_pat('foo^bar'))
|
||||
end)
|
||||
|
||||
it('Does not escape $', function()
|
||||
itp('Does not escape $', function()
|
||||
eq([[^blah$$]], file_pat_to_reg_pat('blah$'))
|
||||
eq([[^foo$bar$]], file_pat_to_reg_pat('foo$bar'))
|
||||
end)
|
||||
|
11
test/unit/fixtures/posix.h
Normal file
11
test/unit/fixtures/posix.h
Normal file
@@ -0,0 +1,11 @@
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <sys/wait.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
enum {
|
||||
kPOSIXErrnoEINTR = EINTR,
|
||||
kPOSIXErrnoECHILD = ECHILD,
|
||||
kPOSIXWaitWUNTRACED = WUNTRACED,
|
||||
};
|
@@ -1,4 +1,5 @@
|
||||
local helpers = require("test.unit.helpers")
|
||||
local helpers = require("test.unit.helpers")(after_each)
|
||||
local itp = helpers.gen_itp(it)
|
||||
|
||||
local cimport = helpers.cimport
|
||||
local internalize = helpers.internalize
|
||||
@@ -8,7 +9,7 @@ local ffi = helpers.ffi
|
||||
local to_cstr = helpers.to_cstr
|
||||
local NULL = helpers.NULL
|
||||
|
||||
local garray = cimport('stdlib.h', './src/nvim/garray.h')
|
||||
local garray = cimport('./src/nvim/garray.h')
|
||||
|
||||
local itemsize = 14
|
||||
local growsize = 95
|
||||
@@ -156,7 +157,7 @@ local ga_append_ints = function(garr, ...)
|
||||
end
|
||||
|
||||
-- enhanced constructors
|
||||
local garray_ctype = ffi.typeof('garray_T[1]')
|
||||
local garray_ctype = function(...) return ffi.typeof('garray_T[1]')(...) end
|
||||
local new_garray = function()
|
||||
local garr = garray_ctype()
|
||||
return ffi.gc(garr, ga_clear)
|
||||
@@ -183,7 +184,7 @@ end
|
||||
describe('garray', function()
|
||||
|
||||
describe('ga_init', function()
|
||||
it('initializes the values of the garray', function()
|
||||
itp('initializes the values of the garray', function()
|
||||
local garr = new_garray()
|
||||
ga_init(garr, itemsize, growsize)
|
||||
eq(0, ga_len(garr))
|
||||
@@ -204,7 +205,7 @@ describe('garray', function()
|
||||
return garr
|
||||
end
|
||||
|
||||
it('grows by growsize items if num < growsize', function()
|
||||
itp('grows by growsize items if num < growsize', function()
|
||||
itemsize = 16
|
||||
growsize = 4
|
||||
local grow_by = growsize - 1
|
||||
@@ -213,7 +214,7 @@ describe('garray', function()
|
||||
eq(growsize, ga_maxlen(garr)) -- we requested LESS than growsize, so...
|
||||
end)
|
||||
|
||||
it('grows by num items if num > growsize', function()
|
||||
itp('grows by num items if num > growsize', function()
|
||||
itemsize = 16
|
||||
growsize = 4
|
||||
local grow_by = growsize + 1
|
||||
@@ -222,7 +223,7 @@ describe('garray', function()
|
||||
eq(grow_by, ga_maxlen(garr)) -- we requested MORE than growsize, so...
|
||||
end)
|
||||
|
||||
it('does not grow when nothing is requested', function()
|
||||
itp('does not grow when nothing is requested', function()
|
||||
local garr = new_and_grow(16, 4, 0)
|
||||
eq(NULL, ga_data(garr))
|
||||
eq(0, ga_maxlen(garr))
|
||||
@@ -230,7 +231,7 @@ describe('garray', function()
|
||||
end)
|
||||
|
||||
describe('ga_clear', function()
|
||||
it('clears an already allocated array', function()
|
||||
itp('clears an already allocated array', function()
|
||||
-- allocate and scramble an array
|
||||
local garr = garray_ctype()
|
||||
ga_init(garr, itemsize, growsize)
|
||||
@@ -247,7 +248,7 @@ describe('garray', function()
|
||||
end)
|
||||
|
||||
describe('ga_append', function()
|
||||
it('can append bytes', function()
|
||||
itp('can append bytes', function()
|
||||
-- this is the actual ga_append, the others are just emulated lua
|
||||
-- versions
|
||||
local garr = new_garray()
|
||||
@@ -262,7 +263,7 @@ describe('garray', function()
|
||||
eq('hello', ffi.string(bytes))
|
||||
end)
|
||||
|
||||
it('can append integers', function()
|
||||
itp('can append integers', function()
|
||||
local garr = new_garray()
|
||||
ga_init(garr, ffi.sizeof("int"), 1)
|
||||
local input = {
|
||||
@@ -279,7 +280,7 @@ describe('garray', function()
|
||||
end
|
||||
end)
|
||||
|
||||
it('can append strings to a growing array of strings', function()
|
||||
itp('can append strings to a growing array of strings', function()
|
||||
local garr = new_string_garray()
|
||||
local input = {
|
||||
"some",
|
||||
@@ -298,7 +299,7 @@ describe('garray', function()
|
||||
end)
|
||||
|
||||
describe('ga_concat', function()
|
||||
it('concatenates the parameter to the growing byte array', function()
|
||||
itp('concatenates the parameter to the growing byte array', function()
|
||||
local garr = new_garray()
|
||||
ga_init(garr, ffi.sizeof("char"), 1)
|
||||
local str = "ohwell●●"
|
||||
@@ -329,11 +330,11 @@ describe('garray', function()
|
||||
end
|
||||
|
||||
describe('ga_concat_strings', function()
|
||||
it('returns an empty string when concatenating an empty array', function()
|
||||
itp('returns an empty string when concatenating an empty array', function()
|
||||
test_concat_fn({ }, ga_concat_strings)
|
||||
end)
|
||||
|
||||
it('can concatenate a non-empty array', function()
|
||||
itp('can concatenate a non-empty array', function()
|
||||
test_concat_fn({
|
||||
'oh',
|
||||
'my',
|
||||
@@ -343,11 +344,11 @@ describe('garray', function()
|
||||
end)
|
||||
|
||||
describe('ga_concat_strings_sep', function()
|
||||
it('returns an empty string when concatenating an empty array', function()
|
||||
itp('returns an empty string when concatenating an empty array', function()
|
||||
test_concat_fn({ }, ga_concat_strings_sep, '---')
|
||||
end)
|
||||
|
||||
it('can concatenate a non-empty array', function()
|
||||
itp('can concatenate a non-empty array', function()
|
||||
local sep = '-●●-'
|
||||
test_concat_fn({
|
||||
'oh',
|
||||
@@ -358,7 +359,7 @@ describe('garray', function()
|
||||
end)
|
||||
|
||||
describe('ga_remove_duplicate_strings', function()
|
||||
it('sorts and removes duplicate strings', function()
|
||||
itp('sorts and removes duplicate strings', function()
|
||||
local garr = new_string_garray()
|
||||
local input = {
|
||||
'ccc',
|
||||
|
@@ -4,8 +4,15 @@ local Set = require('test.unit.set')
|
||||
local Preprocess = require('test.unit.preprocess')
|
||||
local Paths = require('test.config.paths')
|
||||
local global_helpers = require('test.helpers')
|
||||
local assert = require('luassert')
|
||||
local say = require('say')
|
||||
|
||||
local posix = nil
|
||||
local syscall = nil
|
||||
|
||||
local check_cores = global_helpers.check_cores
|
||||
local neq = global_helpers.neq
|
||||
local map = global_helpers.map
|
||||
local eq = global_helpers.eq
|
||||
local ok = global_helpers.ok
|
||||
|
||||
@@ -15,20 +22,110 @@ 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
|
||||
|
||||
-- load neovim shared library
|
||||
local libnvim = ffi.load(Paths.test_libnvim_path)
|
||||
local child_pid = nil
|
||||
local function only_separate(func)
|
||||
return function(...)
|
||||
if child_pid ~= 0 then
|
||||
error('This function must be run in a separate process only')
|
||||
end
|
||||
return func(...)
|
||||
end
|
||||
end
|
||||
local child_calls_init = {}
|
||||
local child_calls_mod = nil
|
||||
local child_calls_mod_once = nil
|
||||
local function child_call(func, ret)
|
||||
return function(...)
|
||||
local child_calls = child_calls_mod or child_calls_init
|
||||
if child_pid ~= 0 then
|
||||
child_calls[#child_calls + 1] = {func=func, args={...}}
|
||||
return ret
|
||||
else
|
||||
return func(...)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Run some code at the start of the child process, before running the test
|
||||
-- itself. Is supposed to be run in `before_each`.
|
||||
local function child_call_once(func, ...)
|
||||
if child_pid ~= 0 then
|
||||
child_calls_mod_once[#child_calls_mod_once + 1] = {
|
||||
func=func, args={...}}
|
||||
else
|
||||
func(...)
|
||||
end
|
||||
end
|
||||
|
||||
local child_cleanups_mod_once = nil
|
||||
|
||||
-- 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.
|
||||
local function child_cleanup_once(func, ...)
|
||||
local child_cleanups = child_cleanups_mod_once
|
||||
if child_pid ~= 0 then
|
||||
child_cleanups[#child_cleanups + 1] = {func=func, args={...}}
|
||||
else
|
||||
func(...)
|
||||
end
|
||||
end
|
||||
|
||||
local libnvim = nil
|
||||
|
||||
local lib = setmetatable({}, {
|
||||
__index = only_separate(function(_, idx)
|
||||
return libnvim[idx]
|
||||
end),
|
||||
__newindex = child_call(function(_, idx, val)
|
||||
libnvim[idx] = val
|
||||
end),
|
||||
})
|
||||
|
||||
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.early_init()
|
||||
libnvim.event_init()
|
||||
if child_calls_mod then
|
||||
for _, c in ipairs(child_calls_mod) do
|
||||
c.func(unpack(c.args))
|
||||
end
|
||||
end
|
||||
if child_calls_mod_once then
|
||||
for _, c in ipairs(child_calls_mod_once) do
|
||||
c.func(unpack(c.args))
|
||||
end
|
||||
child_calls_mod_once = nil
|
||||
end
|
||||
end)
|
||||
|
||||
local deinit = only_separate(function()
|
||||
if child_cleanups_mod_once then
|
||||
for _, c in ipairs(child_cleanups_mod_once) do
|
||||
c.func(unpack(c.args))
|
||||
end
|
||||
child_cleanups_mod_once = nil
|
||||
end
|
||||
end)
|
||||
|
||||
local function trim(s)
|
||||
return s:match('^%s*(.*%S)') or ''
|
||||
end
|
||||
|
||||
-- a Set that keeps around the lines we've already seen
|
||||
local cdefs = Set:new()
|
||||
local cdefs_init = Set:new()
|
||||
local cdefs_mod = nil
|
||||
local imported = Set:new()
|
||||
local pragma_pack_id = 1
|
||||
|
||||
@@ -51,84 +148,120 @@ local function filter_complex_blocks(body)
|
||||
return table.concat(result, "\n")
|
||||
end
|
||||
|
||||
local previous_defines = ''
|
||||
|
||||
local cdef = ffi.cdef
|
||||
|
||||
local cimportstr
|
||||
|
||||
local previous_defines_init = ''
|
||||
local preprocess_cache_init = {}
|
||||
local previous_defines_mod = ''
|
||||
local preprocess_cache_mod = nil
|
||||
|
||||
local function is_child_cdefs()
|
||||
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.
|
||||
local function cimport(...)
|
||||
local paths = {}
|
||||
local args = {...}
|
||||
|
||||
-- filter out paths we've already imported
|
||||
for _,path in pairs(args) do
|
||||
if path ~= nil and not imported:contains(path) then
|
||||
paths[#paths + 1] = path
|
||||
cimport = function(...)
|
||||
local previous_defines, preprocess_cache, cdefs
|
||||
if is_child_cdefs() and preprocess_cache_mod then
|
||||
preprocess_cache = preprocess_cache_mod
|
||||
previous_defines = previous_defines_mod
|
||||
cdefs = cdefs_mod
|
||||
else
|
||||
preprocess_cache = preprocess_cache_init
|
||||
previous_defines = previous_defines_init
|
||||
cdefs = cdefs_init
|
||||
end
|
||||
for _, path in ipairs({...}) do
|
||||
if not (path:sub(1, 1) == '/' or path:sub(1, 1) == '.'
|
||||
or path:sub(2, 2) == ':') then
|
||||
path = './' .. path
|
||||
end
|
||||
end
|
||||
if not preprocess_cache[path] then
|
||||
local body
|
||||
body, previous_defines = Preprocess.preprocess(previous_defines, path)
|
||||
-- format it (so that the lines are "unique" statements), also filter out
|
||||
-- Objective-C blocks
|
||||
if os.getenv('NVIM_TEST_PRINT_I') == '1' then
|
||||
local lnum = 0
|
||||
for line in body:gmatch('[^\n]+') do
|
||||
lnum = lnum + 1
|
||||
print(lnum, line)
|
||||
end
|
||||
end
|
||||
body = formatc(body)
|
||||
body = filter_complex_blocks(body)
|
||||
-- add the formatted lines to a set
|
||||
local new_cdefs = Set:new()
|
||||
for line in body:gmatch("[^\r\n]+") do
|
||||
line = trim(line)
|
||||
-- give each #pragma pack an unique id, so that they don't get removed
|
||||
-- if they are inserted into the set
|
||||
-- (they are needed in the right order with the struct definitions,
|
||||
-- otherwise luajit has wrong memory layouts for the sturcts)
|
||||
if line:match("#pragma%s+pack") then
|
||||
line = line .. " // " .. pragma_pack_id
|
||||
pragma_pack_id = pragma_pack_id + 1
|
||||
end
|
||||
new_cdefs:add(line)
|
||||
end
|
||||
|
||||
for _,path in pairs(paths) do
|
||||
imported:add(path)
|
||||
end
|
||||
-- subtract the lines we've already imported from the new lines, then add
|
||||
-- the new unique lines to the old lines (so they won't be imported again)
|
||||
new_cdefs:diff(cdefs)
|
||||
cdefs:union(new_cdefs)
|
||||
-- request a sorted version of the new lines (same relative order as the
|
||||
-- original preprocessed file) and feed that to the LuaJIT ffi
|
||||
local new_lines = new_cdefs:to_table()
|
||||
if os.getenv('NVIM_TEST_PRINT_CDEF') == '1' then
|
||||
for lnum, line in ipairs(new_lines) do
|
||||
print(lnum, line)
|
||||
end
|
||||
end
|
||||
body = table.concat(new_lines, '\n')
|
||||
|
||||
if #paths == 0 then
|
||||
return libnvim
|
||||
end
|
||||
|
||||
local body
|
||||
body, previous_defines = Preprocess.preprocess(previous_defines, unpack(paths))
|
||||
|
||||
-- format it (so that the lines are "unique" statements), also filter out
|
||||
-- Objective-C blocks
|
||||
if os.getenv('NVIM_TEST_PRINT_I') == '1' then
|
||||
local lnum = 0
|
||||
for line in body:gmatch('[^\n]+') do
|
||||
lnum = lnum + 1
|
||||
print(lnum, line)
|
||||
preprocess_cache[path] = body
|
||||
end
|
||||
cimportstr(preprocess_cache, path)
|
||||
end
|
||||
body = formatc(body)
|
||||
body = filter_complex_blocks(body)
|
||||
|
||||
-- add the formatted lines to a set
|
||||
local new_cdefs = Set:new()
|
||||
for line in body:gmatch("[^\r\n]+") do
|
||||
line = trim(line)
|
||||
-- give each #pragma pack an unique id, so that they don't get removed
|
||||
-- if they are inserted into the set
|
||||
-- (they are needed in the right order with the struct definitions,
|
||||
-- otherwise luajit has wrong memory layouts for the sturcts)
|
||||
if line:match("#pragma%s+pack") then
|
||||
line = line .. " // " .. pragma_pack_id
|
||||
pragma_pack_id = pragma_pack_id + 1
|
||||
end
|
||||
new_cdefs:add(line)
|
||||
end
|
||||
|
||||
-- subtract the lines we've already imported from the new lines, then add
|
||||
-- the new unique lines to the old lines (so they won't be imported again)
|
||||
new_cdefs:diff(cdefs)
|
||||
cdefs:union(new_cdefs)
|
||||
|
||||
if new_cdefs:size() == 0 then
|
||||
-- if there's no new lines, just return
|
||||
return libnvim
|
||||
end
|
||||
|
||||
-- request a sorted version of the new lines (same relative order as the
|
||||
-- original preprocessed file) and feed that to the LuaJIT ffi
|
||||
local new_lines = new_cdefs:to_table()
|
||||
if os.getenv('NVIM_TEST_PRINT_CDEF') == '1' then
|
||||
for lnum, line in ipairs(new_lines) do
|
||||
print(lnum, line)
|
||||
end
|
||||
end
|
||||
ffi.cdef(table.concat(new_lines, "\n"))
|
||||
|
||||
return libnvim
|
||||
return lib
|
||||
end
|
||||
|
||||
local function cppimport(path)
|
||||
return cimport(Paths.test_include_path .. '/' .. path)
|
||||
local cimport_immediate = function(...)
|
||||
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')
|
||||
assert(false)
|
||||
else
|
||||
return lib
|
||||
end
|
||||
end
|
||||
|
||||
local function _cimportstr(preprocess_cache, path)
|
||||
if imported:contains(path) then
|
||||
return lib
|
||||
end
|
||||
local body = preprocess_cache[path]
|
||||
if body == '' then
|
||||
return lib
|
||||
end
|
||||
cdef(body)
|
||||
imported:add(path)
|
||||
|
||||
return lib
|
||||
end
|
||||
|
||||
if is_child_cdefs() then
|
||||
cimportstr = child_call(_cimportstr, lib)
|
||||
else
|
||||
cimportstr = _cimportstr
|
||||
end
|
||||
|
||||
local function alloc_log_new()
|
||||
@@ -141,9 +274,12 @@ local function alloc_log_new()
|
||||
local allocator_functions = {'malloc', 'free', 'calloc', 'realloc'}
|
||||
function log:save_original_functions()
|
||||
for _, funcname in ipairs(allocator_functions) do
|
||||
self.original_functions[funcname] = self.lib['mem_' .. funcname]
|
||||
if not self.original_functions[funcname] then
|
||||
self.original_functions[funcname] = self.lib['mem_' .. funcname]
|
||||
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
|
||||
@@ -170,6 +306,7 @@ local function alloc_log_new()
|
||||
end
|
||||
end
|
||||
end
|
||||
log.set_mocks = child_call(log.set_mocks)
|
||||
function log:clear()
|
||||
self.log = {}
|
||||
end
|
||||
@@ -178,22 +315,28 @@ local function alloc_log_new()
|
||||
self:clear()
|
||||
end
|
||||
function log:restore_original_functions()
|
||||
for k, v in pairs(self.original_functions) do
|
||||
self.lib['mem_' .. k] = v
|
||||
end
|
||||
-- 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:before_each()
|
||||
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
|
||||
|
||||
cimport('./src/nvim/types.h')
|
||||
|
||||
-- take a pointer to a C-allocated string and return an interned
|
||||
-- version while also freeing the memory
|
||||
local function internalize(cdata, len)
|
||||
@@ -206,17 +349,226 @@ local function to_cstr(string)
|
||||
return cstr(#string + 1, string)
|
||||
end
|
||||
|
||||
-- initialize some global variables, this is still necessary to unit test
|
||||
-- functions that rely on global state.
|
||||
do
|
||||
local main = cimport('./src/nvim/main.h')
|
||||
local time = cimport('./src/nvim/os/time.h')
|
||||
time.time_init()
|
||||
main.early_init()
|
||||
main.event_init()
|
||||
local sc
|
||||
|
||||
if posix ~= nil then
|
||||
sc = {
|
||||
fork = posix.fork,
|
||||
pipe = posix.pipe,
|
||||
read = posix.read,
|
||||
write = posix.write,
|
||||
close = posix.close,
|
||||
wait = posix.wait,
|
||||
exit = posix._exit,
|
||||
}
|
||||
elseif syscall ~= nil then
|
||||
sc = {
|
||||
fork = syscall.fork,
|
||||
pipe = function()
|
||||
local ret = {syscall.pipe()}
|
||||
return ret[3], ret[4]
|
||||
end,
|
||||
read = function(rd, len)
|
||||
return rd:read(nil, len)
|
||||
end,
|
||||
write = function(wr, s)
|
||||
return wr:write(s)
|
||||
end,
|
||||
close = function(p)
|
||||
return p:close()
|
||||
end,
|
||||
wait = syscall.wait,
|
||||
exit = syscall.exit,
|
||||
}
|
||||
else
|
||||
cimport_immediate('./test/unit/fixtures/posix.h')
|
||||
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 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
|
||||
end
|
||||
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"):format(
|
||||
err, ffi.string(ffi.C.strerror(err))))
|
||||
end
|
||||
elseif bytes_written == 0 then
|
||||
break
|
||||
else
|
||||
total_bytes_written = total_bytes_written + bytes_written
|
||||
end
|
||||
end
|
||||
return total_bytes_written
|
||||
end,
|
||||
close = ffi.C.close,
|
||||
wait = function(pid)
|
||||
ffi.errno(0)
|
||||
while true do
|
||||
local r = ffi.C.waitpid(pid, nil, 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
|
||||
end
|
||||
end,
|
||||
exit = ffi.C._exit,
|
||||
}
|
||||
end
|
||||
|
||||
return {
|
||||
local function format_list(lst)
|
||||
local ret = ''
|
||||
for _, v in ipairs(lst) do
|
||||
if ret ~= '' then ret = ret .. ', ' end
|
||||
ret = ret .. assert:format({v, n=1})[1]
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
if os.getenv('NVIM_TEST_PRINT_SYSCALLS') == '1' then
|
||||
for k_, v_ in pairs(sc) do
|
||||
(function(k, v)
|
||||
sc[k] = function(...)
|
||||
local rets = {v(...)}
|
||||
io.stderr:write(('%s(%s) = %s\n'):format(k, format_list({...}),
|
||||
format_list(rets)))
|
||||
return unpack(rets)
|
||||
end
|
||||
end)(k_, v_)
|
||||
end
|
||||
end
|
||||
|
||||
local function gen_itp(it)
|
||||
child_calls_mod = {}
|
||||
child_calls_mod_once = {}
|
||||
child_cleanups_mod_once = {}
|
||||
preprocess_cache_mod = map(function(v) return v end, preprocess_cache_init)
|
||||
previous_defines_mod = previous_defines_init
|
||||
cdefs_mod = cdefs_init:copy()
|
||||
local function just_fail(_)
|
||||
return false
|
||||
end
|
||||
say:set('assertion.just_fail.positive', '%s')
|
||||
say:set('assertion.just_fail.negative', '%s')
|
||||
assert:register('assertion', 'just_fail', just_fail,
|
||||
'assertion.just_fail.positive',
|
||||
'assertion.just_fail.negative')
|
||||
local function itp(name, func, allow_failure)
|
||||
if allow_failure and os.getenv('NVIM_TEST_RUN_FAILING_TESTS') ~= '1' then
|
||||
-- FIXME Fix tests with this true
|
||||
return
|
||||
end
|
||||
it(name, function()
|
||||
local rd, wr = sc.pipe()
|
||||
child_pid = sc.fork()
|
||||
if child_pid == 0 then
|
||||
init()
|
||||
sc.close(rd)
|
||||
collectgarbage('stop')
|
||||
local err, emsg = pcall(func)
|
||||
collectgarbage('restart')
|
||||
emsg = tostring(emsg)
|
||||
if not err then
|
||||
sc.write(wr, ('-\n%05u\n%s'):format(#emsg, emsg))
|
||||
deinit()
|
||||
sc.close(wr)
|
||||
sc.exit(1)
|
||||
else
|
||||
sc.write(wr, '+\n')
|
||||
deinit()
|
||||
sc.close(wr)
|
||||
sc.exit(0)
|
||||
end
|
||||
else
|
||||
sc.close(wr)
|
||||
sc.wait(child_pid)
|
||||
child_pid = nil
|
||||
local function check()
|
||||
local res = sc.read(rd, 2)
|
||||
eq(2, #res)
|
||||
if res == '+\n' then
|
||||
return
|
||||
end
|
||||
eq('-\n', res)
|
||||
local len_s = sc.read(rd, 5)
|
||||
local len = tonumber(len_s)
|
||||
neq(0, len)
|
||||
local err = sc.read(rd, len + 1)
|
||||
assert.just_fail(err)
|
||||
end
|
||||
local err, emsg = pcall(check)
|
||||
sc.close(rd)
|
||||
if not err then
|
||||
if allow_failure then
|
||||
io.stderr:write('Errorred out:\n' .. tostring(emsg) .. '\n')
|
||||
os.execute([[sh -c "source .ci/common/test.sh ; check_core_dumps --delete \"]] .. Paths.test_luajit_prg .. [[\""]])
|
||||
else
|
||||
error(emsg)
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
return itp
|
||||
end
|
||||
|
||||
local function cppimport(path)
|
||||
return cimport(Paths.test_include_path .. '/' .. path)
|
||||
end
|
||||
|
||||
cimport('./src/nvim/types.h', './src/nvim/main.h', './src/nvim/os/time.h')
|
||||
|
||||
local module = {
|
||||
cimport = cimport,
|
||||
cppimport = cppimport,
|
||||
internalize = internalize,
|
||||
@@ -224,11 +576,23 @@ return {
|
||||
eq = eq,
|
||||
neq = neq,
|
||||
ffi = ffi,
|
||||
lib = libnvim,
|
||||
lib = lib,
|
||||
cstr = cstr,
|
||||
to_cstr = to_cstr,
|
||||
NULL = NULL,
|
||||
OK = OK,
|
||||
FAIL = FAIL,
|
||||
alloc_log_new = alloc_log_new,
|
||||
gen_itp = gen_itp,
|
||||
only_separate = only_separate,
|
||||
child_call_once = child_call_once,
|
||||
child_cleanup_once = child_cleanup_once,
|
||||
}
|
||||
return function(after_each)
|
||||
if after_each then
|
||||
after_each(function()
|
||||
check_cores(Paths.test_luajit_prg)
|
||||
end)
|
||||
end
|
||||
return module
|
||||
end
|
||||
|
@@ -1,4 +1,5 @@
|
||||
local helpers = require("test.unit.helpers")
|
||||
local helpers = require("test.unit.helpers")(after_each)
|
||||
local itp = helpers.gen_itp(it)
|
||||
|
||||
local ffi = helpers.ffi
|
||||
local eq = helpers.eq
|
||||
@@ -26,7 +27,7 @@ describe('mbyte', function()
|
||||
before_each(function()
|
||||
end)
|
||||
|
||||
it('utf_ptr2char', 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})))
|
||||
@@ -44,7 +45,7 @@ describe('mbyte', function()
|
||||
|
||||
describe('utfc_ptr2char_len', function()
|
||||
|
||||
it('1-byte sequences', function()
|
||||
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))
|
||||
@@ -52,7 +53,7 @@ describe('mbyte', function()
|
||||
end
|
||||
end)
|
||||
|
||||
it('2-byte sequences', function()
|
||||
itp('2-byte sequences', function()
|
||||
local pcc = to_intp()
|
||||
-- No combining characters
|
||||
eq(0x007f, mbyte.utfc_ptr2char_len(to_string({0x7f, 0x7f}), pcc, 2))
|
||||
@@ -76,7 +77,7 @@ describe('mbyte', function()
|
||||
eq(0, pcc[0])
|
||||
end)
|
||||
|
||||
it('3-byte sequences', function()
|
||||
itp('3-byte sequences', function()
|
||||
local pcc = to_intp()
|
||||
|
||||
-- No second UTF-8 character
|
||||
@@ -108,7 +109,7 @@ describe('mbyte', function()
|
||||
eq(0, pcc[0])
|
||||
end)
|
||||
|
||||
it('4-byte sequences', function()
|
||||
itp('4-byte sequences', function()
|
||||
local pcc = to_intp()
|
||||
|
||||
-- No following combining character
|
||||
@@ -145,7 +146,7 @@ describe('mbyte', function()
|
||||
eq(0, pcc[0])
|
||||
end)
|
||||
|
||||
it('5+-byte sequences', function()
|
||||
itp('5+-byte sequences', function()
|
||||
local pcc = to_intp()
|
||||
|
||||
-- No following combining character
|
||||
|
@@ -1,4 +1,5 @@
|
||||
local helpers = require("test.unit.helpers")
|
||||
local helpers = require("test.unit.helpers")(after_each)
|
||||
local itp = helpers.gen_itp(it)
|
||||
|
||||
local cimport = helpers.cimport
|
||||
local cstr = helpers.cstr
|
||||
@@ -26,7 +27,7 @@ describe('xstrlcat()', function()
|
||||
return ffi.string(dst_cstr)
|
||||
end
|
||||
|
||||
it('concatenates strings', function()
|
||||
itp('concatenates strings', function()
|
||||
eq('ab', test_xstrlcat('a', 'b', 3))
|
||||
eq('ab', test_xstrlcat('a', 'b', 4096))
|
||||
eq('ABCיהZdefgiיהZ', test_xstrlcat('ABCיהZ', 'defgiיהZ', 4096))
|
||||
@@ -34,7 +35,7 @@ describe('xstrlcat()', function()
|
||||
eq('a', test_xstrlcat('a', '', 4096))
|
||||
end)
|
||||
|
||||
it('concatenates overlapping strings', function()
|
||||
itp('concatenates overlapping strings', function()
|
||||
eq('abcabc', test_xstrlcat_overlap('abc', 0, 7))
|
||||
eq('abca', test_xstrlcat_overlap('abc', 0, 5))
|
||||
eq('abcb', test_xstrlcat_overlap('abc', 1, 5))
|
||||
@@ -42,7 +43,7 @@ describe('xstrlcat()', function()
|
||||
eq('abcabc', test_xstrlcat_overlap('abc', 0, 2343))
|
||||
end)
|
||||
|
||||
it('truncates if `dsize` is too small', function()
|
||||
itp('truncates if `dsize` is too small', function()
|
||||
eq('a', test_xstrlcat('a', 'b', 2))
|
||||
eq('', test_xstrlcat('', 'b', 1))
|
||||
eq('ABCיהZd', test_xstrlcat('ABCיהZ', 'defgiיהZ', 10))
|
||||
|
@@ -1,4 +1,5 @@
|
||||
local helpers = require("test.unit.helpers")
|
||||
local helpers = require("test.unit.helpers")(after_each)
|
||||
local itp = helpers.gen_itp(it)
|
||||
|
||||
local ffi = helpers.ffi
|
||||
local eq = helpers.eq
|
||||
@@ -35,23 +36,23 @@ describe('trunc_string', function()
|
||||
|
||||
for _,t in ipairs(permutations) do
|
||||
describe('populates buf '..t.desc, function()
|
||||
it('with a small string', function()
|
||||
itp('with a small string', function()
|
||||
t.func('text', 'text')
|
||||
end)
|
||||
|
||||
it('with a medium string', function()
|
||||
itp('with a medium string', function()
|
||||
t.func('a short text', 'a short text')
|
||||
end)
|
||||
|
||||
it('with a string of length == 1/2 room', function()
|
||||
itp('with a string of length == 1/2 room', function()
|
||||
t.func('a text that fits', 'a text that fits', 34)
|
||||
end)
|
||||
|
||||
it('with a string exactly the truncate size', function()
|
||||
itp('with a string exactly the truncate size', function()
|
||||
t.func('a text tha just fits', 'a text tha just fits')
|
||||
end)
|
||||
|
||||
it('with a string that must be truncated', function()
|
||||
itp('with a string that must be truncated', function()
|
||||
t.func('a text that nott fits', 'a text t...nott fits')
|
||||
end)
|
||||
end)
|
||||
|
@@ -1,9 +1,12 @@
|
||||
local helpers = require("test.unit.helpers")
|
||||
local helpers = require("test.unit.helpers")(after_each)
|
||||
local itp = helpers.gen_itp(it)
|
||||
|
||||
local ffi = helpers.ffi
|
||||
local eq = helpers.eq
|
||||
local child_call_once = helpers.child_call_once
|
||||
local cimport = helpers.cimport
|
||||
local ffi = helpers.ffi
|
||||
local eq = helpers.eq
|
||||
|
||||
local multiqueue = helpers.cimport("./test/unit/fixtures/multiqueue.h")
|
||||
local multiqueue = cimport("./test/unit/fixtures/multiqueue.h")
|
||||
|
||||
describe("multiqueue (multi-level event-queue)", function()
|
||||
local parent, child1, child2, child3
|
||||
@@ -21,28 +24,30 @@ describe("multiqueue (multi-level event-queue)", function()
|
||||
end
|
||||
|
||||
before_each(function()
|
||||
parent = multiqueue.multiqueue_new_parent(ffi.NULL, ffi.NULL)
|
||||
child1 = multiqueue.multiqueue_new_child(parent)
|
||||
child2 = multiqueue.multiqueue_new_child(parent)
|
||||
child3 = multiqueue.multiqueue_new_child(parent)
|
||||
put(child1, 'c1i1')
|
||||
put(child1, 'c1i2')
|
||||
put(child2, 'c2i1')
|
||||
put(child1, 'c1i3')
|
||||
put(child2, 'c2i2')
|
||||
put(child2, 'c2i3')
|
||||
put(child2, 'c2i4')
|
||||
put(child3, 'c3i1')
|
||||
put(child3, 'c3i2')
|
||||
child_call_once(function()
|
||||
parent = multiqueue.multiqueue_new_parent(ffi.NULL, ffi.NULL)
|
||||
child1 = multiqueue.multiqueue_new_child(parent)
|
||||
child2 = multiqueue.multiqueue_new_child(parent)
|
||||
child3 = multiqueue.multiqueue_new_child(parent)
|
||||
put(child1, 'c1i1')
|
||||
put(child1, 'c1i2')
|
||||
put(child2, 'c2i1')
|
||||
put(child1, 'c1i3')
|
||||
put(child2, 'c2i2')
|
||||
put(child2, 'c2i3')
|
||||
put(child2, 'c2i4')
|
||||
put(child3, 'c3i1')
|
||||
put(child3, 'c3i2')
|
||||
end)
|
||||
end)
|
||||
|
||||
it('keeps count of added events', function()
|
||||
itp('keeps count of added events', function()
|
||||
eq(3, multiqueue.multiqueue_size(child1))
|
||||
eq(4, multiqueue.multiqueue_size(child2))
|
||||
eq(2, multiqueue.multiqueue_size(child3))
|
||||
end)
|
||||
|
||||
it('keeps count of removed events', function()
|
||||
itp('keeps count of removed events', function()
|
||||
multiqueue.multiqueue_get(child1)
|
||||
eq(2, multiqueue.multiqueue_size(child1))
|
||||
multiqueue.multiqueue_get(child1)
|
||||
@@ -57,7 +62,7 @@ describe("multiqueue (multi-level event-queue)", function()
|
||||
eq(0, multiqueue.multiqueue_size(child1))
|
||||
end)
|
||||
|
||||
it('removing from parent removes from child', function()
|
||||
itp('removing from parent removes from child', function()
|
||||
eq('c1i1', get(parent))
|
||||
eq('c1i2', get(parent))
|
||||
eq('c2i1', get(parent))
|
||||
@@ -67,7 +72,7 @@ describe("multiqueue (multi-level event-queue)", function()
|
||||
eq('c2i4', get(parent))
|
||||
end)
|
||||
|
||||
it('removing from child removes from parent', function()
|
||||
itp('removing from child removes from parent', function()
|
||||
eq('c2i1', get(child2))
|
||||
eq('c2i2', get(child2))
|
||||
eq('c1i1', get(child1))
|
||||
@@ -77,13 +82,13 @@ describe("multiqueue (multi-level event-queue)", function()
|
||||
eq('c2i4', get(parent))
|
||||
end)
|
||||
|
||||
it('removing from child at the beginning of parent', function()
|
||||
itp('removing from child at the beginning of parent', function()
|
||||
eq('c1i1', get(child1))
|
||||
eq('c1i2', get(child1))
|
||||
eq('c2i1', get(parent))
|
||||
end)
|
||||
|
||||
it('removing from parent after get from parent and put to child', function()
|
||||
itp('removing from parent after get from parent and put to child', function()
|
||||
eq('c1i1', get(parent))
|
||||
eq('c1i2', get(parent))
|
||||
eq('c2i1', get(parent))
|
||||
@@ -99,7 +104,7 @@ describe("multiqueue (multi-level event-queue)", function()
|
||||
eq('c1i22', get(parent))
|
||||
end)
|
||||
|
||||
it('removing from parent after get and put to child', function()
|
||||
itp('removing from parent after get and put to child', function()
|
||||
eq('c1i1', get(child1))
|
||||
eq('c1i2', get(child1))
|
||||
eq('c2i1', get(child2))
|
||||
@@ -117,7 +122,7 @@ describe("multiqueue (multi-level event-queue)", function()
|
||||
eq('c1i12', get(parent))
|
||||
end)
|
||||
|
||||
it('put after removing from child at the end of parent', function()
|
||||
itp('put after removing from child at the end of parent', function()
|
||||
eq('c3i1', get(child3))
|
||||
eq('c3i2', get(child3))
|
||||
put(child1, 'c1i11')
|
||||
@@ -133,7 +138,7 @@ describe("multiqueue (multi-level event-queue)", function()
|
||||
eq('c2i11', get(parent))
|
||||
end)
|
||||
|
||||
it('removes from parent queue when child is freed', function()
|
||||
itp('removes from parent queue when child is freed', function()
|
||||
free(child2)
|
||||
eq('c1i1', get(parent))
|
||||
eq('c1i2', get(parent))
|
||||
|
@@ -1,4 +1,5 @@
|
||||
local helpers = require("test.unit.helpers")
|
||||
local helpers = require("test.unit.helpers")(after_each)
|
||||
local itp = helpers.gen_itp(it)
|
||||
|
||||
local to_cstr = helpers.to_cstr
|
||||
local eq = helpers.eq
|
||||
@@ -12,23 +13,23 @@ end
|
||||
|
||||
describe('check_ff_value', function()
|
||||
|
||||
it('views empty string as valid', function()
|
||||
itp('views empty string as valid', function()
|
||||
eq(1, check_ff_value(""))
|
||||
end)
|
||||
|
||||
it('views "unix", "dos" and "mac" as valid', function()
|
||||
itp('views "unix", "dos" and "mac" as valid', function()
|
||||
eq(1, check_ff_value("unix"))
|
||||
eq(1, check_ff_value("dos"))
|
||||
eq(1, check_ff_value("mac"))
|
||||
end)
|
||||
|
||||
it('views "foo" as invalid', function()
|
||||
itp('views "foo" as invalid', function()
|
||||
eq(0, check_ff_value("foo"))
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('get_sts_value', function()
|
||||
it([[returns 'softtabstop' when it is non-negative]], function()
|
||||
itp([[returns 'softtabstop' when it is non-negative]], function()
|
||||
globals.curbuf.b_p_sts = 5
|
||||
eq(5, option.get_sts_value())
|
||||
|
||||
@@ -36,7 +37,7 @@ describe('get_sts_value', function()
|
||||
eq(0, option.get_sts_value())
|
||||
end)
|
||||
|
||||
it([[returns "effective shiftwidth" when 'softtabstop' is negative]], function()
|
||||
itp([[returns "effective shiftwidth" when 'softtabstop' is negative]], function()
|
||||
local shiftwidth = 2
|
||||
globals.curbuf.b_p_sw = shiftwidth
|
||||
local tabstop = 5
|
||||
|
@@ -1,4 +1,5 @@
|
||||
local helpers = require('test.unit.helpers')
|
||||
local helpers = require('test.unit.helpers')(after_each)
|
||||
local itp = helpers.gen_itp(it)
|
||||
|
||||
local cimport = helpers.cimport
|
||||
local eq = helpers.eq
|
||||
@@ -33,7 +34,7 @@ describe('env function', function()
|
||||
describe('os_setenv', function()
|
||||
local OK = 0
|
||||
|
||||
it('sets an env variable and returns OK', function()
|
||||
itp('sets an env variable and returns OK', function()
|
||||
local name = 'NEOVIM_UNIT_TEST_SETENV_1N'
|
||||
local value = 'NEOVIM_UNIT_TEST_SETENV_1V'
|
||||
eq(nil, os.getenv(name))
|
||||
@@ -41,7 +42,7 @@ describe('env function', function()
|
||||
eq(value, os.getenv(name))
|
||||
end)
|
||||
|
||||
it("dosn't overwrite an env variable if overwrite is 0", function()
|
||||
itp("dosn't overwrite an env variable if overwrite is 0", function()
|
||||
local name = 'NEOVIM_UNIT_TEST_SETENV_2N'
|
||||
local value = 'NEOVIM_UNIT_TEST_SETENV_2V'
|
||||
local value_updated = 'NEOVIM_UNIT_TEST_SETENV_2V_UPDATED'
|
||||
@@ -53,13 +54,13 @@ describe('env function', function()
|
||||
end)
|
||||
|
||||
describe('os_setenv_append_path', function()
|
||||
it('appends /foo/bar to $PATH', function()
|
||||
itp('appends /foo/bar to $PATH', function()
|
||||
local original_path = os.getenv('PATH')
|
||||
eq(true, cimp.os_setenv_append_path(to_cstr('/foo/bar/baz')))
|
||||
eq(original_path..':/foo/bar', os.getenv('PATH'))
|
||||
end)
|
||||
|
||||
it('returns false if `fname` is not absolute', function()
|
||||
itp('returns false if `fname` is not absolute', function()
|
||||
local original_path = os.getenv('PATH')
|
||||
eq(false, cimp.os_setenv_append_path(to_cstr('foo/bar/baz')))
|
||||
eq(original_path, os.getenv('PATH'))
|
||||
@@ -67,7 +68,7 @@ describe('env function', function()
|
||||
end)
|
||||
|
||||
describe('os_getenv', function()
|
||||
it('reads an env variable', function()
|
||||
itp('reads an env variable', function()
|
||||
local name = 'NEOVIM_UNIT_TEST_GETENV_1N'
|
||||
local value = 'NEOVIM_UNIT_TEST_GETENV_1V'
|
||||
eq(NULL, os_getenv(name))
|
||||
@@ -76,14 +77,14 @@ describe('env function', function()
|
||||
eq(value, os_getenv(name))
|
||||
end)
|
||||
|
||||
it('returns NULL if the env variable is not found', function()
|
||||
itp('returns NULL if the env variable is not found', function()
|
||||
local name = 'NEOVIM_UNIT_TEST_GETENV_NOTFOUND'
|
||||
return eq(NULL, os_getenv(name))
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('os_unsetenv', function()
|
||||
it('unsets environment variable', function()
|
||||
itp('unsets environment variable', function()
|
||||
local name = 'TEST_UNSETENV'
|
||||
local value = 'TESTVALUE'
|
||||
os_setenv(name, value, 1)
|
||||
@@ -95,7 +96,7 @@ describe('env function', function()
|
||||
end)
|
||||
|
||||
describe('os_getenvname_at_index', function()
|
||||
it('returns names of environment variables', function()
|
||||
itp('returns names of environment variables', function()
|
||||
local test_name = 'NEOVIM_UNIT_TEST_GETENVNAME_AT_INDEX_1N'
|
||||
local test_value = 'NEOVIM_UNIT_TEST_GETENVNAME_AT_INDEX_1V'
|
||||
os_setenv(test_name, test_value, 1)
|
||||
@@ -115,7 +116,7 @@ describe('env function', function()
|
||||
eq(true, found_name)
|
||||
end)
|
||||
|
||||
it('returns NULL if the index is out of bounds', function()
|
||||
itp('returns NULL if the index is out of bounds', function()
|
||||
local huge = ffi.new('size_t', 10000)
|
||||
local maxuint32 = ffi.new('size_t', 4294967295)
|
||||
eq(NULL, cimp.os_getenvname_at_index(huge))
|
||||
@@ -132,7 +133,7 @@ describe('env function', function()
|
||||
end)
|
||||
|
||||
describe('os_get_pid', function()
|
||||
it('returns the process ID', function()
|
||||
itp('returns the process ID', function()
|
||||
local stat_file = io.open('/proc/self/stat')
|
||||
if stat_file then
|
||||
local stat_str = stat_file:read('*l')
|
||||
@@ -147,7 +148,7 @@ describe('env function', function()
|
||||
end)
|
||||
|
||||
describe('os_get_hostname', function()
|
||||
it('returns the hostname', function()
|
||||
itp('returns the hostname', function()
|
||||
local handle = io.popen('hostname')
|
||||
local hostname = handle:read('*l')
|
||||
handle:close()
|
||||
@@ -158,7 +159,7 @@ describe('env function', function()
|
||||
end)
|
||||
|
||||
describe('expand_env_esc', function()
|
||||
it('expands environment variables', function()
|
||||
itp('expands environment variables', function()
|
||||
local name = 'NEOVIM_UNIT_TEST_EXPAND_ENV_ESCN'
|
||||
local value = 'NEOVIM_UNIT_TEST_EXPAND_ENV_ESCV'
|
||||
os_setenv(name, value, 1)
|
||||
@@ -175,7 +176,7 @@ describe('env function', function()
|
||||
eq(output_expected, ffi.string(output_buff2))
|
||||
end)
|
||||
|
||||
it('expands ~ once when `one` is true', function()
|
||||
itp('expands ~ once when `one` is true', function()
|
||||
local input = '~/foo ~ foo'
|
||||
local homedir = cstr(255, '')
|
||||
cimp.expand_env_esc(to_cstr('~'), homedir, 255, false, true, NULL)
|
||||
@@ -185,7 +186,7 @@ describe('env function', function()
|
||||
eq(ffi.string(output), ffi.string(output_expected))
|
||||
end)
|
||||
|
||||
it('expands ~ every time when `one` is false', function()
|
||||
itp('expands ~ every time when `one` is false', function()
|
||||
local input = to_cstr('~/foo ~ foo')
|
||||
local dst = cstr(255, '')
|
||||
cimp.expand_env_esc(to_cstr('~'), dst, 255, false, true, NULL)
|
||||
@@ -196,7 +197,7 @@ describe('env function', function()
|
||||
eq(output_expected, ffi.string(output))
|
||||
end)
|
||||
|
||||
it('does not crash #3725', function()
|
||||
itp('does not crash #3725', function()
|
||||
local name_out = ffi.new('char[100]')
|
||||
cimp.os_get_user_name(name_out, 100)
|
||||
local curuser = ffi.string(name_out)
|
||||
@@ -209,7 +210,7 @@ describe('env function', function()
|
||||
assert.True(len < 99)
|
||||
end)
|
||||
|
||||
it('respects `dstlen` without expansion', function()
|
||||
itp('respects `dstlen` without expansion', function()
|
||||
local input = to_cstr('this is a very long thing that will not fit')
|
||||
-- The buffer is long enough to actually contain the full input in case the
|
||||
-- test fails, but we don't tell expand_env_esc that
|
||||
@@ -223,7 +224,7 @@ describe('env function', function()
|
||||
eq(0, output[4])
|
||||
end)
|
||||
|
||||
it('respects `dstlen` with expansion', function()
|
||||
itp('respects `dstlen` with expansion', function()
|
||||
local varname = to_cstr('NVIM_UNIT_TEST_EXPAND_ENV_ESC_DSTLENN')
|
||||
local varval = to_cstr('NVIM_UNIT_TEST_EXPAND_ENV_ESC_DSTLENV')
|
||||
cimp.os_setenv(varname, varval, 1)
|
||||
|
@@ -1,6 +1,7 @@
|
||||
local lfs = require('lfs')
|
||||
|
||||
local helpers = require('test.unit.helpers')
|
||||
local helpers = require('test.unit.helpers')(after_each)
|
||||
local itp = helpers.gen_itp(it)
|
||||
|
||||
local eq = helpers.eq
|
||||
local ffi = helpers.ffi
|
||||
@@ -88,7 +89,7 @@ local function file_skip(fp, size)
|
||||
end
|
||||
|
||||
describe('file_open', function()
|
||||
it('can create a rwx------ file with kFileCreate', 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)
|
||||
@@ -96,7 +97,7 @@ describe('file_open', function()
|
||||
eq(0, m.file_close(fp))
|
||||
end)
|
||||
|
||||
it('can create a rw------- file with kFileCreate', function()
|
||||
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)
|
||||
@@ -104,7 +105,7 @@ describe('file_open', function()
|
||||
eq(0, m.file_close(fp))
|
||||
end)
|
||||
|
||||
it('can create a rwx------ file with kFileCreateOnly', function()
|
||||
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)
|
||||
@@ -112,7 +113,7 @@ describe('file_open', function()
|
||||
eq(0, m.file_close(fp))
|
||||
end)
|
||||
|
||||
it('can create a rw------- file with kFileCreateOnly', function()
|
||||
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)
|
||||
@@ -120,47 +121,47 @@ describe('file_open', function()
|
||||
eq(0, m.file_close(fp))
|
||||
end)
|
||||
|
||||
it('fails to open an existing file with kFileCreateOnly', function()
|
||||
itp('fails to open an existing file with kFileCreateOnly', function()
|
||||
local err, _ = file_open(file1, m.kFileCreateOnly, 384)
|
||||
eq(m.UV_EEXIST, err)
|
||||
end)
|
||||
|
||||
it('fails to open an symlink with kFileNoSymlink', function()
|
||||
itp('fails to open an symlink with kFileNoSymlink', function()
|
||||
local err, _ = file_open(linkf, m.kFileNoSymlink, 384)
|
||||
-- err is UV_EMLINK in FreeBSD, but if I use `ok(err == m.UV_ELOOP or err ==
|
||||
-- m.UV_EMLINK)`, then I loose the ability to see actual `err` value.
|
||||
if err ~= m.UV_ELOOP then eq(m.UV_EMLINK, err) end
|
||||
end)
|
||||
|
||||
it('can open an existing file write-only with kFileCreate', function()
|
||||
itp('can open an existing file write-only with kFileCreate', function()
|
||||
local err, fp = file_open(file1, m.kFileCreate, 384)
|
||||
eq(0, err)
|
||||
eq(true, fp.wr)
|
||||
eq(0, m.file_close(fp))
|
||||
end)
|
||||
|
||||
it('can open an existing file read-only with zero', function()
|
||||
itp('can open an existing file read-only with zero', function()
|
||||
local err, fp = file_open(file1, 0, 384)
|
||||
eq(0, err)
|
||||
eq(false, fp.wr)
|
||||
eq(0, m.file_close(fp))
|
||||
end)
|
||||
|
||||
it('can open an existing file read-only with kFileReadOnly', function()
|
||||
itp('can open an existing file read-only with kFileReadOnly', function()
|
||||
local err, fp = file_open(file1, m.kFileReadOnly, 384)
|
||||
eq(0, err)
|
||||
eq(false, fp.wr)
|
||||
eq(0, m.file_close(fp))
|
||||
end)
|
||||
|
||||
it('can open an existing file read-only with kFileNoSymlink', function()
|
||||
itp('can open an existing file read-only with kFileNoSymlink', function()
|
||||
local err, fp = file_open(file1, m.kFileNoSymlink, 384)
|
||||
eq(0, err)
|
||||
eq(false, fp.wr)
|
||||
eq(0, m.file_close(fp))
|
||||
end)
|
||||
|
||||
it('can truncate an existing file with kFileTruncate', function()
|
||||
itp('can truncate an existing file with kFileTruncate', function()
|
||||
local err, fp = file_open(file1, m.kFileTruncate, 384)
|
||||
eq(0, err)
|
||||
eq(true, fp.wr)
|
||||
@@ -169,7 +170,7 @@ describe('file_open', function()
|
||||
eq(0, attrs.size)
|
||||
end)
|
||||
|
||||
it('can open an existing file write-only with kFileWriteOnly', function()
|
||||
itp('can open an existing file write-only with kFileWriteOnly', function()
|
||||
local err, fp = file_open(file1, m.kFileWriteOnly, 384)
|
||||
eq(0, err)
|
||||
eq(true, fp.wr)
|
||||
@@ -178,14 +179,14 @@ describe('file_open', function()
|
||||
eq(4096, attrs.size)
|
||||
end)
|
||||
|
||||
it('fails to create a file with just kFileWriteOnly', function()
|
||||
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)
|
||||
eq(nil, attrs)
|
||||
end)
|
||||
|
||||
it('can truncate an existing file with kFileTruncate when opening a symlink',
|
||||
itp('can truncate an existing file with kFileTruncate when opening a symlink',
|
||||
function()
|
||||
local err, fp = file_open(linkf, m.kFileTruncate, 384)
|
||||
eq(0, err)
|
||||
@@ -195,31 +196,31 @@ describe('file_open', function()
|
||||
eq(0, attrs.size)
|
||||
end)
|
||||
|
||||
it('fails to open a directory write-only', function()
|
||||
itp('fails to open a directory write-only', function()
|
||||
local err, _ = file_open(dir, m.kFileWriteOnly, 384)
|
||||
eq(m.UV_EISDIR, err)
|
||||
end)
|
||||
|
||||
it('fails to open a broken symbolic link write-only', function()
|
||||
itp('fails to open a broken symbolic link write-only', function()
|
||||
local err, _ = file_open(linkb, m.kFileWriteOnly, 384)
|
||||
eq(m.UV_ENOENT, err)
|
||||
end)
|
||||
|
||||
it('fails to open a broken symbolic link read-only', function()
|
||||
itp('fails to open a broken symbolic link read-only', function()
|
||||
local err, _ = file_open(linkb, m.kFileReadOnly, 384)
|
||||
eq(m.UV_ENOENT, err)
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('file_open_new', function()
|
||||
it('can open a file read-only', function()
|
||||
itp('can open a file read-only', function()
|
||||
local err, fp = file_open_new(file1, 0, 384)
|
||||
eq(0, err)
|
||||
eq(false, fp.wr)
|
||||
eq(0, m.file_free(fp))
|
||||
end)
|
||||
|
||||
it('fails to open an existing file with kFileCreateOnly', function()
|
||||
itp('fails to open an existing file with kFileCreateOnly', function()
|
||||
local err, fp = file_open_new(file1, m.kFileCreateOnly, 384)
|
||||
eq(m.UV_EEXIST, err)
|
||||
eq(nil, fp)
|
||||
@@ -229,7 +230,7 @@ end)
|
||||
-- file_close is called above, so it is not tested directly
|
||||
|
||||
describe('file_fsync', function()
|
||||
it('can flush writes to disk', function()
|
||||
itp('can flush writes to disk', function()
|
||||
local err, fp = file_open(filec, m.kFileCreateOnly, 384)
|
||||
eq(0, file_fsync(fp))
|
||||
eq(0, err)
|
||||
@@ -244,7 +245,7 @@ describe('file_fsync', function()
|
||||
end)
|
||||
|
||||
describe('file_read', function()
|
||||
it('can read small chunks of input until eof', function()
|
||||
itp('can read small chunks of input until eof', function()
|
||||
local err, fp = file_open(file1, 0, 384)
|
||||
eq(0, err)
|
||||
eq(false, fp.wr)
|
||||
@@ -264,7 +265,7 @@ describe('file_read', function()
|
||||
eq(0, m.file_close(fp))
|
||||
end)
|
||||
|
||||
it('can read the whole file at once', function()
|
||||
itp('can read the whole file at once', function()
|
||||
local err, fp = file_open(file1, 0, 384)
|
||||
eq(0, err)
|
||||
eq(false, fp.wr)
|
||||
@@ -273,7 +274,7 @@ describe('file_read', function()
|
||||
eq(0, m.file_close(fp))
|
||||
end)
|
||||
|
||||
it('can read more then 1024 bytes after reading a small chunk', function()
|
||||
itp('can read more then 1024 bytes after reading a small chunk', function()
|
||||
local err, fp = file_open(file1, 0, 384)
|
||||
eq(0, err)
|
||||
eq(false, fp.wr)
|
||||
@@ -283,7 +284,7 @@ describe('file_read', function()
|
||||
eq(0, m.file_close(fp))
|
||||
end)
|
||||
|
||||
it('can read file by 768-byte-chunks', function()
|
||||
itp('can read file by 768-byte-chunks', function()
|
||||
local err, fp = file_open(file1, 0, 384)
|
||||
eq(0, err)
|
||||
eq(false, fp.wr)
|
||||
@@ -305,7 +306,7 @@ describe('file_read', function()
|
||||
end)
|
||||
|
||||
describe('file_write', function()
|
||||
it('can write the whole file at once', function()
|
||||
itp('can write the whole file at once', function()
|
||||
local err, fp = file_open(filec, m.kFileCreateOnly, 384)
|
||||
eq(0, err)
|
||||
eq(true, fp.wr)
|
||||
@@ -316,7 +317,7 @@ describe('file_write', function()
|
||||
eq(fcontents, io.open(filec):read('*a'))
|
||||
end)
|
||||
|
||||
it('can write the whole file by small chunks', function()
|
||||
itp('can write the whole file by small chunks', function()
|
||||
local err, fp = file_open(filec, m.kFileCreateOnly, 384)
|
||||
eq(0, err)
|
||||
eq(true, fp.wr)
|
||||
@@ -333,7 +334,7 @@ describe('file_write', function()
|
||||
eq(fcontents, io.open(filec):read('*a'))
|
||||
end)
|
||||
|
||||
it('can write the whole file by 768-byte-chunks', function()
|
||||
itp('can write the whole file by 768-byte-chunks', function()
|
||||
local err, fp = file_open(filec, m.kFileCreateOnly, 384)
|
||||
eq(0, err)
|
||||
eq(true, fp.wr)
|
||||
@@ -352,7 +353,7 @@ describe('file_write', function()
|
||||
end)
|
||||
|
||||
describe('file_skip', function()
|
||||
it('can skip 3 bytes', function()
|
||||
itp('can skip 3 bytes', function()
|
||||
local err, fp = file_open(file1, 0, 384)
|
||||
eq(0, err)
|
||||
eq(false, fp.wr)
|
||||
|
@@ -1,7 +1,8 @@
|
||||
local lfs = require('lfs')
|
||||
local bit = require('bit')
|
||||
|
||||
local helpers = require('test.unit.helpers')
|
||||
local helpers = require('test.unit.helpers')(after_each)
|
||||
local itp = helpers.gen_itp(it)
|
||||
|
||||
local cimport = helpers.cimport
|
||||
local cppimport = helpers.cppimport
|
||||
@@ -15,10 +16,10 @@ local to_cstr = helpers.to_cstr
|
||||
local OK = helpers.OK
|
||||
local FAIL = helpers.FAIL
|
||||
local NULL = helpers.NULL
|
||||
|
||||
local NODE_NORMAL = 0
|
||||
local NODE_WRITABLE = 1
|
||||
|
||||
cimport('unistd.h')
|
||||
cimport('./src/nvim/os/shell.h')
|
||||
cimport('./src/nvim/option_defs.h')
|
||||
cimport('./src/nvim/main.h')
|
||||
@@ -65,13 +66,10 @@ local function os_getperm(filename)
|
||||
end
|
||||
|
||||
describe('fs function', function()
|
||||
local orig_test_file_perm
|
||||
|
||||
setup(function()
|
||||
before_each(function()
|
||||
lfs.mkdir('unit-test-directory');
|
||||
|
||||
io.open('unit-test-directory/test.file', 'w').close()
|
||||
orig_test_file_perm = os_getperm('unit-test-directory/test.file')
|
||||
|
||||
io.open('unit-test-directory/test_2.file', 'w').close()
|
||||
lfs.link('test.file', 'unit-test-directory/test_link.file', true)
|
||||
@@ -83,7 +81,7 @@ describe('fs function', function()
|
||||
directory, executable_name = string.match(absolute_executable, '^(.*)/(.*)$')
|
||||
end)
|
||||
|
||||
teardown(function()
|
||||
after_each(function()
|
||||
os.remove('unit-test-directory/test.file')
|
||||
os.remove('unit-test-directory/test_2.file')
|
||||
os.remove('unit-test-directory/test_link.file')
|
||||
@@ -104,13 +102,13 @@ describe('fs function', function()
|
||||
buffer = cstr(length, '')
|
||||
end)
|
||||
|
||||
it('returns OK and writes current directory into the buffer if it is large\n enough', function()
|
||||
itp('returns OK and writes current directory into the buffer if it is large\n enough', function()
|
||||
eq(OK, (os_dirname(buffer, length)))
|
||||
eq(lfs.currentdir(), (ffi.string(buffer)))
|
||||
end)
|
||||
|
||||
-- What kind of other failing cases are possible?
|
||||
it('returns FAIL if the buffer is too small', function()
|
||||
itp('returns FAIL if the buffer is too small', function()
|
||||
local buf = cstr((length - 1), '')
|
||||
eq(FAIL, (os_dirname(buf, (length - 1))))
|
||||
end)
|
||||
@@ -121,35 +119,35 @@ describe('fs function', function()
|
||||
end
|
||||
|
||||
describe('os_isdir', function()
|
||||
it('returns false if an empty string is given', function()
|
||||
itp('returns false if an empty string is given', function()
|
||||
eq(false, (os_isdir('')))
|
||||
end)
|
||||
|
||||
it('returns false if a nonexisting directory is given', function()
|
||||
itp('returns false if a nonexisting directory is given', function()
|
||||
eq(false, (os_isdir('non-existing-directory')))
|
||||
end)
|
||||
|
||||
it('returns false if a nonexisting absolute directory is given', function()
|
||||
itp('returns false if a nonexisting absolute directory is given', function()
|
||||
eq(false, (os_isdir('/non-existing-directory')))
|
||||
end)
|
||||
|
||||
it('returns false if an existing file is given', function()
|
||||
itp('returns false if an existing file is given', function()
|
||||
eq(false, (os_isdir('unit-test-directory/test.file')))
|
||||
end)
|
||||
|
||||
it('returns true if the current directory is given', function()
|
||||
itp('returns true if the current directory is given', function()
|
||||
eq(true, (os_isdir('.')))
|
||||
end)
|
||||
|
||||
it('returns true if the parent directory is given', function()
|
||||
itp('returns true if the parent directory is given', function()
|
||||
eq(true, (os_isdir('..')))
|
||||
end)
|
||||
|
||||
it('returns true if an arbitrary directory is given', function()
|
||||
itp('returns true if an arbitrary directory is given', function()
|
||||
eq(true, (os_isdir('unit-test-directory')))
|
||||
end)
|
||||
|
||||
it('returns true if an absolute directory is given', function()
|
||||
itp('returns true if an absolute directory is given', function()
|
||||
eq(true, (os_isdir(directory)))
|
||||
end)
|
||||
end)
|
||||
@@ -179,24 +177,24 @@ describe('fs function', function()
|
||||
return os_can_exe(name)
|
||||
end
|
||||
|
||||
it('returns false when given a directory', function()
|
||||
itp('returns false when given a directory', function()
|
||||
cant_exe('./unit-test-directory')
|
||||
end)
|
||||
|
||||
it('returns false when given a regular file without executable bit set', function()
|
||||
itp('returns false when given a regular file without executable bit set', function()
|
||||
cant_exe('unit-test-directory/test.file')
|
||||
end)
|
||||
|
||||
it('returns false when the given file does not exists', function()
|
||||
itp('returns false when the given file does not exists', function()
|
||||
cant_exe('does-not-exist.file')
|
||||
end)
|
||||
|
||||
it('returns the absolute path when given an executable inside $PATH', function()
|
||||
itp('returns the absolute path when given an executable inside $PATH', function()
|
||||
local fullpath = exe('ls')
|
||||
eq(1, fs.path_is_absolute_path(to_cstr(fullpath)))
|
||||
end)
|
||||
|
||||
it('returns the absolute path when given an executable relative to the current dir', function()
|
||||
itp('returns the absolute path when given an executable relative to the current dir', function()
|
||||
local old_dir = lfs.currentdir()
|
||||
|
||||
lfs.chdir(directory)
|
||||
@@ -216,10 +214,6 @@ describe('fs function', function()
|
||||
end)
|
||||
|
||||
describe('file permissions', function()
|
||||
before_each(function()
|
||||
os_setperm('unit-test-directory/test.file', orig_test_file_perm)
|
||||
end)
|
||||
|
||||
local function os_fchown(filename, user_id, group_id)
|
||||
local fd = ffi.C.open(filename, 0)
|
||||
local res = fs.os_fchown(fd, user_id, group_id)
|
||||
@@ -240,22 +234,22 @@ describe('fs function', function()
|
||||
end
|
||||
|
||||
describe('os_getperm', function()
|
||||
it('returns UV_ENOENT when the given file does not exist', function()
|
||||
itp('returns UV_ENOENT when the given file does not exist', function()
|
||||
eq(ffi.C.UV_ENOENT, (os_getperm('non-existing-file')))
|
||||
end)
|
||||
|
||||
it('returns a perm > 0 when given an existing file', function()
|
||||
itp('returns a perm > 0 when given an existing file', function()
|
||||
assert.is_true((os_getperm('unit-test-directory')) > 0)
|
||||
end)
|
||||
|
||||
it('returns S_IRUSR when the file is readable', function()
|
||||
itp('returns S_IRUSR when the file is readable', function()
|
||||
local perm = os_getperm('unit-test-directory')
|
||||
assert.is_true((bit_set(perm, ffi.C.kS_IRUSR)))
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('os_setperm', function()
|
||||
it('can set and unset the executable bit of a file', function()
|
||||
itp('can set and unset the executable bit of a file', function()
|
||||
local perm = os_getperm('unit-test-directory/test.file')
|
||||
perm = unset_bit(perm, ffi.C.kS_IXUSR)
|
||||
eq(OK, (os_setperm('unit-test-directory/test.file', perm)))
|
||||
@@ -267,7 +261,7 @@ describe('fs function', function()
|
||||
assert.is_true((bit_set(perm, ffi.C.kS_IXUSR)))
|
||||
end)
|
||||
|
||||
it('fails if given file does not exist', function()
|
||||
itp('fails if given file does not exist', function()
|
||||
local perm = ffi.C.kS_IXUSR
|
||||
eq(FAIL, (os_setperm('non-existing-file', perm)))
|
||||
end)
|
||||
@@ -275,7 +269,7 @@ describe('fs function', function()
|
||||
|
||||
describe('os_fchown', function()
|
||||
local filename = 'unit-test-directory/test.file'
|
||||
it('does not change owner and group if respective IDs are equal to -1', function()
|
||||
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')
|
||||
eq(0, os_fchown(filename, -1, -1))
|
||||
@@ -287,7 +281,7 @@ describe('fs function', function()
|
||||
if (os.execute('id -G > /dev/null 2>&1') ~= 0) then
|
||||
pending('skipped (missing `id` utility)', function() end)
|
||||
else
|
||||
it('owner of a file may change the group of the file to any group of which that owner is a member', function()
|
||||
itp('owner of a file may change the group of the file to any group of which that owner is a member', function()
|
||||
local file_gid = lfs.attributes(filename, 'gid')
|
||||
|
||||
-- Gets ID of any group of which current user is a member except the
|
||||
@@ -311,7 +305,7 @@ describe('fs function', function()
|
||||
if (ffi.os == 'Windows' or ffi.C.geteuid() == 0) then
|
||||
pending('skipped (uv_fs_chown is no-op on Windows)', function() end)
|
||||
else
|
||||
it('returns nonzero if process has not enough permissions', function()
|
||||
itp('returns nonzero if process has not enough permissions', function()
|
||||
-- chown to root
|
||||
neq(0, os_fchown(filename, 0, 0))
|
||||
end)
|
||||
@@ -320,7 +314,7 @@ describe('fs function', function()
|
||||
|
||||
|
||||
describe('os_file_is_readable', function()
|
||||
it('returns false if the file is not readable', function()
|
||||
itp('returns false if the file is not readable', function()
|
||||
local perm = os_getperm('unit-test-directory/test.file')
|
||||
perm = unset_bit(perm, ffi.C.kS_IRUSR)
|
||||
perm = unset_bit(perm, ffi.C.kS_IRGRP)
|
||||
@@ -329,19 +323,19 @@ describe('fs function', function()
|
||||
eq(false, os_file_is_readable('unit-test-directory/test.file'))
|
||||
end)
|
||||
|
||||
it('returns false if the file does not exist', function()
|
||||
itp('returns false if the file does not exist', function()
|
||||
eq(false, os_file_is_readable(
|
||||
'unit-test-directory/what_are_you_smoking.gif'))
|
||||
end)
|
||||
|
||||
it('returns true if the file is readable', function()
|
||||
itp('returns true if the file is readable', function()
|
||||
eq(true, os_file_is_readable(
|
||||
'unit-test-directory/test.file'))
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('os_file_is_writable', function()
|
||||
it('returns 0 if the file is readonly', function()
|
||||
itp('returns 0 if the file is readonly', function()
|
||||
local perm = os_getperm('unit-test-directory/test.file')
|
||||
perm = unset_bit(perm, ffi.C.kS_IWUSR)
|
||||
perm = unset_bit(perm, ffi.C.kS_IWGRP)
|
||||
@@ -350,11 +344,11 @@ describe('fs function', function()
|
||||
eq(0, os_file_is_writable('unit-test-directory/test.file'))
|
||||
end)
|
||||
|
||||
it('returns 1 if the file is writable', function()
|
||||
itp('returns 1 if the file is writable', function()
|
||||
eq(1, os_file_is_writable('unit-test-directory/test.file'))
|
||||
end)
|
||||
|
||||
it('returns 2 when given a folder with rights to write into', function()
|
||||
itp('returns 2 when given a folder with rights to write into', function()
|
||||
eq(2, os_file_is_writable('unit-test-directory'))
|
||||
end)
|
||||
end)
|
||||
@@ -420,19 +414,19 @@ describe('fs function', function()
|
||||
end
|
||||
|
||||
describe('os_path_exists', function()
|
||||
it('returns false when given a non-existing file', function()
|
||||
itp('returns false when given a non-existing file', function()
|
||||
eq(false, (os_path_exists('non-existing-file')))
|
||||
end)
|
||||
|
||||
it('returns true when given an existing file', function()
|
||||
itp('returns true when given an existing file', function()
|
||||
eq(true, (os_path_exists('unit-test-directory/test.file')))
|
||||
end)
|
||||
|
||||
it('returns false when given a broken symlink', function()
|
||||
itp('returns false when given a broken symlink', function()
|
||||
eq(false, (os_path_exists('unit-test-directory/test_broken_link.file')))
|
||||
end)
|
||||
|
||||
it('returns true when given a directory', function()
|
||||
itp('returns true when given a directory', function()
|
||||
eq(true, (os_path_exists('unit-test-directory')))
|
||||
end)
|
||||
end)
|
||||
@@ -441,18 +435,18 @@ describe('fs function', function()
|
||||
local test = 'unit-test-directory/test.file'
|
||||
local not_exist = 'unit-test-directory/not_exist.file'
|
||||
|
||||
it('can rename file if destination file does not exist', function()
|
||||
itp('can rename file if destination file does not exist', function()
|
||||
eq(OK, (os_rename(test, not_exist)))
|
||||
eq(false, (os_path_exists(test)))
|
||||
eq(true, (os_path_exists(not_exist)))
|
||||
eq(OK, (os_rename(not_exist, test))) -- restore test file
|
||||
end)
|
||||
|
||||
it('fail if source file does not exist', function()
|
||||
itp('fail if source file does not exist', function()
|
||||
eq(FAIL, (os_rename(not_exist, test)))
|
||||
end)
|
||||
|
||||
it('can overwrite destination file if it exists', function()
|
||||
itp('can overwrite destination file if it exists', function()
|
||||
local other = 'unit-test-directory/other.file'
|
||||
local file = io.open(other, 'w')
|
||||
file:write('other')
|
||||
@@ -477,11 +471,11 @@ describe('fs function', function()
|
||||
os.remove('unit-test-directory/test_remove.file')
|
||||
end)
|
||||
|
||||
it('returns non-zero when given a non-existing file', function()
|
||||
itp('returns non-zero when given a non-existing file', function()
|
||||
neq(0, (os_remove('non-existing-file')))
|
||||
end)
|
||||
|
||||
it('removes the given file and returns 0', function()
|
||||
itp('removes the given file and returns 0', function()
|
||||
local f = 'unit-test-directory/test_remove.file'
|
||||
assert_file_exists(f)
|
||||
eq(0, (os_remove(f)))
|
||||
@@ -502,30 +496,30 @@ describe('fs function', function()
|
||||
os.remove(new_file)
|
||||
end)
|
||||
|
||||
it('returns UV_ENOENT for O_RDWR on a non-existing file', function()
|
||||
itp('returns UV_ENOENT for O_RDWR on a non-existing file', function()
|
||||
eq(ffi.C.UV_ENOENT, (os_open('non-existing-file', ffi.C.kO_RDWR, 0)))
|
||||
end)
|
||||
|
||||
it('returns non-negative for O_CREAT on a non-existing file which then can be closed', function()
|
||||
itp('returns non-negative for O_CREAT on a non-existing file which then can be closed', function()
|
||||
assert_file_does_not_exist(new_file)
|
||||
local fd = os_open(new_file, ffi.C.kO_CREAT, 0)
|
||||
assert.is_true(0 <= fd)
|
||||
eq(0, os_close(fd))
|
||||
end)
|
||||
|
||||
it('returns non-negative for O_CREAT on a existing file which then can be closed', function()
|
||||
itp('returns non-negative for O_CREAT on a existing file which then can be closed', function()
|
||||
assert_file_exists(existing_file)
|
||||
local fd = os_open(existing_file, ffi.C.kO_CREAT, 0)
|
||||
assert.is_true(0 <= fd)
|
||||
eq(0, os_close(fd))
|
||||
end)
|
||||
|
||||
it('returns UV_EEXIST for O_CREAT|O_EXCL on a existing file', function()
|
||||
itp('returns UV_EEXIST for O_CREAT|O_EXCL on a existing file', function()
|
||||
assert_file_exists(existing_file)
|
||||
eq(ffi.C.kUV_EEXIST, (os_open(existing_file, (bit.bor(ffi.C.kO_CREAT, ffi.C.kO_EXCL)), 0)))
|
||||
end)
|
||||
|
||||
it('sets `rwx` permissions for O_CREAT 700 which then can be closed', function()
|
||||
itp('sets `rwx` permissions for O_CREAT 700 which then can be closed', function()
|
||||
assert_file_does_not_exist(new_file)
|
||||
--create the file
|
||||
local fd = os_open(new_file, ffi.C.kO_CREAT, tonumber("700", 8))
|
||||
@@ -534,7 +528,7 @@ describe('fs function', function()
|
||||
eq(0, os_close(fd))
|
||||
end)
|
||||
|
||||
it('sets `rw` permissions for O_CREAT 600 which then can be closed', function()
|
||||
itp('sets `rw` permissions for O_CREAT 600 which then can be closed', function()
|
||||
assert_file_does_not_exist(new_file)
|
||||
--create the file
|
||||
local fd = os_open(new_file, ffi.C.kO_CREAT, tonumber("600", 8))
|
||||
@@ -543,7 +537,7 @@ describe('fs function', function()
|
||||
eq(0, os_close(fd))
|
||||
end)
|
||||
|
||||
it('returns a non-negative file descriptor for an existing file which then can be closed', function()
|
||||
itp('returns a non-negative file descriptor for an existing file which then can be closed', function()
|
||||
local fd = os_open(existing_file, ffi.C.kO_RDWR, 0)
|
||||
assert.is_true(0 <= fd)
|
||||
eq(0, os_close(fd))
|
||||
@@ -551,7 +545,7 @@ describe('fs function', function()
|
||||
end)
|
||||
|
||||
describe('os_close', function()
|
||||
it('returns EBADF for negative file descriptors', function()
|
||||
itp('returns EBADF for negative file descriptors', function()
|
||||
eq(ffi.C.UV_EBADF, os_close(-1))
|
||||
eq(ffi.C.UV_EBADF, os_close(-1000))
|
||||
end)
|
||||
@@ -570,7 +564,7 @@ describe('fs function', function()
|
||||
os.remove(file)
|
||||
end)
|
||||
|
||||
it('can read zero bytes from a file', function()
|
||||
itp('can read zero bytes from a file', function()
|
||||
local fd = os_open(file, ffi.C.kO_RDONLY, 0)
|
||||
ok(fd >= 0)
|
||||
eq({false, 0, ''}, {os_read(fd, nil)})
|
||||
@@ -578,7 +572,7 @@ describe('fs function', function()
|
||||
eq(0, os_close(fd))
|
||||
end)
|
||||
|
||||
it('can read from a file multiple times', function()
|
||||
itp('can read from a file multiple times', function()
|
||||
local fd = os_open(file, ffi.C.kO_RDONLY, 0)
|
||||
ok(fd >= 0)
|
||||
eq({false, 2, '\000\001'}, {os_read(fd, 2)})
|
||||
@@ -586,7 +580,7 @@ describe('fs function', function()
|
||||
eq(0, os_close(fd))
|
||||
end)
|
||||
|
||||
it('can read the whole file at once and then report eof', function()
|
||||
itp('can read the whole file at once and then report eof', function()
|
||||
local fd = os_open(file, ffi.C.kO_RDONLY, 0)
|
||||
ok(fd >= 0)
|
||||
eq({false, #fcontents, fcontents}, {os_read(fd, #fcontents)})
|
||||
@@ -594,7 +588,7 @@ describe('fs function', function()
|
||||
eq(0, os_close(fd))
|
||||
end)
|
||||
|
||||
it('can read the whole file in two calls, one partially', function()
|
||||
itp('can read the whole file in two calls, one partially', function()
|
||||
local fd = os_open(file, ffi.C.kO_RDONLY, 0)
|
||||
ok(fd >= 0)
|
||||
eq({false, #fcontents * 3/4, fcontents:sub(1, #fcontents * 3/4)},
|
||||
@@ -624,7 +618,7 @@ describe('fs function', function()
|
||||
os.remove(file)
|
||||
end)
|
||||
|
||||
it('can read zero bytes from a file', function()
|
||||
itp('can read zero bytes from a file', function()
|
||||
local fd = os_open(file, ffi.C.kO_RDONLY, 0)
|
||||
ok(fd >= 0)
|
||||
eq({false, 0, {}}, {os_readv(fd, {})})
|
||||
@@ -632,7 +626,7 @@ describe('fs function', function()
|
||||
eq(0, os_close(fd))
|
||||
end)
|
||||
|
||||
it('can read from a file multiple times to a differently-sized buffers', function()
|
||||
itp('can read from a file multiple times to a differently-sized buffers', function()
|
||||
local fd = os_open(file, ffi.C.kO_RDONLY, 0)
|
||||
ok(fd >= 0)
|
||||
eq({false, 2, {'\000\001'}}, {os_readv(fd, {2})})
|
||||
@@ -640,7 +634,7 @@ describe('fs function', function()
|
||||
eq(0, os_close(fd))
|
||||
end)
|
||||
|
||||
it('can read the whole file at once and then report eof', function()
|
||||
itp('can read the whole file at once and then report eof', function()
|
||||
local fd = os_open(file, ffi.C.kO_RDONLY, 0)
|
||||
ok(fd >= 0)
|
||||
eq({false,
|
||||
@@ -657,7 +651,7 @@ describe('fs function', function()
|
||||
eq(0, os_close(fd))
|
||||
end)
|
||||
|
||||
it('can read the whole file in two calls, one partially', function()
|
||||
itp('can read the whole file in two calls, one partially', function()
|
||||
local fd = os_open(file, ffi.C.kO_RDONLY, 0)
|
||||
ok(fd >= 0)
|
||||
eq({false, #fcontents * 3/4, {fcontents:sub(1, #fcontents * 3/4)}},
|
||||
@@ -684,7 +678,7 @@ describe('fs function', function()
|
||||
os.remove(file)
|
||||
end)
|
||||
|
||||
it('can write zero bytes to a file', function()
|
||||
itp('can write zero bytes to a file', function()
|
||||
local fd = os_open(file, ffi.C.kO_WRONLY, 0)
|
||||
ok(fd >= 0)
|
||||
eq(0, os_write(fd, ''))
|
||||
@@ -693,7 +687,7 @@ describe('fs function', function()
|
||||
eq(0, os_close(fd))
|
||||
end)
|
||||
|
||||
it('can write some data to a file', function()
|
||||
itp('can write some data to a file', function()
|
||||
local fd = os_open(file, ffi.C.kO_WRONLY, 0)
|
||||
ok(fd >= 0)
|
||||
eq(3, os_write(fd, 'abc'))
|
||||
@@ -708,11 +702,11 @@ describe('fs function', function()
|
||||
os.remove('non-existing-file')
|
||||
end)
|
||||
|
||||
it('returns NODE_NORMAL for non-existing file', function()
|
||||
itp('returns NODE_NORMAL for non-existing file', function()
|
||||
eq(NODE_NORMAL, fs.os_nodetype(to_cstr('non-existing-file')))
|
||||
end)
|
||||
|
||||
it('returns NODE_WRITABLE for /dev/stderr', function()
|
||||
itp('returns NODE_WRITABLE for /dev/stderr', function()
|
||||
eq(NODE_WRITABLE, fs.os_nodetype(to_cstr('/dev/stderr')))
|
||||
end)
|
||||
end)
|
||||
@@ -738,12 +732,12 @@ describe('fs function', function()
|
||||
end
|
||||
|
||||
describe('os_mkdir', function()
|
||||
it('returns non-zero when given an already existing directory', function()
|
||||
itp('returns non-zero when given an already existing directory', function()
|
||||
local mode = ffi.C.kS_IRUSR + ffi.C.kS_IWUSR + ffi.C.kS_IXUSR
|
||||
neq(0, (os_mkdir('unit-test-directory', mode)))
|
||||
end)
|
||||
|
||||
it('creates a directory and returns 0', function()
|
||||
itp('creates a directory and returns 0', function()
|
||||
local mode = ffi.C.kS_IRUSR + ffi.C.kS_IWUSR + ffi.C.kS_IXUSR
|
||||
eq(false, (os_isdir('unit-test-directory/new-dir')))
|
||||
eq(0, (os_mkdir('unit-test-directory/new-dir', mode)))
|
||||
@@ -753,14 +747,14 @@ describe('fs function', function()
|
||||
end)
|
||||
|
||||
describe('os_mkdir_recurse', function()
|
||||
it('returns zero when given an already existing directory', 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)
|
||||
eq(0, ret)
|
||||
eq(nil, failed_str)
|
||||
end)
|
||||
|
||||
it('fails to create a directory where there is a file', function()
|
||||
itp('fails to create a directory where there is a file', function()
|
||||
local mode = ffi.C.kS_IRUSR + ffi.C.kS_IWUSR + ffi.C.kS_IXUSR
|
||||
local ret, failed_str = os_mkdir_recurse(
|
||||
'unit-test-directory/test.file', mode)
|
||||
@@ -768,7 +762,7 @@ describe('fs function', function()
|
||||
eq('unit-test-directory/test.file', failed_str)
|
||||
end)
|
||||
|
||||
it('fails to create a directory where there is a file in path', function()
|
||||
itp('fails to create a directory where there is a file in path', function()
|
||||
local mode = ffi.C.kS_IRUSR + ffi.C.kS_IWUSR + ffi.C.kS_IXUSR
|
||||
local ret, failed_str = os_mkdir_recurse(
|
||||
'unit-test-directory/test.file/test', mode)
|
||||
@@ -776,7 +770,7 @@ describe('fs function', function()
|
||||
eq('unit-test-directory/test.file', failed_str)
|
||||
end)
|
||||
|
||||
it('succeeds to create a directory', function()
|
||||
itp('succeeds to create a directory', function()
|
||||
local mode = ffi.C.kS_IRUSR + ffi.C.kS_IWUSR + ffi.C.kS_IXUSR
|
||||
local ret, failed_str = os_mkdir_recurse(
|
||||
'unit-test-directory/new-dir-recurse', mode)
|
||||
@@ -787,7 +781,7 @@ describe('fs function', function()
|
||||
eq(false, os_isdir('unit-test-directory/new-dir-recurse'))
|
||||
end)
|
||||
|
||||
it('succeeds to create a directory ending with ///', function()
|
||||
itp('succeeds to create a directory ending with ///', function()
|
||||
local mode = ffi.C.kS_IRUSR + ffi.C.kS_IWUSR + ffi.C.kS_IXUSR
|
||||
local ret, failed_str = os_mkdir_recurse(
|
||||
'unit-test-directory/new-dir-recurse///', mode)
|
||||
@@ -798,7 +792,7 @@ describe('fs function', function()
|
||||
eq(false, os_isdir('unit-test-directory/new-dir-recurse'))
|
||||
end)
|
||||
|
||||
it('succeeds to create a directory ending with /', function()
|
||||
itp('succeeds to create a directory ending with /', function()
|
||||
local mode = ffi.C.kS_IRUSR + ffi.C.kS_IWUSR + ffi.C.kS_IXUSR
|
||||
local ret, failed_str = os_mkdir_recurse(
|
||||
'unit-test-directory/new-dir-recurse/', mode)
|
||||
@@ -809,7 +803,7 @@ describe('fs function', function()
|
||||
eq(false, os_isdir('unit-test-directory/new-dir-recurse'))
|
||||
end)
|
||||
|
||||
it('succeeds to create a directory tree', function()
|
||||
itp('succeeds to create a directory tree', function()
|
||||
local mode = ffi.C.kS_IRUSR + ffi.C.kS_IWUSR + ffi.C.kS_IXUSR
|
||||
local ret, failed_str = os_mkdir_recurse(
|
||||
'unit-test-directory/new-dir-recurse/1/2/3', mode)
|
||||
@@ -828,11 +822,11 @@ describe('fs function', function()
|
||||
end)
|
||||
|
||||
describe('os_rmdir', function()
|
||||
it('returns non_zero when given a non-existing directory', function()
|
||||
itp('returns non_zero when given a non-existing directory', function()
|
||||
neq(0, (os_rmdir('non-existing-directory')))
|
||||
end)
|
||||
|
||||
it('removes the given directory and returns 0', function()
|
||||
itp('removes the given directory and returns 0', function()
|
||||
lfs.mkdir('unit-test-directory/new-dir')
|
||||
eq(0, os_rmdir('unit-test-directory/new-dir'))
|
||||
eq(false, (os_isdir('unit-test-directory/new-dir')))
|
||||
@@ -860,19 +854,19 @@ describe('fs function', function()
|
||||
end
|
||||
|
||||
describe('os_fileinfo', function()
|
||||
it('returns false if given a non-existing file', function()
|
||||
itp('returns false if given a non-existing file', function()
|
||||
local file_info = file_info_new()
|
||||
assert.is_false((fs.os_fileinfo('/non-existent', file_info)))
|
||||
end)
|
||||
|
||||
it('returns true if given an existing file and fills file_info', function()
|
||||
itp('returns true if given an existing file and fills file_info', function()
|
||||
local file_info = file_info_new()
|
||||
local path = 'unit-test-directory/test.file'
|
||||
assert.is_true((fs.os_fileinfo(path, file_info)))
|
||||
assert.is_true((is_file_info_filled(file_info)))
|
||||
end)
|
||||
|
||||
it('returns the file info of the linked file, not the link', function()
|
||||
itp('returns the file info of the linked file, not the link', function()
|
||||
local file_info = file_info_new()
|
||||
local path = 'unit-test-directory/test_link.file'
|
||||
assert.is_true((fs.os_fileinfo(path, file_info)))
|
||||
@@ -883,19 +877,19 @@ describe('fs function', function()
|
||||
end)
|
||||
|
||||
describe('os_fileinfo_link', function()
|
||||
it('returns false if given a non-existing file', function()
|
||||
itp('returns false if given a non-existing file', function()
|
||||
local file_info = file_info_new()
|
||||
assert.is_false((fs.os_fileinfo_link('/non-existent', file_info)))
|
||||
end)
|
||||
|
||||
it('returns true if given an existing file and fills file_info', function()
|
||||
itp('returns true if given an existing file and fills file_info', function()
|
||||
local file_info = file_info_new()
|
||||
local path = 'unit-test-directory/test.file'
|
||||
assert.is_true((fs.os_fileinfo_link(path, file_info)))
|
||||
assert.is_true((is_file_info_filled(file_info)))
|
||||
end)
|
||||
|
||||
it('returns the file info of the link, not the linked file', function()
|
||||
itp('returns the file info of the link, not the linked file', function()
|
||||
local file_info = file_info_new()
|
||||
local path = 'unit-test-directory/test_link.file'
|
||||
assert.is_true((fs.os_fileinfo_link(path, file_info)))
|
||||
@@ -906,12 +900,12 @@ describe('fs function', function()
|
||||
end)
|
||||
|
||||
describe('os_fileinfo_fd', function()
|
||||
it('returns false if given an invalid file descriptor', function()
|
||||
itp('returns false if given an invalid file descriptor', function()
|
||||
local file_info = file_info_new()
|
||||
assert.is_false((fs.os_fileinfo_fd(-1, file_info)))
|
||||
end)
|
||||
|
||||
it('returns true if given a file descriptor and fills file_info', function()
|
||||
itp('returns true if given a file descriptor and fills file_info', function()
|
||||
local file_info = file_info_new()
|
||||
local path = 'unit-test-directory/test.file'
|
||||
local fd = ffi.C.open(path, 0)
|
||||
@@ -922,7 +916,7 @@ describe('fs function', function()
|
||||
end)
|
||||
|
||||
describe('os_fileinfo_id_equal', function()
|
||||
it('returns false if file infos represent different files', function()
|
||||
itp('returns false if file infos represent different files', function()
|
||||
local file_info_1 = file_info_new()
|
||||
local file_info_2 = file_info_new()
|
||||
local path_1 = 'unit-test-directory/test.file'
|
||||
@@ -932,7 +926,7 @@ describe('fs function', function()
|
||||
assert.is_false((fs.os_fileinfo_id_equal(file_info_1, file_info_2)))
|
||||
end)
|
||||
|
||||
it('returns true if file infos represent the same file', function()
|
||||
itp('returns true if file infos represent the same file', function()
|
||||
local file_info_1 = file_info_new()
|
||||
local file_info_2 = file_info_new()
|
||||
local path = 'unit-test-directory/test.file'
|
||||
@@ -941,7 +935,7 @@ describe('fs function', function()
|
||||
assert.is_true((fs.os_fileinfo_id_equal(file_info_1, file_info_2)))
|
||||
end)
|
||||
|
||||
it('returns true if file infos represent the same file (symlink)', function()
|
||||
itp('returns true if file infos represent the same file (symlink)', function()
|
||||
local file_info_1 = file_info_new()
|
||||
local file_info_2 = file_info_new()
|
||||
local path_1 = 'unit-test-directory/test.file'
|
||||
@@ -953,7 +947,7 @@ describe('fs function', function()
|
||||
end)
|
||||
|
||||
describe('os_fileinfo_id', function()
|
||||
it('extracts ino/dev from file_info into file_id', function()
|
||||
itp('extracts ino/dev from file_info into file_id', function()
|
||||
local file_info = file_info_new()
|
||||
local file_id = file_id_new()
|
||||
local path = 'unit-test-directory/test.file'
|
||||
@@ -965,7 +959,7 @@ describe('fs function', function()
|
||||
end)
|
||||
|
||||
describe('os_fileinfo_inode', function()
|
||||
it('returns the inode from file_info', function()
|
||||
itp('returns the inode from file_info', function()
|
||||
local file_info = file_info_new()
|
||||
local path = 'unit-test-directory/test.file'
|
||||
assert.is_true((fs.os_fileinfo(path, file_info)))
|
||||
@@ -975,7 +969,7 @@ describe('fs function', function()
|
||||
end)
|
||||
|
||||
describe('os_fileinfo_size', function()
|
||||
it('returns the correct size of a file', function()
|
||||
itp('returns the correct size of a file', function()
|
||||
local path = 'unit-test-directory/test.file'
|
||||
local file = io.open(path, 'w')
|
||||
file:write('some bytes to get filesize != 0')
|
||||
@@ -989,7 +983,7 @@ describe('fs function', function()
|
||||
end)
|
||||
|
||||
describe('os_fileinfo_hardlinks', function()
|
||||
it('returns the correct number of hardlinks', function()
|
||||
itp('returns the correct number of hardlinks', function()
|
||||
local path = 'unit-test-directory/test.file'
|
||||
local path_link = 'unit-test-directory/test_hlink.file'
|
||||
local file_info = file_info_new()
|
||||
@@ -1002,7 +996,7 @@ describe('fs function', function()
|
||||
end)
|
||||
|
||||
describe('os_fileinfo_blocksize', function()
|
||||
it('returns the correct blocksize of a file', 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 worng value:
|
||||
@@ -1023,12 +1017,12 @@ describe('fs function', function()
|
||||
end)
|
||||
|
||||
describe('os_fileid', function()
|
||||
it('returns false if given an non-existing file', function()
|
||||
itp('returns false if given an non-existing file', function()
|
||||
local file_id = file_id_new()
|
||||
assert.is_false((fs.os_fileid('/non-existent', file_id)))
|
||||
end)
|
||||
|
||||
it('returns true if given an existing file and fills file_id', function()
|
||||
itp('returns true if given an existing file and fills file_id', function()
|
||||
local file_id = file_id_new()
|
||||
local path = 'unit-test-directory/test.file'
|
||||
assert.is_true((fs.os_fileid(path, file_id)))
|
||||
@@ -1038,14 +1032,14 @@ describe('fs function', function()
|
||||
end)
|
||||
|
||||
describe('os_fileid_equal', function()
|
||||
it('returns true if two FileIDs are equal', function()
|
||||
itp('returns true if two FileIDs are equal', function()
|
||||
local file_id = file_id_new()
|
||||
local path = 'unit-test-directory/test.file'
|
||||
assert.is_true((fs.os_fileid(path, file_id)))
|
||||
assert.is_true((fs.os_fileid_equal(file_id, file_id)))
|
||||
end)
|
||||
|
||||
it('returns false if two FileIDs are not equal', function()
|
||||
itp('returns false if two FileIDs are not equal', function()
|
||||
local file_id_1 = file_id_new()
|
||||
local file_id_2 = file_id_new()
|
||||
local path_1 = 'unit-test-directory/test.file'
|
||||
@@ -1057,7 +1051,7 @@ describe('fs function', function()
|
||||
end)
|
||||
|
||||
describe('os_fileid_equal_fileinfo', function()
|
||||
it('returns true if file_id and file_info represent the same file', function()
|
||||
itp('returns true if file_id and file_info represent the same file', function()
|
||||
local file_id = file_id_new()
|
||||
local file_info = file_info_new()
|
||||
local path = 'unit-test-directory/test.file'
|
||||
@@ -1066,7 +1060,7 @@ describe('fs function', function()
|
||||
assert.is_true((fs.os_fileid_equal_fileinfo(file_id, file_info)))
|
||||
end)
|
||||
|
||||
it('returns false if file_id and file_info represent different files', function()
|
||||
itp('returns false if file_id and file_info represent different files', function()
|
||||
local file_id = file_id_new()
|
||||
local file_info = file_info_new()
|
||||
local path_1 = 'unit-test-directory/test.file'
|
||||
|
@@ -1,4 +1,5 @@
|
||||
local helpers = require('test.unit.helpers')
|
||||
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',
|
||||
@@ -51,63 +52,51 @@ describe('shell functions', function()
|
||||
end
|
||||
|
||||
describe('os_system', function()
|
||||
it('can echo some output (shell builtin)', function()
|
||||
itp('can echo some output (shell builtin)', function()
|
||||
local cmd, text = 'echo -n', 'some text'
|
||||
local status, output = os_system(cmd .. ' ' .. text)
|
||||
eq(text, output)
|
||||
eq(0, status)
|
||||
end)
|
||||
|
||||
it('can deal with empty output', function()
|
||||
itp('can deal with empty output', function()
|
||||
local cmd = 'echo -n'
|
||||
local status, output = os_system(cmd)
|
||||
eq('', output)
|
||||
eq(0, status)
|
||||
end)
|
||||
|
||||
it('can pass input on stdin', function()
|
||||
itp('can pass input on stdin', function()
|
||||
local cmd, input = 'cat -', 'some text\nsome other text'
|
||||
local status, output = os_system(cmd, input)
|
||||
eq(input, output)
|
||||
eq(0, status)
|
||||
end)
|
||||
|
||||
it ('returns non-zero exit code', function()
|
||||
itp('returns non-zero exit code', function()
|
||||
local status = os_system('exit 2')
|
||||
eq(2, status)
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('shell_build_argv', function()
|
||||
local saved_opts = {}
|
||||
|
||||
setup(function()
|
||||
saved_opts.p_sh = cimported.p_sh
|
||||
saved_opts.p_shcf = cimported.p_shcf
|
||||
end)
|
||||
|
||||
teardown(function()
|
||||
cimported.p_sh = saved_opts.p_sh
|
||||
cimported.p_shcf = saved_opts.p_shcf
|
||||
end)
|
||||
|
||||
it('works with NULL arguments', function()
|
||||
itp('works with NULL arguments', function()
|
||||
eq({'/bin/bash'}, shell_build_argv(nil, nil))
|
||||
end)
|
||||
|
||||
it('works with cmd', function()
|
||||
itp('works with cmd', function()
|
||||
eq({'/bin/bash', '-c', 'abc def'}, shell_build_argv('abc def', nil))
|
||||
end)
|
||||
|
||||
it('works with extra_args', function()
|
||||
itp('works with extra_args', function()
|
||||
eq({'/bin/bash', 'ghi jkl'}, shell_build_argv(nil, 'ghi jkl'))
|
||||
end)
|
||||
|
||||
it('works with cmd and extra_args', function()
|
||||
itp('works with cmd and extra_args', function()
|
||||
eq({'/bin/bash', 'ghi jkl', '-c', 'abc def'}, shell_build_argv('abc def', 'ghi jkl'))
|
||||
end)
|
||||
|
||||
it('splits and unquotes &shell and &shellcmdflag', function()
|
||||
itp('splits and unquotes &shell and &shellcmdflag', function()
|
||||
cimported.p_sh = to_cstr('/Program" "Files/zsh -f')
|
||||
cimported.p_shcf = to_cstr('-x -o "sh word split" "-"c')
|
||||
eq({'/Program Files/zsh', '-f',
|
||||
@@ -117,7 +106,7 @@ describe('shell functions', function()
|
||||
shell_build_argv('abc def', 'ghi jkl'))
|
||||
end)
|
||||
|
||||
it('applies shellxescape (p_sxe) and shellxquote (p_sxq)', function()
|
||||
itp('applies shellxescape (p_sxe) and shellxquote (p_sxq)', function()
|
||||
cimported.p_sxq = to_cstr('(')
|
||||
cimported.p_sxe = to_cstr('"&|<>()@^')
|
||||
|
||||
@@ -129,7 +118,7 @@ describe('shell functions', function()
|
||||
eq(nil, argv[3])
|
||||
end)
|
||||
|
||||
it('applies shellxquote="(', function()
|
||||
itp('applies shellxquote="(', function()
|
||||
cimported.p_sxq = to_cstr('"(')
|
||||
cimported.p_sxe = to_cstr('"&|<>()@^')
|
||||
|
||||
@@ -141,7 +130,7 @@ describe('shell functions', function()
|
||||
eq(nil, argv[3])
|
||||
end)
|
||||
|
||||
it('applies shellxquote="', function()
|
||||
itp('applies shellxquote="', function()
|
||||
cimported.p_sxq = to_cstr('"')
|
||||
cimported.p_sxe = to_cstr('')
|
||||
|
||||
@@ -153,7 +142,7 @@ describe('shell functions', function()
|
||||
eq(nil, argv[3])
|
||||
end)
|
||||
|
||||
it('with empty shellxquote/shellxescape', function()
|
||||
itp('with empty shellxquote/shellxescape', function()
|
||||
local argv = ffi.cast('char**', cimported.shell_build_argv(
|
||||
to_cstr('echo -n some text'), nil))
|
||||
eq(ffi.string(argv[0]), '/bin/bash')
|
||||
|
@@ -1,4 +1,5 @@
|
||||
local helpers = require('test.unit.helpers')
|
||||
local helpers = require('test.unit.helpers')(after_each)
|
||||
local itp = helpers.gen_itp(it)
|
||||
|
||||
local cimport = helpers.cimport
|
||||
local eq = helpers.eq
|
||||
@@ -27,11 +28,11 @@ describe('users function', function()
|
||||
local current_username = os.getenv('USER')
|
||||
|
||||
describe('os_get_usernames', function()
|
||||
it('returns FAIL if called with NULL', function()
|
||||
itp('returns FAIL if called with NULL', function()
|
||||
eq(FAIL, users.os_get_usernames(NULL))
|
||||
end)
|
||||
|
||||
it('fills the names garray with os usernames and returns OK', function()
|
||||
itp('fills the names garray with os usernames and returns OK', function()
|
||||
local ga_users = garray_new()
|
||||
eq(OK, users.os_get_usernames(ga_users))
|
||||
local user_count = garray_get_len(ga_users)
|
||||
@@ -48,7 +49,7 @@ describe('users function', function()
|
||||
end)
|
||||
|
||||
describe('os_get_user_name', function()
|
||||
it('should write the username into the buffer and return OK', function()
|
||||
itp('should write the username into the buffer and return OK', function()
|
||||
local name_out = ffi.new('char[100]')
|
||||
eq(OK, users.os_get_user_name(name_out, 100))
|
||||
eq(current_username, ffi.string(name_out))
|
||||
@@ -56,14 +57,14 @@ describe('users function', function()
|
||||
end)
|
||||
|
||||
describe('os_get_uname', function()
|
||||
it('should write the username into the buffer and return OK', function()
|
||||
itp('should write the username into the buffer and return OK', function()
|
||||
local name_out = ffi.new('char[100]')
|
||||
local user_id = lib.getuid()
|
||||
eq(OK, users.os_get_uname(user_id, name_out, 100))
|
||||
eq(current_username, ffi.string(name_out))
|
||||
end)
|
||||
|
||||
it('should FAIL if the userid is not found', function()
|
||||
itp('should FAIL if the userid is not found', function()
|
||||
local name_out = ffi.new('char[100]')
|
||||
-- hoping nobody has this uid
|
||||
local user_id = 2342
|
||||
@@ -73,16 +74,16 @@ describe('users function', function()
|
||||
end)
|
||||
|
||||
describe('os_get_user_directory', function()
|
||||
it('should return NULL if called with NULL', function()
|
||||
itp('should return NULL if called with NULL', function()
|
||||
eq(NULL, users.os_get_user_directory(NULL))
|
||||
end)
|
||||
|
||||
it('should return $HOME for the current user', function()
|
||||
itp('should return $HOME for the current user', function()
|
||||
local home = os.getenv('HOME')
|
||||
eq(home, ffi.string((users.os_get_user_directory(current_username))))
|
||||
end)
|
||||
|
||||
it('should return NULL if the user is not found', function()
|
||||
itp('should return NULL if the user is not found', function()
|
||||
eq(NULL, users.os_get_user_directory('neovim_user_not_found_test'))
|
||||
end)
|
||||
end)
|
||||
|
@@ -1,5 +1,6 @@
|
||||
local lfs = require('lfs')
|
||||
local helpers = require('test.unit.helpers')
|
||||
local helpers = require('test.unit.helpers')(after_each)
|
||||
local itp = helpers.gen_itp(it)
|
||||
|
||||
local cimport = helpers.cimport
|
||||
local eq = helpers.eq
|
||||
@@ -14,13 +15,6 @@ local FAIL = helpers.FAIL
|
||||
cimport('string.h')
|
||||
local path = cimport('./src/nvim/path.h')
|
||||
|
||||
-- import constants parsed by ffi
|
||||
local kEqualFiles = path.kEqualFiles
|
||||
local kDifferentFiles = path.kDifferentFiles
|
||||
local kBothFilesMissing = path.kBothFilesMissing
|
||||
local kOneFileMissing = path.kOneFileMissing
|
||||
local kEqualFileNames = path.kEqualFileNames
|
||||
|
||||
local length = 0
|
||||
local buffer = nil
|
||||
|
||||
@@ -45,7 +39,7 @@ describe('path function', function()
|
||||
buffer = cstr(length, '')
|
||||
end)
|
||||
|
||||
it('returns the absolute directory name of a given relative one', function()
|
||||
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()
|
||||
@@ -55,16 +49,16 @@ describe('path function', function()
|
||||
eq(expected, (ffi.string(buffer)))
|
||||
end)
|
||||
|
||||
it('returns the current directory name if the given string is empty', function()
|
||||
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)))
|
||||
end)
|
||||
|
||||
it('fails if the given directory does not exist', function()
|
||||
itp('fails if the given directory does not exist', function()
|
||||
eq(FAIL, path_full_dir_name('does_not_exist', buffer, length))
|
||||
end)
|
||||
|
||||
it('works with a normal relative dir', function()
|
||||
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(OK, result)
|
||||
@@ -91,26 +85,26 @@ describe('path function', function()
|
||||
os.remove(f2)
|
||||
end)
|
||||
|
||||
it('returns kEqualFiles when passed the same file', function()
|
||||
eq(kEqualFiles, (path_full_compare(f1, f1)))
|
||||
itp('returns kEqualFiles when passed the same file', function()
|
||||
eq(path.kEqualFiles, (path_full_compare(f1, f1)))
|
||||
end)
|
||||
|
||||
it('returns kEqualFileNames when files that dont exist and have same name', function()
|
||||
eq(kEqualFileNames, (path_full_compare('null.txt', 'null.txt', true)))
|
||||
itp('returns kEqualFileNames when files that dont exist and have same name', function()
|
||||
eq(path.kEqualFileNames, (path_full_compare('null.txt', 'null.txt', true)))
|
||||
end)
|
||||
|
||||
it('returns kBothFilesMissing when files that dont exist', function()
|
||||
eq(kBothFilesMissing, (path_full_compare('null.txt', 'null.txt')))
|
||||
itp('returns kBothFilesMissing when files that dont exist', function()
|
||||
eq(path.kBothFilesMissing, (path_full_compare('null.txt', 'null.txt')))
|
||||
end)
|
||||
|
||||
it('returns kDifferentFiles when passed different files', function()
|
||||
eq(kDifferentFiles, (path_full_compare(f1, f2)))
|
||||
eq(kDifferentFiles, (path_full_compare(f2, f1)))
|
||||
itp('returns kDifferentFiles when passed different files', function()
|
||||
eq(path.kDifferentFiles, (path_full_compare(f1, f2)))
|
||||
eq(path.kDifferentFiles, (path_full_compare(f2, f1)))
|
||||
end)
|
||||
|
||||
it('returns kOneFileMissing if only one does not exist', function()
|
||||
eq(kOneFileMissing, (path_full_compare(f1, 'null.txt')))
|
||||
eq(kOneFileMissing, (path_full_compare('null.txt', f1)))
|
||||
itp('returns kOneFileMissing if only one does not exist', function()
|
||||
eq(path.kOneFileMissing, (path_full_compare(f1, 'null.txt')))
|
||||
eq(path.kOneFileMissing, (path_full_compare('null.txt', f1)))
|
||||
end)
|
||||
end)
|
||||
|
||||
@@ -121,11 +115,11 @@ describe('path function', function()
|
||||
return ffi.string(res)
|
||||
end
|
||||
|
||||
it('returns the tail of a given file path', function()
|
||||
itp('returns the tail of a given file path', function()
|
||||
eq('file.txt', path_tail('directory/file.txt'))
|
||||
end)
|
||||
|
||||
it('returns an empty string if file ends in a slash', function()
|
||||
itp('returns an empty string if file ends in a slash', function()
|
||||
eq('', path_tail('directory/'))
|
||||
end)
|
||||
end)
|
||||
@@ -137,24 +131,24 @@ describe('path function', function()
|
||||
return ffi.string(res)
|
||||
end
|
||||
|
||||
it('returns the tail of a file together with its separator', function()
|
||||
itp('returns the tail of a file together with its separator', function()
|
||||
eq('///file.txt', path_tail_with_sep('directory///file.txt'))
|
||||
end)
|
||||
|
||||
it('returns an empty string when given an empty file name', function()
|
||||
itp('returns an empty string when given an empty file name', function()
|
||||
eq('', path_tail_with_sep(''))
|
||||
end)
|
||||
|
||||
it('returns only the separator if there is a trailing separator', function()
|
||||
itp('returns only the separator if there is a trailing separator', function()
|
||||
eq('/', path_tail_with_sep('some/directory/'))
|
||||
end)
|
||||
|
||||
it('cuts a leading separator', function()
|
||||
itp('cuts a leading separator', function()
|
||||
eq('file.txt', path_tail_with_sep('/file.txt'))
|
||||
eq('', path_tail_with_sep('/'))
|
||||
end)
|
||||
|
||||
it('returns the whole file name if there is no separator', function()
|
||||
itp('returns the whole file name if there is no separator', function()
|
||||
eq('file.txt', path_tail_with_sep('file.txt'))
|
||||
end)
|
||||
end)
|
||||
@@ -180,13 +174,13 @@ describe('path function', function()
|
||||
return eq(0, (ffi.C.strncmp((to_cstr(base)), pinvk, len)))
|
||||
end
|
||||
|
||||
it('returns the executable name of an invocation given a relative invocation', function()
|
||||
itp('returns the executable name of an invocation given a relative invocation', function()
|
||||
local invk, len = invocation_path_tail('directory/exe a b c')
|
||||
compare("exe a b c", invk, len)
|
||||
eq(3, len)
|
||||
end)
|
||||
|
||||
it('returns the executable name of an invocation given an absolute invocation', function()
|
||||
itp('returns the executable name of an invocation given an absolute invocation', function()
|
||||
if ffi.os == 'Windows' then
|
||||
local invk, len = invocation_path_tail('C:\\Users\\anyone\\Program Files\\z a b')
|
||||
compare('z a b', invk, len)
|
||||
@@ -198,18 +192,18 @@ describe('path function', function()
|
||||
end
|
||||
end)
|
||||
|
||||
it('does not count arguments to the executable as part of its path', function()
|
||||
itp('does not count arguments to the executable as part of its path', function()
|
||||
local invk, len = invocation_path_tail('exe a/b\\c')
|
||||
compare("exe a/b\\c", invk, len)
|
||||
eq(3, len)
|
||||
end)
|
||||
|
||||
it('only accepts whitespace as a terminator for the executable name', function()
|
||||
itp('only accepts whitespace as a terminator for the executable name', function()
|
||||
local invk, _ = invocation_path_tail('exe-a+b_c[]()|#!@$%^&*')
|
||||
eq('exe-a+b_c[]()|#!@$%^&*', (ffi.string(invk)))
|
||||
end)
|
||||
|
||||
it('is equivalent to path_tail when args do not contain a path separator', function()
|
||||
itp('is equivalent to path_tail when args do not contain a path separator', function()
|
||||
local ptail = path.path_tail(to_cstr("a/b/c x y z"))
|
||||
neq(NULL, ptail)
|
||||
local tail = ffi.string(ptail)
|
||||
@@ -217,7 +211,7 @@ describe('path function', function()
|
||||
eq(tail, ffi.string(invk))
|
||||
end)
|
||||
|
||||
it('is not equivalent to path_tail when args contain a path separator', function()
|
||||
itp('is not equivalent to path_tail when args contain a path separator', function()
|
||||
local ptail = path.path_tail(to_cstr("a/b/c x y/z"))
|
||||
neq(NULL, ptail)
|
||||
local invk, _ = invocation_path_tail("a/b/c x y/z")
|
||||
@@ -232,34 +226,34 @@ describe('path function', function()
|
||||
return ffi.string(res)
|
||||
end
|
||||
|
||||
it('returns', function()
|
||||
itp('returns', function()
|
||||
eq('directory/file.txt', path_next_component('some/directory/file.txt'))
|
||||
end)
|
||||
|
||||
it('returns empty string if given file contains no separator', function()
|
||||
itp('returns empty string if given file contains no separator', function()
|
||||
eq('', path_next_component('file.txt'))
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('path_shorten_fname', function()
|
||||
it('returns NULL if `full_path` is NULL', function()
|
||||
itp('returns NULL if `full_path` is NULL', function()
|
||||
local dir = to_cstr('some/directory/file.txt')
|
||||
eq(NULL, (path.path_shorten_fname(NULL, dir)))
|
||||
end)
|
||||
|
||||
it('returns NULL if the path and dir does not match', function()
|
||||
itp('returns NULL if the path and dir does not match', function()
|
||||
local dir = to_cstr('not/the/same')
|
||||
local full = to_cstr('as/this.txt')
|
||||
eq(NULL, (path.path_shorten_fname(full, dir)))
|
||||
end)
|
||||
|
||||
it('returns NULL if the path is not separated properly', function()
|
||||
itp('returns NULL if the path is not separated properly', function()
|
||||
local dir = to_cstr('some/very/long/')
|
||||
local full = to_cstr('some/very/long/directory/file.txt')
|
||||
eq(NULL, (path.path_shorten_fname(full, dir)))
|
||||
end)
|
||||
|
||||
it('shortens the filename if `dir_name` is the start of `full_path`', function()
|
||||
itp('shortens the filename if `dir_name` is the start of `full_path`', function()
|
||||
local full = to_cstr('some/very/long/directory/file.txt')
|
||||
local dir = to_cstr('some/very/long')
|
||||
eq('directory/file.txt', (ffi.string(path.path_shorten_fname(full, dir))))
|
||||
@@ -280,20 +274,20 @@ describe('path_shorten_fname_if_possible', function()
|
||||
end)
|
||||
|
||||
describe('path_shorten_fname_if_possible', function()
|
||||
it('returns shortened path if possible', function()
|
||||
itp('returns shortened path if possible', function()
|
||||
lfs.chdir('ut_directory')
|
||||
local full = to_cstr(lfs.currentdir() .. '/subdir/file.txt')
|
||||
eq('subdir/file.txt', (ffi.string(path.path_shorten_fname_if_possible(full))))
|
||||
end)
|
||||
|
||||
it('returns `full_path` if a shorter version is not possible', function()
|
||||
itp('returns `full_path` if a shorter version is not possible', function()
|
||||
local old = lfs.currentdir()
|
||||
lfs.chdir('ut_directory')
|
||||
local full = old .. '/subdir/file.txt'
|
||||
eq(full, (ffi.string(path.path_shorten_fname_if_possible(to_cstr(full)))))
|
||||
end)
|
||||
|
||||
it('returns NULL if `full_path` is NULL', function()
|
||||
itp('returns NULL if `full_path` is NULL', function()
|
||||
eq(NULL, (path.path_shorten_fname_if_possible(NULL)))
|
||||
end)
|
||||
end)
|
||||
@@ -330,13 +324,13 @@ describe('more path function', function()
|
||||
buffer = cstr(length, '')
|
||||
end)
|
||||
|
||||
it('fails if given filename is NULL', function()
|
||||
itp('fails if given filename is NULL', function()
|
||||
local force_expansion = 1
|
||||
local result = path.vim_FullName(NULL, buffer, length, force_expansion)
|
||||
eq(FAIL, result)
|
||||
end)
|
||||
|
||||
it('fails safely if given length is wrong #5737', function()
|
||||
itp('fails safely if given length is wrong #5737', function()
|
||||
local force_expansion = 1
|
||||
local filename = 'foo/bar/bazzzzzzz/buz/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/a'
|
||||
local too_short_len = 8
|
||||
@@ -347,7 +341,7 @@ describe('more path function', function()
|
||||
eq(FAIL, result)
|
||||
end)
|
||||
|
||||
it('uses the filename if the filename is a URL', function()
|
||||
itp('uses the filename if the filename is a URL', function()
|
||||
local force_expansion = 1
|
||||
local filename = 'http://www.neovim.org'
|
||||
local result = vim_FullName(filename, buffer, length, force_expansion)
|
||||
@@ -355,7 +349,7 @@ describe('more path function', function()
|
||||
eq(OK, result)
|
||||
end)
|
||||
|
||||
it('fails and uses filename if given filename contains non-existing directory', function()
|
||||
itp('fails and uses filename if given filename contains non-existing directory', function()
|
||||
local force_expansion = 1
|
||||
local filename = 'non_existing_dir/test.file'
|
||||
local result = vim_FullName(filename, buffer, length, force_expansion)
|
||||
@@ -363,7 +357,7 @@ describe('more path function', function()
|
||||
eq(FAIL, result)
|
||||
end)
|
||||
|
||||
it('concatenates given filename if it does not contain a slash', function()
|
||||
itp('concatenates given filename if it does not contain a slash', function()
|
||||
local force_expansion = 1
|
||||
local result = vim_FullName('test.file', buffer, length, force_expansion)
|
||||
local expected = lfs.currentdir() .. '/test.file'
|
||||
@@ -371,7 +365,7 @@ describe('more path function', function()
|
||||
eq(OK, result)
|
||||
end)
|
||||
|
||||
it('concatenates given filename if it is a directory but does not contain a\n slash', function()
|
||||
itp('concatenates given filename if it is a directory but does not contain a\n slash', function()
|
||||
local force_expansion = 1
|
||||
local result = vim_FullName('..', buffer, length, force_expansion)
|
||||
local expected = lfs.currentdir() .. '/..'
|
||||
@@ -381,7 +375,7 @@ describe('more path function', function()
|
||||
|
||||
-- Is it possible for every developer to enter '..' directory while running
|
||||
-- the unit tests? Which other directory would be better?
|
||||
it('enters given directory (instead of just concatenating the strings) if possible and if path contains a slash', function()
|
||||
itp('enters given directory (instead of just concatenating the strings) if possible and if path contains a slash', function()
|
||||
local force_expansion = 1
|
||||
local result = vim_FullName('../test.file', buffer, length, force_expansion)
|
||||
local old_dir = lfs.currentdir()
|
||||
@@ -392,7 +386,7 @@ describe('more path function', function()
|
||||
eq(OK, result)
|
||||
end)
|
||||
|
||||
it('just copies the path if it is already absolute and force=0', function()
|
||||
itp('just copies the path if it is already absolute and force=0', function()
|
||||
local force_expansion = 0
|
||||
local absolute_path = '/absolute/path'
|
||||
local result = vim_FullName(absolute_path, buffer, length, force_expansion)
|
||||
@@ -400,7 +394,7 @@ describe('more path function', function()
|
||||
eq(OK, result)
|
||||
end)
|
||||
|
||||
it('fails and uses filename when the path is relative to HOME', function()
|
||||
itp('fails and uses filename when the path is relative to HOME', function()
|
||||
local force_expansion = 1
|
||||
local absolute_path = '~/home.file'
|
||||
local result = vim_FullName(absolute_path, buffer, length, force_expansion)
|
||||
@@ -408,14 +402,14 @@ describe('more path function', function()
|
||||
eq(FAIL, result)
|
||||
end)
|
||||
|
||||
it('works with some "normal" relative path with directories', function()
|
||||
itp('works with some "normal" relative path with directories', function()
|
||||
local force_expansion = 1
|
||||
local result = vim_FullName('unit-test-directory/test.file', buffer, length, force_expansion)
|
||||
eq(OK, result)
|
||||
eq(lfs.currentdir() .. '/unit-test-directory/test.file', (ffi.string(buffer)))
|
||||
end)
|
||||
|
||||
it('does not modify the given filename', function()
|
||||
itp('does not modify the given filename', function()
|
||||
local force_expansion = 1
|
||||
local filename = to_cstr('unit-test-directory/test.file')
|
||||
-- Don't use the wrapper here but pass a cstring directly to the c
|
||||
@@ -426,7 +420,7 @@ describe('more path function', function()
|
||||
eq(OK, result)
|
||||
end)
|
||||
|
||||
it('works with directories that have one path component', function()
|
||||
itp('works with directories that have one path component', function()
|
||||
local force_expansion = 1
|
||||
local filename = to_cstr('/tmp')
|
||||
local result = path.vim_FullName(filename, buffer, length, force_expansion)
|
||||
@@ -446,12 +440,12 @@ describe('more path function', function()
|
||||
after_each(function() lfs.rmdir('CamelCase') end)
|
||||
|
||||
if ffi.os == 'Windows' or ffi.os == 'OSX' then
|
||||
it('Corrects the case of file names in Mac and Windows', function()
|
||||
itp('Corrects the case of file names in Mac and Windows', function()
|
||||
eq('CamelCase', fix_case('camelcase'))
|
||||
eq('CamelCase', fix_case('cAMELcASE'))
|
||||
end)
|
||||
else
|
||||
it('does nothing on Linux', function()
|
||||
itp('does nothing on Linux', function()
|
||||
eq('camelcase', fix_case('camelcase'))
|
||||
eq('cAMELcASE', fix_case('cAMELcASE'))
|
||||
end)
|
||||
@@ -459,41 +453,41 @@ describe('more path function', function()
|
||||
end)
|
||||
|
||||
describe('append_path', function()
|
||||
it('joins given paths with a slash', function()
|
||||
itp('joins given paths with a slash', function()
|
||||
local path1 = cstr(100, 'path1')
|
||||
local to_append = to_cstr('path2')
|
||||
eq(OK, (path.append_path(path1, to_append, 100)))
|
||||
eq("path1/path2", (ffi.string(path1)))
|
||||
end)
|
||||
|
||||
it('joins given paths without adding an unnecessary slash', function()
|
||||
itp('joins given paths without adding an unnecessary slash', function()
|
||||
local path1 = cstr(100, 'path1/')
|
||||
local to_append = to_cstr('path2')
|
||||
eq(OK, path.append_path(path1, to_append, 100))
|
||||
eq("path1/path2", (ffi.string(path1)))
|
||||
end)
|
||||
|
||||
it('fails and uses filename if there is not enough space left for to_append', function()
|
||||
itp('fails and uses filename if there is not enough space left for to_append', function()
|
||||
local path1 = cstr(11, 'path1/')
|
||||
local to_append = to_cstr('path2')
|
||||
eq(FAIL, (path.append_path(path1, to_append, 11)))
|
||||
end)
|
||||
|
||||
it('does not append a slash if to_append is empty', function()
|
||||
itp('does not append a slash if to_append is empty', function()
|
||||
local path1 = cstr(6, 'path1')
|
||||
local to_append = to_cstr('')
|
||||
eq(OK, (path.append_path(path1, to_append, 6)))
|
||||
eq('path1', (ffi.string(path1)))
|
||||
end)
|
||||
|
||||
it('does not append unnecessary dots', function()
|
||||
itp('does not append unnecessary dots', function()
|
||||
local path1 = cstr(6, 'path1')
|
||||
local to_append = to_cstr('.')
|
||||
eq(OK, (path.append_path(path1, to_append, 6)))
|
||||
eq('path1', (ffi.string(path1)))
|
||||
end)
|
||||
|
||||
it('copies to_append to path, if path is empty', function()
|
||||
itp('copies to_append to path, if path is empty', function()
|
||||
local path1 = cstr(7, '')
|
||||
local to_append = to_cstr('/path2')
|
||||
eq(OK, (path.append_path(path1, to_append, 7)))
|
||||
@@ -507,15 +501,15 @@ describe('more path function', function()
|
||||
return path.path_is_absolute_path(filename)
|
||||
end
|
||||
|
||||
it('returns true if filename starts with a slash', function()
|
||||
itp('returns true if filename starts with a slash', function()
|
||||
eq(OK, path_is_absolute_path('/some/directory/'))
|
||||
end)
|
||||
|
||||
it('returns true if filename starts with a tilde', function()
|
||||
itp('returns true if filename starts with a tilde', function()
|
||||
eq(OK, path_is_absolute_path('~/in/my/home~/directory'))
|
||||
end)
|
||||
|
||||
it('returns false if filename starts not with slash nor tilde', function()
|
||||
itp('returns false if filename starts not with slash nor tilde', function()
|
||||
eq(FAIL, path_is_absolute_path('not/in/my/home~/directory'))
|
||||
end)
|
||||
end)
|
||||
|
@@ -2,6 +2,6 @@
|
||||
-- Busted started doing this to help provide more isolation. See issue #62
|
||||
-- for more information about this.
|
||||
local ffi = require('ffi')
|
||||
local helpers = require('test.unit.helpers')
|
||||
local helpers = require('test.unit.helpers')(nil)
|
||||
local lfs = require('lfs')
|
||||
local preprocess = require('test.unit.preprocess')
|
||||
|
@@ -1,10 +1,13 @@
|
||||
local helpers = require 'test.unit.helpers'
|
||||
local helpers = require('test.unit.helpers')(after_each)
|
||||
local itp = helpers.gen_itp(it)
|
||||
|
||||
local prof = helpers.cimport './src/nvim/profile.h'
|
||||
local cimport = helpers.cimport
|
||||
local ffi = helpers.ffi
|
||||
local eq = helpers.eq
|
||||
local neq = helpers.neq
|
||||
|
||||
local prof = cimport('./src/nvim/profile.h')
|
||||
|
||||
local function split(inputstr, sep)
|
||||
if sep == nil then
|
||||
sep = "%s"
|
||||
@@ -78,7 +81,7 @@ describe('profiling related functions', function()
|
||||
end
|
||||
|
||||
describe('profile_equal', function()
|
||||
it('times are equal to themselves', function()
|
||||
itp('times are equal to themselves', function()
|
||||
local start = profile_start()
|
||||
assert.is_true(profile_equal(start, start))
|
||||
|
||||
@@ -86,7 +89,7 @@ describe('profiling related functions', function()
|
||||
assert.is_true(profile_equal(e, e))
|
||||
end)
|
||||
|
||||
it('times are unequal to others', function()
|
||||
itp('times are unequal to others', function()
|
||||
assert.is_false(profile_equal(profile_start(), profile_start()))
|
||||
end)
|
||||
end)
|
||||
@@ -95,24 +98,24 @@ describe('profiling related functions', function()
|
||||
-- the profiling package. Those functions in turn will probably be tested
|
||||
-- using profile_cmp... circular reasoning.
|
||||
describe('profile_cmp', function()
|
||||
it('can compare subsequent starts', function()
|
||||
itp('can compare subsequent starts', function()
|
||||
local s1, s2 = profile_start(), profile_start()
|
||||
assert.is_true(profile_cmp(s1, s2) > 0)
|
||||
assert.is_true(profile_cmp(s2, s1) < 0)
|
||||
end)
|
||||
|
||||
it('can compare the zero element', function()
|
||||
itp('can compare the zero element', function()
|
||||
assert.is_true(profile_cmp(profile_zero(), profile_zero()) == 0)
|
||||
end)
|
||||
|
||||
it('correctly orders divisions', function()
|
||||
itp('correctly orders divisions', function()
|
||||
local start = profile_start()
|
||||
assert.is_true(profile_cmp(start, profile_divide(start, 10)) <= 0)
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('profile_divide', function()
|
||||
it('actually performs division', function()
|
||||
itp('actually performs division', function()
|
||||
-- note: the routine actually performs floating-point division to get
|
||||
-- better rounding behaviour, we have to take that into account when
|
||||
-- checking. (check range, not exact number).
|
||||
@@ -134,14 +137,14 @@ describe('profiling related functions', function()
|
||||
end)
|
||||
|
||||
describe('profile_zero', function()
|
||||
it('returns the same value on each call', function()
|
||||
itp('returns the same value on each call', function()
|
||||
eq(0, profile_zero())
|
||||
assert.is_true(profile_equal(profile_zero(), profile_zero()))
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('profile_start', function()
|
||||
it('increases', function()
|
||||
itp('increases', function()
|
||||
local last = profile_start()
|
||||
for _ = 1, 100 do
|
||||
local curr = profile_start()
|
||||
@@ -152,11 +155,11 @@ describe('profiling related functions', function()
|
||||
end)
|
||||
|
||||
describe('profile_end', function()
|
||||
it('the elapsed time cannot be zero', function()
|
||||
itp('the elapsed time cannot be zero', function()
|
||||
neq(profile_zero(), profile_end(profile_start()))
|
||||
end)
|
||||
|
||||
it('outer elapsed >= inner elapsed', function()
|
||||
itp('outer elapsed >= inner elapsed', function()
|
||||
for _ = 1, 100 do
|
||||
local start_outer = profile_start()
|
||||
local start_inner = profile_start()
|
||||
@@ -169,11 +172,11 @@ describe('profiling related functions', function()
|
||||
end)
|
||||
|
||||
describe('profile_setlimit', function()
|
||||
it('sets no limit when 0 is passed', function()
|
||||
itp('sets no limit when 0 is passed', function()
|
||||
eq(true, profile_equal(profile_setlimit(0), profile_zero()))
|
||||
end)
|
||||
|
||||
it('sets a limit in the future otherwise', function()
|
||||
itp('sets a limit in the future otherwise', function()
|
||||
local future = profile_setlimit(1000)
|
||||
local now = profile_start()
|
||||
assert.is_true(profile_cmp(future, now) < 0)
|
||||
@@ -181,12 +184,12 @@ describe('profiling related functions', function()
|
||||
end)
|
||||
|
||||
describe('profile_passed_limit', function()
|
||||
it('start is in the past', function()
|
||||
itp('start is in the past', function()
|
||||
local start = profile_start()
|
||||
eq(true, profile_passed_limit(start))
|
||||
end)
|
||||
|
||||
it('start + start is in the future', function()
|
||||
itp('start + start is in the future', function()
|
||||
local start = profile_start()
|
||||
local future = profile_add(start, start)
|
||||
eq(false, profile_passed_limit(future))
|
||||
@@ -194,12 +197,12 @@ describe('profiling related functions', function()
|
||||
end)
|
||||
|
||||
describe('profile_msg', function()
|
||||
it('prints the zero time as 0.00000', function()
|
||||
itp('prints the zero time as 0.00000', function()
|
||||
local str = trim(profile_msg(profile_zero()))
|
||||
eq(str, "0.000000")
|
||||
end)
|
||||
|
||||
it('prints the time passed, in seconds.microsends', function()
|
||||
itp('prints the time passed, in seconds.microsends', function()
|
||||
local start = profile_start()
|
||||
local endt = profile_end(start)
|
||||
local str = trim(profile_msg(endt))
|
||||
@@ -221,14 +224,14 @@ describe('profiling related functions', function()
|
||||
end)
|
||||
|
||||
describe('profile_add', function()
|
||||
it('adds profiling times', function()
|
||||
itp('adds profiling times', function()
|
||||
local start = profile_start()
|
||||
assert.equals(start, profile_add(profile_zero(), start))
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('profile_sub', function()
|
||||
it('subtracts profiling times', function()
|
||||
itp('subtracts profiling times', function()
|
||||
-- subtracting zero does nothing
|
||||
local start = profile_start()
|
||||
assert.equals(start, profile_sub(start, profile_zero()))
|
||||
|
@@ -1,9 +1,11 @@
|
||||
local helpers = require("test.unit.helpers")
|
||||
local helpers = require("test.unit.helpers")(after_each)
|
||||
local itp = helpers.gen_itp(it)
|
||||
|
||||
local ffi = helpers.ffi
|
||||
local eq = helpers.eq
|
||||
local cstr = helpers.cstr
|
||||
local eq = helpers.eq
|
||||
local ffi = helpers.ffi
|
||||
local cstr = helpers.cstr
|
||||
local to_cstr = helpers.to_cstr
|
||||
local child_call_once = helpers.child_call_once
|
||||
|
||||
local rbuffer = helpers.cimport("./test/unit/fixtures/rbuffer.h")
|
||||
|
||||
@@ -31,9 +33,11 @@ describe('rbuffer functions', function()
|
||||
end
|
||||
|
||||
before_each(function()
|
||||
rbuf = ffi.gc(rbuffer.rbuffer_new(capacity), rbuffer.rbuffer_free)
|
||||
-- fill the internal buffer with the character '0' to simplify inspecting
|
||||
ffi.C.memset(rbuf.start_ptr, string.byte('0'), capacity)
|
||||
child_call_once(function()
|
||||
rbuf = ffi.gc(rbuffer.rbuffer_new(capacity), rbuffer.rbuffer_free)
|
||||
-- fill the internal buffer with the character '0' to simplify inspecting
|
||||
ffi.C.memset(rbuf.start_ptr, string.byte('0'), capacity)
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('RBUFFER_UNTIL_FULL', function()
|
||||
@@ -50,66 +54,51 @@ describe('rbuffer functions', function()
|
||||
end)
|
||||
|
||||
describe('with empty buffer in one contiguous chunk', function()
|
||||
it('is called once with the empty chunk', function()
|
||||
itp('is called once with the empty chunk', function()
|
||||
collect_write_chunks()
|
||||
eq({'0000000000000000'}, chunks)
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('with partially empty buffer in one contiguous chunk', function()
|
||||
before_each(function()
|
||||
itp('is called once with the empty chunk', function()
|
||||
write('string')
|
||||
end)
|
||||
|
||||
it('is called once with the empty chunk', function()
|
||||
collect_write_chunks()
|
||||
eq({'0000000000'}, chunks)
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('with filled buffer in one contiguous chunk', function()
|
||||
before_each(function()
|
||||
itp('is not called', function()
|
||||
write('abcdefghijklmnopq')
|
||||
end)
|
||||
|
||||
it('is not called', function()
|
||||
collect_write_chunks()
|
||||
eq({}, chunks)
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('with buffer partially empty in two contiguous chunks', function()
|
||||
before_each(function()
|
||||
itp('is called twice with each filled chunk', function()
|
||||
write('1234567890')
|
||||
read(8)
|
||||
end)
|
||||
|
||||
it('is called twice with each filled chunk', function()
|
||||
collect_write_chunks()
|
||||
eq({'000000', '12345678'}, chunks)
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('with buffer empty in two contiguous chunks', function()
|
||||
before_each(function()
|
||||
itp('is called twice with each filled chunk', function()
|
||||
write('12345678')
|
||||
read(8)
|
||||
end)
|
||||
|
||||
it('is called twice with each filled chunk', function()
|
||||
collect_write_chunks()
|
||||
eq({'00000000', '12345678'}, chunks)
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('with buffer filled in two contiguous chunks', function()
|
||||
before_each(function()
|
||||
itp('is not called', function()
|
||||
write('12345678')
|
||||
read(8)
|
||||
write('abcdefghijklmnopq')
|
||||
end)
|
||||
|
||||
it('is not called', function()
|
||||
collect_write_chunks()
|
||||
eq({}, chunks)
|
||||
end)
|
||||
@@ -130,55 +119,43 @@ describe('rbuffer functions', function()
|
||||
end)
|
||||
|
||||
describe('with empty buffer', function()
|
||||
it('is not called', function()
|
||||
itp('is not called', function()
|
||||
collect_read_chunks()
|
||||
eq({}, chunks)
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('with partially filled buffer in one contiguous chunk', function()
|
||||
before_each(function()
|
||||
itp('is called once with the filled chunk', function()
|
||||
write('string')
|
||||
end)
|
||||
|
||||
it('is called once with the filled chunk', function()
|
||||
collect_read_chunks()
|
||||
eq({'string'}, chunks)
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('with filled buffer in one contiguous chunk', function()
|
||||
before_each(function()
|
||||
itp('is called once with the filled chunk', function()
|
||||
write('abcdefghijklmnopq')
|
||||
end)
|
||||
|
||||
it('is called once with the filled chunk', function()
|
||||
collect_read_chunks()
|
||||
eq({'abcdefghijklmnop'}, chunks)
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('with buffer partially filled in two contiguous chunks', function()
|
||||
before_each(function()
|
||||
itp('is called twice with each filled chunk', function()
|
||||
write('1234567890')
|
||||
read(10)
|
||||
write('long string')
|
||||
end)
|
||||
|
||||
it('is called twice with each filled chunk', function()
|
||||
collect_read_chunks()
|
||||
eq({'long s', 'tring'}, chunks)
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('with buffer filled in two contiguous chunks', function()
|
||||
before_each(function()
|
||||
itp('is called twice with each filled chunk', function()
|
||||
write('12345678')
|
||||
read(8)
|
||||
write('abcdefghijklmnopq')
|
||||
end)
|
||||
|
||||
it('is called twice with each filled chunk', function()
|
||||
collect_read_chunks()
|
||||
eq({'abcdefgh', 'ijklmnop'}, chunks)
|
||||
end)
|
||||
@@ -198,20 +175,17 @@ describe('rbuffer functions', function()
|
||||
end)
|
||||
|
||||
describe('with empty buffer', function()
|
||||
it('is not called', function()
|
||||
itp('is not called', function()
|
||||
collect_chars()
|
||||
eq({}, chars)
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('with buffer filled in two contiguous chunks', function()
|
||||
before_each(function()
|
||||
itp('collects each character and index', function()
|
||||
write('1234567890')
|
||||
read(10)
|
||||
write('long string')
|
||||
end)
|
||||
|
||||
it('collects each character and index', function()
|
||||
collect_chars()
|
||||
eq({{'l', 0}, {'o', 1}, {'n', 2}, {'g', 3}, {' ', 4}, {'s', 5},
|
||||
{'t', 6}, {'r', 7}, {'i', 8}, {'n', 9}, {'g', 10}}, chars)
|
||||
@@ -232,20 +206,17 @@ describe('rbuffer functions', function()
|
||||
end)
|
||||
|
||||
describe('with empty buffer', function()
|
||||
it('is not called', function()
|
||||
itp('is not called', function()
|
||||
collect_chars()
|
||||
eq({}, chars)
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('with buffer filled in two contiguous chunks', function()
|
||||
before_each(function()
|
||||
itp('collects each character and index', function()
|
||||
write('1234567890')
|
||||
read(10)
|
||||
write('long string')
|
||||
end)
|
||||
|
||||
it('collects each character and index', function()
|
||||
collect_chars()
|
||||
eq({{'g', 10}, {'n', 9}, {'i', 8}, {'r', 7}, {'t', 6}, {'s', 5},
|
||||
{' ', 4}, {'g', 3}, {'n', 2}, {'o', 1}, {'l', 0}}, chars)
|
||||
@@ -264,13 +235,10 @@ describe('rbuffer functions', function()
|
||||
end
|
||||
|
||||
describe('with buffer filled in two contiguous chunks', function()
|
||||
before_each(function()
|
||||
itp('compares the common longest sequence', function()
|
||||
write('1234567890')
|
||||
read(10)
|
||||
write('long string')
|
||||
end)
|
||||
|
||||
it('compares the common longest sequence', function()
|
||||
eq(0, cmp('long string'))
|
||||
eq(0, cmp('long strin'))
|
||||
eq(-1, cmp('long striM'))
|
||||
@@ -282,31 +250,31 @@ describe('rbuffer functions', function()
|
||||
end)
|
||||
|
||||
describe('with empty buffer', function()
|
||||
it('returns 0 since no characters are compared', function()
|
||||
itp('returns 0 since no characters are compared', function()
|
||||
eq(0, cmp(''))
|
||||
end)
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('rbuffer_write', function()
|
||||
it('fills the internal buffer and returns the write count', function()
|
||||
itp('fills the internal buffer and returns the write count', function()
|
||||
eq(12, write('short string'))
|
||||
eq('short string0000', inspect())
|
||||
end)
|
||||
|
||||
it('wont write beyond capacity', function()
|
||||
itp('wont write beyond capacity', function()
|
||||
eq(16, write('very very long string'))
|
||||
eq('very very long s', inspect())
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('rbuffer_read', function()
|
||||
it('reads what was previously written', function()
|
||||
itp('reads what was previously written', function()
|
||||
write('to read')
|
||||
eq('to read', read(20))
|
||||
end)
|
||||
|
||||
it('reads nothing if the buffer is empty', function()
|
||||
itp('reads nothing if the buffer is empty', function()
|
||||
eq('', read(20))
|
||||
write('empty')
|
||||
eq('empty', read(20))
|
||||
@@ -315,7 +283,7 @@ describe('rbuffer functions', function()
|
||||
end)
|
||||
|
||||
describe('rbuffer_get', function()
|
||||
it('fetch the pointer at offset, wrapping if required', function()
|
||||
itp('fetch the pointer at offset, wrapping if required', function()
|
||||
write('1234567890')
|
||||
read(10)
|
||||
write('long string')
|
||||
@@ -334,7 +302,7 @@ describe('rbuffer functions', function()
|
||||
end)
|
||||
|
||||
describe('wrapping behavior', function()
|
||||
it('writing/reading wraps across the end of the internal buffer', function()
|
||||
itp('writing/reading wraps across the end of the internal buffer', function()
|
||||
write('1234567890')
|
||||
eq('1234', read(4))
|
||||
eq('5678', read(4))
|
||||
|
@@ -26,6 +26,22 @@ function Set:new(items)
|
||||
return obj
|
||||
end
|
||||
|
||||
function Set:copy()
|
||||
local obj = {}
|
||||
obj.nelem = self.nelem
|
||||
obj.tbl = {}
|
||||
obj.items = {}
|
||||
for k, v in pairs(self.tbl) do
|
||||
obj.tbl[k] = v
|
||||
end
|
||||
for k, v in pairs(self.items) do
|
||||
obj.items[k] = v
|
||||
end
|
||||
setmetatable(obj, Set)
|
||||
obj.__index = Set
|
||||
return obj
|
||||
end
|
||||
|
||||
-- adds the argument Set to this Set
|
||||
function Set:union(other)
|
||||
for e in other:iterator() do
|
||||
|
@@ -1,4 +1,5 @@
|
||||
local helpers = require("test.unit.helpers")
|
||||
local helpers = require("test.unit.helpers")(after_each)
|
||||
local itp = helpers.gen_itp(it)
|
||||
|
||||
local cimport = helpers.cimport
|
||||
local eq = helpers.eq
|
||||
@@ -19,23 +20,23 @@ describe('vim_strsave_escaped()', function()
|
||||
return ret
|
||||
end
|
||||
|
||||
it('precedes by a backslash all chars from second argument', function()
|
||||
itp('precedes by a backslash all chars from second argument', function()
|
||||
eq([[\a\b\c\d]], vim_strsave_escaped('abcd','abcd'))
|
||||
end)
|
||||
|
||||
it('precedes by a backslash chars only from second argument', function()
|
||||
itp('precedes by a backslash chars only from second argument', function()
|
||||
eq([[\a\bcd]], vim_strsave_escaped('abcd','ab'))
|
||||
end)
|
||||
|
||||
it('returns a copy of passed string if second argument is empty', function()
|
||||
itp('returns a copy of passed string if second argument is empty', function()
|
||||
eq('text \n text', vim_strsave_escaped('text \n text',''))
|
||||
end)
|
||||
|
||||
it('returns an empty string if first argument is empty string', function()
|
||||
itp('returns an empty string if first argument is empty string', function()
|
||||
eq('', vim_strsave_escaped('','\r'))
|
||||
end)
|
||||
|
||||
it('returns a copy of passed string if it does not contain chars from 2nd argument', function()
|
||||
itp('returns a copy of passed string if it does not contain chars from 2nd argument', function()
|
||||
eq('some text', vim_strsave_escaped('some text', 'a'))
|
||||
end)
|
||||
end)
|
||||
@@ -50,51 +51,51 @@ describe('vim_strnsave_unquoted()', function()
|
||||
return ret
|
||||
end
|
||||
|
||||
it('copies unquoted strings as-is', function()
|
||||
itp('copies unquoted strings as-is', function()
|
||||
eq('-c', vim_strnsave_unquoted('-c'))
|
||||
eq('', vim_strnsave_unquoted(''))
|
||||
end)
|
||||
|
||||
it('respects length argument', function()
|
||||
itp('respects length argument', function()
|
||||
eq('', vim_strnsave_unquoted('-c', 0))
|
||||
eq('-', vim_strnsave_unquoted('-c', 1))
|
||||
eq('-', vim_strnsave_unquoted('"-c', 2))
|
||||
end)
|
||||
|
||||
it('unquotes fully quoted word', function()
|
||||
itp('unquotes fully quoted word', function()
|
||||
eq('/bin/sh', vim_strnsave_unquoted('"/bin/sh"'))
|
||||
end)
|
||||
|
||||
it('unquotes partially quoted word', function()
|
||||
itp('unquotes partially quoted word', function()
|
||||
eq('/Program Files/sh', vim_strnsave_unquoted('/Program" "Files/sh'))
|
||||
end)
|
||||
|
||||
it('removes ""', function()
|
||||
itp('removes ""', function()
|
||||
eq('/Program Files/sh', vim_strnsave_unquoted('/""Program" "Files/sh'))
|
||||
end)
|
||||
|
||||
it('performs unescaping of "', function()
|
||||
itp('performs unescaping of "', function()
|
||||
eq('/"Program Files"/sh', vim_strnsave_unquoted('/"\\""Program Files"\\""/sh'))
|
||||
end)
|
||||
|
||||
it('performs unescaping of \\', function()
|
||||
itp('performs unescaping of \\', function()
|
||||
eq('/\\Program Files\\foo/sh', vim_strnsave_unquoted('/"\\\\"Program Files"\\\\foo"/sh'))
|
||||
end)
|
||||
|
||||
it('strips quote when there is no pair to it', function()
|
||||
itp('strips quote when there is no pair to it', function()
|
||||
eq('/Program Files/sh', vim_strnsave_unquoted('/Program" Files/sh'))
|
||||
eq('', vim_strnsave_unquoted('"'))
|
||||
end)
|
||||
|
||||
it('allows string to end with one backslash unescaped', function()
|
||||
itp('allows string to end with one backslash unescaped', function()
|
||||
eq('/Program Files/sh\\', vim_strnsave_unquoted('/Program" Files/sh\\'))
|
||||
end)
|
||||
|
||||
it('does not perform unescaping out of quotes', function()
|
||||
itp('does not perform unescaping out of quotes', function()
|
||||
eq('/Program\\ Files/sh\\', vim_strnsave_unquoted('/Program\\ Files/sh\\'))
|
||||
end)
|
||||
|
||||
it('does not unescape \\n', function()
|
||||
itp('does not unescape \\n', function()
|
||||
eq('/Program\\nFiles/sh', vim_strnsave_unquoted('/Program"\\n"Files/sh'))
|
||||
end)
|
||||
end)
|
||||
|
@@ -1,58 +1,65 @@
|
||||
local lfs = require 'lfs'
|
||||
local helpers = require 'test.unit.helpers'
|
||||
local lfs = require('lfs')
|
||||
local helpers = require('test.unit.helpers')(after_each)
|
||||
local itp = helpers.gen_itp(it)
|
||||
|
||||
local os = helpers.cimport './src/nvim/os/os.h'
|
||||
local tempfile = helpers.cimport './src/nvim/fileio.h'
|
||||
local eq = helpers.eq
|
||||
local neq = helpers.neq
|
||||
local cimport = helpers.cimport
|
||||
local child_call_once = helpers.child_call_once
|
||||
local child_cleanup_once = helpers.child_cleanup_once
|
||||
|
||||
local lib = cimport('./src/nvim/os/os.h', './src/nvim/fileio.h')
|
||||
|
||||
describe('tempfile related functions', function()
|
||||
before_each(function()
|
||||
tempfile.vim_deltempdir()
|
||||
end)
|
||||
after_each(function()
|
||||
tempfile.vim_deltempdir()
|
||||
local function vim_deltempdir()
|
||||
lib.vim_deltempdir()
|
||||
end
|
||||
child_call_once(vim_deltempdir)
|
||||
child_cleanup_once(vim_deltempdir)
|
||||
end)
|
||||
|
||||
local vim_gettempdir = function()
|
||||
return helpers.ffi.string(tempfile.vim_gettempdir())
|
||||
return helpers.ffi.string(lib.vim_gettempdir())
|
||||
end
|
||||
|
||||
describe('vim_gettempdir', function()
|
||||
it('returns path to Neovim own temp directory', function()
|
||||
itp('returns path to Neovim own temp directory', function()
|
||||
local dir = vim_gettempdir()
|
||||
assert.True(dir ~= nil and dir:len() > 0)
|
||||
-- os_file_is_writable returns 2 for a directory which we have rights
|
||||
-- to write into.
|
||||
assert.equals(os.os_file_is_writable(helpers.to_cstr(dir)), 2)
|
||||
eq(lib.os_file_is_writable(helpers.to_cstr(dir)), 2)
|
||||
for entry in lfs.dir(dir) do
|
||||
assert.True(entry == '.' or entry == '..')
|
||||
end
|
||||
end)
|
||||
|
||||
it('returns the same directory on each call', function()
|
||||
itp('returns the same directory on each call', function()
|
||||
local dir1 = vim_gettempdir()
|
||||
local dir2 = vim_gettempdir()
|
||||
assert.equals(dir1, dir2)
|
||||
eq(dir1, dir2)
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('vim_tempname', function()
|
||||
local vim_tempname = function()
|
||||
return helpers.ffi.string(tempfile.vim_tempname())
|
||||
return helpers.ffi.string(lib.vim_tempname())
|
||||
end
|
||||
|
||||
it('generate name of non-existing file', function()
|
||||
itp('generate name of non-existing file', function()
|
||||
local file = vim_tempname()
|
||||
assert.truthy(file)
|
||||
assert.False(os.os_path_exists(file))
|
||||
assert.False(lib.os_path_exists(file))
|
||||
end)
|
||||
|
||||
it('generate different names on each call', function()
|
||||
itp('generate different names on each call', function()
|
||||
local fst = vim_tempname()
|
||||
local snd = vim_tempname()
|
||||
assert.not_equals(fst, snd)
|
||||
neq(fst, snd)
|
||||
end)
|
||||
|
||||
it('generate file name in Neovim own temp directory', function()
|
||||
itp('generate file name in Neovim own temp directory', function()
|
||||
local dir = vim_gettempdir()
|
||||
local file = vim_tempname()
|
||||
assert.truthy(file:find('^' .. dir .. '[^/]*$'))
|
||||
|
Reference in New Issue
Block a user