1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2010-2014 Intel Corporation
9 #include <rte_string_fns.h>
11 #include <cmdline_parse.h>
12 #include <cmdline_parse_num.h>
14 #include "test_cmdline.h"
16 struct num_unsigned_str
{
21 struct num_signed_str
{
26 const struct num_unsigned_str num_valid_positive_strs
[] = {
27 /* decimal positive */
30 {"128", INT8_MAX
+ 1 },
32 {"256", UINT8_MAX
+ 1 },
33 {"32767", INT16_MAX
},
34 {"32768", INT16_MAX
+ 1 },
35 {"65535", UINT16_MAX
},
36 {"65536", UINT16_MAX
+ 1 },
37 {"2147483647", INT32_MAX
},
38 {"2147483648", INT32_MAX
+ 1U },
39 {"4294967295", UINT32_MAX
},
40 {"4294967296", UINT32_MAX
+ 1ULL },
41 {"9223372036854775807", INT64_MAX
},
42 {"9223372036854775808", INT64_MAX
+ 1ULL},
43 {"18446744073709551615", UINT64_MAX
},
44 /* hexadecimal (no leading zeroes) */
47 {"0x80", INT8_MAX
+ 1 },
49 {"0x100", UINT8_MAX
+ 1 },
50 {"0x7FFF", INT16_MAX
},
51 {"0x8000", INT16_MAX
+ 1 },
52 {"0xFFFF", UINT16_MAX
},
53 {"0x10000", UINT16_MAX
+ 1 },
54 {"0x7FFFFFFF", INT32_MAX
},
55 {"0x80000000", INT32_MAX
+ 1U },
56 {"0xFFFFFFFF", UINT32_MAX
},
57 {"0x100000000", UINT32_MAX
+ 1ULL },
58 {"0x7FFFFFFFFFFFFFFF", INT64_MAX
},
59 {"0x8000000000000000", INT64_MAX
+ 1ULL},
60 {"0xFFFFFFFFFFFFFFFF", UINT64_MAX
},
61 /* hexadecimal (with leading zeroes) */
64 {"0x80", INT8_MAX
+ 1 },
66 {"0x0100", UINT8_MAX
+ 1 },
67 {"0x7FFF", INT16_MAX
},
68 {"0x8000", INT16_MAX
+ 1 },
69 {"0xFFFF", UINT16_MAX
},
70 {"0x00010000", UINT16_MAX
+ 1 },
71 {"0x7FFFFFFF", INT32_MAX
},
72 {"0x80000000", INT32_MAX
+ 1U },
73 {"0xFFFFFFFF", UINT32_MAX
},
74 {"0x0000000100000000", UINT32_MAX
+ 1ULL },
75 {"0x7FFFFFFFFFFFFFFF", INT64_MAX
},
76 {"0x8000000000000000", INT64_MAX
+ 1ULL},
77 {"0xFFFFFFFFFFFFFFFF", UINT64_MAX
},
78 /* check all characters */
79 {"0x1234567890ABCDEF", 0x1234567890ABCDEFULL
},
80 {"0x1234567890abcdef", 0x1234567890ABCDEFULL
},
81 /* binary (no leading zeroes) */
83 {"0b1111111", INT8_MAX
},
84 {"0b10000000", INT8_MAX
+ 1 },
85 {"0b11111111", UINT8_MAX
},
86 {"0b100000000", UINT8_MAX
+ 1 },
87 {"0b111111111111111", INT16_MAX
},
88 {"0b1000000000000000", INT16_MAX
+ 1 },
89 {"0b1111111111111111", UINT16_MAX
},
90 {"0b10000000000000000", UINT16_MAX
+ 1 },
91 {"0b1111111111111111111111111111111", INT32_MAX
},
92 {"0b10000000000000000000000000000000", INT32_MAX
+ 1U },
93 {"0b11111111111111111111111111111111", UINT32_MAX
},
94 {"0b100000000000000000000000000000000", UINT32_MAX
+ 1ULL },
95 {"0b111111111111111111111111111111111111111111111111111111111111111",
97 {"0b1000000000000000000000000000000000000000000000000000000000000000",
99 {"0b1111111111111111111111111111111111111111111111111111111111111111",
101 /* binary (with leading zeroes) */
102 {"0b01111111", INT8_MAX
},
103 {"0b0000000100000000", UINT8_MAX
+ 1 },
104 {"0b0111111111111111", INT16_MAX
},
105 {"0b00000000000000010000000000000000", UINT16_MAX
+ 1 },
106 {"0b01111111111111111111111111111111", INT32_MAX
},
107 {"0b0000000000000000000000000000000100000000000000000000000000000000",
109 {"0b0111111111111111111111111111111111111111111111111111111111111111",
114 {"0200", INT8_MAX
+ 1 },
115 {"0377", UINT8_MAX
},
116 {"0400", UINT8_MAX
+ 1 },
117 {"077777", INT16_MAX
},
118 {"0100000", INT16_MAX
+ 1 },
119 {"0177777", UINT16_MAX
},
120 {"0200000", UINT16_MAX
+ 1 },
121 {"017777777777", INT32_MAX
},
122 {"020000000000", INT32_MAX
+ 1U },
123 {"037777777777", UINT32_MAX
},
124 {"040000000000", UINT32_MAX
+ 1ULL },
125 {"0777777777777777777777", INT64_MAX
},
126 {"01000000000000000000000", INT64_MAX
+ 1ULL},
127 {"01777777777777777777777", UINT64_MAX
},
128 /* check all numbers */
129 {"012345670", 012345670 },
130 {"076543210", 076543210 },
133 const struct num_signed_str num_valid_negative_strs
[] = {
134 /* deciman negative */
136 {"-129", INT8_MIN
- 1 },
137 {"-32768", INT16_MIN
},
138 {"-32769", INT16_MIN
- 1 },
139 {"-2147483648", INT32_MIN
},
140 {"-2147483649", INT32_MIN
- 1LL },
141 {"-9223372036854775808", INT64_MIN
},
144 const struct num_unsigned_str num_garbage_positive_strs
[] = {
145 /* valid strings with garbage on the end, should still be valid */
147 {"9223372036854775807\0garbage", INT64_MAX
},
148 {"9223372036854775807\tgarbage", INT64_MAX
},
149 {"9223372036854775807\rgarbage", INT64_MAX
},
150 {"9223372036854775807\ngarbage", INT64_MAX
},
151 {"9223372036854775807#garbage", INT64_MAX
},
152 {"9223372036854775807 garbage", INT64_MAX
},
154 {"0x7FFFFFFFFFFFFFFF\0garbage", INT64_MAX
},
155 {"0x7FFFFFFFFFFFFFFF\tgarbage", INT64_MAX
},
156 {"0x7FFFFFFFFFFFFFFF\rgarbage", INT64_MAX
},
157 {"0x7FFFFFFFFFFFFFFF\ngarbage", INT64_MAX
},
158 {"0x7FFFFFFFFFFFFFFF#garbage", INT64_MAX
},
159 {"0x7FFFFFFFFFFFFFFF garbage", INT64_MAX
},
161 {"0b1111111111111111111111111111111\0garbage", INT32_MAX
},
162 {"0b1111111111111111111111111111111\rgarbage", INT32_MAX
},
163 {"0b1111111111111111111111111111111\tgarbage", INT32_MAX
},
164 {"0b1111111111111111111111111111111\ngarbage", INT32_MAX
},
165 {"0b1111111111111111111111111111111#garbage", INT32_MAX
},
166 {"0b1111111111111111111111111111111 garbage", INT32_MAX
},
168 {"01777777777777777777777\0garbage", UINT64_MAX
},
169 {"01777777777777777777777\rgarbage", UINT64_MAX
},
170 {"01777777777777777777777\tgarbage", UINT64_MAX
},
171 {"01777777777777777777777\ngarbage", UINT64_MAX
},
172 {"01777777777777777777777#garbage", UINT64_MAX
},
173 {"01777777777777777777777 garbage", UINT64_MAX
},
176 const struct num_signed_str num_garbage_negative_strs
[] = {
177 /* valid strings with garbage on the end, should still be valid */
178 {"-9223372036854775808\0garbage", INT64_MIN
},
179 {"-9223372036854775808\rgarbage", INT64_MIN
},
180 {"-9223372036854775808\tgarbage", INT64_MIN
},
181 {"-9223372036854775808\ngarbage", INT64_MIN
},
182 {"-9223372036854775808#garbage", INT64_MIN
},
183 {"-9223372036854775808 garbage", INT64_MIN
},
186 const char * num_invalid_strs
[] = {
187 "18446744073709551616", /* out of range unsigned */
188 "-9223372036854775809", /* out of range negative signed */
189 "0x10000000000000000", /* out of range hex */
190 /* out of range binary */
191 "0b10000000000000000000000000000000000000000000000000000000000000000",
192 "020000000000000000000000", /* out of range octal */
198 /* false negative numbers */
202 /* too long (128+ chars) */
203 "0b1111000011110000111100001111000011110000111100001111000011110000"
204 "1111000011110000111100001111000011110000111100001111000011110000",
219 #define NUM_POSITIVE_STRS_SIZE \
220 (sizeof(num_valid_positive_strs) / sizeof(num_valid_positive_strs[0]))
221 #define NUM_NEGATIVE_STRS_SIZE \
222 (sizeof(num_valid_negative_strs) / sizeof(num_valid_negative_strs[0]))
223 #define NUM_POSITIVE_GARBAGE_STRS_SIZE \
224 (sizeof(num_garbage_positive_strs) / sizeof(num_garbage_positive_strs[0]))
225 #define NUM_NEGATIVE_GARBAGE_STRS_SIZE \
226 (sizeof(num_garbage_negative_strs) / sizeof(num_garbage_negative_strs[0]))
227 #define NUM_INVALID_STRS_SIZE \
228 (sizeof(num_invalid_strs) / sizeof(num_invalid_strs[0]))
233 can_parse_unsigned(uint64_t expected_result
, enum cmdline_numtype type
)
237 if (expected_result
> UINT8_MAX
)
241 if (expected_result
> UINT16_MAX
)
245 if (expected_result
> UINT32_MAX
)
249 if (expected_result
> INT8_MAX
)
253 if (expected_result
> INT16_MAX
)
257 if (expected_result
> INT32_MAX
)
261 if (expected_result
> INT64_MAX
)
271 can_parse_signed(int64_t expected_result
, enum cmdline_numtype type
)
275 if (expected_result
> UINT8_MAX
|| expected_result
< 0)
279 if (expected_result
> UINT16_MAX
|| expected_result
< 0)
283 if (expected_result
> UINT32_MAX
|| expected_result
< 0)
287 if (expected_result
< 0)
291 if (expected_result
> INT8_MAX
|| expected_result
< INT8_MIN
)
295 if (expected_result
> INT16_MAX
|| expected_result
< INT16_MIN
)
299 if (expected_result
> INT32_MAX
|| expected_result
< INT32_MIN
)
308 /* test invalid parameters */
310 test_parse_num_invalid_param(void)
312 char buf
[CMDLINE_TEST_BUFSIZE
];
314 cmdline_parse_token_num_t token
;
318 token
.num_data
.type
= UINT32
;
320 /* copy string to buffer */
321 strlcpy(buf
, num_valid_positive_strs
[0].str
, sizeof(buf
));
324 ret
= cmdline_parse_num(NULL
, NULL
, NULL
, 0);
326 printf("Error: parser accepted null parameters!\n");
331 ret
= cmdline_parse_num(NULL
, buf
, (void*)&result
, sizeof(result
));
333 printf("Error: parser accepted null token!\n");
338 ret
= cmdline_parse_num((cmdline_parse_token_hdr_t
*)&token
, NULL
,
339 (void*)&result
, sizeof(result
));
341 printf("Error: parser accepted null string!\n");
345 /* try null result */
346 ret
= cmdline_parse_num((cmdline_parse_token_hdr_t
*)&token
, buf
,
349 printf("Error: parser rejected null result!\n");
353 /* test help function */
354 memset(&buf
, 0, sizeof(buf
));
357 ret
= cmdline_get_help_num(NULL
, NULL
, 0);
359 printf("Error: help function accepted null parameters!\n");
364 ret
= cmdline_get_help_num(NULL
, buf
, sizeof(buf
));
366 printf("Error: help function accepted null token!\n");
371 ret
= cmdline_get_help_num((cmdline_parse_token_hdr_t
*)&token
, buf
, sizeof(buf
));
373 printf("Error: help function failed with valid parameters!\n");
379 /* test valid parameters but invalid data */
381 test_parse_num_invalid_data(void)
383 enum cmdline_numtype type
;
386 char buf
[CMDLINE_TEST_BUFSIZE
];
387 uint64_t result
; /* pick largest buffer */
388 cmdline_parse_token_num_t token
;
390 /* cycle through all possible parsed types */
391 for (type
= UINT8
; type
<= INT64
; type
++) {
392 token
.num_data
.type
= type
;
394 /* test full strings */
395 for (i
= 0; i
< NUM_INVALID_STRS_SIZE
; i
++) {
397 memset(&result
, 0, sizeof(uint64_t));
398 memset(&buf
, 0, sizeof(buf
));
400 ret
= cmdline_parse_num((cmdline_parse_token_hdr_t
*)&token
,
401 num_invalid_strs
[i
], (void*)&result
, sizeof(result
));
403 /* get some info about what we are trying to parse */
404 cmdline_get_help_num((cmdline_parse_token_hdr_t
*)&token
,
407 printf("Error: parsing %s as %s succeeded!\n",
408 num_invalid_strs
[i
], buf
);
416 /* test valid parameters and data */
418 test_parse_num_valid(void)
421 enum cmdline_numtype type
;
423 char buf
[CMDLINE_TEST_BUFSIZE
];
425 cmdline_parse_token_num_t token
;
427 /** valid strings **/
429 /* cycle through all possible parsed types */
430 for (type
= UINT8
; type
<= INT64
; type
++) {
431 token
.num_data
.type
= type
;
433 /* test positive strings */
434 for (i
= 0; i
< NUM_POSITIVE_STRS_SIZE
; i
++) {
436 memset(&buf
, 0, sizeof(buf
));
438 cmdline_get_help_num((cmdline_parse_token_hdr_t
*)&token
,
441 ret
= cmdline_parse_num((cmdline_parse_token_hdr_t
*) &token
,
442 num_valid_positive_strs
[i
].str
,
443 (void*)&result
, sizeof(result
));
445 /* if it should have passed but didn't, or if it should have failed but didn't */
446 if ((ret
< 0) == (can_parse_unsigned(num_valid_positive_strs
[i
].result
, type
) > 0)) {
447 printf("Error: parser behaves unexpectedly when parsing %s as %s!\n",
448 num_valid_positive_strs
[i
].str
, buf
);
451 /* check if result matches what it should have matched
452 * since unsigned numbers don't care about number of bits, we can just convert
453 * everything to uint64_t without any worries. */
454 if (ret
> 0 && num_valid_positive_strs
[i
].result
!= result
) {
455 printf("Error: parsing %s as %s failed: result mismatch!\n",
456 num_valid_positive_strs
[i
].str
, buf
);
461 /* test negative strings */
462 for (i
= 0; i
< NUM_NEGATIVE_STRS_SIZE
; i
++) {
464 memset(&buf
, 0, sizeof(buf
));
466 cmdline_get_help_num((cmdline_parse_token_hdr_t
*)&token
,
469 ret
= cmdline_parse_num((cmdline_parse_token_hdr_t
*) &token
,
470 num_valid_negative_strs
[i
].str
,
471 (void*)&result
, sizeof(result
));
473 /* if it should have passed but didn't, or if it should have failed but didn't */
474 if ((ret
< 0) == (can_parse_signed(num_valid_negative_strs
[i
].result
, type
) > 0)) {
475 printf("Error: parser behaves unexpectedly when parsing %s as %s!\n",
476 num_valid_negative_strs
[i
].str
, buf
);
479 /* check if result matches what it should have matched
480 * the result is signed in this case, so we have to account for that */
482 /* detect negative */
485 result
= (int8_t) result
;
488 result
= (int16_t) result
;
491 result
= (int32_t) result
;
496 if (num_valid_negative_strs
[i
].result
== (int64_t) result
)
498 printf("Error: parsing %s as %s failed: result mismatch!\n",
499 num_valid_negative_strs
[i
].str
, buf
);
505 /** garbage strings **/
507 /* cycle through all possible parsed types */
508 for (type
= UINT8
; type
<= INT64
; type
++) {
509 token
.num_data
.type
= type
;
511 /* test positive garbage strings */
512 for (i
= 0; i
< NUM_POSITIVE_GARBAGE_STRS_SIZE
; i
++) {
514 memset(&buf
, 0, sizeof(buf
));
516 cmdline_get_help_num((cmdline_parse_token_hdr_t
*)&token
,
519 ret
= cmdline_parse_num((cmdline_parse_token_hdr_t
*) &token
,
520 num_garbage_positive_strs
[i
].str
,
521 (void*)&result
, sizeof(result
));
523 /* if it should have passed but didn't, or if it should have failed but didn't */
524 if ((ret
< 0) == (can_parse_unsigned(num_garbage_positive_strs
[i
].result
, type
) > 0)) {
525 printf("Error: parser behaves unexpectedly when parsing %s as %s!\n",
526 num_garbage_positive_strs
[i
].str
, buf
);
529 /* check if result matches what it should have matched
530 * since unsigned numbers don't care about number of bits, we can just convert
531 * everything to uint64_t without any worries. */
532 if (ret
> 0 && num_garbage_positive_strs
[i
].result
!= result
) {
533 printf("Error: parsing %s as %s failed: result mismatch!\n",
534 num_garbage_positive_strs
[i
].str
, buf
);
539 /* test negative strings */
540 for (i
= 0; i
< NUM_NEGATIVE_GARBAGE_STRS_SIZE
; i
++) {
542 memset(&buf
, 0, sizeof(buf
));
544 cmdline_get_help_num((cmdline_parse_token_hdr_t
*)&token
,
547 ret
= cmdline_parse_num((cmdline_parse_token_hdr_t
*) &token
,
548 num_garbage_negative_strs
[i
].str
,
549 (void*)&result
, sizeof(result
));
551 /* if it should have passed but didn't, or if it should have failed but didn't */
552 if ((ret
< 0) == (can_parse_signed(num_garbage_negative_strs
[i
].result
, type
) > 0)) {
553 printf("Error: parser behaves unexpectedly when parsing %s as %s!\n",
554 num_garbage_negative_strs
[i
].str
, buf
);
557 /* check if result matches what it should have matched
558 * the result is signed in this case, so we have to account for that */
560 /* detect negative */
563 if (result
& (INT8_MAX
+ 1))
564 result
|= 0xFFFFFFFFFFFFFF00ULL
;
567 if (result
& (INT16_MAX
+ 1))
568 result
|= 0xFFFFFFFFFFFF0000ULL
;
571 if (result
& (INT32_MAX
+ 1ULL))
572 result
|= 0xFFFFFFFF00000000ULL
;
577 if (num_garbage_negative_strs
[i
].result
== (int64_t) result
)
579 printf("Error: parsing %s as %s failed: result mismatch!\n",
580 num_garbage_negative_strs
[i
].str
, buf
);
586 memset(&buf
, 0, sizeof(buf
));
589 cmdline_get_help_num((cmdline_parse_token_hdr_t
*)&token
,