summaryrefslogtreecommitdiff
path: root/gdb/testsuite/gdb.python/py-cmd.exp
blob: 43a96a754193236259a6c0aafc62d6bcbb458575 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
# Copyright (C) 2009-2021 Free Software Foundation, Inc.

# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

# This file is part of the GDB testsuite.  It tests the mechanism
# for defining new GDB commands in Python.

load_lib gdb-python.exp

standard_testfile

if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile}] } {
    return -1
}

# Skip all tests if Python scripting is not enabled.
if { [skip_python_tests] } { continue }

if ![runto_main] then {
    return 0
}

# Test a simple command.

gdb_test_multiline "input simple command" \
  "python" "" \
  "class test_cmd (gdb.Command):" "" \
  "  def __init__ (self):" "" \
  "    super (test_cmd, self).__init__ (\"test_cmd\", gdb.COMMAND_OBSCURE)" "" \
  "  def invoke (self, arg, from_tty):" "" \
  "    print (\"test_cmd output, arg = %s\" % arg)" "" \
  "test_cmd ()" "" \
  "end" ""

gdb_test "test_cmd ugh" "test_cmd output, arg = ugh" "call simple command"

# Test a prefix command, and a subcommand within it.

gdb_test_multiline "input prefix command" \
  "python" "" \
  "class prefix_cmd (gdb.Command):" "" \
  "  def __init__ (self):" "" \
  "    super (prefix_cmd, self).__init__ (\"prefix_cmd\", gdb.COMMAND_OBSCURE, gdb.COMPLETE_NONE, True)" "" \
  "  def invoke (self, arg, from_tty):" "" \
  "    print (\"prefix_cmd output, arg = %s\" % arg)" "" \
  "prefix_cmd ()" "" \
  "end" ""

gdb_test "prefix_cmd ugh" "prefix_cmd output, arg = ugh" "call prefix command"

gdb_test_multiline "input subcommand" \
  "python" "" \
  "class subcmd (gdb.Command):" "" \
  "  def __init__ (self):" "" \
  "    super (subcmd, self).__init__ (\"prefix_cmd subcmd\", gdb.COMMAND_OBSCURE)" "" \
  "  def invoke (self, arg, from_tty):" "" \
  "    print (\"subcmd output, arg = %s\" % arg)" "" \
  "subcmd ()" "" \
  "end" ""

gdb_test "prefix_cmd subcmd ugh" "subcmd output, arg = ugh" "call subcmd"

# Test prefix command using keyword arguments.

gdb_test_multiline "input prefix command, keyword arguments" \
  "python" "" \
  "class prefix_cmd2 (gdb.Command):" "" \
  "  def __init__ (self):" "" \
  "    super (prefix_cmd2, self).__init__ (\"prefix_cmd2\", gdb.COMMAND_OBSCURE, prefix = True, completer_class = gdb.COMPLETE_FILENAME)" "" \
  "  def invoke (self, arg, from_tty):" "" \
  "    print (\"prefix_cmd2 output, arg = %s\" % arg)" "" \
  "prefix_cmd2 ()" "" \
  "end" ""

gdb_test "prefix_cmd2 argh" "prefix_cmd2 output, arg = argh" "call prefix command, keyword arguments"

gdb_test_multiline "input subcommand under prefix_cmd2" \
  "python" "" \
  "class subcmd (gdb.Command):" "" \
  "  def __init__ (self):" "" \
  "    super (subcmd, self).__init__ (\"prefix_cmd2 subcmd\", gdb.COMMAND_OBSCURE)" "" \
  "  def invoke (self, arg, from_tty):" "" \
  "    print (\"subcmd output, arg = %s\" % arg)" "" \
  "subcmd ()" "" \
  "end" ""

gdb_test "prefix_cmd2 subcmd ugh" "subcmd output, arg = ugh" "call subcmd under prefix_cmd2"

# Test a subcommand in an existing GDB prefix.

