tests: Start using the upstream C TAP harness
[openafs.git] / tests / cmd / command-t.c
1 /*
2  * Copyright (c) 2010 Your File System Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
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.
12  *
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.
23  */
24
25 /*
26  * Test the command line parsing library
27  */
28
29 #include <afsconfig.h>
30 #include <afs/param.h>
31
32 #include <roken.h>
33
34 #include <afs/cmd.h>
35
36 #include <tests/tap/basic.h>
37
38 enum cmdOptions {
39    copt_flag = 0,
40    copt_first,
41    copt_second,
42    copt_sugar,
43    copt_fourth,
44    copt_fifth,
45    copt_perhaps,
46    copt_sanity
47 };
48
49 static int
50 testproc(struct cmd_syndesc *as, void *rock)
51 {
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,
57        "flag is set");
58
59     return 0;
60 }
61
62 int
63 main(int argc, char **argv)
64 {
65     char *tv[100];
66     struct cmd_syndesc *opts;
67     struct cmd_syndesc *retopts;
68     int code;
69     int tc;
70     int retval;
71     char *retstring = NULL;
72
73     plan(85);
74
75     initialize_CMD_error_table();
76
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");
81
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);
95     cmd_FreeArgv(tv);
96
97     /* unknown switch */
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");
104     cmd_FreeArgv(tv);
105
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");
113     cmd_FreeArgv(tv);
114
115     /* missing option */
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");
122     cmd_FreeArgv(tv);
123
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");
130     cmd_FreeArgv(tv);
131
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);
140     cmd_FreeArgv(tv);
141
142     /* Abbreviations */
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);
150
151     cmd_FreeArgv(tv);
152
153     /* Ambiguous */
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");
160     cmd_FreeArgv(tv);
161
162     /* Check that paramaters with abbreviation disabled don't make things
163      * ambiguous */
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);
173     cmd_FreeArgv(tv);
174
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");
183     cmd_FreeArgv(tv);
184
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");
193
194     cmd_FreeArgv(tv);
195
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");
206
207     cmd_FreeOptions(&retopts);
208     cmd_FreeArgv(tv);
209     /* Try adding a couple of parameters at specific positions */
210     cmd_AddParmAtOffset(opts, copt_fifth, "-fifth", CMD_SINGLE, CMD_OPTIONAL,
211                        "fifth option");
212     cmd_AddParmAtOffset(opts, copt_fourth, "-fourth", CMD_SINGLE, CMD_OPTIONAL,
213                        "fourth option" );
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);
223     cmd_FreeArgv(tv);
224
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);
229
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");
233
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");
237     free(retstring);
238     retstring = NULL;
239
240     code = cmd_OptionAsFlag(retopts, copt_flag, &retval);
241     is_int(0, code, "cmd_OptionsAsFlag succeeds");
242     ok(retval, " ... and flag is correct");
243
244     cmd_FreeOptions(&retopts);
245     cmd_FreeArgv(tv);
246
247     /* Add an alias */
248     code = cmd_AddParmAlias(opts, copt_second, "-twa");
249     is_int(0, code, "cmd_AddParmAlias succeeds");
250
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");
257     free(retstring);
258     retstring = NULL;
259
260     cmd_FreeOptions(&retopts);
261     cmd_FreeArgv(tv);
262
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,
266                 "what am I");
267     cmd_AddParm(opts, "-sanity", CMD_SINGLE, CMD_OPTIONAL, "sanity check");
268
269     /* Try using as an option */
270
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);
279     cmd_FreeArgv(tv);
280
281     /* And now, as a flag */
282
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);
292     cmd_FreeArgv(tv);
293
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");
300
301     /* Check splitting with '=' */
302
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);
314     cmd_FreeArgv(tv);
315
316     return 0;
317 }
318