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 <tap/basic.h>
47 testproc(struct cmd_syndesc *as, void *rock)
49 is_string("foo", as->parms[FIRST_OFF].items->data,
50 "first option matches");
51 is_string("bar", as->parms[SECOND_OFF].items->data,
52 "second option matches");
53 ok(as->parms[FLAG_OFF].items != NULL,
60 main(int argc, char **argv)
63 struct cmd_syndesc *opts;
64 struct cmd_syndesc *retopts;
68 char *retstring = NULL;
72 initialize_CMD_error_table();
74 opts = cmd_CreateSyntax(NULL, testproc, NULL, NULL);
75 cmd_AddParm(opts, "-flag", CMD_FLAG, CMD_OPTIONAL, "a flag");
76 cmd_AddParm(opts, "-first", CMD_SINGLE, CMD_REQUIRED, "first option");
77 cmd_AddParm(opts, "-second", CMD_LIST, CMD_OPTIONAL, "second option");
79 /* A simple command line */
80 code = cmd_ParseLine("-first foo -second bar -flag", tv, &tc, 100);
81 is_int(0, code, "cmd_ParseLine succeeds");
82 code = cmd_Dispatch(tc, tv);
83 is_int(0, code, "dispatching simple comamnd line succeeds");
84 code = cmd_Parse(tc, tv, &retopts);
85 is_int(0, code, "parsing simple command line succeeds");
86 is_string("foo", retopts->parms[FIRST_OFF].items->data, " ... 1st option matches");
87 is_string("bar", retopts->parms[SECOND_OFF].items->data, " ... 2nd option matches");
88 ok(retopts->parms[FLAG_OFF].items != NULL, " ... 3rd option matches");
89 cmd_FreeOptions(&retopts);
93 code = cmd_ParseLine("-first foo -second bar -third -flag", tv, &tc, 100);
94 is_int(0, code, "cmd_ParseLine succeeds");
95 code = cmd_Dispatch(tc, tv);
96 is_int(CMD_UNKNOWNSWITCH, code, "invalid options fail as expected");
97 code = cmd_Parse(tc, tv, &retopts);
98 is_int(CMD_UNKNOWNSWITCH, code, "and still fail with cmd_Parse");
101 /* missing parameter */
102 code = cmd_ParseLine("-first foo -second -flag", tv, &tc, 100);
103 is_int(0, code, "cmd_ParseLine succeeds");
104 code = cmd_Dispatch(tc, tv);
105 is_int(CMD_TOOFEW, code, "missing parameters fail as expected");
106 code = cmd_Parse(tc, tv, &retopts);
107 is_int(CMD_TOOFEW, code, "and still fail with cmd_Parse");
111 code = cmd_ParseLine("-second bar -third -flag", tv, &tc, 100);
112 is_int(0, code, "cmd_ParseLine succeeds");
113 code = cmd_Dispatch(tc, tv);
114 is_int(CMD_UNKNOWNSWITCH, code, "missing options fail as expected");
115 code = cmd_Parse(tc, tv, &retopts);
116 is_int(CMD_UNKNOWNSWITCH, code, "and still fail with cmd_Parse");
119 code = cmd_ParseLine("-first foo baz -second bar -third -flag", tv, &tc, 100);
120 is_int(0, code, "cmd_ParseLine succeeds");
121 code = cmd_Dispatch(tc, tv);
122 is_int(CMD_NOTLIST, code, "too many parameters fails as expected");
123 code = cmd_Parse(tc, tv, &retopts);
124 is_int(CMD_NOTLIST, code, "and still fail with cmd_Parse");
127 /* Positional parameters */
128 code = cmd_ParseLine("foo bar -flag", tv, &tc, 100);
129 is_int(0, code, "cmd_ParseLine succeeds");
130 code = cmd_Dispatch(tc, tv);
131 is_int(0, code, "dispatching positional parameters succeeds");
132 code = cmd_Parse(tc, tv, &retopts);
133 is_int(0, code, "and works with cmd_Parse");
134 cmd_FreeOptions(&retopts);
138 code = cmd_ParseLine("-fi foo -s bar -flag", tv, &tc, 100);
139 is_int(0, code, "cmd_ParseLine succeeds");
140 code = cmd_Dispatch(tc, tv);
141 is_int(0, code, "dispatching abbreviations succeeds");
142 code = cmd_Parse(tc, tv, &retopts);
143 is_int(0, code, "and works with cmd_Parse");
144 cmd_FreeOptions(&retopts);
149 code = cmd_ParseLine("-f foo -s bar -flag", tv, &tc, 100);
150 is_int(0, code, "cmd_ParseLine succeeds");
151 code = cmd_Dispatch(tc, tv);
152 is_int(CMD_UNKNOWNSWITCH, code, "ambiguous abbreviations correctly fail");
153 code = cmd_Parse(tc, tv, &retopts);
154 is_int(CMD_UNKNOWNSWITCH, code, "and fail with cmd_Parse too");
157 /* Disable positional commands */
158 cmd_DisablePositionalCommands();
159 code = cmd_ParseLine("foo bar -flag", tv, &tc, 100);
160 is_int(0, code, "cmd_ParseLine succeeds");
161 code = cmd_Dispatch(tc, tv);
162 is_int(CMD_NOTLIST, code, "positional parameters can be disabled");
163 code = cmd_Parse(tc, tv, &retopts);
164 is_int(CMD_NOTLIST, code, "and fail with cmd_Parse too");
167 /* Disable abbreviations */
168 cmd_DisableAbbreviations();
169 code = cmd_ParseLine("-fi foo -s bar -flag", tv, &tc, 100);
170 is_int(0, code, "cmd_ParseLine succeeds");
171 code = cmd_Dispatch(tc, tv);
172 is_int(CMD_UNKNOWNSWITCH, code, "dispatching abbreviations succeeds");
173 code = cmd_Parse(tc, tv, &retopts);
174 is_int(CMD_UNKNOWNSWITCH, code, "and fail with cmd_Parse too");
178 /* Try the new cmd_Parse function with something different*/
179 code = cmd_ParseLine("-first one -second two -flag", tv, &tc, 100);
180 is_int(0, code, "cmd_ParseLine succeeds");
181 code = cmd_Parse(tc, tv, &retopts);
182 is_int(0, code, "Parsing with cmd_Parse works");
183 is_string("one", retopts->parms[FIRST_OFF].items->data, " ... 1st option matches");
184 is_string("two", retopts->parms[SECOND_OFF].items->data, " ... 2nd option matches");
185 ok(retopts->parms[FLAG_OFF].items != NULL, " ... 3rd option matches");
187 cmd_FreeOptions(&retopts);
189 /* Try adding a couple of parameters at specific positions */
190 cmd_AddParmAtOffset(opts, "-fifth", CMD_SINGLE, CMD_OPTIONAL,
191 "fifth option", FIFTH_OFF);
192 cmd_AddParmAtOffset(opts, "-fourth", CMD_SINGLE, CMD_OPTIONAL,
193 "fourth option", FOURTH_OFF);
194 code = cmd_ParseLine("-first a -fourth b -fifth c", tv, &tc, 100);
195 is_int(0, code, "cmd_ParseLine succeeds");
196 code = cmd_Parse(tc, tv, &retopts);
197 is_int(0, code, "parsing our new options succeeds");
198 is_string("b", retopts->parms[FOURTH_OFF].items->data, " Fourth option in right place");
199 is_string("c", retopts->parms[FIFTH_OFF].items->data, " Fifth option in right place");
200 cmd_FreeOptions(&retopts);
203 /* Check Accessors */
204 code = cmd_ParseLine("-first 1 -second second -flag", tv, &tc, 100);
205 is_int(0, code, "cmd_ParseLine succeeds");
206 code = cmd_Parse(tc, tv, &retopts);
208 code = cmd_OptionAsInt(retopts, FIRST_OFF, &retval);
209 is_int(0, code, "cmd_OptionsAsInt succeeds");
210 is_int(1, retval, " ... and returns correct value");
212 code = cmd_OptionAsString(retopts, SECOND_OFF, &retstring);
213 is_int(0, code, "cmd_OptionsAsString succeeds");
214 is_string("second", retstring, " ... and returns correct value");
218 code = cmd_OptionAsFlag(retopts, FLAG_OFF, &retval);
219 is_int(0, code, "cmd_OptionsAsFlag succeeds");
220 ok(retval, " ... and flag is correct");
222 cmd_FreeOptions(&retopts);
226 code = cmd_AddParmAlias(opts, SECOND_OFF, "-twa");
227 is_int(0, code, "cmd_AddParmAlias succeeds");
229 code = cmd_ParseLine("-first 1 -twa tup", tv, &tc, 100);
230 is_int(0, code, "cmd_ParseLine succeeds");
231 code = cmd_Parse(tc, tv, &retopts);
232 is_int(0, code, "cmd_Parse succeeds for alias");
233 cmd_OptionAsString(retopts, SECOND_OFF, &retstring);
234 is_string("tup", retstring, " ... and we have the correct value");
238 cmd_FreeOptions(&retopts);
241 /* Add something that can be a flag or a value, and put something after
242 * it so we can check for parse problems*/
243 cmd_AddParm(opts, "-perhaps", CMD_SINGLE_OR_FLAG, CMD_OPTIONAL,
245 cmd_AddParm(opts, "-sanity", CMD_SINGLE, CMD_OPTIONAL, "sanity check");
247 /* Try using as an option */
249 code = cmd_ParseLine("-first 1 -perhaps 2 -sanity 3", tv, &tc, 100);
250 is_int(0, code, "cmd_ParseLine succeeds");
251 code = cmd_Parse(tc, tv, &retopts);
252 is_int(0, code, "cmd_Parse succeeds for option-as-flag as opt");
253 code = cmd_OptionAsInt(retopts, PERHAPS_OFF, &retval);
254 is_int(0, code, "cmd_OptionAsInt succeeds");
255 is_int(2, retval, " ... and we have the correct value");
256 cmd_FreeOptions(&retopts);
259 /* And now, as a flag */
261 code = cmd_ParseLine("-first 1 -perhaps -sanity 3", tv, &tc, 100);
262 is_int(0, code, "cmd_ParseLine succeeds");
263 code = cmd_Parse(tc, tv, &retopts);
264 is_int(0, code, "cmd_Parse succeeds for option-as-flag as flag");
265 code = cmd_OptionAsInt(retopts, PERHAPS_OFF, &retval);
266 is_int(CMD_MISSING, code, " ... pulling out a value fails as expected");
267 cmd_OptionAsFlag(retopts, PERHAPS_OFF, &retval);
268 ok(retval, " ... but parsing as a flag works");
269 cmd_FreeOptions(&retopts);
272 /* Check that we can produce help output */
273 code = cmd_ParseLine("-help", tv, &tc, 100);
274 is_int(0, code, "cmd_ParseLine succeeds");
275 code = cmd_Parse(tc, tv, &retopts);
276 is_int(CMD_USAGE, code, "cmd_Parse returns usage error with help output");
277 ok(retopts == NULL, " ... and options is empty");
279 /* Check splitting with '=' */
281 code = cmd_ParseLine("-first 1 -perhaps=6 -sanity=3", tv, &tc, 100);
282 is_int(0, code, "cmd_ParseLine succeeds");
283 code = cmd_Parse(tc, tv, &retopts);
284 is_int(0, code, "cmd_Parse succeeds for items split with '='");
285 code = cmd_OptionAsInt(retopts, PERHAPS_OFF, &retval);
286 is_int(0, code, "cmd_OptionAsInt succeeds");
287 is_int(6, retval, " ... and we have the correct value once");
288 code = cmd_OptionAsInt(retopts, SANITY_OFF, &retval);
289 is_int(0, code, "cmd_OptionAsInt succeeds");
290 is_int(3, retval, " ... and we have the correct value twice");
291 cmd_FreeOptions(&retopts);