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', ['E161: Breakpoint not found: expr x']) 275 276 " finish the current function 277 call RunDbgCmd(buf, 'finish', [ 278 \ 'function Bazz', 279 \ 'line 8: End of function']) 280 call RunDbgCmd(buf, 'cont') 281 282 " Test for :next 283 call RunDbgCmd(buf, ':debug echo Bar(1)') 284 call RunDbgCmd(buf, 'step') 285 call RunDbgCmd(buf, 'next') 286 call RunDbgCmd(buf, '', [ 287 \ 'function Bar', 288 \ 'line 3: return var2']) 289 call RunDbgCmd(buf, 'c') 290 291 " Test for :interrupt 292 call RunDbgCmd(buf, ':debug echo Bazz(1)') 293 call RunDbgCmd(buf, 'step') 294 call RunDbgCmd(buf, 'step') 295 call RunDbgCmd(buf, 'interrupt', [ 296 \ 'Exception thrown: Vim:Interrupt', 297 \ 'function Bazz', 298 \ 'line 5: catch']) 299 call RunDbgCmd(buf, 'c') 300 301 " Test for :quit 302 call RunDbgCmd(buf, ':debug echo Foo()') 303 call RunDbgCmd(buf, 'breakdel *') 304 call RunDbgCmd(buf, 'breakadd func 3 Foo') 305 call RunDbgCmd(buf, 'breakadd func 3 Bazz') 306 call RunDbgCmd(buf, 'cont', [ 307 \ 'Breakpoint in "Bazz" line 3', 308 \ 'function Foo[2]..Bar[2]..Bazz', 309 \ 'line 3: let var3 = "another var"']) 310 call RunDbgCmd(buf, 'quit', [ 311 \ 'Breakpoint in "Foo" line 3', 312 \ 'function Foo', 313 \ 'line 3: return var2']) 314 call RunDbgCmd(buf, 'breakdel *') 315 call RunDbgCmd(buf, 'quit') 316 call RunDbgCmd(buf, 'enew! | only!') 317 318 call StopVimInTerminal(buf) 319endfunc 320 321func Test_Debugger_breakadd() 322 " Tests for :breakadd file and :breakadd here 323 " Breakpoints should be set before sourcing the file 324 325 let lines =<< trim END 326 let var1 = 10 327 let var2 = 20 328 let var3 = 30 329 let var4 = 40 330 END 331 call writefile(lines, 'Xtest.vim') 332 333 " Start Vim in a terminal 334 let buf = RunVimInTerminal('Xtest.vim', {}) 335 call RunDbgCmd(buf, ':breakadd file 2 Xtest.vim') 336 call RunDbgCmd(buf, ':4 | breakadd here') 337 call RunDbgCmd(buf, ':source Xtest.vim', ['line 2: let var2 = 20']) 338 call RunDbgCmd(buf, 'cont', ['line 4: let var4 = 40']) 339 call RunDbgCmd(buf, 'cont') 340 341 call StopVimInTerminal(buf) 342 343 call delete('Xtest.vim') 344 %bw! 345 346 call assert_fails('breakadd here', 'E32:') 347 call assert_fails('breakadd file Xtest.vim /\)/', 'E55:') 348endfunc 349 350def Test_Debugger_breakadd_expr() 351 var lines =<< trim END 352 vim9script 353 func g:EarlyFunc() 354 endfunc 355 breakadd expr DoesNotExist() 356 func g:LaterFunc() 357 endfunc 358 breakdel * 359 END 360 writefile(lines, 'Xtest.vim') 361 362 # Start Vim in a terminal 363 var buf = RunVimInTerminal('-S Xtest.vim', {wait_for_ruler: 0}) 364 call TermWait(buf) 365 366 # Despite the failure the functions are defined 367 RunDbgCmd(buf, ':function g:EarlyFunc', 368 ['function EarlyFunc()', 'endfunction'], {match: 'pattern'}) 369 RunDbgCmd(buf, ':function g:LaterFunc', 370 ['function LaterFunc()', 'endfunction'], {match: 'pattern'}) 371 372 call StopVimInTerminal(buf) 373 call delete('Xtest.vim') 374enddef 375 376func Test_Backtrace_Through_Source() 377 CheckCWD 378 let file1 =<< trim END 379 func SourceAnotherFile() 380 source Xtest2.vim 381 endfunc 382 383 func CallAFunction() 384 call SourceAnotherFile() 385 call File2Function() 386 endfunc 387 388 func GlobalFunction() 389 call CallAFunction() 390 endfunc 391 END 392 call writefile(file1, 'Xtest1.vim') 393 394 let file2 =<< trim END 395 func DoAThing() 396 echo "DoAThing" 397 endfunc 398 399 func File2Function() 400 call DoAThing() 401 endfunc 402 403 call File2Function() 404 END 405 call writefile(file2, 'Xtest2.vim') 406 407 let buf = RunVimInTerminal('-S Xtest1.vim', {}) 408 409 call RunDbgCmd(buf, 410 \ ':debug call GlobalFunction()', 411 \ ['cmd: call GlobalFunction()']) 412 call RunDbgCmd(buf, 'step', ['line 1: call CallAFunction()']) 413 414 call RunDbgCmd(buf, 'backtrace', ['>backtrace', 415 \ '->0 function GlobalFunction', 416 \ 'line 1: call CallAFunction()']) 417 418 call RunDbgCmd(buf, 'step', ['line 1: call SourceAnotherFile()']) 419 call RunDbgCmd(buf, 'step', ['line 1: source Xtest2.vim']) 420 421 call RunDbgCmd(buf, 'backtrace', ['>backtrace', 422 \ ' 2 function GlobalFunction[1]', 423 \ ' 1 CallAFunction[1]', 424 \ '->0 SourceAnotherFile', 425 \ 'line 1: source Xtest2.vim']) 426 427 " Step into the 'source' command. Note that we print the full trace all the 428 " way though the source command. 429 call RunDbgCmd(buf, 'step', ['line 1: func DoAThing()']) 430 call RunDbgCmd(buf, 'backtrace', [ 431 \ '>backtrace', 432 \ ' 3 function GlobalFunction[1]', 433 \ ' 2 CallAFunction[1]', 434 \ ' 1 SourceAnotherFile[1]', 435 \ '->0 script ' .. getcwd() .. '/Xtest2.vim', 436 \ 'line 1: func DoAThing()']) 437 438 call RunDbgCmd( buf, 'up' ) 439 call RunDbgCmd( buf, 'backtrace', [ 440 \ '>backtrace', 441 \ ' 3 function GlobalFunction[1]', 442 \ ' 2 CallAFunction[1]', 443 \ '->1 SourceAnotherFile[1]', 444 \ ' 0 script ' .. getcwd() .. '/Xtest2.vim', 445 \ 'line 1: func DoAThing()' ] ) 446 447 call RunDbgCmd( buf, 'up' ) 448 call RunDbgCmd( buf, 'backtrace', [ 449 \ '>backtrace', 450 \ ' 3 function GlobalFunction[1]', 451 \ '->2 CallAFunction[1]', 452 \ ' 1 SourceAnotherFile[1]', 453 \ ' 0 script ' .. getcwd() .. '/Xtest2.vim', 454 \ 'line 1: func DoAThing()' ] ) 455 456 call RunDbgCmd( buf, 'up' ) 457 call RunDbgCmd( buf, 'backtrace', [ 458 \ '>backtrace', 459 \ '->3 function GlobalFunction[1]', 460 \ ' 2 CallAFunction[1]', 461 \ ' 1 SourceAnotherFile[1]', 462 \ ' 0 script ' .. getcwd() .. '/Xtest2.vim', 463 \ 'line 1: func DoAThing()' ] ) 464 465 call RunDbgCmd( buf, 'up', [ 'frame at highest level: 3' ] ) 466 call RunDbgCmd( buf, 'backtrace', [ 467 \ '>backtrace', 468 \ '->3 function GlobalFunction[1]', 469 \ ' 2 CallAFunction[1]', 470 \ ' 1 SourceAnotherFile[1]', 471 \ ' 0 script ' .. getcwd() .. '/Xtest2.vim', 472 \ 'line 1: func DoAThing()' ] ) 473 474 call RunDbgCmd( buf, 'down' ) 475 call RunDbgCmd( buf, 'backtrace', [ 476 \ '>backtrace', 477 \ ' 3 function GlobalFunction[1]', 478 \ '->2 CallAFunction[1]', 479 \ ' 1 SourceAnotherFile[1]', 480 \ ' 0 script ' .. getcwd() .. '/Xtest2.vim', 481 \ 'line 1: func DoAThing()' ] ) 482 483 call RunDbgCmd( buf, 'down' ) 484 call RunDbgCmd( buf, 'backtrace', [ 485 \ '>backtrace', 486 \ ' 3 function GlobalFunction[1]', 487 \ ' 2 CallAFunction[1]', 488 \ '->1 SourceAnotherFile[1]', 489 \ ' 0 script ' .. getcwd() .. '/Xtest2.vim', 490 \ 'line 1: func DoAThing()' ] ) 491 492 call RunDbgCmd( buf, 'down' ) 493 call RunDbgCmd( buf, 'backtrace', [ 494 \ '>backtrace', 495 \ ' 3 function GlobalFunction[1]', 496 \ ' 2 CallAFunction[1]', 497 \ ' 1 SourceAnotherFile[1]', 498 \ '->0 script ' .. getcwd() .. '/Xtest2.vim', 499 \ 'line 1: func DoAThing()' ] ) 500 501 call RunDbgCmd( buf, 'down', [ 'frame is zero' ] ) 502 503 " step until we have another meaninfgul trace 504 call RunDbgCmd(buf, 'step', ['line 5: func File2Function()']) 505 call RunDbgCmd(buf, 'step', ['line 9: call File2Function()']) 506 call RunDbgCmd(buf, 'backtrace', [ 507 \ '>backtrace', 508 \ ' 3 function GlobalFunction[1]', 509 \ ' 2 CallAFunction[1]', 510 \ ' 1 SourceAnotherFile[1]', 511 \ '->0 script ' .. getcwd() .. '/Xtest2.vim', 512 \ 'line 9: call File2Function()']) 513 514 call RunDbgCmd(buf, 'step', ['line 1: call DoAThing()']) 515 call RunDbgCmd(buf, 'step', ['line 1: echo "DoAThing"']) 516 call RunDbgCmd(buf, 'backtrace', [ 517 \ '>backtrace', 518 \ ' 5 function GlobalFunction[1]', 519 \ ' 4 CallAFunction[1]', 520 \ ' 3 SourceAnotherFile[1]', 521 \ ' 2 script ' .. getcwd() .. '/Xtest2.vim[9]', 522 \ ' 1 function File2Function[1]', 523 \ '->0 DoAThing', 524 \ 'line 1: echo "DoAThing"']) 525 526 " Now, step (back to Xfile1.vim), and call the function _in_ Xfile2.vim 527 call RunDbgCmd(buf, 'step', ['line 1: End of function']) 528 call RunDbgCmd(buf, 'step', ['line 1: End of function']) 529 call RunDbgCmd(buf, 'step', ['line 10: End of sourced file']) 530 call RunDbgCmd(buf, 'step', ['line 1: End of function']) 531 call RunDbgCmd(buf, 'step', ['line 2: call File2Function()']) 532 call RunDbgCmd(buf, 'backtrace', [ 533 \ '>backtrace', 534 \ ' 1 function GlobalFunction[1]', 535 \ '->0 CallAFunction', 536 \ 'line 2: call File2Function()']) 537 538 call RunDbgCmd(buf, 'step', ['line 1: call DoAThing()']) 539 call RunDbgCmd(buf, 'backtrace', [ 540 \ '>backtrace', 541 \ ' 2 function GlobalFunction[1]', 542 \ ' 1 CallAFunction[2]', 543 \ '->0 File2Function', 544 \ 'line 1: call DoAThing()']) 545 546 call StopVimInTerminal(buf) 547 call delete('Xtest1.vim') 548 call delete('Xtest2.vim') 549endfunc 550 551func Test_Backtrace_Autocmd() 552 CheckCWD 553 let file1 =<< trim END 554 func SourceAnotherFile() 555 source Xtest2.vim 556 endfunc 557 558 func CallAFunction() 559 call SourceAnotherFile() 560 call File2Function() 561 endfunc 562 563 func GlobalFunction() 564 call CallAFunction() 565 endfunc 566 567 au User TestGlobalFunction :call GlobalFunction() | echo "Done" 568 END 569 call writefile(file1, 'Xtest1.vim') 570 571 let file2 =<< trim END 572 func DoAThing() 573 echo "DoAThing" 574 endfunc 575 576 func File2Function() 577 call DoAThing() 578 endfunc 579 580 call File2Function() 581 END 582 call writefile(file2, 'Xtest2.vim') 583 584 let buf = RunVimInTerminal('-S Xtest1.vim', {}) 585 586 call RunDbgCmd(buf, 587 \ ':debug doautocmd User TestGlobalFunction', 588 \ ['cmd: doautocmd User TestGlobalFunction']) 589 call RunDbgCmd(buf, 'step', ['cmd: call GlobalFunction() | echo "Done"']) 590 591 " At this point the ontly thing in the stack is the autocommand 592 call RunDbgCmd(buf, 'backtrace', [ 593 \ '>backtrace', 594 \ '->0 User Autocommands for "TestGlobalFunction"', 595 \ 'cmd: call GlobalFunction() | echo "Done"']) 596 597 " And now we're back into the call stack 598 call RunDbgCmd(buf, 'step', ['line 1: call CallAFunction()']) 599 call RunDbgCmd(buf, 'backtrace', [ 600 \ '>backtrace', 601 \ ' 1 User Autocommands for "TestGlobalFunction"', 602 \ '->0 function GlobalFunction', 603 \ 'line 1: call CallAFunction()']) 604 605 call RunDbgCmd(buf, 'step', ['line 1: call SourceAnotherFile()']) 606 call RunDbgCmd(buf, 'step', ['line 1: source Xtest2.vim']) 607 608 call RunDbgCmd(buf, 'backtrace', [ 609 \ '>backtrace', 610 \ ' 3 User Autocommands for "TestGlobalFunction"', 611 \ ' 2 function GlobalFunction[1]', 612 \ ' 1 CallAFunction[1]', 613 \ '->0 SourceAnotherFile', 614 \ 'line 1: source Xtest2.vim']) 615 616 " Step into the 'source' command. Note that we print the full trace all the 617 " way though the source command. 618 call RunDbgCmd(buf, 'step', ['line 1: func DoAThing()']) 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 628 call RunDbgCmd( buf, 'up' ) 629 call RunDbgCmd( buf, 'backtrace', [ 630 \ '>backtrace', 631 \ ' 4 User Autocommands for "TestGlobalFunction"', 632 \ ' 3 function GlobalFunction[1]', 633 \ ' 2 CallAFunction[1]', 634 \ '->1 SourceAnotherFile[1]', 635 \ ' 0 script ' .. getcwd() .. '/Xtest2.vim', 636 \ 'line 1: func DoAThing()' ] ) 637 638 call RunDbgCmd( buf, 'up' ) 639 call RunDbgCmd( buf, 'backtrace', [ 640 \ '>backtrace', 641 \ ' 4 User Autocommands for "TestGlobalFunction"', 642 \ ' 3 function GlobalFunction[1]', 643 \ '->2 CallAFunction[1]', 644 \ ' 1 SourceAnotherFile[1]', 645 \ ' 0 script ' .. getcwd() .. '/Xtest2.vim', 646 \ 'line 1: func DoAThing()' ] ) 647 648 call RunDbgCmd( buf, 'up' ) 649 call RunDbgCmd( buf, 'backtrace', [ 650 \ '>backtrace', 651 \ ' 4 User Autocommands for "TestGlobalFunction"', 652 \ '->3 function GlobalFunction[1]', 653 \ ' 2 CallAFunction[1]', 654 \ ' 1 SourceAnotherFile[1]', 655 \ ' 0 script ' .. getcwd() .. '/Xtest2.vim', 656 \ 'line 1: func DoAThing()' ] ) 657 658 call RunDbgCmd( buf, 'up' ) 659 call RunDbgCmd( buf, 'backtrace', [ 660 \ '>backtrace', 661 \ '->4 User Autocommands for "TestGlobalFunction"', 662 \ ' 3 function GlobalFunction[1]', 663 \ ' 2 CallAFunction[1]', 664 \ ' 1 SourceAnotherFile[1]', 665 \ ' 0 script ' .. getcwd() .. '/Xtest2.vim', 666 \ 'line 1: func DoAThing()' ] ) 667 668 call RunDbgCmd( buf, 'up', [ 'frame at highest level: 4' ] ) 669 call RunDbgCmd( buf, 'backtrace', [ 670 \ '>backtrace', 671 \ '->4 User Autocommands for "TestGlobalFunction"', 672 \ ' 3 function GlobalFunction[1]', 673 \ ' 2 CallAFunction[1]', 674 \ ' 1 SourceAnotherFile[1]', 675 \ ' 0 script ' .. getcwd() .. '/Xtest2.vim', 676 \ 'line 1: func DoAThing()' ] ) 677 678 call RunDbgCmd( buf, 'down' ) 679 call RunDbgCmd( buf, 'backtrace', [ 680 \ '>backtrace', 681 \ ' 4 User Autocommands for "TestGlobalFunction"', 682 \ '->3 function GlobalFunction[1]', 683 \ ' 2 CallAFunction[1]', 684 \ ' 1 SourceAnotherFile[1]', 685 \ ' 0 script ' .. getcwd() .. '/Xtest2.vim', 686 \ 'line 1: func DoAThing()' ] ) 687 688 689 call RunDbgCmd( buf, 'down' ) 690 call RunDbgCmd( buf, 'backtrace', [ 691 \ '>backtrace', 692 \ ' 4 User Autocommands for "TestGlobalFunction"', 693 \ ' 3 function GlobalFunction[1]', 694 \ '->2 CallAFunction[1]', 695 \ ' 1 SourceAnotherFile[1]', 696 \ ' 0 script ' .. getcwd() .. '/Xtest2.vim', 697 \ 'line 1: func DoAThing()' ] ) 698 699 call RunDbgCmd( buf, 'down' ) 700 call RunDbgCmd( buf, 'backtrace', [ 701 \ '>backtrace', 702 \ ' 4 User Autocommands for "TestGlobalFunction"', 703 \ ' 3 function GlobalFunction[1]', 704 \ ' 2 CallAFunction[1]', 705 \ '->1 SourceAnotherFile[1]', 706 \ ' 0 script ' .. getcwd() .. '/Xtest2.vim', 707 \ 'line 1: func DoAThing()' ] ) 708 709 call RunDbgCmd( buf, 'down' ) 710 call RunDbgCmd( buf, 'backtrace', [ 711 \ '>backtrace', 712 \ ' 4 User Autocommands for "TestGlobalFunction"', 713 \ ' 3 function GlobalFunction[1]', 714 \ ' 2 CallAFunction[1]', 715 \ ' 1 SourceAnotherFile[1]', 716 \ '->0 script ' .. getcwd() .. '/Xtest2.vim', 717 \ 'line 1: func DoAThing()' ] ) 718 719 call RunDbgCmd( buf, 'down', [ 'frame is zero' ] ) 720 721 " step until we have another meaninfgul trace 722 call RunDbgCmd(buf, 'step', ['line 5: func File2Function()']) 723 call RunDbgCmd(buf, 'step', ['line 9: call File2Function()']) 724 call RunDbgCmd(buf, 'backtrace', [ 725 \ '>backtrace', 726 \ ' 4 User Autocommands for "TestGlobalFunction"', 727 \ ' 3 function GlobalFunction[1]', 728 \ ' 2 CallAFunction[1]', 729 \ ' 1 SourceAnotherFile[1]', 730 \ '->0 script ' .. getcwd() .. '/Xtest2.vim', 731 \ 'line 9: call File2Function()']) 732 733 call RunDbgCmd(buf, 'step', ['line 1: call DoAThing()']) 734 call RunDbgCmd(buf, 'step', ['line 1: echo "DoAThing"']) 735 call RunDbgCmd(buf, 'backtrace', [ 736 \ '>backtrace', 737 \ ' 6 User Autocommands for "TestGlobalFunction"', 738 \ ' 5 function GlobalFunction[1]', 739 \ ' 4 CallAFunction[1]', 740 \ ' 3 SourceAnotherFile[1]', 741 \ ' 2 script ' .. getcwd() .. '/Xtest2.vim[9]', 742 \ ' 1 function File2Function[1]', 743 \ '->0 DoAThing', 744 \ 'line 1: echo "DoAThing"']) 745 746 " Now, step (back to Xfile1.vim), and call the function _in_ Xfile2.vim 747 call RunDbgCmd(buf, 'step', ['line 1: End of function']) 748 call RunDbgCmd(buf, 'step', ['line 1: End of function']) 749 call RunDbgCmd(buf, 'step', ['line 10: End of sourced file']) 750 call RunDbgCmd(buf, 'step', ['line 1: End of function']) 751 call RunDbgCmd(buf, 'step', ['line 2: call File2Function()']) 752 call RunDbgCmd(buf, 'backtrace', [ 753 \ '>backtrace', 754 \ ' 2 User Autocommands for "TestGlobalFunction"', 755 \ ' 1 function GlobalFunction[1]', 756 \ '->0 CallAFunction', 757 \ 'line 2: call File2Function()']) 758 759 call RunDbgCmd(buf, 'step', ['line 1: call DoAThing()']) 760 call RunDbgCmd(buf, 'backtrace', [ 761 \ '>backtrace', 762 \ ' 3 User Autocommands for "TestGlobalFunction"', 763 \ ' 2 function GlobalFunction[1]', 764 \ ' 1 CallAFunction[2]', 765 \ '->0 File2Function', 766 \ 'line 1: call DoAThing()']) 767 768 769 " Now unwind so that we get back to the original autocommand (and the second 770 " cmd echo "Done") 771 call RunDbgCmd(buf, 'finish', ['line 1: End of function']) 772 call RunDbgCmd(buf, 'backtrace', [ 773 \ '>backtrace', 774 \ ' 3 User Autocommands for "TestGlobalFunction"', 775 \ ' 2 function GlobalFunction[1]', 776 \ ' 1 CallAFunction[2]', 777 \ '->0 File2Function', 778 \ 'line 1: End of function']) 779 780 call RunDbgCmd(buf, 'finish', ['line 2: End of function']) 781 call RunDbgCmd(buf, 'backtrace', [ 782 \ '>backtrace', 783 \ ' 2 User Autocommands for "TestGlobalFunction"', 784 \ ' 1 function GlobalFunction[1]', 785 \ '->0 CallAFunction', 786 \ 'line 2: End of function']) 787 788 call RunDbgCmd(buf, 'finish', ['line 1: End of function']) 789 call RunDbgCmd(buf, 'backtrace', [ 790 \ '>backtrace', 791 \ ' 1 User Autocommands for "TestGlobalFunction"', 792 \ '->0 function GlobalFunction', 793 \ 'line 1: End of function']) 794 795 call RunDbgCmd(buf, 'step', ['cmd: echo "Done"']) 796 call RunDbgCmd(buf, 'backtrace', [ 797 \ '>backtrace', 798 \ '->0 User Autocommands for "TestGlobalFunction"', 799 \ 'cmd: echo "Done"']) 800 801 call StopVimInTerminal(buf) 802 call delete('Xtest1.vim') 803 call delete('Xtest2.vim') 804endfunc 805 806func Test_Backtrace_CmdLine() 807 CheckCWD 808 let file1 =<< trim END 809 func SourceAnotherFile() 810 source Xtest2.vim 811 endfunc 812 813 func CallAFunction() 814 call SourceAnotherFile() 815 call File2Function() 816 endfunc 817 818 func GlobalFunction() 819 call CallAFunction() 820 endfunc 821 822 au User TestGlobalFunction :call GlobalFunction() | echo "Done" 823 END 824 call writefile(file1, 'Xtest1.vim') 825 826 let file2 =<< trim END 827 func DoAThing() 828 echo "DoAThing" 829 endfunc 830 831 func File2Function() 832 call DoAThing() 833 endfunc 834 835 call File2Function() 836 END 837 call writefile(file2, 'Xtest2.vim') 838 839 let buf = RunVimInTerminal( 840 \ '-S Xtest1.vim -c "debug call GlobalFunction()"', 841 \ {'wait_for_ruler': 0}) 842 843 " Need to wait for the vim-in-terminal to be ready. 844 " With valgrind this can take quite long. 845 call CheckDbgOutput(buf, ['command line', 846 \ 'cmd: call GlobalFunction()'], #{msec: 5000}) 847 848 " At this point the ontly thing in the stack is the cmdline 849 call RunDbgCmd(buf, 'backtrace', [ 850 \ '>backtrace', 851 \ '->0 command line', 852 \ 'cmd: call GlobalFunction()']) 853 854 " And now we're back into the call stack 855 call RunDbgCmd(buf, 'step', ['line 1: call CallAFunction()']) 856 call RunDbgCmd(buf, 'backtrace', [ 857 \ '>backtrace', 858 \ ' 1 command line', 859 \ '->0 function GlobalFunction', 860 \ 'line 1: call CallAFunction()']) 861 862 call StopVimInTerminal(buf) 863 call delete('Xtest1.vim') 864 call delete('Xtest2.vim') 865endfunc 866 867func Test_Backtrace_DefFunction() 868 CheckCWD 869 let file1 =<< trim END 870 vim9script 871 import File2Function from './Xtest2.vim' 872 873 def SourceAnotherFile() 874 source Xtest2.vim 875 enddef 876 877 def CallAFunction() 878 SourceAnotherFile() 879 File2Function() 880 enddef 881 882 def g:GlobalFunction() 883 var some = "some var" 884 CallAFunction() 885 enddef 886 887 defcompile 888 END 889 call writefile(file1, 'Xtest1.vim') 890 891 let file2 =<< trim END 892 vim9script 893 894 def DoAThing(): number 895 var a = 100 * 2 896 a += 3 897 return a 898 enddef 899 900 export def File2Function() 901 DoAThing() 902 enddef 903 904 defcompile 905 File2Function() 906 END 907 call writefile(file2, 'Xtest2.vim') 908 909 let buf = RunVimInTerminal('-S Xtest1.vim', {}) 910 911 call RunDbgCmd(buf, 912 \ ':debug call GlobalFunction()', 913 \ ['cmd: call GlobalFunction()']) 914 915 call RunDbgCmd(buf, 'step', ['line 1: var some = "some var"']) 916 call RunDbgCmd(buf, 'step', ['line 2: CallAFunction()']) 917 call RunDbgCmd(buf, 'echo some', ['some var']) 918 919 call RunDbgCmd(buf, 'backtrace', [ 920 \ '\V>backtrace', 921 \ '\V->0 function GlobalFunction', 922 \ '\Vline 2: CallAFunction()', 923 \ ], 924 \ #{match: 'pattern'}) 925 926 call RunDbgCmd(buf, 'step', ['line 1: SourceAnotherFile()']) 927 call RunDbgCmd(buf, 'step', ['line 1: source Xtest2.vim']) 928 " Repeated line, because we fist are in the compiled function before the 929 " EXEC and then in do_cmdline() before the :source command. 930 call RunDbgCmd(buf, 'step', ['line 1: source Xtest2.vim']) 931 call RunDbgCmd(buf, 'step', ['line 1: vim9script']) 932 call RunDbgCmd(buf, 'step', ['line 3: def DoAThing(): number']) 933 call RunDbgCmd(buf, 'step', ['line 9: export def File2Function()']) 934 call RunDbgCmd(buf, 'step', ['line 9: def File2Function()']) 935 call RunDbgCmd(buf, 'step', ['line 13: defcompile']) 936 call RunDbgCmd(buf, 'step', ['line 14: File2Function()']) 937 call RunDbgCmd(buf, 'backtrace', [ 938 \ '\V>backtrace', 939 \ '\V 3 function GlobalFunction[2]', 940 \ '\V 2 <SNR>\.\*_CallAFunction[1]', 941 \ '\V 1 <SNR>\.\*_SourceAnotherFile[1]', 942 \ '\V->0 script ' .. getcwd() .. '/Xtest2.vim', 943 \ '\Vline 14: File2Function()'], 944 \ #{match: 'pattern'}) 945 946 " Don't step into compiled functions... 947 call RunDbgCmd(buf, 'next', ['line 15: End of sourced file']) 948 call RunDbgCmd(buf, 'backtrace', [ 949 \ '\V>backtrace', 950 \ '\V 3 function GlobalFunction[2]', 951 \ '\V 2 <SNR>\.\*_CallAFunction[1]', 952 \ '\V 1 <SNR>\.\*_SourceAnotherFile[1]', 953 \ '\V->0 script ' .. getcwd() .. '/Xtest2.vim', 954 \ '\Vline 15: End of sourced file'], 955 \ #{match: 'pattern'}) 956 957 call StopVimInTerminal(buf) 958 call delete('Xtest1.vim') 959 call delete('Xtest2.vim') 960endfunc 961 962func Test_DefFunction_expr() 963 CheckCWD 964 let file3 =<< trim END 965 vim9script 966 g:someVar = "foo" 967 def g:ChangeVar() 968 g:someVar = "bar" 969 echo "changed" 970 enddef 971 defcompile 972 END 973 call writefile(file3, 'Xtest3.vim') 974 let buf = RunVimInTerminal('-S Xtest3.vim', {}) 975 976 call RunDbgCmd(buf, ':breakadd expr g:someVar') 977 call RunDbgCmd(buf, ':call g:ChangeVar()', ['Oldval = "''foo''"', 'Newval = "''bar''"', 'function ChangeVar', 'line 2: echo "changed"']) 978 979 call StopVimInTerminal(buf) 980 call delete('Xtest3.vim') 981endfunc 982 983func Test_debug_def_and_legacy_function() 984 CheckCWD 985 let file =<< trim END 986 vim9script 987 def g:SomeFunc() 988 echo "here" 989 echo "and" 990 echo "there" 991 breakadd func 2 LocalFunc 992 LocalFunc() 993 enddef 994 995 def LocalFunc() 996 echo "first" 997 echo "second" 998 breakadd func LegacyFunc 999 LegacyFunc() 1000 enddef 1001 1002 func LegacyFunc() 1003 echo "legone" 1004 echo "legtwo" 1005 endfunc 1006 1007 breakadd func 2 g:SomeFunc 1008 END 1009 call writefile(file, 'XtestDebug.vim') 1010 1011 let buf = RunVimInTerminal('-S XtestDebug.vim', {}) 1012 1013 call RunDbgCmd(buf,':call SomeFunc()', ['line 2: echo "and"']) 1014 call RunDbgCmd(buf,'next', ['line 3: echo "there"']) 1015 call RunDbgCmd(buf,'next', ['line 4: breakadd func 2 LocalFunc']) 1016 1017 " continue, next breakpoint is in LocalFunc() 1018 call RunDbgCmd(buf,'cont', ['line 2: echo "second"']) 1019 1020 " continue, next breakpoint is in LegacyFunc() 1021 call RunDbgCmd(buf,'cont', ['line 1: echo "legone"']) 1022 1023 call RunDbgCmd(buf, 'cont') 1024 1025 call StopVimInTerminal(buf) 1026 call delete('XtestDebug.vim') 1027endfunc 1028 1029func Test_debug_def_function() 1030 CheckCWD 1031 let file =<< trim END 1032 vim9script 1033 def g:Func() 1034 var n: number 1035 def Closure(): number 1036 return n + 3 1037 enddef 1038 n += Closure() 1039 echo 'result: ' .. n 1040 enddef 1041 1042 def g:FuncWithArgs(text: string, nr: number, ...items: list<number>) 1043 echo text .. nr 1044 for it in items 1045 echo it 1046 endfor 1047 echo "done" 1048 enddef 1049 1050 def g:FuncWithDict() 1051 var d = { 1052 a: 1, 1053 b: 2, 1054 } 1055 # comment 1056 def Inner() 1057 eval 1 + 2 1058 enddef 1059 enddef 1060 1061 def g:FuncComment() 1062 # comment 1063 echo "first" 1064 .. "one" 1065 # comment 1066 echo "second" 1067 enddef 1068 1069 def g:FuncForLoop() 1070 eval 1 + 2 1071 for i in [11, 22, 33] 1072 eval i + 2 1073 endfor 1074 echo "done" 1075 enddef 1076 1077 def g:FuncWithSplitLine() 1078 eval 1 + 2 1079 | eval 2 + 3 1080 enddef 1081 END 1082 call writefile(file, 'Xtest.vim') 1083 1084 let buf = RunVimInTerminal('-S Xtest.vim', {}) 1085 1086 call RunDbgCmd(buf, 1087 \ ':debug call Func()', 1088 \ ['cmd: call Func()']) 1089 call RunDbgCmd(buf, 'next', ['result: 3']) 1090 call term_sendkeys(buf, "\r") 1091 call RunDbgCmd(buf, 'cont') 1092 1093 call RunDbgCmd(buf, 1094 \ ':debug call FuncWithArgs("asdf", 42, 1, 2, 3)', 1095 \ ['cmd: call FuncWithArgs("asdf", 42, 1, 2, 3)']) 1096 call RunDbgCmd(buf, 'step', ['line 1: echo text .. nr']) 1097 call RunDbgCmd(buf, 'echo text', ['asdf']) 1098 call RunDbgCmd(buf, 'echo nr', ['42']) 1099 call RunDbgCmd(buf, 'echo items', ['[1, 2, 3]']) 1100 call RunDbgCmd(buf, 'step', ['asdf42', 'function FuncWithArgs', 'line 2: for it in items']) 1101 call RunDbgCmd(buf, 'echo it', ['1']) 1102 call RunDbgCmd(buf, 'step', ['line 3: echo it']) 1103 call RunDbgCmd(buf, 'step', ['1', 'function FuncWithArgs', 'line 4: endfor']) 1104 call RunDbgCmd(buf, 'step', ['line 2: for it in items']) 1105 call RunDbgCmd(buf, 'echo it', ['2']) 1106 call RunDbgCmd(buf, 'step', ['line 3: echo it']) 1107 call RunDbgCmd(buf, 'step', ['2', 'function FuncWithArgs', 'line 4: endfor']) 1108 call RunDbgCmd(buf, 'step', ['line 2: for it in items']) 1109 call RunDbgCmd(buf, 'echo it', ['3']) 1110 call RunDbgCmd(buf, 'step', ['line 3: echo it']) 1111 call RunDbgCmd(buf, 'step', ['3', 'function FuncWithArgs', 'line 4: endfor']) 1112 call RunDbgCmd(buf, 'step', ['line 5: echo "done"']) 1113 call RunDbgCmd(buf, 'cont') 1114 1115 call RunDbgCmd(buf, 1116 \ ':debug call FuncWithDict()', 1117 \ ['cmd: call FuncWithDict()']) 1118 call RunDbgCmd(buf, 'step', ['line 1: var d = { a: 1, b: 2, }']) 1119 call RunDbgCmd(buf, 'step', ['line 6: def Inner()']) 1120 call RunDbgCmd(buf, 'cont') 1121 1122 call RunDbgCmd(buf, ':breakadd func 1 FuncComment') 1123 call RunDbgCmd(buf, ':call FuncComment()', ['function FuncComment', 'line 2: echo "first" .. "one"']) 1124 call RunDbgCmd(buf, ':breakadd func 3 FuncComment') 1125 call RunDbgCmd(buf, 'cont', ['function FuncComment', 'line 5: echo "second"']) 1126 call RunDbgCmd(buf, 'cont') 1127 1128 call RunDbgCmd(buf, ':breakadd func 2 FuncForLoop') 1129 call RunDbgCmd(buf, ':call FuncForLoop()', ['function FuncForLoop', 'line 2: for i in [11, 22, 33]']) 1130 call RunDbgCmd(buf, 'echo i', ['11']) 1131 call RunDbgCmd(buf, 'next', ['function FuncForLoop', 'line 3: eval i + 2']) 1132 call RunDbgCmd(buf, 'next', ['function FuncForLoop', 'line 4: endfor']) 1133 call RunDbgCmd(buf, 'next', ['function FuncForLoop', 'line 2: for i in [11, 22, 33]']) 1134 call RunDbgCmd(buf, 'echo i', ['22']) 1135 1136 call RunDbgCmd(buf, 'breakdel *') 1137 call RunDbgCmd(buf, 'cont') 1138 1139 call RunDbgCmd(buf, ':breakadd func FuncWithSplitLine') 1140 call RunDbgCmd(buf, ':call FuncWithSplitLine()', ['function FuncWithSplitLine', 'line 1: eval 1 + 2 | eval 2 + 3']) 1141 1142 call RunDbgCmd(buf, 'cont') 1143 call StopVimInTerminal(buf) 1144 call delete('Xtest.vim') 1145endfunc 1146 1147func Test_debug_def_function_with_lambda() 1148 CheckCWD 1149 let lines =<< trim END 1150 vim9script 1151 def g:Func() 1152 var s = 'a' 1153 ['b']->map((_, v) => s) 1154 echo "done" 1155 enddef 1156 breakadd func 2 g:Func 1157 END 1158 call writefile(lines, 'XtestLambda.vim') 1159 1160 let buf = RunVimInTerminal('-S XtestLambda.vim', {}) 1161 1162 call RunDbgCmd(buf, 1163 \ ':call g:Func()', 1164 \ ['function Func', 'line 2: [''b'']->map((_, v) => s)']) 1165 call RunDbgCmd(buf, 1166 \ 'next', 1167 \ ['function Func', 'line 3: echo "done"']) 1168 1169 call RunDbgCmd(buf, 'cont') 1170 call StopVimInTerminal(buf) 1171 call delete('XtestLambda.vim') 1172endfunc 1173 1174func Test_debug_backtrace_level() 1175 CheckCWD 1176 let lines =<< trim END 1177 let s:file1_var = 'file1' 1178 let g:global_var = 'global' 1179 1180 func s:File1Func( arg ) 1181 let s:file1_var .= a:arg 1182 let local_var = s:file1_var .. ' test1' 1183 let g:global_var .= local_var 1184 source Xtest2.vim 1185 endfunc 1186 1187 call s:File1Func( 'arg1' ) 1188 END 1189 call writefile(lines, 'Xtest1.vim') 1190 1191 let lines =<< trim END 1192 let s:file2_var = 'file2' 1193 1194 func s:File2Func( arg ) 1195 let s:file2_var .= a:arg 1196 let local_var = s:file2_var .. ' test2' 1197 let g:global_var .= local_var 1198 endfunc 1199 1200 call s:File2Func( 'arg2' ) 1201 END 1202 call writefile(lines, 'Xtest2.vim') 1203 1204 let file1 = getcwd() .. '/Xtest1.vim' 1205 let file2 = getcwd() .. '/Xtest2.vim' 1206 1207 " set a breakpoint and source file1.vim 1208 let buf = RunVimInTerminal( 1209 \ '-c "breakadd file 1 Xtest1.vim" -S Xtest1.vim', 1210 \ #{wait_for_ruler: 0}) 1211 1212 call CheckDbgOutput(buf, [ 1213 \ 'Breakpoint in "' .. file1 .. '" line 1', 1214 \ 'Entering Debug mode. Type "cont" to continue.', 1215 \ 'command line..script ' .. file1, 1216 \ 'line 1: let s:file1_var = ''file1''' 1217 \ ], #{msec: 5000}) 1218 1219 " step through the initial declarations 1220 call RunDbgCmd(buf, 'step', [ 'line 2: let g:global_var = ''global''' ] ) 1221 call RunDbgCmd(buf, 'step', [ 'line 4: func s:File1Func( arg )' ] ) 1222 call RunDbgCmd(buf, 'echo s:file1_var', [ 'file1' ] ) 1223 call RunDbgCmd(buf, 'echo g:global_var', [ 'global' ] ) 1224 call RunDbgCmd(buf, 'echo global_var', [ 'global' ] ) 1225 1226 " step in to the first function 1227 call RunDbgCmd(buf, 'step', [ 'line 11: call s:File1Func( ''arg1'' )' ] ) 1228 call RunDbgCmd(buf, 'step', [ 'line 1: let s:file1_var .= a:arg' ] ) 1229 call RunDbgCmd(buf, 'echo a:arg', [ 'arg1' ] ) 1230 call RunDbgCmd(buf, 'echo s:file1_var', [ 'file1' ] ) 1231 call RunDbgCmd(buf, 'echo g:global_var', [ 'global' ] ) 1232 call RunDbgCmd(buf, 1233 \'echo global_var', 1234 \[ 'E121: Undefined variable: global_var' ] ) 1235 call RunDbgCmd(buf, 1236 \'echo local_var', 1237 \[ 'E121: Undefined variable: local_var' ] ) 1238 call RunDbgCmd(buf, 1239 \'echo l:local_var', 1240 \[ 'E121: Undefined variable: l:local_var' ] ) 1241 1242 " backtrace up 1243 call RunDbgCmd(buf, 'backtrace', [ 1244 \ '\V>backtrace', 1245 \ '\V 2 command line', 1246 \ '\V 1 script ' .. file1 .. '[11]', 1247 \ '\V->0 function <SNR>\.\*_File1Func', 1248 \ '\Vline 1: let s:file1_var .= a:arg', 1249 \ ], 1250 \ #{ match: 'pattern' } ) 1251 call RunDbgCmd(buf, 'up', [ '>up' ] ) 1252 1253 call RunDbgCmd(buf, 'backtrace', [ 1254 \ '\V>backtrace', 1255 \ '\V 2 command line', 1256 \ '\V->1 script ' .. file1 .. '[11]', 1257 \ '\V 0 function <SNR>\.\*_File1Func', 1258 \ '\Vline 1: let s:file1_var .= a:arg', 1259 \ ], 1260 \ #{ match: 'pattern' } ) 1261 1262 " Expression evaluation in the script frame (not the function frame) 1263 " FIXME: Unexpected in this scope (a: should not be visibnle) 1264 call RunDbgCmd(buf, 'echo a:arg', [ 'arg1' ] ) 1265 call RunDbgCmd(buf, 'echo s:file1_var', [ 'file1' ] ) 1266 call RunDbgCmd(buf, 'echo g:global_var', [ 'global' ] ) 1267 " FIXME: Unexpected in this scope (global should be found) 1268 call RunDbgCmd(buf, 1269 \'echo global_var', 1270 \[ 'E121: Undefined variable: global_var' ] ) 1271 call RunDbgCmd(buf, 1272 \'echo local_var', 1273 \[ 'E121: Undefined variable: local_var' ] ) 1274 call RunDbgCmd(buf, 1275 \'echo l:local_var', 1276 \[ 'E121: Undefined variable: l:local_var' ] ) 1277 1278 1279 " step while backtraced jumps to the latest frame 1280 call RunDbgCmd(buf, 'step', [ 1281 \ 'line 2: let local_var = s:file1_var .. '' test1''' ] ) 1282 call RunDbgCmd(buf, 'backtrace', [ 1283 \ '\V>backtrace', 1284 \ '\V 2 command line', 1285 \ '\V 1 script ' .. file1 .. '[11]', 1286 \ '\V->0 function <SNR>\.\*_File1Func', 1287 \ '\Vline 2: let local_var = s:file1_var .. '' test1''', 1288 \ ], 1289 \ #{ match: 'pattern' } ) 1290 1291 call RunDbgCmd(buf, 'step', [ 'line 3: let g:global_var .= local_var' ] ) 1292 call RunDbgCmd(buf, 'echo local_var', [ 'file1arg1 test1' ] ) 1293 call RunDbgCmd(buf, 'echo l:local_var', [ 'file1arg1 test1' ] ) 1294 1295 call RunDbgCmd(buf, 'step', [ 'line 4: source Xtest2.vim' ] ) 1296 call RunDbgCmd(buf, 'step', [ 'line 1: let s:file2_var = ''file2''' ] ) 1297 call RunDbgCmd(buf, 'backtrace', [ 1298 \ '\V>backtrace', 1299 \ '\V 3 command line', 1300 \ '\V 2 script ' .. file1 .. '[11]', 1301 \ '\V 1 function <SNR>\.\*_File1Func[4]', 1302 \ '\V->0 script ' .. file2, 1303 \ '\Vline 1: let s:file2_var = ''file2''', 1304 \ ], 1305 \ #{ match: 'pattern' } ) 1306 1307 " Expression evaluation in the script frame file2 (not the function frame) 1308 call RunDbgCmd(buf, 'echo a:arg', [ 'E121: Undefined variable: a:arg' ] ) 1309 call RunDbgCmd(buf, 1310 \ 'echo s:file1_var', 1311 \ [ 'E121: Undefined variable: s:file1_var' ] ) 1312 call RunDbgCmd(buf, 'echo g:global_var', [ 'globalfile1arg1 test1' ] ) 1313 call RunDbgCmd(buf, 'echo global_var', [ 'globalfile1arg1 test1' ] ) 1314 call RunDbgCmd(buf, 1315 \'echo local_var', 1316 \[ 'E121: Undefined variable: local_var' ] ) 1317 call RunDbgCmd(buf, 1318 \'echo l:local_var', 1319 \[ 'E121: Undefined variable: l:local_var' ] ) 1320 call RunDbgCmd(buf, 1321 \ 'echo s:file2_var', 1322 \ [ 'E121: Undefined variable: s:file2_var' ] ) 1323 1324 call RunDbgCmd(buf, 'step', [ 'line 3: func s:File2Func( arg )' ] ) 1325 call RunDbgCmd(buf, 'echo s:file2_var', [ 'file2' ] ) 1326 1327 " Up the stack to the other script context 1328 call RunDbgCmd(buf, 'up') 1329 call RunDbgCmd(buf, 'backtrace', [ 1330 \ '\V>backtrace', 1331 \ '\V 3 command line', 1332 \ '\V 2 script ' .. file1 .. '[11]', 1333 \ '\V->1 function <SNR>\.\*_File1Func[4]', 1334 \ '\V 0 script ' .. file2, 1335 \ '\Vline 3: func s:File2Func( arg )', 1336 \ ], 1337 \ #{ match: 'pattern' } ) 1338 " FIXME: Unexpected. Should see the a: and l: dicts from File1Func 1339 call RunDbgCmd(buf, 'echo a:arg', [ 'E121: Undefined variable: a:arg' ] ) 1340 call RunDbgCmd(buf, 1341 \ 'echo l:local_var', 1342 \ [ 'E121: Undefined variable: l:local_var' ] ) 1343 1344 call RunDbgCmd(buf, 'up') 1345 call RunDbgCmd(buf, 'backtrace', [ 1346 \ '\V>backtrace', 1347 \ '\V 3 command line', 1348 \ '\V->2 script ' .. file1 .. '[11]', 1349 \ '\V 1 function <SNR>\.\*_File1Func[4]', 1350 \ '\V 0 script ' .. file2, 1351 \ '\Vline 3: func s:File2Func( arg )', 1352 \ ], 1353 \ #{ match: 'pattern' } ) 1354 1355 " FIXME: Unexpected (wrong script vars are used) 1356 call RunDbgCmd(buf, 1357 \ 'echo s:file1_var', 1358 \ [ 'E121: Undefined variable: s:file1_var' ] ) 1359 call RunDbgCmd(buf, 'echo s:file2_var', [ 'file2' ] ) 1360 1361 call RunDbgCmd(buf, 'cont') 1362 call StopVimInTerminal(buf) 1363 call delete('Xtest1.vim') 1364 call delete('Xtest2.vim') 1365endfunc 1366 1367" Test for setting a breakpoint on a :endif where the :if condition is false 1368" and then quit the script. This should generate an interrupt. 1369func Test_breakpt_endif_intr() 1370 func F() 1371 let g:Xpath ..= 'a' 1372 if v:false 1373 let g:Xpath ..= 'b' 1374 endif 1375 invalid_command 1376 endfunc 1377 1378 let g:Xpath = '' 1379 breakadd func 4 F 1380 try 1381 let caught_intr = 0 1382 debuggreedy 1383 call feedkeys(":call F()\<CR>quit\<CR>", "xt") 1384 catch /^Vim:Interrupt$/ 1385 call assert_match('\.F, line 4', v:throwpoint) 1386 let caught_intr = 1 1387 endtry 1388 0debuggreedy 1389 call assert_equal(1, caught_intr) 1390 call assert_equal('a', g:Xpath) 1391 breakdel * 1392 delfunc F 1393endfunc 1394 1395" Test for setting a breakpoint on a :else where the :if condition is false 1396" and then quit the script. This should generate an interrupt. 1397func Test_breakpt_else_intr() 1398 func F() 1399 let g:Xpath ..= 'a' 1400 if v:false 1401 let g:Xpath ..= 'b' 1402 else 1403 invalid_command 1404 endif 1405 invalid_command 1406 endfunc 1407 1408 let g:Xpath = '' 1409 breakadd func 4 F 1410 try 1411 let caught_intr = 0 1412 debuggreedy 1413 call feedkeys(":call F()\<CR>quit\<CR>", "xt") 1414 catch /^Vim:Interrupt$/ 1415 call assert_match('\.F, line 4', v:throwpoint) 1416 let caught_intr = 1 1417 endtry 1418 0debuggreedy 1419 call assert_equal(1, caught_intr) 1420 call assert_equal('a', g:Xpath) 1421 breakdel * 1422 delfunc F 1423endfunc 1424 1425" Test for setting a breakpoint on a :endwhile where the :while condition is 1426" false and then quit the script. This should generate an interrupt. 1427func Test_breakpt_endwhile_intr() 1428 func F() 1429 let g:Xpath ..= 'a' 1430 while v:false 1431 let g:Xpath ..= 'b' 1432 endwhile 1433 invalid_command 1434 endfunc 1435 1436 let g:Xpath = '' 1437 breakadd func 4 F 1438 try 1439 let caught_intr = 0 1440 debuggreedy 1441 call feedkeys(":call F()\<CR>quit\<CR>", "xt") 1442 catch /^Vim:Interrupt$/ 1443 call assert_match('\.F, line 4', v:throwpoint) 1444 let caught_intr = 1 1445 endtry 1446 0debuggreedy 1447 call assert_equal(1, caught_intr) 1448 call assert_equal('a', g:Xpath) 1449 breakdel * 1450 delfunc F 1451endfunc 1452 1453" Test for setting a breakpoint on a script local function 1454func Test_breakpt_scriptlocal_func() 1455 let g:Xpath = '' 1456 func s:G() 1457 let g:Xpath ..= 'a' 1458 endfunc 1459 1460 let funcname = expand("<SID>") .. "G" 1461 exe "breakadd func 1 " .. funcname 1462 debuggreedy 1463 redir => output 1464 call feedkeys(":call " .. funcname .. "()\<CR>c\<CR>", "xt") 1465 redir END 1466 0debuggreedy 1467 call assert_match('Breakpoint in "' .. funcname .. '" line 1', output) 1468 call assert_equal('a', g:Xpath) 1469 breakdel * 1470 exe "delfunc " .. funcname 1471endfunc 1472 1473" vim: shiftwidth=2 sts=2 expandtab 1474