test_debugger.vim 46 KB

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