4 * Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
17 * * Neither the name of Intel Corporation nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 #include <rte_string_fns.h>
40 #include <cmdline_parse.h>
41 #include <cmdline_parse_num.h>
43 #include "test_cmdline.h"
45 struct num_unsigned_str
{
50 struct num_signed_str
{
55 const struct num_unsigned_str num_valid_positive_strs
[] = {
56 /* decimal positive */
59 {"128", INT8_MAX
+ 1 },
61 {"256", UINT8_MAX
+ 1 },
62 {"32767", INT16_MAX
},
63 {"32768", INT16_MAX
+ 1 },
64 {"65535", UINT16_MAX
},
65 {"65536", UINT16_MAX
+ 1 },
66 {"2147483647", INT32_MAX
},
67 {"2147483648", INT32_MAX
+ 1U },
68 {"4294967295", UINT32_MAX
},
69 {"4294967296", UINT32_MAX
+ 1ULL },
70 {"9223372036854775807", INT64_MAX
},
71 {"9223372036854775808", INT64_MAX
+ 1ULL},
72 {"18446744073709551615", UINT64_MAX
},
73 /* hexadecimal (no leading zeroes) */
76 {"0x80", INT8_MAX
+ 1 },
78 {"0x100", UINT8_MAX
+ 1 },
79 {"0x7FFF", INT16_MAX
},
80 {"0x8000", INT16_MAX
+ 1 },
81 {"0xFFFF", UINT16_MAX
},
82 {"0x10000", UINT16_MAX
+ 1 },
83 {"0x7FFFFFFF", INT32_MAX
},
84 {"0x80000000", INT32_MAX
+ 1U },
85 {"0xFFFFFFFF", UINT32_MAX
},
86 {"0x100000000", UINT32_MAX
+ 1ULL },
87 {"0x7FFFFFFFFFFFFFFF", INT64_MAX
},
88 {"0x8000000000000000", INT64_MAX
+ 1ULL},
89 {"0xFFFFFFFFFFFFFFFF", UINT64_MAX
},
90 /* hexadecimal (with leading zeroes) */
93 {"0x80", INT8_MAX
+ 1 },
95 {"0x0100", UINT8_MAX
+ 1 },
96 {"0x7FFF", INT16_MAX
},
97 {"0x8000", INT16_MAX
+ 1 },
98 {"0xFFFF", UINT16_MAX
},
99 {"0x00010000", UINT16_MAX
+ 1 },
100 {"0x7FFFFFFF", INT32_MAX
},
101 {"0x80000000", INT32_MAX
+ 1U },
102 {"0xFFFFFFFF", UINT32_MAX
},
103 {"0x0000000100000000", UINT32_MAX
+ 1ULL },
104 {"0x7FFFFFFFFFFFFFFF", INT64_MAX
},
105 {"0x8000000000000000", INT64_MAX
+ 1ULL},
106 {"0xFFFFFFFFFFFFFFFF", UINT64_MAX
},
107 /* check all characters */
108 {"0x1234567890ABCDEF", 0x1234567890ABCDEFULL
},
109 {"0x1234567890abcdef", 0x1234567890ABCDEFULL
},
110 /* binary (no leading zeroes) */
112 {"0b1111111", INT8_MAX
},
113 {"0b10000000", INT8_MAX
+ 1 },
114 {"0b11111111", UINT8_MAX
},
115 {"0b100000000", UINT8_MAX
+ 1 },
116 {"0b111111111111111", INT16_MAX
},
117 {"0b1000000000000000", INT16_MAX
+ 1 },
118 {"0b1111111111111111", UINT16_MAX
},
119 {"0b10000000000000000", UINT16_MAX
+ 1 },
120 {"0b1111111111111111111111111111111", INT32_MAX
},
121 {"0b10000000000000000000000000000000", INT32_MAX
+ 1U },
122 {"0b11111111111111111111111111111111", UINT32_MAX
},
123 {"0b100000000000000000000000000000000", UINT32_MAX
+ 1ULL },
124 {"0b111111111111111111111111111111111111111111111111111111111111111",
126 {"0b1000000000000000000000000000000000000000000000000000000000000000",
128 {"0b1111111111111111111111111111111111111111111111111111111111111111",
130 /* binary (with leading zeroes) */
131 {"0b01111111", INT8_MAX
},
132 {"0b0000000100000000", UINT8_MAX
+ 1 },
133 {"0b0111111111111111", INT16_MAX
},
134 {"0b00000000000000010000000000000000", UINT16_MAX
+ 1 },
135 {"0b01111111111111111111111111111111", INT32_MAX
},
136 {"0b0000000000000000000000000000000100000000000000000000000000000000",
138 {"0b0111111111111111111111111111111111111111111111111111111111111111",
143 {"0200", INT8_MAX
+ 1 },
144 {"0377", UINT8_MAX
},
145 {"0400", UINT8_MAX
+ 1 },
146 {"077777", INT16_MAX
},
147 {"0100000", INT16_MAX
+ 1 },
148 {"0177777", UINT16_MAX
},
149 {"0200000", UINT16_MAX
+ 1 },
150 {"017777777777", INT32_MAX
},
151 {"020000000000", INT32_MAX
+ 1U },
152 {"037777777777", UINT32_MAX
},
153 {"040000000000", UINT32_MAX
+ 1ULL },
154 {"0777777777777777777777", INT64_MAX
},
155 {"01000000000000000000000", INT64_MAX
+ 1ULL},
156 {"01777777777777777777777", UINT64_MAX
},
157 /* check all numbers */
158 {"012345670", 012345670 },
159 {"076543210", 076543210 },
162 const struct num_signed_str num_valid_negative_strs
[] = {
163 /* deciman negative */
165 {"-129", INT8_MIN
- 1 },
166 {"-32768", INT16_MIN
},
167 {"-32769", INT16_MIN
- 1 },
168 {"-2147483648", INT32_MIN
},
169 {"-2147483649", INT32_MIN
- 1LL },
170 {"-9223372036854775808", INT64_MIN
},
173 const struct num_unsigned_str num_garbage_positive_strs
[] = {
174 /* valid strings with garbage on the end, should still be valid */
176 {"9223372036854775807\0garbage", INT64_MAX
},
177 {"9223372036854775807\tgarbage", INT64_MAX
},
178 {"9223372036854775807\rgarbage", INT64_MAX
},
179 {"9223372036854775807\ngarbage", INT64_MAX
},
180 {"9223372036854775807#garbage", INT64_MAX
},
181 {"9223372036854775807 garbage", INT64_MAX
},
183 {"0x7FFFFFFFFFFFFFFF\0garbage", INT64_MAX
},
184 {"0x7FFFFFFFFFFFFFFF\tgarbage", INT64_MAX
},
185 {"0x7FFFFFFFFFFFFFFF\rgarbage", INT64_MAX
},
186 {"0x7FFFFFFFFFFFFFFF\ngarbage", INT64_MAX
},
187 {"0x7FFFFFFFFFFFFFFF#garbage", INT64_MAX
},
188 {"0x7FFFFFFFFFFFFFFF garbage", INT64_MAX
},
190 {"0b1111111111111111111111111111111\0garbage", INT32_MAX
},
191 {"0b1111111111111111111111111111111\rgarbage", INT32_MAX
},
192 {"0b1111111111111111111111111111111\tgarbage", INT32_MAX
},
193 {"0b1111111111111111111111111111111\ngarbage", INT32_MAX
},
194 {"0b1111111111111111111111111111111#garbage", INT32_MAX
},
195 {"0b1111111111111111111111111111111 garbage", INT32_MAX
},
197 {"01777777777777777777777\0garbage", UINT64_MAX
},
198 {"01777777777777777777777\rgarbage", UINT64_MAX
},
199 {"01777777777777777777777\tgarbage", UINT64_MAX
},
200 {"01777777777777777777777\ngarbage", UINT64_MAX
},
201 {"01777777777777777777777#garbage", UINT64_MAX
},
202 {"01777777777777777777777 garbage", UINT64_MAX
},
205 const struct num_signed_str num_garbage_negative_strs
[] = {
206 /* valid strings with garbage on the end, should still be valid */
207 {"-9223372036854775808\0garbage", INT64_MIN
},
208 {"-9223372036854775808\rgarbage", INT64_MIN
},
209 {"-9223372036854775808\tgarbage", INT64_MIN
},
210 {"-9223372036854775808\ngarbage", INT64_MIN
},
211 {"-9223372036854775808#garbage", INT64_MIN
},
212 {"-9223372036854775808 garbage", INT64_MIN
},
215 const char * num_invalid_strs
[] = {
216 "18446744073709551616", /* out of range unsigned */
217 "-9223372036854775809", /* out of range negative signed */
218 "0x10000000000000000", /* out of range hex */
219 /* out of range binary */
220 "0b10000000000000000000000000000000000000000000000000000000000000000",
221 "020000000000000000000000", /* out of range octal */
227 /* false negative numbers */
231 /* too long (128+ chars) */
232 "0b1111000011110000111100001111000011110000111100001111000011110000"
233 "1111000011110000111100001111000011110000111100001111000011110000",
248 #define NUM_POSITIVE_STRS_SIZE \
249 (sizeof(num_valid_positive_strs) / sizeof(num_valid_positive_strs[0]))
250 #define NUM_NEGATIVE_STRS_SIZE \
251 (sizeof(num_valid_negative_strs) / sizeof(num_valid_negative_strs[0]))
252 #define NUM_POSITIVE_GARBAGE_STRS_SIZE \
253 (sizeof(num_garbage_positive_strs) / sizeof(num_garbage_positive_strs[0]))
254 #define NUM_NEGATIVE_GARBAGE_STRS_SIZE \
255 (sizeof(num_garbage_negative_strs) / sizeof(num_garbage_negative_strs[0]))
256 #define NUM_INVALID_STRS_SIZE \
257 (sizeof(num_invalid_strs) / sizeof(num_invalid_strs[0]))
262 can_parse_unsigned(uint64_t expected_result
, enum cmdline_numtype type
)
266 if (expected_result
> UINT8_MAX
)
270 if (expected_result
> UINT16_MAX
)
274 if (expected_result
> UINT32_MAX
)
278 if (expected_result
> INT8_MAX
)
282 if (expected_result
> INT16_MAX
)
286 if (expected_result
> INT32_MAX
)
290 if (expected_result
> INT64_MAX
)
300 can_parse_signed(int64_t expected_result
, enum cmdline_numtype type
)
304 if (expected_result
> UINT8_MAX
|| expected_result
< 0)
308 if (expected_result
> UINT16_MAX
|| expected_result
< 0)
312 if (expected_result
> UINT32_MAX
|| expected_result
< 0)
316 if (expected_result
< 0)
320 if (expected_result
> INT8_MAX
|| expected_result
< INT8_MIN
)
324 if (expected_result
> INT16_MAX
|| expected_result
< INT16_MIN
)
328 if (expected_result
> INT32_MAX
|| expected_result
< INT32_MIN
)
337 /* test invalid parameters */
339 test_parse_num_invalid_param(void)
341 char buf
[CMDLINE_TEST_BUFSIZE
];
343 cmdline_parse_token_num_t token
;
347 token
.num_data
.type
= UINT32
;
349 /* copy string to buffer */
350 snprintf(buf
, sizeof(buf
), "%s",
351 num_valid_positive_strs
[0].str
);
354 ret
= cmdline_parse_num(NULL
, NULL
, NULL
, 0);
356 printf("Error: parser accepted null parameters!\n");
361 ret
= cmdline_parse_num(NULL
, buf
, (void*)&result
, sizeof(result
));
363 printf("Error: parser accepted null token!\n");
368 ret
= cmdline_parse_num((cmdline_parse_token_hdr_t
*)&token
, NULL
,
369 (void*)&result
, sizeof(result
));
371 printf("Error: parser accepted null string!\n");
375 /* try null result */
376 ret
= cmdline_parse_num((cmdline_parse_token_hdr_t
*)&token
, buf
,
379 printf("Error: parser rejected null result!\n");
383 /* test help function */
384 memset(&buf
, 0, sizeof(buf
));
387 ret
= cmdline_get_help_num(NULL
, NULL
, 0);
389 printf("Error: help function accepted null parameters!\n");
394 ret
= cmdline_get_help_num(NULL
, buf
, sizeof(buf
));
396 printf("Error: help function accepted null token!\n");
401 ret
= cmdline_get_help_num((cmdline_parse_token_hdr_t
*)&token
, buf
, sizeof(buf
));
403 printf("Error: help function failed with valid parameters!\n");
409 /* test valid parameters but invalid data */
411 test_parse_num_invalid_data(void)
413 enum cmdline_numtype type
;
416 char buf
[CMDLINE_TEST_BUFSIZE
];
417 uint64_t result
; /* pick largest buffer */
418 cmdline_parse_token_num_t token
;
420 /* cycle through all possible parsed types */
421 for (type
= UINT8
; type
<= INT64
; type
++) {
422 token
.num_data
.type
= type
;
424 /* test full strings */
425 for (i
= 0; i
< NUM_INVALID_STRS_SIZE
; i
++) {
427 memset(&result
, 0, sizeof(uint64_t));
428 memset(&buf
, 0, sizeof(buf
));
430 ret
= cmdline_parse_num((cmdline_parse_token_hdr_t
*)&token
,
431 num_invalid_strs
[i
], (void*)&result
, sizeof(result
));
433 /* get some info about what we are trying to parse */
434 cmdline_get_help_num((cmdline_parse_token_hdr_t
*)&token
,
437 printf("Error: parsing %s as %s succeeded!\n",
438 num_invalid_strs
[i
], buf
);
446 /* test valid parameters and data */
448 test_parse_num_valid(void)
451 enum cmdline_numtype type
;
453 char buf
[CMDLINE_TEST_BUFSIZE
];
455 cmdline_parse_token_num_t token
;
457 /** valid strings **/
459 /* cycle through all possible parsed types */
460 for (type
= UINT8
; type
<= INT64
; type
++) {
461 token
.num_data
.type
= type
;
463 /* test positive strings */
464 for (i
= 0; i
< NUM_POSITIVE_STRS_SIZE
; i
++) {
466 memset(&buf
, 0, sizeof(buf
));
468 cmdline_get_help_num((cmdline_parse_token_hdr_t
*)&token
,
471 ret
= cmdline_parse_num((cmdline_parse_token_hdr_t
*) &token
,
472 num_valid_positive_strs
[i
].str
,
473 (void*)&result
, sizeof(result
));
475 /* if it should have passed but didn't, or if it should have failed but didn't */
476 if ((ret
< 0) == (can_parse_unsigned(num_valid_positive_strs
[i
].result
, type
) > 0)) {
477 printf("Error: parser behaves unexpectedly when parsing %s as %s!\n",
478 num_valid_positive_strs
[i
].str
, buf
);
481 /* check if result matches what it should have matched
482 * since unsigned numbers don't care about number of bits, we can just convert
483 * everything to uint64_t without any worries. */
484 if (ret
> 0 && num_valid_positive_strs
[i
].result
!= result
) {
485 printf("Error: parsing %s as %s failed: result mismatch!\n",
486 num_valid_positive_strs
[i
].str
, buf
);
491 /* test negative strings */
492 for (i
= 0; i
< NUM_NEGATIVE_STRS_SIZE
; i
++) {
494 memset(&buf
, 0, sizeof(buf
));
496 cmdline_get_help_num((cmdline_parse_token_hdr_t
*)&token
,
499 ret
= cmdline_parse_num((cmdline_parse_token_hdr_t
*) &token
,
500 num_valid_negative_strs
[i
].str
,
501 (void*)&result
, sizeof(result
));
503 /* if it should have passed but didn't, or if it should have failed but didn't */
504 if ((ret
< 0) == (can_parse_signed(num_valid_negative_strs
[i
].result
, type
) > 0)) {
505 printf("Error: parser behaves unexpectedly when parsing %s as %s!\n",
506 num_valid_negative_strs
[i
].str
, buf
);
509 /* check if result matches what it should have matched
510 * the result is signed in this case, so we have to account for that */
512 /* detect negative */
515 result
= (int8_t) result
;
518 result
= (int16_t) result
;
521 result
= (int32_t) result
;
526 if (num_valid_negative_strs
[i
].result
== (int64_t) result
)
528 printf("Error: parsing %s as %s failed: result mismatch!\n",
529 num_valid_negative_strs
[i
].str
, buf
);
535 /** garbage strings **/
537 /* cycle through all possible parsed types */
538 for (type
= UINT8
; type
<= INT64
; type
++) {
539 token
.num_data
.type
= type
;
541 /* test positive garbage strings */
542 for (i
= 0; i
< NUM_POSITIVE_GARBAGE_STRS_SIZE
; i
++) {
544 memset(&buf
, 0, sizeof(buf
));
546 cmdline_get_help_num((cmdline_parse_token_hdr_t
*)&token
,
549 ret
= cmdline_parse_num((cmdline_parse_token_hdr_t
*) &token
,
550 num_garbage_positive_strs
[i
].str
,
551 (void*)&result
, sizeof(result
));
553 /* if it should have passed but didn't, or if it should have failed but didn't */
554 if ((ret
< 0) == (can_parse_unsigned(num_garbage_positive_strs
[i
].result
, type
) > 0)) {
555 printf("Error: parser behaves unexpectedly when parsing %s as %s!\n",
556 num_garbage_positive_strs
[i
].str
, buf
);
559 /* check if result matches what it should have matched
560 * since unsigned numbers don't care about number of bits, we can just convert
561 * everything to uint64_t without any worries. */
562 if (ret
> 0 && num_garbage_positive_strs
[i
].result
!= result
) {
563 printf("Error: parsing %s as %s failed: result mismatch!\n",
564 num_garbage_positive_strs
[i
].str
, buf
);
569 /* test negative strings */
570 for (i
= 0; i
< NUM_NEGATIVE_GARBAGE_STRS_SIZE
; i
++) {
572 memset(&buf
, 0, sizeof(buf
));
574 cmdline_get_help_num((cmdline_parse_token_hdr_t
*)&token
,
577 ret
= cmdline_parse_num((cmdline_parse_token_hdr_t
*) &token
,
578 num_garbage_negative_strs
[i
].str
,
579 (void*)&result
, sizeof(result
));
581 /* if it should have passed but didn't, or if it should have failed but didn't */
582 if ((ret
< 0) == (can_parse_signed(num_garbage_negative_strs
[i
].result
, type
) > 0)) {
583 printf("Error: parser behaves unexpectedly when parsing %s as %s!\n",
584 num_garbage_negative_strs
[i
].str
, buf
);
587 /* check if result matches what it should have matched
588 * the result is signed in this case, so we have to account for that */
590 /* detect negative */
593 if (result
& (INT8_MAX
+ 1))
594 result
|= 0xFFFFFFFFFFFFFF00ULL
;
597 if (result
& (INT16_MAX
+ 1))
598 result
|= 0xFFFFFFFFFFFF0000ULL
;
601 if (result
& (INT32_MAX
+ 1ULL))
602 result
|= 0xFFFFFFFF00000000ULL
;
607 if (num_garbage_negative_strs
[i
].result
== (int64_t) result
)
609 printf("Error: parsing %s as %s failed: result mismatch!\n",
610 num_garbage_negative_strs
[i
].str
, buf
);
616 memset(&buf
, 0, sizeof(buf
));
619 cmdline_get_help_num((cmdline_parse_token_hdr_t
*)&token
,