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)