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, uinteger):
62 (gdb) maint test-options require-delimiter -[TAB]
63 -bool -pinteger-unlimited -xx1
65 -flag -uinteger-unlimited
67 (gdb) maint test-options require-delimiter -bool o[TAB]
69 (gdb) maint test-options require-delimiter -enum [TAB]
71 (gdb) maint test-options require-delimiter -uinteger-unlimited [TAB]
74 '-xx1' and '-xx2' are flag options too. They exist in order to
75 test ambiguous option names, like '-xx'.
77 Invoking the commands makes them print out the options parsed:
79 (gdb) maint test-options unknown-is-error -flag -enum yyy cmdarg
80 -flag 1 -xx1 0 -xx2 0 -bool 0 -enum yyy -uint-unl 0 -pint-unl 0 -string '' -- cmdarg
82 (gdb) maint test-options require-delimiter -flag -enum yyy cmdarg
83 -flag 0 -xx1 0 -xx2 0 -bool 0 -enum xxx -uint-unl 0 -pint-unl 0 -string '' -- -flag -enum yyy cmdarg
84 (gdb) maint test-options require-delimiter -flag -enum yyy cmdarg --
85 Unrecognized option at: cmdarg --
86 (gdb) maint test-options require-delimiter -flag -enum yyy -- cmdarg
87 -flag 1 -xx1 0 -xx2 0 -bool 0 -enum yyy -uint-unl 0 -pint-unl 0 -string '' -- cmdarg
89 The "maint show test-options-completion-result" command exists in
90 order to do something similar for completion:
92 (gdb) maint test-options unknown-is-error -flag -b 0 -enum yyy OPERAND[TAB]
93 (gdb) maint show test-options-completion-result
96 (gdb) maint test-options unknown-is-error -flag -b 0 -enum yyy[TAB]
97 (gdb) maint show test-options-completion-result
100 (gdb) maint test-options require-dash -unknown[TAB]
101 (gdb) maint show test-options-completion-result
104 Here, "1" means the completion function processed the whole input
105 line, and that the command shouldn't do anything with the arguments,
106 since there are no operands. While "0" indicates that there are
107 operands after options. The text after "0" is the operands.
109 This level of detail is particularly important because getting the
110 completion function's entry point to return back to the caller the
111 right pointer into the operand is quite tricky in several
114 /* Enum values for the "maintenance test-options" commands. */
115 const char test_options_enum_values_xxx
[] = "xxx";
116 const char test_options_enum_values_yyy
[] = "yyy";
117 const char test_options_enum_values_zzz
[] = "zzz";
118 static const char *const test_options_enum_values_choices
[] =
120 test_options_enum_values_xxx
,
121 test_options_enum_values_yyy
,
122 test_options_enum_values_zzz
,
126 /* Option data for the "maintenance test-options" commands. */
128 struct test_options_opts
130 bool flag_opt
= false;
131 bool xx1_opt
= false;
132 bool xx2_opt
= false;
133 bool boolean_opt
= false;
134 const char *enum_opt
= test_options_enum_values_xxx
;
135 unsigned int uint_unl_opt
= 0;
136 int pint_unl_opt
= 0;
137 std::string string_opt
;
139 test_options_opts () = default;
141 DISABLE_COPY_AND_ASSIGN (test_options_opts
);
143 /* Dump the options to FILE. ARGS is the remainder unprocessed
145 void dump (ui_file
*file
, const char *args
) const
148 _("-flag %d -xx1 %d -xx2 %d -bool %d "
149 "-enum %s -uint-unl %s -pint-unl %s -string '%s' -- %s\n"),
155 (uint_unl_opt
== UINT_MAX
157 : pulongest (uint_unl_opt
)),
160 : plongest (pint_unl_opt
)),
166 /* Option definitions for the "maintenance test-options" commands. */
168 static const gdb::option::option_def test_options_option_defs
[] = {
171 gdb::option::flag_option_def
<test_options_opts
> {
173 [] (test_options_opts
*opts
) { return &opts
->flag_opt
; },
174 N_("A flag option."),
177 /* A couple flags with similar names, for "ambiguous option names"
179 gdb::option::flag_option_def
<test_options_opts
> {
181 [] (test_options_opts
*opts
) { return &opts
->xx1_opt
; },
182 N_("A flag option."),
184 gdb::option::flag_option_def
<test_options_opts
> {
186 [] (test_options_opts
*opts
) { return &opts
->xx2_opt
; },
187 N_("A flag option."),
190 /* A boolean option. */
191 gdb::option::boolean_option_def
<test_options_opts
> {
193 [] (test_options_opts
*opts
) { return &opts
->boolean_opt
; },
194 nullptr, /* show_cmd_cb */
195 N_("A boolean option."),
198 /* An enum option. */
199 gdb::option::enum_option_def
<test_options_opts
> {
201 test_options_enum_values_choices
,
202 [] (test_options_opts
*opts
) { return &opts
->enum_opt
; },
203 nullptr, /* show_cmd_cb */
204 N_("An enum option."),
207 /* A uinteger + "unlimited" option. */
208 gdb::option::uinteger_option_def
<test_options_opts
> {
209 "uinteger-unlimited",
210 [] (test_options_opts
*opts
) { return &opts
->uint_unl_opt
; },
211 uinteger_unlimited_literals
,
212 nullptr, /* show_cmd_cb */
213 N_("A uinteger option."),
214 nullptr, /* show_doc */
215 N_("A help doc that spawns\nmultiple lines."),
218 /* A pinteger + "unlimited" option. */
219 gdb::option::pinteger_option_def
<test_options_opts
> {
220 "pinteger-unlimited",
221 [] (test_options_opts
*opts
) { return &opts
->pint_unl_opt
; },
222 pinteger_unlimited_literals
,
223 nullptr, /* show_cmd_cb */
224 N_("A pinteger-unlimited option."),
225 nullptr, /* show_doc */
226 nullptr, /* help_doc */
229 /* A string option. */
230 gdb::option::string_option_def
<test_options_opts
> {
232 [] (test_options_opts
*opts
) { return &opts
->string_opt
; },
233 nullptr, /* show_cmd_cb */
234 N_("A string option."),
238 /* Create an option_def_group for the test_options_opts options, with
241 static inline gdb::option::option_def_group
242 make_test_options_options_def_group (test_options_opts
*opts
)
244 return {{test_options_option_defs
}, opts
};
247 /* Implementation of the "maintenance test-options
248 require-delimiter/unknown-is-error/unknown-is-operand" commands.
249 Each of the commands maps to a different enum process_options_mode
250 enumerator. The test strategy is simply processing the options in
251 a number of scenarios, and printing back the parsed result. */
254 maintenance_test_options_command_mode (const char *args
,
255 gdb::option::process_options_mode mode
)
257 test_options_opts opts
;
259 gdb::option::process_options (&args
, mode
,
260 make_test_options_options_def_group (&opts
));
265 args
= skip_spaces (args
);
267 opts
.dump (gdb_stdout
, args
);
270 /* Variable used by the "maintenance show
271 test-options-completion-result" command. This variable is stored
272 by the completer of the "maint test-options" subcommands.
274 If the completer returned false, this includes the text at the word
275 point after gdb::option::complete_options returns. If true, then
276 this includes a dump of the processed options. */
277 static std::string maintenance_test_options_command_completion_text
;
279 /* The "maintenance show test-options-completion-result" command. */
282 maintenance_show_test_options_completion_result (const char *args
,
285 gdb_puts (maintenance_test_options_command_completion_text
.c_str ());
288 /* Save the completion result in the global variables read by the
289 "maintenance test-options require-delimiter" command. */
292 save_completion_result (const test_options_opts
&opts
, bool res
,
300 opts
.dump (&stream
, text
);
301 maintenance_test_options_command_completion_text
= stream
.release ();
305 maintenance_test_options_command_completion_text
306 = string_printf ("0 %s\n", text
);
310 /* Implementation of completer for the "maintenance test-options
311 require-delimiter/unknown-is-error/unknown-is-operand" commands.
312 Each of the commands maps to a different enum process_options_mode
316 maintenance_test_options_completer_mode (completion_tracker
&tracker
,
318 gdb::option::process_options_mode mode
)
320 test_options_opts opts
;
324 bool res
= (gdb::option::complete_options
325 (tracker
, &text
, mode
,
326 make_test_options_options_def_group (&opts
)));
328 save_completion_result (opts
, res
, text
);
330 catch (const gdb_exception_error
&ex
)
332 save_completion_result (opts
, true, text
);
337 /* Implementation of the "maintenance test-options require-delimiter"
341 maintenance_test_options_require_delimiter_command (const char *args
,
344 maintenance_test_options_command_mode
345 (args
, gdb::option::PROCESS_OPTIONS_REQUIRE_DELIMITER
);
348 /* Implementation of the "maintenance test-options
349 unknown-is-error" command. */
352 maintenance_test_options_unknown_is_error_command (const char *args
,
355 maintenance_test_options_command_mode
356 (args
, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_ERROR
);
359 /* Implementation of the "maintenance test-options
360 unknown-is-operand" command. */
363 maintenance_test_options_unknown_is_operand_command (const char *args
,
366 maintenance_test_options_command_mode
367 (args
, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_OPERAND
);
370 /* Completer for the "maintenance test-options require-delimiter"
374 maintenance_test_options_require_delimiter_command_completer
375 (cmd_list_element
*ignore
, completion_tracker
&tracker
,
376 const char *text
, const char *word
)
378 maintenance_test_options_completer_mode
379 (tracker
, text
, gdb::option::PROCESS_OPTIONS_REQUIRE_DELIMITER
);
382 /* Completer for the "maintenance test-options unknown-is-error"
386 maintenance_test_options_unknown_is_error_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_UNKNOWN_IS_ERROR
);
394 /* Completer for the "maintenance test-options unknown-is-operand"
398 maintenance_test_options_unknown_is_operand_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_OPERAND
);
406 /* Command list for maint test-options. */
407 static cmd_list_element
*maintenance_test_options_list
;
410 void _initialize_maint_test_options ();
412 _initialize_maint_test_options ()
414 cmd_list_element
*cmd
;
416 add_basic_prefix_cmd ("test-options", no_class
,
418 Generic command for testing the options infrastructure."),
419 &maintenance_test_options_list
,
420 0, &maintenancelist
);
422 const auto def_group
= make_test_options_options_def_group (nullptr);
424 static const std::string help_require_delim_str
425 = gdb::option::build_help (_("\
426 Command used for testing options processing.\n\
427 Usage: maint test-options require-delimiter [[OPTION]... --] [OPERAND]...\n\
432 If you specify any command option, you must use a double dash (\"--\")\n\
433 to mark the end of option processing."),
436 static const std::string help_unknown_is_error_str
437 = gdb::option::build_help (_("\
438 Command used for testing options processing.\n\
439 Usage: maint test-options unknown-is-error [OPTION]... [OPERAND]...\n\
445 static const std::string help_unknown_is_operand_str
446 = gdb::option::build_help (_("\
447 Command used for testing options processing.\n\
448 Usage: maint test-options unknown-is-operand [OPTION]... [OPERAND]...\n\
454 cmd
= add_cmd ("require-delimiter", class_maintenance
,
455 maintenance_test_options_require_delimiter_command
,
456 help_require_delim_str
.c_str (),
457 &maintenance_test_options_list
);
458 set_cmd_completer_handle_brkchars
459 (cmd
, maintenance_test_options_require_delimiter_command_completer
);
461 cmd
= add_cmd ("unknown-is-error", class_maintenance
,
462 maintenance_test_options_unknown_is_error_command
,
463 help_unknown_is_error_str
.c_str (),
464 &maintenance_test_options_list
);
465 set_cmd_completer_handle_brkchars
466 (cmd
, maintenance_test_options_unknown_is_error_command_completer
);
468 cmd
= add_cmd ("unknown-is-operand", class_maintenance
,
469 maintenance_test_options_unknown_is_operand_command
,
470 help_unknown_is_operand_str
.c_str (),
471 &maintenance_test_options_list
);
472 set_cmd_completer_handle_brkchars
473 (cmd
, maintenance_test_options_unknown_is_operand_command_completer
);
475 add_cmd ("test-options-completion-result", class_maintenance
,
476 maintenance_show_test_options_completion_result
,
478 Show maintenance test-options completion result.\n\
479 Shows the results of completing\n\
480 \"maint test-options require-delimiter\",\n\
481 \"maint test-options unknown-is-error\", or\n\
482 \"maint test-options unknown-is-operand\"."),
483 &maintenance_show_cmdlist
);