1" Tests for the Vim script debug commands
2
3source shared.vim
4source screendump.vim
5source check.vim
6
7func CheckDbgOutput(buf, lines, options = {})
8  " Verify the expected output
9  let lnum = 20 - len(a:lines)
10  for l in a:lines
11    if get(a:options, 'match', 'equal') ==# 'pattern'
12      call WaitForAssert({-> assert_match(l, term_getline(a:buf, lnum))}, 200)
13    else
14      call WaitForAssert({-> assert_equal(l, term_getline(a:buf, lnum))}, 200)
15    endif
16    let lnum += 1
17  endfor
18endfunc
19
20" Run a Vim debugger command
21" If the expected output argument is supplied, then check for it.
22func RunDbgCmd(buf, cmd, ...)
23  call term_sendkeys(a:buf, a:cmd . "\r")
24  call TermWait(a:buf)
25
26  if a:0 != 0
27    let options = #{match: 'equal'}
28    if a:0 > 1
29      call extend(options, a:2)
30    endif
31    call CheckDbgOutput(a:buf, a:1, options)
32  endif
33endfunc
34
35" Debugger tests
36func Test_Debugger()
37  CheckRunVimInTerminal
38
39  " Create a Vim script with some functions
40  let lines =<< trim END
41	func Foo()
42	  let var1 = 1
43	  let var2 = Bar(var1) + 9
44	  return var2
45	endfunc
46	func Bar(var)
47	  let var1 = 2 + a:var
48	  let var2 = Bazz(var1) + 4
49	  return var2
50	endfunc
51	func Bazz(var)
52	  try
53	    let var1 = 3 + a:var
54	    let var3 = "another var"
55	    let var3 = "value2"
56	  catch
57	    let var4 = "exception"
58	  endtry
59	  return var1
60	endfunc
61  END
62  call writefile(lines, 'Xtest.vim')
63
64  " Start Vim in a terminal
65  let buf = RunVimInTerminal('-S Xtest.vim', {})
66
67  " Start the Vim debugger
68  call RunDbgCmd(buf, ':debug echo Foo()', ['cmd: echo Foo()'])
69
70  " Create a few stack frames by stepping through functions
71  call RunDbgCmd(buf, 'step', ['line 1: let var1 = 1'])
72  call RunDbgCmd(buf, 'step', ['line 2: let var2 = Bar(var1) + 9'])
73  call RunDbgCmd(buf, 'step', ['line 1: let var1 = 2 + a:var'])
74  call RunDbgCmd(buf, 'step', ['line 2: let var2 = Bazz(var1) + 4'])
75  call RunDbgCmd(buf, 'step', ['line 1: try'])
76  call RunDbgCmd(buf, 'step', ['line 2: let var1 = 3 + a:var'])
77  call RunDbgCmd(buf, 'step', ['line 3: let var3 = "another var"'])
78
79  " check backtrace
80  call RunDbgCmd(buf, 'backtrace', [
81	      \ '  2 function Foo[2]',
82	      \ '  1 Bar[2]',
83	      \ '->0 Bazz',
84	      \ 'line 3: let var3 = "another var"'])
85
86  " Check variables in different stack frames
87  call RunDbgCmd(buf, 'echo var1', ['6'])
88
89  call RunDbgCmd(buf, 'up')
90  call RunDbgCmd(buf, 'back', [
91	      \ '  2 function Foo[2]',
92	      \ '->1 Bar[2]',
93	      \ '  0 Bazz',
94	      \ 'line 3: let var3 = "another var"'])
95  call RunDbgCmd(buf, 'echo var1', ['3'])
96
97  call RunDbgCmd(buf, 'u')
98  call RunDbgCmd(buf, 'bt', [
99	      \ '->2 function Foo[2]',
100	      \ '  1 Bar[2]',
101	      \ '  0 Bazz',
102	      \ 'line 3: let var3 = "another var"'])
103  call RunDbgCmd(buf, 'echo var1', ['1'])
104
105  " Undefined variables
106  call RunDbgCmd(buf, 'step')
107  call RunDbgCmd(buf, 'frame 2')
108  call RunDbgCmd(buf, 'echo var3', [
109	\ 'Error detected while processing function Foo[2]..Bar[2]..Bazz:',
110	\ 'line    4:',
111	\ 'E121: Undefined variable: var3'])
112
113  " var3 is defined in this level with some other value
114  call RunDbgCmd(buf, 'fr 0')
115  call RunDbgCmd(buf, 'echo var3', ['another var'])
116
117  call RunDbgCmd(buf, 'step')
118  call RunDbgCmd(buf, '')
119  call RunDbgCmd(buf, '')
120  call RunDbgCmd(buf, '')
121  call RunDbgCmd(buf, '')
122  call RunDbgCmd(buf, 'step', [
123	      \ 'function Foo[2]..Bar',
124	      \ 'line 3: End of function'])
125  call RunDbgCmd(buf, 'up')
126
127  " Undefined var2
128  call RunDbgCmd(buf, 'echo var2', [
129	      \ 'Error detected while processing function Foo[2]..Bar:',
130	      \ 'line    3:',
131	      \ 'E121: Undefined variable: var2'])
132
133  " Var2 is defined with 10
134  call RunDbgCmd(buf, 'down')
135  call RunDbgCmd(buf, 'echo var2', ['10'])
136
137  " Backtrace movements
138  call RunDbgCmd(buf, 'b', [
139	      \ '  1 function Foo[2]',
140	      \ '->0 Bar',
141	      \ 'line 3: End of function'])
142
143  " next command cannot go down, we are on bottom
144  call RunDbgCmd(buf, 'down', ['frame is zero'])
145  call RunDbgCmd(buf, 'up')
146
147  " next command cannot go up, we are on top
148  call RunDbgCmd(buf, 'up', ['frame at highest level: 1'])
149  call RunDbgCmd(buf, 'where', [
150	      \ '->1 function Foo[2]',
151	      \ '  0 Bar',
152	      \ 'line 3: End of function'])
153
154  " fil is not frame or finish, it is file
155  call RunDbgCmd(buf, 'fil', ['"[No Name]" --No lines in buffer--'])
156
157  " relative backtrace movement
158  call RunDbgCmd(buf, 'fr -1')
159  call RunDbgCmd(buf, 'frame', [
160	      \ '  1 function Foo[2]',
161	      \ '->0 Bar',
162	      \ 'line 3: End of function'])
163
164  call RunDbgCmd(buf, 'fr +1')
165  call RunDbgCmd(buf, 'fram', [
166	      \ '->1 function Foo[2]',
167	      \ '  0 Bar',
168	      \ 'line 3: End of function'])
169
170  " go beyond limits does not crash
171  call RunDbgCmd(buf, 'fr 100', ['frame at highest level: 1'])
172  call RunDbgCmd(buf, 'fra', [
173	      \ '->1 function Foo[2]',
174	      \ '  0 Bar',
175	      \ 'line 3: End of function'])
176
177  call RunDbgCmd(buf, 'frame -40', ['frame is zero'])
178  call RunDbgCmd(buf, 'fram', [
179	      \ '  1 function Foo[2]',
180	      \ '->0 Bar',
181	      \ 'line 3: End of function'])
182
183  " final result 19
184  call RunDbgCmd(buf, 'cont', ['19'])
185
186  " breakpoints tests
187
188  " Start a debug session, so that reading the last line from the terminal
189  " works properly.
190  call RunDbgCmd(buf, ':debug echo Foo()')
191
192  " No breakpoints
193  call RunDbgCmd(buf, 'breakl', ['No breakpoints defined'])
194
195  " Place some breakpoints
196  call RunDbgCmd(buf, 'breaka func Bar')
197  call RunDbgCmd(buf, 'breaklis', ['  1  func Bar  line 1'])
198  call RunDbgCmd(buf, 'breakadd func 3 Bazz')
199  call RunDbgCmd(buf, 'breaklist', ['  1  func Bar  line 1',
200	      \ '  2  func Bazz  line 3'])
201
202  " Check whether the breakpoints are hit
203  call RunDbgCmd(buf, 'cont', [
204	      \ 'Breakpoint in "Bar" line 1',
205	      \ 'function Foo[2]..Bar',
206	      \ 'line 1: let var1 = 2 + a:var'])
207  call RunDbgCmd(buf, 'cont', [
208	      \ 'Breakpoint in "Bazz" line 3',
209	      \ 'function Foo[2]..Bar[2]..Bazz',
210	      \ 'line 3: let var3 = "another var"'])
211
212  " Delete the breakpoints
213  call RunDbgCmd(buf, 'breakd 1')
214  call RunDbgCmd(buf, 'breakli', ['  2  func Bazz  line 3'])
215  call RunDbgCmd(buf, 'breakdel func 3 Bazz')
216  call RunDbgCmd(buf, 'breakl', ['No breakpoints defined'])
217
218  call RunDbgCmd(buf, 'cont')
219
220  " Make sure the breakpoints are removed
221  call RunDbgCmd(buf, ':echo Foo()', ['19'])
222
223  " Delete a non-existing breakpoint
224  call RunDbgCmd(buf, ':breakdel 2', ['E161: Breakpoint not found: 2'])
225
226  " Expression breakpoint
227  call RunDbgCmd(buf, ':breakadd func 2 Bazz')
228  call RunDbgCmd(buf, ':echo Bazz(1)', [
229	      \ 'Entering Debug mode.  Type "cont" to continue.',
230	      \ 'function Bazz',
231	      \ 'line 2: let var1 = 3 + a:var'])
232  call RunDbgCmd(buf, 'step')
233  call RunDbgCmd(buf, 'step')
234  call RunDbgCmd(buf, 'breaka expr var3')
235  call RunDbgCmd(buf, 'breakl', ['  3  func Bazz  line 2',
236	      \ '  4  expr var3'])
237  call RunDbgCmd(buf, 'cont', ['Breakpoint in "Bazz" line 5',
238	      \ 'Oldval = "''another var''"',
239	      \ 'Newval = "''value2''"',
240	      \ 'function Bazz',
241	      \ 'line 5: catch'])
242
243  call RunDbgCmd(buf, 'breakdel *')
244  call RunDbgCmd(buf, 'breakl', ['No breakpoints defined'])
245
246  " Check for error cases
247  call RunDbgCmd(buf, 'breakadd abcd', [
248	      \ 'Error detected while processing function Bazz:',
249	      \ 'line    5:',
250	      \ 'E475: Invalid argument: abcd'])
251  call RunDbgCmd(buf, 'breakadd func', ['E475: Invalid argument: func'])
252  call RunDbgCmd(buf, 'breakadd func 2', ['E475: Invalid argument: func 2'])
253  call RunDbgCmd(buf, 'breaka func a()', ['E475: Invalid argument: func a()'])
254  call RunDbgCmd(buf, 'breakd abcd', ['E475: Invalid argument: abcd'])
255  call RunDbgCmd(buf, 'breakd func', ['E475: Invalid argument: func'])
256  call RunDbgCmd(buf, 'breakd func a()', ['E475: Invalid argument: func a()'])
257  call RunDbgCmd(buf, 'breakd func a', ['E161: Breakpoint not found: func a'])
258  call RunDbgCmd(buf, 'breakd expr', ['E475: Invalid argument: expr'])
259  call RunDbgCmd(buf, 'breakd expr x', [
260	      \ 'E121: Undefined variable: x',
261	      \ 'E161: Breakpoint not found: expr x'])
262
263  " finish the current function
264  call RunDbgCmd(buf, 'finish', [
265	      \ 'function Bazz',
266	      \ 'line 8: End of function'])
267  call RunDbgCmd(buf, 'cont')
268
269  " Test for :next
270  call RunDbgCmd(buf, ':debug echo Bar(1)')
271  call RunDbgCmd(buf, 'step')
272  call RunDbgCmd(buf, 'next')
273  call RunDbgCmd(buf, '', [
274	      \ 'function Bar',
275	      \ 'line 3: return var2'])
276  call RunDbgCmd(buf, 'c')
277
278  " Test for :interrupt
279  call RunDbgCmd(buf, ':debug echo Bazz(1)')
280  call RunDbgCmd(buf, 'step')
281  call RunDbgCmd(buf, 'step')
282  call RunDbgCmd(buf, 'interrupt', [
283	      \ 'Exception thrown: Vim:Interrupt',
284	      \ 'function Bazz',
285	      \ 'line 5: catch'])
286  call RunDbgCmd(buf, 'c')
287
288  " Test for :quit
289  call RunDbgCmd(buf, ':debug echo Foo()')
290  call RunDbgCmd(buf, 'breakdel *')
291  call RunDbgCmd(buf, 'breakadd func 3 Foo')
292  call RunDbgCmd(buf, 'breakadd func 3 Bazz')
293  call RunDbgCmd(buf, 'cont', [
294	      \ 'Breakpoint in "Bazz" line 3',
295	      \ 'function Foo[2]..Bar[2]..Bazz',
296	      \ 'line 3: let var3 = "another var"'])
297  call RunDbgCmd(buf, 'quit', [
298	      \ 'Breakpoint in "Foo" line 3',
299	      \ 'function Foo',
300	      \ 'line 3: return var2'])
301  call RunDbgCmd(buf, 'breakdel *')
302  call RunDbgCmd(buf, 'quit')
303  call RunDbgCmd(buf, 'enew! | only!')
304
305  call StopVimInTerminal(buf)
306
307  " Tests for :breakadd file and :breakadd here
308  " Breakpoints should be set before sourcing the file
309
310  let lines =<< trim END
311	let var1 = 10
312	let var2 = 20
313	let var3 = 30
314	let var4 = 40
315  END
316  call writefile(lines, 'Xtest.vim')
317
318  " Start Vim in a terminal
319  let buf = RunVimInTerminal('Xtest.vim', {})
320  call RunDbgCmd(buf, ':breakadd file 2 Xtest.vim')
321  call RunDbgCmd(buf, ':4 | breakadd here')
322  call RunDbgCmd(buf, ':source Xtest.vim', ['line 2: let var2 = 20'])
323  call RunDbgCmd(buf, 'cont', ['line 4: let var4 = 40'])
324  call RunDbgCmd(buf, 'cont')
325
326  call StopVimInTerminal(buf)
327
328  call delete('Xtest.vim')
329endfunc
330
331func Test_Backtrace_Through_Source()
332  CheckRunVimInTerminal
333
334  let file1 =<< trim END
335    func SourceAnotherFile()
336      source Xtest2.vim
337    endfunc
338
339    func CallAFunction()
340      call SourceAnotherFile()
341      call File2Function()
342    endfunc
343
344    func GlobalFunction()
345      call CallAFunction()
346    endfunc
347  END
348  call writefile(file1, 'Xtest1.vim')
349
350  let file2 =<< trim END
351    func DoAThing()
352      echo "DoAThing"
353    endfunc
354
355    func File2Function()
356      call DoAThing()
357    endfunc
358
359    call File2Function()
360  END
361  call writefile(file2, 'Xtest2.vim')
362
363  let buf = RunVimInTerminal('-S Xtest1.vim', {})
364
365  call RunDbgCmd(buf,
366                \ ':debug call GlobalFunction()',
367                \ ['cmd: call GlobalFunction()'])
368  call RunDbgCmd(buf, 'step', ['line 1: call CallAFunction()'])
369
370  call RunDbgCmd(buf, 'backtrace', ['>backtrace',
371                                    \ '->0 function GlobalFunction',
372                                    \ 'line 1: call CallAFunction()'])
373
374  call RunDbgCmd(buf, 'step', ['line 1: call SourceAnotherFile()'])
375  call RunDbgCmd(buf, 'step', ['line 1: source Xtest2.vim'])
376
377  call RunDbgCmd(buf, 'backtrace', ['>backtrace',
378                                    \ '  2 function GlobalFunction[1]',
379                                    \ '  1 CallAFunction[1]',
380                                    \ '->0 SourceAnotherFile',
381                                    \ 'line 1: source Xtest2.vim'])
382
383  " Step into the 'source' command. Note that we print the full trace all the
384  " way though the source command.
385  call RunDbgCmd(buf, 'step', ['line 1: func DoAThing()'])
386  call RunDbgCmd(buf, 'backtrace', [
387        \ '>backtrace',
388        \ '  3 function GlobalFunction[1]',
389        \ '  2 CallAFunction[1]',
390        \ '  1 SourceAnotherFile[1]',
391        \ '->0 script ' .. getcwd() .. '/Xtest2.vim',
392        \ 'line 1: func DoAThing()'])
393
394  " step until we have another meaninfgul trace
395  call RunDbgCmd(buf, 'step', ['line 5: func File2Function()'])
396  call RunDbgCmd(buf, 'step', ['line 9: call File2Function()'])
397  call RunDbgCmd(buf, 'backtrace', [
398        \ '>backtrace',
399        \ '  3 function GlobalFunction[1]',
400        \ '  2 CallAFunction[1]',
401        \ '  1 SourceAnotherFile[1]',
402        \ '->0 script ' .. getcwd() .. '/Xtest2.vim',
403        \ 'line 9: call File2Function()'])
404
405  call RunDbgCmd(buf, 'step', ['line 1: call DoAThing()'])
406  call RunDbgCmd(buf, 'step', ['line 1: echo "DoAThing"'])
407  call RunDbgCmd(buf, 'backtrace', [
408        \ '>backtrace',
409        \ '  5 function GlobalFunction[1]',
410        \ '  4 CallAFunction[1]',
411        \ '  3 SourceAnotherFile[1]',
412        \ '  2 script ' .. getcwd() .. '/Xtest2.vim[9]',
413        \ '  1 function File2Function[1]',
414        \ '->0 DoAThing',
415        \ 'line 1: echo "DoAThing"'])
416
417  " Now, step (back to Xfile1.vim), and call the function _in_ Xfile2.vim
418  call RunDbgCmd(buf, 'step', ['line 1: End of function'])
419  call RunDbgCmd(buf, 'step', ['line 1: End of function'])
420  call RunDbgCmd(buf, 'step', ['line 10: End of sourced file'])
421  call RunDbgCmd(buf, 'step', ['line 1: End of function'])
422  call RunDbgCmd(buf, 'step', ['line 2: call File2Function()'])
423  call RunDbgCmd(buf, 'backtrace', [
424        \ '>backtrace',
425        \ '  1 function GlobalFunction[1]',
426        \ '->0 CallAFunction',
427        \ 'line 2: call File2Function()'])
428
429  call RunDbgCmd(buf, 'step', ['line 1: call DoAThing()'])
430  call RunDbgCmd(buf, 'backtrace', [
431        \ '>backtrace',
432        \ '  2 function GlobalFunction[1]',
433        \ '  1 CallAFunction[2]',
434        \ '->0 File2Function',
435        \ 'line 1: call DoAThing()'])
436
437  call StopVimInTerminal(buf)
438  call delete('Xtest1.vim')
439  call delete('Xtest2.vim')
440endfunc
441
442func Test_Backtrace_Autocmd()
443  CheckRunVimInTerminal
444
445  let file1 =<< trim END
446    func SourceAnotherFile()
447      source Xtest2.vim
448    endfunc
449
450    func CallAFunction()
451      call SourceAnotherFile()
452      call File2Function()
453    endfunc
454
455    func GlobalFunction()
456      call CallAFunction()
457    endfunc
458
459    au User TestGlobalFunction :call GlobalFunction() | echo "Done"
460  END
461  call writefile(file1, 'Xtest1.vim')
462
463  let file2 =<< trim END
464    func DoAThing()
465      echo "DoAThing"
466    endfunc
467
468    func File2Function()
469      call DoAThing()
470    endfunc
471
472    call File2Function()
473  END
474  call writefile(file2, 'Xtest2.vim')
475
476  let buf = RunVimInTerminal('-S Xtest1.vim', {})
477
478  call RunDbgCmd(buf,
479                \ ':debug doautocmd User TestGlobalFunction',
480                \ ['cmd: doautocmd User TestGlobalFunction'])
481  call RunDbgCmd(buf, 'step', ['cmd: call GlobalFunction() | echo "Done"'])
482
483  " At this point the ontly thing in the stack is the autocommand
484  call RunDbgCmd(buf, 'backtrace', [
485        \ '>backtrace',
486        \ '->0 User Autocommands for "TestGlobalFunction"',
487        \ 'cmd: call GlobalFunction() | echo "Done"'])
488
489  " And now we're back into the call stack
490  call RunDbgCmd(buf, 'step', ['line 1: call CallAFunction()'])
491  call RunDbgCmd(buf, 'backtrace', [
492        \ '>backtrace',
493        \ '  1 User Autocommands for "TestGlobalFunction"',
494        \ '->0 function GlobalFunction',
495        \ 'line 1: call CallAFunction()'])
496
497  call RunDbgCmd(buf, 'step', ['line 1: call SourceAnotherFile()'])
498  call RunDbgCmd(buf, 'step', ['line 1: source Xtest2.vim'])
499
500  call RunDbgCmd(buf, 'backtrace', [
501        \ '>backtrace',
502        \ '  3 User Autocommands for "TestGlobalFunction"',
503        \ '  2 function GlobalFunction[1]',
504        \ '  1 CallAFunction[1]',
505        \ '->0 SourceAnotherFile',
506        \ 'line 1: source Xtest2.vim'])
507
508  " Step into the 'source' command. Note that we print the full trace all the
509  " way though the source command.
510  call RunDbgCmd(buf, 'step', ['line 1: func DoAThing()'])
511  call RunDbgCmd(buf, 'backtrace', [
512        \ '>backtrace',
513        \ '  4 User Autocommands for "TestGlobalFunction"',
514        \ '  3 function GlobalFunction[1]',
515        \ '  2 CallAFunction[1]',
516        \ '  1 SourceAnotherFile[1]',
517        \ '->0 script ' .. getcwd() .. '/Xtest2.vim',
518        \ 'line 1: func DoAThing()'])
519
520  " step until we have another meaninfgul trace
521  call RunDbgCmd(buf, 'step', ['line 5: func File2Function()'])
522  call RunDbgCmd(buf, 'step', ['line 9: call File2Function()'])
523  call RunDbgCmd(buf, 'backtrace', [
524        \ '>backtrace',
525        \ '  4 User Autocommands for "TestGlobalFunction"',
526        \ '  3 function GlobalFunction[1]',
527        \ '  2 CallAFunction[1]',
528        \ '  1 SourceAnotherFile[1]',
529        \ '->0 script ' .. getcwd() .. '/Xtest2.vim',
530        \ 'line 9: call File2Function()'])
531
532  call RunDbgCmd(buf, 'step', ['line 1: call DoAThing()'])
533  call RunDbgCmd(buf, 'step', ['line 1: echo "DoAThing"'])
534  call RunDbgCmd(buf, 'backtrace', [
535        \ '>backtrace',
536        \ '  6 User Autocommands for "TestGlobalFunction"',
537        \ '  5 function GlobalFunction[1]',
538        \ '  4 CallAFunction[1]',
539        \ '  3 SourceAnotherFile[1]',
540        \ '  2 script ' .. getcwd() .. '/Xtest2.vim[9]',
541        \ '  1 function File2Function[1]',
542        \ '->0 DoAThing',
543        \ 'line 1: echo "DoAThing"'])
544
545  " Now, step (back to Xfile1.vim), and call the function _in_ Xfile2.vim
546  call RunDbgCmd(buf, 'step', ['line 1: End of function'])
547  call RunDbgCmd(buf, 'step', ['line 1: End of function'])
548  call RunDbgCmd(buf, 'step', ['line 10: End of sourced file'])
549  call RunDbgCmd(buf, 'step', ['line 1: End of function'])
550  call RunDbgCmd(buf, 'step', ['line 2: call File2Function()'])
551  call RunDbgCmd(buf, 'backtrace', [
552        \ '>backtrace',
553        \ '  2 User Autocommands for "TestGlobalFunction"',
554        \ '  1 function GlobalFunction[1]',
555        \ '->0 CallAFunction',
556        \ 'line 2: call File2Function()'])
557
558  call RunDbgCmd(buf, 'step', ['line 1: call DoAThing()'])
559  call RunDbgCmd(buf, 'backtrace', [
560        \ '>backtrace',
561        \ '  3 User Autocommands for "TestGlobalFunction"',
562        \ '  2 function GlobalFunction[1]',
563        \ '  1 CallAFunction[2]',
564        \ '->0 File2Function',
565        \ 'line 1: call DoAThing()'])
566
567
568  " Now unwind so that we get back to the original autocommand (and the second
569  " cmd echo "Done")
570  call RunDbgCmd(buf, 'finish', ['line 1: End of function'])
571  call RunDbgCmd(buf, 'backtrace', [
572        \ '>backtrace',
573        \ '  3 User Autocommands for "TestGlobalFunction"',
574        \ '  2 function GlobalFunction[1]',
575        \ '  1 CallAFunction[2]',
576        \ '->0 File2Function',
577        \ 'line 1: End of function'])
578
579  call RunDbgCmd(buf, 'finish', ['line 2: End of function'])
580  call RunDbgCmd(buf, 'backtrace', [
581        \ '>backtrace',
582        \ '  2 User Autocommands for "TestGlobalFunction"',
583        \ '  1 function GlobalFunction[1]',
584        \ '->0 CallAFunction',
585        \ 'line 2: End of function'])
586
587  call RunDbgCmd(buf, 'finish', ['line 1: End of function'])
588  call RunDbgCmd(buf, 'backtrace', [
589        \ '>backtrace',
590        \ '  1 User Autocommands for "TestGlobalFunction"',
591        \ '->0 function GlobalFunction',
592        \ 'line 1: End of function'])
593
594  call RunDbgCmd(buf, 'step', ['cmd: echo "Done"'])
595  call RunDbgCmd(buf, 'backtrace', [
596        \ '>backtrace',
597        \ '->0 User Autocommands for "TestGlobalFunction"',
598        \ 'cmd: echo "Done"'])
599
600  call StopVimInTerminal(buf)
601  call delete('Xtest1.vim')
602  call delete('Xtest2.vim')
603endfunc
604
605func Test_Backtrace_CmdLine()
606  CheckRunVimInTerminal
607
608  let file1 =<< trim END
609    func SourceAnotherFile()
610      source Xtest2.vim
611    endfunc
612
613    func CallAFunction()
614      call SourceAnotherFile()
615      call File2Function()
616    endfunc
617
618    func GlobalFunction()
619      call CallAFunction()
620    endfunc
621
622    au User TestGlobalFunction :call GlobalFunction() | echo "Done"
623  END
624  call writefile(file1, 'Xtest1.vim')
625
626  let file2 =<< trim END
627    func DoAThing()
628      echo "DoAThing"
629    endfunc
630
631    func File2Function()
632      call DoAThing()
633    endfunc
634
635    call File2Function()
636  END
637  call writefile(file2, 'Xtest2.vim')
638
639  let buf = RunVimInTerminal(
640        \ '-S Xtest1.vim -c "debug call GlobalFunction()"',
641        \ {'wait_for_ruler': 0})
642
643  " Need to wait for the vim-in-terminal to be ready
644  call CheckDbgOutput(buf, ['command line',
645                            \ 'cmd: call GlobalFunction()'])
646
647  " At this point the ontly thing in the stack is the cmdline
648  call RunDbgCmd(buf, 'backtrace', [
649        \ '>backtrace',
650        \ '->0 command line',
651        \ 'cmd: call GlobalFunction()'])
652
653  " And now we're back into the call stack
654  call RunDbgCmd(buf, 'step', ['line 1: call CallAFunction()'])
655  call RunDbgCmd(buf, 'backtrace', [
656        \ '>backtrace',
657        \ '  1 command line',
658        \ '->0 function GlobalFunction',
659        \ 'line 1: call CallAFunction()'])
660
661  call StopVimInTerminal(buf)
662  call delete('Xtest1.vim')
663  call delete('Xtest2.vim')
664endfunc
665
666func Test_Backtrace_DefFunction()
667  CheckRunVimInTerminal
668
669  let file1 =<< trim END
670    vim9script
671    import File2Function from './Xtest2.vim'
672
673    def SourceAnotherFile()
674      source Xtest2.vim
675    enddef
676
677    def CallAFunction()
678      SourceAnotherFile()
679      File2Function()
680    enddef
681
682    def g:GlobalFunction()
683      CallAFunction()
684    enddef
685
686    defcompile
687  END
688  call writefile(file1, 'Xtest1.vim')
689
690  let file2 =<< trim END
691    vim9script
692
693    def DoAThing(): number
694      let a = 100 * 2
695      a += 3
696      return a
697    enddef
698
699    export def File2Function()
700      DoAThing()
701    enddef
702
703    defcompile
704    File2Function()
705  END
706  call writefile(file2, 'Xtest2.vim')
707
708  let buf = RunVimInTerminal('-S Xtest1.vim', {})
709
710  call RunDbgCmd(buf,
711                \ ':debug call GlobalFunction()',
712                \ ['cmd: call GlobalFunction()'])
713
714  " FIXME: Vim9 lines are not debugged!
715  call RunDbgCmd(buf, 'step', ['line 1: source Xtest2.vim'])
716
717  " But they do appear in the backtrace
718  call RunDbgCmd(buf, 'backtrace', [
719        \ '\V>backtrace',
720        \ '\V  2 function GlobalFunction[1]',
721        \ '\V  1 <SNR>\.\*_CallAFunction[1]',
722        \ '\V->0 <SNR>\.\*_SourceAnotherFile',
723        \ '\Vline 1: source Xtest2.vim'],
724        \ #{match: 'pattern'})
725
726
727  call RunDbgCmd(buf, 'step', ['line 1: vim9script'])
728  call RunDbgCmd(buf, 'step', ['line 3: def DoAThing(): number'])
729  call RunDbgCmd(buf, 'step', ['line 9: export def File2Function()'])
730  call RunDbgCmd(buf, 'step', ['line 9: def File2Function()'])
731  call RunDbgCmd(buf, 'step', ['line 13: defcompile'])
732  call RunDbgCmd(buf, 'step', ['line 14: File2Function()'])
733  call RunDbgCmd(buf, 'backtrace', [
734        \ '\V>backtrace',
735        \ '\V  3 function GlobalFunction[1]',
736        \ '\V  2 <SNR>\.\*_CallAFunction[1]',
737        \ '\V  1 <SNR>\.\*_SourceAnotherFile[1]',
738        \ '\V->0 script ' .. getcwd() .. '/Xtest2.vim',
739        \ '\Vline 14: File2Function()'],
740        \ #{match: 'pattern'})
741
742  " Don't step into compiled functions...
743  call RunDbgCmd(buf, 'step', ['line 15: End of sourced file'])
744  call RunDbgCmd(buf, 'backtrace', [
745        \ '\V>backtrace',
746        \ '\V  3 function GlobalFunction[1]',
747        \ '\V  2 <SNR>\.\*_CallAFunction[1]',
748        \ '\V  1 <SNR>\.\*_SourceAnotherFile[1]',
749        \ '\V->0 script ' .. getcwd() .. '/Xtest2.vim',
750        \ '\Vline 15: End of sourced file'],
751        \ #{match: 'pattern'})
752
753
754  call StopVimInTerminal(buf)
755  call delete('Xtest1.vim')
756  call delete('Xtest2.vim')
757endfunc
758