1 /* $OpenBSD: optionstest.c,v 1.8 2015/01/22 05:48:00 doug Exp $ */
2 /*
3 * Copyright (c) 2014 Joel Sing <jsing@openbsd.org>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21
22 #include <openssl/bio.h>
23 #include <openssl/conf.h>
24
25 #include <apps.h>
26 #include <apps.c>
27 #include <strtonum.c>
28
29 /* Needed to keep apps.c happy... */
30 BIO *bio_err;
31 CONF *config;
32
33 static int argfunc(char *arg);
34 static int defaultarg(int argc, char **argv, int *argsused);
35 static int multiarg(int argc, char **argv, int *argsused);
36
37 static struct {
38 char *arg;
39 int flag;
40 } test_config;
41
42 static struct option test_options[] = {
43 {
44 .name = "arg",
45 .argname = "argname",
46 .type = OPTION_ARG,
47 .opt.arg = &test_config.arg,
48 },
49 {
50 .name = "argfunc",
51 .argname = "argname",
52 .type = OPTION_ARG_FUNC,
53 .opt.argfunc = argfunc,
54 },
55 {
56 .name = "flag",
57 .type = OPTION_FLAG,
58 .opt.flag = &test_config.flag,
59 },
60 {
61 .name = "multiarg",
62 .type = OPTION_ARGV_FUNC,
63 .opt.argvfunc = multiarg,
64 },
65 {
66 .name = NULL,
67 .type = OPTION_ARGV_FUNC,
68 .opt.argvfunc = defaultarg,
69 },
70 { NULL },
71 };
72
73 char *args1[] = { "opts" };
74 char *args2[] = { "opts", "-arg", "arg", "-flag" };
75 char *args3[] = { "opts", "-arg", "arg", "-flag", "unnamed" };
76 char *args4[] = { "opts", "-arg", "arg", "unnamed", "-flag" };
77 char *args5[] = { "opts", "unnamed1", "-arg", "arg", "-flag", "unnamed2" };
78 char *args6[] = { "opts", "-argfunc", "arg", "-flag" };
79 char *args7[] = { "opts", "-arg", "arg", "-flag", "-", "-unnamed" };
80 char *args8[] = { "opts", "-arg", "arg", "-flag", "file1", "file2", "file3" };
81 char *args9[] = { "opts", "-arg", "arg", "-flag", "file1", "-file2", "file3" };
82 char *args10[] = { "opts", "-arg", "arg", "-flag", "-", "file1", "file2" };
83 char *args11[] = { "opts", "-arg", "arg", "-flag", "-", "-file1", "-file2" };
84 char *args12[] = { "opts", "-multiarg", "arg1", "arg2", "-flag", "unnamed" };
85 char *args13[] = { "opts", "-multiargz", "arg1", "arg2", "-flagz", "unnamed" };
86
87 struct options_test {
88 int argc;
89 char **argv;
90 enum {
91 OPTIONS_TEST_NONE,
92 OPTIONS_TEST_UNNAMED,
93 OPTIONS_TEST_ARGSUSED,
94 } type;
95 char *unnamed;
96 int used;
97 int want;
98 char *wantarg;
99 int wantflag;
100 };
101
102 struct options_test options_tests[] = {
103 {
104 /* Test 1 - No arguments (only program name). */
105 .argc = 1,
106 .argv = args1,
107 .type = OPTIONS_TEST_NONE,
108 .want = 0,
109 .wantarg = NULL,
110 .wantflag = 0,
111 },
112 {
113 /* Test 2 - Named arguments (unnamed not permitted). */
114 .argc = 4,
115 .argv = args2,
116 .type = OPTIONS_TEST_NONE,
117 .want = 0,
118 .wantarg = "arg",
119 .wantflag = 1,
120 },
121 {
122 /* Test 3 - Named arguments (unnamed permitted). */
123 .argc = 4,
124 .argv = args2,
125 .type = OPTIONS_TEST_UNNAMED,
126 .unnamed = NULL,
127 .want = 0,
128 .wantarg = "arg",
129 .wantflag = 1,
130 },
131 {
132 /* Test 4 - Named and single unnamed (unnamed not permitted). */
133 .argc = 5,
134 .argv = args3,
135 .type = OPTIONS_TEST_NONE,
136 .want = 1,
137 },
138 {
139 /* Test 5 - Named and single unnamed (unnamed permitted). */
140 .argc = 5,
141 .argv = args3,
142 .type = OPTIONS_TEST_UNNAMED,
143 .unnamed = "unnamed",
144 .want = 0,
145 .wantarg = "arg",
146 .wantflag = 1,
147 },
148 {
149 /* Test 6 - Named and single unnamed (different sequence). */
150 .argc = 5,
151 .argv = args4,
152 .type = OPTIONS_TEST_UNNAMED,
153 .unnamed = "unnamed",
154 .want = 0,
155 .wantarg = "arg",
156 .wantflag = 1,
157 },
158 {
159 /* Test 7 - Multiple unnamed arguments (should fail). */
160 .argc = 6,
161 .argv = args5,
162 .type = OPTIONS_TEST_UNNAMED,
163 .want = 1,
164 },
165 {
166 /* Test 8 - Function. */
167 .argc = 4,
168 .argv = args6,
169 .type = OPTIONS_TEST_NONE,
170 .want = 0,
171 .wantarg = "arg",
172 .wantflag = 1,
173 },
174 {
175 /* Test 9 - Named and single unnamed (hyphen separated). */
176 .argc = 6,
177 .argv = args7,
178 .type = OPTIONS_TEST_UNNAMED,
179 .unnamed = "-unnamed",
180 .want = 0,
181 .wantarg = "arg",
182 .wantflag = 1,
183 },
184 {
185 /* Test 10 - Named and multiple unnamed. */
186 .argc = 7,
187 .argv = args8,
188 .used = 4,
189 .type = OPTIONS_TEST_ARGSUSED,
190 .want = 0,
191 .wantarg = "arg",
192 .wantflag = 1,
193 },
194 {
195 /* Test 11 - Named and multiple unnamed. */
196 .argc = 7,
197 .argv = args9,
198 .used = 4,
199 .type = OPTIONS_TEST_ARGSUSED,
200 .want = 0,
201 .wantarg = "arg",
202 .wantflag = 1,
203 },
204 {
205 /* Test 12 - Named and multiple unnamed. */
206 .argc = 7,
207 .argv = args10,
208 .used = 5,
209 .type = OPTIONS_TEST_ARGSUSED,
210 .want = 0,
211 .wantarg = "arg",
212 .wantflag = 1,
213 },
214 {
215 /* Test 13 - Named and multiple unnamed. */
216 .argc = 7,
217 .argv = args11,
218 .used = 5,
219 .type = OPTIONS_TEST_ARGSUSED,
220 .want = 0,
221 .wantarg = "arg",
222 .wantflag = 1,
223 },
224 {
225 /* Test 14 - Named only. */
226 .argc = 4,
227 .argv = args2,
228 .used = 4,
229 .type = OPTIONS_TEST_ARGSUSED,
230 .want = 0,
231 .wantarg = "arg",
232 .wantflag = 1,
233 },
234 {
235 /* Test 15 - Multiple argument callback. */
236 .argc = 6,
237 .argv = args12,
238 .unnamed = "unnamed",
239 .type = OPTIONS_TEST_UNNAMED,
240 .want = 0,
241 .wantarg = NULL,
242 .wantflag = 1,
243 },
244 {
245 /* Test 16 - Multiple argument callback. */
246 .argc = 6,
247 .argv = args12,
248 .used = 5,
249 .type = OPTIONS_TEST_ARGSUSED,
250 .want = 0,
251 .wantarg = NULL,
252 .wantflag = 1,
253 },
254 {
255 /* Test 17 - Default callback. */
256 .argc = 6,
257 .argv = args13,
258 .unnamed = "unnamed",
259 .type = OPTIONS_TEST_UNNAMED,
260 .want = 0,
261 .wantarg = NULL,
262 .wantflag = 1,
263 },
264 {
265 /* Test 18 - Default callback. */
266 .argc = 6,
267 .argv = args13,
268 .used = 5,
269 .type = OPTIONS_TEST_ARGSUSED,
270 .want = 0,
271 .wantarg = NULL,
272 .wantflag = 1,
273 },
274 };
275
276 #define N_OPTIONS_TESTS \
277 (sizeof(options_tests) / sizeof(*options_tests))
278
279 static int
argfunc(char * arg)280 argfunc(char *arg)
281 {
282 test_config.arg = arg;
283 return (0);
284 }
285
286 static int
defaultarg(int argc,char ** argv,int * argsused)287 defaultarg(int argc, char **argv, int *argsused)
288 {
289 if (argc < 1)
290 return (1);
291
292 if (strcmp(argv[0], "-multiargz") == 0) {
293 if (argc < 3)
294 return (1);
295 *argsused = 3;
296 return (0);
297 } else if (strcmp(argv[0], "-flagz") == 0) {
298 test_config.flag = 1;
299 *argsused = 1;
300 return (0);
301 }
302
303 return (1);
304 }
305
306 static int
multiarg(int argc,char ** argv,int * argsused)307 multiarg(int argc, char **argv, int *argsused)
308 {
309 if (argc < 3)
310 return (1);
311
312 *argsused = 3;
313 return (0);
314 }
315
316 static int
do_options_test(int test_no,struct options_test * ot)317 do_options_test(int test_no, struct options_test *ot)
318 {
319 int *argsused = NULL;
320 char *unnamed = NULL;
321 char **arg = NULL;
322 int used = 0;
323 int ret;
324
325 if (ot->type == OPTIONS_TEST_UNNAMED)
326 arg = &unnamed;
327 else if (ot->type == OPTIONS_TEST_ARGSUSED)
328 argsused = &used;
329
330 memset(&test_config, 0, sizeof(test_config));
331 ret = options_parse(ot->argc, ot->argv, test_options, arg, argsused);
332 if (ret != ot->want) {
333 fprintf(stderr, "FAIL: test %i options_parse() returned %i, "
334 "want %i\n", test_no, ret, ot->want);
335 return (1);
336 }
337 if (ret != 0)
338 return (0);
339
340 if ((test_config.arg != NULL || ot->wantarg != NULL) &&
341 (test_config.arg == NULL || ot->wantarg == NULL ||
342 strcmp(test_config.arg, ot->wantarg) != 0)) {
343 fprintf(stderr, "FAIL: test %i got arg '%s', want '%s'\n",
344 test_no, test_config.arg, ot->wantarg);
345 return (1);
346 }
347 if (test_config.flag != ot->wantflag) {
348 fprintf(stderr, "FAIL: test %i got flag %i, want %i\n",
349 test_no, test_config.flag, ot->wantflag);
350 return (1);
351 }
352 if (ot->type == OPTIONS_TEST_UNNAMED &&
353 (unnamed != NULL || ot->unnamed != NULL) &&
354 (unnamed == NULL || ot->unnamed == NULL ||
355 strcmp(unnamed, ot->unnamed) != 0)) {
356 fprintf(stderr, "FAIL: test %i got unnamed '%s', want '%s'\n",
357 test_no, unnamed, ot->unnamed);
358 return (1);
359 }
360 if (ot->type == OPTIONS_TEST_ARGSUSED && used != ot->used) {
361 fprintf(stderr, "FAIL: test %i got used %i, want %i\n",
362 test_no, used, ot->used);
363 return (1);
364 }
365
366 return (0);
367 }
368
369 int
main(int argc,char ** argv)370 main(int argc, char **argv)
371 {
372 int failed = 0;
373 size_t i;
374
375 for (i = 0; i < N_OPTIONS_TESTS; i++) {
376 printf("Test %d%s\n", (int)(i + 1), options_tests[i].want == 0 ?
377 "" : " is expected to complain");
378 failed += do_options_test(i + 1, &options_tests[i]);
379 }
380
381 return (failed);
382 }
383