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
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
|
# Copyright (C) 2025 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 gdb.Style.
load_lib gdb-python.exp
require allow_python_tests
# Start GDB, allow styling.
with_ansi_styling_terminal {
clean_restart
}
# Check the error for unknown style names.
foreach unknown_style { "unknown-style" "disassembler unknown-style" } {
gdb_test "python filename_style = gdb.Style('$unknown_style')" \
[multi_line \
"Python Exception <class 'RuntimeError'>: style '$unknown_style' cannot be found\\." \
"Error occurred in Python: style '$unknown_style' cannot be found\\."] \
"attempt to create named style for '$unknown_style'"
}
# Check we can create a style using an abbreviated style name.
gdb_test_no_output "python abbrev_style = gdb.Style('high')" \
"create style using abbreviated name 'high'"
gdb_test "python print(abbrev_style)" \
"^<gdb.Style name='highlight', fg=red, bg=none, intensity=normal>" \
"print the 'highlight' style"
gdb_test_no_output "python abbrev_style = gdb.Style('disas mnem')" \
"create style using abbreviated name 'disas mnem'"
gdb_test "python print(abbrev_style)" \
"^<gdb.Style name='disassembler mnemonic', fg=green, bg=none, intensity=normal>" \
"print the 'disassembler mnemonic' style"
# Creating a style using an ambiguous abbreviated name will give an error.
gdb_test "python abbrev_style = gdb.Style('f')" \
[multi_line \
"Python Exception <class 'RuntimeError'>: style 'f' cannot be found\\." \
"Error occurred in Python: style 'f' cannot be found\\."] \
"create style using abbreviated name 'f'"
# Check a couple of different styles can be read. The 'tui-border' is
# interesting as there is no 'intensity' for this one, the gdb.Style
# object will show this as gdb.INTENSITY_NORMAL. The disassembler
# styles are interesting because they are two word style names, and
# the comment style has a foreground and intensity set.
foreach style_check { { "filename" green none NORMAL } \
{ "title" none none BOLD } \
{ "tui-border" cyan none NORMAL } \
{ "disassembler address" blue none NORMAL } \
{ "disassembler comment" white none DIM } } {
set style_name [lindex $style_check 0]
set fg [lindex $style_check 1]
set bg [lindex $style_check 2]
set intensity [lindex $style_check 3]
with_test_prefix "check style $style_name" {
gdb_test_no_output "python style_obj = gdb.Style('$style_name')" \
"create named style for $style_name"
gdb_test "python print(style_obj.foreground)" "^$fg" \
"print foreground color"
gdb_test "python print(style_obj.background)" "^$bg" \
"print background color"
gdb_test "python print(style_obj.intensity == gdb.INTENSITY_$intensity)" \
"^True" "print intensity"
gdb_test "python print(style_obj)" \
"^<gdb.Style name='$style_name', fg=$fg, bg=$bg, intensity=[string tolower $intensity]>" \
"print string representation"
}
}
# Check that the intensity of a named style with no intensity
# (tui-border) cannot be changed.
gdb_test_no_output "python tui_border_style = gdb.Style('tui-border')" \
"create named style for 'tui-border'"
gdb_test "python tui_border_style.intensity = gdb.INTENSITY_BOLD" \
[multi_line \
"Python Exception <class 'ValueError'>: the intensity of style 'tui-border' is not writable\\." \
"Error occurred in Python: the intensity of style 'tui-border' is not writable\\."]
# Change the attributes of a named style, check the settings update as
# expected.
gdb_test_no_output "python filename_style = gdb.Style('filename')" \
"create named style for 'filename'"
gdb_test_no_output "python filename_style.foreground = gdb.Color('blue')" \
"assign blue to filename foreground color"
gdb_test_no_output "python filename_style.background = gdb.Color('red')" \
"assign red to filename background color"
gdb_test_no_output "python filename_style.intensity = gdb.INTENSITY_BOLD"
# Use 'with style enabled off' so that there are no escape sequences
# in the output.
gdb_test "with style enabled off -- show style filename" \
[multi_line \
"style filename background: The \"filename\" style background color is: red" \
"style filename foreground: The \"filename\" style foreground color is: blue" \
"style filename intensity: The \"filename\" style display intensity is: bold"]
gdb_test "python print(filename_style)" \
"^<gdb.Style name='filename', fg=blue, bg=red, intensity=bold>" \
"print string representation of filename_style"
# Check some attempts to set the gdb.Style attributes to invalid types.
foreach attr { foreground background } {
gdb_test "python filename_style.$attr = None" \
[multi_line \
"Python Exception <class 'TypeError'>: value must be gdb.Color, not NoneType" \
"Error occurred in Python: value must be gdb.Color, not NoneType"]
gdb_test "python filename_style.$attr = list()" \
[multi_line \
"Python Exception <class 'TypeError'>: value must be gdb.Color, not list" \
"Error occurred in Python: value must be gdb.Color, not list"]
gdb_test "python filename_style.$attr = 'red'" \
[multi_line \
"Python Exception <class 'TypeError'>: value must be gdb.Color, not str" \
"Error occurred in Python: value must be gdb.Color, not str"]
}
gdb_test "python filename_style.intensity = None" \
[multi_line \
"Python Exception <class 'TypeError'>: value must be a Long \\(a gdb.INTENSITY constant\\), not NoneType" \
"Error occurred in Python: value must be a Long \\(a gdb.INTENSITY constant\\), not NoneType"]
gdb_test "python filename_style.intensity = 'dim'" \
[multi_line \
"Python Exception <class 'TypeError'>: value must be a Long \\(a gdb.INTENSITY constant\\), not str" \
"Error occurred in Python: value must be a Long \\(a gdb.INTENSITY constant\\), not str"]
# Check attempts to set the intensity to an integer value work as
# expected. This is mostly about testing invalid integer values, but
# we do also check that 0, 1, and 2 work as expected, though it is bad
# practice to use the raw integer value rather than the defined
# constants.
set intensity_str { NORMAL BOLD DIM }
for { set i -3 } { $i < 6 } { incr i } {
if { $i < 0 || $i > 2 } {
gdb_test "python filename_style.intensity = $i" \
[multi_line \
"Python Exception <class 'ValueError'>: invalid 'intensity' value $i\\." \
"Error occurred in Python: invalid 'intensity' value $i\\."]
} else {
gdb_test_no_output "python filename_style.intensity = $i"
set str [lindex $intensity_str $i]
gdb_test "python print(filename_style.intensity == gdb.INTENSITY_$str)" \
"^True" "check filename_style intensity is $str"
}
}
# Check the filename style has changed as expected.
gdb_test "python print(filename_style)" \
"^<gdb.Style name='filename', fg=blue, bg=red, intensity=dim>" \
"check filename_style is now dim"
# Check Style.escape_sequence and Style.apply when styling is disabled.
gdb_test_no_output "with style enabled off -- python print(filename_style.escape_sequence(), end='')" \
"print escape sequence when styling is off"
gdb_test "with style enabled off -- python print(filename_style.apply('xxx'))" "^xxx" \
"apply style to a string when styling is off"
# Now check the escape sequences are emitted as expected.
gdb_test "python print(filename_style.escape_sequence())" \
"\033\\\[34;41;2;23;24;27m" \
"print escape sequence when styling is on"
gdb_test "python print(filename_style.apply('xxx'))" \
"\033\\\[34;41;2;23;24;27mxxx\033\\\[m" \
"apply a style when styling is on"
# Test creating a style from component parts.
gdb_test_no_output "python my_style_1 = gdb.Style(gdb.Color('red'), gdb.Color('blue'), gdb.INTENSITY_BOLD)" \
"create my_style_1"
gdb_test "python print(my_style_1)" \
"^<gdb.Style fg=red, bg=blue, intensity=bold>" \
"check my_style_1"
gdb_test_no_output "python my_style_2 = gdb.Style(background = gdb.Color('blue'))" \
"create my_style_2"
gdb_test "python print(my_style_2)" \
"^<gdb.Style fg=none, bg=blue, intensity=normal>" \
"check my_style_2"
gdb_test_no_output "python my_style_3 = gdb.Style(intensity = gdb.INTENSITY_DIM)" \
"create my_style_3"
gdb_test "python print(my_style_3)" \
"^<gdb.Style fg=none, bg=none, intensity=dim>" \
"check my_style_3"
# The precise error message, about 'None' not being an integer, varies
# with Python version. We just check that we get a TypeError and
# assume that this is related to the argument type.
gdb_test "python my_style_4 = gdb.Style(intensity = None)" \
[multi_line \
"Python Exception <class 'TypeError'>: \[^\r\n\]+" \
"Error occurred in Python: \[^\r\n\]+"] \
"attempt to create my_style_4"
gdb_test "python my_style_5 = gdb.Style(foreground = list())" \
[multi_line \
"Python Exception <class 'TypeError'>: 'foreground' argument must be gdb.Color or None, not list\\." \
"Error occurred in Python: 'foreground' argument must be gdb.Color or None, not list\\."] \
"attempt to create my_style_5"
gdb_test "python my_style_6 = gdb.Style(background = list())" \
[multi_line \
"Python Exception <class 'TypeError'>: 'background' argument must be gdb.Color or None, not list\\." \
"Error occurred in Python: 'background' argument must be gdb.Color or None, not list\\."] \
"attempt to create my_style_6"
# Adjust the attributes of an unnamed style.
gdb_test_no_output "python my_style_1.foreground = gdb.Color('green')" \
"change my_style_1.foreground to green"
gdb_test_no_output "python my_style_1.background = gdb.Color('cyan')" \
"change my_style_1.background to cyan"
gdb_test_no_output "python my_style_1.intensity = gdb.INTENSITY_DIM" \
"change my_style_1.intensity to dim"
gdb_test "python print(my_style_1)" \
"^<gdb.Style fg=green, bg=cyan, intensity=dim>" \
"check my_style_1 after changes."
# Setup some prefix commands under 'set/show style ...'. Each prefix
# command is called 'new-style-X' where X is an integer; 1, 2, 3, or 4.
for { set i 1 } { $i < 5 } { incr i } {
gdb_test_no_output "python gdb.Command('set style new-style-$i', gdb.COMMAND_NONE, prefix = True)" \
"create set style new-style-$i"
gdb_test_no_output "python gdb.Command('show style new-style-$i', gdb.COMMAND_NONE, prefix = True)" \
"create show style new-style-$i"
}
# A helper class for creating color settings under the 'new-style-X'
# prefix commands. The NUM to the __init__ supplies the value of
# 'X', and NAME is either 'foreground' or 'background'.
gdb_test_multiline "Class to create color parameters" \
"python" "" \
"class color_param(gdb.Parameter):" "" \
" def __init__(self, num, name):" "" \
" super().__init__(f\"style new-style-{num} {name}\", gdb.COMMAND_NONE, gdb.PARAM_COLOR)" "" \
" self.value = gdb.Color()" "" \
"end" ""
# A helper class for creating intensity settings under the new
# 'new-style-X' prefix commands. The NUM in the __init__ supplies the
# value of 'X'.
gdb_test_multiline "Class to create intensity parameters" \
"python" "" \
"class intensity_param(gdb.Parameter):" "" \
" def __init__(self, num):" "" \
" super().__init__(f\"style new-style-{num} intensity\", gdb.COMMAND_NONE, gdb.PARAM_ENUM," "" \
" \[\"normal\", \"bold\", \"dim\"\])" "" \
" self.value = \"normal\"" "" \
"end" ""
# Within 'style new-style-1' we only have a 'foreground' setting.
# This will not be usable as a gdb.Style.
gdb_test_no_output "python color_param(1, 'foreground')" \
"setup new-style-1 foreground"
# Within 'style new-style-2' we only have a 'background' setting.
# This will not be usable as a gdb.Style.
gdb_test_no_output "python color_param(2, 'background')" \
"setup new-style-2 background"
# Within 'style new-style-3' we have both a 'foreground' and
# 'background' setting. Even though 'intensity' is missing, this is
# still usable as a style.
gdb_test_no_output "python color_param(3, 'foreground')" \
"setup new-style-3 foreground"
gdb_test_no_output "python color_param(3, 'background')" \
"setup new-style-3 background"
# Within 'style new-style-4' we have a 'foreground', 'background', and
# 'intensity' setting. This is a complete style setting group.
gdb_test_no_output "python color_param(4, 'foreground')" \
"setup new-style-4 foreground"
gdb_test_no_output "python color_param(4, 'background')" \
"setup new-style-4 background"
gdb_test_no_output "python intensity_param(4)" \
"setup new-style-4 intensity"
# Trying to create a style for 'new-style-1' should fail.
gdb_test "python my_style_7 = gdb.Style('new-style-1')" \
[multi_line \
"Python Exception <class 'RuntimeError'>: style 'new-style-1' missing 'background' component\\." \
"Error occurred in Python: style 'new-style-1' missing 'background' component\\."] \
"try to create style for new-style-1"
# Trying to create a style for 'new-style-2' should fail.
gdb_test "python my_style_8 = gdb.Style('new-style-2')" \
[multi_line \
"Python Exception <class 'RuntimeError'>: style 'new-style-2' missing 'foreground' component\\." \
"Error occurred in Python: style 'new-style-2' missing 'foreground' component\\."] \
"try to create style for new-style-2"
# Trying to create a style for 'new-style-3' should succeed.
gdb_test_no_output "python my_style_9 = gdb.Style('new-style-3')" \
"create a style for new-style-3"
gdb_test "python print(my_style_9)" \
"^<gdb.Style name='new-style-3', fg=none, bg=none, intensity=normal>" \
"print my_style_9"
# Trying to create a style for 'new-style-4' should succeed too.
gdb_test_no_output "python my_style_10 = gdb.Style('new-style-4')" \
"create a style for new-style-4"
gdb_test "python print(my_style_10)" \
"^<gdb.Style name='new-style-4', fg=none, bg=none, intensity=normal>" \
"print my_style_10"
# Adjust the settings directly, and check the gdb.Style updates.
gdb_test_no_output "set style new-style-4 intensity bold"
gdb_test_no_output "set style new-style-4 foreground red"
gdb_test_no_output "set style new-style-4 background blue"
gdb_test "python print(my_style_10)" \
"^<gdb.Style name='new-style-4', fg=red, bg=blue, intensity=bold>" \
"print my_style_10, intensity updated"
# Check the reference counting on 'gdb.Style.apply' when global styling is disabled.
gdb_test_no_output "python input_text = \"this is a unique string that is unlikely to appear elsewhere 12345\"" \
"setup an input string"
gdb_test_no_output "with style enabled off -- python output_text = filename_style.apply(input_text)" \
"create an ouput string by applying filename_style"
gdb_test_no_output "python input_text = \"a totally different string that is also, hopefully, unique\"" \
"replace the input string"
gdb_test "python print(output_text)" \
"^this is a unique string that is unlikely to appear elsewhere 12345" \
"check the output_text is still valid"
# Test gdb.write passing in a style. Define a helper function to
# ensure all output is flushed before we return to the prompt.
gdb_test_multiline "create function to call gdb.write then flush" \
"python" "" \
"def write_and_flush(*args, **kwargs):" "" \
" gdb.write(*args, **kwargs)" "" \
" gdb.write(\"\\n\")" "" \
" gdb.flush(gdb.STDOUT)" "" \
"end" ""
gdb_test "python write_and_flush(\"some text\")" \
"^some text" "unstyled text, no style passed"
gdb_test "python write_and_flush(\"some text\", style=None)" \
"^some text" "unstyled text, pass style as None"
gdb_test "python write_and_flush(\"some text\", style=filename_style)" \
"^\033\\\[34;41;2;23;24;27msome text\033\\\[m" \
"styled output, pass style by keyword"
gdb_test "python write_and_flush(\"some text\", gdb.STDOUT, filename_style)" \
"^\033\\\[34;41;2;23;24;27msome text\033\\\[m" \
"styled output, pass style by position"
gdb_test "python write_and_flush(\"some text\", style='filename')" \
[multi_line \
"Python Exception <class 'TypeError'>: 'style' argument must be gdb\\.Style or None, not str\\." \
"Error occurred in Python: 'style' argument must be gdb\\.Style or None, not str\\."]
|