test_debugger.vim 46 KB

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