1" Tests for the Vim script debug commands 2 3source shared.vim 4source screendump.vim 5source check.vim 6 7CheckRunVimInTerminal 8 9func CheckCWD() 10 " Check that the longer lines don't wrap due to the length of the script name 11 " in cwd 12 let script_len = len( getcwd() .. '/Xtest1.vim' ) 13 let longest_line = len( 'Breakpoint in "" line 1' ) 14 if script_len > ( 75 - longest_line ) 15 throw 'Skipped: Your CWD has too many characters' 16 endif 17endfunc 18command! -nargs=0 -bar CheckCWD call CheckCWD() 19 20func CheckDbgOutput(buf, lines, options = {}) 21 " Verify the expected output 22 let lnum = 20 - len(a:lines) 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))}, 200) 26 else 27 call WaitForAssert({-> assert_equal(l, term_getline(a:buf, lnum))}, 200) 28 endif 29 let lnum += 1 30 endfor 31endfunc 32 33" Run a Vim debugger command 34" If the expected output argument is supplied, then check for it. 35func RunDbgCmd(buf, cmd, ...) 36 call term_sendkeys(a:buf, a:cmd . "\r") 37 call TermWait(a:buf) 38 39 if a:0 != 0 40 let options = #{match: 'equal'} 41 if a:0 > 1 42 call extend(options, a:2) 43 endif 44 call CheckDbgOutput(a:buf, a:1, options) 45 endif 46endfunc 47 48" Debugger tests 49func Test_Debugger() 50 " Create a Vim script with some functions 51 let lines =<< trim END 52 func Foo() 53 let var1 = 1 54 let var2 = Bar(var1) + 9 55 return var2 56 endfunc 57 func Bar(var) 58 let var1 = 2 + a:var 59 let var2 = Bazz(var1) + 4 60 return var2 61 endfunc 62 func Bazz(var) 63 try 64 let var1 = 3 + a:var 65 let var3 = "another var" 66 let var3 = "value2" 67 catch 68 let var4 = "exception" 69 endtry 70 return var1 71 endfunc 72 END 73 call writefile(lines, 'Xtest.vim') 74 75 " Start Vim in a terminal 76 let buf = RunVimInTerminal('-S Xtest.vim', {}) 77 78 " Start the Vim debugger 79 call RunDbgCmd(buf, ':debug echo Foo()', ['cmd: echo Foo()']) 80 81 " Create a few stack frames by stepping through functions 82 call RunDbgCmd(buf, 'step', ['line 1: let var1 = 1']) 83 call RunDbgCmd(buf, 'step', ['line 2: let var2 = Bar(var1) + 9']) 84 call RunDbgCmd(buf, 'step', ['line 1: let var1 = 2 + a:var']) 85 call RunDbgCmd(buf, 'step', ['line 2: let var2 = Bazz(var1) + 4']) 86 call RunDbgCmd(buf, 'step', ['line 1: try']) 87 call RunDbgCmd(buf, 'step', ['line 2: let var1 = 3 + a:var']) 88 call RunDbgCmd(buf, 'step', ['line 3: let var3 = "another var"']) 89 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 97 " Check variables in different stack frames 98 call RunDbgCmd(buf, 'echo var1', ['6']) 99 100 call RunDbgCmd(buf, 'up') 101 call RunDbgCmd(buf, 'back', [ 102 \ ' 2 function Foo[2]', 103 \ '->1 Bar[2]', 104 \ ' 0 Bazz', 105 \ 'line 3: let var3 = "another var"']) 106 call RunDbgCmd(buf, 'echo var1', ['3']) 107 108 call RunDbgCmd(buf, 'u') 109 call RunDbgCmd(buf, 'bt', [ 110 \ '->2 function Foo[2]', 111 \ ' 1 Bar[2]', 112 \ ' 0 Bazz', 113 \ 'line 3: let var3 = "another var"']) 114 call RunDbgCmd(buf, 'echo var1', ['1']) 115 116 " Undefined variables 117 call RunDbgCmd(buf, 'step') 118 call RunDbgCmd(buf, 'frame 2') 119 call RunDbgCmd(buf, 'echo var3', [ 120 \ 'Error detected while processing function Foo[2]..Bar[2]..Bazz:', 121 \ 'line 4:', 122 \ 'E121: Undefined variable: var3']) 123 124 " var3 is defined in this level with some other value 125 call RunDbgCmd(buf, 'fr 0') 126 call RunDbgCmd(buf, 'echo var3', ['another var']) 127 128 call RunDbgCmd(buf, 'step') 129 call RunDbgCmd(buf, '') 130 call RunDbgCmd(buf, '') 131 call RunDbgCmd(buf, '') 132 call RunDbgCmd(buf, '') 133 call RunDbgCmd(buf, 'step', [ 134 \ 'function Foo[2]..Bar', 135 \ 'line 3: End of function']) 136 call RunDbgCmd(buf, 'up') 137 138 " Undefined var2 139 call RunDbgCmd(buf, 'echo var2', [ 140 \ 'Error detected while processing function Foo[2]..Bar:', 141 \ 'line 3:', 142 \ 'E121: Undefined variable: var2']) 143 144 " Var2 is defined with 10 145 call RunDbgCmd(buf, 'down') 146 call RunDbgCmd(buf, 'echo var2', ['10']) 147 148 " Backtrace movements 149 call RunDbgCmd(buf, 'b', [ 150 \ ' 1 function Foo[2]', 151 \ '->0 Bar', 152 \ 'line 3: End of function']) 153 154 " next command cannot go down, we are on bottom 155 call RunDbgCmd(buf, 'down', ['frame is zero']) 156 call RunDbgCmd(buf, 'up') 157 158 " next command cannot go up, we are on top 159 call RunDbgCmd(buf, 'up', ['frame at highest level: 1']) 160 call RunDbgCmd(buf, 'where', [ 161 \ '->1 function Foo[2]', 162 \ ' 0 Bar', 163 \ 'line 3: End of function']) 164 165 " fil is not frame or finish, it is file 166 call RunDbgCmd(buf, 'fil', ['"[No Name]" --No lines in buffer--']) 167 168 " relative backtrace movement 169 call RunDbgCmd(buf, 'fr -1') 170 call RunDbgCmd(buf, 'frame', [ 171 \ ' 1 function Foo[2]', 172 \ '->0 Bar', 173 \ 'line 3: End of function']) 174 175 call RunDbgCmd(buf, 'fr +1') 176 call RunDbgCmd(buf, 'fram', [ 177 \ '->1 function Foo[2]', 178 \ ' 0 Bar', 179 \ 'line 3: End of function']) 180 181 " go beyond limits does not crash 182 call RunDbgCmd(buf, 'fr 100', ['frame at highest level: 1']) 183 call RunDbgCmd(buf, 'fra', [ 184 \ '->1 function Foo[2]', 185 \ ' 0 Bar', 186 \ 'line 3: End of function']) 187 188 call RunDbgCmd(buf, 'frame -40', ['frame is zero']) 189 call RunDbgCmd(buf, 'fram', [ 190 \ ' 1 function Foo[2]', 191 \ '->0 Bar', 192 \ 'line 3: End of function']) 193 194 " final result 19 195 call RunDbgCmd(buf, 'cont', ['19']) 196 197 " breakpoints tests 198 199 " Start a debug session, so that reading the last line from the terminal 200 " works properly. 201 call RunDbgCmd(buf, ':debug echo Foo()') 202 203 " No breakpoints 204 call RunDbgCmd(buf, 'breakl', ['No breakpoints defined']) 205 206 " Place some breakpoints 207 call RunDbgCmd(buf, 'breaka func Bar') 208 call RunDbgCmd(buf, 'breaklis', [' 1 func Bar line 1']) 209 call RunDbgCmd(buf, 'breakadd func 3 Bazz') 210 call RunDbgCmd(buf, 'breaklist', [' 1 func Bar line 1', 211 \ ' 2 func Bazz line 3']) 212 213 " Check whether the breakpoints are hit 214 call RunDbgCmd(buf, 'cont', [ 215 \ 'Breakpoint in "Bar" line 1', 216 \ 'function Foo[2]..Bar', 217 \ 'line 1: let var1 = 2 + a:var']) 218 call RunDbgCmd(buf, 'cont', [ 219 \ 'Breakpoint in "Bazz" line 3', 220 \ 'function Foo[2]..Bar[2]..Bazz', 221 \ 'line 3: let var3 = "another var"']) 222 223 " Delete the breakpoints 224 call RunDbgCmd(buf, 'breakd 1') 225 call RunDbgCmd(buf, 'breakli', [' 2 func Bazz line 3']) 226 call RunDbgCmd(buf, 'breakdel func 3 Bazz') 227 call RunDbgCmd(buf, 'breakl', ['No breakpoints defined']) 228 229 call RunDbgCmd(buf, 'cont') 230 231 " Make sure the breakpoints are removed 232 call RunDbgCmd(buf, ':echo Foo()', ['19']) 233 234 " Delete a non-existing breakpoint 235 call RunDbgCmd(buf, ':breakdel 2', ['E161: Breakpoint not found: 2']) 236 237 " Expression breakpoint 238 call RunDbgCmd(buf, ':breakadd func 2 Bazz') 239 call RunDbgCmd(buf, ':echo Bazz(1)', [ 240 \ 'Entering Debug mode. Type "cont" to continue.', 241 \ 'function Bazz', 242 \ 'line 2: let var1 = 3 + a:var']) 243 call RunDbgCmd(buf, 'step') 244 call RunDbgCmd(buf, 'step') 245 call RunDbgCmd(buf, 'breaka expr var3') 246 call RunDbgCmd(buf, 'breakl', [' 3 func Bazz line 2', 247 \ ' 4 expr var3']) 248 call RunDbgCmd(buf, 'cont', ['Breakpoint in "Bazz" line 5', 249 \ 'Oldval = "''another var''"', 250 \ 'Newval = "''value2''"', 251 \ 'function Bazz', 252 \ 'line 5: catch']) 253 254 call RunDbgCmd(buf, 'breakdel *') 255 call RunDbgCmd(buf, 'breakl', ['No breakpoints defined']) 256 257 " Check for error cases 258 call RunDbgCmd(buf, 'breakadd abcd', [ 259 \ 'Error detected while processing function Bazz:', 260 \ 'line 5:', 261 \ 'E475: Invalid argument: abcd']) 262 call RunDbgCmd(buf, 'breakadd func', ['E475: Invalid argument: func']) 263 call RunDbgCmd(buf, 'breakadd func 2', ['E475: Invalid argument: func 2']) 264 call RunDbgCmd(buf, 'breaka func a()', ['E475: Invalid argument: func a()']) 265 call RunDbgCmd(buf, 'breakd abcd', ['E475: Invalid argument: abcd']) 266 call RunDbgCmd(buf, 'breakd func', ['E475: Invalid argument: func']) 267 call RunDbgCmd(buf, 'breakd func a()', ['E475: Invalid argument: func a()']) 268 call RunDbgCmd(buf, 'breakd func a', ['E161: Breakpoint not found: func a']) 269 call RunDbgCmd(buf, 'breakd expr', ['E475: Invalid argument: expr']) 270 call RunDbgCmd(buf, 'breakd expr x', [ 271 \ 'E121: Undefined variable: x', 272 \ 'E161: Breakpoint not found: expr x']) 273 274 " finish the current function 275 call RunDbgCmd(buf, 'finish', [ 276 \ 'function Bazz', 277 \ 'line 8: End of function']) 278 call RunDbgCmd(buf, 'cont') 279 280 " Test for :next 281 call RunDbgCmd(buf, ':debug echo Bar(1)') 282 call RunDbgCmd(buf, 'step') 283 call RunDbgCmd(buf, 'next') 284 call RunDbgCmd(buf, '', [ 285 \ 'function Bar', 286 \ 'line 3: return var2']) 287 call RunDbgCmd(buf, 'c') 288 289 " Test for :interrupt 290 call RunDbgCmd(buf, ':debug echo Bazz(1)') 291 call RunDbgCmd(buf, 'step') 292 call RunDbgCmd(buf, 'step') 293 call RunDbgCmd(buf, 'interrupt', [ 294 \ 'Exception thrown: Vim:Interrupt', 295 \ 'function Bazz', 296 \ 'line 5: catch']) 297 call RunDbgCmd(buf, 'c') 298 299 " Test for :quit 300 call RunDbgCmd(buf, ':debug echo Foo()') 301 call RunDbgCmd(buf, 'breakdel *') 302 call RunDbgCmd(buf, 'breakadd func 3 Foo') 303 call RunDbgCmd(buf, 'breakadd func 3 Bazz') 304 call RunDbgCmd(buf, 'cont', [ 305 \ 'Breakpoint in "Bazz" line 3', 306 \ 'function Foo[2]..Bar[2]..Bazz', 307 \ 'line 3: let var3 = "another var"']) 308 call RunDbgCmd(buf, 'quit', [ 309 \ 'Breakpoint in "Foo" line 3', 310 \ 'function Foo', 311 \ 'line 3: return var2']) 312 call RunDbgCmd(buf, 'breakdel *') 313 call RunDbgCmd(buf, 'quit') 314 call RunDbgCmd(buf, 'enew! | only!') 315 316 call StopVimInTerminal(buf) 317 318 " Tests for :breakadd file and :breakadd here 319 " Breakpoints should be set before sourcing the file 320 321 let lines =<< trim END 322 let var1 = 10 323 let var2 = 20 324 let var3 = 30 325 let var4 = 40 326 END 327 call writefile(lines, 'Xtest.vim') 328 329 " Start Vim in a terminal 330 let buf = RunVimInTerminal('Xtest.vim', {}) 331 call RunDbgCmd(buf, ':breakadd file 2 Xtest.vim') 332 call RunDbgCmd(buf, ':4 | breakadd here') 333 call RunDbgCmd(buf, ':source Xtest.vim', ['line 2: let var2 = 20']) 334 call RunDbgCmd(buf, 'cont', ['line 4: let var4 = 40']) 335 call RunDbgCmd(buf, 'cont') 336 337 call StopVimInTerminal(buf) 338 339 call delete('Xtest.vim') 340endfunc 341 342func Test_Backtrace_Through_Source() 343 CheckCWD 344 let file1 =<< trim END 345 func SourceAnotherFile() 346 source Xtest2.vim 347 endfunc 348 349 func CallAFunction() 350 call SourceAnotherFile() 351 call File2Function() 352 endfunc 353 354 func GlobalFunction() 355 call CallAFunction() 356 endfunc 357 END 358 call writefile(file1, 'Xtest1.vim') 359 360 let file2 =<< trim END 361 func DoAThing() 362 echo "DoAThing" 363 endfunc 364 365 func File2Function() 366 call DoAThing() 367 endfunc 368 369 call File2Function() 370 END 371 call writefile(file2, 'Xtest2.vim') 372 373 let buf = RunVimInTerminal('-S Xtest1.vim', {}) 374 375 call RunDbgCmd(buf, 376 \ ':debug call GlobalFunction()', 377 \ ['cmd: call GlobalFunction()']) 378 call RunDbgCmd(buf, 'step', ['line 1: call CallAFunction()']) 379 380 call RunDbgCmd(buf, 'backtrace', ['>backtrace', 381 \ '->0 function GlobalFunction', 382 \ 'line 1: call CallAFunction()']) 383 384 call RunDbgCmd(buf, 'step', ['line 1: call SourceAnotherFile()']) 385 call RunDbgCmd(buf, 'step', ['line 1: source Xtest2.vim']) 386 387 call RunDbgCmd(buf, 'backtrace', ['>backtrace', 388 \ ' 2 function GlobalFunction[1]', 389 \ ' 1 CallAFunction[1]', 390 \ '->0 SourceAnotherFile', 391 \ 'line 1: source Xtest2.vim']) 392 393 " Step into the 'source' command. Note that we print the full trace all the 394 " way though the source command. 395 call RunDbgCmd(buf, 'step', ['line 1: func DoAThing()']) 396 call RunDbgCmd(buf, 'backtrace', [ 397 \ '>backtrace', 398 \ ' 3 function GlobalFunction[1]', 399 \ ' 2 CallAFunction[1]', 400 \ ' 1 SourceAnotherFile[1]', 401 \ '->0 script ' .. getcwd() .. '/Xtest2.vim', 402 \ 'line 1: func DoAThing()']) 403 404 call RunDbgCmd( buf, 'up' ) 405 call RunDbgCmd( buf, 'backtrace', [ 406 \ '>backtrace', 407 \ ' 3 function GlobalFunction[1]', 408 \ ' 2 CallAFunction[1]', 409 \ '->1 SourceAnotherFile[1]', 410 \ ' 0 script ' .. getcwd() .. '/Xtest2.vim', 411 \ 'line 1: func DoAThing()' ] ) 412 413 call RunDbgCmd( buf, 'up' ) 414 call RunDbgCmd( buf, 'backtrace', [ 415 \ '>backtrace', 416 \ ' 3 function GlobalFunction[1]', 417 \ '->2 CallAFunction[1]', 418 \ ' 1 SourceAnotherFile[1]', 419 \ ' 0 script ' .. getcwd() .. '/Xtest2.vim', 420 \ 'line 1: func DoAThing()' ] ) 421 422 call RunDbgCmd( buf, 'up' ) 423 call RunDbgCmd( buf, 'backtrace', [ 424 \ '>backtrace', 425 \ '->3 function GlobalFunction[1]', 426 \ ' 2 CallAFunction[1]', 427 \ ' 1 SourceAnotherFile[1]', 428 \ ' 0 script ' .. getcwd() .. '/Xtest2.vim', 429 \ 'line 1: func DoAThing()' ] ) 430 431 call RunDbgCmd( buf, 'up', [ 'frame at highest level: 3' ] ) 432 call RunDbgCmd( buf, 'backtrace', [ 433 \ '>backtrace', 434 \ '->3 function GlobalFunction[1]', 435 \ ' 2 CallAFunction[1]', 436 \ ' 1 SourceAnotherFile[1]', 437 \ ' 0 script ' .. getcwd() .. '/Xtest2.vim', 438 \ 'line 1: func DoAThing()' ] ) 439 440 call RunDbgCmd( buf, 'down' ) 441 call RunDbgCmd( buf, 'backtrace', [ 442 \ '>backtrace', 443 \ ' 3 function GlobalFunction[1]', 444 \ '->2 CallAFunction[1]', 445 \ ' 1 SourceAnotherFile[1]', 446 \ ' 0 script ' .. getcwd() .. '/Xtest2.vim', 447 \ 'line 1: func DoAThing()' ] ) 448 449 call RunDbgCmd( buf, 'down' ) 450 call RunDbgCmd( buf, 'backtrace', [ 451 \ '>backtrace', 452 \ ' 3 function GlobalFunction[1]', 453 \ ' 2 CallAFunction[1]', 454 \ '->1 SourceAnotherFile[1]', 455 \ ' 0 script ' .. getcwd() .. '/Xtest2.vim', 456 \ 'line 1: func DoAThing()' ] ) 457 458 call RunDbgCmd( buf, 'down' ) 459 call RunDbgCmd( buf, 'backtrace', [ 460 \ '>backtrace', 461 \ ' 3 function GlobalFunction[1]', 462 \ ' 2 CallAFunction[1]', 463 \ ' 1 SourceAnotherFile[1]', 464 \ '->0 script ' .. getcwd() .. '/Xtest2.vim', 465 \ 'line 1: func DoAThing()' ] ) 466 467 call RunDbgCmd( buf, 'down', [ 'frame is zero' ] ) 468 469 " step until we have another meaninfgul trace 470 call RunDbgCmd(buf, 'step', ['line 5: func File2Function()']) 471 call RunDbgCmd(buf, 'step', ['line 9: call File2Function()']) 472 call RunDbgCmd(buf, 'backtrace', [ 473 \ '>backtrace', 474 \ ' 3 function GlobalFunction[1]', 475 \ ' 2 CallAFunction[1]', 476 \ ' 1 SourceAnotherFile[1]', 477 \ '->0 script ' .. getcwd() .. '/Xtest2.vim', 478 \ 'line 9: call File2Function()']) 479 480 call RunDbgCmd(buf, 'step', ['line 1: call DoAThing()']) 481 call RunDbgCmd(buf, 'step', ['line 1: echo "DoAThing"']) 482 call RunDbgCmd(buf, 'backtrace', [ 483 \ '>backtrace', 484 \ ' 5 function GlobalFunction[1]', 485 \ ' 4 CallAFunction[1]', 486 \ ' 3 SourceAnotherFile[1]', 487 \ ' 2 script ' .. getcwd() .. '/Xtest2.vim[9]', 488 \ ' 1 function File2Function[1]', 489 \ '->0 DoAThing', 490 \ 'line 1: echo "DoAThing"']) 491 492 " Now, step (back to Xfile1.vim), and call the function _in_ Xfile2.vim 493 call RunDbgCmd(buf, 'step', ['line 1: End of function']) 494 call RunDbgCmd(buf, 'step', ['line 1: End of function']) 495 call RunDbgCmd(buf, 'step', ['line 10: End of sourced file']) 496 call RunDbgCmd(buf, 'step', ['line 1: End of function']) 497 call RunDbgCmd(buf, 'step', ['line 2: call File2Function()']) 498 call RunDbgCmd(buf, 'backtrace', [ 499 \ '>backtrace', 500 \ ' 1 function GlobalFunction[1]', 501 \ '->0 CallAFunction', 502 \ 'line 2: call File2Function()']) 503 504 call RunDbgCmd(buf, 'step', ['line 1: call DoAThing()']) 505 call RunDbgCmd(buf, 'backtrace', [ 506 \ '>backtrace', 507 \ ' 2 function GlobalFunction[1]', 508 \ ' 1 CallAFunction[2]', 509 \ '->0 File2Function', 510 \ 'line 1: call DoAThing()']) 511 512 call StopVimInTerminal(buf) 513 call delete('Xtest1.vim') 514 call delete('Xtest2.vim') 515endfunc 516 517func Test_Backtrace_Autocmd() 518 CheckCWD 519 let file1 =<< trim END 520 func SourceAnotherFile() 521 source Xtest2.vim 522 endfunc 523 524 func CallAFunction() 525 call SourceAnotherFile() 526 call File2Function() 527 endfunc 528 529 func GlobalFunction() 530 call CallAFunction() 531 endfunc 532 533 au User TestGlobalFunction :call GlobalFunction() | echo "Done" 534 END 535 call writefile(file1, 'Xtest1.vim') 536 537 let file2 =<< trim END 538 func DoAThing() 539 echo "DoAThing" 540 endfunc 541 542 func File2Function() 543 call DoAThing() 544 endfunc 545 546 call File2Function() 547 END 548 call writefile(file2, 'Xtest2.vim') 549 550 let buf = RunVimInTerminal('-S Xtest1.vim', {}) 551 552 call RunDbgCmd(buf, 553 \ ':debug doautocmd User TestGlobalFunction', 554 \ ['cmd: doautocmd User TestGlobalFunction']) 555 call RunDbgCmd(buf, 'step', ['cmd: call GlobalFunction() | echo "Done"']) 556 557 " At this point the ontly thing in the stack is the autocommand 558 call RunDbgCmd(buf, 'backtrace', [ 559 \ '>backtrace', 560 \ '->0 User Autocommands for "TestGlobalFunction"', 561 \ 'cmd: call GlobalFunction() | echo "Done"']) 562 563 " And now we're back into the call stack 564 call RunDbgCmd(buf, 'step', ['line 1: call CallAFunction()']) 565 call RunDbgCmd(buf, 'backtrace', [ 566 \ '>backtrace', 567 \ ' 1 User Autocommands for "TestGlobalFunction"', 568 \ '->0 function GlobalFunction', 569 \ 'line 1: call CallAFunction()']) 570 571 call RunDbgCmd(buf, 'step', ['line 1: call SourceAnotherFile()']) 572 call RunDbgCmd(buf, 'step', ['line 1: source Xtest2.vim']) 573 574 call RunDbgCmd(buf, 'backtrace', [ 575 \ '>backtrace', 576 \ ' 3 User Autocommands for "TestGlobalFunction"', 577 \ ' 2 function GlobalFunction[1]', 578 \ ' 1 CallAFunction[1]', 579 \ '->0 SourceAnotherFile', 580 \ 'line 1: source Xtest2.vim']) 581 582 " Step into the 'source' command. Note that we print the full trace all the 583 " way though the source command. 584 call RunDbgCmd(buf, 'step', ['line 1: func DoAThing()']) 585 call RunDbgCmd(buf, 'backtrace', [ 586 \ '>backtrace', 587 \ ' 4 User Autocommands for "TestGlobalFunction"', 588 \ ' 3 function GlobalFunction[1]', 589 \ ' 2 CallAFunction[1]', 590 \ ' 1 SourceAnotherFile[1]', 591 \ '->0 script ' .. getcwd() .. '/Xtest2.vim', 592 \ 'line 1: func DoAThing()']) 593 594 " step until we have another meaninfgul trace 595 call RunDbgCmd(buf, 'step', ['line 5: func File2Function()']) 596 call RunDbgCmd(buf, 'step', ['line 9: call File2Function()']) 597 call RunDbgCmd(buf, 'backtrace', [ 598 \ '>backtrace', 599 \ ' 4 User Autocommands for "TestGlobalFunction"', 600 \ ' 3 function GlobalFunction[1]', 601 \ ' 2 CallAFunction[1]', 602 \ ' 1 SourceAnotherFile[1]', 603 \ '->0 script ' .. getcwd() .. '/Xtest2.vim', 604 \ 'line 9: call File2Function()']) 605 606 call RunDbgCmd(buf, 'step', ['line 1: call DoAThing()']) 607 call RunDbgCmd(buf, 'step', ['line 1: echo "DoAThing"']) 608 call RunDbgCmd(buf, 'backtrace', [ 609 \ '>backtrace', 610 \ ' 6 User Autocommands for "TestGlobalFunction"', 611 \ ' 5 function GlobalFunction[1]', 612 \ ' 4 CallAFunction[1]', 613 \ ' 3 SourceAnotherFile[1]', 614 \ ' 2 script ' .. getcwd() .. '/Xtest2.vim[9]', 615 \ ' 1 function File2Function[1]', 616 \ '->0 DoAThing', 617 \ 'line 1: echo "DoAThing"']) 618 619 " Now, step (back to Xfile1.vim), and call the function _in_ Xfile2.vim 620 call RunDbgCmd(buf, 'step', ['line 1: End of function']) 621 call RunDbgCmd(buf, 'step', ['line 1: End of function']) 622 call RunDbgCmd(buf, 'step', ['line 10: End of sourced file']) 623 call RunDbgCmd(buf, 'step', ['line 1: End of function']) 624 call RunDbgCmd(buf, 'step', ['line 2: call File2Function()']) 625 call RunDbgCmd(buf, 'backtrace', [ 626 \ '>backtrace', 627 \ ' 2 User Autocommands for "TestGlobalFunction"', 628 \ ' 1 function GlobalFunction[1]', 629 \ '->0 CallAFunction', 630 \ 'line 2: call File2Function()']) 631 632 call RunDbgCmd(buf, 'step', ['line 1: call DoAThing()']) 633 call RunDbgCmd(buf, 'backtrace', [ 634 \ '>backtrace', 635 \ ' 3 User Autocommands for "TestGlobalFunction"', 636 \ ' 2 function GlobalFunction[1]', 637 \ ' 1 CallAFunction[2]', 638 \ '->0 File2Function', 639 \ 'line 1: call DoAThing()']) 640 641 642 " Now unwind so that we get back to the original autocommand (and the second 643 " cmd echo "Done") 644 call RunDbgCmd(buf, 'finish', ['line 1: End of function']) 645 call RunDbgCmd(buf, 'backtrace', [ 646 \ '>backtrace', 647 \ ' 3 User Autocommands for "TestGlobalFunction"', 648 \ ' 2 function GlobalFunction[1]', 649 \ ' 1 CallAFunction[2]', 650 \ '->0 File2Function', 651 \ 'line 1: End of function']) 652 653 call RunDbgCmd(buf, 'finish', ['line 2: End of function']) 654 call RunDbgCmd(buf, 'backtrace', [ 655 \ '>backtrace', 656 \ ' 2 User Autocommands for "TestGlobalFunction"', 657 \ ' 1 function GlobalFunction[1]', 658 \ '->0 CallAFunction', 659 \ 'line 2: End of function']) 660 661 call RunDbgCmd(buf, 'finish', ['line 1: End of function']) 662 call RunDbgCmd(buf, 'backtrace', [ 663 \ '>backtrace', 664 \ ' 1 User Autocommands for "TestGlobalFunction"', 665 \ '->0 function GlobalFunction', 666 \ 'line 1: End of function']) 667 668 call RunDbgCmd(buf, 'step', ['cmd: echo "Done"']) 669 call RunDbgCmd(buf, 'backtrace', [ 670 \ '>backtrace', 671 \ '->0 User Autocommands for "TestGlobalFunction"', 672 \ 'cmd: echo "Done"']) 673 674 call StopVimInTerminal(buf) 675 call delete('Xtest1.vim') 676 call delete('Xtest2.vim') 677endfunc 678 679func Test_Backtrace_CmdLine() 680 CheckCWD 681 let file1 =<< trim END 682 func SourceAnotherFile() 683 source Xtest2.vim 684 endfunc 685 686 func CallAFunction() 687 call SourceAnotherFile() 688 call File2Function() 689 endfunc 690 691 func GlobalFunction() 692 call CallAFunction() 693 endfunc 694 695 au User TestGlobalFunction :call GlobalFunction() | echo "Done" 696 END 697 call writefile(file1, 'Xtest1.vim') 698 699 let file2 =<< trim END 700 func DoAThing() 701 echo "DoAThing" 702 endfunc 703 704 func File2Function() 705 call DoAThing() 706 endfunc 707 708 call File2Function() 709 END 710 call writefile(file2, 'Xtest2.vim') 711 712 let buf = RunVimInTerminal( 713 \ '-S Xtest1.vim -c "debug call GlobalFunction()"', 714 \ {'wait_for_ruler': 0}) 715 716 " Need to wait for the vim-in-terminal to be ready 717 call CheckDbgOutput(buf, ['command line', 718 \ 'cmd: call GlobalFunction()']) 719 720 " At this point the ontly thing in the stack is the cmdline 721 call RunDbgCmd(buf, 'backtrace', [ 722 \ '>backtrace', 723 \ '->0 command line', 724 \ 'cmd: call GlobalFunction()']) 725 726 " And now we're back into the call stack 727 call RunDbgCmd(buf, 'step', ['line 1: call CallAFunction()']) 728 call RunDbgCmd(buf, 'backtrace', [ 729 \ '>backtrace', 730 \ ' 1 command line', 731 \ '->0 function GlobalFunction', 732 \ 'line 1: call CallAFunction()']) 733 734 call StopVimInTerminal(buf) 735 call delete('Xtest1.vim') 736 call delete('Xtest2.vim') 737endfunc 738 739func Test_Backtrace_DefFunction() 740 CheckCWD 741 let file1 =<< trim END 742 vim9script 743 import File2Function from './Xtest2.vim' 744 745 def SourceAnotherFile() 746 source Xtest2.vim 747 enddef 748 749 def CallAFunction() 750 SourceAnotherFile() 751 File2Function() 752 enddef 753 754 def g:GlobalFunction() 755 CallAFunction() 756 enddef 757 758 defcompile 759 END 760 call writefile(file1, 'Xtest1.vim') 761 762 let file2 =<< trim END 763 vim9script 764 765 def DoAThing(): number 766 let a = 100 * 2 767 a += 3 768 return a 769 enddef 770 771 export def File2Function() 772 DoAThing() 773 enddef 774 775 defcompile 776 File2Function() 777 END 778 call writefile(file2, 'Xtest2.vim') 779 780 let buf = RunVimInTerminal('-S Xtest1.vim', {}) 781 782 call RunDbgCmd(buf, 783 \ ':debug call GlobalFunction()', 784 \ ['cmd: call GlobalFunction()']) 785 786 " FIXME: Vim9 lines are not debugged! 787 call RunDbgCmd(buf, 'step', ['line 1: source Xtest2.vim']) 788 789 " But they do appear in the backtrace 790 call RunDbgCmd(buf, 'backtrace', [ 791 \ '\V>backtrace', 792 \ '\V 2 function GlobalFunction[1]', 793 \ '\V 1 <SNR>\.\*_CallAFunction[1]', 794 \ '\V->0 <SNR>\.\*_SourceAnotherFile', 795 \ '\Vline 1: source Xtest2.vim'], 796 \ #{match: 'pattern'}) 797 798 799 call RunDbgCmd(buf, 'step', ['line 1: vim9script']) 800 call RunDbgCmd(buf, 'step', ['line 3: def DoAThing(): number']) 801 call RunDbgCmd(buf, 'step', ['line 9: export def File2Function()']) 802 call RunDbgCmd(buf, 'step', ['line 9: def File2Function()']) 803 call RunDbgCmd(buf, 'step', ['line 13: defcompile']) 804 call RunDbgCmd(buf, 'step', ['line 14: File2Function()']) 805 call RunDbgCmd(buf, 'backtrace', [ 806 \ '\V>backtrace', 807 \ '\V 3 function GlobalFunction[1]', 808 \ '\V 2 <SNR>\.\*_CallAFunction[1]', 809 \ '\V 1 <SNR>\.\*_SourceAnotherFile[1]', 810 \ '\V->0 script ' .. getcwd() .. '/Xtest2.vim', 811 \ '\Vline 14: File2Function()'], 812 \ #{match: 'pattern'}) 813 814 " Don't step into compiled functions... 815 call RunDbgCmd(buf, 'step', ['line 15: End of sourced file']) 816 call RunDbgCmd(buf, 'backtrace', [ 817 \ '\V>backtrace', 818 \ '\V 3 function GlobalFunction[1]', 819 \ '\V 2 <SNR>\.\*_CallAFunction[1]', 820 \ '\V 1 <SNR>\.\*_SourceAnotherFile[1]', 821 \ '\V->0 script ' .. getcwd() .. '/Xtest2.vim', 822 \ '\Vline 15: End of sourced file'], 823 \ #{match: 'pattern'}) 824 825 826 call StopVimInTerminal(buf) 827 call delete('Xtest1.vim') 828 call delete('Xtest2.vim') 829endfunc 830 831func Test_debug_backtrace_level() 832 CheckCWD 833 let lines =<< trim END 834 let s:file1_var = 'file1' 835 let g:global_var = 'global' 836 837 func s:File1Func( arg ) 838 let s:file1_var .= a:arg 839 let local_var = s:file1_var .. ' test1' 840 let g:global_var .= local_var 841 source Xtest2.vim 842 endfunc 843 844 call s:File1Func( 'arg1' ) 845 END 846 call writefile(lines, 'Xtest1.vim') 847 848 let lines =<< trim END 849 let s:file2_var = 'file2' 850 851 func s:File2Func( arg ) 852 let s:file2_var .= a:arg 853 let local_var = s:file2_var .. ' test2' 854 let g:global_var .= local_var 855 endfunc 856 857 call s:File2Func( 'arg2' ) 858 END 859 call writefile(lines, 'Xtest2.vim') 860 861 let file1 = getcwd() .. '/Xtest1.vim' 862 let file2 = getcwd() .. '/Xtest2.vim' 863 864 " set a breakpoint and source file1.vim 865 let buf = RunVimInTerminal( 866 \ '-c "breakadd file 1 Xtest1.vim" -S Xtest1.vim', 867 \ #{ wait_for_ruler: 0 } ) 868 869 call CheckDbgOutput(buf, [ 870 \ 'Breakpoint in "' .. file1 .. '" line 1', 871 \ 'Entering Debug mode. Type "cont" to continue.', 872 \ 'command line..script ' .. file1, 873 \ 'line 1: let s:file1_var = ''file1''' 874 \ ]) 875 876 " step throught the initial declarations 877 call RunDbgCmd(buf, 'step', [ 'line 2: let g:global_var = ''global''' ] ) 878 call RunDbgCmd(buf, 'step', [ 'line 4: func s:File1Func( arg )' ] ) 879 call RunDbgCmd(buf, 'echo s:file1_var', [ 'file1' ] ) 880 call RunDbgCmd(buf, 'echo g:global_var', [ 'global' ] ) 881 call RunDbgCmd(buf, 'echo global_var', [ 'global' ] ) 882 883 " step in to the first function 884 call RunDbgCmd(buf, 'step', [ 'line 11: call s:File1Func( ''arg1'' )' ] ) 885 call RunDbgCmd(buf, 'step', [ 'line 1: let s:file1_var .= a:arg' ] ) 886 call RunDbgCmd(buf, 'echo a:arg', [ 'arg1' ] ) 887 call RunDbgCmd(buf, 'echo s:file1_var', [ 'file1' ] ) 888 call RunDbgCmd(buf, 'echo g:global_var', [ 'global' ] ) 889 call RunDbgCmd(buf, 890 \'echo global_var', 891 \[ 'E121: Undefined variable: global_var' ] ) 892 call RunDbgCmd(buf, 893 \'echo local_var', 894 \[ 'E121: Undefined variable: local_var' ] ) 895 call RunDbgCmd(buf, 896 \'echo l:local_var', 897 \[ 'E121: Undefined variable: l:local_var' ] ) 898 899 " backtrace up 900 call RunDbgCmd(buf, 'backtrace', [ 901 \ '\V>backtrace', 902 \ '\V 2 command line', 903 \ '\V 1 script ' .. file1 .. '[11]', 904 \ '\V->0 function <SNR>\.\*_File1Func', 905 \ '\Vline 1: let s:file1_var .= a:arg', 906 \ ], 907 \ #{ match: 'pattern' } ) 908 call RunDbgCmd(buf, 'up', [ '>up' ] ) 909 910 call RunDbgCmd(buf, 'backtrace', [ 911 \ '\V>backtrace', 912 \ '\V 2 command line', 913 \ '\V->1 script ' .. file1 .. '[11]', 914 \ '\V 0 function <SNR>\.\*_File1Func', 915 \ '\Vline 1: let s:file1_var .= a:arg', 916 \ ], 917 \ #{ match: 'pattern' } ) 918 919 " Expression evaluation in the script frame (not the function frame) 920 " FIXME: Unexpected in this scope (a: should not be visibnle) 921 call RunDbgCmd(buf, 'echo a:arg', [ 'arg1' ] ) 922 call RunDbgCmd(buf, 'echo s:file1_var', [ 'file1' ] ) 923 call RunDbgCmd(buf, 'echo g:global_var', [ 'global' ] ) 924 " FIXME: Unexpected in this scope (global should be found) 925 call RunDbgCmd(buf, 926 \'echo global_var', 927 \[ 'E121: Undefined variable: global_var' ] ) 928 call RunDbgCmd(buf, 929 \'echo local_var', 930 \[ 'E121: Undefined variable: local_var' ] ) 931 call RunDbgCmd(buf, 932 \'echo l:local_var', 933 \[ 'E121: Undefined variable: l:local_var' ] ) 934 935 936 " step while backtraced jumps to the latest frame 937 call RunDbgCmd(buf, 'step', [ 938 \ 'line 2: let local_var = s:file1_var .. '' test1''' ] ) 939 call RunDbgCmd(buf, 'backtrace', [ 940 \ '\V>backtrace', 941 \ '\V 2 command line', 942 \ '\V 1 script ' .. file1 .. '[11]', 943 \ '\V->0 function <SNR>\.\*_File1Func', 944 \ '\Vline 2: let local_var = s:file1_var .. '' test1''', 945 \ ], 946 \ #{ match: 'pattern' } ) 947 948 call RunDbgCmd(buf, 'step', [ 'line 3: let g:global_var .= local_var' ] ) 949 call RunDbgCmd(buf, 'echo local_var', [ 'file1arg1 test1' ] ) 950 call RunDbgCmd(buf, 'echo l:local_var', [ 'file1arg1 test1' ] ) 951 952 call RunDbgCmd(buf, 'step', [ 'line 4: source Xtest2.vim' ] ) 953 call RunDbgCmd(buf, 'step', [ 'line 1: let s:file2_var = ''file2''' ] ) 954 call RunDbgCmd(buf, 'backtrace', [ 955 \ '\V>backtrace', 956 \ '\V 3 command line', 957 \ '\V 2 script ' .. file1 .. '[11]', 958 \ '\V 1 function <SNR>\.\*_File1Func[4]', 959 \ '\V->0 script ' .. file2, 960 \ '\Vline 1: let s:file2_var = ''file2''', 961 \ ], 962 \ #{ match: 'pattern' } ) 963 964 " Expression evaluation in the script frame file2 (not the function frame) 965 call RunDbgCmd(buf, 'echo a:arg', [ 'E121: Undefined variable: a:arg' ] ) 966 call RunDbgCmd(buf, 967 \ 'echo s:file1_var', 968 \ [ 'E121: Undefined variable: s:file1_var' ] ) 969 call RunDbgCmd(buf, 'echo g:global_var', [ 'globalfile1arg1 test1' ] ) 970 call RunDbgCmd(buf, 'echo global_var', [ 'globalfile1arg1 test1' ] ) 971 call RunDbgCmd(buf, 972 \'echo local_var', 973 \[ 'E121: Undefined variable: local_var' ] ) 974 call RunDbgCmd(buf, 975 \'echo l:local_var', 976 \[ 'E121: Undefined variable: l:local_var' ] ) 977 call RunDbgCmd(buf, 978 \ 'echo s:file2_var', 979 \ [ 'E121: Undefined variable: s:file2_var' ] ) 980 981 call RunDbgCmd(buf, 'step', [ 'line 3: func s:File2Func( arg )' ] ) 982 call RunDbgCmd(buf, 'echo s:file2_var', [ 'file2' ] ) 983 984 " Up the stack to the other script context 985 call RunDbgCmd(buf, 'up') 986 call RunDbgCmd(buf, 'backtrace', [ 987 \ '\V>backtrace', 988 \ '\V 3 command line', 989 \ '\V 2 script ' .. file1 .. '[11]', 990 \ '\V->1 function <SNR>\.\*_File1Func[4]', 991 \ '\V 0 script ' .. file2, 992 \ '\Vline 3: func s:File2Func( arg )', 993 \ ], 994 \ #{ match: 'pattern' } ) 995 " FIXME: Unexpected. Should see the a: and l: dicts from File1Func 996 call RunDbgCmd(buf, 'echo a:arg', [ 'E121: Undefined variable: a:arg' ] ) 997 call RunDbgCmd(buf, 998 \ 'echo l:local_var', 999 \ [ 'E121: Undefined variable: l:local_var' ] ) 1000 1001 call RunDbgCmd(buf, 'up') 1002 call RunDbgCmd(buf, 'backtrace', [ 1003 \ '\V>backtrace', 1004 \ '\V 3 command line', 1005 \ '\V->2 script ' .. file1 .. '[11]', 1006 \ '\V 1 function <SNR>\.\*_File1Func[4]', 1007 \ '\V 0 script ' .. file2, 1008 \ '\Vline 3: func s:File2Func( arg )', 1009 \ ], 1010 \ #{ match: 'pattern' } ) 1011 1012 " FIXME: Unexpected (wrong script vars are used) 1013 call RunDbgCmd(buf, 1014 \ 'echo s:file1_var', 1015 \ [ 'E121: Undefined variable: s:file1_var' ] ) 1016 call RunDbgCmd(buf, 'echo s:file2_var', [ 'file2' ] ) 1017 1018 call StopVimInTerminal(buf) 1019 call delete('Xtest1.vim') 1020 call delete('Xtest2.vim') 1021endfunc 1022