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.
37 #include <rte_string_fns.h>
39 #include <cmdline_parse.h>
40 #include <cmdline_parse_num.h>
42 #include "test_cmdline.h"
44 struct num_unsigned_str {
49 struct num_signed_str {
54 const struct num_unsigned_str num_valid_positive_strs[] = {
55 /* decimal positive */
58 {"128", INT8_MAX + 1 },
60 {"256", UINT8_MAX + 1 },
61 {"32767", INT16_MAX },
62 {"32768", INT16_MAX + 1 },
63 {"65535", UINT16_MAX },
64 {"65536", UINT16_MAX + 1 },
65 {"2147483647", INT32_MAX },
66 {"2147483648", INT32_MAX + 1U },
67 {"4294967295", UINT32_MAX },
68 {"4294967296", UINT32_MAX + 1ULL },
69 {"9223372036854775807", INT64_MAX },
70 {"9223372036854775808", INT64_MAX + 1ULL},
71 {"18446744073709551615", UINT64_MAX },
72 /* hexadecimal (no leading zeroes) */
75 {"0x80", INT8_MAX + 1 },
77 {"0x100", UINT8_MAX + 1 },
78 {"0x7FFF", INT16_MAX },
79 {"0x8000", INT16_MAX + 1 },
80 {"0xFFFF", UINT16_MAX },
81 {"0x10000", UINT16_MAX + 1 },
82 {"0x7FFFFFFF", INT32_MAX },
83 {"0x80000000", INT32_MAX + 1U },
84 {"0xFFFFFFFF", UINT32_MAX },
85 {"0x100000000", UINT32_MAX + 1ULL },
86 {"0x7FFFFFFFFFFFFFFF", INT64_MAX },
87 {"0x8000000000000000", INT64_MAX + 1ULL},
88 {"0xFFFFFFFFFFFFFFFF", UINT64_MAX },
89 /* hexadecimal (with leading zeroes) */
92 {"0x80", INT8_MAX + 1 },
94 {"0x0100", UINT8_MAX + 1 },
95 {"0x7FFF", INT16_MAX },
96 {"0x8000", INT16_MAX + 1 },
97 {"0xFFFF", UINT16_MAX },
98 {"0x00010000", UINT16_MAX + 1 },
99 {"0x7FFFFFFF", INT32_MAX },
100 {"0x80000000", INT32_MAX + 1U },
101 {"0xFFFFFFFF", UINT32_MAX },
102 {"0x0000000100000000", UINT32_MAX + 1ULL },
103 {"0x7FFFFFFFFFFFFFFF", INT64_MAX },
104 {"0x8000000000000000", INT64_MAX + 1ULL},
105 {"0xFFFFFFFFFFFFFFFF", UINT64_MAX },
106 /* check all characters */
107 {"0x1234567890ABCDEF", 0x1234567890ABCDEFULL },
108 {"0x1234567890abcdef", 0x1234567890ABCDEFULL },
109 /* binary (no leading zeroes) */
111 {"0b1111111", INT8_MAX },
112 {"0b10000000", INT8_MAX + 1 },
113 {"0b11111111", UINT8_MAX },
114 {"0b100000000", UINT8_MAX + 1 },
115 {"0b111111111111111", INT16_MAX },
116 {"0b1000000000000000", INT16_MAX + 1 },
117 {"0b1111111111111111", UINT16_MAX },
118 {"0b10000000000000000", UINT16_MAX + 1 },
119 {"0b1111111111111111111111111111111", INT32_MAX },
120 {"0b10000000000000000000000000000000", INT32_MAX + 1U },
121 {"0b11111111111111111111111111111111", UINT32_MAX },
122 {"0b100000000000000000000000000000000", UINT32_MAX + 1ULL },
123 {"0b111111111111111111111111111111111111111111111111111111111111111",
125 {"0b1000000000000000000000000000000000000000000000000000000000000000",
127 {"0b1111111111111111111111111111111111111111111111111111111111111111",
129 /* binary (with leading zeroes) */
130 {"0b01111111", INT8_MAX },
131 {"0b0000000100000000", UINT8_MAX + 1 },
132 {"0b0111111111111111", INT16_MAX },
133 {"0b00000000000000010000000000000000", UINT16_MAX + 1 },
134 {"0b01111111111111111111111111111111", INT32_MAX },
135 {"0b0000000000000000000000000000000100000000000000000000000000000000",
137 {"0b0111111111111111111111111111111111111111111111111111111111111111",
142 {"0200", INT8_MAX + 1 },
143 {"0377", UINT8_MAX },
144 {"0400", UINT8_MAX + 1 },
145 {"077777", INT16_MAX },
146 {"0100000", INT16_MAX + 1 },
147 {"0177777", UINT16_MAX },
148 {"0200000", UINT16_MAX + 1 },
149 {"017777777777", INT32_MAX },
150 {"020000000000", INT32_MAX + 1U },
151 {"037777777777", UINT32_MAX },
152 {"040000000000", UINT32_MAX + 1ULL },
153 {"0777777777777777777777", INT64_MAX },
154 {"01000000000000000000000", INT64_MAX + 1ULL},
155 {"01777777777777777777777", UINT64_MAX },
156 /* check all numbers */
157 {"012345670", 012345670 },
158 {"076543210", 076543210 },
161 const struct num_signed_str num_valid_negative_strs[] = {
162 /* deciman negative */
164 {"-129", INT8_MIN - 1 },
165 {"-32768", INT16_MIN },
166 {"-32769", INT16_MIN - 1 },
167 {"-2147483648", INT32_MIN },
168 {"-2147483649", INT32_MIN - 1LL },
169 {"-9223372036854775808", INT64_MIN },
172 const struct num_unsigned_str num_garbage_positive_strs[] = {
173 /* valid strings with garbage on the end, should still be valid */
175 {"9223372036854775807\0garbage", INT64_MAX },
176 {"9223372036854775807\tgarbage", INT64_MAX },
177 {"9223372036854775807\rgarbage", INT64_MAX },
178 {"9223372036854775807\ngarbage", INT64_MAX },
179 {"9223372036854775807#garbage", INT64_MAX },
180 {"9223372036854775807 garbage", INT64_MAX },
182 {"0x7FFFFFFFFFFFFFFF\0garbage", INT64_MAX },
183 {"0x7FFFFFFFFFFFFFFF\tgarbage", INT64_MAX },
184 {"0x7FFFFFFFFFFFFFFF\rgarbage", INT64_MAX },
185 {"0x7FFFFFFFFFFFFFFF\ngarbage", INT64_MAX },
186 {"0x7FFFFFFFFFFFFFFF#garbage", INT64_MAX },
187 {"0x7FFFFFFFFFFFFFFF garbage", INT64_MAX },
189 {"0b1111111111111111111111111111111\0garbage", INT32_MAX },
190 {"0b1111111111111111111111111111111\rgarbage", INT32_MAX },
191 {"0b1111111111111111111111111111111\tgarbage", INT32_MAX },
192 {"0b1111111111111111111111111111111\ngarbage", INT32_MAX },
193 {"0b1111111111111111111111111111111#garbage", INT32_MAX },
194 {"0b1111111111111111111111111111111 garbage", INT32_MAX },
196 {"01777777777777777777777\0garbage", UINT64_MAX },
197 {"01777777777777777777777\rgarbage", UINT64_MAX },
198 {"01777777777777777777777\tgarbage", UINT64_MAX },
199 {"01777777777777777777777\ngarbage", UINT64_MAX },
200 {"01777777777777777777777#garbage", UINT64_MAX },
201 {"01777777777777777777777 garbage", UINT64_MAX },
204 const struct num_signed_str num_garbage_negative_strs[] = {
205 /* valid strings with garbage on the end, should still be valid */
206 {"-9223372036854775808\0garbage", INT64_MIN },
207 {"-9223372036854775808\rgarbage", INT64_MIN },
208 {"-9223372036854775808\tgarbage", INT64_MIN },
209 {"-9223372036854775808\ngarbage", INT64_MIN },
210 {"-9223372036854775808#garbage", INT64_MIN },
211 {"-9223372036854775808 garbage", INT64_MIN },
214 const char * num_invalid_strs[] = {
215 "18446744073709551616", /* out of range unsigned */
216 "-9223372036854775809", /* out of range negative signed */
217 "0x10000000000000000", /* out of range hex */
218 /* out of range binary */
219 "0b10000000000000000000000000000000000000000000000000000000000000000",
220 "020000000000000000000000", /* out of range octal */
226 /* false negative numbers */
230 /* too long (128+ chars) */
231 "0b1111000011110000111100001111000011110000111100001111000011110000"
232 "1111000011110000111100001111000011110000111100001111000011110000",
247 #define NUM_POSITIVE_STRS_SIZE \
248 (sizeof(num_valid_positive_strs) / sizeof(num_valid_positive_strs[0]))
249 #define NUM_NEGATIVE_STRS_SIZE \
250 (sizeof(num_valid_negative_strs) / sizeof(num_valid_negative_strs[0]))
251 #define NUM_POSITIVE_GARBAGE_STRS_SIZE \
252 (sizeof(num_garbage_positive_strs) / sizeof(num_garbage_positive_strs[0]))
253 #define NUM_NEGATIVE_GARBAGE_STRS_SIZE \
254 (sizeof(num_garbage_negative_strs) / sizeof(num_garbage_negative_strs[0]))
255 #define NUM_INVALID_STRS_SIZE \
256 (sizeof(num_invalid_strs) / sizeof(num_invalid_strs[0]))
261 can_parse_unsigned(uint64_t expected_result, enum cmdline_numtype type)
265 if (expected_result > UINT8_MAX)
269 if (expected_result > UINT16_MAX)
273 if (expected_result > UINT32_MAX)
277 if (expected_result > INT8_MAX)
281 if (expected_result > INT16_MAX)
285 if (expected_result > INT32_MAX)
289 if (expected_result > INT64_MAX)
299 can_parse_signed(int64_t expected_result, enum cmdline_numtype type)
303 if (expected_result > UINT8_MAX || expected_result < 0)
307 if (expected_result > UINT16_MAX || expected_result < 0)
311 if (expected_result > UINT32_MAX || expected_result < 0)
315 if (expected_result < 0)
318 if (expected_result > INT8_MAX || expected_result < INT8_MIN)
322 if (expected_result > INT16_MAX || expected_result < INT16_MIN)
326 if (expected_result > INT32_MAX || expected_result < INT32_MIN)
335 /* test invalid parameters */
337 test_parse_num_invalid_param(void)
339 char buf[CMDLINE_TEST_BUFSIZE];
341 cmdline_parse_token_num_t token;
345 token.num_data.type = UINT32;
347 /* copy string to buffer */
348 rte_snprintf(buf, sizeof(buf), "%s",
349 num_valid_positive_strs[0].str);
352 ret = cmdline_parse_num(NULL, NULL, NULL);
354 printf("Error: parser accepted null parameters!\n");
359 ret = cmdline_parse_num(NULL, buf, (void*)&result);
361 printf("Error: parser accepted null token!\n");
366 ret = cmdline_parse_num((cmdline_parse_token_hdr_t*)&token, NULL,
369 printf("Error: parser accepted null string!\n");
373 /* try null result */
374 ret = cmdline_parse_num((cmdline_parse_token_hdr_t*)&token, buf, NULL);
376 printf("Error: parser rejected null result!\n");
380 /* test help function */
381 memset(&buf, 0, sizeof(buf));
384 ret = cmdline_get_help_num(NULL, NULL, 0);
386 printf("Error: help function accepted null parameters!\n");
391 ret = cmdline_get_help_num(NULL, buf, sizeof(buf));
393 printf("Error: help function accepted null token!\n");
398 ret = cmdline_get_help_num((cmdline_parse_token_hdr_t*)&token, NULL, sizeof(buf));
400 printf("Error: help function accepted null buffer!\n");
405 ret = cmdline_get_help_num((cmdline_parse_token_hdr_t*)&token, buf, sizeof(buf));
407 printf("Error: help function failed with valid parameters!\n");
413 /* test valid parameters but invalid data */
415 test_parse_num_invalid_data(void)
417 enum cmdline_numtype type;
420 char buf[CMDLINE_TEST_BUFSIZE];
421 uint64_t result; /* pick largest buffer */
422 cmdline_parse_token_num_t token;
424 /* cycle through all possible parsed types */
425 for (type = UINT8; type <= INT64; type++) {
426 token.num_data.type = type;
428 /* test full strings */
429 for (i = 0; i < NUM_INVALID_STRS_SIZE; i++) {
431 memset(&result, 0, sizeof(uint64_t));
432 memset(&buf, 0, sizeof(buf));
434 ret = cmdline_parse_num((cmdline_parse_token_hdr_t*)&token,
435 num_invalid_strs[i], (void*)&result);
437 /* get some info about what we are trying to parse */
438 cmdline_get_help_num((cmdline_parse_token_hdr_t*)&token,
441 printf("Error: parsing %s as %s succeeded!\n",
442 num_invalid_strs[i], buf);
450 /* test valid parameters and data */
452 test_parse_num_valid(void)
455 enum cmdline_numtype type;
457 char buf[CMDLINE_TEST_BUFSIZE];
459 cmdline_parse_token_num_t token;
461 /** valid strings **/
463 /* cycle through all possible parsed types */
464 for (type = UINT8; type <= INT64; type++) {
465 token.num_data.type = type;
467 /* test positive strings */
468 for (i = 0; i < NUM_POSITIVE_STRS_SIZE; i++) {
470 memset(&buf, 0, sizeof(buf));
472 cmdline_get_help_num((cmdline_parse_token_hdr_t*)&token,
475 ret = cmdline_parse_num((cmdline_parse_token_hdr_t*) &token, num_valid_positive_strs[i].str,
478 /* if it should have passed but didn't, or if it should have failed but didn't */
479 if ((ret < 0) == (can_parse_unsigned(num_valid_positive_strs[i].result, type) > 0)) {
480 printf("Error: parser behaves unexpectedly when parsing %s as %s!\n",
481 num_valid_positive_strs[i].str, buf);
484 /* check if result matches what it should have matched
485 * since unsigned numbers don't care about number of bits, we can just convert
486 * everything to uint64_t without any worries. */
487 if (ret > 0 && num_valid_positive_strs[i].result != result) {
488 printf("Error: parsing %s as %s failed: result mismatch!\n",
489 num_valid_positive_strs[i].str, buf);
494 /* test negative strings */
495 for (i = 0; i < NUM_NEGATIVE_STRS_SIZE; i++) {
497 memset(&buf, 0, sizeof(buf));
499 cmdline_get_help_num((cmdline_parse_token_hdr_t*)&token,
502 ret = cmdline_parse_num((cmdline_parse_token_hdr_t*) &token, num_valid_negative_strs[i].str,
505 /* if it should have passed but didn't, or if it should have failed but didn't */
506 if ((ret < 0) == (can_parse_signed(num_valid_negative_strs[i].result, type) > 0)) {
507 printf("Error: parser behaves unexpectedly when parsing %s as %s!\n",
508 num_valid_negative_strs[i].str, buf);
511 /* check if result matches what it should have matched
512 * the result is signed in this case, so we have to account for that */
514 /* detect negative */
517 result = (int8_t) result;
520 result = (int16_t) result;
523 result = (int32_t) result;
528 if (num_valid_negative_strs[i].result == (int64_t) result)
530 printf("Error: parsing %s as %s failed: result mismatch!\n",
531 num_valid_negative_strs[i].str, buf);
537 /** garbage strings **/
539 /* cycle through all possible parsed types */
540 for (type = UINT8; type <= INT64; type++) {
541 token.num_data.type = type;
543 /* test positive garbage strings */
544 for (i = 0; i < NUM_POSITIVE_GARBAGE_STRS_SIZE; i++) {
546 memset(&buf, 0, sizeof(buf));
548 cmdline_get_help_num((cmdline_parse_token_hdr_t*)&token,
551 ret = cmdline_parse_num((cmdline_parse_token_hdr_t*) &token, num_garbage_positive_strs[i].str,
554 /* if it should have passed but didn't, or if it should have failed but didn't */
555 if ((ret < 0) == (can_parse_unsigned(num_garbage_positive_strs[i].result, type) > 0)) {
556 printf("Error: parser behaves unexpectedly when parsing %s as %s!\n",
557 num_garbage_positive_strs[i].str, buf);
560 /* check if result matches what it should have matched
561 * since unsigned numbers don't care about number of bits, we can just convert
562 * everything to uint64_t without any worries. */
563 if (ret > 0 && num_garbage_positive_strs[i].result != result) {
564 printf("Error: parsing %s as %s failed: result mismatch!\n",
565 num_garbage_positive_strs[i].str, buf);
570 /* test negative strings */
571 for (i = 0; i < NUM_NEGATIVE_GARBAGE_STRS_SIZE; i++) {
573 memset(&buf, 0, sizeof(buf));
575 cmdline_get_help_num((cmdline_parse_token_hdr_t*)&token,
578 ret = cmdline_parse_num((cmdline_parse_token_hdr_t*) &token, num_garbage_negative_strs[i].str,
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,