numam-dpdk/app/test/test_cmdline_num.c
Bruce Richardson e9d48c0072 update Intel copyright years to 2014
Signed-off-by: Bruce Richardson <bruce.richardson@intel.com>
2014-02-25 21:29:14 +01:00

624 lines
18 KiB
C

/*-
* BSD LICENSE
*
* Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Intel Corporation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <string.h>
#include <inttypes.h>
#include <rte_string_fns.h>
#include <cmdline_parse.h>
#include <cmdline_parse_num.h>
#include "test_cmdline.h"
struct num_unsigned_str {
const char * str;
uint64_t result;
};
struct num_signed_str {
const char * str;
int64_t result;
};
const struct num_unsigned_str num_valid_positive_strs[] = {
/* decimal positive */
{"0", 0 },
{"127", INT8_MAX },
{"128", INT8_MAX + 1 },
{"255", UINT8_MAX },
{"256", UINT8_MAX + 1 },
{"32767", INT16_MAX },
{"32768", INT16_MAX + 1 },
{"65535", UINT16_MAX },
{"65536", UINT16_MAX + 1 },
{"2147483647", INT32_MAX },
{"2147483648", INT32_MAX + 1U },
{"4294967295", UINT32_MAX },
{"4294967296", UINT32_MAX + 1ULL },
{"9223372036854775807", INT64_MAX },
{"9223372036854775808", INT64_MAX + 1ULL},
{"18446744073709551615", UINT64_MAX },
/* hexadecimal (no leading zeroes) */
{"0x0", 0 },
{"0x7F", INT8_MAX },
{"0x80", INT8_MAX + 1 },
{"0xFF", UINT8_MAX },
{"0x100", UINT8_MAX + 1 },
{"0x7FFF", INT16_MAX },
{"0x8000", INT16_MAX + 1 },
{"0xFFFF", UINT16_MAX },
{"0x10000", UINT16_MAX + 1 },
{"0x7FFFFFFF", INT32_MAX },
{"0x80000000", INT32_MAX + 1U },
{"0xFFFFFFFF", UINT32_MAX },
{"0x100000000", UINT32_MAX + 1ULL },
{"0x7FFFFFFFFFFFFFFF", INT64_MAX },
{"0x8000000000000000", INT64_MAX + 1ULL},
{"0xFFFFFFFFFFFFFFFF", UINT64_MAX },
/* hexadecimal (with leading zeroes) */
{"0x00", 0 },
{"0x7F", INT8_MAX },
{"0x80", INT8_MAX + 1 },
{"0xFF", UINT8_MAX },
{"0x0100", UINT8_MAX + 1 },
{"0x7FFF", INT16_MAX },
{"0x8000", INT16_MAX + 1 },
{"0xFFFF", UINT16_MAX },
{"0x00010000", UINT16_MAX + 1 },
{"0x7FFFFFFF", INT32_MAX },
{"0x80000000", INT32_MAX + 1U },
{"0xFFFFFFFF", UINT32_MAX },
{"0x0000000100000000", UINT32_MAX + 1ULL },
{"0x7FFFFFFFFFFFFFFF", INT64_MAX },
{"0x8000000000000000", INT64_MAX + 1ULL},
{"0xFFFFFFFFFFFFFFFF", UINT64_MAX },
/* check all characters */
{"0x1234567890ABCDEF", 0x1234567890ABCDEFULL },
{"0x1234567890abcdef", 0x1234567890ABCDEFULL },
/* binary (no leading zeroes) */
{"0b0", 0 },
{"0b1111111", INT8_MAX },
{"0b10000000", INT8_MAX + 1 },
{"0b11111111", UINT8_MAX },
{"0b100000000", UINT8_MAX + 1 },
{"0b111111111111111", INT16_MAX },
{"0b1000000000000000", INT16_MAX + 1 },
{"0b1111111111111111", UINT16_MAX },
{"0b10000000000000000", UINT16_MAX + 1 },
{"0b1111111111111111111111111111111", INT32_MAX },
{"0b10000000000000000000000000000000", INT32_MAX + 1U },
{"0b11111111111111111111111111111111", UINT32_MAX },
{"0b100000000000000000000000000000000", UINT32_MAX + 1ULL },
{"0b111111111111111111111111111111111111111111111111111111111111111",
INT64_MAX },
{"0b1000000000000000000000000000000000000000000000000000000000000000",
INT64_MAX + 1ULL},
{"0b1111111111111111111111111111111111111111111111111111111111111111",
UINT64_MAX },
/* binary (with leading zeroes) */
{"0b01111111", INT8_MAX },
{"0b0000000100000000", UINT8_MAX + 1 },
{"0b0111111111111111", INT16_MAX },
{"0b00000000000000010000000000000000", UINT16_MAX + 1 },
{"0b01111111111111111111111111111111", INT32_MAX },
{"0b0000000000000000000000000000000100000000000000000000000000000000",
UINT32_MAX + 1ULL },
{"0b0111111111111111111111111111111111111111111111111111111111111111",
INT64_MAX },
/* octal */
{"00", 0 },
{"0177", INT8_MAX },
{"0200", INT8_MAX + 1 },
{"0377", UINT8_MAX },
{"0400", UINT8_MAX + 1 },
{"077777", INT16_MAX },
{"0100000", INT16_MAX + 1 },
{"0177777", UINT16_MAX },
{"0200000", UINT16_MAX + 1 },
{"017777777777", INT32_MAX },
{"020000000000", INT32_MAX + 1U },
{"037777777777", UINT32_MAX },
{"040000000000", UINT32_MAX + 1ULL },
{"0777777777777777777777", INT64_MAX },
{"01000000000000000000000", INT64_MAX + 1ULL},
{"01777777777777777777777", UINT64_MAX },
/* check all numbers */
{"012345670", 012345670 },
{"076543210", 076543210 },
};
const struct num_signed_str num_valid_negative_strs[] = {
/* deciman negative */
{"-128", INT8_MIN },
{"-129", INT8_MIN - 1 },
{"-32768", INT16_MIN },
{"-32769", INT16_MIN - 1 },
{"-2147483648", INT32_MIN },
{"-2147483649", INT32_MIN - 1LL },
{"-9223372036854775808", INT64_MIN },
};
const struct num_unsigned_str num_garbage_positive_strs[] = {
/* valid strings with garbage on the end, should still be valid */
/* decimal */
{"9223372036854775807\0garbage", INT64_MAX },
{"9223372036854775807\tgarbage", INT64_MAX },
{"9223372036854775807\rgarbage", INT64_MAX },
{"9223372036854775807\ngarbage", INT64_MAX },
{"9223372036854775807#garbage", INT64_MAX },
{"9223372036854775807 garbage", INT64_MAX },
/* hex */
{"0x7FFFFFFFFFFFFFFF\0garbage", INT64_MAX },
{"0x7FFFFFFFFFFFFFFF\tgarbage", INT64_MAX },
{"0x7FFFFFFFFFFFFFFF\rgarbage", INT64_MAX },
{"0x7FFFFFFFFFFFFFFF\ngarbage", INT64_MAX },
{"0x7FFFFFFFFFFFFFFF#garbage", INT64_MAX },
{"0x7FFFFFFFFFFFFFFF garbage", INT64_MAX },
/* binary */
{"0b1111111111111111111111111111111\0garbage", INT32_MAX },
{"0b1111111111111111111111111111111\rgarbage", INT32_MAX },
{"0b1111111111111111111111111111111\tgarbage", INT32_MAX },
{"0b1111111111111111111111111111111\ngarbage", INT32_MAX },
{"0b1111111111111111111111111111111#garbage", INT32_MAX },
{"0b1111111111111111111111111111111 garbage", INT32_MAX },
/* octal */
{"01777777777777777777777\0garbage", UINT64_MAX },
{"01777777777777777777777\rgarbage", UINT64_MAX },
{"01777777777777777777777\tgarbage", UINT64_MAX },
{"01777777777777777777777\ngarbage", UINT64_MAX },
{"01777777777777777777777#garbage", UINT64_MAX },
{"01777777777777777777777 garbage", UINT64_MAX },
};
const struct num_signed_str num_garbage_negative_strs[] = {
/* valid strings with garbage on the end, should still be valid */
{"-9223372036854775808\0garbage", INT64_MIN },
{"-9223372036854775808\rgarbage", INT64_MIN },
{"-9223372036854775808\tgarbage", INT64_MIN },
{"-9223372036854775808\ngarbage", INT64_MIN },
{"-9223372036854775808#garbage", INT64_MIN },
{"-9223372036854775808 garbage", INT64_MIN },
};
const char * num_invalid_strs[] = {
"18446744073709551616", /* out of range unsigned */
"-9223372036854775809", /* out of range negative signed */
"0x10000000000000000", /* out of range hex */
/* out of range binary */
"0b10000000000000000000000000000000000000000000000000000000000000000",
"020000000000000000000000", /* out of range octal */
/* wrong chars */
"0123456239",
"0x1234580AGE",
"0b0111010101g001",
"0b01110101017001",
/* false negative numbers */
"-12345F623",
"-0x1234580A",
"-0b0111010101",
/* too long (128+ chars) */
"0b1111000011110000111100001111000011110000111100001111000011110000"
"1111000011110000111100001111000011110000111100001111000011110000",
"1E3",
"0A",
"-B",
"+4",
"1.23G",
"",
" ",
"#",
"\r",
"\t",
"\n",
"\0",
};
#define NUM_POSITIVE_STRS_SIZE \
(sizeof(num_valid_positive_strs) / sizeof(num_valid_positive_strs[0]))
#define NUM_NEGATIVE_STRS_SIZE \
(sizeof(num_valid_negative_strs) / sizeof(num_valid_negative_strs[0]))
#define NUM_POSITIVE_GARBAGE_STRS_SIZE \
(sizeof(num_garbage_positive_strs) / sizeof(num_garbage_positive_strs[0]))
#define NUM_NEGATIVE_GARBAGE_STRS_SIZE \
(sizeof(num_garbage_negative_strs) / sizeof(num_garbage_negative_strs[0]))
#define NUM_INVALID_STRS_SIZE \
(sizeof(num_invalid_strs) / sizeof(num_invalid_strs[0]))
static int
can_parse_unsigned(uint64_t expected_result, enum cmdline_numtype type)
{
switch (type) {
case UINT8:
if (expected_result > UINT8_MAX)
return 0;
break;
case UINT16:
if (expected_result > UINT16_MAX)
return 0;
break;
case UINT32:
if (expected_result > UINT32_MAX)
return 0;
break;
case INT8:
if (expected_result > INT8_MAX)
return 0;
break;
case INT16:
if (expected_result > INT16_MAX)
return 0;
break;
case INT32:
if (expected_result > INT32_MAX)
return 0;
break;
case INT64:
if (expected_result > INT64_MAX)
return 0;
break;
default:
return 1;
}
return 1;
}
static int
can_parse_signed(int64_t expected_result, enum cmdline_numtype type)
{
switch (type) {
case UINT8:
if (expected_result > UINT8_MAX || expected_result < 0)
return 0;
break;
case UINT16:
if (expected_result > UINT16_MAX || expected_result < 0)
return 0;
break;
case UINT32:
if (expected_result > UINT32_MAX || expected_result < 0)
return 0;
break;
case UINT64:
if (expected_result < 0)
return 0;
case INT8:
if (expected_result > INT8_MAX || expected_result < INT8_MIN)
return 0;
break;
case INT16:
if (expected_result > INT16_MAX || expected_result < INT16_MIN)
return 0;
break;
case INT32:
if (expected_result > INT32_MAX || expected_result < INT32_MIN)
return 0;
break;
default:
return 1;
}
return 1;
}
/* test invalid parameters */
int
test_parse_num_invalid_param(void)
{
char buf[CMDLINE_TEST_BUFSIZE];
uint32_t result;
cmdline_parse_token_num_t token;
int ret = 0;
/* set up a token */
token.num_data.type = UINT32;
/* copy string to buffer */
rte_snprintf(buf, sizeof(buf), "%s",
num_valid_positive_strs[0].str);
/* try all null */
ret = cmdline_parse_num(NULL, NULL, NULL);
if (ret != -1) {
printf("Error: parser accepted null parameters!\n");
return -1;
}
/* try null token */
ret = cmdline_parse_num(NULL, buf, (void*)&result);
if (ret != -1) {
printf("Error: parser accepted null token!\n");
return -1;
}
/* try null buf */
ret = cmdline_parse_num((cmdline_parse_token_hdr_t*)&token, NULL,
(void*)&result);
if (ret != -1) {
printf("Error: parser accepted null string!\n");
return -1;
}
/* try null result */
ret = cmdline_parse_num((cmdline_parse_token_hdr_t*)&token, buf, NULL);
if (ret == -1) {
printf("Error: parser rejected null result!\n");
return -1;
}
/* test help function */
memset(&buf, 0, sizeof(buf));
/* try all null */
ret = cmdline_get_help_num(NULL, NULL, 0);
if (ret != -1) {
printf("Error: help function accepted null parameters!\n");
return -1;
}
/* try null token */
ret = cmdline_get_help_num(NULL, buf, sizeof(buf));
if (ret != -1) {
printf("Error: help function accepted null token!\n");
return -1;
}
/* try null buf */
ret = cmdline_get_help_num((cmdline_parse_token_hdr_t*)&token, NULL, sizeof(buf));
if (ret != -1) {
printf("Error: help function accepted null buffer!\n");
return -1;
}
/* coverage! */
ret = cmdline_get_help_num((cmdline_parse_token_hdr_t*)&token, buf, sizeof(buf));
if (ret < 0) {
printf("Error: help function failed with valid parameters!\n");
return -1;
}
return 0;
}
/* test valid parameters but invalid data */
int
test_parse_num_invalid_data(void)
{
enum cmdline_numtype type;
int ret = 0;
unsigned i;
char buf[CMDLINE_TEST_BUFSIZE];
uint64_t result; /* pick largest buffer */
cmdline_parse_token_num_t token;
/* cycle through all possible parsed types */
for (type = UINT8; type <= INT64; type++) {
token.num_data.type = type;
/* test full strings */
for (i = 0; i < NUM_INVALID_STRS_SIZE; i++) {
memset(&result, 0, sizeof(uint64_t));
memset(&buf, 0, sizeof(buf));
ret = cmdline_parse_num((cmdline_parse_token_hdr_t*)&token,
num_invalid_strs[i], (void*)&result);
if (ret != -1) {
/* get some info about what we are trying to parse */
cmdline_get_help_num((cmdline_parse_token_hdr_t*)&token,
buf, sizeof(buf));
printf("Error: parsing %s as %s succeeded!\n",
num_invalid_strs[i], buf);
return -1;
}
}
}
return 0;
}
/* test valid parameters and data */
int
test_parse_num_valid(void)
{
int ret = 0;
enum cmdline_numtype type;
unsigned i;
char buf[CMDLINE_TEST_BUFSIZE];
uint64_t result;
cmdline_parse_token_num_t token;
/** valid strings **/
/* cycle through all possible parsed types */
for (type = UINT8; type <= INT64; type++) {
token.num_data.type = type;
/* test positive strings */
for (i = 0; i < NUM_POSITIVE_STRS_SIZE; i++) {
result = 0;
memset(&buf, 0, sizeof(buf));
cmdline_get_help_num((cmdline_parse_token_hdr_t*)&token,
buf, sizeof(buf));
ret = cmdline_parse_num((cmdline_parse_token_hdr_t*) &token, num_valid_positive_strs[i].str,
(void*)&result);
/* if it should have passed but didn't, or if it should have failed but didn't */
if ((ret < 0) == (can_parse_unsigned(num_valid_positive_strs[i].result, type) > 0)) {
printf("Error: parser behaves unexpectedly when parsing %s as %s!\n",
num_valid_positive_strs[i].str, buf);
return -1;
}
/* check if result matches what it should have matched
* since unsigned numbers don't care about number of bits, we can just convert
* everything to uint64_t without any worries. */
if (ret > 0 && num_valid_positive_strs[i].result != result) {
printf("Error: parsing %s as %s failed: result mismatch!\n",
num_valid_positive_strs[i].str, buf);
return -1;
}
}
/* test negative strings */
for (i = 0; i < NUM_NEGATIVE_STRS_SIZE; i++) {
result = 0;
memset(&buf, 0, sizeof(buf));
cmdline_get_help_num((cmdline_parse_token_hdr_t*)&token,
buf, sizeof(buf));
ret = cmdline_parse_num((cmdline_parse_token_hdr_t*) &token, num_valid_negative_strs[i].str,
(void*)&result);
/* if it should have passed but didn't, or if it should have failed but didn't */
if ((ret < 0) == (can_parse_signed(num_valid_negative_strs[i].result, type) > 0)) {
printf("Error: parser behaves unexpectedly when parsing %s as %s!\n",
num_valid_negative_strs[i].str, buf);
return -1;
}
/* check if result matches what it should have matched
* the result is signed in this case, so we have to account for that */
if (ret > 0) {
/* detect negative */
switch (type) {
case INT8:
result = (int8_t) result;
break;
case INT16:
result = (int16_t) result;
break;
case INT32:
result = (int32_t) result;
break;
default:
break;
}
if (num_valid_negative_strs[i].result == (int64_t) result)
continue;
printf("Error: parsing %s as %s failed: result mismatch!\n",
num_valid_negative_strs[i].str, buf);
return -1;
}
}
}
/** garbage strings **/
/* cycle through all possible parsed types */
for (type = UINT8; type <= INT64; type++) {
token.num_data.type = type;
/* test positive garbage strings */
for (i = 0; i < NUM_POSITIVE_GARBAGE_STRS_SIZE; i++) {
result = 0;
memset(&buf, 0, sizeof(buf));
cmdline_get_help_num((cmdline_parse_token_hdr_t*)&token,
buf, sizeof(buf));
ret = cmdline_parse_num((cmdline_parse_token_hdr_t*) &token, num_garbage_positive_strs[i].str,
(void*)&result);
/* if it should have passed but didn't, or if it should have failed but didn't */
if ((ret < 0) == (can_parse_unsigned(num_garbage_positive_strs[i].result, type) > 0)) {
printf("Error: parser behaves unexpectedly when parsing %s as %s!\n",
num_garbage_positive_strs[i].str, buf);
return -1;
}
/* check if result matches what it should have matched
* since unsigned numbers don't care about number of bits, we can just convert
* everything to uint64_t without any worries. */
if (ret > 0 && num_garbage_positive_strs[i].result != result) {
printf("Error: parsing %s as %s failed: result mismatch!\n",
num_garbage_positive_strs[i].str, buf);
return -1;
}
}
/* test negative strings */
for (i = 0; i < NUM_NEGATIVE_GARBAGE_STRS_SIZE; i++) {
result = 0;
memset(&buf, 0, sizeof(buf));
cmdline_get_help_num((cmdline_parse_token_hdr_t*)&token,
buf, sizeof(buf));
ret = cmdline_parse_num((cmdline_parse_token_hdr_t*) &token, num_garbage_negative_strs[i].str,
(void*)&result);
/* if it should have passed but didn't, or if it should have failed but didn't */
if ((ret < 0) == (can_parse_signed(num_garbage_negative_strs[i].result, type) > 0)) {
printf("Error: parser behaves unexpectedly when parsing %s as %s!\n",
num_garbage_negative_strs[i].str, buf);
return -1;
}
/* check if result matches what it should have matched
* the result is signed in this case, so we have to account for that */
if (ret > 0) {
/* detect negative */
switch (type) {
case INT8:
if (result & (INT8_MAX + 1))
result |= 0xFFFFFFFFFFFFFF00ULL;
break;
case INT16:
if (result & (INT16_MAX + 1))
result |= 0xFFFFFFFFFFFF0000ULL;
break;
case INT32:
if (result & (INT32_MAX + 1ULL))
result |= 0xFFFFFFFF00000000ULL;
break;
default:
break;
}
if (num_garbage_negative_strs[i].result == (int64_t) result)
continue;
printf("Error: parsing %s as %s failed: result mismatch!\n",
num_garbage_negative_strs[i].str, buf);
return -1;
}
}
}
memset(&buf, 0, sizeof(buf));
/* coverage! */
cmdline_get_help_num((cmdline_parse_token_hdr_t*)&token,
buf, sizeof(buf));
return 0;
}