blob: eb09fe7e85da428f98189fe2f5e86fcda0462828 [file] [log] [blame]
# 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.ParameterPrefix. See each of the test procs for a full
# description of what is being tested.
load_lib gdb-python.exp
require allow_python_tests
clean_restart
# Helper proc to generate the output of 'show PREFIX' commands for the
# case where the prefix command doesn't handle unknown sub-commands.
# In this case GDB will list the value of every sub-command under
# PREFIX.
proc make_show_prefix_re { prefix } {
return "$prefix param-1:\\s+The current value of '$prefix param-1' is \"off\"\\."
}
# Helper proc to generate the help text that describes all of the sub
# commands under PREFIX. The MODE is either 'set' or 'show'. This
# output will appear for 'help MODE PREFIX' and also for 'set PREFIX'.
proc make_sub_cmd_help_re { mode prefix } {
if { $mode == "set" } {
set word "Set"
} else {
set word "Show"
}
return \
[multi_line \
"List of \"$mode $prefix\" subcommands:" \
"" \
"$mode $prefix param-1 -- $word the current value of '$prefix param-1'\\." \
"" \
"Type \"help $mode $prefix\" followed by subcommand name for full documentation\\." \
"Type \"apropos word\" to search for commands related to \"word\"\\." \
"Type \"apropos -v word\" for full documentation of commands related to \"word\"\\." \
"Command name abbreviations are allowed if unambiguous\\."]
}
# Helper proc to generate the output of 'help MODE PREFIX', where MODE
# will be either 'set' or 'show'. The HELP_TEXT is the expected help
# text for this prefix command, this should not be a regexp, as this
# proc converts the text to a regexp.
#
# Return a single regexp which should match the output.
proc make_help_re { mode prefix help_text } {
set help_re [string_to_regexp $help_text]
return \
[multi_line \
"$help_re" \
"" \
[make_sub_cmd_help_re $mode $prefix]]
}
# Create gdb.ParameterPrefix without using a sub-class, both with, and
# without a doc string. For the doc string case, test single line,
# and multi-line doc strings.
proc_with_prefix test_basic_usage {} {
gdb_test_multiline "some basic ParameterPrefix usage" \
"python" "" \
"gdb.ParameterPrefix('prefix-1', gdb.COMMAND_NONE)" "" \
"gdb.Parameter('prefix-1 param-1', gdb.COMMAND_NONE, gdb.PARAM_BOOLEAN)" "" \
"gdb.Parameter('prefix-1 param-1', gdb.COMMAND_NONE, gdb.PARAM_BOOLEAN)" "" \
"gdb.ParameterPrefix('prefix-2', gdb.COMMAND_NONE," "" \
" \"\"\"This is prefix-2 help string.\"\"\")" "" \
"gdb.Parameter('prefix-2 param-1', gdb.COMMAND_NONE, gdb.PARAM_BOOLEAN)" "" \
"gdb.ParameterPrefix('prefix-3', gdb.COMMAND_NONE," "" \
" \"\"\"This is prefix-3 help string." "" \
" " "" \
" This help text spans multiple lines.\"\"\")" "" \
"gdb.Parameter('prefix-3 param-1', gdb.COMMAND_NONE, gdb.PARAM_BOOLEAN)" "" \
"end"
foreach mode { "set" "show" } {
gdb_test "help $mode prefix-1" \
[make_help_re $mode "prefix-1" \
"This command is not documented."]
gdb_test "help $mode prefix-2" \
[make_help_re $mode "prefix-2" \
"This is prefix-2 help string."]
gdb_test "help $mode prefix-3" \
[make_help_re $mode "prefix-3" \
[multi_line \
"This is prefix-3 help string." \
"" \
"This help text spans multiple lines."]]
foreach prefix { prefix-1 prefix-2 prefix-3 } {
gdb_test "$mode $prefix xxx" \
"^Undefined $mode $prefix command: \"xxx\"\\. Try \"help $mode $prefix\"\\."
}
}
foreach prefix { prefix-1 prefix-2 prefix-3 } {
gdb_test "set $prefix" \
[make_sub_cmd_help_re "set" $prefix]
gdb_test "show $prefix" \
[make_show_prefix_re $prefix]
}
}
# Create a sub-class of gdb.ParameterPrefix, but don't do anything
# particularly interesting. Again test the with and without
# documentation string cases.
proc_with_prefix test_simple_sub_class {} {
gdb_test_multiline "some basic ParameterPrefix usage" \
"python" "" \
"class BasicParamPrefix(gdb.ParameterPrefix):" "" \
" def __init__(self, name):" "" \
" super().__init__(name, gdb.COMMAND_NONE)" "" \
"BasicParamPrefix('prefix-4')" "" \
"gdb.Parameter('prefix-4 param-1', gdb.COMMAND_NONE, gdb.PARAM_BOOLEAN)" "" \
"class BasicParamPrefixWithSingleLineDoc(gdb.ParameterPrefix):" "" \
" \"\"\"This is a single line doc string.\"\"\"" "" \
" def __init__(self, name):" "" \
" super().__init__(name, gdb.COMMAND_NONE)" "" \
"BasicParamPrefixWithSingleLineDoc('prefix-5')" "" \
"gdb.Parameter('prefix-5 param-1', gdb.COMMAND_NONE, gdb.PARAM_BOOLEAN)" "" \
"class BasicParamPrefixWithMultiLineDoc(gdb.ParameterPrefix):" "" \
" \"\"\"This is a multi line doc string." "" \
" " "" \
" The rest of the doc string is here.\"\"\"" "" \
" def __init__(self, name):" "" \
" super().__init__(name, gdb.COMMAND_NONE)" "" \
"BasicParamPrefixWithMultiLineDoc('prefix-6')" "" \
"gdb.Parameter('prefix-6 param-1', gdb.COMMAND_NONE, gdb.PARAM_BOOLEAN)" "" \
"class BasicParamPrefixWithDocParameter(gdb.ParameterPrefix):" "" \
" \"\"\"This is an unsused doc string.\"\"\"" "" \
" def __init__(self, name, doc):" "" \
" super().__init__(name, gdb.COMMAND_NONE, doc)" "" \
"BasicParamPrefixWithDocParameter('prefix-7'," "" \
" \"\"\"The doc string text is here.\"\"\")" "" \
"gdb.Parameter('prefix-7 param-1', gdb.COMMAND_NONE, gdb.PARAM_BOOLEAN)" "" \
"end"
foreach mode { "set" "show" } {
gdb_test "help $mode prefix-4" \
[make_help_re $mode "prefix-4" \
"This command is not documented."]
gdb_test "help $mode prefix-5" \
[make_help_re $mode "prefix-5" \
"This is a single line doc string."]
gdb_test "help $mode prefix-6" \
[make_help_re $mode "prefix-6" \
[multi_line \
"This is a multi line doc string." \
"" \
"The rest of the doc string is here."]]
gdb_test "help $mode prefix-7" \
[make_help_re $mode "prefix-7" \
"The doc string text is here."]
foreach prefix { prefix-4 prefix-5 prefix-6 prefix-7 } {
gdb_test "$mode $prefix xxx" \
"^Undefined $mode $prefix command: \"xxx\"\\. Try \"help $mode $prefix\"\\."
}
}
foreach prefix { prefix-4 prefix-5 prefix-6 prefix-7 } {
gdb_test "set $prefix" \
[make_sub_cmd_help_re "set" $prefix]
gdb_test "show $prefix" \
[make_show_prefix_re $prefix]
}
}
# Create a sub-class of gdb.ParameterPrefix, and make use of
# 'invoke_set' and 'invoke_show'. Test that the invoke method is
# executed when expected, and that, by default, these invoke methods
# repeat when the user issues an empty command.
proc_with_prefix test_prefix_with_invoke {} {
gdb_test_multiline "ParameterPrefix with invoke_set" \
"python" "" \
"class PrefixWithInvokeSet(gdb.ParameterPrefix):" "" \
" def __init__(self, name):" "" \
" super().__init__(name, gdb.COMMAND_NONE)" "" \
" def invoke_set(self, args, from_tty):" "" \
" print(f\"invoke_set (a): \\\"{args}\\\" {from_tty}\")" "" \
"PrefixWithInvokeSet('prefix-8')" "" \
"gdb.Parameter('prefix-8 param-1', gdb.COMMAND_NONE, gdb.PARAM_BOOLEAN)" "" \
"class PrefixWithInvokeShow(gdb.ParameterPrefix):" "" \
" def __init__(self, name):" "" \
" super().__init__(name, gdb.COMMAND_NONE)" "" \
" def invoke_show(self, args, from_tty):" "" \
" print(f\"invoke_show (b): \\\"{args}\\\" {from_tty}\")" "" \
"PrefixWithInvokeShow('prefix-9')" "" \
"gdb.Parameter('prefix-9 param-1', gdb.COMMAND_NONE, gdb.PARAM_BOOLEAN)" "" \
"class PrefixWithBothInvoke(gdb.ParameterPrefix):" "" \
" def __init__(self, name):" "" \
" super().__init__(name, gdb.COMMAND_NONE)" "" \
" def invoke_set(self, args, from_tty):" "" \
" print(f\"invoke_set (c): \\\"{args}\\\" {from_tty}\")" "" \
" def invoke_show(self, args, from_tty):" "" \
" print(f\"invoke_show (d): \\\"{args}\\\" {from_tty}\")" "" \
"PrefixWithBothInvoke('prefix-10')" "" \
"gdb.Parameter('prefix-10 param-1', gdb.COMMAND_NONE, gdb.PARAM_BOOLEAN)" "" \
"end"
gdb_test "set prefix-8 xxx yyy" \
"^invoke_set \\(a\\): \"xxx yyy\" True"
send_gdb "\n"
gdb_test "" "^\r\ninvoke_set \\(a\\): \"xxx yyy\" True" \
"repeat set prefix-8 xxx yyy"
gdb_test "show prefix-8 xxx yyy" \
"^Undefined show prefix-8 command: \"xxx yyy\"\\. Try \"help show prefix-8\"\\."
gdb_test "set prefix-9 xxx yyy" \
"^Undefined set prefix-9 command: \"xxx yyy\"\\. Try \"help set prefix-9\"\\."
gdb_test "show prefix-9 xxx yyy" \
"^invoke_show \\(b\\): \"xxx yyy\" True"
send_gdb "\n"
gdb_test "" "^\r\ninvoke_show \\(b\\): \"xxx yyy\" True" \
"repeat show prefix-9 xxx yyy"
gdb_test "set prefix-10 xxx yyy" \
"^invoke_set \\(c\\): \"xxx yyy\" True"
send_gdb "\n"
gdb_test "" "^\r\ninvoke_set \\(c\\): \"xxx yyy\" True" \
"repeat set prefix-10 xxx yyy"
gdb_test "show prefix-10 xxx yyy" \
"^invoke_show \\(d\\): \"xxx yyy\" True"
send_gdb "\n"
gdb_test "" "^\r\ninvoke_show \\(d\\): \"xxx yyy\" True" \
"repeat show prefix-10 xxx yyy"
gdb_test "set prefix-8" \
"^invoke_set \\(a\\): \"\" True"
gdb_test "show prefix-8" \
[make_show_prefix_re "prefix-8"]
gdb_test "set prefix-9" \
[make_sub_cmd_help_re "set" "prefix-9"]
gdb_test "show prefix-9" \
"^invoke_show \\(b\\): \"\" True"
gdb_test "set prefix-10" \
"^invoke_set \\(c\\): \"\" True"
gdb_test "show prefix-10" \
"^invoke_show \\(d\\): \"\" True"
}
# Create ParameterPrefix sub-classes that make use of the
# dont_repeat() method. Check that the relevant set/show invoke
# callback doesn't repeat when an empty command is used.
proc_with_prefix test_dont_repeat {} {
gdb_test_multiline "ParameterPrefix with invoke_set and dont_repeat" \
"python" "" \
"class PrefixWithInvokeAndDoNotRepeatSet(gdb.ParameterPrefix):" "" \
" def __init__(self, name):" "" \
" super().__init__(name, gdb.COMMAND_NONE)" "" \
" def invoke_set(self, args, from_tty):" "" \
" self.dont_repeat()" "" \
" print(f\"invoke_set: \\\"{args}\\\" {from_tty}\")" "" \
" def invoke_show(self, args, from_tty):" "" \
" print(f\"invoke_show: \\\"{args}\\\" {from_tty}\")" "" \
"PrefixWithInvokeAndDoNotRepeatSet('prefix-11')" "" \
"gdb.Parameter('prefix-11 param-1', gdb.COMMAND_NONE, gdb.PARAM_BOOLEAN)" "" \
"class PrefixWithInvokeAndDoNotRepeatShow(gdb.ParameterPrefix):" "" \
" def __init__(self, name):" "" \
" super().__init__(name, gdb.COMMAND_NONE)" "" \
" def invoke_set(self, args, from_tty):" "" \
" print(f\"invoke_set: \\\"{args}\\\" {from_tty}\")" "" \
" def invoke_show(self, args, from_tty):" "" \
" self.dont_repeat()" "" \
" print(f\"invoke_show: \\\"{args}\\\" {from_tty}\")" "" \
"PrefixWithInvokeAndDoNotRepeatShow('prefix-12')" "" \
"gdb.Parameter('prefix-12 param-1', gdb.COMMAND_NONE, gdb.PARAM_BOOLEAN)" "" \
"end"
gdb_test "set prefix-11 xxx yyy" \
"^invoke_set: \"xxx yyy\" True"
send_gdb "\n"
gdb_test "" "^" \
"repeat set prefix-11 xxx yyy"
gdb_test "show prefix-11 xxx yyy" \
"^invoke_show: \"xxx yyy\" True"
send_gdb "\n"
gdb_test "" "invoke_show: \"xxx yyy\" True" \
"repeat show prefix-11 xxx yyy"
gdb_test "set prefix-12 xxx yyy" \
"^invoke_set: \"xxx yyy\" True"
send_gdb "\n"
gdb_test "" "^\r\ninvoke_set: \"xxx yyy\" True" \
"repeat set prefix-12 xxx yyy"
gdb_test "show prefix-12 xxx yyy" \
"^invoke_show: \"xxx yyy\" True"
send_gdb "\n"
gdb_test "" "^" \
"repeat show prefix-12 xxx yyy"
}
# Create a parameter prefixm, and immediately add another prefix under
# the first. The important thing here is that the second prefix is
# created into an otherwise empty prefix as this triggered a bug at
# one point.
proc_with_prefix test_nested {} {
gdb_test_multiline "Create nested parameter prefixes" \
"python" "" \
"gdb.ParameterPrefix('prefix-13', gdb.COMMAND_NONE)" "" \
"gdb.ParameterPrefix('prefix-13 prefix-14', gdb.COMMAND_NONE)" "" \
"gdb.Parameter('prefix-13 param-1', gdb.COMMAND_NONE, gdb.PARAM_BOOLEAN)" "" \
"gdb.Parameter('prefix-13 param-2', gdb.COMMAND_NONE, gdb.PARAM_BOOLEAN)" "" \
"gdb.Parameter('prefix-13 prefix-14 param-3', gdb.COMMAND_NONE, gdb.PARAM_BOOLEAN)" "" \
"gdb.Parameter('prefix-13 prefix-14 param-4', gdb.COMMAND_NONE, gdb.PARAM_BOOLEAN)" "" \
"end" ""
gdb_test "show prefix-13 prefix-14" \
[multi_line \
"^prefix-13 prefix-14 param-3: The current value of 'prefix-13 prefix-14 param-3' is \"off\"\\." \
"prefix-13 prefix-14 param-4: The current value of 'prefix-13 prefix-14 param-4' is \"off\"\\."]
gdb_test "show prefix-13" \
[multi_line \
"^prefix-13 param-1: The current value of 'prefix-13 param-1' is \"off\"\\." \
"prefix-13 param-2: The current value of 'prefix-13 param-2' is \"off\"\\." \
"prefix-13 prefix-14 param-3: The current value of 'prefix-13 prefix-14 param-3' is \"off\"\\." \
"prefix-13 prefix-14 param-4: The current value of 'prefix-13 prefix-14 param-4' is \"off\"\\."]
gdb_test "set prefix-13 prefix-14" \
[multi_line \
"" \
"set prefix-13 prefix-14 param-3 -- Set the current value of 'prefix-13 prefix-14 param-3'\\." \
"set prefix-13 prefix-14 param-4 -- Set the current value of 'prefix-13 prefix-14 param-4'\\." \
"" \
".*"]
gdb_test "set prefix-13" \
[multi_line \
"" \
"set prefix-13 param-1 -- Set the current value of 'prefix-13 param-1'\\." \
"set prefix-13 param-2 -- Set the current value of 'prefix-13 param-2'\\." \
"set prefix-13 prefix-14 -- This command is not documented\\." \
"" \
".*"]
}
test_basic_usage
test_simple_sub_class
test_prefix_with_invoke
test_dont_repeat
test_nested