undo_spec.lua 7.3 KB

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