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