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