test_swap.vim (16283B)
1 " Tests for the swap feature 2 3 source check.vim 4 source shared.vim 5 source term_util.vim 6 7 func s:swapname() 8 return trim(execute('swapname')) 9 endfunc 10 11 " Tests for 'directory' option. 12 func 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', 'D') 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", 'R') 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", 'R') 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 endfunc 53 54 func Test_swap_group() 55 CheckUnix 56 57 let groups = split(system('groups')) 58 if len(groups) <= 1 59 throw 'Skipped: need at least two groups, got ' . string(groups) 60 endif 61 62 try 63 call delete('Xtest') 64 split Xtest 65 call setline(1, 'just some text') 66 wq 67 if system('ls -l Xtest') !~ ' ' . groups[0] . ' \d' 68 throw 'Skipped: test file does not have the first group' 69 else 70 silent !chmod 640 Xtest 71 call system('chgrp ' . groups[1] . ' Xtest') 72 if system('ls -l Xtest') !~ ' ' . groups[1] . ' \d' 73 throw 'Skipped: cannot set second group on test file' 74 else 75 split Xtest 76 let swapname = substitute(execute('swapname'), '[[:space:]]', '', 'g') 77 call assert_match('Xtest', swapname) 78 " Group of swapfile must now match original file. 79 call assert_match(' ' . groups[1] . ' \d', system('ls -l ' . swapname)) 80 81 bwipe! 82 endif 83 endif 84 finally 85 call delete('Xtest') 86 endtry 87 endfunc 88 89 func Test_missing_dir() 90 call mkdir('Xswapdir') 91 exe 'set directory=' . getcwd() . '/Xswapdir' 92 93 call assert_equal('', glob('foo')) 94 call assert_equal('', glob('bar')) 95 edit foo/x.txt 96 " This should not give a warning for an existing swap file. 97 split bar/x.txt 98 only 99 100 " Delete the buffer so that swap file is removed before we try to delete the 101 " directory. That fails on MS-Windows. 102 %bdelete! 103 set directory& 104 call delete('Xswapdir', 'rf') 105 endfunc 106 107 func Test_swapinfo() 108 new Xswapinfo 109 call setline(1, ['one', 'two', 'three']) 110 w 111 let fname = s:swapname() 112 call assert_match('Xswapinfo', fname) 113 114 " Check the tail appears in the list from swapfilelist(). The path depends 115 " on the system. 116 let tail = fnamemodify(fname, ":t")->fnameescape() 117 let nr = 0 118 for name in swapfilelist() 119 if name =~ tail .. '$' 120 let nr += 1 121 endif 122 endfor 123 call assert_equal(1, nr, 'not found in ' .. string(swapfilelist())) 124 125 let info = fname->swapinfo() 126 let ver = printf('VIM %d.%d', v:version / 100, v:version % 100) 127 call assert_equal(ver, info.version) 128 129 call assert_match('\w', info.user) 130 " host name is truncated to 39 bytes in the swap file 131 call assert_equal(hostname()[:38], info.host) 132 call assert_match('Xswapinfo', info.fname) 133 call assert_match(0, info.dirty) 134 call assert_equal(getpid(), info.pid) 135 call assert_match('^\d*$', info.mtime) 136 if has_key(info, 'inode') 137 call assert_match('\d', info.inode) 138 endif 139 bwipe! 140 call delete(fname) 141 call delete('Xswapinfo') 142 143 let info = swapinfo('doesnotexist') 144 call assert_equal('Cannot open file', info.error) 145 146 call writefile(['burp'], 'Xnotaswapfile', 'D') 147 let info = swapinfo('Xnotaswapfile') 148 call assert_equal('Cannot read file', info.error) 149 call delete('Xnotaswapfile') 150 151 call writefile([repeat('x', 10000)], 'Xnotaswapfile') 152 let info = swapinfo('Xnotaswapfile') 153 call assert_equal('Not a swap file', info.error) 154 endfunc 155 156 func Test_swapname() 157 edit Xtest1 158 let expected = s:swapname() 159 call assert_equal(expected, swapname('%')) 160 161 new Xtest2 162 let buf = bufnr('%') 163 let expected = s:swapname() 164 wincmd p 165 call assert_equal(expected, buf->swapname()) 166 167 new Xtest3 168 setlocal noswapfile 169 call assert_equal('', swapname('%')) 170 171 bwipe! 172 call delete('Xtest1') 173 call delete('Xtest2') 174 call delete('Xtest3') 175 endfunc 176 177 func Test_swapfile_delete() 178 autocmd! SwapExists 179 function s:swap_exists() 180 let v:swapchoice = s:swap_choice 181 let s:swapname = v:swapname 182 let s:filename = expand('<afile>') 183 endfunc 184 augroup test_swapfile_delete 185 autocmd! 186 autocmd SwapExists * call s:swap_exists() 187 augroup END 188 189 190 " Create a valid swapfile by editing a file. 191 split XswapfileText 192 call setline(1, ['one', 'two', 'three']) 193 write " file is written, not modified 194 " read the swapfile as a Blob 195 let swapfile_name = swapname('%') 196 let swapfile_bytes = readfile(swapfile_name, 'B') 197 198 " Close the file and recreate the swap file. 199 " Now editing the file will run into the process still existing 200 quit 201 call writefile(swapfile_bytes, swapfile_name, 'D') 202 let s:swap_choice = 'e' 203 let s:swapname = '' 204 split XswapfileText 205 quit 206 call assert_equal(fnamemodify(swapfile_name, ':t'), fnamemodify(s:swapname, ':t')) 207 208 " This test won't work as root because root can successfully run kill(1, 0) 209 if !IsRoot() 210 " Write the swapfile with a modified PID, now it will be automatically 211 " deleted. Process 0x3fffffff most likely does not exist. 212 let swapfile_bytes[24:27] = 0zffffff3f 213 call writefile(swapfile_bytes, swapfile_name) 214 let s:swapname = '' 215 split XswapfileText 216 quit 217 call assert_equal('', s:swapname) 218 endif 219 220 " Now set the modified flag, the swap file will not be deleted 221 let swapfile_bytes[28 + 80 + 899] = 0x55 222 call writefile(swapfile_bytes, swapfile_name) 223 let s:swapname = '' 224 split XswapfileText 225 quit 226 call assert_equal(fnamemodify(swapfile_name, ':t'), fnamemodify(s:swapname, ':t')) 227 228 call delete('XswapfileText') 229 augroup test_swapfile_delete 230 autocmd! 231 augroup END 232 augroup! test_swapfile_delete 233 endfunc 234 235 func Test_swap_recover() 236 autocmd! SwapExists 237 augroup test_swap_recover 238 autocmd! 239 autocmd SwapExists * let v:swapchoice = 'r' 240 augroup END 241 242 call mkdir('Xswap', 'R') 243 let $Xswap = 'foo' " Check for issue #4369. 244 set dir=Xswap// 245 " Create a valid swapfile by editing a file. 246 split Xswap/text 247 call setline(1, ['one', 'two', 'three']) 248 write " file is written, not modified 249 " read the swapfile as a Blob 250 let swapfile_name = swapname('%') 251 let swapfile_bytes = readfile(swapfile_name, 'B') 252 253 " Close the file and recreate the swap file. 254 quit 255 call writefile(swapfile_bytes, swapfile_name, 'D') 256 " Edit the file again. This triggers recovery. 257 try 258 split Xswap/text 259 catch 260 " E308 should be caught, not E305. 261 call assert_exception('E308:') " Original file may have been changed 262 endtry 263 " The file should be recovered. 264 call assert_equal(['one', 'two', 'three'], getline(1, 3)) 265 quit! 266 267 unlet $Xswap 268 set dir& 269 augroup test_swap_recover 270 autocmd! 271 augroup END 272 augroup! test_swap_recover 273 endfunc 274 275 func Test_swap_recover_ext() 276 autocmd! SwapExists 277 augroup test_swap_recover_ext 278 autocmd! 279 autocmd SwapExists * let v:swapchoice = 'r' 280 augroup END 281 282 " Create a valid swapfile by editing a file with a special extension. 283 split Xtest.scr 284 call setline(1, ['one', 'two', 'three']) 285 write " file is written, not modified 286 write " write again to make sure the swapfile is created 287 " read the swapfile as a Blob 288 let swapfile_name = swapname('%') 289 let swapfile_bytes = readfile(swapfile_name, 'B') 290 291 " Close and delete the file and recreate the swap file. 292 quit 293 call delete('Xtest.scr') 294 call writefile(swapfile_bytes, swapfile_name, 'D') 295 " Edit the file again. This triggers recovery. 296 try 297 split Xtest.scr 298 catch 299 " E308 should be caught, not E306. 300 call assert_exception('E308:') " Original file may have been changed 301 endtry 302 " The file should be recovered. 303 call assert_equal(['one', 'two', 'three'], getline(1, 3)) 304 quit! 305 306 call delete('Xtest.scr') 307 augroup test_swap_recover_ext 308 autocmd! 309 augroup END 310 augroup! test_swap_recover_ext 311 endfunc 312 313 " Test for closing a split window automatically when a swap file is detected 314 " and 'Q' is selected in the confirmation prompt. 315 func Test_swap_split_win() 316 autocmd! SwapExists 317 augroup test_swap_splitwin 318 autocmd! 319 autocmd SwapExists * let v:swapchoice = 'q' 320 augroup END 321 322 " Create a valid swapfile by editing a file with a special extension. 323 split Xtest.scr 324 call setline(1, ['one', 'two', 'three']) 325 write " file is written, not modified 326 write " write again to make sure the swapfile is created 327 " read the swapfile as a Blob 328 let swapfile_name = swapname('%') 329 let swapfile_bytes = readfile(swapfile_name, 'B') 330 331 " Close and delete the file and recreate the swap file. 332 quit 333 call delete('Xtest.scr') 334 call writefile(swapfile_bytes, swapfile_name, 'D') 335 " Split edit the file again. This should fail to open the window 336 try 337 split Xtest.scr 338 catch 339 " E308 should be caught, not E306. 340 call assert_exception('E308:') " Original file may have been changed 341 endtry 342 call assert_equal(1, winnr('$')) 343 344 call delete('Xtest.scr') 345 346 augroup test_swap_splitwin 347 autocmd! 348 augroup END 349 augroup! test_swap_splitwin 350 endfunc 351 352 " Test for selecting 'q' in the attention prompt 353 func Test_swap_prompt_splitwin() 354 CheckRunVimInTerminal 355 356 call writefile(['foo bar'], 'Xfile1', 'D') 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 364 call term_sendkeys(buf, ":split Xfile1\n") 365 call TermWait(buf) 366 call WaitForAssert({-> assert_match('^\[O\]pen Read-Only, (E)dit anyway, (R)ecover, (Q)uit, (A)bort: $', term_getline(buf, 20))}) 367 call term_sendkeys(buf, "q") 368 call TermWait(buf) 369 call term_sendkeys(buf, ":\<CR>") 370 call WaitForAssert({-> assert_match('^:$', term_getline(buf, 20))}) 371 call term_sendkeys(buf, ":echomsg winnr('$')\<CR>") 372 call TermWait(buf) 373 call WaitForAssert({-> assert_match('^1$', term_getline(buf, 20))}) 374 call StopVimInTerminal(buf) 375 376 " This caused Vim to crash when typing "q" at the swap file prompt. 377 let buf = RunVimInTerminal('-c "au bufadd * let foo_w = wincol()"', {'rows': 18}) 378 call term_sendkeys(buf, ":e Xfile1\<CR>") 379 call WaitForAssert({-> assert_match('More', term_getline(buf, 18))}) 380 call term_sendkeys(buf, " ") 381 call WaitForAssert({-> assert_match('^\[O\]pen Read-Only, (E)dit anyway, (R)ecover, (Q)uit, (A)bort:', term_getline(buf, 18))}) 382 call term_sendkeys(buf, "q") 383 call TermWait(buf) 384 " check that Vim is still running 385 call term_sendkeys(buf, ":echo 'hello'\<CR>") 386 call WaitForAssert({-> assert_match('^hello', term_getline(buf, 18))}) 387 call term_sendkeys(buf, ":%bwipe!\<CR>") 388 call StopVimInTerminal(buf) 389 390 %bwipe! 391 endfunc 392 393 func Test_swap_symlink() 394 CheckUnix 395 396 call writefile(['text'], 'Xtestfile', 'D') 397 silent !ln -s -f Xtestfile Xtestlink 398 399 set dir=. 400 401 " Test that swap file uses the name of the file when editing through a 402 " symbolic link (so that editing the file twice is detected) 403 edit Xtestlink 404 call assert_match('Xtestfile\.swp$', s:swapname()) 405 bwipe! 406 407 call mkdir('Xswapdir', 'R') 408 exe 'set dir=' . getcwd() . '/Xswapdir//' 409 410 " Check that this also works when 'directory' ends with '//' 411 edit Xtestlink 412 call assert_match('Xswapdir[/\\]%.*testdir%Xtestfile\.swp$', s:swapname()) 413 bwipe! 414 415 set dir& 416 call delete('Xtestlink') 417 endfunc 418 419 func s:get_unused_pid(base) 420 if has('job') 421 " Execute 'echo' as a temporary job, and return its pid as an unused pid. 422 if has('win32') 423 let cmd = 'cmd /D /c echo' 424 else 425 let cmd = 'echo' 426 endif 427 let j = job_start(cmd) 428 while job_status(j) ==# 'run' 429 sleep 10m 430 endwhile 431 if job_status(j) ==# 'dead' 432 return job_info(j).process 433 endif 434 elseif has('nvim') 435 let j = jobstart('echo') 436 let pid = jobpid(j) 437 if jobwait([j])[0] >= 0 438 return pid 439 endif 440 endif 441 " Must add four for MS-Windows to see it as a different one. 442 return a:base + 4 443 endfunc 444 445 func s:blob_to_pid(b) 446 return a:b[3] * 16777216 + a:b[2] * 65536 + a:b[1] * 256 + a:b[0] 447 endfunc 448 449 func s:pid_to_blob(i) 450 let b = 0z 451 let b[0] = and(a:i, 0xff) 452 let b[1] = and(a:i / 256, 0xff) 453 let b[2] = and(a:i / 65536, 0xff) 454 let b[3] = and(a:i / 16777216, 0xff) 455 return b 456 endfunc 457 458 func Test_swap_auto_delete() 459 " Create a valid swapfile by editing a file with a special extension. 460 split Xtest.scr 461 call setline(1, ['one', 'two', 'three']) 462 write " file is written, not modified 463 write " write again to make sure the swapfile is created 464 " read the swapfile as a Blob 465 let swapfile_name = swapname('%') 466 let swapfile_bytes = readfile(swapfile_name, 'B') 467 468 " Forget about the file, recreate the swap file, then edit it again. The 469 " swap file should be automatically deleted. 470 bwipe! 471 " Change the process ID to avoid the "still running" warning. 472 let swapfile_bytes[24:27] = s:pid_to_blob(s:get_unused_pid( 473 \ s:blob_to_pid(swapfile_bytes[24:27]))) 474 call writefile(swapfile_bytes, swapfile_name, 'D') 475 edit Xtest.scr 476 " will end up using the same swap file after deleting the existing one 477 call assert_equal(swapfile_name, swapname('%')) 478 bwipe! 479 480 " create the swap file again, but change the host name so that it won't be 481 " deleted 482 autocmd! SwapExists 483 augroup test_swap_recover_ext 484 autocmd! 485 autocmd SwapExists * let v:swapchoice = 'e' 486 augroup END 487 488 " change the host name 489 let swapfile_bytes[28 + 40] = swapfile_bytes[28 + 40] + 2 490 call writefile(swapfile_bytes, swapfile_name) 491 edit Xtest.scr 492 call assert_equal(1, filereadable(swapfile_name)) 493 " will use another same swap file name 494 call assert_notequal(swapfile_name, swapname('%')) 495 bwipe! 496 497 call delete('Xtest.scr') 498 augroup test_swap_recover_ext 499 autocmd! 500 augroup END 501 augroup! test_swap_recover_ext 502 endfunc 503 504 " Test for renaming a buffer when the swap file is deleted out-of-band 505 func Test_missing_swap_file() 506 CheckUnix 507 new Xfile2 508 call delete(swapname('')) 509 call assert_fails('file Xfile3', 'E301:') 510 call assert_equal('Xfile3', bufname()) 511 call assert_true(bufexists('Xfile2')) 512 call assert_true(bufexists('Xfile3')) 513 %bw! 514 endfunc 515 516 " Test for :preserve command 517 func Test_preserve() 518 new Xfile4 519 setlocal noswapfile 520 call assert_fails('preserve', 'E313:') 521 bw! 522 endfunc 523 524 " Test for the v:swapchoice variable 525 func Test_swapchoice() 526 call writefile(['aaa', 'bbb'], 'Xfile5', 'D') 527 edit Xfile5 528 preserve 529 let swapfname = swapname('') 530 let b = readblob(swapfname) 531 bw! 532 call writefile(b, swapfname, 'D') 533 534 autocmd! SwapExists 535 536 " Test for v:swapchoice = 'o' (readonly) 537 augroup test_swapchoice 538 autocmd! 539 autocmd SwapExists * let v:swapchoice = 'o' 540 augroup END 541 edit Xfile5 542 call assert_true(&readonly) 543 call assert_equal(['aaa', 'bbb'], getline(1, '$')) 544 %bw! 545 call assert_true(filereadable(swapfname)) 546 547 " Test for v:swapchoice = 'a' (abort) 548 augroup test_swapchoice 549 autocmd! 550 autocmd SwapExists * let v:swapchoice = 'a' 551 augroup END 552 try 553 edit Xfile5 554 catch /^Vim:Interrupt$/ 555 endtry 556 call assert_equal('', @%) 557 call assert_true(bufexists('Xfile5')) 558 %bw! 559 call assert_true(filereadable(swapfname)) 560 561 " Test for v:swapchoice = 'd' (delete) 562 augroup test_swapchoice 563 autocmd! 564 autocmd SwapExists * let v:swapchoice = 'd' 565 augroup END 566 edit Xfile5 567 call assert_equal('Xfile5', @%) 568 %bw! 569 call assert_false(filereadable(swapfname)) 570 571 call delete(swapfname) 572 augroup test_swapchoice 573 autocmd! 574 augroup END 575 augroup! test_swapchoice 576 endfunc 577 578 func Test_no_swap_file() 579 call assert_equal("\nNo swap file", execute('swapname')) 580 endfunc 581 582 " vim: shiftwidth=2 sts=2 expandtab