2 * Copyright (c) 2010 Your File System Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
17 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
18 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 * Test the command line parsing library
29 #include <afsconfig.h>
30 #include <afs/param.h>
36 #include <tests/tap/basic.h>
50 testproc(struct cmd_syndesc *as, void *rock)
52 is_string("foo", as->parms[copt_first].items->data,
53 "first option matches");
54 is_string("bar", as->parms[copt_second].items->data,
55 "second option matches");
56 ok(as->parms[copt_flag].items != NULL,
63 main(int argc, char **argv)
66 struct cmd_syndesc *opts;
67 struct cmd_syndesc *retopts;
71 char *retstring = NULL;
75 initialize_CMD_error_table();
77 opts = cmd_CreateSyntax(NULL, testproc, NULL, NULL);
78 cmd_AddParm(opts, "-flag", CMD_FLAG, CMD_OPTIONAL, "a flag");
79 cmd_AddParm(opts, "-first", CMD_SINGLE, CMD_REQUIRED, "first option");
80 cmd_AddParm(opts, "-second", CMD_LIST, CMD_OPTIONAL, "second option");
82 /* A simple command line */
83 code = cmd_ParseLine("-first foo -second bar -flag", tv, &tc, 100);
84 is_int(0, code, "cmd_ParseLine succeeds");
85 code = cmd_Dispatch(tc, tv);
86 is_int(0, code, "dispatching simple comamnd line succeeds");
87 code = cmd_Parse(tc, tv, &retopts);
88 is_int(0, code, "parsing simple command line succeeds");
89 is_string("foo", retopts->parms[copt_first].items->data,
90 " ... 1st option matches");
91 is_string("bar", retopts->parms[copt_second].items->data,
92 " ... 2nd option matches");
93 ok(retopts->parms[copt_flag].items != NULL, " ... 3rd option matches");
94 cmd_FreeOptions(&retopts);
98 code = cmd_ParseLine("-first foo -second bar -third -flag", tv, &tc, 100);
99 is_int(0, code, "cmd_ParseLine succeeds");
100 code = cmd_Dispatch(tc, tv);
101 is_int(CMD_UNKNOWNSWITCH, code, "invalid options fail as expected");
102 code = cmd_Parse(tc, tv, &retopts);
103 is_int(CMD_UNKNOWNSWITCH, code, "and still fail with cmd_Parse");
106 /* missing parameter */
107 code = cmd_ParseLine("-first foo -second -flag", tv, &tc, 100);
108 is_int(0, code, "cmd_ParseLine succeeds");
109 code = cmd_Dispatch(tc, tv);
110 is_int(CMD_TOOFEW, code, "missing parameters fail as expected");
111 code = cmd_Parse(tc, tv, &retopts);
112 is_int(CMD_TOOFEW, code, "and still fail with cmd_Parse");
116 code = cmd_ParseLine("-second bar -third -flag", tv, &tc, 100);
117 is_int(0, code, "cmd_ParseLine succeeds");
118 code = cmd_Dispatch(tc, tv);
119 is_int(CMD_UNKNOWNSWITCH, code, "missing options fail as expected");
120 code = cmd_Parse(tc, tv, &retopts);
121 is_int(CMD_UNKNOWNSWITCH, code, "and still fail with cmd_Parse");
124 code = cmd_ParseLine("-first foo baz -second bar -third -flag", tv, &tc, 100);
125 is_int(0, code, "cmd_ParseLine succeeds");
126 code = cmd_Dispatch(tc, tv);
127 is_int(CMD_NOTLIST, code, "too many parameters fails as expected");
128 code = cmd_Parse(tc, tv, &retopts);
129 is_int(CMD_NOTLIST, code, "and still fail with cmd_Parse");
132 /* Positional parameters */
133 code = cmd_ParseLine("foo bar -flag", tv, &tc, 100);
134 is_int(0, code, "cmd_ParseLine succeeds");
135 code = cmd_Dispatch(tc, tv);
136 is_int(0, code, "dispatching positional parameters succeeds");
137 code = cmd_Parse(tc, tv, &retopts);
138 is_int(0, code, "and works with cmd_Parse");
139 cmd_FreeOptions(&retopts);
143 code = cmd_ParseLine("-fi foo -s bar -flag", tv, &tc, 100);
144 is_int(0, code, "cmd_ParseLine succeeds");
145 code = cmd_Dispatch(tc, tv);
146 is_int(0, code, "dispatching abbreviations succeeds");
147 code = cmd_Parse(tc, tv, &retopts);
148 is_int(0, code, "and works with cmd_Parse");
149 cmd_FreeOptions(&retopts);
154 code = cmd_ParseLine("-f foo -s bar -flag", tv, &tc, 100);
155 is_int(0, code, "cmd_ParseLine succeeds");
156 code = cmd_Dispatch(tc, tv);
157 is_int(CMD_UNKNOWNSWITCH, code, "ambiguous abbreviations correctly fail");
158 code = cmd_Parse(tc, tv, &retopts);
159 is_int(CMD_UNKNOWNSWITCH, code, "and fail with cmd_Parse too");
162 /* Check that paramaters with abbreviation disabled don't make things
164 cmd_AddParmAtOffset(opts, copt_sugar, "-sugar", CMD_SINGLE,
165 CMD_OPTIONAL | CMD_NOABBRV, "sugar with that");
166 code = cmd_ParseLine("-fi foo -s bar -flag", tv, &tc, 100);
167 is_int(0, code, "cmd_ParseLine succeeds");
168 code = cmd_Dispatch(tc, tv);
169 is_int(0, code, "disabling specific abbreviations succeeds");
170 code = cmd_Parse(tc, tv, &retopts);
171 is_int(0, code, "and works with cmd_Parse into the bargain");
172 cmd_FreeOptions(&retopts);
175 /* Disable positional commands */
176 cmd_DisablePositionalCommands();
177 code = cmd_ParseLine("foo bar -flag", tv, &tc, 100);
178 is_int(0, code, "cmd_ParseLine succeeds");
179 code = cmd_Dispatch(tc, tv);
180 is_int(CMD_NOTLIST, code, "positional parameters can be disabled");
181 code = cmd_Parse(tc, tv, &retopts);
182 is_int(CMD_NOTLIST, code, "and fail with cmd_Parse too");
185 /* Disable abbreviations */
186 cmd_DisableAbbreviations();
187 code = cmd_ParseLine("-fi foo -s bar -flag", tv, &tc, 100);
188 is_int(0, code, "cmd_ParseLine succeeds");
189 code = cmd_Dispatch(tc, tv);
190 is_int(CMD_UNKNOWNSWITCH, code, "dispatching abbreviations succeeds");
191 code = cmd_Parse(tc, tv, &retopts);
192 is_int(CMD_UNKNOWNSWITCH, code, "and fail with cmd_Parse too");
196 /* Try the new cmd_Parse function with something different*/
197 code = cmd_ParseLine("-first one -second two -flag", tv, &tc, 100);
198 is_int(0, code, "cmd_ParseLine succeeds");
199 code = cmd_Parse(tc, tv, &retopts);
200 is_int(0, code, "Parsing with cmd_Parse works");
201 is_string("one", retopts->parms[copt_first].items->data,
202 " ... 1st option matches");
203 is_string("two", retopts->parms[copt_second].items->data,
204 " ... 2nd option matches");
205 ok(retopts->parms[copt_flag].items != NULL, " ... 3rd option matches");
207 cmd_FreeOptions(&retopts);
209 /* Try adding a couple of parameters at specific positions */
210 cmd_AddParmAtOffset(opts, copt_fifth, "-fifth", CMD_SINGLE, CMD_OPTIONAL,
212 cmd_AddParmAtOffset(opts, copt_fourth, "-fourth", CMD_SINGLE, CMD_OPTIONAL,
214 code = cmd_ParseLine("-first a -fourth b -fifth c", tv, &tc, 100);
215 is_int(0, code, "cmd_ParseLine succeeds");
216 code = cmd_Parse(tc, tv, &retopts);
217 is_int(0, code, "parsing our new options succeeds");
218 is_string("b", retopts->parms[copt_fourth].items->data,
219 " Fourth option in right place");
220 is_string("c", retopts->parms[copt_fifth].items->data,
221 " Fifth option in right place");
222 cmd_FreeOptions(&retopts);
225 /* Check Accessors */
226 code = cmd_ParseLine("-first 1 -second second -flag", tv, &tc, 100);
227 is_int(0, code, "cmd_ParseLine succeeds");
228 code = cmd_Parse(tc, tv, &retopts);
230 code = cmd_OptionAsInt(retopts, copt_first, &retval);
231 is_int(0, code, "cmd_OptionsAsInt succeeds");
232 is_int(1, retval, " ... and returns correct value");
234 code = cmd_OptionAsString(retopts, copt_second, &retstring);
235 is_int(0, code, "cmd_OptionsAsString succeeds");
236 is_string("second", retstring, " ... and returns correct value");
240 code = cmd_OptionAsFlag(retopts, copt_flag, &retval);
241 is_int(0, code, "cmd_OptionsAsFlag succeeds");
242 ok(retval, " ... and flag is correct");
244 cmd_FreeOptions(&retopts);
248 code = cmd_AddParmAlias(opts, copt_second, "-twa");
249 is_int(0, code, "cmd_AddParmAlias succeeds");
251 code = cmd_ParseLine("-first 1 -twa tup", tv, &tc, 100);
252 is_int(0, code, "cmd_ParseLine succeeds");
253 code = cmd_Parse(tc, tv, &retopts);
254 is_int(0, code, "cmd_Parse succeeds for alias");
255 cmd_OptionAsString(retopts, copt_second, &retstring);
256 is_string("tup", retstring, " ... and we have the correct value");
260 cmd_FreeOptions(&retopts);
263 /* Add something that can be a flag or a value, and put something after
264 * it so we can check for parse problems*/
265 cmd_AddParm(opts, "-perhaps", CMD_SINGLE_OR_FLAG, CMD_OPTIONAL,
267 cmd_AddParm(opts, "-sanity", CMD_SINGLE, CMD_OPTIONAL, "sanity check");
269 /* Try using as an option */
271 code = cmd_ParseLine("-first 1 -perhaps 2 -sanity 3", tv, &tc, 100);
272 is_int(0, code, "cmd_ParseLine succeeds");
273 code = cmd_Parse(tc, tv, &retopts);
274 is_int(0, code, "cmd_Parse succeeds for option-as-flag as opt");
275 code = cmd_OptionAsInt(retopts, copt_perhaps, &retval);
276 is_int(0, code, "cmd_OptionAsInt succeeds");
277 is_int(2, retval, " ... and we have the correct value");
278 cmd_FreeOptions(&retopts);
281 /* And now, as a flag */
283 code = cmd_ParseLine("-first 1 -perhaps -sanity 3", tv, &tc, 100);
284 is_int(0, code, "cmd_ParseLine succeeds");
285 code = cmd_Parse(tc, tv, &retopts);
286 is_int(0, code, "cmd_Parse succeeds for option-as-flag as flag");
287 code = cmd_OptionAsInt(retopts, copt_perhaps, &retval);
288 is_int(CMD_MISSING, code, " ... pulling out a value fails as expected");
289 cmd_OptionAsFlag(retopts, copt_perhaps, &retval);
290 ok(retval, " ... but parsing as a flag works");
291 cmd_FreeOptions(&retopts);
294 /* Check that we can produce help output */
295 code = cmd_ParseLine("-help", tv, &tc, 100);
296 is_int(0, code, "cmd_ParseLine succeeds");
297 code = cmd_Parse(tc, tv, &retopts);
298 is_int(CMD_USAGE, code, "cmd_Parse returns usage error with help output");
299 ok(retopts == NULL, " ... and options is empty");
301 /* Check splitting with '=' */
303 code = cmd_ParseLine("-first 1 -perhaps=6 -sanity=3", tv, &tc, 100);
304 is_int(0, code, "cmd_ParseLine succeeds");
305 code = cmd_Parse(tc, tv, &retopts);
306 is_int(0, code, "cmd_Parse succeeds for items split with '='");
307 code = cmd_OptionAsInt(retopts, copt_perhaps, &retval);
308 is_int(0, code, "cmd_OptionAsInt succeeds");
309 is_int(6, retval, " ... and we have the correct value once");
310 code = cmd_OptionAsInt(retopts, copt_sanity, &retval);
311 is_int(0, code, "cmd_OptionAsInt succeeds");
312 is_int(3, retval, " ... and we have the correct value twice");
313 cmd_FreeOptions(&retopts);