xref: /netbsd-src/external/gpl3/gdb/dist/gdb/testsuite/gdb.python/py-mi-cmd.exp (revision 901e7e84758515fbf39dfc064cb0b45ab146d8b0)
1# Copyright (C) 2019-2023 Free Software Foundation, Inc.
2# This program is free software; you can redistribute it and/or modify
3# it under the terms of the GNU General Public License as published by
4# the Free Software Foundation; either version 3 of the License, or
5# (at your option) any later version.
6#
7# This program is distributed in the hope that it will be useful,
8# but WITHOUT ANY WARRANTY; without even the implied warranty of
9# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10# GNU General Public License for more details.
11#
12# You should have received a copy of the GNU General Public License
13# along with this program.  If not, see <http://www.gnu.org/licenses/>.
14
15# Test custom MI commands implemented in Python.
16
17load_lib gdb-python.exp
18load_lib mi-support.exp
19set MIFLAGS "-i=mi"
20
21gdb_exit
22if {[mi_gdb_start]} {
23    return
24}
25
26if {[lsearch -exact [mi_get_features] python] < 0} {
27    unsupported "python support is disabled"
28    return -1
29}
30
31standard_testfile
32
33mi_gdb_test "set python print-stack full" \
34    ".*\\^done" \
35    "set python print-stack full"
36
37mi_gdb_test "source ${srcdir}/${subdir}/${testfile}.py" \
38    ".*\\^done" \
39    "load python file"
40
41mi_gdb_test "python pycmd1('-pycmd')" \
42    ".*\\^done" \
43    "define -pycmd MI command"
44
45mi_gdb_test "-pycmd int" \
46    "\\^done,result=\"42\"" \
47    "-pycmd int"
48
49mi_gdb_test "-pycmd str" \
50    "\\^done,result=\"Hello world!\"" \
51    "-pycmd str"
52
53mi_gdb_test "-pycmd ary" \
54    "\\^done,result=\\\[\"Hello\",\"42\"\\\]" \
55    "-pycmd ary"
56
57set re_order1 "\\^done,result={hello=\"world\",times=\"42\"}"
58set re_order2 "\\^done,result={times=\"42\",hello=\"world\"}"
59mi_gdb_test "-pycmd dct" \
60    "($re_order1|$re_order2)" \
61    "-pycmd dct"
62
63mi_gdb_test "-pycmd bk1" \
64    "\\^error,msg=\"Error occurred in Python: non-string object used as key: Bad Key\"" \
65    "-pycmd bk1"
66
67mi_gdb_test "-pycmd bk2" \
68    "\\^error,msg=\"Error occurred in Python: non-string object used as key: 1\"" \
69    "-pycmd bk2"
70
71mi_gdb_test "-pycmd bk3" \
72    [multi_line \
73	 "&\"TypeError: __repr__ returned non-string \\(type BadKey\\)..\"" \
74	 "\\^error,msg=\"Error occurred in Python: __repr__ returned non-string \\(type BadKey\\)\""] \
75    "-pycmd bk3"
76
77mi_gdb_test "-pycmd tpl" \
78    "\\^done,result=\\\[\"42\",\"Hello\"\\\]" \
79    "-pycmd tpl"
80
81mi_gdb_test "-pycmd itr" \
82    "\\^done,result=\\\[\"1\",\"2\",\"3\"\\\]" \
83    "-pycmd itr"
84
85mi_gdb_test "-pycmd nn1" \
86    "\\^done" \
87    "-pycmd nn1"
88
89mi_gdb_test "-pycmd nn2" \
90    "\\^done,result=\\\[\"None\"\\\]" \
91    "-pycmd nn2"
92
93mi_gdb_test "-pycmd bogus" \
94    "\\^error,msg=\"Invalid parameter: bogus\"" \
95    "-pycmd bogus"
96
97# Check that the top-level result from 'invoke' must be a dictionary.
98foreach test_name { nd1 nd2 nd3 } {
99    mi_gdb_test "-pycmd ${test_name}" \
100	"\\^error,msg=\"Error occurred in Python: Result from invoke must be a dictionary\""
101}
102
103# Check for invalid strings in the result.
104foreach test_desc { {ik1 "xxx yyy"} {ik2 "xxx yyy"} {ik3 "xxx\\+yyy"} \
105			{ik4 "xxx\\.yyy"} {ik5 "123xxxyyy"} } {
106    lassign $test_desc name pattern
107
108    mi_gdb_test "-pycmd ${name}" \
109	"\\^error,msg=\"Error occurred in Python: Invalid key in MI result: ${pattern}\""
110}
111
112mi_gdb_test "-pycmd empty_key" \
113    "\\^error,msg=\"Error occurred in Python: Invalid empty key in MI result\""
114
115# Check that a dash ('-') can be used in a key name.
116mi_gdb_test "-pycmd dash-key" \
117    "\\^done,the-key=\"123\""
118
119# With this argument the command raises a gdb.GdbError with no message
120# string.  GDB considers this a bug in the user program, so prints a
121# backtrace, and a generic error message.
122mi_gdb_test "-pycmd exp" \
123    [multi_line ".*&\"Traceback \\(most recent call last\\):..\"" \
124	 "&\"\[^\r\n\]+${testfile}.py\[^\r\n\]+\"" \
125	 "&\"\[^\r\n\]+raise gdb.GdbError\\(\\)..\"" \
126	 "&\"gdb.GdbError..\"" \
127	 "\\^error,msg=\"Error occurred in Python\\.\""] \
128    "-pycmd exp"
129
130mi_gdb_test "python pycmd2('-pycmd')" \
131    ".*\\^done" \
132    "redefine -pycmd MI command from CLI command"
133
134mi_gdb_test "-pycmd str" \
135    "\\^done,result=\"Ciao!\"" \
136    "-pycmd str - redefined from CLI"
137
138mi_gdb_test "-pycmd int" \
139    "\\^error,msg=\"Invalid parameter: int\"" \
140    "-pycmd int - redefined from CLI"
141
142mi_gdb_test "-pycmd new" \
143    "\\^done" \
144    "Define new command -pycmd-new MI command from Python MI command"
145
146mi_gdb_test "-pycmd red" \
147    "\\^error,msg=\"Command redefined but we failing anyway\"" \
148    "redefine -pycmd MI command from Python MI command"
149
150mi_gdb_test "-pycmd int" \
151    "\\^done,result=\"42\"" \
152    "-pycmd int - redefined from MI"
153
154mi_gdb_test "-pycmd-new int" \
155    "\\^done,result=\"42\"" \
156    "-pycmd-new int - defined from MI"
157
158mi_gdb_test "python pycmd1('')" \
159    ".*&\"ValueError: MI command name is empty\\...\".*\\^error,msg=\"Error while executing Python code\\.\"" \
160    "empty MI command name"
161
162mi_gdb_test "python pycmd1('-')" \
163    [multi_line \
164	 ".*" \
165	 "&\"ValueError: MI command name does not start with '-' followed by at least one letter or digit\\...\"" \
166	 "&\"Error while executing Python code\\...\"" \
167	 "\\^error,msg=\"Error while executing Python code\\.\""] \
168    "invalid MI command name"
169
170mi_gdb_test "python pycmd1('-bad-character-@')" \
171    [multi_line \
172	 ".*" \
173	 "&\"ValueError: MI command name contains invalid character: @\\...\"" \
174	 "&\"Error while executing Python code\\...\"" \
175	 "\\^error,msg=\"Error while executing Python code\\.\""] \
176    "invalid character in MI command name"
177
178mi_gdb_test "python cmd=pycmd1('-abc')" \
179    ".*\\^done" \
180    "create command -abc, stored in a python variable"
181
182mi_gdb_test "python print(cmd.name)" \
183    ".*\r\n~\"-abc\\\\n\"\r\n\\^done" \
184    "print the name of the stored mi command"
185
186mi_gdb_test "python print(cmd.installed)" \
187    ".*\r\n~\"True\\\\n\"\r\n\\^done" \
188    "print the installed status of the stored mi command"
189
190mi_gdb_test "-abc str" \
191    "\\^done,result=\"Hello world!\"" \
192    "-abc str"
193
194mi_gdb_test "python cmd.installed = False" \
195    ".*\\^done" \
196    "uninstall the mi command"
197
198mi_gdb_test "-abc str" \
199    "\\^error,msg=\"Undefined MI command: abc\",code=\"undefined-command\"" \
200    "-abc str, but now the command is gone"
201
202mi_gdb_test "python cmd.installed = True" \
203    ".*\\^done" \
204    "re-install the mi command"
205
206mi_gdb_test "-abc str" \
207    "\\^done,result=\"Hello world!\"" \
208    "-abc str, the command is back again"
209
210mi_gdb_test "python other=pycmd2('-abc')" \
211    ".*\\^done" \
212    "create another command called -abc, stored in a separate python variable"
213
214mi_gdb_test "python print(other.installed)" \
215    ".*\r\n~\"True\\\\n\"\r\n\\^done" \
216    "print the installed status of the other stored mi command"
217
218mi_gdb_test "python print(cmd.installed)" \
219    ".*\r\n~\"False\\\\n\"\r\n\\^done" \
220    "print the installed status of the original stored mi command"
221
222mi_gdb_test "-abc str" \
223    "\\^done,result=\"Ciao!\"" \
224    "-abc str, when the other command is in place"
225
226mi_gdb_test "python cmd.installed = True" \
227    ".*\\^done" \
228    "re-install the original mi command"
229
230mi_gdb_test "-abc str" \
231    "\\^done,result=\"Hello world!\"" \
232    "-abc str, the original command is back again"
233
234mi_gdb_test "python print(other.installed)" \
235    ".*\r\n~\"False\\\\n\"\r\n\\^done" \
236    "the other command is now not installed"
237
238mi_gdb_test "python print(cmd.installed)" \
239    ".*\r\n~\"True\\\\n\"\r\n\\^done" \
240    "the original command is now installed"
241
242mi_gdb_test "python aa = pycmd3('-aa', 'message one', 'xxx')" \
243    ".*\\^done" \
244    "created a new -aa command"
245
246mi_gdb_test "-aa" \
247    ".*\\^done,xxx={msg=\"message one\"}" \
248    "call the -aa command"
249
250mi_gdb_test "python aa.__init__('-aa', 'message two', 'yyy')" \
251    ".*\\^done" \
252    "reinitialise -aa command with a new message"
253
254mi_gdb_test "-aa" \
255    ".*\\^done,yyy={msg=\"message two\"}" \
256    "call the -aa command, get the new message"
257
258mi_gdb_test "python aa.__init__('-bb', 'message three', 'zzz')" \
259    [multi_line \
260	 ".*" \
261	 "&\"ValueError: can't reinitialize object with a different command name..\"" \
262	 "&\"Error while executing Python code\\...\"" \
263	 "\\^error,msg=\"Error while executing Python code\\.\""] \
264    "attempt to reinitialise aa variable to a new command name"
265
266mi_gdb_test "-aa" \
267    ".*\\^done,yyy={msg=\"message two\"}" \
268    "check the aa object has not changed after failed initialization"
269
270mi_gdb_test "python aa.installed = False" \
271    ".*\\^done" \
272    "uninstall the -aa command"
273
274mi_gdb_test "python aa.__init__('-bb', 'message three', 'zzz')" \
275    [multi_line \
276	 ".*" \
277	 "&\"ValueError: can't reinitialize object with a different command name..\"" \
278	 "&\"Error while executing Python code\\...\"" \
279	 "\\^error,msg=\"Error while executing Python code\\.\""] \
280    "attempt to reinitialise aa variable to a new command name while uninstalled"
281
282mi_gdb_test "python aa.__init__('-aa', 'message three', 'zzz')" \
283    ".*\\^done" \
284    "reinitialise -aa command with a new message while uninstalled"
285
286mi_gdb_test "python aa.installed = True" \
287    ".*\\^done" \
288    "install the -aa command"
289
290mi_gdb_test "-aa" \
291    ".*\\^done,zzz={msg=\"message three\"}" \
292    "call the -aa command looking for message three"
293
294# Try to register a command object that is missing an invoke method.
295# This is accepted, but will give an error when the user tries to run
296# the command.
297mi_gdb_test "python no_invoke('-no-invoke')" ".*\\^done" \
298    "attempt to register command with no invoke method"
299mi_gdb_test "-no-invoke" \
300    [multi_line \
301	 ".*" \
302	 "&\"AttributeError: 'no_invoke' object has no attribute 'invoke'..\"" \
303	 "\\^error,msg=\"Error occurred in Python: 'no_invoke' object has no attribute 'invoke'\""] \
304    "execute -no-invoke command, which is missing the invoke method"
305
306# Register a command, then delete its invoke method.  What is the user thinking!!
307mi_gdb_test "python setattr(no_invoke, 'invoke', free_invoke)" ".*\\^done"
308mi_gdb_test "python cmd = no_invoke('-hello')" ".*\\^done"
309mi_gdb_test "-hello" ".*\\^done,result=\\\[\\\]" \
310    "execute no_invoke command, while it still has an invoke attribute"
311mi_gdb_test "python delattr(no_invoke, 'invoke')" ".*\\^done"
312mi_gdb_test "-hello" \
313    [multi_line \
314	 ".*" \
315	 "&\"AttributeError: 'no_invoke' object has no attribute 'invoke'..\"" \
316	 "\\^error,msg=\"Error occurred in Python: 'no_invoke' object has no attribute 'invoke'\""] \
317    "execute -hello command, that had its invoke method removed"
318mi_gdb_test "python cmd.invoke = 'string'" ".*\\^done"
319mi_gdb_test "-hello" \
320    [multi_line \
321	 ".*" \
322	 "&\"TypeError: 'str' object is not callable..\"" \
323	 "\\^error,msg=\"Error occurred in Python: 'str' object is not callable\""] \
324    "execute command with invoke set to a string"
325
326# Try to create a new MI command that uses the name of a builtin MI command.
327mi_gdb_test "python cmd = pycmd2('-data-disassemble')" \
328    [multi_line \
329	 ".*" \
330	 "&\"RuntimeError: unable to add command, name is already in use..\"" \
331	 "&\"Error while executing Python code\\...\"" \
332	 "\\^error,msg=\"Error while executing Python code\\.\""] \
333    "try to register a command that replaces -data-disassemble"
334
335
336
337mi_gdb_test "python run_exception_tests()" \
338    [multi_line \
339	 ".*" \
340	 "~\"PASS..\"" \
341	 "\\^done"]
342