shada_spec.lua 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. -- Other ShaDa tests
  2. local t = require('test.testutil')
  3. local n = require('test.functional.testnvim')()
  4. local t_shada = require('test.functional.shada.testutil')
  5. local uv = vim.uv
  6. local paths = t.paths
  7. local api, nvim_command, fn, eq = n.api, n.command, n.fn, t.eq
  8. local write_file, set_session, exc_exec = t.write_file, n.set_session, n.exc_exec
  9. local is_os = t.is_os
  10. local skip = t.skip
  11. local reset, clear, get_shada_rw = t_shada.reset, t_shada.clear, t_shada.get_shada_rw
  12. local read_shada_file = t_shada.read_shada_file
  13. local wshada, _, shada_fname, clean = get_shada_rw('Xtest-functional-shada-shada.shada')
  14. local dirname = 'Xtest-functional-shada-shada.d'
  15. local dirshada = dirname .. '/main.shada'
  16. describe('ShaDa support code', function()
  17. before_each(reset)
  18. after_each(function()
  19. clear()
  20. clean()
  21. uv.fs_rmdir(dirname)
  22. end)
  23. it('preserves `s` item size limit with unknown entries', function()
  24. wshada(
  25. '\100\000\207\000\000\000\000\000\000\004\000\218\003\253'
  26. .. ('-'):rep(1024 - 3)
  27. .. '\100\000\207\000\000\000\000\000\000\004\001\218\003\254'
  28. .. ('-'):rep(1025 - 3)
  29. )
  30. eq(0, exc_exec('wshada ' .. shada_fname))
  31. local found = 0
  32. for _, v in ipairs(read_shada_file(shada_fname)) do
  33. if v.type == 100 then
  34. found = found + 1
  35. end
  36. end
  37. eq(2, found)
  38. eq(0, exc_exec('set shada-=s10 shada+=s1'))
  39. eq(0, exc_exec('wshada ' .. shada_fname))
  40. found = 0
  41. for _, v in ipairs(read_shada_file(shada_fname)) do
  42. if v.type == 100 then
  43. found = found + 1
  44. end
  45. end
  46. eq(1, found)
  47. end)
  48. it('preserves `s` item size limit with instance history entries', function()
  49. local hist1 = ('-'):rep(1024 - 5)
  50. local hist2 = ('-'):rep(1025 - 5)
  51. nvim_command('set shada-=s10 shada+=s1')
  52. fn.histadd(':', hist1)
  53. fn.histadd(':', hist2)
  54. eq(0, exc_exec('wshada ' .. shada_fname))
  55. local found = 0
  56. for _, v in ipairs(read_shada_file(shada_fname)) do
  57. if v.type == 4 then
  58. found = found + 1
  59. eq(hist1, v.value[2])
  60. end
  61. end
  62. eq(1, found)
  63. end)
  64. it('leaves .tmp.a in-place when there is error in original ShaDa', function()
  65. wshada('Some text file')
  66. eq(
  67. 'Vim(wshada):E576: Error while reading ShaDa file: last entry specified that it occupies 109 bytes, but file ended earlier',
  68. exc_exec('wshada ' .. shada_fname)
  69. )
  70. eq(1, read_shada_file(shada_fname .. '.tmp.a')[1].type)
  71. end)
  72. it(
  73. 'does not leave .tmp.a in-place when there is error in original ShaDa, but writing with bang',
  74. function()
  75. wshada('Some text file')
  76. eq(0, exc_exec('wshada! ' .. shada_fname))
  77. eq(1, read_shada_file(shada_fname)[1].type)
  78. eq(nil, uv.fs_stat(shada_fname .. '.tmp.a'))
  79. end
  80. )
  81. it('leaves .tmp.b in-place when there is error in original ShaDa and it has .tmp.a', function()
  82. wshada('Some text file')
  83. eq(
  84. 'Vim(wshada):E576: Error while reading ShaDa file: last entry specified that it occupies 109 bytes, but file ended earlier',
  85. exc_exec('wshada ' .. shada_fname)
  86. )
  87. eq(
  88. 'Vim(wshada):E576: Error while reading ShaDa file: last entry specified that it occupies 109 bytes, but file ended earlier',
  89. exc_exec('wshada ' .. shada_fname)
  90. )
  91. eq(1, read_shada_file(shada_fname .. '.tmp.a')[1].type)
  92. eq(1, read_shada_file(shada_fname .. '.tmp.b')[1].type)
  93. end)
  94. it(
  95. 'leaves .tmp.z in-place when there is error in original ShaDa and it has .tmp.a … .tmp.x',
  96. function()
  97. wshada('Some text file')
  98. local i = ('a'):byte()
  99. while i < ('z'):byte() do
  100. write_file(shada_fname .. ('.tmp.%c'):format(i), 'Some text file', true)
  101. i = i + 1
  102. end
  103. eq(
  104. 'Vim(wshada):E576: Error while reading ShaDa file: last entry specified that it occupies 109 bytes, but file ended earlier',
  105. exc_exec('wshada ' .. shada_fname)
  106. )
  107. eq(1, read_shada_file(shada_fname .. '.tmp.z')[1].type)
  108. end
  109. )
  110. it('errors out when there are .tmp.a … .tmp.z ShaDa files', function()
  111. wshada('')
  112. local i = ('a'):byte()
  113. while i <= ('z'):byte() do
  114. write_file(shada_fname .. ('.tmp.%c'):format(i), '', true)
  115. i = i + 1
  116. end
  117. eq(
  118. 'Vim(wshada):E138: All Xtest-functional-shada-shada.shada.tmp.X files exist, cannot write ShaDa file!',
  119. exc_exec('wshada ' .. shada_fname)
  120. )
  121. end)
  122. it('reads correctly various timestamps', function()
  123. local msgpack = {
  124. '\100', -- Positive fixnum 100
  125. '\204\255', -- uint 8 255
  126. '\205\010\003', -- uint 16 2563
  127. '\206\255\010\030\004', -- uint 32 4278853124
  128. '\207\005\100\060\250\255\010\030\004', -- uint 64 388502516579048964
  129. }
  130. local s = '\100'
  131. local e = '\001\192'
  132. wshada(s .. table.concat(msgpack, e .. s) .. e)
  133. eq(0, exc_exec('wshada ' .. shada_fname))
  134. local found = 0
  135. local typ = vim.mpack.decode(s)
  136. for _, v in ipairs(read_shada_file(shada_fname)) do
  137. if v.type == typ then
  138. found = found + 1
  139. eq(vim.mpack.decode(msgpack[found]), v.timestamp)
  140. end
  141. end
  142. eq(#msgpack, found)
  143. end)
  144. local marklike = { [7] = true, [8] = true, [10] = true, [11] = true }
  145. local find_file = function(fname)
  146. local found = {}
  147. for _, v in ipairs(read_shada_file(shada_fname)) do
  148. if marklike[v.type] and v.value.f == fname then
  149. found[v.type] = (found[v.type] or 0) + 1
  150. elseif v.type == 9 then
  151. for _, b in ipairs(v.value) do
  152. if b.f == fname then
  153. found[v.type] = (found[v.type] or 0) + 1
  154. end
  155. end
  156. end
  157. end
  158. return found
  159. end
  160. it('correctly uses shada-r option', function()
  161. nvim_command('set shellslash')
  162. api.nvim_set_var('__home', paths.test_source_path)
  163. nvim_command('let $HOME = __home')
  164. nvim_command('unlet __home')
  165. nvim_command('edit ~/README.md')
  166. nvim_command('normal! GmAggmaAabc')
  167. nvim_command('undo')
  168. nvim_command('set shada+=%')
  169. nvim_command('wshada! ' .. shada_fname)
  170. local readme_fname = fn.resolve(paths.test_source_path) .. '/README.md'
  171. eq({ [7] = 2, [8] = 2, [9] = 1, [10] = 4, [11] = 1 }, find_file(readme_fname))
  172. nvim_command('set shada+=r~')
  173. nvim_command('wshada! ' .. shada_fname)
  174. eq({}, find_file(readme_fname))
  175. nvim_command('set shada-=r~')
  176. nvim_command('wshada! ' .. shada_fname)
  177. eq({ [7] = 2, [8] = 2, [9] = 1, [10] = 4, [11] = 1 }, find_file(readme_fname))
  178. nvim_command('set shada+=r' .. fn.escape(fn.escape(paths.test_source_path, '$~'), ' "\\,'))
  179. nvim_command('wshada! ' .. shada_fname)
  180. eq({}, find_file(readme_fname))
  181. end)
  182. it('correctly ignores case with shada-r option', function()
  183. nvim_command('set shellslash')
  184. local pwd = fn.getcwd()
  185. local relfname = 'абв/test'
  186. local fname = pwd .. '/' .. relfname
  187. api.nvim_set_var('__fname', fname)
  188. nvim_command('silent! edit `=__fname`')
  189. fn.setline(1, { 'a', 'b', 'c', 'd' })
  190. nvim_command('normal! GmAggmaAabc')
  191. nvim_command('undo')
  192. nvim_command('set shada+=%')
  193. nvim_command('wshada! ' .. shada_fname)
  194. eq({ [7] = 2, [8] = 2, [9] = 1, [10] = 4, [11] = 2 }, find_file(fname))
  195. nvim_command('set shada+=r' .. pwd .. '/АБВ')
  196. nvim_command('wshada! ' .. shada_fname)
  197. eq({}, find_file(fname))
  198. end)
  199. it('is able to set &shada after &viminfo', function()
  200. api.nvim_set_option_value('viminfo', "'10", {})
  201. eq("'10", api.nvim_get_option_value('viminfo', {}))
  202. eq("'10", api.nvim_get_option_value('shada', {}))
  203. api.nvim_set_option_value('shada', '', {})
  204. eq('', api.nvim_get_option_value('viminfo', {}))
  205. eq('', api.nvim_get_option_value('shada', {}))
  206. end)
  207. it('is able to set all& after setting &shada', function()
  208. api.nvim_set_option_value('shada', "'10", {})
  209. eq("'10", api.nvim_get_option_value('viminfo', {}))
  210. eq("'10", api.nvim_get_option_value('shada', {}))
  211. nvim_command('set all&')
  212. eq("!,'100,<50,s10,h", api.nvim_get_option_value('viminfo', {}))
  213. eq("!,'100,<50,s10,h", api.nvim_get_option_value('shada', {}))
  214. end)
  215. it('is able to set &shada after &viminfo using :set', function()
  216. nvim_command("set viminfo='10")
  217. eq("'10", api.nvim_get_option_value('viminfo', {}))
  218. eq("'10", api.nvim_get_option_value('shada', {}))
  219. nvim_command('set shada=')
  220. eq('', api.nvim_get_option_value('viminfo', {}))
  221. eq('', api.nvim_get_option_value('shada', {}))
  222. end)
  223. it('setting &shada gives proper error message on missing number', function()
  224. eq([[Vim(set):E526: Missing number after <">: shada="]], exc_exec([[set shada=\"]]))
  225. for _, c in ipairs({ "'", '/', ':', '<', '@', 's' }) do
  226. eq(
  227. ([[Vim(set):E526: Missing number after <%s>: shada=%s]]):format(c, c),
  228. exc_exec(([[set shada=%s]]):format(c))
  229. )
  230. end
  231. end)
  232. it('does not crash when ShaDa file directory is not writable', function()
  233. skip(is_os('win'))
  234. fn.mkdir(dirname, '', '0')
  235. eq(0, fn.filewritable(dirname))
  236. reset { shadafile = dirshada, args = { '--cmd', 'set shada=' } }
  237. api.nvim_set_option_value('shada', "'10", {})
  238. eq(
  239. 'Vim(wshada):E886: System error while opening ShaDa file '
  240. .. 'Xtest-functional-shada-shada.d/main.shada for reading to merge '
  241. .. 'before writing it: permission denied',
  242. exc_exec('wshada')
  243. )
  244. api.nvim_set_option_value('shada', '', {})
  245. end)
  246. end)
  247. describe('ShaDa support code', function()
  248. it('does not write NONE file', function()
  249. local session = n.new_session(false, {
  250. merge = false,
  251. args = { '-u', 'NONE', '-i', 'NONE', '--embed', '--headless', '--cmd', 'qall' },
  252. })
  253. session:close()
  254. eq(nil, uv.fs_stat('NONE'))
  255. eq(nil, uv.fs_stat('NONE.tmp.a'))
  256. end)
  257. it('does not read NONE file', function()
  258. write_file('NONE', '\005\001\015\131\161na\162rX\194\162rc\145\196\001-')
  259. local session = n.new_session(
  260. false,
  261. { merge = false, args = { '-u', 'NONE', '-i', 'NONE', '--embed', '--headless' } }
  262. )
  263. set_session(session)
  264. eq('', fn.getreg('a'))
  265. session:close()
  266. os.remove('NONE')
  267. end)
  268. end)