]>
Commit | Line | Data |
---|---|---|
58e6ac70 | 1 | /* Self tests for GDB command definitions for GDB, the GNU debugger. |
d2834edc | 2 | |
3666a048 | 3 | Copyright (C) 2019-2021 Free Software Foundation, Inc. |
d2834edc PW |
4 | |
5 | This file is part of GDB. | |
6 | ||
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. | |
11 | ||
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. | |
16 | ||
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/>. */ | |
19 | ||
20 | #include "defs.h" | |
21 | #include "cli/cli-cmds.h" | |
22 | #include "cli/cli-decode.h" | |
23 | #include "gdbsupport/selftest.h" | |
24 | ||
58e6ac70 PW |
25 | #include <map> |
26 | ||
d2834edc | 27 | namespace selftests { |
58e6ac70 PW |
28 | |
29 | /* Verify some invariants of GDB commands documentation. */ | |
30 | ||
d2834edc PW |
31 | namespace help_doc_tests { |
32 | ||
33 | static unsigned int nr_failed_invariants; | |
34 | ||
35 | /* Report a broken invariant and increments nr_failed_invariants. */ | |
36 | ||
37 | static void | |
38 | broken_doc_invariant (const char *prefix, const char *name, const char *msg) | |
39 | { | |
40 | fprintf_filtered (gdb_stdout, | |
41 | "help doc broken invariant: command '%s%s' help doc %s\n", | |
42 | prefix, name, msg); | |
43 | nr_failed_invariants++; | |
44 | } | |
45 | ||
46 | /* Recursively walk the commandlist structures, and check doc invariants: | |
47 | - The first line of the doc must end with a '.'. | |
48 | - the doc must not end with a new line. | |
49 | If an invariant is not respected, produce a message and increment | |
50 | nr_failed_invariants. | |
51 | Note that we do not call SELF_CHECK in this function, as we want | |
52 | all commands to be checked before making the test fail. */ | |
53 | ||
54 | static void | |
55 | check_doc (struct cmd_list_element *commandlist, const char *prefix) | |
56 | { | |
57 | struct cmd_list_element *c; | |
58 | ||
59 | /* Walk through the commands. */ | |
60 | for (c = commandlist; c; c = c->next) | |
61 | { | |
62 | /* Checks the doc has a first line terminated with a '.'. */ | |
63 | const char *p = c->doc; | |
64 | ||
65 | /* Position p on the first LF, or on terminating null byte. */ | |
66 | while (*p && *p != '\n') | |
67 | p++; | |
68 | if (p == c->doc) | |
69 | broken_doc_invariant | |
70 | (prefix, c->name, | |
71 | "is missing the first line terminated with a '.' character"); | |
72 | else if (*(p-1) != '.') | |
73 | broken_doc_invariant | |
74 | (prefix, c->name, | |
75 | "first line is not terminated with a '.' character"); | |
76 | ||
77 | /* Checks the doc is not terminated with a new line. */ | |
78 | if (c->doc[strlen (c->doc) - 1] == '\n') | |
79 | broken_doc_invariant | |
80 | (prefix, c->name, | |
81 | "has a superfluous trailing end of line"); | |
82 | ||
83 | /* Check if this command has subcommands and is not an | |
84 | abbreviation. We skip checking subcommands of abbreviations | |
85 | in order to avoid duplicates in the output. */ | |
3d0b3564 | 86 | if (c->is_prefix () && !c->abbrev_flag) |
d2834edc PW |
87 | { |
88 | /* Recursively call ourselves on the subcommand list, | |
89 | passing the right prefix in. */ | |
14b42fc4 | 90 | check_doc (*c->subcommands, c->prefixname ().c_str ()); |
d2834edc PW |
91 | } |
92 | } | |
93 | } | |
94 | ||
95 | static void | |
96 | help_doc_invariants_tests () | |
97 | { | |
98 | nr_failed_invariants = 0; | |
99 | check_doc (cmdlist, ""); | |
100 | SELF_CHECK (nr_failed_invariants == 0); | |
101 | } | |
102 | ||
103 | } /* namespace help_doc_tests */ | |
58e6ac70 PW |
104 | |
105 | /* Verify some invariants of GDB command structure. */ | |
106 | ||
107 | namespace command_structure_tests { | |
108 | ||
89bcba74 | 109 | /* Nr of commands in which a duplicated list is found. */ |
6bd434d6 | 110 | static unsigned int nr_duplicates = 0; |
89bcba74 | 111 | /* Nr of commands in a list having no valid prefix cmd. */ |
6bd434d6 | 112 | static unsigned int nr_invalid_prefixcmd = 0; |
58e6ac70 PW |
113 | |
114 | /* A map associating a list with the prefix leading to it. */ | |
115 | ||
6bd434d6 | 116 | static std::map<cmd_list_element **, const char *> lists; |
58e6ac70 PW |
117 | |
118 | /* Store each command list in lists, associated with the prefix to reach it. A | |
89bcba74 PW |
119 | list must only be found once. |
120 | ||
121 | Verifies that all elements of the list have the same non-null prefix | |
122 | command. */ | |
58e6ac70 PW |
123 | |
124 | static void | |
125 | traverse_command_structure (struct cmd_list_element **list, | |
126 | const char *prefix) | |
127 | { | |
89bcba74 | 128 | struct cmd_list_element *c, *prefixcmd; |
58e6ac70 PW |
129 | |
130 | auto dupl = lists.find (list); | |
131 | if (dupl != lists.end ()) | |
132 | { | |
133 | fprintf_filtered (gdb_stdout, | |
134 | "list %p duplicated," | |
135 | " reachable via prefix '%s' and '%s'." | |
136 | " Duplicated list first command is '%s'\n", | |
137 | list, | |
138 | prefix, dupl->second, | |
139 | (*list)->name); | |
140 | nr_duplicates++; | |
141 | return; | |
142 | } | |
143 | ||
144 | lists.insert ({list, prefix}); | |
145 | ||
89bcba74 PW |
146 | /* All commands of *list must have a prefix command equal to PREFIXCMD, |
147 | the prefix command of the first command. */ | |
148 | if (*list == nullptr) | |
149 | prefixcmd = nullptr; /* A prefix command with an empty subcommand list. */ | |
150 | else | |
151 | prefixcmd = (*list)->prefix; | |
152 | ||
58e6ac70 PW |
153 | /* Walk through the commands. */ |
154 | for (c = *list; c; c = c->next) | |
155 | { | |
156 | /* If this command has subcommands and is not an alias, | |
157 | traverse the subcommands. */ | |
3d0b3564 | 158 | if (c->is_prefix () && !c->is_alias ()) |
58e6ac70 PW |
159 | { |
160 | /* Recursively call ourselves on the subcommand list, | |
161 | passing the right prefix in. */ | |
14b42fc4 | 162 | traverse_command_structure (c->subcommands, c->prefixname ().c_str ()); |
58e6ac70 | 163 | } |
89bcba74 PW |
164 | if (prefixcmd != c->prefix |
165 | || (prefixcmd == nullptr && *list != cmdlist)) | |
166 | { | |
167 | if (c->prefix == nullptr) | |
168 | fprintf_filtered (gdb_stdout, | |
169 | "list %p reachable via prefix '%s'." | |
170 | " command '%s' has null prefixcmd\n", | |
171 | list, | |
172 | prefix, c->name); | |
173 | else | |
174 | fprintf_filtered (gdb_stdout, | |
175 | "list %p reachable via prefix '%s'." | |
176 | " command '%s' has a different prefixcmd\n", | |
177 | list, | |
178 | prefix, c->name); | |
179 | nr_invalid_prefixcmd++; | |
180 | } | |
58e6ac70 PW |
181 | } |
182 | } | |
183 | ||
184 | /* Verify that a list of commands is present in the tree only once. */ | |
185 | ||
186 | static void | |
187 | command_structure_invariants_tests () | |
188 | { | |
189 | nr_duplicates = 0; | |
89bcba74 PW |
190 | nr_invalid_prefixcmd = 0; |
191 | ||
58e6ac70 PW |
192 | traverse_command_structure (&cmdlist, ""); |
193 | ||
194 | /* Release memory, be ready to be re-run. */ | |
195 | lists.clear (); | |
196 | ||
197 | SELF_CHECK (nr_duplicates == 0); | |
89bcba74 | 198 | SELF_CHECK (nr_invalid_prefixcmd == 0); |
58e6ac70 PW |
199 | } |
200 | ||
201 | } | |
202 | ||
d2834edc PW |
203 | } /* namespace selftests */ |
204 | ||
58e6ac70 | 205 | void _initialize_command_def_selftests (); |
d2834edc | 206 | void |
58e6ac70 | 207 | _initialize_command_def_selftests () |
d2834edc PW |
208 | { |
209 | selftests::register_test | |
210 | ("help_doc_invariants", | |
211 | selftests::help_doc_tests::help_doc_invariants_tests); | |
58e6ac70 PW |
212 | |
213 | selftests::register_test | |
214 | ("command_structure_invariants", | |
215 | selftests::command_structure_tests::command_structure_invariants_tests); | |
d2834edc | 216 | } |