xref: /vim-8.2.3635/src/testdir/test_undo.vim (revision 01a6c216)
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" Test for undo working properly when executing commands from a register.
339" Also test this in an empty buffer.
340func Test_cmd_in_reg_undo()
341  enew!
342  let @a = "Ox\<Esc>jAy\<Esc>kdd"
343  edit +/^$ test_undo.vim
344  normal @au
345  call assert_equal(0, &modified)
346  return
347  new
348  normal @au
349  call assert_equal(0, &modified)
350  only!
351  let @a = ''
352endfunc
353
354" This used to cause an illegal memory access
355func Test_undo_append()
356  new
357  call feedkeys("axx\<Esc>v", 'xt')
358  undo
359  norm o
360  quit
361endfunc
362
363func Test_undo_0()
364  new
365  set ul=100
366  normal i1
367  undo
368  normal i2
369  undo
370  normal i3
371
372  undo 0
373  let d = undotree()
374  call assert_equal('', getline(1))
375  call assert_equal(0, d.seq_cur)
376
377  redo
378  let d = undotree()
379  call assert_equal('3', getline(1))
380  call assert_equal(3, d.seq_cur)
381
382  undo 2
383  undo 0
384  let d = undotree()
385  call assert_equal('', getline(1))
386  call assert_equal(0, d.seq_cur)
387
388  redo
389  let d = undotree()
390  call assert_equal('2', getline(1))
391  call assert_equal(2, d.seq_cur)
392
393  undo 1
394  undo 0
395  let d = undotree()
396  call assert_equal('', getline(1))
397  call assert_equal(0, d.seq_cur)
398
399  redo
400  let d = undotree()
401  call assert_equal('1', getline(1))
402  call assert_equal(1, d.seq_cur)
403
404  bwipe!
405endfunc
406
407func Test_redo_empty_line()
408  new
409  exe "norm\x16r\x160"
410  exe "norm."
411  bwipe!
412endfunc
413
414funct Test_undofile()
415  " Test undofile() without setting 'undodir'.
416  if has('persistent_undo')
417    call assert_equal(fnamemodify('.Xundofoo.un~', ':p'), undofile('Xundofoo'))
418  else
419    call assert_equal('', undofile('Xundofoo'))
420  endif
421  call assert_equal('', undofile(''))
422
423  " Test undofile() with 'undodir' set to to an existing directory.
424  call mkdir('Xundodir')
425  set undodir=Xundodir
426  let cwd = getcwd()
427  if has('win32')
428    " Replace windows drive such as C:... into C%...
429    let cwd = substitute(cwd, '^\([a-zA-Z]\):', '\1%', 'g')
430  endif
431  let cwd = substitute(cwd . '/Xundofoo', '/', '%', 'g')
432  if has('persistent_undo')
433    call assert_equal('Xundodir/' . cwd, undofile('Xundofoo'))
434  else
435    call assert_equal('', undofile('Xundofoo'))
436  endif
437  call assert_equal('', undofile(''))
438  call delete('Xundodir', 'd')
439
440  " Test undofile() with 'undodir' set to a non-existing directory.
441  call assert_equal('', undofile('Xundofoo'))
442
443  set undodir&
444endfunc
445