1" Tests for the Vim script debug commands 2 3source shared.vim 4source screendump.vim 5source check.vim 6 7" Run a Vim debugger command 8" If the expected output argument is supplied, then check for it. 9func RunDbgCmd(buf, cmd, ...) 10 call term_sendkeys(a:buf, a:cmd . "\r") 11 call term_wait(a:buf, 20) 12 13 if a:0 != 0 14 " Verify the expected output 15 let lnum = 20 - len(a:1) 16 for l in a:1 17 call WaitForAssert({-> assert_equal(l, term_getline(a:buf, lnum))}, 200) 18 let lnum += 1 19 endfor 20 endif 21endfunc 22 23" Debugger tests 24func Test_Debugger() 25 CheckRunVimInTerminal 26 27 " Create a Vim script with some functions 28 let lines =<< trim END 29 func Foo() 30 let var1 = 1 31 let var2 = Bar(var1) + 9 32 return var2 33 endfunc 34 func Bar(var) 35 let var1 = 2 + a:var 36 let var2 = Bazz(var1) + 4 37 return var2 38 endfunc 39 func Bazz(var) 40 try 41 let var1 = 3 + a:var 42 let var3 = "another var" 43 let var3 = "value2" 44 catch 45 let var4 = "exception" 46 endtry 47 return var1 48 endfunc 49 END 50 call writefile(lines, 'Xtest.vim') 51 52 " Start Vim in a terminal 53 let buf = RunVimInTerminal('-S Xtest.vim', {}) 54 55 " Start the Vim debugger 56 call RunDbgCmd(buf, ':debug echo Foo()', ['cmd: echo Foo()']) 57 58 " Create a few stack frames by stepping through functions 59 call RunDbgCmd(buf, 'step', ['line 1: let var1 = 1']) 60 call RunDbgCmd(buf, 'step', ['line 2: let var2 = Bar(var1) + 9']) 61 call RunDbgCmd(buf, 'step', ['line 1: let var1 = 2 + a:var']) 62 call RunDbgCmd(buf, 'step', ['line 2: let var2 = Bazz(var1) + 4']) 63 call RunDbgCmd(buf, 'step', ['line 1: try']) 64 call RunDbgCmd(buf, 'step', ['line 2: let var1 = 3 + a:var']) 65 call RunDbgCmd(buf, 'step', ['line 3: let var3 = "another var"']) 66 67 " check backtrace 68 call RunDbgCmd(buf, 'backtrace', [ 69 \ ' 2 function Foo[2]', 70 \ ' 1 Bar[2]', 71 \ '->0 Bazz', 72 \ 'line 3: let var3 = "another var"']) 73 74 " Check variables in different stack frames 75 call RunDbgCmd(buf, 'echo var1', ['6']) 76 77 call RunDbgCmd(buf, 'up') 78 call RunDbgCmd(buf, 'back', [ 79 \ ' 2 function Foo[2]', 80 \ '->1 Bar[2]', 81 \ ' 0 Bazz', 82 \ 'line 3: let var3 = "another var"']) 83 call RunDbgCmd(buf, 'echo var1', ['3']) 84 85 call RunDbgCmd(buf, 'u') 86 call RunDbgCmd(buf, 'bt', [ 87 \ '->2 function Foo[2]', 88 \ ' 1 Bar[2]', 89 \ ' 0 Bazz', 90 \ 'line 3: let var3 = "another var"']) 91 call RunDbgCmd(buf, 'echo var1', ['1']) 92 93 " Undefined variables 94 call RunDbgCmd(buf, 'step') 95 call RunDbgCmd(buf, 'frame 2') 96 call RunDbgCmd(buf, 'echo var3', [ 97 \ 'Error detected while processing function Foo[2]..Bar[2]..Bazz:', 98 \ 'line 4:', 99 \ 'E121: Undefined variable: var3']) 100 101 " var3 is defined in this level with some other value 102 call RunDbgCmd(buf, 'fr 0') 103 call RunDbgCmd(buf, 'echo var3', ['another var']) 104 105 call RunDbgCmd(buf, 'step') 106 call RunDbgCmd(buf, '') 107 call RunDbgCmd(buf, '') 108 call RunDbgCmd(buf, '') 109 call RunDbgCmd(buf, '') 110 call RunDbgCmd(buf, 'step', [ 111 \ 'function Foo[2]..Bar', 112 \ 'line 3: End of function']) 113 call RunDbgCmd(buf, 'up') 114 115 " Undefined var2 116 call RunDbgCmd(buf, 'echo var2', [ 117 \ 'Error detected while processing function Foo[2]..Bar:', 118 \ 'line 3:', 119 \ 'E121: Undefined variable: var2']) 120 121 " Var2 is defined with 10 122 call RunDbgCmd(buf, 'down') 123 call RunDbgCmd(buf, 'echo var2', ['10']) 124 125 " Backtrace movements 126 call RunDbgCmd(buf, 'b', [ 127 \ ' 1 function Foo[2]', 128 \ '->0 Bar', 129 \ 'line 3: End of function']) 130 131 " next command cannot go down, we are on bottom 132 call RunDbgCmd(buf, 'down', ['frame is zero']) 133 call RunDbgCmd(buf, 'up') 134 135 " next command cannot go up, we are on top 136 call RunDbgCmd(buf, 'up', ['frame at highest level: 1']) 137 call RunDbgCmd(buf, 'where', [ 138 \ '->1 function Foo[2]', 139 \ ' 0 Bar', 140 \ 'line 3: End of function']) 141 142 " fil is not frame or finish, it is file 143 call RunDbgCmd(buf, 'fil', ['"[No Name]" --No lines in buffer--']) 144 145 " relative backtrace movement 146 call RunDbgCmd(buf, 'fr -1') 147 call RunDbgCmd(buf, 'frame', [ 148 \ ' 1 function Foo[2]', 149 \ '->0 Bar', 150 \ 'line 3: End of function']) 151 152 call RunDbgCmd(buf, 'fr +1') 153 call RunDbgCmd(buf, 'fram', [ 154 \ '->1 function Foo[2]', 155 \ ' 0 Bar', 156 \ 'line 3: End of function']) 157 158 " go beyond limits does not crash 159 call RunDbgCmd(buf, 'fr 100', ['frame at highest level: 1']) 160 call RunDbgCmd(buf, 'fra', [ 161 \ '->1 function Foo[2]', 162 \ ' 0 Bar', 163 \ 'line 3: End of function']) 164 165 call RunDbgCmd(buf, 'frame -40', ['frame is zero']) 166 call RunDbgCmd(buf, 'fram', [ 167 \ ' 1 function Foo[2]', 168 \ '->0 Bar', 169 \ 'line 3: End of function']) 170 171 " final result 19 172 call RunDbgCmd(buf, 'cont', ['19']) 173 174 " breakpoints tests 175 176 " Start a debug session, so that reading the last line from the terminal 177 " works properly. 178 call RunDbgCmd(buf, ':debug echo Foo()') 179 180 " No breakpoints 181 call RunDbgCmd(buf, 'breakl', ['No breakpoints defined']) 182 183 " Place some breakpoints 184 call RunDbgCmd(buf, 'breaka func Bar') 185 call RunDbgCmd(buf, 'breaklis', [' 1 func Bar line 1']) 186 call RunDbgCmd(buf, 'breakadd func 3 Bazz') 187 call RunDbgCmd(buf, 'breaklist', [' 1 func Bar line 1', 188 \ ' 2 func Bazz line 3']) 189 190 " Check whether the breakpoints are hit 191 call RunDbgCmd(buf, 'cont', [ 192 \ 'Breakpoint in "Bar" line 1', 193 \ 'function Foo[2]..Bar', 194 \ 'line 1: let var1 = 2 + a:var']) 195 call RunDbgCmd(buf, 'cont', [ 196 \ 'Breakpoint in "Bazz" line 3', 197 \ 'function Foo[2]..Bar[2]..Bazz', 198 \ 'line 3: let var3 = "another var"']) 199 200 " Delete the breakpoints 201 call RunDbgCmd(buf, 'breakd 1') 202 call RunDbgCmd(buf, 'breakli', [' 2 func Bazz line 3']) 203 call RunDbgCmd(buf, 'breakdel func 3 Bazz') 204 call RunDbgCmd(buf, 'breakl', ['No breakpoints defined']) 205 206 call RunDbgCmd(buf, 'cont') 207 208 " Make sure the breakpoints are removed 209 call RunDbgCmd(buf, ':echo Foo()', ['19']) 210 211 " Delete a non-existing breakpoint 212 call RunDbgCmd(buf, ':breakdel 2', ['E161: Breakpoint not found: 2']) 213 214 " Expression breakpoint 215 call RunDbgCmd(buf, ':breakadd func 2 Bazz') 216 call RunDbgCmd(buf, ':echo Bazz(1)', [ 217 \ 'Entering Debug mode. Type "cont" to continue.', 218 \ 'function Bazz', 219 \ 'line 2: let var1 = 3 + a:var']) 220 call RunDbgCmd(buf, 'step') 221 call RunDbgCmd(buf, 'step') 222 call RunDbgCmd(buf, 'breaka expr var3') 223 call RunDbgCmd(buf, 'breakl', [' 3 func Bazz line 2', 224 \ ' 4 expr var3']) 225 call RunDbgCmd(buf, 'cont', ['Breakpoint in "Bazz" line 5', 226 \ 'Oldval = "''another var''"', 227 \ 'Newval = "''value2''"', 228 \ 'function Bazz', 229 \ 'line 5: catch']) 230 231 call RunDbgCmd(buf, 'breakdel *') 232 call RunDbgCmd(buf, 'breakl', ['No breakpoints defined']) 233 234 " Check for error cases 235 call RunDbgCmd(buf, 'breakadd abcd', [ 236 \ 'Error detected while processing function Bazz:', 237 \ 'line 5:', 238 \ 'E475: Invalid argument: abcd']) 239 call RunDbgCmd(buf, 'breakadd func', ['E475: Invalid argument: func']) 240 call RunDbgCmd(buf, 'breakadd func 2', ['E475: Invalid argument: func 2']) 241 call RunDbgCmd(buf, 'breaka func a()', ['E475: Invalid argument: func a()']) 242 call RunDbgCmd(buf, 'breakd abcd', ['E475: Invalid argument: abcd']) 243 call RunDbgCmd(buf, 'breakd func', ['E475: Invalid argument: func']) 244 call RunDbgCmd(buf, 'breakd func a()', ['E475: Invalid argument: func a()']) 245 call RunDbgCmd(buf, 'breakd func a', ['E161: Breakpoint not found: func a']) 246 call RunDbgCmd(buf, 'breakd expr', ['E475: Invalid argument: expr']) 247 call RunDbgCmd(buf, 'breakd expr x', [ 248 \ 'E121: Undefined variable: x', 249 \ 'E161: Breakpoint not found: expr x']) 250 251 " finish the current function 252 call RunDbgCmd(buf, 'finish', [ 253 \ 'function Bazz', 254 \ 'line 8: End of function']) 255 call RunDbgCmd(buf, 'cont') 256 257 " Test for :next 258 call RunDbgCmd(buf, ':debug echo Bar(1)') 259 call RunDbgCmd(buf, 'step') 260 call RunDbgCmd(buf, 'next') 261 call RunDbgCmd(buf, '', [ 262 \ 'function Bar', 263 \ 'line 3: return var2']) 264 call RunDbgCmd(buf, 'c') 265 266 " Test for :interrupt 267 call RunDbgCmd(buf, ':debug echo Bazz(1)') 268 call RunDbgCmd(buf, 'step') 269 call RunDbgCmd(buf, 'step') 270 call RunDbgCmd(buf, 'interrupt', [ 271 \ 'Exception thrown: Vim:Interrupt', 272 \ 'function Bazz', 273 \ 'line 5: catch']) 274 call RunDbgCmd(buf, 'c') 275 276 " Test for :quit 277 call RunDbgCmd(buf, ':debug echo Foo()') 278 call RunDbgCmd(buf, 'breakdel *') 279 call RunDbgCmd(buf, 'breakadd func 3 Foo') 280 call RunDbgCmd(buf, 'breakadd func 3 Bazz') 281 call RunDbgCmd(buf, 'cont', [ 282 \ 'Breakpoint in "Bazz" line 3', 283 \ 'function Foo[2]..Bar[2]..Bazz', 284 \ 'line 3: let var3 = "another var"']) 285 call RunDbgCmd(buf, 'quit', [ 286 \ 'Breakpoint in "Foo" line 3', 287 \ 'function Foo', 288 \ 'line 3: return var2']) 289 call RunDbgCmd(buf, 'breakdel *') 290 call RunDbgCmd(buf, 'quit') 291 call RunDbgCmd(buf, 'enew! | only!') 292 293 call StopVimInTerminal(buf) 294 295 " Tests for :breakadd file and :breakadd here 296 " Breakpoints should be set before sourcing the file 297 298 let lines =<< trim END 299 let var1 = 10 300 let var2 = 20 301 let var3 = 30 302 let var4 = 40 303 END 304 call writefile(lines, 'Xtest.vim') 305 306 " Start Vim in a terminal 307 let buf = RunVimInTerminal('Xtest.vim', {}) 308 call RunDbgCmd(buf, ':breakadd file 2 Xtest.vim') 309 call RunDbgCmd(buf, ':4 | breakadd here') 310 call RunDbgCmd(buf, ':source Xtest.vim', ['line 2: let var2 = 20']) 311 call RunDbgCmd(buf, 'cont', ['line 4: let var4 = 40']) 312 call RunDbgCmd(buf, 'cont') 313 314 call StopVimInTerminal(buf) 315 316 call delete('Xtest.vim') 317endfunc 318