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