| # 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 |