mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
@@ -12,15 +12,18 @@ local Paths = require('test.config.paths')
|
||||
|
||||
local check_cores = global_helpers.check_cores
|
||||
local check_logs = global_helpers.check_logs
|
||||
local neq = global_helpers.neq
|
||||
local dedent = global_helpers.dedent
|
||||
local eq = global_helpers.eq
|
||||
local expect_err = global_helpers.expect_err
|
||||
local ok = global_helpers.ok
|
||||
local filter = global_helpers.filter
|
||||
local map = global_helpers.map
|
||||
local matches = global_helpers.matches
|
||||
local filter = global_helpers.filter
|
||||
local dedent = global_helpers.dedent
|
||||
local neq = global_helpers.neq
|
||||
local ok = global_helpers.ok
|
||||
local read_file = global_helpers.read_file
|
||||
local sleep = global_helpers.sleep
|
||||
local table_flatten = global_helpers.table_flatten
|
||||
local write_file = global_helpers.write_file
|
||||
|
||||
local start_dir = lfs.currentdir()
|
||||
-- XXX: NVIM_PROG takes precedence, QuickBuild sets it.
|
||||
@@ -374,34 +377,6 @@ local function feed_command(...)
|
||||
end
|
||||
end
|
||||
|
||||
-- Dedent the given text and write it to the file name.
|
||||
local function write_file(name, text, no_dedent, append)
|
||||
local file = io.open(name, (append and 'a' or 'w'))
|
||||
if type(text) == 'table' then
|
||||
-- Byte blob
|
||||
local bytes = text
|
||||
text = ''
|
||||
for _, char in ipairs(bytes) do
|
||||
text = ('%s%c'):format(text, char)
|
||||
end
|
||||
elseif not no_dedent then
|
||||
text = dedent(text)
|
||||
end
|
||||
file:write(text)
|
||||
file:flush()
|
||||
file:close()
|
||||
end
|
||||
|
||||
local function read_file(name)
|
||||
local file = io.open(name, 'r')
|
||||
if not file then
|
||||
return nil
|
||||
end
|
||||
local ret = file:read('*a')
|
||||
file:close()
|
||||
return ret
|
||||
end
|
||||
|
||||
local sourced_fnames = {}
|
||||
local function source(code)
|
||||
local fname = tmpname()
|
||||
@@ -466,11 +441,6 @@ local function wait()
|
||||
session:request('nvim_eval', '1')
|
||||
end
|
||||
|
||||
-- sleeps the test runner (_not_ the nvim instance)
|
||||
local function sleep(ms)
|
||||
luv.sleep(ms)
|
||||
end
|
||||
|
||||
local function curbuf_contents()
|
||||
wait() -- Before inspecting the buffer, process all input.
|
||||
return table.concat(curbuf('get_lines', 0, -1, true), '\n')
|
||||
@@ -682,31 +652,6 @@ local function alter_slashes(obj)
|
||||
end
|
||||
end
|
||||
|
||||
local function hexdump(str)
|
||||
local len = string.len(str)
|
||||
local dump = ""
|
||||
local hex = ""
|
||||
local asc = ""
|
||||
|
||||
for i = 1, len do
|
||||
if 1 == i % 8 then
|
||||
dump = dump .. hex .. asc .. "\n"
|
||||
hex = string.format("%04x: ", i - 1)
|
||||
asc = ""
|
||||
end
|
||||
|
||||
local ord = string.byte(str, i)
|
||||
hex = hex .. string.format("%02x ", ord)
|
||||
if ord >= 32 and ord <= 126 then
|
||||
asc = asc .. string.char(ord)
|
||||
else
|
||||
asc = asc .. "."
|
||||
end
|
||||
end
|
||||
|
||||
return dump .. hex .. string.rep(" ", 8 - len % 8) .. asc
|
||||
end
|
||||
|
||||
local module = {
|
||||
NIL = mpack.NIL,
|
||||
alter_slashes = alter_slashes,
|
||||
@@ -737,7 +682,6 @@ local module = {
|
||||
filter = filter,
|
||||
funcs = funcs,
|
||||
get_pathsep = get_pathsep,
|
||||
hexdump = hexdump,
|
||||
insert = insert,
|
||||
iswin = iswin,
|
||||
map = map,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
local assert = require('luassert')
|
||||
local luv = require('luv')
|
||||
local lfs = require('lfs')
|
||||
|
||||
local quote_me = '[^.%w%+%-%@%_%/]' -- complement (needn't quote)
|
||||
@@ -33,6 +34,11 @@ local function popen_w(...)
|
||||
return io.popen(argss_to_cmd(...), 'w')
|
||||
end
|
||||
|
||||
-- sleeps the test runner (_not_ the nvim instance)
|
||||
local function sleep(ms)
|
||||
luv.sleep(ms)
|
||||
end
|
||||
|
||||
local check_logs_useless_lines = {
|
||||
['Warning: noted but unhandled ioctl']=1,
|
||||
['could cause spurious value errors to appear']=2,
|
||||
@@ -612,7 +618,60 @@ local function table_flatten(arr)
|
||||
return result
|
||||
end
|
||||
|
||||
return {
|
||||
local function hexdump(str)
|
||||
local len = string.len(str)
|
||||
local dump = ""
|
||||
local hex = ""
|
||||
local asc = ""
|
||||
|
||||
for i = 1, len do
|
||||
if 1 == i % 8 then
|
||||
dump = dump .. hex .. asc .. "\n"
|
||||
hex = string.format("%04x: ", i - 1)
|
||||
asc = ""
|
||||
end
|
||||
|
||||
local ord = string.byte(str, i)
|
||||
hex = hex .. string.format("%02x ", ord)
|
||||
if ord >= 32 and ord <= 126 then
|
||||
asc = asc .. string.char(ord)
|
||||
else
|
||||
asc = asc .. "."
|
||||
end
|
||||
end
|
||||
|
||||
return dump .. hex .. string.rep(" ", 8 - len % 8) .. asc
|
||||
end
|
||||
|
||||
local function read_file(name)
|
||||
local file = io.open(name, 'r')
|
||||
if not file then
|
||||
return nil
|
||||
end
|
||||
local ret = file:read('*a')
|
||||
file:close()
|
||||
return ret
|
||||
end
|
||||
|
||||
-- Dedent the given text and write it to the file name.
|
||||
local function write_file(name, text, no_dedent, append)
|
||||
local file = io.open(name, (append and 'a' or 'w'))
|
||||
if type(text) == 'table' then
|
||||
-- Byte blob
|
||||
local bytes = text
|
||||
text = ''
|
||||
for _, char in ipairs(bytes) do
|
||||
text = ('%s%c'):format(text, char)
|
||||
end
|
||||
elseif not no_dedent then
|
||||
text = dedent(text)
|
||||
end
|
||||
file:write(text)
|
||||
file:flush()
|
||||
file:close()
|
||||
end
|
||||
|
||||
local module = {
|
||||
REMOVE_THIS = REMOVE_THIS,
|
||||
argss_to_cmd = argss_to_cmd,
|
||||
check_cores = check_cores,
|
||||
@@ -630,6 +689,7 @@ return {
|
||||
format_string = format_string,
|
||||
glob = glob,
|
||||
hasenv = hasenv,
|
||||
hexdump = hexdump,
|
||||
intchar2lua = intchar2lua,
|
||||
map = map,
|
||||
matches = matches,
|
||||
@@ -638,11 +698,16 @@ return {
|
||||
ok = ok,
|
||||
popen_r = popen_r,
|
||||
popen_w = popen_w,
|
||||
read_file = read_file,
|
||||
repeated_read_cmd = repeated_read_cmd,
|
||||
sleep = sleep,
|
||||
shallowcopy = shallowcopy,
|
||||
table_flatten = table_flatten,
|
||||
tmpname = tmpname,
|
||||
uname = uname,
|
||||
updated = updated,
|
||||
which = which,
|
||||
write_file = write_file,
|
||||
}
|
||||
|
||||
return module
|
||||
|
||||
216
test/unit/undo_spec.lua
Normal file
216
test/unit/undo_spec.lua
Normal file
@@ -0,0 +1,216 @@
|
||||
local helpers = require('test.unit.helpers')(after_each)
|
||||
local itp = helpers.gen_itp(it)
|
||||
local lfs = require('lfs')
|
||||
local child_call_once = helpers.child_call_once
|
||||
|
||||
local global_helpers = require('test.helpers')
|
||||
local hexdump = global_helpers.hexdump
|
||||
local sleep = global_helpers.sleep
|
||||
|
||||
local ffi = helpers.ffi
|
||||
local cimport = helpers.cimport
|
||||
local to_cstr = helpers.to_cstr
|
||||
local neq = helpers.neq
|
||||
local eq = helpers.eq
|
||||
|
||||
cimport('./src/nvim/ex_cmds_defs.h')
|
||||
cimport('./src/nvim/buffer_defs.h')
|
||||
local options = cimport('./src/nvim/option_defs.h')
|
||||
-- TODO: remove: local vim = cimport('./src/nvim/vim.h')
|
||||
local undo = cimport('./src/nvim/undo.h')
|
||||
local buffer = cimport('./src/nvim/buffer.h')
|
||||
|
||||
local old_p_udir = nil
|
||||
|
||||
-- Values expected by tests. Set in the setup function and destroyed in teardown
|
||||
local file_buffer = nil
|
||||
local buffer_hash = nil
|
||||
|
||||
child_call_once(function()
|
||||
if old_p_udir == nil then
|
||||
old_p_udir = options.p_udir -- save the old value of p_udir (undodir)
|
||||
end
|
||||
|
||||
-- create a new buffer
|
||||
local c_file = to_cstr('Xtest-unit-undo')
|
||||
file_buffer = buffer.buflist_new(c_file, c_file, 1, buffer.BLN_LISTED)
|
||||
file_buffer.b_u_numhead = 1 -- Pretend that the buffer has been changed
|
||||
|
||||
-- TODO(christopher.waldon.dev@gmail.com): replace the 32 with UNDO_HASH_SIZE
|
||||
-- requires refactor of UNDO_HASH_SIZE into constant/enum for ffi
|
||||
--
|
||||
-- compute a hash for this undofile
|
||||
buffer_hash = ffi.new('char_u[32]')
|
||||
undo.u_compute_hash(buffer_hash)
|
||||
end)
|
||||
|
||||
|
||||
describe('u_write_undo', function()
|
||||
setup(function()
|
||||
lfs.mkdir('unit-test-directory')
|
||||
lfs.chdir('unit-test-directory')
|
||||
options.p_udir = to_cstr(lfs.currentdir()) -- set p_udir to be the test dir
|
||||
end)
|
||||
|
||||
teardown(function()
|
||||
lfs.chdir('..')
|
||||
local success, err = lfs.rmdir('unit-test-directory')
|
||||
if not success then
|
||||
print(err) -- inform tester if directory fails to delete
|
||||
end
|
||||
options.p_udir = old_p_udir --restore old p_udir
|
||||
end)
|
||||
|
||||
-- Lua wrapper for u_write_undo
|
||||
local function u_write_undo(name, forceit, buf, buf_hash)
|
||||
if name ~= nil then
|
||||
name = to_cstr(name)
|
||||
end
|
||||
|
||||
return undo.u_write_undo(name, forceit, buf, buf_hash)
|
||||
end
|
||||
|
||||
itp('writes an undo file to undodir given a buffer and hash', function()
|
||||
u_write_undo(nil, false, file_buffer, buffer_hash)
|
||||
local correct_name = ffi.string(undo.u_get_undo_file_name(file_buffer.b_ffname, false))
|
||||
local undo_file = io.open(correct_name, "r")
|
||||
|
||||
neq(undo_file, nil)
|
||||
local success, err = os.remove(correct_name) -- delete the file now that we're done with it.
|
||||
if not success then
|
||||
print(err) -- inform tester if undofile fails to delete
|
||||
end
|
||||
end)
|
||||
|
||||
itp('writes a correctly-named undo file to undodir given a name, buffer, and hash', function()
|
||||
local correct_name = "undofile.test"
|
||||
u_write_undo(correct_name, false, file_buffer, buffer_hash)
|
||||
local undo_file = io.open(correct_name, "r")
|
||||
|
||||
neq(undo_file, nil)
|
||||
local success, err = os.remove(correct_name) -- delete the file now that we're done with it.
|
||||
if not success then
|
||||
print(err) -- inform tester if undofile fails to delete
|
||||
end
|
||||
end)
|
||||
|
||||
itp('does not write an undofile when the buffer has no valid undofile name', function()
|
||||
-- TODO(christopher.waldon.dev@gmail.com): Figure out how to test this.
|
||||
-- it's hard because u_get_undo_file_name() would need to return null
|
||||
end)
|
||||
|
||||
itp('writes the undofile with the same permissions as the original file', function()
|
||||
-- Create Test file and set permissions
|
||||
local test_file_name = "./test.file"
|
||||
local test_permission_file = io.open(test_file_name, "w")
|
||||
test_permission_file:write("testing permissions")
|
||||
test_permission_file:close()
|
||||
local test_permissions = lfs.attributes(test_file_name).permissions
|
||||
|
||||
-- Create vim buffer
|
||||
local c_file = to_cstr(test_file_name)
|
||||
file_buffer = buffer.buflist_new(c_file, c_file, 1, buffer.BLN_LISTED)
|
||||
file_buffer.b_u_numhead = 1 -- Pretend that the buffer has been changed
|
||||
|
||||
u_write_undo(nil, false, file_buffer, buffer_hash)
|
||||
|
||||
-- Find out the correct name of the undofile
|
||||
local undo_file_name = ffi.string(undo.u_get_undo_file_name(file_buffer.b_ffname, false))
|
||||
|
||||
-- Find out the permissions of the new file
|
||||
local permissions = lfs.attributes(undo_file_name).permissions
|
||||
eq(test_permissions, permissions)
|
||||
|
||||
-- delete the file now that we're done with it.
|
||||
local success, err = os.remove(test_file_name)
|
||||
if not success then
|
||||
print(err) -- inform tester if undofile fails to delete
|
||||
end
|
||||
success, err = os.remove(undo_file_name)
|
||||
if not success then
|
||||
print(err) -- inform tester if undofile fails to delete
|
||||
end
|
||||
end)
|
||||
|
||||
itp('writes an undofile only readable by the user if the buffer is unnamed', function()
|
||||
local correct_permissions = "rw-------"
|
||||
local undo_file_name = "test.undo"
|
||||
|
||||
-- Create vim buffer
|
||||
file_buffer = buffer.buflist_new(nil, nil, 1, buffer.BLN_LISTED)
|
||||
file_buffer.b_u_numhead = 1 -- Pretend that the buffer has been changed
|
||||
|
||||
u_write_undo(undo_file_name, false, file_buffer, buffer_hash)
|
||||
|
||||
-- Find out the permissions of the new file
|
||||
local permissions = lfs.attributes(undo_file_name).permissions
|
||||
eq(correct_permissions, permissions)
|
||||
|
||||
-- delete the file now that we're done with it.
|
||||
local success, err = os.remove(undo_file_name)
|
||||
if not success then
|
||||
print(err) -- inform tester if undofile fails to delete
|
||||
end
|
||||
end)
|
||||
|
||||
itp('forces writing undo file for :wundo! command', function()
|
||||
local file_contents = "testing permissions"
|
||||
-- Write a text file where the undofile should go
|
||||
local correct_name = ffi.string(undo.u_get_undo_file_name(file_buffer.b_ffname, false))
|
||||
global_helpers.write_file(correct_name, file_contents, true, false)
|
||||
|
||||
-- Call with `forceit`.
|
||||
u_write_undo(correct_name, true, file_buffer, buffer_hash)
|
||||
|
||||
local undo_file_contents = global_helpers.read_file(correct_name)
|
||||
|
||||
neq(file_contents, undo_file_contents)
|
||||
local success, deletion_err = os.remove(correct_name) -- delete the file now that we're done with it.
|
||||
if not success then
|
||||
print(deletion_err) -- inform tester if undofile fails to delete
|
||||
end
|
||||
end)
|
||||
|
||||
itp('overwrites an existing undo file', function()
|
||||
u_write_undo(nil, false, file_buffer, buffer_hash)
|
||||
local correct_name = ffi.string(undo.u_get_undo_file_name(file_buffer.b_ffname, false))
|
||||
|
||||
local file_last_modified = lfs.attributes(correct_name).modification
|
||||
|
||||
sleep(1000) -- Ensure difference in timestamps.
|
||||
file_buffer.b_u_numhead = 1 -- Mark it as if there are changes
|
||||
u_write_undo(nil, false, file_buffer, buffer_hash)
|
||||
|
||||
local file_last_modified_2 = lfs.attributes(correct_name).modification
|
||||
|
||||
-- print(file_last_modified, file_last_modified_2)
|
||||
neq(file_last_modified, file_last_modified_2)
|
||||
local success, err = os.remove(correct_name) -- delete the file now that we're done with it.
|
||||
if not success then
|
||||
print(err) -- inform tester if undofile fails to delete
|
||||
end
|
||||
end)
|
||||
|
||||
itp('does not overwrite an existing file that is not an undo file', function()
|
||||
-- TODO: write test
|
||||
end)
|
||||
|
||||
itp('does not overwrite an existing file that has the wrong permissions', function()
|
||||
-- TODO: write test
|
||||
end)
|
||||
|
||||
itp('does not write an undo file if there is no undo information for the buffer', function()
|
||||
file_buffer.b_u_numhead = 0 -- Mark it as if there is no undo information
|
||||
local correct_name = ffi.string(undo.u_get_undo_file_name(file_buffer.b_ffname, false))
|
||||
|
||||
local existing_file = io.open(correct_name,"r")
|
||||
if existing_file then
|
||||
existing_file:close()
|
||||
os.remove(correct_name)
|
||||
end
|
||||
u_write_undo(nil, false, file_buffer, buffer_hash)
|
||||
local undo_file = io.open(correct_name, "r")
|
||||
|
||||
eq(undo_file, nil)
|
||||
end)
|
||||
end)
|
||||
Reference in New Issue
Block a user