14418919fSjohnjiang /* SPDX-License-Identifier: BSD-3-Clause
24418919fSjohnjiang * Copyright(c) 2010-2014 Intel Corporation
34418919fSjohnjiang */
44418919fSjohnjiang
54418919fSjohnjiang #include <stdio.h>
64418919fSjohnjiang #include <string.h>
74418919fSjohnjiang #include <inttypes.h>
84418919fSjohnjiang
94418919fSjohnjiang #include <rte_common.h>
104418919fSjohnjiang #include <rte_string_fns.h>
114418919fSjohnjiang
124418919fSjohnjiang #include <cmdline_parse.h>
134418919fSjohnjiang #include <cmdline_parse_string.h>
144418919fSjohnjiang
154418919fSjohnjiang #include "test_cmdline.h"
164418919fSjohnjiang
174418919fSjohnjiang /* structures needed to run tests */
184418919fSjohnjiang
194418919fSjohnjiang struct string_elt_str {
204418919fSjohnjiang const char * str; /* parsed string */
214418919fSjohnjiang const char * result; /* expected string */
224418919fSjohnjiang int idx; /* position at which result is expected to be */
234418919fSjohnjiang };
244418919fSjohnjiang
254418919fSjohnjiang struct string_elt_str string_elt_strs[] = {
264418919fSjohnjiang {"one#two#three", "three", 2},
274418919fSjohnjiang {"one#two with spaces#three", "three", 2},
284418919fSjohnjiang {"one#two\twith\ttabs#three", "three", 2},
294418919fSjohnjiang {"one#two\rwith\rreturns#three", "three", 2},
304418919fSjohnjiang {"one#two\nwith\nnewlines#three", "three", 2},
314418919fSjohnjiang {"one#two#three", "one", 0},
324418919fSjohnjiang {"one#two#three", "two", 1},
334418919fSjohnjiang {"one#two\0three", "two", 1},
344418919fSjohnjiang {"one#two with spaces#three", "two with spaces", 1},
354418919fSjohnjiang {"one#two\twith\ttabs#three", "two\twith\ttabs", 1},
364418919fSjohnjiang {"one#two\rwith\rreturns#three", "two\rwith\rreturns", 1},
374418919fSjohnjiang {"one#two\nwith\nnewlines#three", "two\nwith\nnewlines", 1},
384418919fSjohnjiang };
394418919fSjohnjiang
404418919fSjohnjiang #if (CMDLINE_TEST_BUFSIZE < STR_TOKEN_SIZE) \
414418919fSjohnjiang || (CMDLINE_TEST_BUFSIZE < STR_MULTI_TOKEN_SIZE)
424418919fSjohnjiang #undef CMDLINE_TEST_BUFSIZE
434418919fSjohnjiang #define CMDLINE_TEST_BUFSIZE RTE_MAX(STR_TOKEN_SIZE, STR_MULTI_TOKEN_SIZE)
444418919fSjohnjiang #endif
454418919fSjohnjiang
464418919fSjohnjiang struct string_nb_str {
474418919fSjohnjiang const char * str; /* parsed string */
484418919fSjohnjiang int nb_strs; /* expected number of strings in str */
494418919fSjohnjiang };
504418919fSjohnjiang
514418919fSjohnjiang struct string_nb_str string_nb_strs[] = {
524418919fSjohnjiang {"one#two#three", 3},
534418919fSjohnjiang {"one", 1},
544418919fSjohnjiang {"one# \t two \r # three \n #four", 4},
554418919fSjohnjiang };
564418919fSjohnjiang
574418919fSjohnjiang
584418919fSjohnjiang
594418919fSjohnjiang struct string_parse_str {
604418919fSjohnjiang const char * str; /* parsed string */
614418919fSjohnjiang const char * fixed_str; /* parsing mode (any, fixed or multi) */
624418919fSjohnjiang const char * result; /* expected result */
634418919fSjohnjiang };
644418919fSjohnjiang
654418919fSjohnjiang struct string_parse_str string_parse_strs[] = {
664418919fSjohnjiang {"one", NULL, "one"}, /* any string */
674418919fSjohnjiang {"two", "one#two#three", "two"}, /* multiple choice string */
684418919fSjohnjiang {"three", "three", "three"}, /* fixed string */
694418919fSjohnjiang {"three", "one#two with\rgarbage\tcharacters\n#three", "three"},
704418919fSjohnjiang {"two with\rgarbage\tcharacters\n",
714418919fSjohnjiang "one#two with\rgarbage\tcharacters\n#three",
724418919fSjohnjiang "two with\rgarbage\tcharacters\n"},
734418919fSjohnjiang {"one two", "one", "one"}, /* fixed string */
744418919fSjohnjiang {"one two", TOKEN_STRING_MULTI, "one two"}, /* multi string */
754418919fSjohnjiang {"one two", NULL, "one"}, /* any string */
764418919fSjohnjiang {"one two #three", TOKEN_STRING_MULTI, "one two "},
774418919fSjohnjiang /* multi string with comment */
784418919fSjohnjiang };
794418919fSjohnjiang
804418919fSjohnjiang
814418919fSjohnjiang
824418919fSjohnjiang struct string_invalid_str {
834418919fSjohnjiang const char * str; /* parsed string */
844418919fSjohnjiang const char * fixed_str; /* parsing mode (any, fixed or multi) */
854418919fSjohnjiang };
864418919fSjohnjiang
874418919fSjohnjiang struct string_invalid_str string_invalid_strs[] = {
884418919fSjohnjiang {"invalid", "one"}, /* fixed string */
894418919fSjohnjiang {"invalid", "one#two#three"}, /* multiple choice string */
904418919fSjohnjiang {"invalid", "invalidone"}, /* string that starts the same */
914418919fSjohnjiang {"invalidone", "invalid"}, /* string that starts the same */
924418919fSjohnjiang {"toolong!!!toolong!!!toolong!!!toolong!!!toolong!!!toolong!!!"
934418919fSjohnjiang "toolong!!!toolong!!!toolong!!!toolong!!!toolong!!!toolong!!!"
944418919fSjohnjiang "toolong!!!", NULL },
954418919fSjohnjiang {"toolong!!!toolong!!!toolong!!!toolong!!!toolong!!!toolong!!!"
964418919fSjohnjiang "toolong!!!toolong!!!toolong!!!toolong!!!toolong!!!toolong!!!"
974418919fSjohnjiang "toolong!!!", "fixed" },
984418919fSjohnjiang {"toolong!!!toolong!!!toolong!!!toolong!!!toolong!!!toolong!!!"
994418919fSjohnjiang "toolong!!!toolong!!!toolong!!!toolong!!!toolong!!!toolong!!!"
1004418919fSjohnjiang "toolong!!!", "multi#choice#string" },
1014418919fSjohnjiang {"invalid",
1024418919fSjohnjiang "toolong!!!toolong!!!toolong!!!toolong!!!toolong!!!toolong!!!"
1034418919fSjohnjiang "toolong!!!toolong!!!toolong!!!toolong!!!toolong!!!toolong!!!"
1044418919fSjohnjiang "toolong!!!" },
1054418919fSjohnjiang {"", "invalid"}
1064418919fSjohnjiang };
1074418919fSjohnjiang
1084418919fSjohnjiang
1094418919fSjohnjiang
1104418919fSjohnjiang const char * string_help_strs[] = {
1114418919fSjohnjiang NULL,
1124418919fSjohnjiang "fixed_str",
1134418919fSjohnjiang "multi#str",
1144418919fSjohnjiang };
1154418919fSjohnjiang
1164418919fSjohnjiang #define SMALL_BUF 8
1174418919fSjohnjiang
1184418919fSjohnjiang /* test invalid parameters */
1194418919fSjohnjiang int
test_parse_string_invalid_param(void)1204418919fSjohnjiang test_parse_string_invalid_param(void)
1214418919fSjohnjiang {
1224418919fSjohnjiang cmdline_parse_token_string_t token;
1234418919fSjohnjiang int result;
1244418919fSjohnjiang char buf[CMDLINE_TEST_BUFSIZE];
1254418919fSjohnjiang
1264418919fSjohnjiang memset(&token, 0, sizeof(token));
1274418919fSjohnjiang
1284418919fSjohnjiang snprintf(buf, sizeof(buf), "buffer");
1294418919fSjohnjiang
1304418919fSjohnjiang /* test null token */
1314418919fSjohnjiang if (cmdline_get_help_string(
1324418919fSjohnjiang NULL, buf, 0) != -1) {
1334418919fSjohnjiang printf("Error: function accepted null token!\n");
1344418919fSjohnjiang return -1;
1354418919fSjohnjiang }
1364418919fSjohnjiang if (cmdline_complete_get_elt_string(
1374418919fSjohnjiang NULL, 0, buf, 0) != -1) {
1384418919fSjohnjiang printf("Error: function accepted null token!\n");
1394418919fSjohnjiang return -1;
1404418919fSjohnjiang }
1414418919fSjohnjiang if (cmdline_complete_get_nb_string(NULL) != -1) {
1424418919fSjohnjiang printf("Error: function accepted null token!\n");
1434418919fSjohnjiang return -1;
1444418919fSjohnjiang }
1454418919fSjohnjiang if (cmdline_parse_string(NULL, buf, NULL, 0) != -1) {
1464418919fSjohnjiang printf("Error: function accepted null token!\n");
1474418919fSjohnjiang return -1;
1484418919fSjohnjiang }
1494418919fSjohnjiang /* test null buffer */
1504418919fSjohnjiang if (cmdline_complete_get_elt_string(
1514418919fSjohnjiang (cmdline_parse_token_hdr_t*)&token, 0, NULL, 0) != -1) {
1524418919fSjohnjiang printf("Error: function accepted null buffer!\n");
1534418919fSjohnjiang return -1;
1544418919fSjohnjiang }
1554418919fSjohnjiang if (cmdline_parse_string(
1564418919fSjohnjiang (cmdline_parse_token_hdr_t*)&token, NULL,
1574418919fSjohnjiang (void*)&result, sizeof(result)) != -1) {
1584418919fSjohnjiang printf("Error: function accepted null buffer!\n");
1594418919fSjohnjiang return -1;
1604418919fSjohnjiang }
1614418919fSjohnjiang if (cmdline_get_help_string(
1624418919fSjohnjiang (cmdline_parse_token_hdr_t*)&token, NULL, 0) != -1) {
1634418919fSjohnjiang printf("Error: function accepted null buffer!\n");
1644418919fSjohnjiang return -1;
1654418919fSjohnjiang }
1664418919fSjohnjiang /* test null result */
1674418919fSjohnjiang if (cmdline_parse_string(
1684418919fSjohnjiang (cmdline_parse_token_hdr_t*)&token, buf, NULL, 0) == -1) {
1694418919fSjohnjiang printf("Error: function rejected null result!\n");
1704418919fSjohnjiang return -1;
1714418919fSjohnjiang }
1724418919fSjohnjiang /* test negative index */
1734418919fSjohnjiang if (cmdline_complete_get_elt_string(
1744418919fSjohnjiang (cmdline_parse_token_hdr_t*)&token, -1, buf, 0) != -1) {
1754418919fSjohnjiang printf("Error: function accepted negative index!\n");
1764418919fSjohnjiang return -1;
1774418919fSjohnjiang }
1784418919fSjohnjiang return 0;
1794418919fSjohnjiang }
1804418919fSjohnjiang
1814418919fSjohnjiang /* test valid parameters but invalid data */
1824418919fSjohnjiang int
test_parse_string_invalid_data(void)1834418919fSjohnjiang test_parse_string_invalid_data(void)
1844418919fSjohnjiang {
1854418919fSjohnjiang cmdline_parse_token_string_t token;
1864418919fSjohnjiang cmdline_parse_token_string_t help_token;
1874418919fSjohnjiang char buf[CMDLINE_TEST_BUFSIZE];
1884418919fSjohnjiang char help_str[CMDLINE_TEST_BUFSIZE];
1894418919fSjohnjiang char small_buf[SMALL_BUF];
1904418919fSjohnjiang unsigned i;
1914418919fSjohnjiang
1924418919fSjohnjiang /* test parsing invalid strings */
193*2d9fd380Sjfb8856606 for (i = 0; i < RTE_DIM(string_invalid_strs); i++) {
1944418919fSjohnjiang memset(&token, 0, sizeof(token));
1954418919fSjohnjiang memset(buf, 0, sizeof(buf));
1964418919fSjohnjiang
1974418919fSjohnjiang /* prepare test token data */
1984418919fSjohnjiang token.string_data.str = string_invalid_strs[i].fixed_str;
1994418919fSjohnjiang
2004418919fSjohnjiang if (cmdline_parse_string((cmdline_parse_token_hdr_t*)&token,
2014418919fSjohnjiang string_invalid_strs[i].str, (void*)buf,
2024418919fSjohnjiang sizeof(buf)) != -1) {
2034418919fSjohnjiang memset(help_str, 0, sizeof(help_str));
2044418919fSjohnjiang memset(&help_token, 0, sizeof(help_token));
2054418919fSjohnjiang
2064418919fSjohnjiang help_token.string_data.str = string_invalid_strs[i].fixed_str;
2074418919fSjohnjiang
2084418919fSjohnjiang /* get parse type so we can give a good error message */
2094418919fSjohnjiang cmdline_get_help_string((cmdline_parse_token_hdr_t*)&token, help_str,
2104418919fSjohnjiang sizeof(help_str));
2114418919fSjohnjiang
2124418919fSjohnjiang printf("Error: parsing %s as %s succeeded!\n",
2134418919fSjohnjiang string_invalid_strs[i].str, help_str);
2144418919fSjohnjiang return -1;
2154418919fSjohnjiang }
2164418919fSjohnjiang }
2174418919fSjohnjiang
2184418919fSjohnjiang /* misc tests (big comments signify test cases) */
2194418919fSjohnjiang memset(&token, 0, sizeof(token));
2204418919fSjohnjiang memset(small_buf, 0, sizeof(small_buf));
2214418919fSjohnjiang
2224418919fSjohnjiang /*
2234418919fSjohnjiang * try to get element from a null token
2244418919fSjohnjiang */
2254418919fSjohnjiang token.string_data.str = NULL;
2264418919fSjohnjiang if (cmdline_complete_get_elt_string(
2274418919fSjohnjiang (cmdline_parse_token_hdr_t*)&token, 1,
2284418919fSjohnjiang buf, sizeof(buf)) != -1) {
2294418919fSjohnjiang printf("Error: getting token from null token string!\n");
2304418919fSjohnjiang return -1;
2314418919fSjohnjiang }
2324418919fSjohnjiang
2334418919fSjohnjiang /*
2344418919fSjohnjiang * try to get element into a buffer that is too small
2354418919fSjohnjiang */
2364418919fSjohnjiang token.string_data.str = "too_small_buffer";
2374418919fSjohnjiang if (cmdline_complete_get_elt_string(
2384418919fSjohnjiang (cmdline_parse_token_hdr_t*)&token, 0,
2394418919fSjohnjiang small_buf, sizeof(small_buf)) != -1) {
2404418919fSjohnjiang printf("Error: writing token into too small a buffer succeeded!\n");
2414418919fSjohnjiang return -1;
2424418919fSjohnjiang }
2434418919fSjohnjiang
2444418919fSjohnjiang /*
2454418919fSjohnjiang * get help string written into a buffer smaller than help string
2464418919fSjohnjiang * truncation should occur
2474418919fSjohnjiang */
2484418919fSjohnjiang token.string_data.str = NULL;
2494418919fSjohnjiang if (cmdline_get_help_string(
2504418919fSjohnjiang (cmdline_parse_token_hdr_t*)&token,
2514418919fSjohnjiang small_buf, sizeof(small_buf)) == -1) {
2524418919fSjohnjiang printf("Error: writing help string into too small a buffer failed!\n");
2534418919fSjohnjiang return -1;
2544418919fSjohnjiang }
2554418919fSjohnjiang /* get help string for "any string" so we can compare it with small_buf */
2564418919fSjohnjiang cmdline_get_help_string((cmdline_parse_token_hdr_t*)&token, help_str,
2574418919fSjohnjiang sizeof(help_str));
2584418919fSjohnjiang if (strncmp(small_buf, help_str, sizeof(small_buf) - 1)) {
2594418919fSjohnjiang printf("Error: help string mismatch!\n");
2604418919fSjohnjiang return -1;
2614418919fSjohnjiang }
2624418919fSjohnjiang /* check null terminator */
2634418919fSjohnjiang if (small_buf[sizeof(small_buf) - 1] != '\0') {
2644418919fSjohnjiang printf("Error: small buffer doesn't have a null terminator!\n");
2654418919fSjohnjiang return -1;
2664418919fSjohnjiang }
2674418919fSjohnjiang
2684418919fSjohnjiang /*
2694418919fSjohnjiang * try to count tokens in a null token
2704418919fSjohnjiang */
2714418919fSjohnjiang token.string_data.str = NULL;
2724418919fSjohnjiang if (cmdline_complete_get_nb_string(
2734418919fSjohnjiang (cmdline_parse_token_hdr_t*)&token) != 0) {
2744418919fSjohnjiang printf("Error: getting token count from null token succeeded!\n");
2754418919fSjohnjiang return -1;
2764418919fSjohnjiang }
2774418919fSjohnjiang
2784418919fSjohnjiang return 0;
2794418919fSjohnjiang }
2804418919fSjohnjiang
2814418919fSjohnjiang /* test valid parameters and data */
2824418919fSjohnjiang int
test_parse_string_valid(void)2834418919fSjohnjiang test_parse_string_valid(void)
2844418919fSjohnjiang {
2854418919fSjohnjiang cmdline_parse_token_string_t token;
2864418919fSjohnjiang cmdline_parse_token_string_t help_token;
2874418919fSjohnjiang char buf[CMDLINE_TEST_BUFSIZE];
2884418919fSjohnjiang char help_str[CMDLINE_TEST_BUFSIZE];
2894418919fSjohnjiang unsigned i;
2904418919fSjohnjiang
2914418919fSjohnjiang /* test parsing strings */
292*2d9fd380Sjfb8856606 for (i = 0; i < RTE_DIM(string_parse_strs); i++) {
2934418919fSjohnjiang memset(&token, 0, sizeof(token));
2944418919fSjohnjiang memset(buf, 0, sizeof(buf));
2954418919fSjohnjiang
2964418919fSjohnjiang token.string_data.str = string_parse_strs[i].fixed_str;
2974418919fSjohnjiang
2984418919fSjohnjiang if (cmdline_parse_string((cmdline_parse_token_hdr_t*)&token,
2994418919fSjohnjiang string_parse_strs[i].str, (void*)buf,
3004418919fSjohnjiang sizeof(buf)) < 0) {
3014418919fSjohnjiang
3024418919fSjohnjiang /* clean help data */
3034418919fSjohnjiang memset(&help_token, 0, sizeof(help_token));
3044418919fSjohnjiang memset(help_str, 0, sizeof(help_str));
3054418919fSjohnjiang
3064418919fSjohnjiang /* prepare help token */
3074418919fSjohnjiang help_token.string_data.str = string_parse_strs[i].fixed_str;
3084418919fSjohnjiang
3094418919fSjohnjiang /* get help string so that we get an informative error message */
3104418919fSjohnjiang cmdline_get_help_string((cmdline_parse_token_hdr_t*)&token, help_str,
3114418919fSjohnjiang sizeof(help_str));
3124418919fSjohnjiang
3134418919fSjohnjiang printf("Error: parsing %s as %s failed!\n",
3144418919fSjohnjiang string_parse_strs[i].str, help_str);
3154418919fSjohnjiang return -1;
3164418919fSjohnjiang }
3174418919fSjohnjiang if (strcmp(buf, string_parse_strs[i].result) != 0) {
3184418919fSjohnjiang printf("Error: result mismatch!\n");
3194418919fSjohnjiang return -1;
3204418919fSjohnjiang }
3214418919fSjohnjiang }
3224418919fSjohnjiang
3234418919fSjohnjiang /* get number of string tokens and verify it's correct */
324*2d9fd380Sjfb8856606 for (i = 0; i < RTE_DIM(string_nb_strs); i++) {
3254418919fSjohnjiang memset(&token, 0, sizeof(token));
3264418919fSjohnjiang
3274418919fSjohnjiang token.string_data.str = string_nb_strs[i].str;
3284418919fSjohnjiang
3294418919fSjohnjiang if (cmdline_complete_get_nb_string(
3304418919fSjohnjiang (cmdline_parse_token_hdr_t*)&token) <
3314418919fSjohnjiang string_nb_strs[i].nb_strs) {
3324418919fSjohnjiang printf("Error: strings count mismatch!\n");
3334418919fSjohnjiang return -1;
3344418919fSjohnjiang }
3354418919fSjohnjiang }
3364418919fSjohnjiang
3374418919fSjohnjiang /* get token at specified position and verify it's correct */
338*2d9fd380Sjfb8856606 for (i = 0; i < RTE_DIM(string_elt_strs); i++) {
3394418919fSjohnjiang memset(&token, 0, sizeof(token));
3404418919fSjohnjiang memset(buf, 0, sizeof(buf));
3414418919fSjohnjiang
3424418919fSjohnjiang token.string_data.str = string_elt_strs[i].str;
3434418919fSjohnjiang
3444418919fSjohnjiang if (cmdline_complete_get_elt_string(
3454418919fSjohnjiang (cmdline_parse_token_hdr_t*)&token, string_elt_strs[i].idx,
3464418919fSjohnjiang buf, sizeof(buf)) < 0) {
3474418919fSjohnjiang printf("Error: getting string element failed!\n");
3484418919fSjohnjiang return -1;
3494418919fSjohnjiang }
3504418919fSjohnjiang if (strncmp(buf, string_elt_strs[i].result,
3514418919fSjohnjiang sizeof(buf)) != 0) {
3524418919fSjohnjiang printf("Error: result mismatch!\n");
3534418919fSjohnjiang return -1;
3544418919fSjohnjiang }
3554418919fSjohnjiang }
3564418919fSjohnjiang
3574418919fSjohnjiang /* cover all cases with help strings */
358*2d9fd380Sjfb8856606 for (i = 0; i < RTE_DIM(string_help_strs); i++) {
3594418919fSjohnjiang memset(&help_token, 0, sizeof(help_token));
3604418919fSjohnjiang memset(help_str, 0, sizeof(help_str));
3614418919fSjohnjiang help_token.string_data.str = string_help_strs[i];
3624418919fSjohnjiang if (cmdline_get_help_string((cmdline_parse_token_hdr_t*)&help_token,
3634418919fSjohnjiang help_str, sizeof(help_str)) < 0) {
3644418919fSjohnjiang printf("Error: help operation failed!\n");
3654418919fSjohnjiang return -1;
3664418919fSjohnjiang }
3674418919fSjohnjiang }
3684418919fSjohnjiang
3694418919fSjohnjiang return 0;
3704418919fSjohnjiang }
371