1" Tests for the undo tree. 2" Since this script is sourced we need to explicitly break changes up in 3" undo-able pieces. Do that by setting 'undolevels'. 4" Also tests :earlier and :later. 5 6func Test_undotree() 7 new 8 9 normal! Aabc 10 set ul=100 11 let d = undotree() 12 call assert_equal(1, d.seq_last) 13 call assert_equal(1, d.seq_cur) 14 call assert_equal(0, d.save_last) 15 call assert_equal(0, d.save_cur) 16 call assert_equal(1, len(d.entries)) 17 call assert_equal(1, d.entries[0].newhead) 18 call assert_equal(1, d.entries[0].seq) 19 call assert_true(d.entries[0].time <= d.time_cur) 20 21 normal! Adef 22 set ul=100 23 let d = undotree() 24 call assert_equal(2, d.seq_last) 25 call assert_equal(2, d.seq_cur) 26 call assert_equal(0, d.save_last) 27 call assert_equal(0, d.save_cur) 28 call assert_equal(2, len(d.entries)) 29 call assert_equal(1, d.entries[0].seq) 30 call assert_equal(1, d.entries[1].newhead) 31 call assert_equal(2, d.entries[1].seq) 32 call assert_true(d.entries[1].time <= d.time_cur) 33 34 undo 35 set ul=100 36 let d = undotree() 37 call assert_equal(2, d.seq_last) 38 call assert_equal(1, d.seq_cur) 39 call assert_equal(0, d.save_last) 40 call assert_equal(0, d.save_cur) 41 call assert_equal(2, len(d.entries)) 42 call assert_equal(1, d.entries[0].seq) 43 call assert_equal(1, d.entries[1].curhead) 44 call assert_equal(1, d.entries[1].newhead) 45 call assert_equal(2, d.entries[1].seq) 46 call assert_true(d.entries[1].time == d.time_cur) 47 48 normal! Aghi 49 set ul=100 50 let d = undotree() 51 call assert_equal(3, d.seq_last) 52 call assert_equal(3, d.seq_cur) 53 call assert_equal(0, d.save_last) 54 call assert_equal(0, d.save_cur) 55 call assert_equal(2, len(d.entries)) 56 call assert_equal(1, d.entries[0].seq) 57 call assert_equal(2, d.entries[1].alt[0].seq) 58 call assert_equal(1, d.entries[1].newhead) 59 call assert_equal(3, d.entries[1].seq) 60 call assert_true(d.entries[1].time <= d.time_cur) 61 62 undo 63 set ul=100 64 let d = undotree() 65 call assert_equal(3, d.seq_last) 66 call assert_equal(1, d.seq_cur) 67 call assert_equal(0, d.save_last) 68 call assert_equal(0, d.save_cur) 69 call assert_equal(2, len(d.entries)) 70 call assert_equal(1, d.entries[0].seq) 71 call assert_equal(2, d.entries[1].alt[0].seq) 72 call assert_equal(1, d.entries[1].curhead) 73 call assert_equal(1, d.entries[1].newhead) 74 call assert_equal(3, d.entries[1].seq) 75 call assert_true(d.entries[1].time == d.time_cur) 76 77 w! Xtest 78 let d = undotree() 79 call assert_equal(1, d.save_cur) 80 call assert_equal(1, d.save_last) 81 call delete('Xtest') 82 bwipe! Xtest 83endfunc 84 85func FillBuffer() 86 for i in range(1,13) 87 put=i 88 " Set 'undolevels' to split undo. 89 exe "setg ul=" . &g:ul 90 endfor 91endfunc 92 93func Test_global_local_undolevels() 94 new one 95 set undolevels=5 96 call FillBuffer() 97 " will only undo the last 5 changes, end up with 13 - (5 + 1) = 7 lines 98 earlier 10 99 call assert_equal(5, &g:undolevels) 100 call assert_equal(-123456, &l:undolevels) 101 call assert_equal('7', getline('$')) 102 103 new two 104 setlocal undolevels=2 105 call FillBuffer() 106 " will only undo the last 2 changes, end up with 13 - (2 + 1) = 10 lines 107 earlier 10 108 call assert_equal(5, &g:undolevels) 109 call assert_equal(2, &l:undolevels) 110 call assert_equal('10', getline('$')) 111 112 setlocal ul=10 113 call assert_equal(5, &g:undolevels) 114 call assert_equal(10, &l:undolevels) 115 116 " Setting local value in "two" must not change local value in "one" 117 wincmd p 118 call assert_equal(5, &g:undolevels) 119 call assert_equal(-123456, &l:undolevels) 120 121 new three 122 setglobal ul=50 123 call assert_equal(50, &g:undolevels) 124 call assert_equal(-123456, &l:undolevels) 125 126 " Drop created windows 127 set ul& 128 new 129 only! 130endfunc 131 132func BackOne(expected) 133 call feedkeys('g-', 'xt') 134 call assert_equal(a:expected, getline(1)) 135endfunc 136 137func Test_undo_del_chars() 138 " Setup a buffer without creating undo entries 139 new 140 set ul=-1 141 call setline(1, ['123-456']) 142 set ul=100 143 1 144 call test_settime(100) 145 146 " Delete three characters and undo with g- 147 call feedkeys('x', 'xt') 148 call feedkeys('x', 'xt') 149 call feedkeys('x', 'xt') 150 call assert_equal('-456', getline(1)) 151 call BackOne('3-456') 152 call BackOne('23-456') 153 call BackOne('123-456') 154 call assert_fails("BackOne('123-456')") 155 156 :" Delete three other characters and go back in time with g- 157 call feedkeys('$x', 'xt') 158 call feedkeys('x', 'xt') 159 call feedkeys('x', 'xt') 160 call assert_equal('123-', getline(1)) 161 call test_settime(101) 162 163 call BackOne('123-4') 164 call BackOne('123-45') 165 " skips '123-456' because it's older 166 call BackOne('-456') 167 call BackOne('3-456') 168 call BackOne('23-456') 169 call BackOne('123-456') 170 call assert_fails("BackOne('123-456')") 171 normal 10g+ 172 call assert_equal('123-', getline(1)) 173 174 :" Jump two seconds and go some seconds forward and backward 175 call test_settime(103) 176 call feedkeys("Aa\<Esc>", 'xt') 177 call feedkeys("Ab\<Esc>", 'xt') 178 call feedkeys("Ac\<Esc>", 'xt') 179 call assert_equal('123-abc', getline(1)) 180 earlier 1s 181 call assert_equal('123-', getline(1)) 182 earlier 3s 183 call assert_equal('123-456', getline(1)) 184 later 1s 185 call assert_equal('123-', getline(1)) 186 later 1h 187 call assert_equal('123-abc', getline(1)) 188 189 close! 190endfunc 191 192func Test_undolist() 193 new 194 set ul=100 195 196 let a = execute('undolist') 197 call assert_equal("\nNothing to undo", a) 198 199 " 1 leaf (2 changes). 200 call feedkeys('achange1', 'xt') 201 call feedkeys('achange2', 'xt') 202 let a = execute('undolist') 203 call assert_match("^\nnumber changes when *saved\n *2 *2 .*$", a) 204 205 " 2 leaves. 206 call feedkeys('u', 'xt') 207 call feedkeys('achange3\<Esc>', 'xt') 208 let a = execute('undolist') 209 call assert_match("^\nnumber changes when *saved\n *2 *2 *.*\n *3 *2 .*$", a) 210 close! 211endfunc 212 213func Test_U_command() 214 new 215 set ul=100 216 call feedkeys("achange1\<Esc>", 'xt') 217 call feedkeys("achange2\<Esc>", 'xt') 218 norm! U 219 call assert_equal('', getline(1)) 220 norm! U 221 call assert_equal('change1change2', getline(1)) 222 close! 223endfunc 224 225func Test_undojoin() 226 new 227 call feedkeys("Goaaaa\<Esc>", 'xt') 228 call feedkeys("obbbb\<Esc>", 'xt') 229 call assert_equal(['aaaa', 'bbbb'], getline(2, '$')) 230 call feedkeys("u", 'xt') 231 call assert_equal(['aaaa'], getline(2, '$')) 232 call feedkeys("obbbb\<Esc>", 'xt') 233 undojoin 234 " Note: next change must not be as if typed 235 call feedkeys("occcc\<Esc>", 'x') 236 call assert_equal(['aaaa', 'bbbb', 'cccc'], getline(2, '$')) 237 call feedkeys("u", 'xt') 238 call assert_equal(['aaaa'], getline(2, '$')) 239 bwipe! 240endfunc 241 242func Test_undojoin_redo() 243 new 244 call setline(1, ['first line', 'second line']) 245 call feedkeys("ixx\<Esc>", 'xt') 246 call feedkeys(":undojoin | redo\<CR>", 'xt') 247 call assert_equal('xxfirst line', getline(1)) 248 call assert_equal('second line', getline(2)) 249 bwipe! 250endfunc 251 252func Test_undo_write() 253 call delete('Xtest') 254 split Xtest 255 call feedkeys("ione one one\<Esc>", 'xt') 256 w! 257 call feedkeys("otwo\<Esc>", 'xt') 258 call feedkeys("otwo\<Esc>", 'xt') 259 w 260 call feedkeys("othree\<Esc>", 'xt') 261 call assert_equal(['one one one', 'two', 'two', 'three'], getline(1, '$')) 262 earlier 1f 263 call assert_equal(['one one one', 'two', 'two'], getline(1, '$')) 264 earlier 1f 265 call assert_equal(['one one one'], getline(1, '$')) 266 earlier 1f 267 call assert_equal([''], getline(1, '$')) 268 later 1f 269 call assert_equal(['one one one'], getline(1, '$')) 270 later 1f 271 call assert_equal(['one one one', 'two', 'two'], getline(1, '$')) 272 later 1f 273 call assert_equal(['one one one', 'two', 'two', 'three'], getline(1, '$')) 274 275 close! 276 call delete('Xtest') 277 bwipe! Xtest 278endfunc 279 280func Test_insert_expr() 281 new 282 " calling setline() triggers undo sync 283 call feedkeys("oa\<Esc>", 'xt') 284 call feedkeys("ob\<Esc>", 'xt') 285 set ul=100 286 call feedkeys("o1\<Esc>a2\<C-R>=setline('.','1234')\<CR>\<CR>\<Esc>", 'x') 287 call assert_equal(['a', 'b', '120', '34'], getline(2, '$')) 288 call feedkeys("u", 'x') 289 call assert_equal(['a', 'b', '12'], getline(2, '$')) 290 call feedkeys("u", 'x') 291 call assert_equal(['a', 'b'], getline(2, '$')) 292 293 call feedkeys("oc\<Esc>", 'xt') 294 set ul=100 295 call feedkeys("o1\<Esc>a2\<C-R>=setline('.','1234')\<CR>\<CR>\<Esc>", 'x') 296 call assert_equal(['a', 'b', 'c', '120', '34'], getline(2, '$')) 297 call feedkeys("u", 'x') 298 call assert_equal(['a', 'b', 'c', '12'], getline(2, '$')) 299 300 call feedkeys("od\<Esc>", 'xt') 301 set ul=100 302 call feedkeys("o1\<Esc>a2\<C-R>=string(123)\<CR>\<Esc>", 'x') 303 call assert_equal(['a', 'b', 'c', '12', 'd', '12123'], getline(2, '$')) 304 call feedkeys("u", 'x') 305 call assert_equal(['a', 'b', 'c', '12', 'd'], getline(2, '$')) 306 307 close! 308endfunc 309 310func Test_undofile_earlier() 311 " Issue #1254 312 " create undofile with timestamps older than Vim startup time. 313 let t0 = localtime() - 43200 314 call test_settime(t0) 315 new Xfile 316 call feedkeys("ione\<Esc>", 'xt') 317 set ul=100 318 call test_settime(t0 + 1) 319 call feedkeys("otwo\<Esc>", 'xt') 320 set ul=100 321 call test_settime(t0 + 2) 322 call feedkeys("othree\<Esc>", 'xt') 323 set ul=100 324 w 325 wundo Xundofile 326 bwipe! 327 " restore normal timestamps. 328 call test_settime(0) 329 new Xfile 330 rundo Xundofile 331 earlier 1d 332 call assert_equal('', getline(1)) 333 bwipe! 334 call delete('Xfile') 335 call delete('Xundofile') 336endfunc 337 338" Check that reading a truncted undo file doesn't hang. 339func Test_undofile_truncated() 340 new 341 call setline(1, 'hello') 342 set ul=100 343 wundo Xundofile 344 let contents = readfile('Xundofile', 'B') 345 346 " try several sizes 347 for size in range(20, 500, 33) 348 call writefile(contents[0:size], 'Xundofile') 349 call assert_fails('rundo Xundofile', 'E825:') 350 endfor 351 352 bwipe! 353 call delete('Xundofile') 354endfunc 355 356" Test for undo working properly when executing commands from a register. 357" Also test this in an empty buffer. 358func Test_cmd_in_reg_undo() 359 enew! 360 let @a = "Ox\<Esc>jAy\<Esc>kdd" 361 edit +/^$ test_undo.vim 362 normal @au 363 call assert_equal(0, &modified) 364 return 365 new 366 normal @au 367 call assert_equal(0, &modified) 368 only! 369 let @a = '' 370endfunc 371 372" This used to cause an illegal memory access 373func Test_undo_append() 374 new 375 call feedkeys("axx\<Esc>v", 'xt') 376 undo 377 norm o 378 quit 379endfunc 380 381func Test_undo_0() 382 new 383 set ul=100 384 normal i1 385 undo 386 normal i2 387 undo 388 normal i3 389 390 undo 0 391 let d = undotree() 392 call assert_equal('', getline(1)) 393 call assert_equal(0, d.seq_cur) 394 395 redo 396 let d = undotree() 397 call assert_equal('3', getline(1)) 398 call assert_equal(3, d.seq_cur) 399 400 undo 2 401 undo 0 402 let d = undotree() 403 call assert_equal('', getline(1)) 404 call assert_equal(0, d.seq_cur) 405 406 redo 407 let d = undotree() 408 call assert_equal('2', getline(1)) 409 call assert_equal(2, d.seq_cur) 410 411 undo 1 412 undo 0 413 let d = undotree() 414 call assert_equal('', getline(1)) 415 call assert_equal(0, d.seq_cur) 416 417 redo 418 let d = undotree() 419 call assert_equal('1', getline(1)) 420 call assert_equal(1, d.seq_cur) 421 422 bwipe! 423endfunc 424 425func Test_redo_empty_line() 426 new 427 exe "norm\x16r\x160" 428 exe "norm." 429 bwipe! 430endfunc 431 432funct Test_undofile() 433 " Test undofile() without setting 'undodir'. 434 if has('persistent_undo') 435 call assert_equal(fnamemodify('.Xundofoo.un~', ':p'), undofile('Xundofoo')) 436 else 437 call assert_equal('', undofile('Xundofoo')) 438 endif 439 call assert_equal('', undofile('')) 440 441 " Test undofile() with 'undodir' set to to an existing directory. 442 call mkdir('Xundodir') 443 set undodir=Xundodir 444 let cwd = getcwd() 445 if has('win32') 446 " Replace windows drive such as C:... into C%... 447 let cwd = substitute(cwd, '^\([a-zA-Z]\):', '\1%', 'g') 448 endif 449 let cwd = substitute(cwd . '/Xundofoo', '/', '%', 'g') 450 if has('persistent_undo') 451 call assert_equal('Xundodir/' . cwd, undofile('Xundofoo')) 452 else 453 call assert_equal('', undofile('Xundofoo')) 454 endif 455 call assert_equal('', undofile('')) 456 call delete('Xundodir', 'd') 457 458 " Test undofile() with 'undodir' set to a non-existing directory. 459 call assert_equal('', 'Xundofoo'->undofile()) 460 461 if !has('win32') && isdirectory('/tmp') 462 set undodir=/tmp 463 if has('osx') 464 call assert_equal('/tmp/%private%tmp%file', undofile('///tmp/file')) 465 else 466 call assert_equal('/tmp/%tmp%file', undofile('///tmp/file')) 467 endif 468 endif 469 470 set undodir& 471endfunc 472 473" Tests for the undo file 474" Explicitly break changes up in undo-able pieces by setting 'undolevels'. 475func Test_undofile_2() 476 set undolevels=100 undofile 477 edit Xtestfile 478 call append(0, 'this is one line') 479 call cursor(1, 1) 480 481 " first a simple one-line change. 482 set undolevels=100 483 s/one/ONE/ 484 set undolevels=100 485 write 486 bwipe! 487 edit Xtestfile 488 undo 489 call assert_equal('this is one line', getline(1)) 490 491 " change in original file fails check 492 set noundofile 493 edit! Xtestfile 494 s/line/Line/ 495 write 496 set undofile 497 bwipe! 498 edit Xtestfile 499 undo 500 call assert_equal('this is ONE Line', getline(1)) 501 502 " add 10 lines, delete 6 lines, undo 3 503 set undofile 504 call setbufline(0, 1, ['one', 'two', 'three', 'four', 'five', 'six', 505 \ 'seven', 'eight', 'nine', 'ten']) 506 set undolevels=100 507 normal 3Gdd 508 set undolevels=100 509 normal dd 510 set undolevels=100 511 normal dd 512 set undolevels=100 513 normal dd 514 set undolevels=100 515 normal dd 516 set undolevels=100 517 normal dd 518 set undolevels=100 519 write 520 bwipe! 521 edit Xtestfile 522 normal uuu 523 call assert_equal(['one', 'two', 'six', 'seven', 'eight', 'nine', 'ten'], 524 \ getline(1, '$')) 525 526 " Test that reading the undofiles when setting undofile works 527 set noundofile undolevels=0 528 exe "normal i\n" 529 undo 530 edit! Xtestfile 531 set undofile undolevels=100 532 normal uuuuuu 533 call assert_equal(['one', 'two', 'three', 'four', 'five', 'six', 'seven', 534 \ 'eight', 'nine', 'ten'], getline(1, '$')) 535 536 bwipe! 537 call delete('Xtestfile') 538 let ufile = has('vms') ? '_un_Xtestfile' : '.Xtestfile.un~' 539 call delete(ufile) 540 set undofile& undolevels& 541endfunc 542 543" Test 'undofile' using a file encrypted with 'zip' crypt method 544func Test_undofile_cryptmethod_zip() 545 edit Xtestfile 546 set undofile cryptmethod=zip 547 call append(0, ['monday', 'tuesday', 'wednesday', 'thursday', 'friday']) 548 call cursor(5, 1) 549 550 set undolevels=100 551 normal kkkdd 552 set undolevels=100 553 normal dd 554 set undolevels=100 555 normal dd 556 set undolevels=100 557 " encrypt the file using key 'foobar' 558 call feedkeys("foobar\nfoobar\n") 559 X 560 write! 561 bwipe! 562 563 call feedkeys("foobar\n") 564 edit Xtestfile 565 set key= 566 normal uu 567 call assert_equal(['monday', 'wednesday', 'thursday', 'friday', ''], 568 \ getline(1, '$')) 569 570 bwipe! 571 call delete('Xtestfile') 572 let ufile = has('vms') ? '_un_Xtestfile' : '.Xtestfile.un~' 573 call delete(ufile) 574 set undofile& undolevels& cryptmethod& 575endfunc 576 577" Test 'undofile' using a file encrypted with 'blowfish' crypt method 578func Test_undofile_cryptmethod_blowfish() 579 edit Xtestfile 580 set undofile cryptmethod=blowfish 581 call append(0, ['jan', 'feb', 'mar', 'apr', 'jun']) 582 call cursor(5, 1) 583 584 set undolevels=100 585 exe 'normal kk0ifoo ' 586 set undolevels=100 587 normal dd 588 set undolevels=100 589 exe 'normal ibar ' 590 set undolevels=100 591 " encrypt the file using key 'foobar' 592 call feedkeys("foobar\nfoobar\n") 593 X 594 write! 595 bwipe! 596 597 call feedkeys("foobar\n") 598 edit Xtestfile 599 set key= 600 call search('bar') 601 call assert_equal('bar apr', getline('.')) 602 undo 603 call assert_equal('apr', getline('.')) 604 undo 605 call assert_equal('foo mar', getline('.')) 606 undo 607 call assert_equal('mar', getline('.')) 608 609 bwipe! 610 call delete('Xtestfile') 611 let ufile = has('vms') ? '_un_Xtestfile' : '.Xtestfile.un~' 612 call delete(ufile) 613 set undofile& undolevels& cryptmethod& 614endfunc 615 616" Test 'undofile' using a file encrypted with 'blowfish2' crypt method 617func Test_undofile_cryptmethod_blowfish2() 618 edit Xtestfile 619 set undofile cryptmethod=blowfish2 620 call append(0, ['jan', 'feb', 'mar', 'apr', 'jun']) 621 call cursor(5, 1) 622 623 set undolevels=100 624 exe 'normal kk0ifoo ' 625 set undolevels=100 626 normal dd 627 set undolevels=100 628 exe 'normal ibar ' 629 set undolevels=100 630 " encrypt the file using key 'foo2bar' 631 call feedkeys("foo2bar\nfoo2bar\n") 632 X 633 write! 634 bwipe! 635 636 call feedkeys("foo2bar\n") 637 edit Xtestfile 638 set key= 639 call search('bar') 640 call assert_equal('bar apr', getline('.')) 641 normal u 642 call assert_equal('apr', getline('.')) 643 normal u 644 call assert_equal('foo mar', getline('.')) 645 normal u 646 call assert_equal('mar', getline('.')) 647 648 bwipe! 649 call delete('Xtestfile') 650 let ufile = has('vms') ? '_un_Xtestfile' : '.Xtestfile.un~' 651 call delete(ufile) 652 set undofile& undolevels& cryptmethod& 653endfunc 654 655" vim: shiftwidth=2 sts=2 expandtab 656