1 /* Maintenance commands for testing the options framework.
3 Copyright (C) 2019-2024 Free Software Foundation, Inc.
5 This file is part of GDB.
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>. */
20 #include "cli/cli-cmds.h"
21 #include "cli/cli-option.h"
23 /* This file defines three "maintenance test-options" subcommands to
24 exercise TAB-completion and option processing:
26 (gdb) maint test-options require-delimiter
27 (gdb) maint test-options unknown-is-error
28 (gdb) maint test-options unknown-is-operand
30 And a fourth one to help with TAB-completion testing.
32 (gdb) maint show test-options-completion-result
34 Each of the test-options subcommands exercise
35 gdb::option::process_options with a different enum
36 process_options_mode value. Examples for commands they model:
38 - "print" and "compile print", are like "require-delimiter",
39 because they accept random expressions as argument.
41 - "backtrace" and "frame/thread apply" are like
42 "unknown-is-operand", because "-" is a valid command.
44 - "compile file" and "compile code" are like "unknown-is-error".
46 These commands allow exercising all aspects of option processing
47 without having to pick some existing command. That should be more
48 stable going forward than relying on an existing user command,
49 since if we picked say "print", that command or its options could
50 change in future, and then we'd be left with having to pick some
51 other command or option to exercise some non-command-specific
52 option processing detail. Also, actual user commands have side
53 effects that we're not interested in when we're focusing on unit
54 testing the options machinery. BTW, a maintenance command is used
55 as a sort of unit test driver instead of actual "maint selftest"
56 unit tests, since we need to go all the way via gdb including
57 readline, for proper testing of TAB completion.
59 These maintenance commands support options of all the different
60 available kinds of commands (boolean, enum, flag, string, filename,
63 (gdb) maint test-options require-delimiter -[TAB]
64 -bool -flag -uinteger-unlimited
65 -enum -pinteger-unlimited -xx1
66 -filename -string -xx2
68 (gdb) maint test-options require-delimiter -bool o[TAB]
70 (gdb) maint test-options require-delimiter -enum [TAB]
72 (gdb) maint test-options require-delimiter -uinteger-unlimited [TAB]
75 '-xx1' and '-xx2' are flag options too. They exist in order to
76 test ambiguous option names, like '-xx'.
78 Invoking the commands makes them print out the options parsed:
80 (gdb) maint test-options unknown-is-error -flag -enum yyy cmdarg
81 -flag 1 -xx1 0 -xx2 0 -bool 0 -enum yyy -uint-unl 0 -pint-unl 0 -string '' -filename '' -- cmdarg
83 (gdb) maint test-options require-delimiter -flag -enum yyy cmdarg
84 -flag 0 -xx1 0 -xx2 0 -bool 0 -enum xxx -uint-unl 0 -pint-unl 0 -string '' -filename '' -- -flag -enum yyy cmdarg
85 (gdb) maint test-options require-delimiter -flag -enum yyy cmdarg --
86 Unrecognized option at: cmdarg --
87 (gdb) maint test-options require-delimiter -flag -enum yyy -- cmdarg
88 -flag 1 -xx1 0 -xx2 0 -bool 0 -enum yyy -uint-unl 0 -pint-unl 0 -string '' -filename '' -- cmdarg
90 The "maint show test-options-completion-result" command exists in
91 order to do something similar for completion:
93 (gdb) maint test-options unknown-is-error -flag -b 0 -enum yyy OPERAND[TAB]
94 (gdb) maint show test-options-completion-result
97 (gdb) maint test-options unknown-is-error -flag -b 0 -enum yyy[TAB]
98 (gdb) maint show test-options-completion-result
101 (gdb) maint test-options require-dash -unknown[TAB]
102 (gdb) maint show test-options-completion-result
105 Here, "1" means the completion function processed the whole input
106 line, and that the command shouldn't do anything with the arguments,
107 since there are no operands. While "0" indicates that there are
108 operands after options. The text after "0" is the operands.
110 This level of detail is particularly important because getting the
111 completion function's entry point to return back to the caller the
112 right pointer into the operand is quite tricky in several
115 /* Enum values for the "maintenance test-options" commands. */
116 const char test_options_enum_values_xxx
[] = "xxx";
117 const char test_options_enum_values_yyy
[] = "yyy";
118 const char test_options_enum_values_zzz
[] = "zzz";
119 static const char *const test_options_enum_values_choices
[] =
121 test_options_enum_values_xxx
,
122 test_options_enum_values_yyy
,
123 test_options_enum_values_zzz
,
127 /* Option data for the "maintenance test-options" commands. */
129 struct test_options_opts
131 bool flag_opt
= false;
132 bool xx1_opt
= false;
133 bool xx2_opt
= false;
134 bool boolean_opt
= false;
135 const char *enum_opt
= test_options_enum_values_xxx
;
136 unsigned int uint_unl_opt
= 0;
137 int pint_unl_opt
= 0;
138 std::string string_opt
;
139 std::string filename_opt
;
141 test_options_opts () = default;
143 DISABLE_COPY_AND_ASSIGN (test_options_opts
);
145 /* Dump the options to FILE. ARGS is the remainder unprocessed
147 void dump (ui_file
*file
, const char *args
) const
150 _("-flag %d -xx1 %d -xx2 %d -bool %d "
151 "-enum %s -uint-unl %s -pint-unl %s -string '%s' "
152 "-filename '%s' -- %s\n"),
158 (uint_unl_opt
== UINT_MAX
160 : pulongest (uint_unl_opt
)),
163 : plongest (pint_unl_opt
)),
165 filename_opt
.c_str (),
170 /* Option definitions for the "maintenance test-options" commands. */
172 static const gdb::option::option_def test_options_option_defs
[] = {
175 gdb::option::flag_option_def
<test_options_opts
> {
177 [] (test_options_opts
*opts
) { return &opts
->flag_opt
; },
178 N_("A flag option."),
181 /* A couple flags with similar names, for "ambiguous option names"
183 gdb::option::flag_option_def
<test_options_opts
> {
185 [] (test_options_opts
*opts
) { return &opts
->xx1_opt
; },
186 N_("A flag option."),
188 gdb::option::flag_option_def
<test_options_opts
> {
190 [] (test_options_opts
*opts
) { return &opts
->xx2_opt
; },
191 N_("A flag option."),
194 /* A boolean option. */
195 gdb::option::boolean_option_def
<test_options_opts
> {
197 [] (test_options_opts
*opts
) { return &opts
->boolean_opt
; },
198 nullptr, /* show_cmd_cb */
199 N_("A boolean option."),
202 /* An enum option. */
203 gdb::option::enum_option_def
<test_options_opts
> {
205 test_options_enum_values_choices
,
206 [] (test_options_opts
*opts
) { return &opts
->enum_opt
; },
207 nullptr, /* show_cmd_cb */
208 N_("An enum option."),
211 /* A uinteger + "unlimited" option. */
212 gdb::option::uinteger_option_def
<test_options_opts
> {
213 "uinteger-unlimited",
214 [] (test_options_opts
*opts
) { return &opts
->uint_unl_opt
; },
215 uinteger_unlimited_literals
,
216 nullptr, /* show_cmd_cb */
217 N_("A uinteger option."),
218 nullptr, /* show_doc */
219 N_("A help doc that spawns\nmultiple lines."),
222 /* A pinteger + "unlimited" option. */
223 gdb::option::pinteger_option_def
<test_options_opts
> {
224 "pinteger-unlimited",
225 [] (test_options_opts
*opts
) { return &opts
->pint_unl_opt
; },
226 pinteger_unlimited_literals
,
227 nullptr, /* show_cmd_cb */
228 N_("A pinteger-unlimited option."),
229 nullptr, /* show_doc */
230 nullptr, /* help_doc */
233 /* A string option. */
234 gdb::option::string_option_def
<test_options_opts
> {
236 [] (test_options_opts
*opts
) { return &opts
->string_opt
; },
237 nullptr, /* show_cmd_cb */
238 N_("A string option."),
241 /* A filename option. */
242 gdb::option::filename_option_def
<test_options_opts
> {
244 [] (test_options_opts
*opts
) { return &opts
->filename_opt
; },
245 nullptr, /* show_cmd_cb */
246 N_("A filename option."),
250 /* Create an option_def_group for the test_options_opts options, with
253 static inline gdb::option::option_def_group
254 make_test_options_options_def_group (test_options_opts
*opts
)
256 return {{test_options_option_defs
}, opts
};
259 /* Implementation of the "maintenance test-options
260 require-delimiter/unknown-is-error/unknown-is-operand" commands.
261 Each of the commands maps to a different enum process_options_mode
262 enumerator. The test strategy is simply processing the options in
263 a number of scenarios, and printing back the parsed result. */
266 maintenance_test_options_command_mode (const char *args
,
267 gdb::option::process_options_mode mode
)
269 test_options_opts opts
;
271 gdb::option::process_options (&args
, mode
,
272 make_test_options_options_def_group (&opts
));
277 args
= skip_spaces (args
);
279 opts
.dump (gdb_stdout
, args
);
282 /* Variable used by the "maintenance show
283 test-options-completion-result" command. This variable is stored
284 by the completer of the "maint test-options" subcommands.
286 If the completer returned false, this includes the text at the word
287 point after gdb::option::complete_options returns. If true, then
288 this includes a dump of the processed options. */
289 static std::string maintenance_test_options_command_completion_text
;
291 /* The "maintenance show test-options-completion-result" command. */
294 maintenance_show_test_options_completion_result (const char *args
,
297 gdb_puts (maintenance_test_options_command_completion_text
.c_str ());
300 /* Save the completion result in the global variables read by the
301 "maintenance test-options require-delimiter" command. */
304 save_completion_result (const test_options_opts
&opts
, bool res
,
312 opts
.dump (&stream
, text
);
313 maintenance_test_options_command_completion_text
= stream
.release ();
317 maintenance_test_options_command_completion_text
318 = string_printf ("0 %s\n", text
);
322 /* Implementation of completer for the "maintenance test-options
323 require-delimiter/unknown-is-error/unknown-is-operand" commands.
324 Each of the commands maps to a different enum process_options_mode
328 maintenance_test_options_completer_mode (completion_tracker
&tracker
,
330 gdb::option::process_options_mode mode
)
332 test_options_opts opts
;
336 bool res
= (gdb::option::complete_options
337 (tracker
, &text
, mode
,
338 make_test_options_options_def_group (&opts
)));
340 save_completion_result (opts
, res
, text
);
342 catch (const gdb_exception_error
&ex
)
344 save_completion_result (opts
, true, text
);
349 /* Implementation of the "maintenance test-options require-delimiter"
353 maintenance_test_options_require_delimiter_command (const char *args
,
356 maintenance_test_options_command_mode
357 (args
, gdb::option::PROCESS_OPTIONS_REQUIRE_DELIMITER
);
360 /* Implementation of the "maintenance test-options
361 unknown-is-error" command. */
364 maintenance_test_options_unknown_is_error_command (const char *args
,
367 maintenance_test_options_command_mode
368 (args
, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_ERROR
);
371 /* Implementation of the "maintenance test-options
372 unknown-is-operand" command. */
375 maintenance_test_options_unknown_is_operand_command (const char *args
,
378 maintenance_test_options_command_mode
379 (args
, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_OPERAND
);
382 /* Completer for the "maintenance test-options require-delimiter"
386 maintenance_test_options_require_delimiter_command_completer
387 (cmd_list_element
*ignore
, completion_tracker
&tracker
,
388 const char *text
, const char *word
)
390 maintenance_test_options_completer_mode
391 (tracker
, text
, gdb::option::PROCESS_OPTIONS_REQUIRE_DELIMITER
);
394 /* Completer for the "maintenance test-options unknown-is-error"
398 maintenance_test_options_unknown_is_error_command_completer
399 (cmd_list_element
*ignore
, completion_tracker
&tracker
,
400 const char *text
, const char *word
)
402 maintenance_test_options_completer_mode
403 (tracker
, text
, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_ERROR
);
406 /* Completer for the "maintenance test-options unknown-is-operand"
410 maintenance_test_options_unknown_is_operand_command_completer
411 (cmd_list_element
*ignore
, completion_tracker
&tracker
,
412 const char *text
, const char *word
)
414 maintenance_test_options_completer_mode
415 (tracker
, text
, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_OPERAND
);
418 /* Command list for maint test-options. */
419 static cmd_list_element
*maintenance_test_options_list
;
422 void _initialize_maint_test_options ();
424 _initialize_maint_test_options ()
426 cmd_list_element
*cmd
;
428 add_basic_prefix_cmd ("test-options", no_class
,
430 Generic command for testing the options infrastructure."),
431 &maintenance_test_options_list
,
432 0, &maintenancelist
);
434 const auto def_group
= make_test_options_options_def_group (nullptr);
436 static const std::string help_require_delim_str
437 = gdb::option::build_help (_("\
438 Command used for testing options processing.\n\
439 Usage: maint test-options require-delimiter [[OPTION]... --] [OPERAND]...\n\
444 If you specify any command option, you must use a double dash (\"--\")\n\
445 to mark the end of option processing."),
448 static const std::string help_unknown_is_error_str
449 = gdb::option::build_help (_("\
450 Command used for testing options processing.\n\
451 Usage: maint test-options unknown-is-error [OPTION]... [OPERAND]...\n\
457 static const std::string help_unknown_is_operand_str
458 = gdb::option::build_help (_("\
459 Command used for testing options processing.\n\
460 Usage: maint test-options unknown-is-operand [OPTION]... [OPERAND]...\n\
466 cmd
= add_cmd ("require-delimiter", class_maintenance
,
467 maintenance_test_options_require_delimiter_command
,
468 help_require_delim_str
.c_str (),
469 &maintenance_test_options_list
);
470 set_cmd_completer_handle_brkchars
471 (cmd
, maintenance_test_options_require_delimiter_command_completer
);
473 cmd
= add_cmd ("unknown-is-error", class_maintenance
,
474 maintenance_test_options_unknown_is_error_command
,
475 help_unknown_is_error_str
.c_str (),
476 &maintenance_test_options_list
);
477 set_cmd_completer_handle_brkchars
478 (cmd
, maintenance_test_options_unknown_is_error_command_completer
);
480 cmd
= add_cmd ("unknown-is-operand", class_maintenance
,
481 maintenance_test_options_unknown_is_operand_command
,
482 help_unknown_is_operand_str
.c_str (),
483 &maintenance_test_options_list
);
484 set_cmd_completer_handle_brkchars
485 (cmd
, maintenance_test_options_unknown_is_operand_command_completer
);
487 add_cmd ("test-options-completion-result", class_maintenance
,
488 maintenance_show_test_options_completion_result
,
490 Show maintenance test-options completion result.\n\
491 Shows the results of completing\n\
492 \"maint test-options require-delimiter\",\n\
493 \"maint test-options unknown-is-error\", or\n\
494 \"maint test-options unknown-is-operand\"."),
495 &maintenance_show_cmdlist
);