725e84f201b4f8c5d2be0b002479a9c7c758defa
[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 <tap/basic.h>
37
38 #define FIRST_OFF   0
39 #define SECOND_OFF  1
40 #define FLAG_OFF    2
41 #define FOURTH_OFF  4
42 #define FIFTH_OFF   5
43 #define PERHAPS_OFF 6
44 #define SANITY_OFF  7
45
46 static int
47 testproc(struct cmd_syndesc *as, void *rock)
48 {
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,
54        "flag is set");
55
56     return 0;
57 }
58
59 int
60 main(int argc, char **argv)
61 {
62     char *tv[100];
63     struct cmd_syndesc *opts;
64     struct cmd_syndesc *retopts;
65     int code;
66     int tc;
67     int retval;
68     char *retstring = NULL;
69
70     plan(79);
71
72     initialize_CMD_error_table();
73
74     opts = cmd_CreateSyntax(NULL, testproc, NULL, NULL);
75     cmd_AddParm(opts, "-first", CMD_SINGLE, CMD_REQUIRED, "first option");
76     cmd_AddParm(opts, "-second", CMD_LIST, CMD_OPTIONAL, "second option");
77     cmd_AddParm(opts, "-flag", CMD_FLAG, CMD_OPTIONAL, "a flag");
78
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);
90     cmd_FreeArgv(tv);
91
92     /* unknown switch */
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");
99     cmd_FreeArgv(tv);
100
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");
108     cmd_FreeArgv(tv);
109
110     /* missing option */
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");
117     cmd_FreeArgv(tv);
118
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");
125     cmd_FreeArgv(tv);
126
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);
135     cmd_FreeArgv(tv);
136
137     /* Abbreviations */
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);
145
146     cmd_FreeArgv(tv);
147
148     /* Ambiguous */
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");
155     cmd_FreeArgv(tv);
156
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");
165     cmd_FreeArgv(tv);
166
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");
175
176     cmd_FreeArgv(tv);
177
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");
186
187     cmd_FreeOptions(&retopts);
188     cmd_FreeArgv(tv);
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);
201     cmd_FreeArgv(tv);
202
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);
207
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");
211
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");
215     free(retstring);
216     retstring = NULL;
217
218     code = cmd_OptionAsFlag(retopts, FLAG_OFF, &retval);
219     is_int(0, code, "cmd_OptionsAsFlag succeeds");
220     ok(retval, " ... and flag is correct");
221
222     cmd_FreeOptions(&retopts);
223     cmd_FreeArgv(tv);
224
225     /* Add an alias */
226     code = cmd_AddParmAlias(opts, SECOND_OFF, "-twa");
227     is_int(0, code, "cmd_AddParmAlias succeeds");
228
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");
235     free(retstring);
236     retstring = NULL;
237
238     cmd_FreeOptions(&retopts);
239     cmd_FreeArgv(tv);
240
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,
244                 "what am I");
245     cmd_AddParm(opts, "-sanity", CMD_SINGLE, CMD_OPTIONAL, "sanity check");
246
247     /* Try using as an option */
248
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);
257     cmd_FreeArgv(tv);
258
259     /* And now, as a flag */
260
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);
270     cmd_FreeArgv(tv);
271
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");
278
279     /* Check splitting with '=' */
280
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);
292     cmd_FreeArgv(tv);
293
294     return 0;
295 }
296