neovim

Neovim text editor
git clone https://git.dasho.dev/neovim.git
Log | Files | Refs | README

undo_spec.lua (7480B)


      1 local t = require('test.unit.testutil')
      2 local itp = t.gen_itp(it)
      3 local uv = vim.uv
      4 local child_call_once = t.child_call_once
      5 local sleep = uv.sleep
      6 
      7 local ffi = t.ffi
      8 local cimport = t.cimport
      9 local to_cstr = t.to_cstr
     10 local neq = t.neq
     11 local eq = t.eq
     12 local mkdir = t.mkdir
     13 
     14 local options = cimport('./src/nvim/option_vars.h')
     15 local undo = cimport('./src/nvim/undo.h')
     16 local buffer = cimport('./src/nvim/buffer.h')
     17 
     18 local old_p_udir = nil
     19 
     20 -- Values expected by tests. Set in the setup function and destroyed in teardown
     21 local file_buffer = nil
     22 local buffer_hash = nil
     23 
     24 child_call_once(function()
     25  if old_p_udir == nil then
     26    old_p_udir = options.p_udir -- save the old value of p_udir (undodir)
     27  end
     28 
     29  -- create a new buffer
     30  local c_file = to_cstr('Xtest-unit-undo')
     31  file_buffer = buffer.buflist_new(c_file, c_file, 1, buffer.BLN_LISTED)
     32  file_buffer.b_u_numhead = 1 -- Pretend that the buffer has been changed
     33 
     34  -- TODO(christopher.waldon.dev@gmail.com): replace the 32 with UNDO_HASH_SIZE
     35  -- requires refactor of UNDO_HASH_SIZE into constant/enum for ffi
     36  --
     37  -- compute a hash for this undofile
     38  buffer_hash = ffi.new('char[32]')
     39  undo.u_compute_hash(file_buffer, buffer_hash)
     40 end)
     41 
     42 describe('u_write_undo', function()
     43  setup(function()
     44    mkdir('unit-test-directory')
     45    uv.chdir('unit-test-directory')
     46    options.p_udir = to_cstr(uv.cwd()) -- set p_udir to be the test dir
     47  end)
     48 
     49  teardown(function()
     50    uv.chdir('..')
     51    local success, err = uv.fs_rmdir('unit-test-directory')
     52    if not success then
     53      print(err) -- inform tester if directory fails to delete
     54    end
     55    options.p_udir = old_p_udir --restore old p_udir
     56  end)
     57 
     58  -- Lua wrapper for u_write_undo
     59  local function u_write_undo(name, forceit, buf, buf_hash)
     60    if name ~= nil then
     61      name = to_cstr(name)
     62    end
     63 
     64    return undo.u_write_undo(name, forceit, buf, buf_hash)
     65  end
     66 
     67  itp('writes an undo file to undodir given a buffer and hash', function()
     68    u_write_undo(nil, false, file_buffer, buffer_hash)
     69    local correct_name = ffi.string(undo.u_get_undo_file_name(file_buffer.b_ffname, false))
     70    local undo_file = io.open(correct_name, 'r')
     71 
     72    neq(undo_file, nil)
     73    local success, err = os.remove(correct_name) -- delete the file now that we're done with it.
     74    if not success then
     75      print(err) -- inform tester if undofile fails to delete
     76    end
     77  end)
     78 
     79  itp('writes a correctly-named undo file to undodir given a name, buffer, and hash', function()
     80    local correct_name = 'undofile.test'
     81    u_write_undo(correct_name, false, file_buffer, buffer_hash)
     82    local undo_file = io.open(correct_name, 'r')
     83 
     84    neq(undo_file, nil)
     85    local success, err = os.remove(correct_name) -- delete the file now that we're done with it.
     86    if not success then
     87      print(err) -- inform tester if undofile fails to delete
     88    end
     89  end)
     90 
     91  itp('does not write an undofile when the buffer has no valid undofile name', function()
     92    -- TODO(christopher.waldon.dev@gmail.com): Figure out how to test this.
     93    -- it's hard because u_get_undo_file_name() would need to return null
     94  end)
     95 
     96  itp('writes the undofile with the same permissions as the original file', function()
     97    -- Create Test file and set permissions
     98    local test_file_name = './test.file'
     99    local test_permission_file = io.open(test_file_name, 'w')
    100    test_permission_file:write('testing permissions')
    101    test_permission_file:close()
    102    local test_permissions = uv.fs_stat(test_file_name).mode
    103 
    104    -- Create vim buffer
    105    local c_file = to_cstr(test_file_name)
    106    file_buffer = buffer.buflist_new(c_file, c_file, 1, buffer.BLN_LISTED)
    107    file_buffer.b_u_numhead = 1 -- Pretend that the buffer has been changed
    108 
    109    u_write_undo(nil, false, file_buffer, buffer_hash)
    110 
    111    -- Find out the correct name of the undofile
    112    local undo_file_name = ffi.string(undo.u_get_undo_file_name(file_buffer.b_ffname, false))
    113 
    114    -- Find out the permissions of the new file
    115    local permissions = uv.fs_stat(undo_file_name).mode
    116    eq(test_permissions, permissions)
    117 
    118    -- delete the file now that we're done with it.
    119    local success, err = os.remove(test_file_name)
    120    if not success then
    121      print(err) -- inform tester if undofile fails to delete
    122    end
    123    success, err = os.remove(undo_file_name)
    124    if not success then
    125      print(err) -- inform tester if undofile fails to delete
    126    end
    127  end)
    128 
    129  itp('writes an undofile only readable by the user if the buffer is unnamed', function()
    130    local correct_permissions = 33152
    131    local undo_file_name = 'test.undo'
    132 
    133    -- Create vim buffer
    134    file_buffer = buffer.buflist_new(nil, nil, 1, buffer.BLN_LISTED)
    135    file_buffer.b_u_numhead = 1 -- Pretend that the buffer has been changed
    136 
    137    u_write_undo(undo_file_name, false, file_buffer, buffer_hash)
    138 
    139    -- Find out the permissions of the new file
    140    local permissions = uv.fs_stat(undo_file_name).mode
    141    eq(correct_permissions, permissions)
    142 
    143    -- delete the file now that we're done with it.
    144    local success, err = os.remove(undo_file_name)
    145    if not success then
    146      print(err) -- inform tester if undofile fails to delete
    147    end
    148  end)
    149 
    150  itp('forces writing undo file for :wundo! command', function()
    151    local file_contents = 'testing permissions'
    152    -- Write a text file where the undofile should go
    153    local correct_name = ffi.string(undo.u_get_undo_file_name(file_buffer.b_ffname, false))
    154    t.write_file(correct_name, file_contents, true, false)
    155 
    156    -- Call with `forceit`.
    157    u_write_undo(correct_name, true, file_buffer, buffer_hash)
    158 
    159    local undo_file_contents = t.read_file(correct_name)
    160 
    161    neq(file_contents, undo_file_contents)
    162    local success, deletion_err = os.remove(correct_name) -- delete the file now that we're done with it.
    163    if not success then
    164      print(deletion_err) -- inform tester if undofile fails to delete
    165    end
    166  end)
    167 
    168  itp('overwrites an existing undo file', function()
    169    u_write_undo(nil, false, file_buffer, buffer_hash)
    170    local correct_name = ffi.string(undo.u_get_undo_file_name(file_buffer.b_ffname, false))
    171 
    172    local file_last_modified = uv.fs_stat(correct_name).mtime.sec
    173 
    174    sleep(1000) -- Ensure difference in timestamps.
    175    file_buffer.b_u_numhead = 1 -- Mark it as if there are changes
    176    u_write_undo(nil, false, file_buffer, buffer_hash)
    177 
    178    local file_last_modified_2 = uv.fs_stat(correct_name).mtime.sec
    179 
    180    -- print(file_last_modified, file_last_modified_2)
    181    neq(file_last_modified, file_last_modified_2)
    182    local success, err = os.remove(correct_name) -- delete the file now that we're done with it.
    183    if not success then
    184      print(err) -- inform tester if undofile fails to delete
    185    end
    186  end)
    187 
    188  itp('does not overwrite an existing file that is not an undo file', function()
    189    -- TODO: write test
    190  end)
    191 
    192  itp('does not overwrite an existing file that has the wrong permissions', function()
    193    -- TODO: write test
    194  end)
    195 
    196  itp('does not write an undo file if there is no undo information for the buffer', function()
    197    file_buffer.b_u_numhead = 0 -- Mark it as if there is no undo information
    198    local correct_name = ffi.string(undo.u_get_undo_file_name(file_buffer.b_ffname, false))
    199 
    200    local existing_file = io.open(correct_name, 'r')
    201    if existing_file then
    202      existing_file:close()
    203      os.remove(correct_name)
    204    end
    205    u_write_undo(nil, false, file_buffer, buffer_hash)
    206    local undo_file = io.open(correct_name, 'r')
    207 
    208    eq(undo_file, nil)
    209  end)
    210 end)