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