xref: /dpdk/app/test/test_argparse.c (revision f48e4eed4aebba5b61565fbf8515fd723b53cd0c)
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 	uint64_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 &= ~RTE_ARGPARSE_HAS_VAL_BITMASK;
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 &= ~RTE_ARGPARSE_HAS_VAL_BITMASK;
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 |= ~(RTE_ARGPARSE_HAS_VAL_BITMASK |
273 				RTE_ARGPARSE_VAL_TYPE_BITMASK |
274 				RTE_ARGPARSE_ARG_SUPPORT_MULTI);
275 	ret = rte_argparse_parse(obj, default_argc, default_argv);
276 	TEST_ASSERT(ret == -EINVAL, "Argparse parse expect failed!");
277 
278 	obj = test_argparse_init_obj();
279 	obj->args[0].name_long = "positional";
280 	obj->args[0].name_short = NULL;
281 	obj->args[0].val_saver = (void *)1;
282 	obj->args[0].val_set = (void *)1;
283 	obj->args[0].flags = RTE_ARGPARSE_ARG_REQUIRED_VALUE | RTE_ARGPARSE_ARG_VALUE_INT |
284 			     RTE_ARGPARSE_ARG_SUPPORT_MULTI;
285 	ret = rte_argparse_parse(obj, default_argc, default_argv);
286 	TEST_ASSERT(ret == -EINVAL, "Argparse parse expect failed!");
287 
288 	obj = test_argparse_init_obj();
289 	obj->args[0].flags |= RTE_ARGPARSE_ARG_SUPPORT_MULTI;
290 	ret = rte_argparse_parse(obj, default_argc, default_argv);
291 	TEST_ASSERT(ret == -EINVAL, "Argparse parse expect failed!");
292 
293 	return 0;
294 }
295 
296 static int
297 test_argparse_invalid_arg_repeat(void)
298 {
299 	struct rte_argparse *obj;
300 	int ret;
301 
302 	/* test for long name repeat! */
303 	obj = test_argparse_init_obj();
304 	obj->args[1].name_long = obj->args[0].name_long;
305 	ret = rte_argparse_parse(obj, default_argc, default_argv);
306 	TEST_ASSERT(ret == -EINVAL, "Argparse parse expect failed!");
307 
308 	/* test for short name repeat! */
309 	obj = test_argparse_init_obj();
310 	obj->args[1].name_short = obj->args[0].name_short;
311 	ret = rte_argparse_parse(obj, default_argc, default_argv);
312 	TEST_ASSERT(ret == -EINVAL, "Argparse parse expect failed!");
313 
314 	return 0;
315 }
316 
317 static int
318 test_argparse_invalid_option(void)
319 {
320 	struct rte_argparse *obj;
321 	char *argv[2];
322 	int ret;
323 
324 	obj = test_argparse_init_obj();
325 	argv[0] = test_strdup(obj->usage);
326 	argv[1] = test_strdup("--invalid");
327 	ret = rte_argparse_parse(obj, 2, argv);
328 	TEST_ASSERT(ret == -EINVAL, "Argparse parse expect failed!");
329 
330 	obj = test_argparse_init_obj();
331 	argv[0] = test_strdup(obj->usage);
332 	argv[1] = test_strdup("invalid");
333 	ret = rte_argparse_parse(obj, 2, argv);
334 	TEST_ASSERT(ret == -EINVAL, "Argparse parse expect failed!");
335 
336 	return 0;
337 }
338 
339 static int
340 test_argparse_opt_autosave_parse_int_of_no_val(void)
341 {
342 	uint64_t flags = RTE_ARGPARSE_ARG_NO_VALUE | RTE_ARGPARSE_ARG_VALUE_INT;
343 	struct rte_argparse *obj;
344 	int val_saver = 0;
345 	char *argv[2];
346 	int ret;
347 
348 	obj = test_argparse_init_obj();
349 	obj->args[0].name_long = "--test-long";
350 	obj->args[0].name_short = "-t";
351 	obj->args[0].val_saver = (void *)&val_saver;
352 	obj->args[0].val_set = (void *)100;
353 	obj->args[0].flags = flags;
354 	obj->args[1].name_long = NULL;
355 	argv[0] = test_strdup(obj->usage);
356 	argv[1] = test_strdup("--test-long");
357 	ret = rte_argparse_parse(obj, 2, argv);
358 	TEST_ASSERT(ret == 0, "Argparse parse expect success!");
359 	TEST_ASSERT(val_saver == 100, "Argparse parse expect success!");
360 
361 	obj->args[0].flags = flags;
362 	val_saver = 0;
363 	argv[1] = test_strdup("-t");
364 	ret = rte_argparse_parse(obj, 2, argv);
365 	TEST_ASSERT(ret == 0, "Argparse parse expect success!");
366 	TEST_ASSERT(val_saver == 100, "Argparse parse expect success!");
367 
368 	return 0;
369 }
370 
371 static int
372 test_argparse_opt_autosave_parse_int_of_required_val(void)
373 {
374 	uint64_t flags = RTE_ARGPARSE_ARG_REQUIRED_VALUE | RTE_ARGPARSE_ARG_VALUE_INT;
375 	struct rte_argparse *obj;
376 	int val_saver = 0;
377 	char *argv[3];
378 	int ret;
379 
380 	obj = test_argparse_init_obj();
381 	obj->args[0].name_long = "--test-long";
382 	obj->args[0].name_short = "-t";
383 	obj->args[0].val_saver = (void *)&val_saver;
384 	obj->args[0].val_set = NULL;
385 	obj->args[0].flags = flags;
386 	obj->args[1].name_long = NULL;
387 	argv[0] = test_strdup(obj->usage);
388 	argv[1] = test_strdup("--test-long");
389 	argv[2] = test_strdup("100");
390 	ret = rte_argparse_parse(obj, 3, argv);
391 	TEST_ASSERT(ret == 0, "Argparse parse expect success!");
392 	TEST_ASSERT(val_saver == 100, "Argparse parse expect success!");
393 
394 	obj->args[0].flags = flags;
395 	val_saver = 0;
396 	argv[1] = test_strdup("-t");
397 	ret = rte_argparse_parse(obj, 3, argv);
398 	TEST_ASSERT(ret == 0, "Argparse parse expect success!");
399 	TEST_ASSERT(val_saver == 100, "Argparse parse expect success!");
400 
401 	/* test invalid value. */
402 	obj->args[0].flags = flags;
403 	val_saver = 0;
404 	argv[1] = test_strdup("-t");
405 	argv[2] = test_strdup("100a");
406 	ret = rte_argparse_parse(obj, 3, argv);
407 	TEST_ASSERT(ret == -EINVAL, "Argparse parse expect failed!");
408 
409 	return 0;
410 }
411 
412 static int
413 test_argparse_opt_autosave_parse_int_of_optional_val(void)
414 {
415 	uint64_t flags = RTE_ARGPARSE_ARG_OPTIONAL_VALUE | RTE_ARGPARSE_ARG_VALUE_INT;
416 	struct rte_argparse *obj;
417 	int val_saver = 0;
418 	char *argv[2];
419 	int ret;
420 
421 	obj = test_argparse_init_obj();
422 	obj->args[0].name_long = "--test-long";
423 	obj->args[0].name_short = "-t";
424 	obj->args[0].val_saver = (void *)&val_saver;
425 	obj->args[0].val_set = (void *)100;
426 	obj->args[0].flags = flags;
427 	obj->args[1].name_long = NULL;
428 	argv[0] = test_strdup(obj->usage);
429 	argv[1] = test_strdup("--test-long");
430 	ret = rte_argparse_parse(obj, 2, argv);
431 	TEST_ASSERT(ret == 0, "Argparse parse expect success!");
432 	TEST_ASSERT(val_saver == 100, "Argparse parse expect success!");
433 	obj->args[0].flags = flags;
434 	val_saver = 0;
435 	argv[1] = test_strdup("-t");
436 	ret = rte_argparse_parse(obj, 2, argv);
437 	TEST_ASSERT(ret == 0, "Argparse parse expect success!");
438 	TEST_ASSERT(val_saver == 100, "Argparse parse expect success!");
439 
440 	/* test with value. */
441 	obj->args[0].flags = flags;
442 	val_saver = 0;
443 	argv[1] = test_strdup("--test-long=200");
444 	ret = rte_argparse_parse(obj, 2, argv);
445 	TEST_ASSERT(ret == 0, "Argparse parse expect success!");
446 	TEST_ASSERT(val_saver == 200, "Argparse parse expect success!");
447 	obj->args[0].flags = flags;
448 	val_saver = 0;
449 	argv[1] = test_strdup("-t=200");
450 	ret = rte_argparse_parse(obj, 2, argv);
451 	TEST_ASSERT(ret == 0, "Argparse parse expect success!");
452 	TEST_ASSERT(val_saver == 200, "Argparse parse expect success!");
453 
454 	/* test with option value, but with wrong value. */
455 	obj->args[0].flags = flags;
456 	val_saver = 0;
457 	argv[1] = test_strdup("--test-long=200a");
458 	ret = rte_argparse_parse(obj, 2, argv);
459 	TEST_ASSERT(ret == -EINVAL, "Argparse parse expect failed!");
460 	obj->args[0].flags = flags;
461 	val_saver = 0;
462 	argv[1] = test_strdup("-t=200a");
463 	ret = rte_argparse_parse(obj, 2, argv);
464 	TEST_ASSERT(ret == -EINVAL, "Argparse parse expect failed!");
465 
466 	return 0;
467 }
468 
469 static int
470 opt_callback_parse_int_of_no_val(uint32_t index, const char *value, void *opaque)
471 {
472 	RTE_SET_USED(index);
473 	if (value != NULL)
474 		return -EINVAL;
475 	*(int *)opaque = 100;
476 	return 0;
477 }
478 
479 static int
480 test_argparse_opt_callback_parse_int_of_no_val(void)
481 {
482 	struct rte_argparse *obj;
483 	int val_saver = 0;
484 	char *argv[2];
485 	int ret;
486 
487 	obj = test_argparse_init_obj();
488 	obj->callback = opt_callback_parse_int_of_no_val;
489 	obj->opaque = (void *)&val_saver;
490 	obj->args[0].name_long = "--test-long";
491 	obj->args[0].name_short = "-t";
492 	obj->args[0].val_saver = NULL;
493 	obj->args[0].val_set = (void *)100;
494 	obj->args[0].flags = RTE_ARGPARSE_ARG_NO_VALUE;
495 	obj->args[1].name_long = NULL;
496 	argv[0] = test_strdup(obj->usage);
497 	argv[1] = test_strdup("--test-long");
498 	ret = rte_argparse_parse(obj, 2, argv);
499 	TEST_ASSERT(ret == 0, "Argparse parse expect success!");
500 	TEST_ASSERT(val_saver == 100, "Argparse parse expect success!");
501 
502 	obj->args[0].flags = RTE_ARGPARSE_ARG_NO_VALUE;
503 	val_saver = 0;
504 	argv[1] = test_strdup("-t");
505 	ret = rte_argparse_parse(obj, 2, argv);
506 	TEST_ASSERT(ret == 0, "Argparse parse expect success!");
507 	TEST_ASSERT(val_saver == 100, "Argparse parse expect success!");
508 
509 	return 0;
510 }
511 
512 static int
513 opt_callback_parse_int_of_required_val(uint32_t index, const char *value, void *opaque)
514 {
515 	char *s = NULL;
516 
517 	if (index != 1)
518 		return -EINVAL;
519 
520 	if (value == NULL)
521 		return -EINVAL;
522 	*(int *)opaque = strtol(value, &s, 0);
523 
524 	if (s[0] != '\0')
525 		return -EINVAL;
526 
527 	return 0;
528 }
529 
530 static int
531 test_argparse_opt_callback_parse_int_of_required_val(void)
532 {
533 	struct rte_argparse *obj;
534 	int val_saver = 0;
535 	char *argv[3];
536 	int ret;
537 
538 	obj = test_argparse_init_obj();
539 	obj->callback = opt_callback_parse_int_of_required_val;
540 	obj->opaque = (void *)&val_saver;
541 	obj->args[0].name_long = "--test-long";
542 	obj->args[0].name_short = "-t";
543 	obj->args[0].val_saver = NULL;
544 	obj->args[0].val_set = (void *)1;
545 	obj->args[0].flags = RTE_ARGPARSE_ARG_REQUIRED_VALUE;
546 	obj->args[1].name_long = NULL;
547 	argv[0] = test_strdup(obj->usage);
548 	argv[1] = test_strdup("--test-long");
549 	argv[2] = test_strdup("100");
550 	ret = rte_argparse_parse(obj, 3, argv);
551 	TEST_ASSERT(ret == 0, "Argparse parse expect success!");
552 	TEST_ASSERT(val_saver == 100, "Argparse parse expect success!");
553 
554 	obj->args[0].flags = RTE_ARGPARSE_ARG_REQUIRED_VALUE;
555 	val_saver = 0;
556 	argv[1] = test_strdup("-t");
557 	ret = rte_argparse_parse(obj, 3, argv);
558 	TEST_ASSERT(ret == 0, "Argparse parse expect success!");
559 	TEST_ASSERT(val_saver == 100, "Argparse parse expect success!");
560 
561 	/* test no more parameters. */
562 	obj->args[0].flags = RTE_ARGPARSE_ARG_REQUIRED_VALUE;
563 	ret = rte_argparse_parse(obj, 2, argv);
564 	TEST_ASSERT(ret == -EINVAL, "Argparse parse expect failed!");
565 
566 	/* test callback return failed. */
567 	obj->args[0].flags = RTE_ARGPARSE_ARG_REQUIRED_VALUE;
568 	argv[2] = test_strdup("100a");
569 	ret = rte_argparse_parse(obj, 3, argv);
570 	TEST_ASSERT(ret == -EINVAL, "Argparse parse expect failed!");
571 
572 	return 0;
573 }
574 
575 static int
576 opt_callback_parse_int_of_optional_val(uint32_t index, const char *value, void *opaque)
577 {
578 	char *s = NULL;
579 
580 	if (index != 1)
581 		return -EINVAL;
582 
583 	if (value == NULL) {
584 		*(int *)opaque = 10;
585 	} else {
586 		*(int *)opaque = strtol(value, &s, 0);
587 		if (s[0] != '\0')
588 			return -EINVAL;
589 	}
590 
591 	return 0;
592 }
593 
594 static int
595 test_argparse_opt_callback_parse_int_of_optional_val(void)
596 {
597 	struct rte_argparse *obj;
598 	int val_saver = 0;
599 	char *argv[2];
600 	int ret;
601 
602 	obj = test_argparse_init_obj();
603 	obj->callback = opt_callback_parse_int_of_optional_val;
604 	obj->opaque = (void *)&val_saver;
605 	obj->args[0].name_long = "--test-long";
606 	obj->args[0].name_short = "-t";
607 	obj->args[0].val_saver = NULL;
608 	obj->args[0].val_set = (void *)1;
609 	obj->args[0].flags = RTE_ARGPARSE_ARG_OPTIONAL_VALUE;
610 	obj->args[1].name_long = NULL;
611 	argv[0] = test_strdup(obj->usage);
612 	argv[1] = test_strdup("--test-long");
613 	ret = rte_argparse_parse(obj, 2, argv);
614 	TEST_ASSERT(ret == 0, "Argparse parse expect success!");
615 	TEST_ASSERT(val_saver == 10, "Argparse parse expect success!");
616 
617 	obj->args[0].flags = RTE_ARGPARSE_ARG_OPTIONAL_VALUE;
618 	val_saver = 0;
619 	argv[1] = test_strdup("-t");
620 	ret = rte_argparse_parse(obj, 2, argv);
621 	TEST_ASSERT(ret == 0, "Argparse parse expect success!");
622 	TEST_ASSERT(val_saver == 10, "Argparse parse expect success!");
623 
624 	/* test with value. */
625 	obj->args[0].flags = RTE_ARGPARSE_ARG_OPTIONAL_VALUE;
626 	val_saver = 0;
627 	argv[1] = test_strdup("--test-long=100");
628 	ret = rte_argparse_parse(obj, 2, argv);
629 	TEST_ASSERT(ret == 0, "Argparse parse expect success!");
630 	TEST_ASSERT(val_saver == 100, "Argparse parse expect success!");
631 	obj->args[0].flags = RTE_ARGPARSE_ARG_OPTIONAL_VALUE;
632 	val_saver = 0;
633 	argv[1] = test_strdup("-t=100");
634 	ret = rte_argparse_parse(obj, 2, argv);
635 	TEST_ASSERT(ret == 0, "Argparse parse expect success!");
636 	TEST_ASSERT(val_saver == 100, "Argparse parse expect success!");
637 
638 	/* test callback return failed. */
639 	obj->args[0].flags = RTE_ARGPARSE_ARG_OPTIONAL_VALUE;
640 	argv[1] = test_strdup("-t=100a");
641 	ret = rte_argparse_parse(obj, 2, argv);
642 	TEST_ASSERT(ret == -EINVAL, "Argparse parse expect failed!");
643 
644 	return 0;
645 }
646 
647 static int
648 test_argparse_pos_autosave_parse_int(void)
649 {
650 	uint64_t flags = RTE_ARGPARSE_ARG_REQUIRED_VALUE | RTE_ARGPARSE_ARG_VALUE_INT;
651 	struct rte_argparse *obj;
652 	int val_saver = 0;
653 	char *argv[3];
654 	int ret;
655 
656 	obj = test_argparse_init_obj();
657 	obj->args[0].name_long = "test-long";
658 	obj->args[0].name_short = NULL;
659 	obj->args[0].val_saver = (void *)&val_saver;
660 	obj->args[0].val_set = NULL;
661 	obj->args[0].flags = flags;
662 	obj->args[1].name_long = NULL;
663 	argv[0] = test_strdup(obj->usage);
664 	argv[1] = test_strdup("100");
665 	ret = rte_argparse_parse(obj, 2, argv);
666 	TEST_ASSERT(ret == 0, "Argparse parse expect success!");
667 	TEST_ASSERT(val_saver == 100, "Argparse parse expect success!");
668 
669 	obj->args[0].flags = flags;
670 	val_saver = 0;
671 	argv[1] = test_strdup("100a");
672 	ret = rte_argparse_parse(obj, 2, argv);
673 	TEST_ASSERT(ret == -EINVAL, "Argparse parse expect failed!");
674 
675 	/* test over position parameters. */
676 	obj->args[0].flags = flags;
677 	argv[1] = test_strdup("100");
678 	argv[2] = test_strdup("200");
679 	ret = rte_argparse_parse(obj, 3, argv);
680 	TEST_ASSERT(ret == -EINVAL, "Argparse parse expect failed!");
681 
682 	return 0;
683 }
684 
685 static int
686 pos_callback_parse_int(uint32_t index, const char *value, void *opaque)
687 {
688 	uint32_t int_val;
689 	char *s = NULL;
690 
691 	if (index != 1 && index != 2)
692 		return -EINVAL;
693 	if (value == NULL)
694 		return -EINVAL;
695 
696 	int_val = strtol(value, &s, 0);
697 	if (s[0] != '\0')
698 		return -EINVAL;
699 
700 	*((int *)opaque	+ index) = int_val;
701 
702 	return 0;
703 }
704 
705 static int
706 test_argparse_pos_callback_parse_int(void)
707 {
708 	int val_saver[3] = { 0, 0, 0 };
709 	struct rte_argparse *obj;
710 	char *argv[3];
711 	int ret;
712 
713 	obj = test_argparse_init_obj();
714 	obj->callback = pos_callback_parse_int;
715 	obj->opaque = (void *)val_saver;
716 	obj->args[0].name_long = "test-long1";
717 	obj->args[0].name_short = NULL;
718 	obj->args[0].val_saver = NULL;
719 	obj->args[0].val_set = (void *)1;
720 	obj->args[0].flags = RTE_ARGPARSE_ARG_REQUIRED_VALUE;
721 	obj->args[1].name_long = "test-long2";
722 	obj->args[1].name_short = NULL;
723 	obj->args[1].val_saver = NULL;
724 	obj->args[1].val_set = (void *)2;
725 	obj->args[1].flags = RTE_ARGPARSE_ARG_REQUIRED_VALUE;
726 	obj->args[2].name_long = NULL;
727 	argv[0] = test_strdup(obj->usage);
728 	argv[1] = test_strdup("100");
729 	argv[2] = test_strdup("200");
730 	ret = rte_argparse_parse(obj, 3, argv);
731 	TEST_ASSERT(ret == 0, "Argparse parse expect success!");
732 	TEST_ASSERT(val_saver[1] == 100, "Argparse parse expect success!");
733 	TEST_ASSERT(val_saver[2] == 200, "Argparse parse expect success!");
734 
735 	/* test callback return failed. */
736 	obj->args[0].flags = RTE_ARGPARSE_ARG_REQUIRED_VALUE;
737 	obj->args[1].flags = RTE_ARGPARSE_ARG_REQUIRED_VALUE;
738 	argv[2] = test_strdup("200a");
739 	ret = rte_argparse_parse(obj, 3, argv);
740 	TEST_ASSERT(ret == -EINVAL, "Argparse parse expect failed!");
741 
742 	return 0;
743 }
744 
745 static int
746 test_argparse_parse_type(void)
747 {
748 	char *str_erange = test_strdup("9999999999999999999999999999999999");
749 	char *str_erange_u32 = test_strdup("4294967296");
750 	char *str_erange_u16 = test_strdup("65536");
751 	char *str_erange_u8 = test_strdup("256");
752 	char *str_invalid = test_strdup("1a");
753 	char *str_ok = test_strdup("123");
754 	uint16_t val_u16;
755 	uint32_t val_u32;
756 	uint64_t val_u64;
757 	uint8_t val_u8;
758 	int val_int;
759 	int ret;
760 
761 	/* test for int parsing */
762 	ret = rte_argparse_parse_type(str_erange, RTE_ARGPARSE_ARG_VALUE_INT, &val_int);
763 	TEST_ASSERT(ret != 0, "Argparse parse type expect failed!");
764 	ret = rte_argparse_parse_type(str_invalid, RTE_ARGPARSE_ARG_VALUE_INT, &val_int);
765 	TEST_ASSERT(ret != 0, "Argparse parse type expect failed!");
766 	ret = rte_argparse_parse_type(str_ok, RTE_ARGPARSE_ARG_VALUE_INT, &val_int);
767 	TEST_ASSERT(ret == 0, "Argparse parse type expect failed!");
768 	TEST_ASSERT(val_int == 123, "Argparse parse type expect failed!");
769 
770 	/* test for u8 parsing */
771 	ret = rte_argparse_parse_type(str_erange, RTE_ARGPARSE_ARG_VALUE_U8, &val_u8);
772 	TEST_ASSERT(ret != 0, "Argparse parse type expect failed!");
773 	ret = rte_argparse_parse_type(str_erange_u8, RTE_ARGPARSE_ARG_VALUE_U8, &val_u8);
774 	TEST_ASSERT(ret != 0, "Argparse parse type expect failed!");
775 	ret = rte_argparse_parse_type(str_invalid, RTE_ARGPARSE_ARG_VALUE_U8, &val_u8);
776 	TEST_ASSERT(ret != 0, "Argparse parse type expect failed!");
777 	val_u8 = 0;
778 	ret = rte_argparse_parse_type(str_ok, RTE_ARGPARSE_ARG_VALUE_U8, &val_u8);
779 	TEST_ASSERT(ret == 0, "Argparse parse type expect failed!");
780 	TEST_ASSERT(val_u8 == 123, "Argparse parse type expect failed!");
781 
782 	/* test for u16 parsing */
783 	ret = rte_argparse_parse_type(str_erange, RTE_ARGPARSE_ARG_VALUE_U16, &val_u16);
784 	TEST_ASSERT(ret != 0, "Argparse parse type expect failed!");
785 	ret = rte_argparse_parse_type(str_erange_u16, RTE_ARGPARSE_ARG_VALUE_U16, &val_u16);
786 	TEST_ASSERT(ret != 0, "Argparse parse type expect failed!");
787 	ret = rte_argparse_parse_type(str_invalid, RTE_ARGPARSE_ARG_VALUE_U16, &val_u16);
788 	TEST_ASSERT(ret != 0, "Argparse parse type expect failed!");
789 	val_u16 = 0;
790 	ret = rte_argparse_parse_type(str_ok, RTE_ARGPARSE_ARG_VALUE_U16, &val_u16);
791 	TEST_ASSERT(ret == 0, "Argparse parse type expect failed!");
792 	TEST_ASSERT(val_u16 == 123, "Argparse parse type expect failed!");
793 
794 	/* test for u32 parsing */
795 	ret = rte_argparse_parse_type(str_erange, RTE_ARGPARSE_ARG_VALUE_U32, &val_u32);
796 	TEST_ASSERT(ret != 0, "Argparse parse type expect failed!");
797 	ret = rte_argparse_parse_type(str_erange_u32, RTE_ARGPARSE_ARG_VALUE_U32, &val_u32);
798 	TEST_ASSERT(ret != 0, "Argparse parse type expect failed!");
799 	ret = rte_argparse_parse_type(str_invalid, RTE_ARGPARSE_ARG_VALUE_U32, &val_u32);
800 	TEST_ASSERT(ret != 0, "Argparse parse type expect failed!");
801 	val_u32 = 0;
802 	ret = rte_argparse_parse_type(str_ok, RTE_ARGPARSE_ARG_VALUE_U32, &val_u32);
803 	TEST_ASSERT(ret == 0, "Argparse parse type expect failed!");
804 	TEST_ASSERT(val_u32 == 123, "Argparse parse type expect failed!");
805 
806 	/* test for u64 parsing */
807 	ret = rte_argparse_parse_type(str_erange, RTE_ARGPARSE_ARG_VALUE_U64, &val_u64);
808 	TEST_ASSERT(ret != 0, "Argparse parse type expect failed!");
809 	ret = rte_argparse_parse_type(str_invalid, RTE_ARGPARSE_ARG_VALUE_U64, &val_u64);
810 	TEST_ASSERT(ret != 0, "Argparse parse type expect failed!");
811 	val_u64 = 0;
812 	ret = rte_argparse_parse_type(str_ok, RTE_ARGPARSE_ARG_VALUE_U64, &val_u64);
813 	TEST_ASSERT(ret == 0, "Argparse parse type expect failed!");
814 	TEST_ASSERT(val_u64 == 123, "Argparse parse type expect failed!");
815 
816 	return 0;
817 }
818 
819 static struct unit_test_suite argparse_test_suite = {
820 	.suite_name = "Argparse Unit Test Suite",
821 	.setup = test_argparse_setup,
822 	.teardown = test_argparse_teardown,
823 	.unit_test_cases = {
824 		TEST_CASE(test_argparse_invalid_basic_param),
825 		TEST_CASE(test_argparse_invalid_arg_name),
826 		TEST_CASE(test_argparse_invalid_arg_help),
827 		TEST_CASE(test_argparse_invalid_has_val),
828 		TEST_CASE(test_argparse_invalid_arg_saver),
829 		TEST_CASE(test_argparse_invalid_arg_flags),
830 		TEST_CASE(test_argparse_invalid_arg_repeat),
831 		TEST_CASE(test_argparse_invalid_option),
832 		TEST_CASE(test_argparse_opt_autosave_parse_int_of_no_val),
833 		TEST_CASE(test_argparse_opt_autosave_parse_int_of_required_val),
834 		TEST_CASE(test_argparse_opt_autosave_parse_int_of_optional_val),
835 		TEST_CASE(test_argparse_opt_callback_parse_int_of_no_val),
836 		TEST_CASE(test_argparse_opt_callback_parse_int_of_required_val),
837 		TEST_CASE(test_argparse_opt_callback_parse_int_of_optional_val),
838 		TEST_CASE(test_argparse_pos_autosave_parse_int),
839 		TEST_CASE(test_argparse_pos_callback_parse_int),
840 		TEST_CASE(test_argparse_parse_type),
841 
842 		TEST_CASES_END() /**< NULL terminate unit test array */
843 	}
844 };
845 
846 static int
847 test_argparse(void)
848 {
849 	return unit_test_suite_runner(&argparse_test_suite);
850 }
851 
852 REGISTER_FAST_TEST(argparse_autotest, true, true, test_argparse);
853