xref: /vim-8.2.3635/src/testdir/test_swap.vim (revision a0122dcd)
1" Tests for the swap feature
2
3source check.vim
4source shared.vim
5source term_util.vim
6
7func s:swapname()
8  return trim(execute('swapname'))
9endfunc
10
11" Tests for 'directory' option.
12func Test_swap_directory()
13  CheckUnix
14
15  let content = ['start of testfile',
16	      \ 'line 2 Abcdefghij',
17	      \ 'line 3 Abcdefghij',
18	      \ 'end of testfile']
19  call writefile(content, 'Xtest1')
20
21  "  '.', swap file in the same directory as file
22  set dir=.,~
23
24  " Verify that the swap file doesn't exist in the current directory
25  call assert_equal([], glob(".Xtest1*.swp", 1, 1, 1))
26  edit Xtest1
27  let swfname = s:swapname()
28  call assert_equal([swfname], glob(swfname, 1, 1, 1))
29
30  " './dir', swap file in a directory relative to the file
31  set dir=./Xtest2,.,~
32
33  call mkdir("Xtest2")
34  edit Xtest1
35  call assert_equal([], glob(swfname, 1, 1, 1))
36  let swfname = "Xtest2/Xtest1.swp"
37  call assert_equal(swfname, s:swapname())
38  call assert_equal([swfname], glob("Xtest2/*", 1, 1, 1))
39
40  " 'dir', swap file in directory relative to the current dir
41  set dir=Xtest.je,~
42
43  call mkdir("Xtest.je")
44  call writefile(content, 'Xtest2/Xtest3')
45  edit Xtest2/Xtest3
46  call assert_equal(["Xtest2/Xtest3"], glob("Xtest2/*", 1, 1, 1))
47  let swfname = "Xtest.je/Xtest3.swp"
48  call assert_equal(swfname, s:swapname())
49  call assert_equal([swfname], glob("Xtest.je/*", 1, 1, 1))
50
51  set dir&
52  call delete("Xtest1")
53  call delete("Xtest2", "rf")
54  call delete("Xtest.je", "rf")
55endfunc
56
57func Test_swap_group()
58  CheckUnix
59
60  let groups = split(system('groups'))
61  if len(groups) <= 1
62    throw 'Skipped: need at least two groups, got ' . string(groups)
63  endif
64
65  try
66    call delete('Xtest')
67    split Xtest
68    call setline(1, 'just some text')
69    wq
70    if system('ls -l Xtest') !~ ' ' . groups[0] . ' \d'
71      throw 'Skipped: test file does not have the first group'
72    else
73      silent !chmod 640 Xtest
74      call system('chgrp ' . groups[1] . ' Xtest')
75      if system('ls -l Xtest') !~ ' ' . groups[1] . ' \d'
76	throw 'Skipped: cannot set second group on test file'
77      else
78	split Xtest
79	let swapname = s:swapname()
80	call assert_match('Xtest', swapname)
81	" Group of swapfile must now match original file.
82	call assert_match(' ' . groups[1] . ' \d', system('ls -l ' . swapname))
83
84	bwipe!
85      endif
86    endif
87  finally
88    call delete('Xtest')
89  endtry
90endfunc
91
92func Test_missing_dir()
93  call mkdir('Xswapdir')
94  exe 'set directory=' . getcwd() . '/Xswapdir'
95
96  call assert_equal('', glob('foo'))
97  call assert_equal('', glob('bar'))
98  edit foo/x.txt
99  " This should not give a warning for an existing swap file.
100  split bar/x.txt
101  only
102
103  " Delete the buffer so that swap file is removed before we try to delete the
104  " directory.  That fails on MS-Windows.
105  %bdelete!
106  set directory&
107  call delete('Xswapdir', 'rf')
108endfunc
109
110func Test_swapinfo()
111  new Xswapinfo
112  call setline(1, ['one', 'two', 'three'])
113  w
114  let fname = s:swapname()
115  call assert_match('Xswapinfo', fname)
116  let info = fname->swapinfo()
117
118  let ver = printf('VIM %d.%d', v:version / 100, v:version % 100)
119  call assert_equal(ver, info.version)
120
121  call assert_match('\w', info.user)
122  " host name is truncated to 39 bytes in the swap file
123  call assert_equal(hostname()[:38], info.host)
124  call assert_match('Xswapinfo', info.fname)
125  call assert_match(0, info.dirty)
126  call assert_equal(getpid(), info.pid)
127  call assert_match('^\d*$', info.mtime)
128  if has_key(info, 'inode')
129    call assert_match('\d', info.inode)
130  endif
131  bwipe!
132  call delete(fname)
133  call delete('Xswapinfo')
134
135  let info = swapinfo('doesnotexist')
136  call assert_equal('Cannot open file', info.error)
137
138  call writefile(['burp'], 'Xnotaswapfile')
139  let info = swapinfo('Xnotaswapfile')
140  call assert_equal('Cannot read file', info.error)
141  call delete('Xnotaswapfile')
142
143  call writefile([repeat('x', 10000)], 'Xnotaswapfile')
144  let info = swapinfo('Xnotaswapfile')
145  call assert_equal('Not a swap file', info.error)
146  call delete('Xnotaswapfile')
147endfunc
148
149func Test_swapname()
150  edit Xtest1
151  let expected = s:swapname()
152  call assert_equal(expected, swapname('%'))
153
154  new Xtest2
155  let buf = bufnr('%')
156  let expected = s:swapname()
157  wincmd p
158  call assert_equal(expected, buf->swapname())
159
160  new Xtest3
161  setlocal noswapfile
162  call assert_equal('', swapname('%'))
163
164  bwipe!
165  call delete('Xtest1')
166  call delete('Xtest2')
167  call delete('Xtest3')
168endfunc
169
170func Test_swapfile_delete()
171  autocmd! SwapExists
172  function s:swap_exists()
173    let v:swapchoice = s:swap_choice
174    let s:swapname = v:swapname
175    let s:filename = expand('<afile>')
176  endfunc
177  augroup test_swapfile_delete
178    autocmd!
179    autocmd SwapExists * call s:swap_exists()
180  augroup END
181
182
183  " Create a valid swapfile by editing a file.
184  split XswapfileText
185  call setline(1, ['one', 'two', 'three'])
186  write  " file is written, not modified
187  " read the swapfile as a Blob
188  let swapfile_name = swapname('%')
189  let swapfile_bytes = readfile(swapfile_name, 'B')
190
191  " Close the file and recreate the swap file.
192  " Now editing the file will run into the process still existing
193  quit
194  call writefile(swapfile_bytes, swapfile_name)
195  let s:swap_choice = 'e'
196  let s:swapname = ''
197  split XswapfileText
198  quit
199  call assert_equal(fnamemodify(swapfile_name, ':t'), fnamemodify(s:swapname, ':t'))
200
201  " This test won't work as root because root can successfully run kill(1, 0)
202  if !IsRoot()
203    " Write the swapfile with a modified PID, now it will be automatically
204    " deleted. Process one should never be Vim.
205    let swapfile_bytes[24:27] = 0z01000000
206    call writefile(swapfile_bytes, swapfile_name)
207    let s:swapname = ''
208    split XswapfileText
209    quit
210    call assert_equal('', s:swapname)
211  endif
212
213  " Now set the modified flag, the swap file will not be deleted
214  let swapfile_bytes[28 + 80 + 899] = 0x55
215  call writefile(swapfile_bytes, swapfile_name)
216  let s:swapname = ''
217  split XswapfileText
218  quit
219  call assert_equal(fnamemodify(swapfile_name, ':t'), fnamemodify(s:swapname, ':t'))
220
221  call delete('XswapfileText')
222  call delete(swapfile_name)
223  augroup test_swapfile_delete
224    autocmd!
225  augroup END
226  augroup! test_swapfile_delete
227endfunc
228
229func Test_swap_recover()
230  autocmd! SwapExists
231  augroup test_swap_recover
232    autocmd!
233    autocmd SwapExists * let v:swapchoice = 'r'
234  augroup END
235
236
237  call mkdir('Xswap')
238  let $Xswap = 'foo'  " Check for issue #4369.
239  set dir=Xswap//
240  " Create a valid swapfile by editing a file.
241  split Xswap/text
242  call setline(1, ['one', 'two', 'three'])
243  write  " file is written, not modified
244  " read the swapfile as a Blob
245  let swapfile_name = swapname('%')
246  let swapfile_bytes = readfile(swapfile_name, 'B')
247
248  " Close the file and recreate the swap file.
249  quit
250  call writefile(swapfile_bytes, swapfile_name)
251  " Edit the file again. This triggers recovery.
252  try
253    split Xswap/text
254  catch
255    " E308 should be caught, not E305.
256    call assert_exception('E308:')  " Original file may have been changed
257  endtry
258  " The file should be recovered.
259  call assert_equal(['one', 'two', 'three'], getline(1, 3))
260  quit!
261
262  call delete('Xswap/text')
263  call delete(swapfile_name)
264  call delete('Xswap', 'd')
265  unlet $Xswap
266  set dir&
267  augroup test_swap_recover
268    autocmd!
269  augroup END
270  augroup! test_swap_recover
271endfunc
272
273func Test_swap_recover_ext()
274  autocmd! SwapExists
275  augroup test_swap_recover_ext
276    autocmd!
277    autocmd SwapExists * let v:swapchoice = 'r'
278  augroup END
279
280  " Create a valid swapfile by editing a file with a special extension.
281  split Xtest.scr
282  call setline(1, ['one', 'two', 'three'])
283  write  " file is written, not modified
284  write  " write again to make sure the swapfile is created
285  " read the swapfile as a Blob
286  let swapfile_name = swapname('%')
287  let swapfile_bytes = readfile(swapfile_name, 'B')
288
289  " Close and delete the file and recreate the swap file.
290  quit
291  call delete('Xtest.scr')
292  call writefile(swapfile_bytes, swapfile_name)
293  " Edit the file again. This triggers recovery.
294  try
295    split Xtest.scr
296  catch
297    " E308 should be caught, not E306.
298    call assert_exception('E308:')  " Original file may have been changed
299  endtry
300  " The file should be recovered.
301  call assert_equal(['one', 'two', 'three'], getline(1, 3))
302  quit!
303
304  call delete('Xtest.scr')
305  call delete(swapfile_name)
306  augroup test_swap_recover_ext
307    autocmd!
308  augroup END
309  augroup! test_swap_recover_ext
310endfunc
311
312" Test for closing a split window automatically when a swap file is detected
313" and 'Q' is selected in the confirmation prompt.
314func Test_swap_split_win()
315  autocmd! SwapExists
316  augroup test_swap_splitwin
317    autocmd!
318    autocmd SwapExists * let v:swapchoice = 'q'
319  augroup END
320
321  " Create a valid swapfile by editing a file with a special extension.
322  split Xtest.scr
323  call setline(1, ['one', 'two', 'three'])
324  write  " file is written, not modified
325  write  " write again to make sure the swapfile is created
326  " read the swapfile as a Blob
327  let swapfile_name = swapname('%')
328  let swapfile_bytes = readfile(swapfile_name, 'B')
329
330  " Close and delete the file and recreate the swap file.
331  quit
332  call delete('Xtest.scr')
333  call writefile(swapfile_bytes, swapfile_name)
334  " Split edit the file again. This should fail to open the window
335  try
336    split Xtest.scr
337  catch
338    " E308 should be caught, not E306.
339    call assert_exception('E308:')  " Original file may have been changed
340  endtry
341  call assert_equal(1, winnr('$'))
342
343  call delete('Xtest.scr')
344  call delete(swapfile_name)
345
346  augroup test_swap_splitwin
347      autocmd!
348  augroup END
349  augroup! test_swap_splitwin
350endfunc
351
352" Test for selecting 'q' in the attention prompt
353func Test_swap_prompt_splitwin()
354  CheckRunVimInTerminal
355
356  call writefile(['foo bar'], 'Xfile1')
357  edit Xfile1
358  preserve  " should help to make sure the swap file exists
359
360  let buf = RunVimInTerminal('', {'rows': 20})
361  call term_sendkeys(buf, ":set nomore\n")
362  call term_sendkeys(buf, ":set noruler\n")
363  call term_sendkeys(buf, ":split Xfile1\n")
364  call TermWait(buf)
365  call WaitForAssert({-> assert_match('^\[O\]pen Read-Only, (E)dit anyway, (R)ecover, (Q)uit, (A)bort: $', term_getline(buf, 20))})
366  call term_sendkeys(buf, "q")
367  call TermWait(buf)
368  call term_sendkeys(buf, ":\<CR>")
369  call WaitForAssert({-> assert_match('^:$', term_getline(buf, 20))})
370  call term_sendkeys(buf, ":echomsg winnr('$')\<CR>")
371  call TermWait(buf)
372  call WaitForAssert({-> assert_match('^1$', term_getline(buf, 20))})
373  call StopVimInTerminal(buf)
374  %bwipe!
375  call delete('Xfile1')
376endfunc
377
378func Test_swap_symlink()
379  CheckUnix
380
381  call writefile(['text'], 'Xtestfile')
382  silent !ln -s -f Xtestfile Xtestlink
383
384  set dir=.
385
386  " Test that swap file uses the name of the file when editing through a
387  " symbolic link (so that editing the file twice is detected)
388  edit Xtestlink
389  call assert_match('Xtestfile\.swp$', s:swapname())
390  bwipe!
391
392  call mkdir('Xswapdir')
393  exe 'set dir=' . getcwd() . '/Xswapdir//'
394
395  " Check that this also works when 'directory' ends with '//'
396  edit Xtestlink
397  call assert_match('Xtestfile\.swp$', s:swapname())
398  bwipe!
399
400  set dir&
401  call delete('Xtestfile')
402  call delete('Xtestlink')
403  call delete('Xswapdir', 'rf')
404endfunc
405
406func s:get_unused_pid(base)
407  if has('job')
408    " Execute 'echo' as a temporary job, and return its pid as an unused pid.
409    if has('win32')
410      let cmd = 'cmd /c echo'
411    else
412      let cmd = 'echo'
413    endif
414    let j = job_start(cmd)
415    while job_status(j) ==# 'run'
416      sleep 10m
417    endwhile
418    if job_status(j) ==# 'dead'
419      return job_info(j).process
420    endif
421  endif
422  " Must add four for MS-Windows to see it as a different one.
423  return a:base + 4
424endfunc
425
426func s:blob_to_pid(b)
427  return a:b[3] * 16777216 + a:b[2] * 65536 + a:b[1] * 256 + a:b[0]
428endfunc
429
430func s:pid_to_blob(i)
431  let b = 0z
432  let b[0] = and(a:i, 0xff)
433  let b[1] = and(a:i / 256, 0xff)
434  let b[2] = and(a:i / 65536, 0xff)
435  let b[3] = and(a:i / 16777216, 0xff)
436  return b
437endfunc
438
439func Test_swap_auto_delete()
440  " Create a valid swapfile by editing a file with a special extension.
441  split Xtest.scr
442  call setline(1, ['one', 'two', 'three'])
443  write  " file is written, not modified
444  write  " write again to make sure the swapfile is created
445  " read the swapfile as a Blob
446  let swapfile_name = swapname('%')
447  let swapfile_bytes = readfile(swapfile_name, 'B')
448
449  " Forget about the file, recreate the swap file, then edit it again.  The
450  " swap file should be automatically deleted.
451  bwipe!
452  " Change the process ID to avoid the "still running" warning.
453  let swapfile_bytes[24:27] = s:pid_to_blob(s:get_unused_pid(
454        \ s:blob_to_pid(swapfile_bytes[24:27])))
455  call writefile(swapfile_bytes, swapfile_name)
456  edit Xtest.scr
457  " will end up using the same swap file after deleting the existing one
458  call assert_equal(swapfile_name, swapname('%'))
459  bwipe!
460
461  " create the swap file again, but change the host name so that it won't be
462  " deleted
463  autocmd! SwapExists
464  augroup test_swap_recover_ext
465    autocmd!
466    autocmd SwapExists * let v:swapchoice = 'e'
467  augroup END
468
469  " change the host name
470  let swapfile_bytes[28 + 40] = swapfile_bytes[28 + 40] + 2
471  call writefile(swapfile_bytes, swapfile_name)
472  edit Xtest.scr
473  call assert_equal(1, filereadable(swapfile_name))
474  " will use another same swap file name
475  call assert_notequal(swapfile_name, swapname('%'))
476  bwipe!
477
478  call delete('Xtest.scr')
479  call delete(swapfile_name)
480  augroup test_swap_recover_ext
481    autocmd!
482  augroup END
483  augroup! test_swap_recover_ext
484endfunc
485
486" vim: shiftwidth=2 sts=2 expandtab
487