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 0x3fffffff most likely does not exist. 205 let swapfile_bytes[24:27] = 0zffffff3f 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 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 call delete('Xfile1') 392endfunc 393 394func Test_swap_symlink() 395 CheckUnix 396 397 call writefile(['text'], 'Xtestfile') 398 silent !ln -s -f Xtestfile Xtestlink 399 400 set dir=. 401 402 " Test that swap file uses the name of the file when editing through a 403 " symbolic link (so that editing the file twice is detected) 404 edit Xtestlink 405 call assert_match('Xtestfile\.swp$', s:swapname()) 406 bwipe! 407 408 call mkdir('Xswapdir') 409 exe 'set dir=' . getcwd() . '/Xswapdir//' 410 411 " Check that this also works when 'directory' ends with '//' 412 edit Xtestlink 413 call assert_match('Xswapdir[/\\]%.*testdir%Xtestfile\.swp$', s:swapname()) 414 bwipe! 415 416 set dir& 417 call delete('Xtestfile') 418 call delete('Xtestlink') 419 call delete('Xswapdir', 'rf') 420endfunc 421 422func s:get_unused_pid(base) 423 if has('job') 424 " Execute 'echo' as a temporary job, and return its pid as an unused pid. 425 if has('win32') 426 let cmd = 'cmd /c echo' 427 else 428 let cmd = 'echo' 429 endif 430 let j = job_start(cmd) 431 while job_status(j) ==# 'run' 432 sleep 10m 433 endwhile 434 if job_status(j) ==# 'dead' 435 return job_info(j).process 436 endif 437 endif 438 " Must add four for MS-Windows to see it as a different one. 439 return a:base + 4 440endfunc 441 442func s:blob_to_pid(b) 443 return a:b[3] * 16777216 + a:b[2] * 65536 + a:b[1] * 256 + a:b[0] 444endfunc 445 446func s:pid_to_blob(i) 447 let b = 0z 448 let b[0] = and(a:i, 0xff) 449 let b[1] = and(a:i / 256, 0xff) 450 let b[2] = and(a:i / 65536, 0xff) 451 let b[3] = and(a:i / 16777216, 0xff) 452 return b 453endfunc 454 455func Test_swap_auto_delete() 456 " Create a valid swapfile by editing a file with a special extension. 457 split Xtest.scr 458 call setline(1, ['one', 'two', 'three']) 459 write " file is written, not modified 460 write " write again to make sure the swapfile is created 461 " read the swapfile as a Blob 462 let swapfile_name = swapname('%') 463 let swapfile_bytes = readfile(swapfile_name, 'B') 464 465 " Forget about the file, recreate the swap file, then edit it again. The 466 " swap file should be automatically deleted. 467 bwipe! 468 " Change the process ID to avoid the "still running" warning. 469 let swapfile_bytes[24:27] = s:pid_to_blob(s:get_unused_pid( 470 \ s:blob_to_pid(swapfile_bytes[24:27]))) 471 call writefile(swapfile_bytes, swapfile_name) 472 edit Xtest.scr 473 " will end up using the same swap file after deleting the existing one 474 call assert_equal(swapfile_name, swapname('%')) 475 bwipe! 476 477 " create the swap file again, but change the host name so that it won't be 478 " deleted 479 autocmd! SwapExists 480 augroup test_swap_recover_ext 481 autocmd! 482 autocmd SwapExists * let v:swapchoice = 'e' 483 augroup END 484 485 " change the host name 486 let swapfile_bytes[28 + 40] = swapfile_bytes[28 + 40] + 2 487 call writefile(swapfile_bytes, swapfile_name) 488 edit Xtest.scr 489 call assert_equal(1, filereadable(swapfile_name)) 490 " will use another same swap file name 491 call assert_notequal(swapfile_name, swapname('%')) 492 bwipe! 493 494 call delete('Xtest.scr') 495 call delete(swapfile_name) 496 augroup test_swap_recover_ext 497 autocmd! 498 augroup END 499 augroup! test_swap_recover_ext 500endfunc 501 502" Test for renaming a buffer when the swap file is deleted out-of-band 503func Test_missing_swap_file() 504 CheckUnix 505 new Xfile2 506 call delete(swapname('')) 507 call assert_fails('file Xfile3', 'E301:') 508 call assert_equal('Xfile3', bufname()) 509 call assert_true(bufexists('Xfile2')) 510 call assert_true(bufexists('Xfile3')) 511 %bw! 512endfunc 513 514" Test for :preserve command 515func Test_preserve() 516 new Xfile4 517 setlocal noswapfile 518 call assert_fails('preserve', 'E313:') 519 bw! 520endfunc 521 522" Test for the v:swapchoice variable 523func Test_swapchoice() 524 call writefile(['aaa', 'bbb'], 'Xfile5') 525 edit Xfile5 526 preserve 527 let swapfname = swapname('') 528 let b = readblob(swapfname) 529 bw! 530 call writefile(b, swapfname) 531 532 autocmd! SwapExists 533 534 " Test for v:swapchoice = 'o' (readonly) 535 augroup test_swapchoice 536 autocmd! 537 autocmd SwapExists * let v:swapchoice = 'o' 538 augroup END 539 edit Xfile5 540 call assert_true(&readonly) 541 call assert_equal(['aaa', 'bbb'], getline(1, '$')) 542 %bw! 543 call assert_true(filereadable(swapfname)) 544 545 " Test for v:swapchoice = 'a' (abort) 546 augroup test_swapchoice 547 autocmd! 548 autocmd SwapExists * let v:swapchoice = 'a' 549 augroup END 550 try 551 edit Xfile5 552 catch /^Vim:Interrupt$/ 553 endtry 554 call assert_equal('', @%) 555 call assert_true(bufexists('Xfile5')) 556 %bw! 557 call assert_true(filereadable(swapfname)) 558 559 " Test for v:swapchoice = 'd' (delete) 560 augroup test_swapchoice 561 autocmd! 562 autocmd SwapExists * let v:swapchoice = 'd' 563 augroup END 564 edit Xfile5 565 call assert_equal('Xfile5', @%) 566 %bw! 567 call assert_false(filereadable(swapfname)) 568 569 call delete('Xfile5') 570 call delete(swapfname) 571 augroup test_swapchoice 572 autocmd! 573 augroup END 574 augroup! test_swapchoice 575endfunc 576 577func Test_no_swap_file() 578 call assert_equal("\nNo swap file", execute('swapname')) 579endfunc 580 581" vim: shiftwidth=2 sts=2 expandtab 582