diff options
Diffstat (limited to 'src/seastar/dpdk/test/test/test_cmdline_num.c')
-rw-r--r-- | src/seastar/dpdk/test/test/test_cmdline_num.c | 623 |
1 files changed, 623 insertions, 0 deletions
diff --git a/src/seastar/dpdk/test/test/test_cmdline_num.c b/src/seastar/dpdk/test/test/test_cmdline_num.c new file mode 100644 index 00000000..e8f60cfa --- /dev/null +++ b/src/seastar/dpdk/test/test/test_cmdline_num.c @@ -0,0 +1,623 @@ +/*- + * 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 <stdio.h> +#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; + break; + 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 */ + snprintf(buf, sizeof(buf), "%s", + num_valid_positive_strs[0].str); + + /* try all null */ + ret = cmdline_parse_num(NULL, NULL, NULL, 0); + if (ret != -1) { + printf("Error: parser accepted null parameters!\n"); + return -1; + } + + /* try null token */ + ret = cmdline_parse_num(NULL, buf, (void*)&result, sizeof(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, sizeof(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, 0); + 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; + } + + /* 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, sizeof(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, sizeof(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, sizeof(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, sizeof(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, sizeof(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; +} |