undo_spec.lua 7.6 KB

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