1a9de470cSBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause 2a9de470cSBruce Richardson * Copyright 2014 6WIND S.A. 3a9de470cSBruce Richardson */ 4a9de470cSBruce Richardson 5a9de470cSBruce Richardson #include <stdlib.h> 6a9de470cSBruce Richardson #include <stdio.h> 7a9de470cSBruce Richardson #include <string.h> 8a9de470cSBruce Richardson 9a9de470cSBruce Richardson #include <rte_common.h> 10a9de470cSBruce Richardson #include <rte_kvargs.h> 11a9de470cSBruce Richardson 12a9de470cSBruce Richardson #include "test.h" 13a9de470cSBruce Richardson 14*0e95a677SChengwen Feng typedef int (*f_kvargs_process)(const struct rte_kvargs *kvlist, 15*0e95a677SChengwen Feng const char *key_match, arg_handler_t handler, 16*0e95a677SChengwen Feng void *opaque_arg); 17*0e95a677SChengwen Feng 18*0e95a677SChengwen Feng static bool use_kvargs_process_opt[] = { false, true }; 19*0e95a677SChengwen Feng 207be78d02SJosh Soref /* incremented in handler, to check it is properly called once per 21a9de470cSBruce Richardson * key/value association */ 22a9de470cSBruce Richardson static unsigned count; 23a9de470cSBruce Richardson 24a9de470cSBruce Richardson /* this handler increment the "count" variable at each call and check 25a9de470cSBruce Richardson * that the key is "check" and the value is "value%d" */ 26*0e95a677SChengwen Feng static int 27*0e95a677SChengwen Feng check_handler(const char *key, const char *value, __rte_unused void *opaque) 28a9de470cSBruce Richardson { 29a9de470cSBruce Richardson char buf[16]; 30a9de470cSBruce Richardson 31a9de470cSBruce Richardson /* we check that the value is "check" */ 32a9de470cSBruce Richardson if (strcmp(key, "check")) 33a9de470cSBruce Richardson return -1; 34a9de470cSBruce Richardson 35a9de470cSBruce Richardson /* we check that the value is "value$(count)" */ 36a9de470cSBruce Richardson snprintf(buf, sizeof(buf), "value%d", count); 37a9de470cSBruce Richardson if (strncmp(buf, value, sizeof(buf))) 38a9de470cSBruce Richardson return -1; 39a9de470cSBruce Richardson 40a9de470cSBruce Richardson count ++; 41a9de470cSBruce Richardson return 0; 42a9de470cSBruce Richardson } 43a9de470cSBruce Richardson 44ce7e937fSChengwen Feng static int 45*0e95a677SChengwen Feng check_only_handler(const char *key, const char *value, __rte_unused void *opaque) 46*0e95a677SChengwen Feng { 47*0e95a677SChengwen Feng if (strcmp(key, "check")) 48*0e95a677SChengwen Feng return -1; 49*0e95a677SChengwen Feng 50*0e95a677SChengwen Feng if (value != NULL) 51*0e95a677SChengwen Feng return -1; 52*0e95a677SChengwen Feng 53*0e95a677SChengwen Feng return 0; 54*0e95a677SChengwen Feng } 55*0e95a677SChengwen Feng 56*0e95a677SChengwen Feng static int 57ce7e937fSChengwen Feng test_basic_token_count(void) 58ce7e937fSChengwen Feng { 59ce7e937fSChengwen Feng static const struct { 60ce7e937fSChengwen Feng unsigned int expected; 61ce7e937fSChengwen Feng const char *input; 62ce7e937fSChengwen Feng } valid_inputs[] = { 63ce7e937fSChengwen Feng { 3, "foo=1,check=1,check=2" }, 64ce7e937fSChengwen Feng { 3, "foo=1,check,check=2" }, 65ce7e937fSChengwen Feng { 2, "foo=1,foo=" }, 66ce7e937fSChengwen Feng { 2, "foo=1,foo=" }, 67ce7e937fSChengwen Feng { 2, "foo=1,foo" }, 68ce7e937fSChengwen Feng { 2, "foo=1,=2" }, 69ce7e937fSChengwen Feng { 2, "foo=1,,foo=2,," }, 70ce7e937fSChengwen Feng { 1, "foo=[1,2" }, 71ce7e937fSChengwen Feng { 1, ",=" }, 72ce7e937fSChengwen Feng { 1, "foo=[" }, 73ce7e937fSChengwen Feng { 0, "" }, 74ce7e937fSChengwen Feng }; 75ce7e937fSChengwen Feng struct rte_kvargs *kvlist; 76ce7e937fSChengwen Feng unsigned int count; 77ce7e937fSChengwen Feng const char *args; 78ce7e937fSChengwen Feng unsigned int i; 79ce7e937fSChengwen Feng 80ce7e937fSChengwen Feng for (i = 0; i < RTE_DIM(valid_inputs); i++) { 81ce7e937fSChengwen Feng args = valid_inputs[i].input; 82ce7e937fSChengwen Feng kvlist = rte_kvargs_parse(args, NULL); 83ce7e937fSChengwen Feng if (kvlist == NULL) { 84ce7e937fSChengwen Feng printf("rte_kvargs_parse() error: %s\n", args); 85ce7e937fSChengwen Feng return -1; 86ce7e937fSChengwen Feng } 87ce7e937fSChengwen Feng count = rte_kvargs_count(kvlist, NULL); 88ce7e937fSChengwen Feng if (count != valid_inputs[i].expected) { 89ce7e937fSChengwen Feng printf("invalid count value %u (expected %u): %s\n", 90ce7e937fSChengwen Feng count, valid_inputs[i].expected, args); 91ce7e937fSChengwen Feng rte_kvargs_free(kvlist); 92ce7e937fSChengwen Feng return -1; 93ce7e937fSChengwen Feng } 94ce7e937fSChengwen Feng rte_kvargs_free(kvlist); 95ce7e937fSChengwen Feng } 96ce7e937fSChengwen Feng 97ce7e937fSChengwen Feng return 0; 98ce7e937fSChengwen Feng } 99ce7e937fSChengwen Feng 1007dd71026SChengwen Feng static int 101*0e95a677SChengwen Feng test_parse_without_valid_keys(const void *params) 1027dd71026SChengwen Feng { 103*0e95a677SChengwen Feng const bool use_opt = *(const bool *)params; 104*0e95a677SChengwen Feng f_kvargs_process proc_func = use_opt ? rte_kvargs_process_opt : rte_kvargs_process; 105*0e95a677SChengwen Feng const char *proc_name = use_opt ? "rte_kvargs_process_opt" : "rte_kvargs_process"; 1067dd71026SChengwen Feng const char *args = "foo=1234,check=value0,check=value1"; 1077dd71026SChengwen Feng struct rte_kvargs *kvlist; 1087dd71026SChengwen Feng 1097dd71026SChengwen Feng kvlist = rte_kvargs_parse(args, NULL); 1107dd71026SChengwen Feng if (kvlist == NULL) { 1117dd71026SChengwen Feng printf("rte_kvargs_parse() error\n"); 1127dd71026SChengwen Feng return -1; 1137dd71026SChengwen Feng } 1147dd71026SChengwen Feng 1157dd71026SChengwen Feng /* call check_handler() for all entries with key="check" */ 1167dd71026SChengwen Feng count = 0; 117*0e95a677SChengwen Feng if (proc_func(kvlist, "check", check_handler, NULL) < 0) { 118*0e95a677SChengwen Feng printf("%s(check) error\n", proc_name); 1197dd71026SChengwen Feng rte_kvargs_free(kvlist); 1207dd71026SChengwen Feng return -1; 1217dd71026SChengwen Feng } 1227dd71026SChengwen Feng if (count != 2) { 123*0e95a677SChengwen Feng printf("invalid count value %u after %s(check)\n", 124*0e95a677SChengwen Feng count, proc_name); 1257dd71026SChengwen Feng rte_kvargs_free(kvlist); 1267dd71026SChengwen Feng return -1; 1277dd71026SChengwen Feng } 1287dd71026SChengwen Feng 1297dd71026SChengwen Feng /* call check_handler() for all entries with key="nonexistent_key" */ 1307dd71026SChengwen Feng count = 0; 131*0e95a677SChengwen Feng if (proc_func(kvlist, "nonexistent_key", check_handler, NULL) < 0) { 132*0e95a677SChengwen Feng printf("%s(nonexistent_key) error\n", proc_name); 1337dd71026SChengwen Feng rte_kvargs_free(kvlist); 1347dd71026SChengwen Feng return -1; 1357dd71026SChengwen Feng } 1367dd71026SChengwen Feng if (count != 0) { 137*0e95a677SChengwen Feng printf("invalid count value %d after %s(nonexistent_key)\n", 138*0e95a677SChengwen Feng count, proc_name); 1397dd71026SChengwen Feng rte_kvargs_free(kvlist); 1407dd71026SChengwen Feng return -1; 1417dd71026SChengwen Feng } 1427dd71026SChengwen Feng 1437dd71026SChengwen Feng /* count all entries with key="foo" */ 1447dd71026SChengwen Feng count = rte_kvargs_count(kvlist, "foo"); 1457dd71026SChengwen Feng if (count != 1) { 1467dd71026SChengwen Feng printf("invalid count value %d after rte_kvargs_count(foo)\n", 1477dd71026SChengwen Feng count); 1487dd71026SChengwen Feng rte_kvargs_free(kvlist); 1497dd71026SChengwen Feng return -1; 1507dd71026SChengwen Feng } 1517dd71026SChengwen Feng 1527dd71026SChengwen Feng /* count all entries with key="nonexistent_key" */ 1537dd71026SChengwen Feng count = rte_kvargs_count(kvlist, "nonexistent_key"); 1547dd71026SChengwen Feng if (count != 0) { 1557dd71026SChengwen Feng printf("invalid count value %d after rte_kvargs_count(nonexistent_key)\n", 1567dd71026SChengwen Feng count); 1577dd71026SChengwen Feng rte_kvargs_free(kvlist); 1587dd71026SChengwen Feng return -1; 1597dd71026SChengwen Feng } 1607dd71026SChengwen Feng 1617dd71026SChengwen Feng rte_kvargs_free(kvlist); 1627dd71026SChengwen Feng return 0; 1637dd71026SChengwen Feng } 1647dd71026SChengwen Feng 165a04d13aaSChengwen Feng static int 166*0e95a677SChengwen Feng test_parse_with_valid_keys(const void *params) 167a04d13aaSChengwen Feng { 168*0e95a677SChengwen Feng const bool use_opt = *(const bool *)params; 169*0e95a677SChengwen Feng f_kvargs_process proc_func = use_opt ? rte_kvargs_process_opt : rte_kvargs_process; 170*0e95a677SChengwen Feng const char *proc_name = use_opt ? "rte_kvargs_process_opt" : "rte_kvargs_process"; 171a04d13aaSChengwen Feng const char *args = "foo=droids,check=value0,check=value1,check=wrong_value"; 172a04d13aaSChengwen Feng const char *valid_keys[] = { "foo", "check", NULL }; 173a04d13aaSChengwen Feng struct rte_kvargs *kvlist; 174a04d13aaSChengwen Feng 175a04d13aaSChengwen Feng kvlist = rte_kvargs_parse(args, valid_keys); 176a04d13aaSChengwen Feng if (kvlist == NULL) { 177a04d13aaSChengwen Feng printf("rte_kvargs_parse() error\n"); 178a04d13aaSChengwen Feng return -1; 179a04d13aaSChengwen Feng } 180a04d13aaSChengwen Feng 181a04d13aaSChengwen Feng /* call check_handler() on all entries with key="check", it 182a04d13aaSChengwen Feng * should fail as the value is not recognized by the handler 183a04d13aaSChengwen Feng */ 184a04d13aaSChengwen Feng count = 0; 185*0e95a677SChengwen Feng if (proc_func(kvlist, "check", check_handler, NULL) == 0 || count != 2) { 186*0e95a677SChengwen Feng printf("%s(check) is success but should not\n", proc_name); 187a04d13aaSChengwen Feng rte_kvargs_free(kvlist); 188a04d13aaSChengwen Feng return -1; 189a04d13aaSChengwen Feng } 190a04d13aaSChengwen Feng 191a04d13aaSChengwen Feng count = rte_kvargs_count(kvlist, "check"); 192a04d13aaSChengwen Feng if (count != 3) { 193a04d13aaSChengwen Feng printf("invalid count value %u after rte_kvargs_count(check)\n", 194a04d13aaSChengwen Feng count); 195a04d13aaSChengwen Feng rte_kvargs_free(kvlist); 196a04d13aaSChengwen Feng return -1; 197a04d13aaSChengwen Feng } 198a04d13aaSChengwen Feng 199a04d13aaSChengwen Feng rte_kvargs_free(kvlist); 200a04d13aaSChengwen Feng return 0; 201a04d13aaSChengwen Feng } 202a04d13aaSChengwen Feng 203c189450bSChengwen Feng static int 204c189450bSChengwen Feng test_parse_list_value(void) 205c189450bSChengwen Feng { 206c189450bSChengwen Feng const char *valid_keys[] = { "foo", "check", NULL }; 207c189450bSChengwen Feng const char *args = "foo=[0,1],check=value2"; 208c189450bSChengwen Feng struct rte_kvargs *kvlist; 209c189450bSChengwen Feng 210c189450bSChengwen Feng kvlist = rte_kvargs_parse(args, valid_keys); 211c189450bSChengwen Feng if (kvlist == NULL) { 212c189450bSChengwen Feng printf("rte_kvargs_parse() error\n"); 213c189450bSChengwen Feng return -1; 214c189450bSChengwen Feng } 215c189450bSChengwen Feng 216c189450bSChengwen Feng count = kvlist->count; 217c189450bSChengwen Feng if (count != 2) { 218c189450bSChengwen Feng printf("invalid count value %u\n", count); 219c189450bSChengwen Feng rte_kvargs_free(kvlist); 220c189450bSChengwen Feng return -1; 221c189450bSChengwen Feng } 222c189450bSChengwen Feng 223c189450bSChengwen Feng if (strcmp(kvlist->pairs[0].value, "[0,1]") != 0) { 224c189450bSChengwen Feng printf("wrong value %s", kvlist->pairs[0].value); 225c189450bSChengwen Feng rte_kvargs_free(kvlist); 226c189450bSChengwen Feng return -1; 227c189450bSChengwen Feng } 228c189450bSChengwen Feng 229c189450bSChengwen Feng rte_kvargs_free(kvlist); 230c189450bSChengwen Feng return 0; 231c189450bSChengwen Feng } 232c189450bSChengwen Feng 2338b1656a9SChengwen Feng static int 2348b1656a9SChengwen Feng test_parse_empty_elements(void) 2358b1656a9SChengwen Feng { 2368b1656a9SChengwen Feng const char *args = "foo=1,,check=value2,,"; 2378b1656a9SChengwen Feng struct rte_kvargs *kvlist; 2388b1656a9SChengwen Feng 2398b1656a9SChengwen Feng kvlist = rte_kvargs_parse(args, NULL); 2408b1656a9SChengwen Feng if (kvlist == NULL) { 2418b1656a9SChengwen Feng printf("rte_kvargs_parse() error\n"); 2428b1656a9SChengwen Feng return -1; 2438b1656a9SChengwen Feng } 2448b1656a9SChengwen Feng 245*0e95a677SChengwen Feng count = kvlist->count; 246*0e95a677SChengwen Feng if (count != 2) { 247*0e95a677SChengwen Feng printf("invalid count value %u\n", count); 248*0e95a677SChengwen Feng rte_kvargs_free(kvlist); 249*0e95a677SChengwen Feng return -1; 250*0e95a677SChengwen Feng } 251*0e95a677SChengwen Feng 2528b1656a9SChengwen Feng if (rte_kvargs_count(kvlist, "foo") != 1) { 2538b1656a9SChengwen Feng printf("invalid count value for 'foo'\n"); 2548b1656a9SChengwen Feng rte_kvargs_free(kvlist); 2558b1656a9SChengwen Feng return -1; 2568b1656a9SChengwen Feng } 2578b1656a9SChengwen Feng 2588b1656a9SChengwen Feng if (rte_kvargs_count(kvlist, "check") != 1) { 2598b1656a9SChengwen Feng printf("invalid count value for 'check'\n"); 2608b1656a9SChengwen Feng rte_kvargs_free(kvlist); 2618b1656a9SChengwen Feng return -1; 2628b1656a9SChengwen Feng } 2638b1656a9SChengwen Feng 2648b1656a9SChengwen Feng rte_kvargs_free(kvlist); 2658b1656a9SChengwen Feng return 0; 2668b1656a9SChengwen Feng } 2678b1656a9SChengwen Feng 268*0e95a677SChengwen Feng static int 269*0e95a677SChengwen Feng test_parse_with_only_key(void) 270*0e95a677SChengwen Feng { 271*0e95a677SChengwen Feng const char *args = "foo,check"; 272*0e95a677SChengwen Feng struct rte_kvargs *kvlist; 273*0e95a677SChengwen Feng 274*0e95a677SChengwen Feng kvlist = rte_kvargs_parse(args, NULL); 275*0e95a677SChengwen Feng if (kvlist == NULL) { 276*0e95a677SChengwen Feng printf("rte_kvargs_parse() error\n"); 277*0e95a677SChengwen Feng return -1; 278*0e95a677SChengwen Feng } 279*0e95a677SChengwen Feng 280*0e95a677SChengwen Feng if (rte_kvargs_process(kvlist, "check", check_only_handler, NULL) == 0) { 281*0e95a677SChengwen Feng printf("rte_kvargs_process(check) error\n"); 282*0e95a677SChengwen Feng rte_kvargs_free(kvlist); 283*0e95a677SChengwen Feng return -1; 284*0e95a677SChengwen Feng } 285*0e95a677SChengwen Feng 286*0e95a677SChengwen Feng if (rte_kvargs_process_opt(kvlist, "check", check_only_handler, NULL) != 0) { 287*0e95a677SChengwen Feng printf("rte_kvargs_process_opt(check) error\n"); 288*0e95a677SChengwen Feng rte_kvargs_free(kvlist); 289*0e95a677SChengwen Feng return -1; 290*0e95a677SChengwen Feng } 291*0e95a677SChengwen Feng 292*0e95a677SChengwen Feng rte_kvargs_free(kvlist); 293*0e95a677SChengwen Feng return 0; 294*0e95a677SChengwen Feng } 295*0e95a677SChengwen Feng 296a9de470cSBruce Richardson /* test several error cases */ 297a9de470cSBruce Richardson static int test_invalid_kvargs(void) 298a9de470cSBruce Richardson { 299a9de470cSBruce Richardson struct rte_kvargs *kvlist; 300a9de470cSBruce Richardson /* list of argument that should fail */ 301a9de470cSBruce Richardson const char *args_list[] = { 302a9de470cSBruce Richardson "wrong-key=x", /* key not in valid_keys_list */ 303a9de470cSBruce Richardson NULL }; 304a9de470cSBruce Richardson const char **args; 305a9de470cSBruce Richardson const char *valid_keys_list[] = { "foo", "check", NULL }; 306a9de470cSBruce Richardson const char **valid_keys = valid_keys_list; 307a9de470cSBruce Richardson 308a9de470cSBruce Richardson for (args = args_list; *args != NULL; args++) { 309a9de470cSBruce Richardson 310a9de470cSBruce Richardson kvlist = rte_kvargs_parse(*args, valid_keys); 311a9de470cSBruce Richardson if (kvlist != NULL) { 312a9de470cSBruce Richardson printf("rte_kvargs_parse() returned 0 (but should not)\n"); 313a9de470cSBruce Richardson rte_kvargs_free(kvlist); 314a9de470cSBruce Richardson goto fail; 315a9de470cSBruce Richardson } 316a9de470cSBruce Richardson } 3174bf2b36fSOlivier Matz return 0; 318a9de470cSBruce Richardson 319a9de470cSBruce Richardson fail: 320a9de470cSBruce Richardson printf("while processing <%s>", *args); 321a9de470cSBruce Richardson if (valid_keys != NULL && *valid_keys != NULL) { 322a9de470cSBruce Richardson printf(" using valid_keys=<%s", *valid_keys); 323a9de470cSBruce Richardson while (*(++valid_keys) != NULL) 324a9de470cSBruce Richardson printf(",%s", *valid_keys); 325a9de470cSBruce Richardson printf(">"); 326a9de470cSBruce Richardson } 327a9de470cSBruce Richardson printf("\n"); 328a9de470cSBruce Richardson return -1; 329a9de470cSBruce Richardson } 330a9de470cSBruce Richardson 331a79d5ce9SChengwen Feng static struct unit_test_suite kvargs_test_suite = { 332a79d5ce9SChengwen Feng .suite_name = "Kvargs Unit Test Suite", 333a79d5ce9SChengwen Feng .setup = NULL, 334a79d5ce9SChengwen Feng .teardown = NULL, 335a79d5ce9SChengwen Feng .unit_test_cases = { 336ce7e937fSChengwen Feng TEST_CASE(test_basic_token_count), 337*0e95a677SChengwen Feng TEST_CASE_NAMED_WITH_DATA("test_parse_without_valid_keys_no_opt", 338*0e95a677SChengwen Feng NULL, NULL, 339*0e95a677SChengwen Feng test_parse_without_valid_keys, 340*0e95a677SChengwen Feng &use_kvargs_process_opt[0]), 341*0e95a677SChengwen Feng TEST_CASE_NAMED_WITH_DATA("test_parse_without_valid_keys_with_opt", 342*0e95a677SChengwen Feng NULL, NULL, 343*0e95a677SChengwen Feng test_parse_without_valid_keys, 344*0e95a677SChengwen Feng &use_kvargs_process_opt[1]), 345*0e95a677SChengwen Feng TEST_CASE_NAMED_WITH_DATA("test_parse_with_valid_keys_no_opt", 346*0e95a677SChengwen Feng NULL, NULL, 347*0e95a677SChengwen Feng test_parse_with_valid_keys, 348*0e95a677SChengwen Feng &use_kvargs_process_opt[0]), 349*0e95a677SChengwen Feng TEST_CASE_NAMED_WITH_DATA("test_parse_with_valid_keys_with_opt", 350*0e95a677SChengwen Feng NULL, NULL, 351*0e95a677SChengwen Feng test_parse_with_valid_keys, 352*0e95a677SChengwen Feng &use_kvargs_process_opt[1]), 353c189450bSChengwen Feng TEST_CASE(test_parse_list_value), 3548b1656a9SChengwen Feng TEST_CASE(test_parse_empty_elements), 355*0e95a677SChengwen Feng TEST_CASE(test_parse_with_only_key), 356a79d5ce9SChengwen Feng TEST_CASE(test_invalid_kvargs), 357a79d5ce9SChengwen Feng TEST_CASES_END() /**< NULL terminate unit test array */ 358a79d5ce9SChengwen Feng } 359a79d5ce9SChengwen Feng }; 360a79d5ce9SChengwen Feng 361a9de470cSBruce Richardson static int 362a9de470cSBruce Richardson test_kvargs(void) 363a9de470cSBruce Richardson { 364a79d5ce9SChengwen Feng return unit_test_suite_runner(&kvargs_test_suite); 365a9de470cSBruce Richardson } 366a9de470cSBruce Richardson 367e0a8442cSBruce Richardson REGISTER_FAST_TEST(kvargs_autotest, true, true, test_kvargs); 368