gdb_test_multiline "input new subcommand" \
  "python" "" \
  "class newsubcmd (gdb.Command):" "" \
  "  def __init__ (self):" "" \
  "    super (newsubcmd, self).__init__ (\"info newsubcmd\", gdb.COMMAND_OBSCURE)" "" \
  "  def invoke (self, arg, from_tty):" "" \
  "    print (\"newsubcmd output, arg = %s\" % arg)" "" \
  "newsubcmd ()" "" \
  "end" ""

gdb_test "info newsubcmd ugh" "newsubcmd output, arg = ugh" "call newsubcmd"

# Test a command that throws gdb.GdbError.

gdb_test_multiline "input command to throw error" \
  "python" "" \
  "class test_error_cmd (gdb.Command):" "" \
  "  def __init__ (self):" "" \
  "    super (test_error_cmd, self).__init__ (\"test_error_cmd\", gdb.COMMAND_OBSCURE)" "" \
  "  def invoke (self, arg, from_tty):" "" \
  "    raise gdb.GdbError ('you lose!')" "" \
  "test_error_cmd ()" "" \
  "end" ""

gdb_test "test_error_cmd ugh" "you lose!" "call error command"

# Test gdb.string_to_argv.

gdb_test "python print (gdb.string_to_argv (\"1 2 3\"))" \
  {\['1', '2', '3'\]} \
  "string_to_argv (\"1 2 3\")"

gdb_test "python print (gdb.string_to_argv (\"'1 2' 3\"))" \
  {\['1 2', '3'\]} \
  "string_to_argv (\"'1 2' 3\")"

gdb_test "python print (gdb.string_to_argv ('\"1 2\" 3'))" \
  {\['1 2', '3'\]} \
  "string_to_argv ('\"1 2\" 3')"

gdb_test "python print (gdb.string_to_argv ('1\\ 2 3'))" \
  {\['1 2', '3'\]} \
    "string_to_argv ('1\\ 2 3')"

# Test user-defined python commands.
gdb_test_multiline "input simple user-defined command" \
  "python" "" \
  "class test_help (gdb.Command):" "" \
  "  \"\"\"Docstring\"\"\"" "" \
  "  def __init__ (self):" "" \
  "    super (test_help, self).__init__ (\"test_help\", gdb.COMMAND_USER)" "" \
  "  def invoke (self, arg, from_tty):" "" \
  "    print (\"test_cmd output, arg = %s\" % arg)" "" \
  "test_help ()" "" \
  "end" ""

gdb_test "test_help ugh" "test_cmd output, arg = ugh" "call simple user-defined command"

# Make sure the command shows up in `help user-defined`.
test_user_defined_class_help {"test_help -- Docstring[\r\n]"}

# Make sure the command does not show up in `show user`.
gdb_test "show user test_help" "Not a user command\." \
    "don't show user-defined python command in `show user command`"

# Test expression completion on fields
gdb_test_multiline "expression completion command" \
  "python" "" \
  "class expr_test (gdb.Command):" "" \
  "  def __init__ (self):" "" \
  "    super (expr_test, self).__init__ (\"expr_test\", gdb.COMMAND_USER, gdb.COMPLETE_EXPRESSION)" "" \
  "  def invoke (self, arg, from_tty):" "" \
  "    print (\"invoked on = %s\" % arg)" "" \
  "expr_test ()" "" \
  "end" ""


gdb_test "complete expr_test bar\." \
    "expr_test bar\.bc.*expr_test bar\.ij.*" \
    "test completion through complete command"

