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	      \ '  let var1 = 3 + a:var',
42	      \ '  let var3 = "another var"',
43	      \ '  let var3 = "value2"',
44	      \ '  let var3 = "value3"',
45	      \ '  return var1',
46	      \ 'endfunc'], 'Xtest.vim')
47
48  " Start Vim in a terminal
49  let buf = RunVimInTerminal('-S Xtest.vim', {})
50
51  " Start the Vim debugger
52  call RunDbgCmd(buf, ':debug echo Foo()')
53
54  " Create a few stack frames by stepping through functions
55  call RunDbgCmd(buf, 'step')
56  call RunDbgCmd(buf, 'step')
57  call RunDbgCmd(buf, 'step')
58  call RunDbgCmd(buf, 'step')
59  call RunDbgCmd(buf, 'step')
60  call RunDbgCmd(buf, 'step')
61
62  " check backtrace
63  call RunDbgCmd(buf, 'backtrace', [
64	      \ '  2 function Foo[2]',
65	      \ '  1 Bar[2]',
66	      \ '->0 Bazz',
67	      \ 'line 2: let var3 = "another var"'])
68
69  " Check variables in different stack frames
70  call RunDbgCmd(buf, 'echo var1', ['6'])
71
72  call RunDbgCmd(buf, 'up')
73  call RunDbgCmd(buf, 'back', [
74	      \ '  2 function Foo[2]',
75	      \ '->1 Bar[2]',
76	      \ '  0 Bazz',
77	      \ 'line 2: let var3 = "another var"'])
78  call RunDbgCmd(buf, 'echo var1', ['3'])
79
80  call RunDbgCmd(buf, 'u')
81  call RunDbgCmd(buf, 'bt', [
82	      \ '->2 function Foo[2]',
83	      \ '  1 Bar[2]',
84	      \ '  0 Bazz',
85	      \ 'line 2: let var3 = "another var"'])
86  call RunDbgCmd(buf, 'echo var1', ['1'])
87
88  " Undefined variables
89  call RunDbgCmd(buf, 'step')
90  call RunDbgCmd(buf, 'frame 2')
91  call RunDbgCmd(buf, 'echo var3', [
92	\ 'Error detected while processing function Foo[2]..Bar[2]..Bazz:',
93	\ 'line    3:',
94	\ 'E121: Undefined variable: var3'])
95
96  " var3 is defined in this level with some other value
97  call RunDbgCmd(buf, 'fr 0')
98  call RunDbgCmd(buf, 'echo var3', ['another var'])
99
100  call RunDbgCmd(buf, 'step')
101  call RunDbgCmd(buf, 'step')
102  call RunDbgCmd(buf, 'step')
103  call RunDbgCmd(buf, 'step')
104  call RunDbgCmd(buf, 'step', [
105	      \ 'function Foo[2]..Bar',
106	      \ 'line 3: End of function'])
107  call RunDbgCmd(buf, 'up')
108
109  " Undefined var2
110  call RunDbgCmd(buf, 'echo var2', [
111	      \ 'Error detected while processing function Foo[2]..Bar:',
112	      \ 'line    3:',
113	      \ 'E121: Undefined variable: var2'])
114
115  " Var2 is defined with 10
116  call RunDbgCmd(buf, 'down')
117  call RunDbgCmd(buf, 'echo var2', ['10'])
118
119  " Backtrace movements
120  call RunDbgCmd(buf, 'b', [
121	      \ '  1 function Foo[2]',
122	      \ '->0 Bar',
123	      \ 'line 3: End of function'])
124
125  " next command cannot go down, we are on bottom
126  call RunDbgCmd(buf, 'down', ['frame is zero'])
127  call RunDbgCmd(buf, 'up')
128
129  " next command cannot go up, we are on top
130  call RunDbgCmd(buf, 'up', ['frame at highest level: 1'])
131  call RunDbgCmd(buf, 'where', [
132	      \ '->1 function Foo[2]',
133	      \ '  0 Bar',
134	      \ 'line 3: End of function'])
135
136  " fil is not frame or finish, it is file
137  call RunDbgCmd(buf, 'fil', ['"[No Name]" --No lines in buffer--'])
138
139  " relative backtrace movement
140  call RunDbgCmd(buf, 'fr -1')
141  call RunDbgCmd(buf, 'frame', [
142	      \ '  1 function Foo[2]',
143	      \ '->0 Bar',
144	      \ 'line 3: End of function'])
145
146  call RunDbgCmd(buf, 'fr +1')
147  call RunDbgCmd(buf, 'fram', [
148	      \ '->1 function Foo[2]',
149	      \ '  0 Bar',
150	      \ 'line 3: End of function'])
151
152  " go beyond limits does not crash
153  call RunDbgCmd(buf, 'fr 100', ['frame at highest level: 1'])
154  call RunDbgCmd(buf, 'fra', [
155	      \ '->1 function Foo[2]',
156	      \ '  0 Bar',
157	      \ 'line 3: End of function'])
158
159  call RunDbgCmd(buf, 'frame -40', ['frame is zero'])
160  call RunDbgCmd(buf, 'fram', [
161	      \ '  1 function Foo[2]',
162	      \ '->0 Bar',
163	      \ 'line 3: End of function'])
164
165  " final result 19
166  call RunDbgCmd(buf, 'cont', ['19'])
167
168  " breakpoints tests
169
170  " Start a debug session, so that reading the last line from the terminal
171  " works properly.
172  call RunDbgCmd(buf, ':debug echo Foo()')
173
174  " No breakpoints
175  call RunDbgCmd(buf, 'breakl', ['No breakpoints defined'])
176
177  " Place some breakpoints
178  call RunDbgCmd(buf, 'breaka func Bar')
179  call RunDbgCmd(buf, 'breaklis', ['  1  func Bar  line 1'])
180  call RunDbgCmd(buf, 'breakadd func 3 Bazz')
181  call RunDbgCmd(buf, 'breaklist', ['  1  func Bar  line 1',
182	      \ '  2  func Bazz  line 3'])
183
184  " Check whether the breakpoints are hit
185  call RunDbgCmd(buf, 'cont', [
186	      \ 'Breakpoint in "Bar" line 1',
187	      \ 'function Foo[2]..Bar',
188	      \ 'line 1: let var1 = 2 + a:var'])
189  call RunDbgCmd(buf, 'cont', [
190	      \ 'Breakpoint in "Bazz" line 3',
191	      \ 'function Foo[2]..Bar[2]..Bazz',
192	      \ 'line 3: let var3 = "value2"'])
193
194  " Delete the breakpoints
195  call RunDbgCmd(buf, 'breakd 1')
196  call RunDbgCmd(buf, 'breakli', ['  2  func Bazz  line 3'])
197  call RunDbgCmd(buf, 'breakdel func 3 Bazz')
198  call RunDbgCmd(buf, 'breakl', ['No breakpoints defined'])
199
200  call RunDbgCmd(buf, 'cont')
201
202  " Make sure the breakpoints are removed
203  call RunDbgCmd(buf, ':echo Foo()', ['19'])
204
205  " Delete a non-existing breakpoint
206  call RunDbgCmd(buf, ':breakdel 2', ['E161: Breakpoint not found: 2'])
207
208  " Expression breakpoint
209  call RunDbgCmd(buf, ':breakadd func 2 Bazz')
210  call RunDbgCmd(buf, ':echo Bazz(1)')
211  call RunDbgCmd(buf, 'step')
212  call RunDbgCmd(buf, 'breaka expr var3')
213  call RunDbgCmd(buf, 'breakl', ['  4  expr var3'])
214  call RunDbgCmd(buf, 'cont', ['Breakpoint in "Bazz" line 4',
215	      \ 'Oldval = "''another var''"',
216	      \ 'Newval = "''value2''"',
217	      \ 'function Bazz',
218	      \ 'line 4: let var3 = "value3"'])
219
220  call RunDbgCmd(buf, 'breakdel *')
221  call RunDbgCmd(buf, 'breakl', ['No breakpoints defined'])
222
223  " finish the current function
224  call RunDbgCmd(buf, 'finish', [
225	      \ 'function Bazz',
226	      \ 'line 5: End of function'])
227  call RunDbgCmd(buf, 'cont')
228
229  call StopVimInTerminal(buf)
230
231  call delete('Xtest.vim')
232endfunc
233