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