blob: 63225f31d95ff7245644e38a3b5989226085ab37 [file] [log] [blame]
Bram Moolenaarc525e3a2017-02-18 16:59:02 +01001" Test :recover
2
Bram Moolenaarf52f0602021-03-10 21:26:37 +01003source check.vim
4
Bram Moolenaarc525e3a2017-02-18 16:59:02 +01005func Test_recover_root_dir()
6 " This used to access invalid memory.
7 split Xtest
8 set dir=/
9 call assert_fails('recover', 'E305:')
10 close!
11
Bram Moolenaar2a0b06d2017-05-18 16:23:43 +020012 if has('win32') || filewritable('/') == 2
Bram Moolenaar80345202017-02-18 22:43:19 +010013 " can write in / directory on MS-Windows
14 set dir=/notexist/
15 endif
Bram Moolenaarc525e3a2017-02-18 16:59:02 +010016 call assert_fails('split Xtest', 'E303:')
Bram Moolenaar00e192b2019-10-19 17:01:28 +020017
18 " No error with empty 'directory' setting.
19 set directory=
20 split XtestOK
21 close!
22
Bram Moolenaarc525e3a2017-02-18 16:59:02 +010023 set dir&
24endfunc
25
Bram Moolenaarf52f0602021-03-10 21:26:37 +010026" Make a copy of the current swap file to "Xswap".
27" Return the name of the swap file.
28func CopySwapfile()
29 preserve
30 " get the name of the swap file
31 let swname = split(execute("swapname"))[0]
32 let swname = substitute(swname, '[[:blank:][:cntrl:]]*\(.\{-}\)[[:blank:][:cntrl:]]*$', '\1', '')
33 " make a copy of the swap file in Xswap
34 set binary
35 exe 'sp ' . swname
36 w! Xswap
37 set nobinary
38 return swname
39endfunc
40
Bram Moolenaar4a6fcf82017-10-12 21:29:22 +020041" Inserts 10000 lines with text to fill the swap file with two levels of pointer
42" blocks. Then recovers from the swap file and checks all text is restored.
43"
44" We need about 10000 lines of 100 characters to get two levels of pointer
45" blocks.
46func Test_swap_file()
Bram Moolenaar67418d92017-10-15 22:07:39 +020047 set fileformat=unix undolevels=-1
Bram Moolenaar4a6fcf82017-10-12 21:29:22 +020048 edit! Xtest
49 let text = "\tabcdefghijklmnoparstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnoparstuvwxyz0123456789"
50 let i = 1
51 let linecount = 10000
52 while i <= linecount
53 call append(i - 1, i . text)
54 let i += 1
55 endwhile
56 $delete
Bram Moolenaarf52f0602021-03-10 21:26:37 +010057
58 let swname = CopySwapfile()
59
Bram Moolenaar4a6fcf82017-10-12 21:29:22 +020060 new
61 only!
62 bwipe! Xtest
63 call rename('Xswap', swname)
64 recover Xtest
65 call delete(swname)
66 let linedollar = line('$')
67 call assert_equal(linecount, linedollar)
68 if linedollar < linecount
69 let linecount = linedollar
70 endif
71 let i = 1
72 while i <= linecount
73 call assert_equal(i . text, getline(i))
74 let i += 1
75 endwhile
76
77 set undolevels&
78 enew! | only
79endfunc
Bram Moolenaar6d91bcb2020-08-12 18:50:36 +020080
Bram Moolenaarf52f0602021-03-10 21:26:37 +010081func Test_nocatch_process_still_running()
Bram Moolenaar6635ae12021-03-10 21:46:39 +010082 " sysinfo.uptime probably only works on Linux
Bram Moolenaar776b9542021-03-10 22:27:48 +010083 if !has('linux')
84 let g:skipped_reason = 'only works on Linux'
85 return
86 endif
Bram Moolenaar6635ae12021-03-10 21:46:39 +010087 " the GUI dialog can't be handled
Bram Moolenaar776b9542021-03-10 22:27:48 +010088 if has('gui_running')
89 let g:skipped_reason = 'only works in the terminal'
90 return
91 endif
Bram Moolenaarf52f0602021-03-10 21:26:37 +010092
93 " don't intercept existing swap file here
94 au! SwapExists
95
96 " Edit a file and grab its swapfile.
97 edit Xswaptest
98 call setline(1, ['a', 'b', 'c'])
99 let swname = CopySwapfile()
100
101 " Forget we edited this file
102 new
103 only!
104 bwipe! Xswaptest
105
106 call rename('Xswap', swname)
107 call feedkeys('e', 'tL')
108 redir => editOutput
109 edit Xswaptest
110 redir END
111 call assert_match('E325: ATTENTION', editOutput)
112 call assert_match('file name: .*Xswaptest', editOutput)
113 call assert_match('process ID: \d* (STILL RUNNING)', editOutput)
114
115 " Forget we edited this file
116 new
117 only!
118 bwipe! Xswaptest
119
120 " pretend we rebooted
121 call test_override("uptime", 0)
122 sleep 1
123
124 call rename('Xswap', swname)
125 call feedkeys('e', 'tL')
126 redir => editOutput
127 edit Xswaptest
128 redir END
129 call assert_match('E325: ATTENTION', editOutput)
130 call assert_notmatch('(STILL RUNNING)', editOutput)
131
132 call test_override("ALL", 0)
133 call delete(swname)
134endfunc
135
Yegappan Lakshmanan59b26232021-06-05 20:59:22 +0200136" Test for :recover with multiple swap files
137func Test_recover_multiple_swap_files()
138 CheckUnix
139 new Xfile1
140 call setline(1, ['a', 'b', 'c'])
141 preserve
Yegappan Lakshmanan99285552021-06-06 17:12:46 +0200142 let b = readblob(swapname(''))
Yegappan Lakshmanan59b26232021-06-05 20:59:22 +0200143 call writefile(b, '.Xfile1.swm')
144 call writefile(b, '.Xfile1.swn')
145 call writefile(b, '.Xfile1.swo')
146 %bw!
147 call feedkeys(":recover Xfile1\<CR>3\<CR>q", 'xt')
148 call assert_equal(['a', 'b', 'c'], getline(1, '$'))
Yegappan Lakshmanan8cf02e52021-06-07 20:41:22 +0200149 " try using out-of-range number to select a swap file
150 bw!
151 call feedkeys(":recover Xfile1\<CR>4\<CR>q", 'xt')
152 call assert_equal('Xfile1', @%)
153 call assert_equal([''], getline(1, '$'))
154 bw!
155 call feedkeys(":recover Xfile1\<CR>0\<CR>q", 'xt')
156 call assert_equal('Xfile1', @%)
157 call assert_equal([''], getline(1, '$'))
158 bw!
Yegappan Lakshmanan59b26232021-06-05 20:59:22 +0200159
160 call delete('.Xfile1.swm')
161 call delete('.Xfile1.swn')
162 call delete('.Xfile1.swo')
163endfunc
164
165" Test for :recover using an empty swap file
166func Test_recover_empty_swap_file()
167 CheckUnix
168 call writefile([], '.Xfile1.swp')
169 let msg = execute('recover Xfile1')
170 call assert_match('Unable to read block 0 from .Xfile1.swp', msg)
171 call assert_equal('Xfile1', @%)
172 bw!
173 " :recover from an empty buffer
174 call assert_fails('recover', 'E305:')
175 call delete('.Xfile1.swp')
176endfunc
177
178" Test for :recover using a corrupted swap file
Yegappan Lakshmanan8cf02e52021-06-07 20:41:22 +0200179" Refer to the comments in the memline.c file for the swap file headers
180" definition.
Yegappan Lakshmanan59b26232021-06-05 20:59:22 +0200181func Test_recover_corrupted_swap_file()
182 CheckUnix
Yegappan Lakshmanan99285552021-06-06 17:12:46 +0200183
Yegappan Lakshmanan59b26232021-06-05 20:59:22 +0200184 " recover using a partial swap file
185 call writefile(0z1234, '.Xfile1.swp')
186 call assert_fails('recover Xfile1', 'E295:')
187 bw!
188
189 " recover using invalid content in the swap file
190 call writefile([repeat('1', 2*1024)], '.Xfile1.swp')
191 call assert_fails('recover Xfile1', 'E307:')
192 call delete('.Xfile1.swp')
193
194 " :recover using a swap file with a corrupted header
195 edit Xfile1
196 preserve
197 let sn = swapname('')
198 let b = readblob(sn)
Yegappan Lakshmanan99285552021-06-06 17:12:46 +0200199 let save_b = copy(b)
Yegappan Lakshmanan59b26232021-06-05 20:59:22 +0200200 bw!
Yegappan Lakshmanan99285552021-06-06 17:12:46 +0200201 " Run these tests only on little-endian systems. These tests fail on a
202 " big-endian system (IBM S390x system).
203 if b[1008:1011] == 0z33323130
204 \ && b[4096:4097] == 0z7470
205 \ && b[8192:8193] == 0z6164
206
207 " clear the B0_MAGIC_LONG field
208 let b[1008:1011] = 0z00000000
209 call writefile(b, sn)
210 let msg = execute('recover Xfile1')
211 call assert_match('the file has been damaged', msg)
Yegappan Lakshmanan8cf02e52021-06-07 20:41:22 +0200212 call assert_equal('Xfile1', @%)
213 call assert_equal([''], getline(1, '$'))
214 bw!
215
216 " reduce the page size
217 let b = copy(save_b)
218 let b[12:15] = 0z00010000
219 call writefile(b, sn)
220 let msg = execute('recover Xfile1')
221 call assert_match('page size is smaller than minimum value', msg)
222 call assert_equal('Xfile1', @%)
223 call assert_equal([''], getline(1, '$'))
Yegappan Lakshmanan99285552021-06-06 17:12:46 +0200224 bw!
225
226 " clear the pointer ID
227 let b = copy(save_b)
228 let b[4096:4097] = 0z0000
229 call writefile(b, sn)
230 call assert_fails('recover Xfile1', 'E310:')
Yegappan Lakshmanan8cf02e52021-06-07 20:41:22 +0200231 call assert_equal('Xfile1', @%)
232 call assert_equal([''], getline(1, '$'))
233 bw!
234
235 " set the number of pointers in a pointer block to zero
236 let b = copy(save_b)
237 let b[4098:4099] = 0z0000
238 call writefile(b, sn)
239 call assert_fails('recover Xfile1', 'E312:')
240 call assert_equal('Xfile1', @%)
241 call assert_equal(['???EMPTY BLOCK'], getline(1, '$'))
242 bw!
243
244 " set the block number in a pointer entry to a negative number
245 let b = copy(save_b)
246 let b[4104:4111] = 0z00000000.00000080
247 call writefile(b, sn)
248 call assert_fails('recover Xfile1', 'E312:')
249 call assert_equal('Xfile1', @%)
250 call assert_equal(['???LINES MISSING'], getline(1, '$'))
Yegappan Lakshmanan99285552021-06-06 17:12:46 +0200251 bw!
252
253 " clear the data block ID
254 let b = copy(save_b)
255 let b[8192:8193] = 0z0000
256 call writefile(b, sn)
257 call assert_fails('recover Xfile1', 'E312:')
Yegappan Lakshmanan8cf02e52021-06-07 20:41:22 +0200258 call assert_equal('Xfile1', @%)
259 call assert_equal(['???BLOCK MISSING'], getline(1, '$'))
260 bw!
261
262 " set the number of lines in the data block to zero
263 let b = copy(save_b)
264 let b[8208:8211] = 0z00000000
265 call writefile(b, sn)
266 call assert_fails('recover Xfile1', 'E312:')
267 call assert_equal('Xfile1', @%)
268 call assert_equal(['??? from here until ???END lines may have been inserted/deleted',
269 \ '???END'], getline(1, '$'))
270 bw!
271
272 " use an invalid text start for the lines in a data block
273 let b = copy(save_b)
274 let b[8216:8219] = 0z00000000
275 call writefile(b, sn)
276 call assert_fails('recover Xfile1', 'E312:')
277 call assert_equal('Xfile1', @%)
278 call assert_equal(['???'], getline(1, '$'))
279 bw!
280
281 " use an incorrect text end (db_txt_end) for the data block
282 let b = copy(save_b)
283 let b[8204:8207] = 0z80000000
284 call writefile(b, sn)
285 call assert_fails('recover Xfile1', 'E312:')
286 call assert_equal('Xfile1', @%)
287 call assert_equal(['??? from here until ???END lines may be messed up', '',
288 \ '???END'], getline(1, '$'))
Yegappan Lakshmanan99285552021-06-06 17:12:46 +0200289 bw!
290
291 " remove the data block
292 let b = copy(save_b)
293 call writefile(b[:8191], sn)
294 call assert_fails('recover Xfile1', 'E312:')
Yegappan Lakshmanan8cf02e52021-06-07 20:41:22 +0200295 call assert_equal('Xfile1', @%)
296 call assert_equal(['???MANY LINES MISSING'], getline(1, '$'))
Yegappan Lakshmanan99285552021-06-06 17:12:46 +0200297 endif
298
Yegappan Lakshmanan59b26232021-06-05 20:59:22 +0200299 bw!
300 call delete(sn)
301endfunc
302
303" Test for :recover using an encrypted swap file
304func Test_recover_encrypted_swap_file()
305 CheckUnix
306
307 " Recover an encrypted file from the swap file without the original file
308 new Xfile1
309 call feedkeys(":X\<CR>vim\<CR>vim\<CR>", 'xt')
310 call setline(1, ['aaa', 'bbb', 'ccc'])
311 preserve
312 let b = readblob('.Xfile1.swp')
313 call writefile(b, '.Xfile1.swm')
314 bw!
315 call feedkeys(":recover Xfile1\<CR>vim\<CR>\<CR>", 'xt')
316 call assert_equal(['aaa', 'bbb', 'ccc'], getline(1, '$'))
317 bw!
318 call delete('.Xfile1.swm')
319
320 " Recover an encrypted file from the swap file with the original file
321 new Xfile1
322 call feedkeys(":X\<CR>vim\<CR>vim\<CR>", 'xt')
323 call setline(1, ['aaa', 'bbb', 'ccc'])
324 update
325 call setline(1, ['111', '222', '333'])
326 preserve
327 let b = readblob('.Xfile1.swp')
328 call writefile(b, '.Xfile1.swm')
329 bw!
330 call feedkeys(":recover Xfile1\<CR>vim\<CR>\<CR>", 'xt')
331 call assert_equal(['111', '222', '333'], getline(1, '$'))
332 call assert_true(&modified)
333 bw!
334 call delete('.Xfile1.swm')
335 call delete('Xfile1')
336endfunc
337
338" Test for :recover using a unreadable swap file
339func Test_recover_unreadble_swap_file()
340 CheckUnix
341 CheckNotRoot
342 new Xfile1
343 let b = readblob('.Xfile1.swp')
344 call writefile(b, '.Xfile1.swm')
345 bw!
346 call setfperm('.Xfile1.swm', '-w-------')
347 call assert_fails('recover Xfile1', 'E306:')
348 call delete('.Xfile1.swm')
349endfunc
350
351" Test for using :recover when the original file and the swap file have the
352" same contents.
353func Test_recover_unmodified_file()
354 CheckUnix
355 call writefile(['aaa', 'bbb', 'ccc'], 'Xfile1')
356 edit Xfile1
357 preserve
358 let b = readblob('.Xfile1.swp')
359 %bw!
360 call writefile(b, '.Xfile1.swz')
361 let msg = execute('recover Xfile1')
362 call assert_equal(['aaa', 'bbb', 'ccc'], getline(1, '$'))
363 call assert_false(&modified)
364 call assert_match('Buffer contents equals file contents', msg)
365 bw!
366 call delete('Xfile1')
367 call delete('.Xfile1.swz')
368endfunc
369
Yegappan Lakshmanan8cf02e52021-06-07 20:41:22 +0200370" Test for recovering a file when editing a symbolically linked file
371func Test_recover_symbolic_link()
372 CheckUnix
373 call writefile(['aaa', 'bbb', 'ccc'], 'Xfile1')
374 silent !ln -s Xfile1 Xfile2
375 edit Xfile2
376 call assert_equal('.Xfile1.swp', fnamemodify(swapname(''), ':t'))
377 preserve
378 let b = readblob('.Xfile1.swp')
379 %bw!
380 call writefile([], 'Xfile1')
381 call writefile(b, '.Xfile1.swp')
382 silent! recover Xfile2
383 call assert_equal(['aaa', 'bbb', 'ccc'], getline(1, '$'))
384 call assert_true(&modified)
385 update
386 %bw!
387 call assert_equal(['aaa', 'bbb', 'ccc'], readfile('Xfile1'))
388 call delete('Xfile1')
389 call delete('Xfile2')
390 call delete('.Xfile1.swp')
391endfunc
392
Bram Moolenaar6d91bcb2020-08-12 18:50:36 +0200393" vim: shiftwidth=2 sts=2 expandtab