blob: 5326576d02144add5b33bac2539091cf21549af0 [file] [log] [blame]
Bram Moolenaar113bf062019-04-17 16:54:05 +02001" Tests for the Vim script debug commands
2
3source shared.vim
4source screendump.vim
Bram Moolenaar8c5a2782019-08-07 23:07:07 +02005source check.vim
Bram Moolenaar113bf062019-04-17 16:54:05 +02006
Bram Moolenaarb7f4fa52020-08-08 14:41:52 +02007CheckRunVimInTerminal
8
9func CheckCWD()
10 " Check that the longer lines don't wrap due to the length of the script name
11 " in cwd
12 let script_len = len( getcwd() .. '/Xtest1.vim' )
13 let longest_line = len( 'Breakpoint in "" line 1' )
14 if script_len > ( 75 - longest_line )
15 throw 'Skipped: Your CWD has too many characters'
16 endif
17endfunc
18command! -nargs=0 -bar CheckCWD call CheckCWD()
19
Bram Moolenaar18dc3552020-11-22 14:24:00 +010020" "options" argument can contain:
21" 'msec' - time to wait for a match
22" 'match' - "pattern" to use "lines" as pattern instead of text
Bram Moolenaar6ca6ca42020-07-27 19:47:07 +020023func CheckDbgOutput(buf, lines, options = {})
24 " Verify the expected output
25 let lnum = 20 - len(a:lines)
Bram Moolenaar18dc3552020-11-22 14:24:00 +010026 let msec = get(a:options, 'msec', 1000)
Bram Moolenaar6ca6ca42020-07-27 19:47:07 +020027 for l in a:lines
28 if get(a:options, 'match', 'equal') ==# 'pattern'
Bram Moolenaar18dc3552020-11-22 14:24:00 +010029 call WaitForAssert({-> assert_match(l, term_getline(a:buf, lnum))}, msec)
Bram Moolenaar6ca6ca42020-07-27 19:47:07 +020030 else
Bram Moolenaar18dc3552020-11-22 14:24:00 +010031 call WaitForAssert({-> assert_equal(l, term_getline(a:buf, lnum))}, msec)
Bram Moolenaar6ca6ca42020-07-27 19:47:07 +020032 endif
33 let lnum += 1
34 endfor
35endfunc
36
Bram Moolenaar113bf062019-04-17 16:54:05 +020037" Run a Vim debugger command
38" If the expected output argument is supplied, then check for it.
39func RunDbgCmd(buf, cmd, ...)
40 call term_sendkeys(a:buf, a:cmd . "\r")
Bram Moolenaar6a2c5a72020-04-08 21:50:25 +020041 call TermWait(a:buf)
Bram Moolenaar113bf062019-04-17 16:54:05 +020042
43 if a:0 != 0
Bram Moolenaar6ca6ca42020-07-27 19:47:07 +020044 let options = #{match: 'equal'}
45 if a:0 > 1
46 call extend(options, a:2)
47 endif
48 call CheckDbgOutput(a:buf, a:1, options)
Bram Moolenaar113bf062019-04-17 16:54:05 +020049 endif
50endfunc
51
52" Debugger tests
53func Test_Debugger()
Bram Moolenaar113bf062019-04-17 16:54:05 +020054 " Create a Vim script with some functions
Bram Moolenaare7eb9272019-06-24 00:58:07 +020055 let lines =<< trim END
56 func Foo()
57 let var1 = 1
58 let var2 = Bar(var1) + 9
59 return var2
60 endfunc
61 func Bar(var)
62 let var1 = 2 + a:var
63 let var2 = Bazz(var1) + 4
64 return var2
65 endfunc
66 func Bazz(var)
67 try
68 let var1 = 3 + a:var
69 let var3 = "another var"
70 let var3 = "value2"
71 catch
72 let var4 = "exception"
73 endtry
74 return var1
75 endfunc
76 END
77 call writefile(lines, 'Xtest.vim')
Bram Moolenaar113bf062019-04-17 16:54:05 +020078
79 " Start Vim in a terminal
80 let buf = RunVimInTerminal('-S Xtest.vim', {})
81
82 " Start the Vim debugger
Bram Moolenaarddd33082019-06-03 23:07:25 +020083 call RunDbgCmd(buf, ':debug echo Foo()', ['cmd: echo Foo()'])
Bram Moolenaar113bf062019-04-17 16:54:05 +020084
85 " Create a few stack frames by stepping through functions
Bram Moolenaarddd33082019-06-03 23:07:25 +020086 call RunDbgCmd(buf, 'step', ['line 1: let var1 = 1'])
87 call RunDbgCmd(buf, 'step', ['line 2: let var2 = Bar(var1) + 9'])
88 call RunDbgCmd(buf, 'step', ['line 1: let var1 = 2 + a:var'])
89 call RunDbgCmd(buf, 'step', ['line 2: let var2 = Bazz(var1) + 4'])
90 call RunDbgCmd(buf, 'step', ['line 1: try'])
91 call RunDbgCmd(buf, 'step', ['line 2: let var1 = 3 + a:var'])
92 call RunDbgCmd(buf, 'step', ['line 3: let var3 = "another var"'])
Bram Moolenaar113bf062019-04-17 16:54:05 +020093
94 " check backtrace
95 call RunDbgCmd(buf, 'backtrace', [
96 \ ' 2 function Foo[2]',
97 \ ' 1 Bar[2]',
98 \ '->0 Bazz',
Bram Moolenaar0fdd9432019-04-20 22:28:48 +020099 \ 'line 3: let var3 = "another var"'])
Bram Moolenaar113bf062019-04-17 16:54:05 +0200100
101 " Check variables in different stack frames
102 call RunDbgCmd(buf, 'echo var1', ['6'])
103
104 call RunDbgCmd(buf, 'up')
105 call RunDbgCmd(buf, 'back', [
106 \ ' 2 function Foo[2]',
107 \ '->1 Bar[2]',
108 \ ' 0 Bazz',
Bram Moolenaar0fdd9432019-04-20 22:28:48 +0200109 \ 'line 3: let var3 = "another var"'])
Bram Moolenaar113bf062019-04-17 16:54:05 +0200110 call RunDbgCmd(buf, 'echo var1', ['3'])
111
112 call RunDbgCmd(buf, 'u')
113 call RunDbgCmd(buf, 'bt', [
114 \ '->2 function Foo[2]',
115 \ ' 1 Bar[2]',
116 \ ' 0 Bazz',
Bram Moolenaar0fdd9432019-04-20 22:28:48 +0200117 \ 'line 3: let var3 = "another var"'])
Bram Moolenaar113bf062019-04-17 16:54:05 +0200118 call RunDbgCmd(buf, 'echo var1', ['1'])
119
120 " Undefined variables
121 call RunDbgCmd(buf, 'step')
122 call RunDbgCmd(buf, 'frame 2')
123 call RunDbgCmd(buf, 'echo var3', [
124 \ 'Error detected while processing function Foo[2]..Bar[2]..Bazz:',
Bram Moolenaar0fdd9432019-04-20 22:28:48 +0200125 \ 'line 4:',
Bram Moolenaar113bf062019-04-17 16:54:05 +0200126 \ 'E121: Undefined variable: var3'])
127
128 " var3 is defined in this level with some other value
129 call RunDbgCmd(buf, 'fr 0')
130 call RunDbgCmd(buf, 'echo var3', ['another var'])
131
132 call RunDbgCmd(buf, 'step')
Bram Moolenaar0fdd9432019-04-20 22:28:48 +0200133 call RunDbgCmd(buf, '')
134 call RunDbgCmd(buf, '')
135 call RunDbgCmd(buf, '')
136 call RunDbgCmd(buf, '')
Bram Moolenaar113bf062019-04-17 16:54:05 +0200137 call RunDbgCmd(buf, 'step', [
138 \ 'function Foo[2]..Bar',
139 \ 'line 3: End of function'])
140 call RunDbgCmd(buf, 'up')
141
142 " Undefined var2
143 call RunDbgCmd(buf, 'echo var2', [
144 \ 'Error detected while processing function Foo[2]..Bar:',
145 \ 'line 3:',
146 \ 'E121: Undefined variable: var2'])
147
148 " Var2 is defined with 10
149 call RunDbgCmd(buf, 'down')
150 call RunDbgCmd(buf, 'echo var2', ['10'])
151
152 " Backtrace movements
153 call RunDbgCmd(buf, 'b', [
154 \ ' 1 function Foo[2]',
155 \ '->0 Bar',
156 \ 'line 3: End of function'])
157
158 " next command cannot go down, we are on bottom
159 call RunDbgCmd(buf, 'down', ['frame is zero'])
160 call RunDbgCmd(buf, 'up')
161
162 " next command cannot go up, we are on top
163 call RunDbgCmd(buf, 'up', ['frame at highest level: 1'])
164 call RunDbgCmd(buf, 'where', [
165 \ '->1 function Foo[2]',
166 \ ' 0 Bar',
167 \ 'line 3: End of function'])
168
169 " fil is not frame or finish, it is file
170 call RunDbgCmd(buf, 'fil', ['"[No Name]" --No lines in buffer--'])
171
172 " relative backtrace movement
173 call RunDbgCmd(buf, 'fr -1')
174 call RunDbgCmd(buf, 'frame', [
175 \ ' 1 function Foo[2]',
176 \ '->0 Bar',
177 \ 'line 3: End of function'])
178
179 call RunDbgCmd(buf, 'fr +1')
180 call RunDbgCmd(buf, 'fram', [
181 \ '->1 function Foo[2]',
182 \ ' 0 Bar',
183 \ 'line 3: End of function'])
184
185 " go beyond limits does not crash
186 call RunDbgCmd(buf, 'fr 100', ['frame at highest level: 1'])
187 call RunDbgCmd(buf, 'fra', [
188 \ '->1 function Foo[2]',
189 \ ' 0 Bar',
190 \ 'line 3: End of function'])
191
192 call RunDbgCmd(buf, 'frame -40', ['frame is zero'])
193 call RunDbgCmd(buf, 'fram', [
194 \ ' 1 function Foo[2]',
195 \ '->0 Bar',
196 \ 'line 3: End of function'])
197
198 " final result 19
199 call RunDbgCmd(buf, 'cont', ['19'])
200
201 " breakpoints tests
202
203 " Start a debug session, so that reading the last line from the terminal
204 " works properly.
Bram Moolenaar18dc3552020-11-22 14:24:00 +0100205 call RunDbgCmd(buf, ':debug echo Foo()', ['cmd: echo Foo()'])
Bram Moolenaar113bf062019-04-17 16:54:05 +0200206
207 " No breakpoints
208 call RunDbgCmd(buf, 'breakl', ['No breakpoints defined'])
209
210 " Place some breakpoints
211 call RunDbgCmd(buf, 'breaka func Bar')
212 call RunDbgCmd(buf, 'breaklis', [' 1 func Bar line 1'])
213 call RunDbgCmd(buf, 'breakadd func 3 Bazz')
214 call RunDbgCmd(buf, 'breaklist', [' 1 func Bar line 1',
215 \ ' 2 func Bazz line 3'])
216
217 " Check whether the breakpoints are hit
218 call RunDbgCmd(buf, 'cont', [
219 \ 'Breakpoint in "Bar" line 1',
220 \ 'function Foo[2]..Bar',
221 \ 'line 1: let var1 = 2 + a:var'])
222 call RunDbgCmd(buf, 'cont', [
223 \ 'Breakpoint in "Bazz" line 3',
224 \ 'function Foo[2]..Bar[2]..Bazz',
Bram Moolenaar0fdd9432019-04-20 22:28:48 +0200225 \ 'line 3: let var3 = "another var"'])
Bram Moolenaar113bf062019-04-17 16:54:05 +0200226
227 " Delete the breakpoints
228 call RunDbgCmd(buf, 'breakd 1')
229 call RunDbgCmd(buf, 'breakli', [' 2 func Bazz line 3'])
230 call RunDbgCmd(buf, 'breakdel func 3 Bazz')
231 call RunDbgCmd(buf, 'breakl', ['No breakpoints defined'])
232
233 call RunDbgCmd(buf, 'cont')
234
235 " Make sure the breakpoints are removed
236 call RunDbgCmd(buf, ':echo Foo()', ['19'])
237
238 " Delete a non-existing breakpoint
239 call RunDbgCmd(buf, ':breakdel 2', ['E161: Breakpoint not found: 2'])
240
241 " Expression breakpoint
242 call RunDbgCmd(buf, ':breakadd func 2 Bazz')
Bram Moolenaar0fdd9432019-04-20 22:28:48 +0200243 call RunDbgCmd(buf, ':echo Bazz(1)', [
244 \ 'Entering Debug mode. Type "cont" to continue.',
245 \ 'function Bazz',
246 \ 'line 2: let var1 = 3 + a:var'])
247 call RunDbgCmd(buf, 'step')
Bram Moolenaar113bf062019-04-17 16:54:05 +0200248 call RunDbgCmd(buf, 'step')
249 call RunDbgCmd(buf, 'breaka expr var3')
Bram Moolenaar0fdd9432019-04-20 22:28:48 +0200250 call RunDbgCmd(buf, 'breakl', [' 3 func Bazz line 2',
251 \ ' 4 expr var3'])
252 call RunDbgCmd(buf, 'cont', ['Breakpoint in "Bazz" line 5',
Bram Moolenaar113bf062019-04-17 16:54:05 +0200253 \ 'Oldval = "''another var''"',
254 \ 'Newval = "''value2''"',
255 \ 'function Bazz',
Bram Moolenaar0fdd9432019-04-20 22:28:48 +0200256 \ 'line 5: catch'])
Bram Moolenaar113bf062019-04-17 16:54:05 +0200257
258 call RunDbgCmd(buf, 'breakdel *')
259 call RunDbgCmd(buf, 'breakl', ['No breakpoints defined'])
260
Bram Moolenaar0fdd9432019-04-20 22:28:48 +0200261 " Check for error cases
262 call RunDbgCmd(buf, 'breakadd abcd', [
263 \ 'Error detected while processing function Bazz:',
264 \ 'line 5:',
265 \ 'E475: Invalid argument: abcd'])
266 call RunDbgCmd(buf, 'breakadd func', ['E475: Invalid argument: func'])
267 call RunDbgCmd(buf, 'breakadd func 2', ['E475: Invalid argument: func 2'])
268 call RunDbgCmd(buf, 'breaka func a()', ['E475: Invalid argument: func a()'])
269 call RunDbgCmd(buf, 'breakd abcd', ['E475: Invalid argument: abcd'])
270 call RunDbgCmd(buf, 'breakd func', ['E475: Invalid argument: func'])
271 call RunDbgCmd(buf, 'breakd func a()', ['E475: Invalid argument: func a()'])
272 call RunDbgCmd(buf, 'breakd func a', ['E161: Breakpoint not found: func a'])
273 call RunDbgCmd(buf, 'breakd expr', ['E475: Invalid argument: expr'])
274 call RunDbgCmd(buf, 'breakd expr x', [
275 \ 'E121: Undefined variable: x',
276 \ 'E161: Breakpoint not found: expr x'])
277
Bram Moolenaar113bf062019-04-17 16:54:05 +0200278 " finish the current function
279 call RunDbgCmd(buf, 'finish', [
280 \ 'function Bazz',
Bram Moolenaar0fdd9432019-04-20 22:28:48 +0200281 \ 'line 8: End of function'])
282 call RunDbgCmd(buf, 'cont')
283
284 " Test for :next
285 call RunDbgCmd(buf, ':debug echo Bar(1)')
286 call RunDbgCmd(buf, 'step')
287 call RunDbgCmd(buf, 'next')
288 call RunDbgCmd(buf, '', [
289 \ 'function Bar',
290 \ 'line 3: return var2'])
291 call RunDbgCmd(buf, 'c')
292
293 " Test for :interrupt
294 call RunDbgCmd(buf, ':debug echo Bazz(1)')
295 call RunDbgCmd(buf, 'step')
296 call RunDbgCmd(buf, 'step')
297 call RunDbgCmd(buf, 'interrupt', [
298 \ 'Exception thrown: Vim:Interrupt',
299 \ 'function Bazz',
300 \ 'line 5: catch'])
301 call RunDbgCmd(buf, 'c')
302
303 " Test for :quit
304 call RunDbgCmd(buf, ':debug echo Foo()')
305 call RunDbgCmd(buf, 'breakdel *')
306 call RunDbgCmd(buf, 'breakadd func 3 Foo')
307 call RunDbgCmd(buf, 'breakadd func 3 Bazz')
308 call RunDbgCmd(buf, 'cont', [
309 \ 'Breakpoint in "Bazz" line 3',
310 \ 'function Foo[2]..Bar[2]..Bazz',
311 \ 'line 3: let var3 = "another var"'])
312 call RunDbgCmd(buf, 'quit', [
313 \ 'Breakpoint in "Foo" line 3',
314 \ 'function Foo',
315 \ 'line 3: return var2'])
316 call RunDbgCmd(buf, 'breakdel *')
317 call RunDbgCmd(buf, 'quit')
318 call RunDbgCmd(buf, 'enew! | only!')
319
320 call StopVimInTerminal(buf)
321
322 " Tests for :breakadd file and :breakadd here
323 " Breakpoints should be set before sourcing the file
324
Bram Moolenaare7eb9272019-06-24 00:58:07 +0200325 let lines =<< trim END
326 let var1 = 10
327 let var2 = 20
328 let var3 = 30
329 let var4 = 40
330 END
331 call writefile(lines, 'Xtest.vim')
Bram Moolenaar0fdd9432019-04-20 22:28:48 +0200332
333 " Start Vim in a terminal
334 let buf = RunVimInTerminal('Xtest.vim', {})
335 call RunDbgCmd(buf, ':breakadd file 2 Xtest.vim')
336 call RunDbgCmd(buf, ':4 | breakadd here')
337 call RunDbgCmd(buf, ':source Xtest.vim', ['line 2: let var2 = 20'])
338 call RunDbgCmd(buf, 'cont', ['line 4: let var4 = 40'])
Bram Moolenaar113bf062019-04-17 16:54:05 +0200339 call RunDbgCmd(buf, 'cont')
340
341 call StopVimInTerminal(buf)
342
343 call delete('Xtest.vim')
Bram Moolenaar16c62322020-08-13 19:20:04 +0200344 %bw!
345 call assert_fails('breakadd here', 'E32:')
Bram Moolenaar531be472020-09-23 22:38:05 +0200346 call assert_fails('breakadd file Xtest.vim /\)/', 'E55:')
Bram Moolenaar113bf062019-04-17 16:54:05 +0200347endfunc
Bram Moolenaar6ca6ca42020-07-27 19:47:07 +0200348
349func Test_Backtrace_Through_Source()
Bram Moolenaarb7f4fa52020-08-08 14:41:52 +0200350 CheckCWD
Bram Moolenaar6ca6ca42020-07-27 19:47:07 +0200351 let file1 =<< trim END
352 func SourceAnotherFile()
353 source Xtest2.vim
354 endfunc
355
356 func CallAFunction()
357 call SourceAnotherFile()
358 call File2Function()
359 endfunc
360
361 func GlobalFunction()
362 call CallAFunction()
363 endfunc
364 END
365 call writefile(file1, 'Xtest1.vim')
366
367 let file2 =<< trim END
368 func DoAThing()
369 echo "DoAThing"
370 endfunc
371
372 func File2Function()
373 call DoAThing()
374 endfunc
375
376 call File2Function()
377 END
378 call writefile(file2, 'Xtest2.vim')
379
380 let buf = RunVimInTerminal('-S Xtest1.vim', {})
381
382 call RunDbgCmd(buf,
383 \ ':debug call GlobalFunction()',
384 \ ['cmd: call GlobalFunction()'])
385 call RunDbgCmd(buf, 'step', ['line 1: call CallAFunction()'])
386
387 call RunDbgCmd(buf, 'backtrace', ['>backtrace',
388 \ '->0 function GlobalFunction',
389 \ 'line 1: call CallAFunction()'])
390
391 call RunDbgCmd(buf, 'step', ['line 1: call SourceAnotherFile()'])
392 call RunDbgCmd(buf, 'step', ['line 1: source Xtest2.vim'])
393
394 call RunDbgCmd(buf, 'backtrace', ['>backtrace',
395 \ ' 2 function GlobalFunction[1]',
396 \ ' 1 CallAFunction[1]',
397 \ '->0 SourceAnotherFile',
398 \ 'line 1: source Xtest2.vim'])
399
400 " Step into the 'source' command. Note that we print the full trace all the
401 " way though the source command.
402 call RunDbgCmd(buf, 'step', ['line 1: func DoAThing()'])
403 call RunDbgCmd(buf, 'backtrace', [
404 \ '>backtrace',
405 \ ' 3 function GlobalFunction[1]',
406 \ ' 2 CallAFunction[1]',
407 \ ' 1 SourceAnotherFile[1]',
408 \ '->0 script ' .. getcwd() .. '/Xtest2.vim',
409 \ 'line 1: func DoAThing()'])
410
Bram Moolenaarb7f4fa52020-08-08 14:41:52 +0200411 call RunDbgCmd( buf, 'up' )
412 call RunDbgCmd( buf, 'backtrace', [
413 \ '>backtrace',
414 \ ' 3 function GlobalFunction[1]',
415 \ ' 2 CallAFunction[1]',
416 \ '->1 SourceAnotherFile[1]',
417 \ ' 0 script ' .. getcwd() .. '/Xtest2.vim',
418 \ 'line 1: func DoAThing()' ] )
419
420 call RunDbgCmd( buf, 'up' )
421 call RunDbgCmd( buf, 'backtrace', [
422 \ '>backtrace',
423 \ ' 3 function GlobalFunction[1]',
424 \ '->2 CallAFunction[1]',
425 \ ' 1 SourceAnotherFile[1]',
426 \ ' 0 script ' .. getcwd() .. '/Xtest2.vim',
427 \ 'line 1: func DoAThing()' ] )
428
429 call RunDbgCmd( buf, 'up' )
430 call RunDbgCmd( buf, 'backtrace', [
431 \ '>backtrace',
432 \ '->3 function GlobalFunction[1]',
433 \ ' 2 CallAFunction[1]',
434 \ ' 1 SourceAnotherFile[1]',
435 \ ' 0 script ' .. getcwd() .. '/Xtest2.vim',
436 \ 'line 1: func DoAThing()' ] )
437
438 call RunDbgCmd( buf, 'up', [ 'frame at highest level: 3' ] )
439 call RunDbgCmd( buf, 'backtrace', [
440 \ '>backtrace',
441 \ '->3 function GlobalFunction[1]',
442 \ ' 2 CallAFunction[1]',
443 \ ' 1 SourceAnotherFile[1]',
444 \ ' 0 script ' .. getcwd() .. '/Xtest2.vim',
445 \ 'line 1: func DoAThing()' ] )
446
447 call RunDbgCmd( buf, 'down' )
448 call RunDbgCmd( buf, 'backtrace', [
449 \ '>backtrace',
450 \ ' 3 function GlobalFunction[1]',
451 \ '->2 CallAFunction[1]',
452 \ ' 1 SourceAnotherFile[1]',
453 \ ' 0 script ' .. getcwd() .. '/Xtest2.vim',
454 \ 'line 1: func DoAThing()' ] )
455
456 call RunDbgCmd( buf, 'down' )
457 call RunDbgCmd( buf, 'backtrace', [
458 \ '>backtrace',
459 \ ' 3 function GlobalFunction[1]',
460 \ ' 2 CallAFunction[1]',
461 \ '->1 SourceAnotherFile[1]',
462 \ ' 0 script ' .. getcwd() .. '/Xtest2.vim',
463 \ 'line 1: func DoAThing()' ] )
464
465 call RunDbgCmd( buf, 'down' )
466 call RunDbgCmd( buf, 'backtrace', [
467 \ '>backtrace',
468 \ ' 3 function GlobalFunction[1]',
469 \ ' 2 CallAFunction[1]',
470 \ ' 1 SourceAnotherFile[1]',
471 \ '->0 script ' .. getcwd() .. '/Xtest2.vim',
472 \ 'line 1: func DoAThing()' ] )
473
474 call RunDbgCmd( buf, 'down', [ 'frame is zero' ] )
475
Bram Moolenaar6ca6ca42020-07-27 19:47:07 +0200476 " step until we have another meaninfgul trace
477 call RunDbgCmd(buf, 'step', ['line 5: func File2Function()'])
478 call RunDbgCmd(buf, 'step', ['line 9: call File2Function()'])
479 call RunDbgCmd(buf, 'backtrace', [
480 \ '>backtrace',
481 \ ' 3 function GlobalFunction[1]',
482 \ ' 2 CallAFunction[1]',
483 \ ' 1 SourceAnotherFile[1]',
484 \ '->0 script ' .. getcwd() .. '/Xtest2.vim',
485 \ 'line 9: call File2Function()'])
486
487 call RunDbgCmd(buf, 'step', ['line 1: call DoAThing()'])
488 call RunDbgCmd(buf, 'step', ['line 1: echo "DoAThing"'])
489 call RunDbgCmd(buf, 'backtrace', [
490 \ '>backtrace',
491 \ ' 5 function GlobalFunction[1]',
492 \ ' 4 CallAFunction[1]',
493 \ ' 3 SourceAnotherFile[1]',
494 \ ' 2 script ' .. getcwd() .. '/Xtest2.vim[9]',
495 \ ' 1 function File2Function[1]',
496 \ '->0 DoAThing',
497 \ 'line 1: echo "DoAThing"'])
498
499 " Now, step (back to Xfile1.vim), and call the function _in_ Xfile2.vim
500 call RunDbgCmd(buf, 'step', ['line 1: End of function'])
501 call RunDbgCmd(buf, 'step', ['line 1: End of function'])
502 call RunDbgCmd(buf, 'step', ['line 10: End of sourced file'])
503 call RunDbgCmd(buf, 'step', ['line 1: End of function'])
504 call RunDbgCmd(buf, 'step', ['line 2: call File2Function()'])
505 call RunDbgCmd(buf, 'backtrace', [
506 \ '>backtrace',
507 \ ' 1 function GlobalFunction[1]',
508 \ '->0 CallAFunction',
509 \ 'line 2: call File2Function()'])
510
511 call RunDbgCmd(buf, 'step', ['line 1: call DoAThing()'])
512 call RunDbgCmd(buf, 'backtrace', [
513 \ '>backtrace',
514 \ ' 2 function GlobalFunction[1]',
515 \ ' 1 CallAFunction[2]',
516 \ '->0 File2Function',
517 \ 'line 1: call DoAThing()'])
518
519 call StopVimInTerminal(buf)
520 call delete('Xtest1.vim')
521 call delete('Xtest2.vim')
522endfunc
523
524func Test_Backtrace_Autocmd()
Bram Moolenaarb7f4fa52020-08-08 14:41:52 +0200525 CheckCWD
Bram Moolenaar6ca6ca42020-07-27 19:47:07 +0200526 let file1 =<< trim END
527 func SourceAnotherFile()
528 source Xtest2.vim
529 endfunc
530
531 func CallAFunction()
532 call SourceAnotherFile()
533 call File2Function()
534 endfunc
535
536 func GlobalFunction()
537 call CallAFunction()
538 endfunc
539
540 au User TestGlobalFunction :call GlobalFunction() | echo "Done"
541 END
542 call writefile(file1, 'Xtest1.vim')
543
544 let file2 =<< trim END
545 func DoAThing()
546 echo "DoAThing"
547 endfunc
548
549 func File2Function()
550 call DoAThing()
551 endfunc
552
553 call File2Function()
554 END
555 call writefile(file2, 'Xtest2.vim')
556
557 let buf = RunVimInTerminal('-S Xtest1.vim', {})
558
559 call RunDbgCmd(buf,
560 \ ':debug doautocmd User TestGlobalFunction',
561 \ ['cmd: doautocmd User TestGlobalFunction'])
562 call RunDbgCmd(buf, 'step', ['cmd: call GlobalFunction() | echo "Done"'])
563
564 " At this point the ontly thing in the stack is the autocommand
565 call RunDbgCmd(buf, 'backtrace', [
566 \ '>backtrace',
567 \ '->0 User Autocommands for "TestGlobalFunction"',
568 \ 'cmd: call GlobalFunction() | echo "Done"'])
569
570 " And now we're back into the call stack
571 call RunDbgCmd(buf, 'step', ['line 1: call CallAFunction()'])
572 call RunDbgCmd(buf, 'backtrace', [
573 \ '>backtrace',
574 \ ' 1 User Autocommands for "TestGlobalFunction"',
575 \ '->0 function GlobalFunction',
576 \ 'line 1: call CallAFunction()'])
577
578 call RunDbgCmd(buf, 'step', ['line 1: call SourceAnotherFile()'])
579 call RunDbgCmd(buf, 'step', ['line 1: source Xtest2.vim'])
580
581 call RunDbgCmd(buf, 'backtrace', [
582 \ '>backtrace',
583 \ ' 3 User Autocommands for "TestGlobalFunction"',
584 \ ' 2 function GlobalFunction[1]',
585 \ ' 1 CallAFunction[1]',
586 \ '->0 SourceAnotherFile',
587 \ 'line 1: source Xtest2.vim'])
588
589 " Step into the 'source' command. Note that we print the full trace all the
590 " way though the source command.
591 call RunDbgCmd(buf, 'step', ['line 1: func DoAThing()'])
592 call RunDbgCmd(buf, 'backtrace', [
593 \ '>backtrace',
594 \ ' 4 User Autocommands for "TestGlobalFunction"',
595 \ ' 3 function GlobalFunction[1]',
596 \ ' 2 CallAFunction[1]',
597 \ ' 1 SourceAnotherFile[1]',
598 \ '->0 script ' .. getcwd() .. '/Xtest2.vim',
599 \ 'line 1: func DoAThing()'])
600
Bram Moolenaarc63b72b2020-08-22 16:04:52 +0200601 call RunDbgCmd( buf, 'up' )
602 call RunDbgCmd( buf, 'backtrace', [
603 \ '>backtrace',
604 \ ' 4 User Autocommands for "TestGlobalFunction"',
605 \ ' 3 function GlobalFunction[1]',
606 \ ' 2 CallAFunction[1]',
607 \ '->1 SourceAnotherFile[1]',
608 \ ' 0 script ' .. getcwd() .. '/Xtest2.vim',
609 \ 'line 1: func DoAThing()' ] )
610
611 call RunDbgCmd( buf, 'up' )
612 call RunDbgCmd( buf, 'backtrace', [
613 \ '>backtrace',
614 \ ' 4 User Autocommands for "TestGlobalFunction"',
615 \ ' 3 function GlobalFunction[1]',
616 \ '->2 CallAFunction[1]',
617 \ ' 1 SourceAnotherFile[1]',
618 \ ' 0 script ' .. getcwd() .. '/Xtest2.vim',
619 \ 'line 1: func DoAThing()' ] )
620
621 call RunDbgCmd( buf, 'up' )
622 call RunDbgCmd( buf, 'backtrace', [
623 \ '>backtrace',
624 \ ' 4 User Autocommands for "TestGlobalFunction"',
625 \ '->3 function GlobalFunction[1]',
626 \ ' 2 CallAFunction[1]',
627 \ ' 1 SourceAnotherFile[1]',
628 \ ' 0 script ' .. getcwd() .. '/Xtest2.vim',
629 \ 'line 1: func DoAThing()' ] )
630
631 call RunDbgCmd( buf, 'up' )
632 call RunDbgCmd( buf, 'backtrace', [
633 \ '>backtrace',
634 \ '->4 User Autocommands for "TestGlobalFunction"',
635 \ ' 3 function GlobalFunction[1]',
636 \ ' 2 CallAFunction[1]',
637 \ ' 1 SourceAnotherFile[1]',
638 \ ' 0 script ' .. getcwd() .. '/Xtest2.vim',
639 \ 'line 1: func DoAThing()' ] )
640
641 call RunDbgCmd( buf, 'up', [ 'frame at highest level: 4' ] )
642 call RunDbgCmd( buf, 'backtrace', [
643 \ '>backtrace',
644 \ '->4 User Autocommands for "TestGlobalFunction"',
645 \ ' 3 function GlobalFunction[1]',
646 \ ' 2 CallAFunction[1]',
647 \ ' 1 SourceAnotherFile[1]',
648 \ ' 0 script ' .. getcwd() .. '/Xtest2.vim',
649 \ 'line 1: func DoAThing()' ] )
650
651 call RunDbgCmd( buf, 'down' )
652 call RunDbgCmd( buf, 'backtrace', [
653 \ '>backtrace',
654 \ ' 4 User Autocommands for "TestGlobalFunction"',
655 \ '->3 function GlobalFunction[1]',
656 \ ' 2 CallAFunction[1]',
657 \ ' 1 SourceAnotherFile[1]',
658 \ ' 0 script ' .. getcwd() .. '/Xtest2.vim',
659 \ 'line 1: func DoAThing()' ] )
660
661
662 call RunDbgCmd( buf, 'down' )
663 call RunDbgCmd( buf, 'backtrace', [
664 \ '>backtrace',
665 \ ' 4 User Autocommands for "TestGlobalFunction"',
666 \ ' 3 function GlobalFunction[1]',
667 \ '->2 CallAFunction[1]',
668 \ ' 1 SourceAnotherFile[1]',
669 \ ' 0 script ' .. getcwd() .. '/Xtest2.vim',
670 \ 'line 1: func DoAThing()' ] )
671
672 call RunDbgCmd( buf, 'down' )
673 call RunDbgCmd( buf, 'backtrace', [
674 \ '>backtrace',
675 \ ' 4 User Autocommands for "TestGlobalFunction"',
676 \ ' 3 function GlobalFunction[1]',
677 \ ' 2 CallAFunction[1]',
678 \ '->1 SourceAnotherFile[1]',
679 \ ' 0 script ' .. getcwd() .. '/Xtest2.vim',
680 \ 'line 1: func DoAThing()' ] )
681
682 call RunDbgCmd( buf, 'down' )
683 call RunDbgCmd( buf, 'backtrace', [
684 \ '>backtrace',
685 \ ' 4 User Autocommands for "TestGlobalFunction"',
686 \ ' 3 function GlobalFunction[1]',
687 \ ' 2 CallAFunction[1]',
688 \ ' 1 SourceAnotherFile[1]',
689 \ '->0 script ' .. getcwd() .. '/Xtest2.vim',
690 \ 'line 1: func DoAThing()' ] )
691
692 call RunDbgCmd( buf, 'down', [ 'frame is zero' ] )
693
Bram Moolenaar6ca6ca42020-07-27 19:47:07 +0200694 " step until we have another meaninfgul trace
695 call RunDbgCmd(buf, 'step', ['line 5: func File2Function()'])
696 call RunDbgCmd(buf, 'step', ['line 9: call File2Function()'])
697 call RunDbgCmd(buf, 'backtrace', [
698 \ '>backtrace',
699 \ ' 4 User Autocommands for "TestGlobalFunction"',
700 \ ' 3 function GlobalFunction[1]',
701 \ ' 2 CallAFunction[1]',
702 \ ' 1 SourceAnotherFile[1]',
703 \ '->0 script ' .. getcwd() .. '/Xtest2.vim',
704 \ 'line 9: call File2Function()'])
705
706 call RunDbgCmd(buf, 'step', ['line 1: call DoAThing()'])
707 call RunDbgCmd(buf, 'step', ['line 1: echo "DoAThing"'])
708 call RunDbgCmd(buf, 'backtrace', [
709 \ '>backtrace',
710 \ ' 6 User Autocommands for "TestGlobalFunction"',
711 \ ' 5 function GlobalFunction[1]',
712 \ ' 4 CallAFunction[1]',
713 \ ' 3 SourceAnotherFile[1]',
714 \ ' 2 script ' .. getcwd() .. '/Xtest2.vim[9]',
715 \ ' 1 function File2Function[1]',
716 \ '->0 DoAThing',
717 \ 'line 1: echo "DoAThing"'])
718
719 " Now, step (back to Xfile1.vim), and call the function _in_ Xfile2.vim
720 call RunDbgCmd(buf, 'step', ['line 1: End of function'])
721 call RunDbgCmd(buf, 'step', ['line 1: End of function'])
722 call RunDbgCmd(buf, 'step', ['line 10: End of sourced file'])
723 call RunDbgCmd(buf, 'step', ['line 1: End of function'])
724 call RunDbgCmd(buf, 'step', ['line 2: call File2Function()'])
725 call RunDbgCmd(buf, 'backtrace', [
726 \ '>backtrace',
727 \ ' 2 User Autocommands for "TestGlobalFunction"',
728 \ ' 1 function GlobalFunction[1]',
729 \ '->0 CallAFunction',
730 \ 'line 2: call File2Function()'])
731
732 call RunDbgCmd(buf, 'step', ['line 1: call DoAThing()'])
733 call RunDbgCmd(buf, 'backtrace', [
734 \ '>backtrace',
735 \ ' 3 User Autocommands for "TestGlobalFunction"',
736 \ ' 2 function GlobalFunction[1]',
737 \ ' 1 CallAFunction[2]',
738 \ '->0 File2Function',
739 \ 'line 1: call DoAThing()'])
740
741
742 " Now unwind so that we get back to the original autocommand (and the second
743 " cmd echo "Done")
744 call RunDbgCmd(buf, 'finish', ['line 1: End of function'])
745 call RunDbgCmd(buf, 'backtrace', [
746 \ '>backtrace',
747 \ ' 3 User Autocommands for "TestGlobalFunction"',
748 \ ' 2 function GlobalFunction[1]',
749 \ ' 1 CallAFunction[2]',
750 \ '->0 File2Function',
751 \ 'line 1: End of function'])
752
753 call RunDbgCmd(buf, 'finish', ['line 2: End of function'])
754 call RunDbgCmd(buf, 'backtrace', [
755 \ '>backtrace',
756 \ ' 2 User Autocommands for "TestGlobalFunction"',
757 \ ' 1 function GlobalFunction[1]',
758 \ '->0 CallAFunction',
759 \ 'line 2: End of function'])
760
761 call RunDbgCmd(buf, 'finish', ['line 1: End of function'])
762 call RunDbgCmd(buf, 'backtrace', [
763 \ '>backtrace',
764 \ ' 1 User Autocommands for "TestGlobalFunction"',
765 \ '->0 function GlobalFunction',
766 \ 'line 1: End of function'])
767
768 call RunDbgCmd(buf, 'step', ['cmd: echo "Done"'])
769 call RunDbgCmd(buf, 'backtrace', [
770 \ '>backtrace',
771 \ '->0 User Autocommands for "TestGlobalFunction"',
772 \ 'cmd: echo "Done"'])
773
774 call StopVimInTerminal(buf)
775 call delete('Xtest1.vim')
776 call delete('Xtest2.vim')
777endfunc
778
779func Test_Backtrace_CmdLine()
Bram Moolenaarb7f4fa52020-08-08 14:41:52 +0200780 CheckCWD
Bram Moolenaar6ca6ca42020-07-27 19:47:07 +0200781 let file1 =<< trim END
782 func SourceAnotherFile()
783 source Xtest2.vim
784 endfunc
785
786 func CallAFunction()
787 call SourceAnotherFile()
788 call File2Function()
789 endfunc
790
791 func GlobalFunction()
792 call CallAFunction()
793 endfunc
794
795 au User TestGlobalFunction :call GlobalFunction() | echo "Done"
796 END
797 call writefile(file1, 'Xtest1.vim')
798
799 let file2 =<< trim END
800 func DoAThing()
801 echo "DoAThing"
802 endfunc
803
804 func File2Function()
805 call DoAThing()
806 endfunc
807
808 call File2Function()
809 END
810 call writefile(file2, 'Xtest2.vim')
811
812 let buf = RunVimInTerminal(
813 \ '-S Xtest1.vim -c "debug call GlobalFunction()"',
814 \ {'wait_for_ruler': 0})
815
Bram Moolenaar18dc3552020-11-22 14:24:00 +0100816 " Need to wait for the vim-in-terminal to be ready.
817 " With valgrind this can take quite long.
Bram Moolenaar6ca6ca42020-07-27 19:47:07 +0200818 call CheckDbgOutput(buf, ['command line',
Bram Moolenaar18dc3552020-11-22 14:24:00 +0100819 \ 'cmd: call GlobalFunction()'], #{msec: 5000})
Bram Moolenaar6ca6ca42020-07-27 19:47:07 +0200820
821 " At this point the ontly thing in the stack is the cmdline
822 call RunDbgCmd(buf, 'backtrace', [
823 \ '>backtrace',
824 \ '->0 command line',
825 \ 'cmd: call GlobalFunction()'])
826
827 " And now we're back into the call stack
828 call RunDbgCmd(buf, 'step', ['line 1: call CallAFunction()'])
829 call RunDbgCmd(buf, 'backtrace', [
830 \ '>backtrace',
831 \ ' 1 command line',
832 \ '->0 function GlobalFunction',
833 \ 'line 1: call CallAFunction()'])
834
835 call StopVimInTerminal(buf)
836 call delete('Xtest1.vim')
837 call delete('Xtest2.vim')
838endfunc
839
840func Test_Backtrace_DefFunction()
Bram Moolenaarb7f4fa52020-08-08 14:41:52 +0200841 CheckCWD
Bram Moolenaar6ca6ca42020-07-27 19:47:07 +0200842 let file1 =<< trim END
843 vim9script
844 import File2Function from './Xtest2.vim'
845
846 def SourceAnotherFile()
847 source Xtest2.vim
848 enddef
849
850 def CallAFunction()
851 SourceAnotherFile()
852 File2Function()
853 enddef
854
855 def g:GlobalFunction()
Bram Moolenaarb69c6fb2021-06-14 20:40:37 +0200856 var some = "some var"
Bram Moolenaar6ca6ca42020-07-27 19:47:07 +0200857 CallAFunction()
858 enddef
859
860 defcompile
861 END
862 call writefile(file1, 'Xtest1.vim')
863
864 let file2 =<< trim END
865 vim9script
866
867 def DoAThing(): number
Bram Moolenaar1bdae402020-10-03 14:14:56 +0200868 var a = 100 * 2
Bram Moolenaar6ca6ca42020-07-27 19:47:07 +0200869 a += 3
870 return a
871 enddef
872
873 export def File2Function()
874 DoAThing()
875 enddef
876
877 defcompile
878 File2Function()
879 END
880 call writefile(file2, 'Xtest2.vim')
881
882 let buf = RunVimInTerminal('-S Xtest1.vim', {})
883
884 call RunDbgCmd(buf,
885 \ ':debug call GlobalFunction()',
886 \ ['cmd: call GlobalFunction()'])
887
Bram Moolenaarb69c6fb2021-06-14 20:40:37 +0200888 call RunDbgCmd(buf, 'step', ['line 1: var some = "some var"'])
889 call RunDbgCmd(buf, 'step', ['line 2: CallAFunction()'])
890 call RunDbgCmd(buf, 'echo some', ['some var'])
Bram Moolenaar6ca6ca42020-07-27 19:47:07 +0200891
Bram Moolenaar6ca6ca42020-07-27 19:47:07 +0200892 call RunDbgCmd(buf, 'backtrace', [
893 \ '\V>backtrace',
Bram Moolenaare99d4222021-06-13 14:01:26 +0200894 \ '\V->0 function GlobalFunction',
Bram Moolenaarb69c6fb2021-06-14 20:40:37 +0200895 \ '\Vline 2: CallAFunction()',
Bram Moolenaare99d4222021-06-13 14:01:26 +0200896 \ ],
Bram Moolenaar6ca6ca42020-07-27 19:47:07 +0200897 \ #{match: 'pattern'})
898
Bram Moolenaare99d4222021-06-13 14:01:26 +0200899 call RunDbgCmd(buf, 'step', ['line 1: SourceAnotherFile()'])
900 call RunDbgCmd(buf, 'step', ['line 1: source Xtest2.vim'])
Bram Moolenaarb69c6fb2021-06-14 20:40:37 +0200901 " Repeated line, because we fist are in the compiled function before the
902 " EXEC and then in do_cmdline() before the :source command.
Bram Moolenaare99d4222021-06-13 14:01:26 +0200903 call RunDbgCmd(buf, 'step', ['line 1: source Xtest2.vim'])
Bram Moolenaar6ca6ca42020-07-27 19:47:07 +0200904 call RunDbgCmd(buf, 'step', ['line 1: vim9script'])
905 call RunDbgCmd(buf, 'step', ['line 3: def DoAThing(): number'])
906 call RunDbgCmd(buf, 'step', ['line 9: export def File2Function()'])
907 call RunDbgCmd(buf, 'step', ['line 9: def File2Function()'])
908 call RunDbgCmd(buf, 'step', ['line 13: defcompile'])
909 call RunDbgCmd(buf, 'step', ['line 14: File2Function()'])
910 call RunDbgCmd(buf, 'backtrace', [
911 \ '\V>backtrace',
Bram Moolenaarb69c6fb2021-06-14 20:40:37 +0200912 \ '\V 3 function GlobalFunction[2]',
Bram Moolenaar6ca6ca42020-07-27 19:47:07 +0200913 \ '\V 2 <SNR>\.\*_CallAFunction[1]',
914 \ '\V 1 <SNR>\.\*_SourceAnotherFile[1]',
915 \ '\V->0 script ' .. getcwd() .. '/Xtest2.vim',
916 \ '\Vline 14: File2Function()'],
917 \ #{match: 'pattern'})
918
919 " Don't step into compiled functions...
Bram Moolenaare99d4222021-06-13 14:01:26 +0200920 call RunDbgCmd(buf, 'next', ['line 15: End of sourced file'])
Bram Moolenaar6ca6ca42020-07-27 19:47:07 +0200921 call RunDbgCmd(buf, 'backtrace', [
922 \ '\V>backtrace',
Bram Moolenaarb69c6fb2021-06-14 20:40:37 +0200923 \ '\V 3 function GlobalFunction[2]',
Bram Moolenaar6ca6ca42020-07-27 19:47:07 +0200924 \ '\V 2 <SNR>\.\*_CallAFunction[1]',
925 \ '\V 1 <SNR>\.\*_SourceAnotherFile[1]',
926 \ '\V->0 script ' .. getcwd() .. '/Xtest2.vim',
927 \ '\Vline 15: End of sourced file'],
928 \ #{match: 'pattern'})
929
Bram Moolenaar6ca6ca42020-07-27 19:47:07 +0200930 call StopVimInTerminal(buf)
931 call delete('Xtest1.vim')
932 call delete('Xtest2.vim')
933endfunc
Bram Moolenaarb7f4fa52020-08-08 14:41:52 +0200934
Bram Moolenaar968a5b62021-06-15 19:32:40 +0200935func Test_debug_def_function()
936 CheckCWD
937 let file =<< trim END
938 vim9script
939 def g:Func()
Bram Moolenaar6bc30b02021-06-16 19:19:55 +0200940 var n: number
941 def Closure(): number
942 return n + 3
943 enddef
944 n += Closure()
945 echo 'result: ' .. n
946 enddef
947
948 def g:FuncWithArgs(text: string, nr: number, ...items: list<number>)
949 echo text .. nr
950 for it in items
951 echo it
952 endfor
953 echo "done"
Bram Moolenaar968a5b62021-06-15 19:32:40 +0200954 enddef
955 END
956 call writefile(file, 'Xtest.vim')
957
958 let buf = RunVimInTerminal('-S Xtest.vim', {})
959
960 call RunDbgCmd(buf,
961 \ ':debug call Func()',
962 \ ['cmd: call Func()'])
963 call RunDbgCmd(buf, 'next', ['result: 3'])
964 call term_sendkeys(buf, "\r")
Bram Moolenaar6bc30b02021-06-16 19:19:55 +0200965 call RunDbgCmd(buf, 'cont')
Bram Moolenaar968a5b62021-06-15 19:32:40 +0200966
Bram Moolenaar6bc30b02021-06-16 19:19:55 +0200967 call RunDbgCmd(buf,
968 \ ':debug call FuncWithArgs("asdf", 42, 1, 2, 3)',
969 \ ['cmd: call FuncWithArgs("asdf", 42, 1, 2, 3)'])
970 call RunDbgCmd(buf, 'step', ['line 1: echo text .. nr'])
971 call RunDbgCmd(buf, 'echo text', ['asdf'])
972 call RunDbgCmd(buf, 'echo nr', ['42'])
973 call RunDbgCmd(buf, 'echo items', ['[1, 2, 3]'])
974 call RunDbgCmd(buf, 'step', ['asdf42', 'function FuncWithArgs', 'line 2: for it in items'])
975 call RunDbgCmd(buf, 'echo it', ['1'])
976 call RunDbgCmd(buf, 'step', ['line 3: echo it'])
977 call RunDbgCmd(buf, 'step', ['1', 'function FuncWithArgs', 'line 4: endfor'])
978 call RunDbgCmd(buf, 'step', ['line 2: for it in items'])
979 call RunDbgCmd(buf, 'echo it', ['2'])
980 call RunDbgCmd(buf, 'step', ['line 3: echo it'])
981 call RunDbgCmd(buf, 'step', ['2', 'function FuncWithArgs', 'line 4: endfor'])
982 call RunDbgCmd(buf, 'step', ['line 2: for it in items'])
983 call RunDbgCmd(buf, 'echo it', ['3'])
984 call RunDbgCmd(buf, 'step', ['line 3: echo it'])
985 call RunDbgCmd(buf, 'step', ['3', 'function FuncWithArgs', 'line 4: endfor'])
986 call RunDbgCmd(buf, 'step', ['line 5: echo "done"'])
987
988 call RunDbgCmd(buf, 'cont')
Bram Moolenaar968a5b62021-06-15 19:32:40 +0200989 call StopVimInTerminal(buf)
990 call delete('Xtest.vim')
991endfunc
992
Bram Moolenaarb7f4fa52020-08-08 14:41:52 +0200993func Test_debug_backtrace_level()
994 CheckCWD
995 let lines =<< trim END
996 let s:file1_var = 'file1'
997 let g:global_var = 'global'
998
999 func s:File1Func( arg )
1000 let s:file1_var .= a:arg
1001 let local_var = s:file1_var .. ' test1'
1002 let g:global_var .= local_var
1003 source Xtest2.vim
1004 endfunc
1005
1006 call s:File1Func( 'arg1' )
1007 END
1008 call writefile(lines, 'Xtest1.vim')
1009
1010 let lines =<< trim END
1011 let s:file2_var = 'file2'
1012
1013 func s:File2Func( arg )
1014 let s:file2_var .= a:arg
1015 let local_var = s:file2_var .. ' test2'
1016 let g:global_var .= local_var
1017 endfunc
1018
1019 call s:File2Func( 'arg2' )
1020 END
1021 call writefile(lines, 'Xtest2.vim')
1022
1023 let file1 = getcwd() .. '/Xtest1.vim'
1024 let file2 = getcwd() .. '/Xtest2.vim'
1025
1026 " set a breakpoint and source file1.vim
1027 let buf = RunVimInTerminal(
1028 \ '-c "breakadd file 1 Xtest1.vim" -S Xtest1.vim',
Bram Moolenaar18dc3552020-11-22 14:24:00 +01001029 \ #{wait_for_ruler: 0})
Bram Moolenaarb7f4fa52020-08-08 14:41:52 +02001030
1031 call CheckDbgOutput(buf, [
1032 \ 'Breakpoint in "' .. file1 .. '" line 1',
1033 \ 'Entering Debug mode. Type "cont" to continue.',
1034 \ 'command line..script ' .. file1,
1035 \ 'line 1: let s:file1_var = ''file1'''
Bram Moolenaar18dc3552020-11-22 14:24:00 +01001036 \ ], #{msec: 5000})
Bram Moolenaarb7f4fa52020-08-08 14:41:52 +02001037
Bram Moolenaar8e7d6222020-12-18 19:49:56 +01001038 " step through the initial declarations
Bram Moolenaarb7f4fa52020-08-08 14:41:52 +02001039 call RunDbgCmd(buf, 'step', [ 'line 2: let g:global_var = ''global''' ] )
1040 call RunDbgCmd(buf, 'step', [ 'line 4: func s:File1Func( arg )' ] )
1041 call RunDbgCmd(buf, 'echo s:file1_var', [ 'file1' ] )
1042 call RunDbgCmd(buf, 'echo g:global_var', [ 'global' ] )
1043 call RunDbgCmd(buf, 'echo global_var', [ 'global' ] )
1044
1045 " step in to the first function
1046 call RunDbgCmd(buf, 'step', [ 'line 11: call s:File1Func( ''arg1'' )' ] )
1047 call RunDbgCmd(buf, 'step', [ 'line 1: let s:file1_var .= a:arg' ] )
1048 call RunDbgCmd(buf, 'echo a:arg', [ 'arg1' ] )
1049 call RunDbgCmd(buf, 'echo s:file1_var', [ 'file1' ] )
1050 call RunDbgCmd(buf, 'echo g:global_var', [ 'global' ] )
1051 call RunDbgCmd(buf,
1052 \'echo global_var',
1053 \[ 'E121: Undefined variable: global_var' ] )
1054 call RunDbgCmd(buf,
1055 \'echo local_var',
1056 \[ 'E121: Undefined variable: local_var' ] )
1057 call RunDbgCmd(buf,
1058 \'echo l:local_var',
1059 \[ 'E121: Undefined variable: l:local_var' ] )
1060
1061 " backtrace up
1062 call RunDbgCmd(buf, 'backtrace', [
1063 \ '\V>backtrace',
1064 \ '\V 2 command line',
1065 \ '\V 1 script ' .. file1 .. '[11]',
1066 \ '\V->0 function <SNR>\.\*_File1Func',
1067 \ '\Vline 1: let s:file1_var .= a:arg',
1068 \ ],
1069 \ #{ match: 'pattern' } )
1070 call RunDbgCmd(buf, 'up', [ '>up' ] )
1071
1072 call RunDbgCmd(buf, 'backtrace', [
1073 \ '\V>backtrace',
1074 \ '\V 2 command line',
1075 \ '\V->1 script ' .. file1 .. '[11]',
1076 \ '\V 0 function <SNR>\.\*_File1Func',
1077 \ '\Vline 1: let s:file1_var .= a:arg',
1078 \ ],
1079 \ #{ match: 'pattern' } )
1080
1081 " Expression evaluation in the script frame (not the function frame)
1082 " FIXME: Unexpected in this scope (a: should not be visibnle)
1083 call RunDbgCmd(buf, 'echo a:arg', [ 'arg1' ] )
1084 call RunDbgCmd(buf, 'echo s:file1_var', [ 'file1' ] )
1085 call RunDbgCmd(buf, 'echo g:global_var', [ 'global' ] )
1086 " FIXME: Unexpected in this scope (global should be found)
1087 call RunDbgCmd(buf,
1088 \'echo global_var',
1089 \[ 'E121: Undefined variable: global_var' ] )
1090 call RunDbgCmd(buf,
1091 \'echo local_var',
1092 \[ 'E121: Undefined variable: local_var' ] )
1093 call RunDbgCmd(buf,
1094 \'echo l:local_var',
1095 \[ 'E121: Undefined variable: l:local_var' ] )
1096
1097
1098 " step while backtraced jumps to the latest frame
1099 call RunDbgCmd(buf, 'step', [
1100 \ 'line 2: let local_var = s:file1_var .. '' test1''' ] )
1101 call RunDbgCmd(buf, 'backtrace', [
1102 \ '\V>backtrace',
1103 \ '\V 2 command line',
1104 \ '\V 1 script ' .. file1 .. '[11]',
1105 \ '\V->0 function <SNR>\.\*_File1Func',
1106 \ '\Vline 2: let local_var = s:file1_var .. '' test1''',
1107 \ ],
1108 \ #{ match: 'pattern' } )
1109
1110 call RunDbgCmd(buf, 'step', [ 'line 3: let g:global_var .= local_var' ] )
1111 call RunDbgCmd(buf, 'echo local_var', [ 'file1arg1 test1' ] )
1112 call RunDbgCmd(buf, 'echo l:local_var', [ 'file1arg1 test1' ] )
1113
1114 call RunDbgCmd(buf, 'step', [ 'line 4: source Xtest2.vim' ] )
1115 call RunDbgCmd(buf, 'step', [ 'line 1: let s:file2_var = ''file2''' ] )
1116 call RunDbgCmd(buf, 'backtrace', [
1117 \ '\V>backtrace',
1118 \ '\V 3 command line',
1119 \ '\V 2 script ' .. file1 .. '[11]',
1120 \ '\V 1 function <SNR>\.\*_File1Func[4]',
1121 \ '\V->0 script ' .. file2,
1122 \ '\Vline 1: let s:file2_var = ''file2''',
1123 \ ],
1124 \ #{ match: 'pattern' } )
1125
1126 " Expression evaluation in the script frame file2 (not the function frame)
1127 call RunDbgCmd(buf, 'echo a:arg', [ 'E121: Undefined variable: a:arg' ] )
1128 call RunDbgCmd(buf,
1129 \ 'echo s:file1_var',
1130 \ [ 'E121: Undefined variable: s:file1_var' ] )
1131 call RunDbgCmd(buf, 'echo g:global_var', [ 'globalfile1arg1 test1' ] )
1132 call RunDbgCmd(buf, 'echo global_var', [ 'globalfile1arg1 test1' ] )
1133 call RunDbgCmd(buf,
1134 \'echo local_var',
1135 \[ 'E121: Undefined variable: local_var' ] )
1136 call RunDbgCmd(buf,
1137 \'echo l:local_var',
1138 \[ 'E121: Undefined variable: l:local_var' ] )
1139 call RunDbgCmd(buf,
1140 \ 'echo s:file2_var',
1141 \ [ 'E121: Undefined variable: s:file2_var' ] )
1142
1143 call RunDbgCmd(buf, 'step', [ 'line 3: func s:File2Func( arg )' ] )
1144 call RunDbgCmd(buf, 'echo s:file2_var', [ 'file2' ] )
1145
1146 " Up the stack to the other script context
1147 call RunDbgCmd(buf, 'up')
1148 call RunDbgCmd(buf, 'backtrace', [
1149 \ '\V>backtrace',
1150 \ '\V 3 command line',
1151 \ '\V 2 script ' .. file1 .. '[11]',
1152 \ '\V->1 function <SNR>\.\*_File1Func[4]',
1153 \ '\V 0 script ' .. file2,
1154 \ '\Vline 3: func s:File2Func( arg )',
1155 \ ],
1156 \ #{ match: 'pattern' } )
1157 " FIXME: Unexpected. Should see the a: and l: dicts from File1Func
1158 call RunDbgCmd(buf, 'echo a:arg', [ 'E121: Undefined variable: a:arg' ] )
1159 call RunDbgCmd(buf,
1160 \ 'echo l:local_var',
1161 \ [ 'E121: Undefined variable: l:local_var' ] )
1162
1163 call RunDbgCmd(buf, 'up')
1164 call RunDbgCmd(buf, 'backtrace', [
1165 \ '\V>backtrace',
1166 \ '\V 3 command line',
1167 \ '\V->2 script ' .. file1 .. '[11]',
1168 \ '\V 1 function <SNR>\.\*_File1Func[4]',
1169 \ '\V 0 script ' .. file2,
1170 \ '\Vline 3: func s:File2Func( arg )',
1171 \ ],
1172 \ #{ match: 'pattern' } )
1173
1174 " FIXME: Unexpected (wrong script vars are used)
1175 call RunDbgCmd(buf,
1176 \ 'echo s:file1_var',
1177 \ [ 'E121: Undefined variable: s:file1_var' ] )
1178 call RunDbgCmd(buf, 'echo s:file2_var', [ 'file2' ] )
1179
Bram Moolenaare99d4222021-06-13 14:01:26 +02001180 call RunDbgCmd(buf, 'cont')
Bram Moolenaarb7f4fa52020-08-08 14:41:52 +02001181 call StopVimInTerminal(buf)
1182 call delete('Xtest1.vim')
1183 call delete('Xtest2.vim')
1184endfunc
Bram Moolenaar6d91bcb2020-08-12 18:50:36 +02001185
Bram Moolenaar7ac616c2020-08-12 22:22:09 +02001186" Test for setting a breakpoint on a :endif where the :if condition is false
1187" and then quit the script. This should generate an interrupt.
1188func Test_breakpt_endif_intr()
1189 func F()
1190 let g:Xpath ..= 'a'
1191 if v:false
1192 let g:Xpath ..= 'b'
1193 endif
1194 invalid_command
1195 endfunc
1196
1197 let g:Xpath = ''
1198 breakadd func 4 F
1199 try
1200 let caught_intr = 0
1201 debuggreedy
1202 call feedkeys(":call F()\<CR>quit\<CR>", "xt")
Bram Moolenaar7ac616c2020-08-12 22:22:09 +02001203 catch /^Vim:Interrupt$/
1204 call assert_match('\.F, line 4', v:throwpoint)
1205 let caught_intr = 1
1206 endtry
1207 0debuggreedy
1208 call assert_equal(1, caught_intr)
1209 call assert_equal('a', g:Xpath)
1210 breakdel *
1211 delfunc F
1212endfunc
1213
1214" Test for setting a breakpoint on a :else where the :if condition is false
1215" and then quit the script. This should generate an interrupt.
1216func Test_breakpt_else_intr()
1217 func F()
1218 let g:Xpath ..= 'a'
1219 if v:false
1220 let g:Xpath ..= 'b'
1221 else
1222 invalid_command
1223 endif
1224 invalid_command
1225 endfunc
1226
1227 let g:Xpath = ''
1228 breakadd func 4 F
1229 try
1230 let caught_intr = 0
1231 debuggreedy
1232 call feedkeys(":call F()\<CR>quit\<CR>", "xt")
Bram Moolenaar7ac616c2020-08-12 22:22:09 +02001233 catch /^Vim:Interrupt$/
1234 call assert_match('\.F, line 4', v:throwpoint)
1235 let caught_intr = 1
1236 endtry
1237 0debuggreedy
1238 call assert_equal(1, caught_intr)
1239 call assert_equal('a', g:Xpath)
1240 breakdel *
1241 delfunc F
1242endfunc
1243
1244" Test for setting a breakpoint on a :endwhile where the :while condition is
1245" false and then quit the script. This should generate an interrupt.
1246func Test_breakpt_endwhile_intr()
1247 func F()
1248 let g:Xpath ..= 'a'
1249 while v:false
1250 let g:Xpath ..= 'b'
1251 endwhile
1252 invalid_command
1253 endfunc
1254
1255 let g:Xpath = ''
1256 breakadd func 4 F
1257 try
1258 let caught_intr = 0
1259 debuggreedy
1260 call feedkeys(":call F()\<CR>quit\<CR>", "xt")
Bram Moolenaar7ac616c2020-08-12 22:22:09 +02001261 catch /^Vim:Interrupt$/
1262 call assert_match('\.F, line 4', v:throwpoint)
1263 let caught_intr = 1
1264 endtry
1265 0debuggreedy
1266 call assert_equal(1, caught_intr)
1267 call assert_equal('a', g:Xpath)
1268 breakdel *
1269 delfunc F
1270endfunc
1271
Bram Moolenaar16c62322020-08-13 19:20:04 +02001272" Test for setting a breakpoint on a script local function
1273func Test_breakpt_scriptlocal_func()
1274 let g:Xpath = ''
1275 func s:G()
1276 let g:Xpath ..= 'a'
Bram Moolenaar7ac616c2020-08-12 22:22:09 +02001277 endfunc
1278
Bram Moolenaar16c62322020-08-13 19:20:04 +02001279 let funcname = expand("<SID>") .. "G"
1280 exe "breakadd func 1 " .. funcname
1281 debuggreedy
1282 redir => output
1283 call feedkeys(":call " .. funcname .. "()\<CR>c\<CR>", "xt")
1284 redir END
Bram Moolenaar7ac616c2020-08-12 22:22:09 +02001285 0debuggreedy
Bram Moolenaar16c62322020-08-13 19:20:04 +02001286 call assert_match('Breakpoint in "' .. funcname .. '" line 1', output)
Bram Moolenaar7ac616c2020-08-12 22:22:09 +02001287 call assert_equal('a', g:Xpath)
1288 breakdel *
Bram Moolenaar16c62322020-08-13 19:20:04 +02001289 exe "delfunc " .. funcname
Bram Moolenaar7ac616c2020-08-12 22:22:09 +02001290endfunc
1291
Bram Moolenaar6d91bcb2020-08-12 18:50:36 +02001292" vim: shiftwidth=2 sts=2 expandtab