1 /* Maintenance commands for testing the options framework.
3 Copyright (C) 2019-2020 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/>. */
22 #include "cli/cli-option.h"
24 /* This file defines three "maintenance test-options" subcommands to
25 exercise TAB-completion and option processing:
27 (gdb) maint test-options require-delimiter
28 (gdb) maint test-options unknown-is-error
29 (gdb) maint test-options unknown-is-operand
31 And a fourth one to help with TAB-completion testing.
33 (gdb) maint show test-options-completion-result
35 Each of the test-options subcommands exercise
36 gdb::option::process_options with a different enum
37 process_options_mode value. Examples for commands they model:
39 - "print" and "compile print", are like "require-delimiter",
40 because they accept random expressions as argument.
42 - "backtrace" and "frame/thread apply" are like
43 "unknown-is-operand", because "-" is a valid command.
45 - "compile file" and "compile code" are like "unknown-is-error".
47 These commands allow exercising all aspects of option processing
48 without having to pick some existing command. That should be more
49 stable going forward than relying on an existing user command,
50 since if we picked say "print", that command or its options could
51 change in future, and then we'd be left with having to pick some
52 other command or option to exercise some non-command-specific
53 option processing detail. Also, actual user commands have side
54 effects that we're not interested in when we're focusing on unit
55 testing the options machinery. BTW, a maintenance command is used
56 as a sort of unit test driver instead of actual "maint selftest"
57 unit tests, since we need to go all the way via gdb including
58 readline, for proper testing of TAB completion.
60 These maintenance commands support options of all the different
61 available kinds of commands (boolean, enum, flag, string, uinteger):
63 (gdb) maint test-options require-delimiter -[TAB]
64 -bool -enum -flag -string -uinteger -xx1 -xx2
66 (gdb) maint test-options require-delimiter -bool o[TAB]
68 (gdb) maint test-options require-delimiter -enum [TAB]
70 (gdb) maint test-options require-delimiter -uinteger [TAB]
73 '-xx1' and '-xx2' are flag options too. They exist in order to
74 test ambiguous option names, like '-xx'.
76 Invoking the commands makes them print out the options parsed:
78 (gdb) maint test-options unknown-is-error -flag -enum yyy cmdarg
79 -flag 1 -xx1 0 -xx2 0 -bool 0 -enum yyy -uint 0 -zuint-unl 0 -- cmdarg
81 (gdb) maint test-options require-delimiter -flag -enum yyy cmdarg
82 -flag 0 -xx1 0 -xx2 0 -bool 0 -enum xxx -uint 0 -zuint-unl 0 -- -flag -enum yyy cmdarg
83 (gdb) maint test-options require-delimiter -flag -enum yyy cmdarg --
84 Unrecognized option at: cmdarg --
85 (gdb) maint test-options require-delimiter -flag -enum yyy -- cmdarg
86 -flag 1 -xx1 0 -xx2 0 -bool 0 -enum yyy -uint 0 -zuint-unl 0 -- cmdarg
88 The "maint show test-options-completion-result" command exists in
89 order to do something similar for completion:
91 (gdb) maint test-options unknown-is-error -flag -b 0 -enum yyy OPERAND[TAB]
92 (gdb) maint show test-options-completion-result
95 (gdb) maint test-options unknown-is-error -flag -b 0 -enum yyy[TAB]
96 (gdb) maint show test-options-completion-result
99 (gdb) maint test-options require-dash -unknown[TAB]
100 (gdb) maint show test-options-completion-result
103 Here, "1" means the completion function processed the whole input
104 line, and that the command shouldn't do anything with the arguments,
105 since there are no operands. While "0" indicates that there are
106 operands after options. The text after "0" is the operands.
108 This level of detail is particularly important because getting the
109 completion function's entry point to return back to the caller the
110 right pointer into the operand is quite tricky in several
113 /* Enum values for the "maintenance test-options" commands. */
114 const char test_options_enum_values_xxx
[] = "xxx";
115 const char test_options_enum_values_yyy
[] = "yyy";
116 const char test_options_enum_values_zzz
[] = "zzz";
117 static const char *const test_options_enum_values_choices
[] =
119 test_options_enum_values_xxx
,
120 test_options_enum_values_yyy
,
121 test_options_enum_values_zzz
,
125 /* Option data for the "maintenance test-options" commands. */
127 struct test_options_opts
129 bool flag_opt
= false;
130 bool xx1_opt
= false;
131 bool xx2_opt
= false;
132 bool boolean_opt
= false;
133 const char *enum_opt
= test_options_enum_values_xxx
;
134 unsigned int uint_opt
= 0;
135 int zuint_unl_opt
= 0;
136 char *string_opt
= nullptr;
138 test_options_opts () = default;
140 DISABLE_COPY_AND_ASSIGN (test_options_opts
);
142 ~test_options_opts ()
147 /* Dump the options to FILE. ARGS is the remainder unprocessed
149 void dump (ui_file
*file
, const char *args
) const
151 fprintf_unfiltered (file
,
152 _("-flag %d -xx1 %d -xx2 %d -bool %d "
153 "-enum %s -uint %s -zuint-unl %s -string '%s' -- %s\n"),
159 (uint_opt
== UINT_MAX
161 : pulongest (uint_opt
)),
164 : plongest (zuint_unl_opt
)),
165 (string_opt
!= nullptr
172 /* Option definitions for the "maintenance test-options" commands. */
174 static const gdb::option::option_def test_options_option_defs
[] = {
177 gdb::option::flag_option_def
<test_options_opts
> {
179 [] (test_options_opts
*opts
) { return &opts
->flag_opt
; },
180 N_("A flag option."),
183 /* A couple flags with similar names, for "ambiguous option names"
185 gdb::option::flag_option_def
<test_options_opts
> {
187 [] (test_options_opts
*opts
) { return &opts
->xx1_opt
; },
188 N_("A flag option."),
190 gdb::option::flag_option_def
<test_options_opts
> {
192 [] (test_options_opts
*opts
) { return &opts
->xx2_opt
; },
193 N_("A flag option."),
196 /* A boolean option. */
197 gdb::option::boolean_option_def
<test_options_opts
> {
199 [] (test_options_opts
*opts
) { return &opts
->boolean_opt
; },
200 nullptr, /* show_cmd_cb */
201 N_("A boolean option."),
204 /* An enum option. */
205 gdb::option::enum_option_def
<test_options_opts
> {
207 test_options_enum_values_choices
,
208 [] (test_options_opts
*opts
) { return &opts
->enum_opt
; },
209 nullptr, /* show_cmd_cb */
210 N_("An enum option."),
213 /* A uinteger option. */
214 gdb::option::uinteger_option_def
<test_options_opts
> {
216 [] (test_options_opts
*opts
) { return &opts
->uint_opt
; },
217 nullptr, /* show_cmd_cb */
218 N_("A uinteger option."),
219 nullptr, /* show_doc */
220 N_("A help doc that spawns\nmultiple lines."),
223 /* A zuinteger_unlimited option. */
224 gdb::option::zuinteger_unlimited_option_def
<test_options_opts
> {
225 "zuinteger-unlimited",
226 [] (test_options_opts
*opts
) { return &opts
->zuint_unl_opt
; },
227 nullptr, /* show_cmd_cb */
228 N_("A zuinteger-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."),
242 /* Create an option_def_group for the test_options_opts options, with
245 static inline gdb::option::option_def_group
246 make_test_options_options_def_group (test_options_opts
*opts
)
248 return {{test_options_option_defs
}, opts
};
251 /* Implementation of the "maintenance test-options
252 require-delimiter/unknown-is-error/unknown-is-operand" commands.
253 Each of the commands maps to a different enum process_options_mode
254 enumerator. The test strategy is simply processing the options in
255 a number of scenarios, and printing back the parsed result. */
258 maintenance_test_options_command_mode (const char *args
,
259 gdb::option::process_options_mode mode
)
261 test_options_opts opts
;
263 gdb::option::process_options (&args
, mode
,
264 make_test_options_options_def_group (&opts
));
269 args
= skip_spaces (args
);
271 opts
.dump (gdb_stdout
, args
);
274 /* Variable used by the "maintenance show
275 test-options-completion-result" command. This variable is stored
276 by the completer of the "maint test-options" subcommands.
278 If the completer returned false, this includes the text at the word
279 point after gdb::option::complete_options returns. If true, then
280 this includes a dump of the processed options. */
281 static std::string maintenance_test_options_command_completion_text
;
283 /* The "maintenance show test-options-completion-result" command. */
286 maintenance_show_test_options_completion_result (const char *args
,
289 puts_filtered (maintenance_test_options_command_completion_text
.c_str ());
292 /* Save the completion result in the global variables read by the
293 "maintenance test-options require-delimiter" command. */
296 save_completion_result (const test_options_opts
&opts
, bool res
,
304 opts
.dump (&stream
, text
);
305 maintenance_test_options_command_completion_text
306 = std::move (stream
.string ());
310 maintenance_test_options_command_completion_text
311 = string_printf ("0 %s\n", text
);
315 /* Implementation of completer for the "maintenance test-options
316 require-delimiter/unknown-is-error/unknown-is-operand" commands.
317 Each of the commands maps to a different enum process_options_mode
321 maintenance_test_options_completer_mode (completion_tracker
&tracker
,
323 gdb::option::process_options_mode mode
)
325 test_options_opts opts
;
329 bool res
= (gdb::option::complete_options
330 (tracker
, &text
, mode
,
331 make_test_options_options_def_group (&opts
)));
333 save_completion_result (opts
, res
, text
);
335 catch (const gdb_exception_error
&ex
)
337 save_completion_result (opts
, true, text
);
342 /* Implementation of the "maintenance test-options require-delimiter"
346 maintenance_test_options_require_delimiter_command (const char *args
,
349 maintenance_test_options_command_mode
350 (args
, gdb::option::PROCESS_OPTIONS_REQUIRE_DELIMITER
);
353 /* Implementation of the "maintenance test-options
354 unknown-is-error" command. */
357 maintenance_test_options_unknown_is_error_command (const char *args
,
360 maintenance_test_options_command_mode
361 (args
, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_ERROR
);
364 /* Implementation of the "maintenance test-options
365 unknown-is-operand" command. */
368 maintenance_test_options_unknown_is_operand_command (const char *args
,
371 maintenance_test_options_command_mode
372 (args
, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_OPERAND
);
375 /* Completer for the "maintenance test-options require-delimiter"
379 maintenance_test_options_require_delimiter_command_completer
380 (cmd_list_element
*ignore
, completion_tracker
&tracker
,
381 const char *text
, const char *word
)
383 maintenance_test_options_completer_mode
384 (tracker
, text
, gdb::option::PROCESS_OPTIONS_REQUIRE_DELIMITER
);
387 /* Completer for the "maintenance test-options unknown-is-error"
391 maintenance_test_options_unknown_is_error_command_completer
392 (cmd_list_element
*ignore
, completion_tracker
&tracker
,
393 const char *text
, const char *word
)
395 maintenance_test_options_completer_mode
396 (tracker
, text
, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_ERROR
);
399 /* Completer for the "maintenance test-options unknown-is-operand"
403 maintenance_test_options_unknown_is_operand_command_completer
404 (cmd_list_element
*ignore
, completion_tracker
&tracker
,
405 const char *text
, const char *word
)
407 maintenance_test_options_completer_mode
408 (tracker
, text
, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_OPERAND
);
411 /* Command list for maint test-options. */
412 struct cmd_list_element
*maintenance_test_options_list
;
414 /* The "maintenance test-options" prefix command. */
417 maintenance_test_options_command (const char *arg
, int from_tty
)
420 (_("\"maintenance test-options\" must be followed "
421 "by the name of a subcommand.\n"));
422 help_list (maintenance_test_options_list
, "maintenance test-options ",
423 all_commands
, gdb_stdout
);
427 void _initialize_maint_test_options ();
429 _initialize_maint_test_options ()
431 cmd_list_element
*cmd
;
433 add_prefix_cmd ("test-options", no_class
, maintenance_test_options_command
,
435 Generic command for testing the options infrastructure."),
436 &maintenance_test_options_list
,
437 "maintenance test-options ", 0,
440 const auto def_group
= make_test_options_options_def_group (nullptr);
442 static const std::string help_require_delim_str
443 = gdb::option::build_help (_("\
444 Command used for testing options processing.\n\
445 Usage: maint test-options require-delimiter [[OPTION]... --] [OPERAND]...\n\
450 If you specify any command option, you must use a double dash (\"--\")\n\
451 to mark the end of option processing."),
454 static const std::string help_unknown_is_error_str
455 = gdb::option::build_help (_("\
456 Command used for testing options processing.\n\
457 Usage: maint test-options unknown-is-error [OPTION]... [OPERAND]...\n\
463 static const std::string help_unknown_is_operand_str
464 = gdb::option::build_help (_("\
465 Command used for testing options processing.\n\
466 Usage: maint test-options unknown-is-operand [OPTION]... [OPERAND]...\n\
472 cmd
= add_cmd ("require-delimiter", class_maintenance
,
473 maintenance_test_options_require_delimiter_command
,
474 help_require_delim_str
.c_str (),
475 &maintenance_test_options_list
);
476 set_cmd_completer_handle_brkchars
477 (cmd
, maintenance_test_options_require_delimiter_command_completer
);
479 cmd
= add_cmd ("unknown-is-error", class_maintenance
,
480 maintenance_test_options_unknown_is_error_command
,
481 help_unknown_is_error_str
.c_str (),
482 &maintenance_test_options_list
);
483 set_cmd_completer_handle_brkchars
484 (cmd
, maintenance_test_options_unknown_is_error_command_completer
);
486 cmd
= add_cmd ("unknown-is-operand", class_maintenance
,
487 maintenance_test_options_unknown_is_operand_command
,
488 help_unknown_is_operand_str
.c_str (),
489 &maintenance_test_options_list
);
490 set_cmd_completer_handle_brkchars
491 (cmd
, maintenance_test_options_unknown_is_operand_command_completer
);
493 add_cmd ("test-options-completion-result", class_maintenance
,
494 maintenance_show_test_options_completion_result
,
496 Show maintenance test-options completion result.\n\
497 Shows the results of completing\n\
498 \"maint test-options require-delimiter\",\n\
499 \"maint test-options unknown-is-error\", or\n\
500 \"maint test-options unknown-is-operand\"."),
501 &maintenance_show_cmdlist
);