xref: /dpdk/app/test/test_argparse.c (revision e9fd1ebf981f361844aea9ec94e17f4bda5e1479)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2024 HiSilicon Limited
3  */
4 
5 #include <stdio.h>
6 #include <string.h>
7 
8 #include <rte_argparse.h>
9 
10 #include "test.h"
11 
12 static int default_argc;
13 static char *default_argv[1];
14 
15 #define MAX_STRDUP_STORE_NUM	512
16 static char *strdup_store_array[MAX_STRDUP_STORE_NUM];
17 static uint32_t strdup_store_index;
18 
19 /*
20  * Define strdup wrapper.
21  * 1. Mainly to fix compile error "warning: assignment discards 'const'
22  *    qualifier from pointer target type [-Wdiscarded-qualifiers]" for
23  *    following code:
24  *      argv[x] = "100";
25  * 2. The strdup result will store in the strdup_store_array, and then
26  *    freed in the teardown function, prevent ASAN errors from being
27  *    triggered.
28  */
29 static char *
30 test_strdup(const char *str)
31 {
32 	char *s = strdup(str);
33 	if (s == NULL) {
34 		printf("strdup failed! exiting...\n");
35 		exit(-ENOMEM);
36 	}
37 	if (strdup_store_index >= MAX_STRDUP_STORE_NUM) {
38 		printf("too much strdup calls! exiting...\n");
39 		exit(-ERANGE);
40 	}
41 	strdup_store_array[strdup_store_index++] = s;
42 	return s;
43 }
44 
45 static int
46 test_argparse_setup(void)
47 {
48 	strdup_store_index = 0;
49 	default_argc = 1;
50 	default_argv[0] = test_strdup("test_argparse");
51 	return 0;
52 }
53 
54 static void
55 test_argparse_teardown(void)
56 {
57 	uint32_t i;
58 	printf("total used strdup_store_index = %u\n", strdup_store_index);
59 	for (i = 0; i < strdup_store_index; i++)
60 		free(strdup_store_array[i]);
61 	strdup_store_index = 0;
62 }
63 
64 static int
65 test_argparse_callback(uint32_t index, const char *value, void *opaque)
66 {
67 	RTE_SET_USED(index);
68 	RTE_SET_USED(value);
69 	RTE_SET_USED(opaque);
70 	return 0;
71 }
72 
73 /* valid templater, must contain at least two args. */
74 #define argparse_templater() { \
75 	.prog_name = "test_argparse", \
76 	.usage = "-a xx -b yy", \
77 	.descriptor = NULL, \
78 	.epilog = NULL, \
79 	.exit_on_error = false, \
80 	.callback = test_argparse_callback, \
81 	.args = { \
82 		{ "--abc", "-a", "abc argument", (void *)1, (void *)1, RTE_ARGPARSE_ARG_NO_VALUE | RTE_ARGPARSE_ARG_VALUE_INT }, \
83 		{ "--xyz", "-x", "xyz argument", (void *)1, (void *)2, RTE_ARGPARSE_ARG_NO_VALUE | RTE_ARGPARSE_ARG_VALUE_INT }, \
84 		ARGPARSE_ARG_END(), \
85 	}, \
86 }
87 
88 static void
89 test_argparse_copy(struct rte_argparse *dst, struct rte_argparse *src)
90 {
91 	uint32_t i;
92 	memcpy(dst, src, sizeof(*src));
93 	for (i = 0; /* NULL */; i++) {
94 		memcpy(&dst->args[i], &src->args[i], sizeof(src->args[i]));
95 		if (src->args[i].name_long == NULL)
96 			break;
97 	}
98 }
99 
100 static struct rte_argparse *
101 test_argparse_init_obj(void)
102 {
103 	static struct rte_argparse backup = argparse_templater();
104 	static struct rte_argparse obj = argparse_templater();
105 	/* Because obj may be overwritten, do a deep copy. */
106 	test_argparse_copy(&obj, &backup);
107 	return &obj;
108 }
109 
110 static int
111 test_argparse_invalid_basic_param(void)
112 {
113 	struct rte_argparse *obj;
114 	int ret;
115 
116 	obj = test_argparse_init_obj();
117 	obj->prog_name = NULL;
118 	ret = rte_argparse_parse(obj, default_argc, default_argv);
119 	TEST_ASSERT(ret == -EINVAL, "Argparse parse expect failed!");
120 
121 	obj = test_argparse_init_obj();
122 	obj->usage = NULL;
123 	ret = rte_argparse_parse(obj, default_argc, default_argv);
124 	TEST_ASSERT(ret == -EINVAL, "Argparse parse expect failed!");
125 
126 	return TEST_SUCCESS;
127 }
128 
129 static int
130 test_argparse_invalid_arg_name(void)
131 {
132 	struct rte_argparse *obj;
133 	int ret;
134 
135 	obj = test_argparse_init_obj();
136 	obj->args[0].name_long = "-ab";
137 	ret = rte_argparse_parse(obj, default_argc, default_argv);
138 	TEST_ASSERT(ret == -EINVAL, "Argparse parse expect failed!");
139 
140 	obj = test_argparse_init_obj();
141 	obj->args[0].name_long = "-abc";
142 	ret = rte_argparse_parse(obj, default_argc, default_argv);
143 	TEST_ASSERT(ret == -EINVAL, "Argparse parse expect failed!");
144 
145 	obj = test_argparse_init_obj();
146 	obj->args[0].name_long = "---c";
147 	ret = rte_argparse_parse(obj, default_argc, default_argv);
148 	TEST_ASSERT(ret == -EINVAL, "Argparse parse expect failed!");
149 
150 	obj = test_argparse_init_obj();
151 	obj->args[0].name_long = "abc";
152 	obj->args[0].name_short = "-a";
153 	ret = rte_argparse_parse(obj, default_argc, default_argv);
154 	TEST_ASSERT(ret == -EINVAL, "Argparse parse expect failed!");
155 
156 	obj = test_argparse_init_obj();
157 	obj->args[0].name_short = "a";
158 	ret = rte_argparse_parse(obj, default_argc, default_argv);
159 	TEST_ASSERT(ret == -EINVAL, "Argparse parse expect failed!");
160 
161 	obj = test_argparse_init_obj();
162 	obj->args[0].name_short = "abc";
163 	ret = rte_argparse_parse(obj, default_argc, default_argv);
164 	TEST_ASSERT(ret == -EINVAL, "Argparse parse expect failed!");
165 
166 	obj = test_argparse_init_obj();
167 	obj->args[0].name_short = "ab";
168 	ret = rte_argparse_parse(obj, default_argc, default_argv);
169 	TEST_ASSERT(ret == -EINVAL, "Argparse parse expect failed!");
170 
171 	return 0;
172 }
173 
174 static int
175 test_argparse_invalid_arg_help(void)
176 {
177 	struct rte_argparse *obj;
178 	int ret;
179 
180 	obj = test_argparse_init_obj();
181 	obj->args[0].help = NULL;
182 	ret = rte_argparse_parse(obj, default_argc, default_argv);
183 	TEST_ASSERT(ret == -EINVAL, "Argparse parse expect failed!");
184 
185 	return 0;
186 }
187 
188 static int
189 test_argparse_invalid_has_val(void)
190 {
191 	uint32_t set_mask[] = { 0,
192 				RTE_ARGPARSE_ARG_NO_VALUE,
193 				RTE_ARGPARSE_ARG_OPTIONAL_VALUE
194 			      };
195 	struct rte_argparse *obj;
196 	uint32_t index;
197 	int ret;
198 
199 	obj = test_argparse_init_obj();
200 	obj->args[0].flags &= ~0x3u;
201 	ret = rte_argparse_parse(obj, default_argc, default_argv);
202 	TEST_ASSERT(ret == -EINVAL, "Argparse parse expect failed!");
203 
204 	for (index = 0; index < RTE_DIM(set_mask); index++) {
205 		obj = test_argparse_init_obj();
206 		obj->args[0].name_long = "abc";
207 		obj->args[0].name_short = NULL;
208 		obj->args[0].flags &= ~0x3u;
209 		obj->args[0].flags |= set_mask[index];
210 		ret = rte_argparse_parse(obj, default_argc, default_argv);
211 		TEST_ASSERT(ret == -EINVAL, "Argparse parse expect failed!");
212 	}
213 
214 	return 0;
215 }
216 
217 static int
218 test_argparse_invalid_arg_saver(void)
219 {
220 	struct rte_argparse *obj;
221 	int ret;
222 
223 	/* test saver == NULL with val-type != 0. */
224 	obj = test_argparse_init_obj();
225 	obj->args[0].val_saver = NULL;
226 	obj->args[0].flags = RTE_ARGPARSE_ARG_NO_VALUE | RTE_ARGPARSE_ARG_VALUE_INT;
227 	ret = rte_argparse_parse(obj, default_argc, default_argv);
228 	TEST_ASSERT(ret == -EINVAL, "Argparse parse expect failed!");
229 
230 	/* test saver == NULL with callback is NULL. */
231 	obj = test_argparse_init_obj();
232 	obj->args[0].val_saver = NULL;
233 	obj->args[0].flags = RTE_ARGPARSE_ARG_NO_VALUE;
234 	obj->callback = NULL;
235 	ret = rte_argparse_parse(obj, default_argc, default_argv);
236 	TEST_ASSERT(ret == -EINVAL, "Argparse parse expect failed!");
237 
238 	/* test saver != NULL with val-type is zero! */
239 	obj = test_argparse_init_obj();
240 	obj->args[0].val_saver = (void *)1;
241 	obj->args[0].val_set = (void *)1;
242 	obj->args[0].flags = RTE_ARGPARSE_ARG_NO_VALUE;
243 	ret = rte_argparse_parse(obj, default_argc, default_argv);
244 	TEST_ASSERT(ret == -EINVAL, "Argparse parse expect failed!");
245 
246 	/* test saver != NULL with val-type is max. */
247 	obj = test_argparse_init_obj();
248 	obj->args[0].val_saver = (void *)1;
249 	obj->args[0].val_set = (void *)1;
250 	obj->args[0].flags = RTE_ARGPARSE_ARG_NO_VALUE | RTE_ARGPARSE_ARG_VALUE_MAX;
251 	ret = rte_argparse_parse(obj, default_argc, default_argv);
252 	TEST_ASSERT(ret == -EINVAL, "Argparse parse expect failed!");
253 
254 	/* test saver != NULL with required value, but val-set is not NULL. */
255 	obj = test_argparse_init_obj();
256 	obj->args[0].val_saver = (void *)1;
257 	obj->args[0].val_set = (void *)1;
258 	obj->args[0].flags = RTE_ARGPARSE_ARG_REQUIRED_VALUE | RTE_ARGPARSE_ARG_VALUE_INT;
259 	ret = rte_argparse_parse(obj, default_argc, default_argv);
260 	TEST_ASSERT(ret == -EINVAL, "Argparse parse expect failed!");
261 
262 	return 0;
263 }
264 
265 static int
266 test_argparse_invalid_arg_flags(void)
267 {
268 	struct rte_argparse *obj;
269 	int ret;
270 
271 	obj = test_argparse_init_obj();
272 	obj->args[0].flags |= ~0x107FFu;
273 	ret = rte_argparse_parse(obj, default_argc, default_argv);
274 	TEST_ASSERT(ret == -EINVAL, "Argparse parse expect failed!");
275 
276 	obj = test_argparse_init_obj();
277 	obj->args[0].name_long = "positional";
278 	obj->args[0].name_short = NULL;
279 	obj->args[0].val_saver = (void *)1;
280 	obj->args[0].val_set = (void *)1;
281 	obj->args[0].flags = RTE_ARGPARSE_ARG_REQUIRED_VALUE | RTE_ARGPARSE_ARG_VALUE_INT |
282 			     RTE_ARGPARSE_ARG_SUPPORT_MULTI;
283 	ret = rte_argparse_parse(obj, default_argc, default_argv);
284 	TEST_ASSERT(ret == -EINVAL, "Argparse parse expect failed!");
285 
286 	obj = test_argparse_init_obj();
287 	obj->args[0].flags |= RTE_ARGPARSE_ARG_SUPPORT_MULTI;
288 	ret = rte_argparse_parse(obj, default_argc, default_argv);
289 	TEST_ASSERT(ret == -EINVAL, "Argparse parse expect failed!");
290 
291 	obj = test_argparse_init_obj();
292 	obj->args[0].val_saver = NULL;
293 	obj->args[0].flags = RTE_ARGPARSE_ARG_REQUIRED_VALUE | RTE_ARGPARSE_ARG_SUPPORT_MULTI;
294 	obj->callback = NULL;
295 	ret = rte_argparse_parse(obj, default_argc, default_argv);
296 	TEST_ASSERT(ret == -EINVAL, "Argparse parse expect failed!");
297 
298 	return 0;
299 }
300 
301 static int
302 test_argparse_invalid_arg_repeat(void)
303 {
304 	struct rte_argparse *obj;
305 	int ret;
306 
307 	/* test for long name repeat! */
308 	obj = test_argparse_init_obj();
309 	obj->args[1].name_long = obj->args[0].name_long;
310 	ret = rte_argparse_parse(obj, default_argc, default_argv);
311 	TEST_ASSERT(ret == -EINVAL, "Argparse parse expect failed!");
312 
313 	/* test for short name repeat! */
314 	obj = test_argparse_init_obj();
315 	obj->args[1].name_short = obj->args[0].name_short;
316 	ret = rte_argparse_parse(obj, default_argc, default_argv);
317 	TEST_ASSERT(ret == -EINVAL, "Argparse parse expect failed!");
318 
319 	return 0;
320 }
321 
322 static int
323 test_argparse_invalid_option(void)
324 {
325 	struct rte_argparse *obj;
326 	char *argv[2];
327 	int ret;
328 
329 	obj = test_argparse_init_obj();
330 	argv[0] = test_strdup(obj->usage);
331 	argv[1] = test_strdup("--invalid");
332 	ret = rte_argparse_parse(obj, 2, argv);
333 	TEST_ASSERT(ret == -EINVAL, "Argparse parse expect failed!");
334 
335 	obj = test_argparse_init_obj();
336 	argv[0] = test_strdup(obj->usage);
337 	argv[1] = test_strdup("invalid");
338 	ret = rte_argparse_parse(obj, 2, argv);
339 	TEST_ASSERT(ret == -EINVAL, "Argparse parse expect failed!");
340 
341 	return 0;
342 }
343 
344 static int
345 test_argparse_opt_autosave_parse_int_of_no_val(void)
346 {
347 	uint32_t flags = RTE_ARGPARSE_ARG_NO_VALUE | RTE_ARGPARSE_ARG_VALUE_INT;
348 	struct rte_argparse *obj;
349 	int val_saver = 0;
350 	char *argv[2];
351 	int ret;
352 
353 	obj = test_argparse_init_obj();
354 	obj->args[0].name_long = "--test-long";
355 	obj->args[0].name_short = "-t";
356 	obj->args[0].val_saver = (void *)&val_saver;
357 	obj->args[0].val_set = (void *)100;
358 	obj->args[0].flags = flags;
359 	obj->args[1].name_long = NULL;
360 	argv[0] = test_strdup(obj->usage);
361 	argv[1] = test_strdup("--test-long");
362 	ret = rte_argparse_parse(obj, 2, argv);
363 	TEST_ASSERT(ret == 0, "Argparse parse expect success!");
364 	TEST_ASSERT(val_saver == 100, "Argparse parse expect success!");
365 
366 	obj->args[0].flags = flags;
367 	val_saver = 0;
368 	argv[1] = test_strdup("-t");
369 	ret = rte_argparse_parse(obj, 2, argv);
370 	TEST_ASSERT(ret == 0, "Argparse parse expect success!");
371 	TEST_ASSERT(val_saver == 100, "Argparse parse expect success!");
372 
373 	return 0;
374 }
375 
376 static int
377 test_argparse_opt_autosave_parse_int_of_required_val(void)
378 {
379 	uint32_t flags = RTE_ARGPARSE_ARG_REQUIRED_VALUE | RTE_ARGPARSE_ARG_VALUE_INT;
380 	struct rte_argparse *obj;
381 	int val_saver = 0;
382 	char *argv[3];
383 	int ret;
384 
385 	obj = test_argparse_init_obj();
386 	obj->args[0].name_long = "--test-long";
387 	obj->args[0].name_short = "-t";
388 	obj->args[0].val_saver = (void *)&val_saver;
389 	obj->args[0].val_set = NULL;
390 	obj->args[0].flags = flags;
391 	obj->args[1].name_long = NULL;
392 	argv[0] = test_strdup(obj->usage);
393 	argv[1] = test_strdup("--test-long");
394 	argv[2] = test_strdup("100");
395 	ret = rte_argparse_parse(obj, 3, argv);
396 	TEST_ASSERT(ret == 0, "Argparse parse expect success!");
397 	TEST_ASSERT(val_saver == 100, "Argparse parse expect success!");
398 
399 	obj->args[0].flags = flags;
400 	val_saver = 0;
401 	argv[1] = test_strdup("-t");
402 	ret = rte_argparse_parse(obj, 3, argv);
403 	TEST_ASSERT(ret == 0, "Argparse parse expect success!");
404 	TEST_ASSERT(val_saver == 100, "Argparse parse expect success!");
405 
406 	/* test invalid value. */
407 	obj->args[0].flags = flags;
408 	val_saver = 0;
409 	argv[1] = test_strdup("-t");
410 	argv[2] = test_strdup("100a");
411 	ret = rte_argparse_parse(obj, 3, argv);
412 	TEST_ASSERT(ret == -EINVAL, "Argparse parse expect failed!");
413 
414 	return 0;
415 }
416 
417 static int
418 test_argparse_opt_autosave_parse_int_of_optional_val(void)
419 {
420 	uint32_t flags = RTE_ARGPARSE_ARG_OPTIONAL_VALUE | RTE_ARGPARSE_ARG_VALUE_INT;
421 	struct rte_argparse *obj;
422 	int val_saver = 0;
423 	char *argv[2];
424 	int ret;
425 
426 	obj = test_argparse_init_obj();
427 	obj->args[0].name_long = "--test-long";
428 	obj->args[0].name_short = "-t";
429 	obj->args[0].val_saver = (void *)&val_saver;
430 	obj->args[0].val_set = (void *)100;
431 	obj->args[0].flags = flags;
432 	obj->args[1].name_long = NULL;
433 	argv[0] = test_strdup(obj->usage);
434 	argv[1] = test_strdup("--test-long");
435 	ret = rte_argparse_parse(obj, 2, argv);
436 	TEST_ASSERT(ret == 0, "Argparse parse expect success!");
437 	TEST_ASSERT(val_saver == 100, "Argparse parse expect success!");
438 	obj->args[0].flags = flags;
439 	val_saver = 0;
440 	argv[1] = test_strdup("-t");
441 	ret = rte_argparse_parse(obj, 2, argv);
442 	TEST_ASSERT(ret == 0, "Argparse parse expect success!");
443 	TEST_ASSERT(val_saver == 100, "Argparse parse expect success!");
444 
445 	/* test with value. */
446 	obj->args[0].flags = flags;
447 	val_saver = 0;
448 	argv[1] = test_strdup("--test-long=200");
449 	ret = rte_argparse_parse(obj, 2, argv);
450 	TEST_ASSERT(ret == 0, "Argparse parse expect success!");
451 	TEST_ASSERT(val_saver == 200, "Argparse parse expect success!");
452 	obj->args[0].flags = flags;
453 	val_saver = 0;
454 	argv[1] = test_strdup("-t=200");
455 	ret = rte_argparse_parse(obj, 2, argv);
456 	TEST_ASSERT(ret == 0, "Argparse parse expect success!");
457 	TEST_ASSERT(val_saver == 200, "Argparse parse expect success!");
458 
459 	/* test with option value, but with wrong value. */
460 	obj->args[0].flags = flags;
461 	val_saver = 0;
462 	argv[1] = test_strdup("--test-long=200a");
463 	ret = rte_argparse_parse(obj, 2, argv);
464 	TEST_ASSERT(ret == -EINVAL, "Argparse parse expect failed!");
465 	obj->args[0].flags = flags;
466 	val_saver = 0;
467 	argv[1] = test_strdup("-t=200a");
468 	ret = rte_argparse_parse(obj, 2, argv);
469 	TEST_ASSERT(ret == -EINVAL, "Argparse parse expect failed!");
470 
471 	return 0;
472 }
473 
474 static int
475 opt_callback_parse_int_of_no_val(uint32_t index, const char *value, void *opaque)
476 {
477 	RTE_SET_USED(index);
478 	if (value != NULL)
479 		return -EINVAL;
480 	*(int *)opaque = 100;
481 	return 0;
482 }
483 
484 static int
485 test_argparse_opt_callback_parse_int_of_no_val(void)
486 {
487 	struct rte_argparse *obj;
488 	int val_saver = 0;
489 	char *argv[2];
490 	int ret;
491 
492 	obj = test_argparse_init_obj();
493 	obj->callback = opt_callback_parse_int_of_no_val;
494 	obj->opaque = (void *)&val_saver;
495 	obj->args[0].name_long = "--test-long";
496 	obj->args[0].name_short = "-t";
497 	obj->args[0].val_saver = NULL;
498 	obj->args[0].val_set = (void *)100;
499 	obj->args[0].flags = RTE_ARGPARSE_ARG_NO_VALUE;
500 	obj->args[1].name_long = NULL;
501 	argv[0] = test_strdup(obj->usage);
502 	argv[1] = test_strdup("--test-long");
503 	ret = rte_argparse_parse(obj, 2, argv);
504 	TEST_ASSERT(ret == 0, "Argparse parse expect success!");
505 	TEST_ASSERT(val_saver == 100, "Argparse parse expect success!");
506 
507 	obj->args[0].flags = RTE_ARGPARSE_ARG_NO_VALUE;
508 	val_saver = 0;
509 	argv[1] = test_strdup("-t");
510 	ret = rte_argparse_parse(obj, 2, argv);
511 	TEST_ASSERT(ret == 0, "Argparse parse expect success!");
512 	TEST_ASSERT(val_saver == 100, "Argparse parse expect success!");
513 
514 	return 0;
515 }
516 
517 static int
518 opt_callback_parse_int_of_required_val(uint32_t index, const char *value, void *opaque)
519 {
520 	char *s = NULL;
521 
522 	if (index != 1)
523 		return -EINVAL;
524 
525 	if (value == NULL)
526 		return -EINVAL;
527 	*(int *)opaque = strtol(value, &s, 0);
528 
529 	if (s[0] != '\0')
530 		return -EINVAL;
531 
532 	return 0;
533 }
534 
535 static int
536 test_argparse_opt_callback_parse_int_of_required_val(void)
537 {
538 	struct rte_argparse *obj;
539 	int val_saver = 0;
540 	char *argv[3];
541 	int ret;
542 
543 	obj = test_argparse_init_obj();
544 	obj->callback = opt_callback_parse_int_of_required_val;
545 	obj->opaque = (void *)&val_saver;
546 	obj->args[0].name_long = "--test-long";
547 	obj->args[0].name_short = "-t";
548 	obj->args[0].val_saver = NULL;
549 	obj->args[0].val_set = (void *)1;
550 	obj->args[0].flags = RTE_ARGPARSE_ARG_REQUIRED_VALUE;
551 	obj->args[1].name_long = NULL;
552 	argv[0] = test_strdup(obj->usage);
553 	argv[1] = test_strdup("--test-long");
554 	argv[2] = test_strdup("100");
555 	ret = rte_argparse_parse(obj, 3, argv);
556 	TEST_ASSERT(ret == 0, "Argparse parse expect success!");
557 	TEST_ASSERT(val_saver == 100, "Argparse parse expect success!");
558 
559 	obj->args[0].flags = RTE_ARGPARSE_ARG_REQUIRED_VALUE;
560 	val_saver = 0;
561 	argv[1] = test_strdup("-t");
562 	ret = rte_argparse_parse(obj, 3, argv);
563 	TEST_ASSERT(ret == 0, "Argparse parse expect success!");
564 	TEST_ASSERT(val_saver == 100, "Argparse parse expect success!");
565 
566 	/* test no more parameters. */
567 	obj->args[0].flags = RTE_ARGPARSE_ARG_REQUIRED_VALUE;
568 	ret = rte_argparse_parse(obj, 2, argv);
569 	TEST_ASSERT(ret == -EINVAL, "Argparse parse expect failed!");
570 
571 	/* test callback return failed. */
572 	obj->args[0].flags = RTE_ARGPARSE_ARG_REQUIRED_VALUE;
573 	argv[2] = test_strdup("100a");
574 	ret = rte_argparse_parse(obj, 3, argv);
575 	TEST_ASSERT(ret == -EINVAL, "Argparse parse expect failed!");
576 
577 	return 0;
578 }
579 
580 static int
581 opt_callback_parse_int_of_optional_val(uint32_t index, const char *value, void *opaque)
582 {
583 	char *s = NULL;
584 
585 	if (index != 1)
586 		return -EINVAL;
587 
588 	if (value == NULL) {
589 		*(int *)opaque = 10;
590 	} else {
591 		*(int *)opaque = strtol(value, &s, 0);
592 		if (s[0] != '\0')
593 			return -EINVAL;
594 	}
595 
596 	return 0;
597 }
598 
599 static int
600 test_argparse_opt_callback_parse_int_of_optional_val(void)
601 {
602 	struct rte_argparse *obj;
603 	int val_saver = 0;
604 	char *argv[2];
605 	int ret;
606 
607 	obj = test_argparse_init_obj();
608 	obj->callback = opt_callback_parse_int_of_optional_val;
609 	obj->opaque = (void *)&val_saver;
610 	obj->args[0].name_long = "--test-long";
611 	obj->args[0].name_short = "-t";
612 	obj->args[0].val_saver = NULL;
613 	obj->args[0].val_set = (void *)1;
614 	obj->args[0].flags = RTE_ARGPARSE_ARG_OPTIONAL_VALUE;
615 	obj->args[1].name_long = NULL;
616 	argv[0] = test_strdup(obj->usage);
617 	argv[1] = test_strdup("--test-long");
618 	ret = rte_argparse_parse(obj, 2, argv);
619 	TEST_ASSERT(ret == 0, "Argparse parse expect success!");
620 	TEST_ASSERT(val_saver == 10, "Argparse parse expect success!");
621 
622 	obj->args[0].flags = RTE_ARGPARSE_ARG_OPTIONAL_VALUE;
623 	val_saver = 0;
624 	argv[1] = test_strdup("-t");
625 	ret = rte_argparse_parse(obj, 2, argv);
626 	TEST_ASSERT(ret == 0, "Argparse parse expect success!");
627 	TEST_ASSERT(val_saver == 10, "Argparse parse expect success!");
628 
629 	/* test with value. */
630 	obj->args[0].flags = RTE_ARGPARSE_ARG_OPTIONAL_VALUE;
631 	val_saver = 0;
632 	argv[1] = test_strdup("--test-long=100");
633 	ret = rte_argparse_parse(obj, 2, argv);
634 	TEST_ASSERT(ret == 0, "Argparse parse expect success!");
635 	TEST_ASSERT(val_saver == 100, "Argparse parse expect success!");
636 	obj->args[0].flags = RTE_ARGPARSE_ARG_OPTIONAL_VALUE;
637 	val_saver = 0;
638 	argv[1] = test_strdup("-t=100");
639 	ret = rte_argparse_parse(obj, 2, argv);
640 	TEST_ASSERT(ret == 0, "Argparse parse expect success!");
641 	TEST_ASSERT(val_saver == 100, "Argparse parse expect success!");
642 
643 	/* test callback return failed. */
644 	obj->args[0].flags = RTE_ARGPARSE_ARG_OPTIONAL_VALUE;
645 	argv[1] = test_strdup("-t=100a");
646 	ret = rte_argparse_parse(obj, 2, argv);
647 	TEST_ASSERT(ret == -EINVAL, "Argparse parse expect failed!");
648 
649 	return 0;
650 }
651 
652 static int
653 test_argparse_pos_autosave_parse_int(void)
654 {
655 	uint32_t flags = RTE_ARGPARSE_ARG_REQUIRED_VALUE | RTE_ARGPARSE_ARG_VALUE_INT;
656 	struct rte_argparse *obj;
657 	int val_saver = 0;
658 	char *argv[3];
659 	int ret;
660 
661 	obj = test_argparse_init_obj();
662 	obj->args[0].name_long = "test-long";
663 	obj->args[0].name_short = NULL;
664 	obj->args[0].val_saver = (void *)&val_saver;
665 	obj->args[0].val_set = NULL;
666 	obj->args[0].flags = flags;
667 	obj->args[1].name_long = NULL;
668 	argv[0] = test_strdup(obj->usage);
669 	argv[1] = test_strdup("100");
670 	ret = rte_argparse_parse(obj, 2, argv);
671 	TEST_ASSERT(ret == 0, "Argparse parse expect success!");
672 	TEST_ASSERT(val_saver == 100, "Argparse parse expect success!");
673 
674 	obj->args[0].flags = flags;
675 	val_saver = 0;
676 	argv[1] = test_strdup("100a");
677 	ret = rte_argparse_parse(obj, 2, argv);
678 	TEST_ASSERT(ret == -EINVAL, "Argparse parse expect failed!");
679 
680 	/* test over position parameters. */
681 	obj->args[0].flags = flags;
682 	argv[1] = test_strdup("100");
683 	argv[2] = test_strdup("200");
684 	ret = rte_argparse_parse(obj, 3, argv);
685 	TEST_ASSERT(ret == -EINVAL, "Argparse parse expect failed!");
686 
687 	return 0;
688 }
689 
690 static int
691 pos_callback_parse_int(uint32_t index, const char *value, void *opaque)
692 {
693 	uint32_t int_val;
694 	char *s = NULL;
695 
696 	if (index != 1 && index != 2)
697 		return -EINVAL;
698 	if (value == NULL)
699 		return -EINVAL;
700 
701 	int_val = strtol(value, &s, 0);
702 	if (s[0] != '\0')
703 		return -EINVAL;
704 
705 	*((int *)opaque	+ index) = int_val;
706 
707 	return 0;
708 }
709 
710 static int
711 test_argparse_pos_callback_parse_int(void)
712 {
713 	int val_saver[3] = { 0, 0, 0 };
714 	struct rte_argparse *obj;
715 	char *argv[3];
716 	int ret;
717 
718 	obj = test_argparse_init_obj();
719 	obj->callback = pos_callback_parse_int;
720 	obj->opaque = (void *)val_saver;
721 	obj->args[0].name_long = "test-long1";
722 	obj->args[0].name_short = NULL;
723 	obj->args[0].val_saver = NULL;
724 	obj->args[0].val_set = (void *)1;
725 	obj->args[0].flags = RTE_ARGPARSE_ARG_REQUIRED_VALUE;
726 	obj->args[1].name_long = "test-long2";
727 	obj->args[1].name_short = NULL;
728 	obj->args[1].val_saver = NULL;
729 	obj->args[1].val_set = (void *)2;
730 	obj->args[1].flags = RTE_ARGPARSE_ARG_REQUIRED_VALUE;
731 	obj->args[2].name_long = NULL;
732 	argv[0] = test_strdup(obj->usage);
733 	argv[1] = test_strdup("100");
734 	argv[2] = test_strdup("200");
735 	ret = rte_argparse_parse(obj, 3, argv);
736 	TEST_ASSERT(ret == 0, "Argparse parse expect success!");
737 	TEST_ASSERT(val_saver[1] == 100, "Argparse parse expect success!");
738 	TEST_ASSERT(val_saver[2] == 200, "Argparse parse expect success!");
739 
740 	/* test callback return failed. */
741 	obj->args[0].flags = RTE_ARGPARSE_ARG_REQUIRED_VALUE;
742 	obj->args[1].flags = RTE_ARGPARSE_ARG_REQUIRED_VALUE;
743 	argv[2] = test_strdup("200a");
744 	ret = rte_argparse_parse(obj, 3, argv);
745 	TEST_ASSERT(ret == -EINVAL, "Argparse parse expect failed!");
746 
747 	return 0;
748 }
749 
750 static int
751 test_argparse_parse_type(void)
752 {
753 	char *str_erange = test_strdup("9999999999999999999999999999999999");
754 	char *str_erange_u32 = test_strdup("4294967296");
755 	char *str_erange_u16 = test_strdup("65536");
756 	char *str_erange_u8 = test_strdup("256");
757 	char *str_invalid = test_strdup("1a");
758 	char *str_ok = test_strdup("123");
759 	uint16_t val_u16;
760 	uint32_t val_u32;
761 	uint64_t val_u64;
762 	uint8_t val_u8;
763 	int val_int;
764 	int ret;
765 
766 	/* test for int parsing */
767 	ret = rte_argparse_parse_type(str_erange, RTE_ARGPARSE_ARG_VALUE_INT, &val_int);
768 	TEST_ASSERT(ret != 0, "Argparse parse type expect failed!");
769 	ret = rte_argparse_parse_type(str_invalid, RTE_ARGPARSE_ARG_VALUE_INT, &val_int);
770 	TEST_ASSERT(ret != 0, "Argparse parse type expect failed!");
771 	ret = rte_argparse_parse_type(str_ok, RTE_ARGPARSE_ARG_VALUE_INT, &val_int);
772 	TEST_ASSERT(ret == 0, "Argparse parse type expect failed!");
773 	TEST_ASSERT(val_int == 123, "Argparse parse type expect failed!");
774 
775 	/* test for u8 parsing */
776 	ret = rte_argparse_parse_type(str_erange, RTE_ARGPARSE_ARG_VALUE_U8, &val_u8);
777 	TEST_ASSERT(ret != 0, "Argparse parse type expect failed!");
778 	ret = rte_argparse_parse_type(str_erange_u8, RTE_ARGPARSE_ARG_VALUE_U8, &val_u8);
779 	TEST_ASSERT(ret != 0, "Argparse parse type expect failed!");
780 	ret = rte_argparse_parse_type(str_invalid, RTE_ARGPARSE_ARG_VALUE_U8, &val_u8);
781 	TEST_ASSERT(ret != 0, "Argparse parse type expect failed!");
782 	val_u8 = 0;
783 	ret = rte_argparse_parse_type(str_ok, RTE_ARGPARSE_ARG_VALUE_U8, &val_u8);
784 	TEST_ASSERT(ret == 0, "Argparse parse type expect failed!");
785 	TEST_ASSERT(val_u8 == 123, "Argparse parse type expect failed!");
786 
787 	/* test for u16 parsing */
788 	ret = rte_argparse_parse_type(str_erange, RTE_ARGPARSE_ARG_VALUE_U16, &val_u16);
789 	TEST_ASSERT(ret != 0, "Argparse parse type expect failed!");
790 	ret = rte_argparse_parse_type(str_erange_u16, RTE_ARGPARSE_ARG_VALUE_U16, &val_u16);
791 	TEST_ASSERT(ret != 0, "Argparse parse type expect failed!");
792 	ret = rte_argparse_parse_type(str_invalid, RTE_ARGPARSE_ARG_VALUE_U16, &val_u16);
793 	TEST_ASSERT(ret != 0, "Argparse parse type expect failed!");
794 	val_u16 = 0;
795 	ret = rte_argparse_parse_type(str_ok, RTE_ARGPARSE_ARG_VALUE_U16, &val_u16);
796 	TEST_ASSERT(ret == 0, "Argparse parse type expect failed!");
797 	TEST_ASSERT(val_u16 == 123, "Argparse parse type expect failed!");
798 
799 	/* test for u32 parsing */
800 	ret = rte_argparse_parse_type(str_erange, RTE_ARGPARSE_ARG_VALUE_U32, &val_u32);
801 	TEST_ASSERT(ret != 0, "Argparse parse type expect failed!");
802 	ret = rte_argparse_parse_type(str_erange_u32, RTE_ARGPARSE_ARG_VALUE_U32, &val_u32);
803 	TEST_ASSERT(ret != 0, "Argparse parse type expect failed!");
804 	ret = rte_argparse_parse_type(str_invalid, RTE_ARGPARSE_ARG_VALUE_U32, &val_u32);
805 	TEST_ASSERT(ret != 0, "Argparse parse type expect failed!");
806 	val_u32 = 0;
807 	ret = rte_argparse_parse_type(str_ok, RTE_ARGPARSE_ARG_VALUE_U32, &val_u32);
808 	TEST_ASSERT(ret == 0, "Argparse parse type expect failed!");
809 	TEST_ASSERT(val_u32 == 123, "Argparse parse type expect failed!");
810 
811 	/* test for u64 parsing */
812 	ret = rte_argparse_parse_type(str_erange, RTE_ARGPARSE_ARG_VALUE_U64, &val_u64);
813 	TEST_ASSERT(ret != 0, "Argparse parse type expect failed!");
814 	ret = rte_argparse_parse_type(str_invalid, RTE_ARGPARSE_ARG_VALUE_U64, &val_u64);
815 	TEST_ASSERT(ret != 0, "Argparse parse type expect failed!");
816 	val_u64 = 0;
817 	ret = rte_argparse_parse_type(str_ok, RTE_ARGPARSE_ARG_VALUE_U64, &val_u64);
818 	TEST_ASSERT(ret == 0, "Argparse parse type expect failed!");
819 	TEST_ASSERT(val_u64 == 123, "Argparse parse type expect failed!");
820 
821 	return 0;
822 }
823 
824 static struct unit_test_suite argparse_test_suite = {
825 	.suite_name = "Argparse Unit Test Suite",
826 	.setup = test_argparse_setup,
827 	.teardown = test_argparse_teardown,
828 	.unit_test_cases = {
829 		TEST_CASE(test_argparse_invalid_basic_param),
830 		TEST_CASE(test_argparse_invalid_arg_name),
831 		TEST_CASE(test_argparse_invalid_arg_help),
832 		TEST_CASE(test_argparse_invalid_has_val),
833 		TEST_CASE(test_argparse_invalid_arg_saver),
834 		TEST_CASE(test_argparse_invalid_arg_flags),
835 		TEST_CASE(test_argparse_invalid_arg_repeat),
836 		TEST_CASE(test_argparse_invalid_option),
837 		TEST_CASE(test_argparse_opt_autosave_parse_int_of_no_val),
838 		TEST_CASE(test_argparse_opt_autosave_parse_int_of_required_val),
839 		TEST_CASE(test_argparse_opt_autosave_parse_int_of_optional_val),
840 		TEST_CASE(test_argparse_opt_callback_parse_int_of_no_val),
841 		TEST_CASE(test_argparse_opt_callback_parse_int_of_required_val),
842 		TEST_CASE(test_argparse_opt_callback_parse_int_of_optional_val),
843 		TEST_CASE(test_argparse_pos_autosave_parse_int),
844 		TEST_CASE(test_argparse_pos_callback_parse_int),
845 		TEST_CASE(test_argparse_parse_type),
846 
847 		TEST_CASES_END() /**< NULL terminate unit test array */
848 	}
849 };
850 
851 static int
852 test_argparse(void)
853 {
854 	return unit_test_suite_runner(&argparse_test_suite);
855 }
856 
857 REGISTER_FAST_TEST(argparse_autotest, true, true, test_argparse);
858