blob: 844ba77ea5040fbd26fcc71261ee65d36958aadb [file] [log] [blame]
Bram Moolenaar170b10b2016-07-29 16:15:27 +02001" 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
Bram Moolenaar3f8f8272022-12-08 21:49:35 +00006source check.vim
7source screendump.vim
8
Bram Moolenaar170b10b2016-07-29 16:15:27 +02009func Test_undotree()
Bram Moolenaar80eaddd2017-11-11 23:37:08 +010010 new
11
12 normal! Aabc
Bram Moolenaar170b10b2016-07-29 16:15:27 +020013 set ul=100
Bram Moolenaar170b10b2016-07-29 16:15:27 +020014 let d = undotree()
Bram Moolenaar80eaddd2017-11-11 23:37:08 +010015 call assert_equal(1, d.seq_last)
16 call assert_equal(1, d.seq_cur)
17 call assert_equal(0, d.save_last)
18 call assert_equal(0, d.save_cur)
19 call assert_equal(1, len(d.entries))
20 call assert_equal(1, d.entries[0].newhead)
21 call assert_equal(1, d.entries[0].seq)
22 call assert_true(d.entries[0].time <= d.time_cur)
23
24 normal! Adef
25 set ul=100
26 let d = undotree()
27 call assert_equal(2, d.seq_last)
28 call assert_equal(2, d.seq_cur)
29 call assert_equal(0, d.save_last)
30 call assert_equal(0, d.save_cur)
31 call assert_equal(2, len(d.entries))
32 call assert_equal(1, d.entries[0].seq)
33 call assert_equal(1, d.entries[1].newhead)
34 call assert_equal(2, d.entries[1].seq)
35 call assert_true(d.entries[1].time <= d.time_cur)
36
37 undo
38 set ul=100
39 let d = undotree()
40 call assert_equal(2, d.seq_last)
41 call assert_equal(1, d.seq_cur)
42 call assert_equal(0, d.save_last)
43 call assert_equal(0, d.save_cur)
44 call assert_equal(2, len(d.entries))
45 call assert_equal(1, d.entries[0].seq)
46 call assert_equal(1, d.entries[1].curhead)
47 call assert_equal(1, d.entries[1].newhead)
48 call assert_equal(2, d.entries[1].seq)
49 call assert_true(d.entries[1].time == d.time_cur)
50
51 normal! Aghi
52 set ul=100
53 let d = undotree()
54 call assert_equal(3, d.seq_last)
55 call assert_equal(3, d.seq_cur)
56 call assert_equal(0, d.save_last)
57 call assert_equal(0, d.save_cur)
58 call assert_equal(2, len(d.entries))
59 call assert_equal(1, d.entries[0].seq)
60 call assert_equal(2, d.entries[1].alt[0].seq)
61 call assert_equal(1, d.entries[1].newhead)
62 call assert_equal(3, d.entries[1].seq)
63 call assert_true(d.entries[1].time <= d.time_cur)
64
65 undo
66 set ul=100
67 let d = undotree()
68 call assert_equal(3, d.seq_last)
69 call assert_equal(1, d.seq_cur)
70 call assert_equal(0, d.save_last)
71 call assert_equal(0, d.save_cur)
72 call assert_equal(2, len(d.entries))
73 call assert_equal(1, d.entries[0].seq)
74 call assert_equal(2, d.entries[1].alt[0].seq)
75 call assert_equal(1, d.entries[1].curhead)
76 call assert_equal(1, d.entries[1].newhead)
77 call assert_equal(3, d.entries[1].seq)
78 call assert_true(d.entries[1].time == d.time_cur)
Bram Moolenaar170b10b2016-07-29 16:15:27 +020079
80 w! Xtest
Bram Moolenaar80eaddd2017-11-11 23:37:08 +010081 let d = undotree()
82 call assert_equal(1, d.save_cur)
83 call assert_equal(1, d.save_last)
Bram Moolenaar170b10b2016-07-29 16:15:27 +020084 call delete('Xtest')
Bram Moolenaar80eaddd2017-11-11 23:37:08 +010085 bwipe! Xtest
Bram Moolenaar170b10b2016-07-29 16:15:27 +020086endfunc
87
88func FillBuffer()
89 for i in range(1,13)
90 put=i
Bram Moolenaare5fa1112018-05-26 18:46:30 +020091 " Set 'undolevels' to split undo.
Bram Moolenaar170b10b2016-07-29 16:15:27 +020092 exe "setg ul=" . &g:ul
93 endfor
94endfunc
95
Devin J. Pohly5fee1112023-04-23 20:26:59 -050096func Test_undotree_bufnr()
97 new
98 let buf1 = bufnr()
99
100 normal! Aabc
101 set ul=100
102
103 " Save undo tree without bufnr as ground truth for buffer 1
104 let d1 = undotree()
105
106 new
107 let buf2 = bufnr()
108
109 normal! Adef
110 set ul=100
111
112 normal! Aghi
113 set ul=100
114
115 " Save undo tree without bufnr as ground truth for buffer 2
116 let d2 = undotree()
117
118 " Check undotree() with bufnr argument
119 let d = undotree(buf1)
120 call assert_equal(d1, d)
121 call assert_notequal(d2, d)
122
123 let d = undotree(buf2)
124 call assert_notequal(d1, d)
125 call assert_equal(d2, d)
126
127 " Switch buffers and check again
128 wincmd p
129
130 let d = undotree(buf1)
131 call assert_equal(d1, d)
132
133 let d = undotree(buf2)
134 call assert_notequal(d1, d)
135 call assert_equal(d2, d)
136
zeertzjqab9f2ec2023-08-20 18:35:10 +0200137 " error cases
138 call assert_fails('call undotree(-1)', 'E158:')
139 call assert_fails('call undotree("nosuchbuf")', 'E158:')
140
141 " after creating a buffer nosuchbuf, undotree('nosuchbuf') should
142 " not error out
143 new nosuchbuf
144 let d = {'seq_last': 0, 'entries': [], 'time_cur': 0, 'save_last': 0, 'synced': 1, 'save_cur': 0, 'seq_cur': 0}
145 call assert_equal(d, undotree("nosuchbuf"))
146 " clean up
147 bw nosuchbuf
148
Devin J. Pohly5fee1112023-04-23 20:26:59 -0500149 " Drop created windows
150 set ul&
151 new
John Marriottfd1a8382024-11-06 21:21:50 +0100152 bw!
Devin J. Pohly5fee1112023-04-23 20:26:59 -0500153endfunc
154
Bram Moolenaar170b10b2016-07-29 16:15:27 +0200155func Test_global_local_undolevels()
156 new one
157 set undolevels=5
158 call FillBuffer()
159 " will only undo the last 5 changes, end up with 13 - (5 + 1) = 7 lines
160 earlier 10
161 call assert_equal(5, &g:undolevels)
162 call assert_equal(-123456, &l:undolevels)
163 call assert_equal('7', getline('$'))
164
165 new two
166 setlocal undolevels=2
167 call FillBuffer()
168 " will only undo the last 2 changes, end up with 13 - (2 + 1) = 10 lines
169 earlier 10
170 call assert_equal(5, &g:undolevels)
171 call assert_equal(2, &l:undolevels)
172 call assert_equal('10', getline('$'))
173
174 setlocal ul=10
175 call assert_equal(5, &g:undolevels)
176 call assert_equal(10, &l:undolevels)
177
178 " Setting local value in "two" must not change local value in "one"
179 wincmd p
180 call assert_equal(5, &g:undolevels)
181 call assert_equal(-123456, &l:undolevels)
182
183 new three
184 setglobal ul=50
185 call assert_equal(50, &g:undolevels)
186 call assert_equal(-123456, &l:undolevels)
187
Bram Moolenaar1363a302020-04-12 13:50:26 +0200188 " Resetting the local 'undolevels' value to use the global value
189 setlocal undolevels=5
190 setlocal undolevels<
191 call assert_equal(-123456, &l:undolevels)
192
Bram Moolenaar170b10b2016-07-29 16:15:27 +0200193 " Drop created windows
194 set ul&
195 new
John Marriottfd1a8382024-11-06 21:21:50 +0100196 bw! one two
Bram Moolenaar170b10b2016-07-29 16:15:27 +0200197 only!
198endfunc
199
200func BackOne(expected)
201 call feedkeys('g-', 'xt')
202 call assert_equal(a:expected, getline(1))
203endfunc
204
205func Test_undo_del_chars()
206 " Setup a buffer without creating undo entries
207 new
208 set ul=-1
209 call setline(1, ['123-456'])
210 set ul=100
211 1
212 call test_settime(100)
213
214 " Delete three characters and undo with g-
215 call feedkeys('x', 'xt')
216 call feedkeys('x', 'xt')
217 call feedkeys('x', 'xt')
218 call assert_equal('-456', getline(1))
219 call BackOne('3-456')
220 call BackOne('23-456')
221 call BackOne('123-456')
222 call assert_fails("BackOne('123-456')")
223
224 :" Delete three other characters and go back in time with g-
225 call feedkeys('$x', 'xt')
226 call feedkeys('x', 'xt')
227 call feedkeys('x', 'xt')
228 call assert_equal('123-', getline(1))
229 call test_settime(101)
230
231 call BackOne('123-4')
232 call BackOne('123-45')
233 " skips '123-456' because it's older
234 call BackOne('-456')
235 call BackOne('3-456')
236 call BackOne('23-456')
237 call BackOne('123-456')
238 call assert_fails("BackOne('123-456')")
239 normal 10g+
240 call assert_equal('123-', getline(1))
241
242 :" Jump two seconds and go some seconds forward and backward
243 call test_settime(103)
244 call feedkeys("Aa\<Esc>", 'xt')
245 call feedkeys("Ab\<Esc>", 'xt')
246 call feedkeys("Ac\<Esc>", 'xt')
247 call assert_equal('123-abc', getline(1))
248 earlier 1s
249 call assert_equal('123-', getline(1))
250 earlier 3s
251 call assert_equal('123-456', getline(1))
252 later 1s
253 call assert_equal('123-', getline(1))
254 later 1h
255 call assert_equal('123-abc', getline(1))
256
John Marriottfd1a8382024-11-06 21:21:50 +0100257 bw!
Bram Moolenaar170b10b2016-07-29 16:15:27 +0200258endfunc
259
Bram Moolenaarc628fdc2016-08-31 20:33:27 +0200260func Test_undolist()
261 new
262 set ul=100
263
Bram Moolenaare5fa1112018-05-26 18:46:30 +0200264 let a = execute('undolist')
Bram Moolenaarc628fdc2016-08-31 20:33:27 +0200265 call assert_equal("\nNothing to undo", a)
266
267 " 1 leaf (2 changes).
268 call feedkeys('achange1', 'xt')
269 call feedkeys('achange2', 'xt')
Bram Moolenaare5fa1112018-05-26 18:46:30 +0200270 let a = execute('undolist')
Bram Moolenaarc628fdc2016-08-31 20:33:27 +0200271 call assert_match("^\nnumber changes when *saved\n *2 *2 .*$", a)
272
273 " 2 leaves.
274 call feedkeys('u', 'xt')
275 call feedkeys('achange3\<Esc>', 'xt')
Bram Moolenaare5fa1112018-05-26 18:46:30 +0200276 let a = execute('undolist')
Bram Moolenaarc628fdc2016-08-31 20:33:27 +0200277 call assert_match("^\nnumber changes when *saved\n *2 *2 *.*\n *3 *2 .*$", a)
John Marriottfd1a8382024-11-06 21:21:50 +0100278
279 " 3 save number
280 if has("persistent_undo")
281 setl undofile
282 w Xundolist.txt
283 defer delete('Xundolist.txt')
284 let lastline = execute('undolist')->split("\n")[-1]
Christian Brabandt381ff772024-12-16 22:28:28 +0100285 call assert_match('seconds\? ago \?1', lastline)
286
John Marriottfd1a8382024-11-06 21:21:50 +0100287 endif
288 bw!
Bram Moolenaarc628fdc2016-08-31 20:33:27 +0200289endfunc
290
291func Test_U_command()
292 new
293 set ul=100
294 call feedkeys("achange1\<Esc>", 'xt')
295 call feedkeys("achange2\<Esc>", 'xt')
296 norm! U
297 call assert_equal('', getline(1))
298 norm! U
299 call assert_equal('change1change2', getline(1))
John Marriottfd1a8382024-11-06 21:21:50 +0100300 bw!
Bram Moolenaarc628fdc2016-08-31 20:33:27 +0200301endfunc
302
Bram Moolenaar170b10b2016-07-29 16:15:27 +0200303func Test_undojoin()
304 new
305 call feedkeys("Goaaaa\<Esc>", 'xt')
306 call feedkeys("obbbb\<Esc>", 'xt')
307 call assert_equal(['aaaa', 'bbbb'], getline(2, '$'))
308 call feedkeys("u", 'xt')
309 call assert_equal(['aaaa'], getline(2, '$'))
310 call feedkeys("obbbb\<Esc>", 'xt')
311 undojoin
312 " Note: next change must not be as if typed
313 call feedkeys("occcc\<Esc>", 'x')
314 call assert_equal(['aaaa', 'bbbb', 'cccc'], getline(2, '$'))
315 call feedkeys("u", 'xt')
316 call assert_equal(['aaaa'], getline(2, '$'))
Bram Moolenaar5e4e1b12017-01-17 22:09:45 +0100317 bwipe!
318endfunc
319
320func Test_undojoin_redo()
321 new
322 call setline(1, ['first line', 'second line'])
323 call feedkeys("ixx\<Esc>", 'xt')
324 call feedkeys(":undojoin | redo\<CR>", 'xt')
325 call assert_equal('xxfirst line', getline(1))
326 call assert_equal('second line', getline(2))
327 bwipe!
Bram Moolenaar170b10b2016-07-29 16:15:27 +0200328endfunc
329
Bram Moolenaar559b9c62019-12-15 18:09:19 +0100330" undojoin not allowed after undo
331func Test_undojoin_after_undo()
332 new
333 call feedkeys("ixx\<Esc>u", 'xt')
334 call assert_fails(':undojoin', 'E790:')
335 bwipe!
336endfunc
337
338" undojoin is a noop when no change yet, or when 'undolevels' is negative
339func Test_undojoin_noop()
340 new
341 call feedkeys(":undojoin\<CR>", 'xt')
342 call assert_equal([''], getline(1, '$'))
343 setlocal undolevels=-1
344 call feedkeys("ixx\<Esc>u", 'xt')
345 call feedkeys(":undojoin\<CR>", 'xt')
346 call assert_equal(['xx'], getline(1, '$'))
347 bwipe!
348endfunc
349
Bram Moolenaar170b10b2016-07-29 16:15:27 +0200350func Test_undo_write()
Bram Moolenaar5842a742017-11-04 22:36:53 +0100351 call delete('Xtest')
Bram Moolenaar170b10b2016-07-29 16:15:27 +0200352 split Xtest
353 call feedkeys("ione one one\<Esc>", 'xt')
354 w!
355 call feedkeys("otwo\<Esc>", 'xt')
356 call feedkeys("otwo\<Esc>", 'xt')
357 w
358 call feedkeys("othree\<Esc>", 'xt')
359 call assert_equal(['one one one', 'two', 'two', 'three'], getline(1, '$'))
360 earlier 1f
361 call assert_equal(['one one one', 'two', 'two'], getline(1, '$'))
362 earlier 1f
363 call assert_equal(['one one one'], getline(1, '$'))
364 earlier 1f
365 call assert_equal([''], getline(1, '$'))
366 later 1f
367 call assert_equal(['one one one'], getline(1, '$'))
368 later 1f
369 call assert_equal(['one one one', 'two', 'two'], getline(1, '$'))
370 later 1f
371 call assert_equal(['one one one', 'two', 'two', 'three'], getline(1, '$'))
372
373 close!
374 call delete('Xtest')
375 bwipe! Xtest
Bram Moolenaar9f6277b2020-02-11 22:04:02 +0100376
377 call assert_fails('earlier xyz', 'E475:')
Bram Moolenaar170b10b2016-07-29 16:15:27 +0200378endfunc
379
380func Test_insert_expr()
381 new
382 " calling setline() triggers undo sync
383 call feedkeys("oa\<Esc>", 'xt')
384 call feedkeys("ob\<Esc>", 'xt')
385 set ul=100
386 call feedkeys("o1\<Esc>a2\<C-R>=setline('.','1234')\<CR>\<CR>\<Esc>", 'x')
387 call assert_equal(['a', 'b', '120', '34'], getline(2, '$'))
388 call feedkeys("u", 'x')
389 call assert_equal(['a', 'b', '12'], getline(2, '$'))
390 call feedkeys("u", 'x')
391 call assert_equal(['a', 'b'], getline(2, '$'))
392
393 call feedkeys("oc\<Esc>", 'xt')
394 set ul=100
395 call feedkeys("o1\<Esc>a2\<C-R>=setline('.','1234')\<CR>\<CR>\<Esc>", 'x')
396 call assert_equal(['a', 'b', 'c', '120', '34'], getline(2, '$'))
397 call feedkeys("u", 'x')
398 call assert_equal(['a', 'b', 'c', '12'], getline(2, '$'))
399
400 call feedkeys("od\<Esc>", 'xt')
401 set ul=100
402 call feedkeys("o1\<Esc>a2\<C-R>=string(123)\<CR>\<Esc>", 'x')
403 call assert_equal(['a', 'b', 'c', '12', 'd', '12123'], getline(2, '$'))
404 call feedkeys("u", 'x')
405 call assert_equal(['a', 'b', 'c', '12', 'd'], getline(2, '$'))
406
John Marriottfd1a8382024-11-06 21:21:50 +0100407 bw!
Bram Moolenaar170b10b2016-07-29 16:15:27 +0200408endfunc
Bram Moolenaarcbd4de42017-01-07 16:14:57 +0100409
410func Test_undofile_earlier()
K.Takata0500e872022-09-08 12:28:02 +0100411 if has('win32')
412 " FIXME: This test is flaky on MS-Windows.
413 let g:test_is_flaky = 1
414 endif
415
Bram Moolenaarcbd4de42017-01-07 16:14:57 +0100416 " Issue #1254
417 " create undofile with timestamps older than Vim startup time.
418 let t0 = localtime() - 43200
419 call test_settime(t0)
Bram Moolenaarcce293f2022-08-15 17:28:27 +0100420 new XfileEarlier
Bram Moolenaarcbd4de42017-01-07 16:14:57 +0100421 call feedkeys("ione\<Esc>", 'xt')
422 set ul=100
423 call test_settime(t0 + 1)
424 call feedkeys("otwo\<Esc>", 'xt')
425 set ul=100
426 call test_settime(t0 + 2)
427 call feedkeys("othree\<Esc>", 'xt')
428 set ul=100
429 w
430 wundo Xundofile
431 bwipe!
432 " restore normal timestamps.
433 call test_settime(0)
Bram Moolenaarcce293f2022-08-15 17:28:27 +0100434 new XfileEarlier
Bram Moolenaarcbd4de42017-01-07 16:14:57 +0100435 rundo Xundofile
436 earlier 1d
437 call assert_equal('', getline(1))
438 bwipe!
Bram Moolenaarcce293f2022-08-15 17:28:27 +0100439 call delete('XfileEarlier')
Bram Moolenaarcbd4de42017-01-07 16:14:57 +0100440 call delete('Xundofile')
441endfunc
Bram Moolenaar15993ce2017-10-26 20:21:44 +0200442
Bram Moolenaar559b9c62019-12-15 18:09:19 +0100443func Test_wundo_errors()
444 new
445 call setline(1, 'hello')
446 call assert_fails('wundo! Xdoesnotexist/Xundofile', 'E828:')
447 bwipe!
448endfunc
449
450" Check that reading a truncated undo file doesn't hang.
Bram Moolenaarfb06d762019-08-04 18:55:35 +0200451func Test_undofile_truncated()
452 new
453 call setline(1, 'hello')
454 set ul=100
455 wundo Xundofile
456 let contents = readfile('Xundofile', 'B')
457
458 " try several sizes
459 for size in range(20, 500, 33)
Bram Moolenaar5b148ef2022-10-15 21:35:56 +0100460 call writefile(contents[0:size], 'Xundofile', 'D')
Bram Moolenaarfb06d762019-08-04 18:55:35 +0200461 call assert_fails('rundo Xundofile', 'E825:')
462 endfor
463
464 bwipe!
Bram Moolenaarfb06d762019-08-04 18:55:35 +0200465endfunc
466
Bram Moolenaar559b9c62019-12-15 18:09:19 +0100467func Test_rundo_errors()
468 call assert_fails('rundo XfileDoesNotExist', 'E822:')
469
Bram Moolenaar5b148ef2022-10-15 21:35:56 +0100470 call writefile(['abc'], 'Xundofile', 'D')
Bram Moolenaar559b9c62019-12-15 18:09:19 +0100471 call assert_fails('rundo Xundofile', 'E823:')
Bram Moolenaar559b9c62019-12-15 18:09:19 +0100472endfunc
473
Bram Moolenaar55b419b2020-10-04 19:56:39 +0200474func Test_undofile_next()
475 set undofile
476 new Xfoo.txt
477 execute "norm ix\<c-g>uy\<c-g>uz\<Esc>"
478 write
479 bwipe
480
481 next Xfoo.txt
482 call assert_equal('xyz', getline(1))
483 silent undo
484 call assert_equal('xy', getline(1))
485 silent undo
486 call assert_equal('x', getline(1))
487 bwipe!
488
489 call delete('Xfoo.txt')
490 call delete('.Xfoo.txt.un~')
491 set undofile&
492endfunc
493
Bram Moolenaar15993ce2017-10-26 20:21:44 +0200494" Test for undo working properly when executing commands from a register.
495" Also test this in an empty buffer.
496func Test_cmd_in_reg_undo()
497 enew!
Bram Moolenaare5fa1112018-05-26 18:46:30 +0200498 let @a = "Ox\<Esc>jAy\<Esc>kdd"
Bram Moolenaar15993ce2017-10-26 20:21:44 +0200499 edit +/^$ test_undo.vim
500 normal @au
501 call assert_equal(0, &modified)
502 return
503 new
504 normal @au
505 call assert_equal(0, &modified)
506 only!
Bram Moolenaare5fa1112018-05-26 18:46:30 +0200507 let @a = ''
Bram Moolenaar15993ce2017-10-26 20:21:44 +0200508endfunc
Bram Moolenaar95dbcbe2018-01-27 21:01:34 +0100509
510" This used to cause an illegal memory access
511func Test_undo_append()
512 new
513 call feedkeys("axx\<Esc>v", 'xt')
514 undo
515 norm o
516 quit
517endfunc
Bram Moolenaarce46d932018-01-30 22:46:06 +0100518
519func Test_undo_0()
520 new
521 set ul=100
522 normal i1
523 undo
524 normal i2
525 undo
526 normal i3
527
528 undo 0
529 let d = undotree()
530 call assert_equal('', getline(1))
531 call assert_equal(0, d.seq_cur)
532
533 redo
534 let d = undotree()
535 call assert_equal('3', getline(1))
536 call assert_equal(3, d.seq_cur)
537
538 undo 2
539 undo 0
540 let d = undotree()
541 call assert_equal('', getline(1))
542 call assert_equal(0, d.seq_cur)
543
544 redo
545 let d = undotree()
546 call assert_equal('2', getline(1))
547 call assert_equal(2, d.seq_cur)
548
549 undo 1
550 undo 0
551 let d = undotree()
552 call assert_equal('', getline(1))
553 call assert_equal(0, d.seq_cur)
554
555 redo
556 let d = undotree()
557 call assert_equal('1', getline(1))
558 call assert_equal(1, d.seq_cur)
559
560 bwipe!
561endfunc
Bram Moolenaarf12519d2018-02-06 22:52:49 +0100562
Bram Moolenaar559b9c62019-12-15 18:09:19 +0100563" undo or redo are noop if there is nothing to undo or redo
564func Test_undo_redo_noop()
565 new
566 call assert_fails('undo 2', 'E830:')
567
568 message clear
569 undo
570 let messages = split(execute('message'), "\n")
571 call assert_equal('Already at oldest change', messages[-1])
572
573 message clear
574 redo
575 let messages = split(execute('message'), "\n")
576 call assert_equal('Already at newest change', messages[-1])
577
578 bwipe!
579endfunc
580
Bram Moolenaarf12519d2018-02-06 22:52:49 +0100581func Test_redo_empty_line()
582 new
583 exe "norm\x16r\x160"
584 exe "norm."
585 bwipe!
586endfunc
Bram Moolenaare5fa1112018-05-26 18:46:30 +0200587
588funct Test_undofile()
589 " Test undofile() without setting 'undodir'.
590 if has('persistent_undo')
591 call assert_equal(fnamemodify('.Xundofoo.un~', ':p'), undofile('Xundofoo'))
592 else
593 call assert_equal('', undofile('Xundofoo'))
594 endif
595 call assert_equal('', undofile(''))
596
zeertzjq0df8f932024-03-07 21:40:53 +0100597 " Test undofile() with 'undodir' set to an existing directory.
Bram Moolenaare5fa1112018-05-26 18:46:30 +0200598 call mkdir('Xundodir')
599 set undodir=Xundodir
600 let cwd = getcwd()
601 if has('win32')
602 " Replace windows drive such as C:... into C%...
Bram Moolenaar56242f22018-12-14 15:48:48 +0100603 let cwd = substitute(cwd, '^\([a-zA-Z]\):', '\1%', 'g')
Bram Moolenaare5fa1112018-05-26 18:46:30 +0200604 endif
605 let cwd = substitute(cwd . '/Xundofoo', '/', '%', 'g')
606 if has('persistent_undo')
607 call assert_equal('Xundodir/' . cwd, undofile('Xundofoo'))
608 else
609 call assert_equal('', undofile('Xundofoo'))
610 endif
611 call assert_equal('', undofile(''))
612 call delete('Xundodir', 'd')
613
614 " Test undofile() with 'undodir' set to a non-existing directory.
Bram Moolenaarf92e58c2019-09-08 21:51:41 +0200615 call assert_equal('', 'Xundofoo'->undofile())
Bram Moolenaare5fa1112018-05-26 18:46:30 +0200616
Bram Moolenaar077ff432019-10-28 00:42:21 +0100617 if !has('win32') && isdirectory('/tmp')
Bram Moolenaare9ebc9a2019-05-19 15:27:14 +0200618 set undodir=/tmp
Bram Moolenaar2b39d802019-05-19 16:38:56 +0200619 if has('osx')
620 call assert_equal('/tmp/%private%tmp%file', undofile('///tmp/file'))
621 else
622 call assert_equal('/tmp/%tmp%file', undofile('///tmp/file'))
623 endif
Bram Moolenaare9ebc9a2019-05-19 15:27:14 +0200624 endif
625
Bram Moolenaare5fa1112018-05-26 18:46:30 +0200626 set undodir&
627endfunc
Bram Moolenaar3e2d1c82019-12-14 20:35:01 +0100628
629" Tests for the undo file
630" Explicitly break changes up in undo-able pieces by setting 'undolevels'.
631func Test_undofile_2()
632 set undolevels=100 undofile
633 edit Xtestfile
634 call append(0, 'this is one line')
635 call cursor(1, 1)
636
637 " first a simple one-line change.
638 set undolevels=100
639 s/one/ONE/
640 set undolevels=100
641 write
642 bwipe!
643 edit Xtestfile
644 undo
645 call assert_equal('this is one line', getline(1))
646
647 " change in original file fails check
648 set noundofile
649 edit! Xtestfile
650 s/line/Line/
651 write
652 set undofile
653 bwipe!
654 edit Xtestfile
655 undo
656 call assert_equal('this is ONE Line', getline(1))
657
658 " add 10 lines, delete 6 lines, undo 3
659 set undofile
Bram Moolenaarb8bd2e62021-08-21 17:13:14 +0200660 call setbufline('%', 1, ['one', 'two', 'three', 'four', 'five', 'six',
Bram Moolenaar3e2d1c82019-12-14 20:35:01 +0100661 \ 'seven', 'eight', 'nine', 'ten'])
662 set undolevels=100
663 normal 3Gdd
664 set undolevels=100
665 normal dd
666 set undolevels=100
667 normal dd
668 set undolevels=100
669 normal dd
670 set undolevels=100
671 normal dd
672 set undolevels=100
673 normal dd
674 set undolevels=100
675 write
676 bwipe!
677 edit Xtestfile
678 normal uuu
679 call assert_equal(['one', 'two', 'six', 'seven', 'eight', 'nine', 'ten'],
680 \ getline(1, '$'))
681
682 " Test that reading the undofiles when setting undofile works
683 set noundofile undolevels=0
684 exe "normal i\n"
685 undo
686 edit! Xtestfile
687 set undofile undolevels=100
688 normal uuuuuu
689 call assert_equal(['one', 'two', 'three', 'four', 'five', 'six', 'seven',
690 \ 'eight', 'nine', 'ten'], getline(1, '$'))
691
692 bwipe!
693 call delete('Xtestfile')
694 let ufile = has('vms') ? '_un_Xtestfile' : '.Xtestfile.un~'
695 call delete(ufile)
696 set undofile& undolevels&
697endfunc
698
699" Test 'undofile' using a file encrypted with 'zip' crypt method
700func Test_undofile_cryptmethod_zip()
701 edit Xtestfile
702 set undofile cryptmethod=zip
703 call append(0, ['monday', 'tuesday', 'wednesday', 'thursday', 'friday'])
704 call cursor(5, 1)
705
706 set undolevels=100
707 normal kkkdd
708 set undolevels=100
709 normal dd
710 set undolevels=100
711 normal dd
712 set undolevels=100
713 " encrypt the file using key 'foobar'
714 call feedkeys("foobar\nfoobar\n")
715 X
716 write!
717 bwipe!
718
719 call feedkeys("foobar\n")
720 edit Xtestfile
721 set key=
722 normal uu
723 call assert_equal(['monday', 'wednesday', 'thursday', 'friday', ''],
724 \ getline(1, '$'))
725
726 bwipe!
727 call delete('Xtestfile')
728 let ufile = has('vms') ? '_un_Xtestfile' : '.Xtestfile.un~'
729 call delete(ufile)
730 set undofile& undolevels& cryptmethod&
731endfunc
732
733" Test 'undofile' using a file encrypted with 'blowfish' crypt method
734func Test_undofile_cryptmethod_blowfish()
735 edit Xtestfile
736 set undofile cryptmethod=blowfish
737 call append(0, ['jan', 'feb', 'mar', 'apr', 'jun'])
738 call cursor(5, 1)
739
740 set undolevels=100
741 exe 'normal kk0ifoo '
742 set undolevels=100
743 normal dd
744 set undolevels=100
745 exe 'normal ibar '
746 set undolevels=100
747 " encrypt the file using key 'foobar'
748 call feedkeys("foobar\nfoobar\n")
749 X
750 write!
751 bwipe!
752
753 call feedkeys("foobar\n")
754 edit Xtestfile
755 set key=
756 call search('bar')
757 call assert_equal('bar apr', getline('.'))
758 undo
759 call assert_equal('apr', getline('.'))
760 undo
761 call assert_equal('foo mar', getline('.'))
762 undo
763 call assert_equal('mar', getline('.'))
764
765 bwipe!
766 call delete('Xtestfile')
767 let ufile = has('vms') ? '_un_Xtestfile' : '.Xtestfile.un~'
768 call delete(ufile)
769 set undofile& undolevels& cryptmethod&
770endfunc
771
772" Test 'undofile' using a file encrypted with 'blowfish2' crypt method
773func Test_undofile_cryptmethod_blowfish2()
774 edit Xtestfile
775 set undofile cryptmethod=blowfish2
776 call append(0, ['jan', 'feb', 'mar', 'apr', 'jun'])
777 call cursor(5, 1)
778
779 set undolevels=100
780 exe 'normal kk0ifoo '
781 set undolevels=100
782 normal dd
783 set undolevels=100
784 exe 'normal ibar '
785 set undolevels=100
786 " encrypt the file using key 'foo2bar'
787 call feedkeys("foo2bar\nfoo2bar\n")
788 X
789 write!
790 bwipe!
791
792 call feedkeys("foo2bar\n")
793 edit Xtestfile
794 set key=
795 call search('bar')
796 call assert_equal('bar apr', getline('.'))
797 normal u
798 call assert_equal('apr', getline('.'))
799 normal u
800 call assert_equal('foo mar', getline('.'))
801 normal u
802 call assert_equal('mar', getline('.'))
803
804 bwipe!
805 call delete('Xtestfile')
806 let ufile = has('vms') ? '_un_Xtestfile' : '.Xtestfile.un~'
807 call delete(ufile)
808 set undofile& undolevels& cryptmethod&
809endfunc
810
Bram Moolenaarf4fcedc2021-03-15 18:36:20 +0100811" Test for redoing with incrementing numbered registers
812func Test_redo_repeat_numbered_register()
813 new
814 for [i, v] in [[1, 'one'], [2, 'two'], [3, 'three'],
815 \ [4, 'four'], [5, 'five'], [6, 'six'],
816 \ [7, 'seven'], [8, 'eight'], [9, 'nine']]
817 exe 'let @' .. i .. '="' .. v .. '\n"'
818 endfor
819 call feedkeys('"1p.........', 'xt')
820 call assert_equal(['', 'one', 'two', 'three', 'four', 'five', 'six',
821 \ 'seven', 'eight', 'nine', 'nine'], getline(1, '$'))
822 bwipe!
823endfunc
824
Bram Moolenaar1f448d92021-03-22 19:37:06 +0100825" Test for redo in insert mode using CTRL-O with multibyte characters
826func Test_redo_multibyte_in_insert_mode()
827 new
828 call feedkeys("a\<C-K>ft", 'xt')
829 call feedkeys("uiHe\<C-O>.llo", 'xt')
830 call assert_equal("He\ufb05llo", getline(1))
831 bwipe!
832endfunc
833
LemonBoy82444ce2022-05-12 15:39:31 +0100834func Test_undo_mark()
835 new
836 " The undo is applied to the only line.
837 call setline(1, 'hello')
838 call feedkeys("ggyiw$p", 'xt')
839 undo
840 call assert_equal([0, 1, 1, 0], getpos("'["))
841 call assert_equal([0, 1, 1, 0], getpos("']"))
842 " The undo removes the last line.
843 call feedkeys("Goaaaa\<Esc>", 'xt')
844 call feedkeys("obbbb\<Esc>", 'xt')
845 undo
846 call assert_equal([0, 2, 1, 0], getpos("'["))
847 call assert_equal([0, 2, 1, 0], getpos("']"))
848 bwipe!
849endfunc
850
Bram Moolenaar3f8f8272022-12-08 21:49:35 +0000851func Test_undo_after_write()
852 " use a terminal to make undo work like when text is typed
853 CheckRunVimInTerminal
854
855 let lines =<< trim END
856 edit Xtestfile.txt
857 set undolevels=100 undofile
858 imap . <Cmd>write<CR>
859 write
860 END
861 call writefile(lines, 'Xtest_undo_after_write', 'D')
862 let buf = RunVimInTerminal('-S Xtest_undo_after_write', #{rows: 6})
863
864 call term_sendkeys(buf, "Otest.\<CR>boo!!!\<Esc>")
865 sleep 100m
866 call term_sendkeys(buf, "u")
867 call VerifyScreenDump(buf, 'Test_undo_after_write_1', {})
868
869 call term_sendkeys(buf, "u")
870 call VerifyScreenDump(buf, 'Test_undo_after_write_2', {})
871
872 call StopVimInTerminal(buf)
873 call delete('Xtestfile.txt')
Dominique Pelléb07b9dc2023-10-09 18:07:24 +0200874 call delete('.Xtestfile.txt.un~')
Bram Moolenaar3f8f8272022-12-08 21:49:35 +0000875endfunc
876
zeertzjqdccc29c2023-09-04 22:25:07 +0200877func Test_undo_range_normal()
878 new
879 call setline(1, ['asa', 'bsb'])
880 let &l:undolevels = &l:undolevels
881 %normal dfs
882 call assert_equal(['a', 'b'], getline(1, '$'))
883 undo
884 call assert_equal(['asa', 'bsb'], getline(1, '$'))
885 bwipe!
886endfunc
Bram Moolenaar3f8f8272022-12-08 21:49:35 +0000887
Christian Brabandt14382c82024-11-28 21:59:33 +0100888func Test_load_existing_undofile()
889 CheckFeature persistent_undo
890 sp samples/test_undo.txt
891 let mess=execute(':verbose rundo samples/test_undo.txt.undo')
892 call assert_match('Finished reading undo file', mess)
893
894 call assert_equal(['one', 'two', 'three'], getline(1, '$'))
895 norm! u
896 call assert_equal(['one', 'two'], getline(1, '$'))
897 norm! u
898 call assert_equal(['one'], getline(1, '$'))
899 norm! u
900 call assert_equal([''], getline(1, '$'))
901 let mess = execute(':norm! u')
902 call assert_equal([''], getline(1, '$'))
903 call assert_match('Already at oldest change', mess)
904 exe ":norm! \<c-r>"
905 call assert_equal(['one'], getline(1, '$'))
906 exe ":norm! \<c-r>"
907 call assert_equal(['one', 'two'], getline(1, '$'))
908 exe ":norm! \<c-r>"
909 call assert_equal(['one', 'two', 'three'], getline(1, '$'))
910 let mess = execute(":norm! \<c-r>")
911 call assert_equal(['one', 'two', 'three'], getline(1, '$'))
912 call assert_match('Already at newest change', mess)
913 bw!
914endfunc
915
916
Bram Moolenaar3e2d1c82019-12-14 20:35:01 +0100917" vim: shiftwidth=2 sts=2 expandtab