# Test that the "python" command is correctly recognized as
# inline/multi-line when entering a sequence of commands.
#
# This proc tests PR cli/21688.  The PR is not language-specific, but
# the easiest way is just to test with Python.
proc test_python_inline_or_multiline { } {
    global gdb_prompt
    set end "\r\n$gdb_prompt $"

    set define_cmd_not_inline [ list \
	[ list "if 1"                 " >$"            "multi-line if 1" ] \
	[ list "python"               " >$"            "multi-line python command" ] \
	[ list "print ('hello')"      "  >$"           "multi-line print" ] \
	[ list "end"                  " >$"            "multi-line first end" ] \
	[ list "end"                  "hello$end"      "multi-line last end" ] ]

    # This also tests trailing whitespace on the command.
    set define_cmd_alias_not_inline [ list \
	[ list "if 1"                 " >$"            "multi-line if 1 alias" ] \
	[ list "py    "               " >$"            "multi-line python command alias" ] \
	[ list "print ('hello')"      "  >$"           "multi-line print alias" ] \
	[ list "end"                  " >$"            "multi-line first end alias" ] \
	[ list "end"                  "hello$end"      "multi-line last end alias" ] ]

    set define_cmd_alias_foo_not_inline [ list \
	[ list "alias foo=python"     "$end"           "multi-line alias foo" ] \
	[ list "if 1"                 " >$"            "multi-line if 1 alias foo" ] \
	[ list "foo    "              " >$"            "multi-line python command alias foo" ] \
	[ list "print ('hello')"      "  >$"           "multi-line print alias foo" ] \
	[ list "end"                  " >$"            "multi-line first end alias foo" ] \
	[ list "end"                  "hello$end"      "multi-line last end alias foo" ] ]

    set define_cmd_inline [ list \
	[ list "if 1"                      " >$"          "inline if 1" ] \
	[ list "python print ('hello')"    " >$"          "inline python command" ] \
	[ list "end"                       "hello$end"    "inline end" ] ]

    set define_cmd_alias_inline [ list \
	[ list "if 1"                      " >$"          "inline if 1 alias" ] \
	[ list "py print ('hello')"        " >$"          "inline python command alias" ] \
	[ list "end"                       "hello$end"    "inline end alias" ] ]

    set define_cmd_alias_foo_inline [ list \
	[ list "if 1"                      " >$"          "inline if 1 alias foo" ] \
	[ list "foo print ('hello')"       " >$"          "inline python command alias foo" ] \
	[ list "end"                       "hello$end"    "inline end alias foo" ] ]

    foreach t [list $define_cmd_not_inline \
	       $define_cmd_alias_not_inline \
	       $define_cmd_alias_foo_not_inline \
	       $define_cmd_inline \
	       $define_cmd_alias_inline \
	       $define_cmd_alias_foo_inline] {
	foreach l $t {
	    lassign $l command regex testmsg
	    gdb_test_multiple "$command" "$testmsg" {
		-re "$regex" {
		    pass "$testmsg"
		}
	    }
	}
    }
}

test_python_inline_or_multiline

if { [readline_is_used] } {
    set test "complete 'expr_test bar.i'"
    send_gdb "expr_test bar\.i\t\t"
    gdb_test_multiple "" "$test" {
	-re "expr_test bar\.ij \\\x07$" {
	    send_gdb "\n"
	    gdb_test_multiple "" $test {
		-re "invoked on = bar.ij.*$gdb_prompt $" {
		    pass "$test"
		}
	    }
	}
    }
}


# Test that interrupting pagination throws a gdb quit.
gdb_test_no_output "set height 10"

gdb_test_multiline "input multi-line-output command" \
  "python" "" \
  "class test_mline (gdb.Command):" "" \
  "  \"\"\"Docstring\"\"\"" "" \
  "  def __init__ (self):" "" \
  "    super (test_mline, self).__init__ (\"test_multiline\", gdb.COMMAND_USER)" "" \
  "  def invoke (self, arg, from_tty):" "" \
  "    for f in range(20):" "" \
  "      print (\"test_multiline output\")" "" \
  "test_mline ()" "" \
  "end" ""

set test "verify pagination from test_multiline"
gdb_test_multiple "test_multiline" $test {
    -re "--Type <RET>" {
	exp_continue
    }
    -re " for more, q to quit" {
	exp_continue
    }
    -re ", c to continue without paging--$" {
	pass $test
    }
}

send_gdb "q\n"
set test "verify pagination from test_multiline: q"
gdb_test_multiple "test_multiline" $test {
    -re "Error occurred in Python" {
	fail $test
    }
    -re "Quit" {
	pass $test
    }
}