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