LCOV - code coverage report
Current view: top level - app/test - test_string_fns.c (source / functions) Hit Total Coverage
Test: Code coverage Lines: 92 133 69.2 %
Date: 2026-07-01 18:02:41 Functions: 6 6 100.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 46 74 62.2 %

           Branch data     Line data    Source code
       1                 :            : /* SPDX-License-Identifier: BSD-3-Clause
       2                 :            :  * Copyright(c) 2010-2014 Intel Corporation
       3                 :            :  */
       4                 :            : 
       5                 :            : #include <stdio.h>
       6                 :            : #include <stdarg.h>
       7                 :            : #include <stddef.h>
       8                 :            : #include <inttypes.h>
       9                 :            : #include <errno.h>
      10                 :            : #include <string.h>
      11                 :            : 
      12                 :            : #include <rte_string_fns.h>
      13                 :            : 
      14                 :            : #include "test.h"
      15                 :            : 
      16                 :            : #define LOG(...) do {\
      17                 :            :         fprintf(stderr, "%s() ln %d: ", __func__, __LINE__); \
      18                 :            :         fprintf(stderr, __VA_ARGS__); \
      19                 :            : } while(0)
      20                 :            : 
      21                 :            : #define DATA_BYTE 'a'
      22                 :            : 
      23                 :            : static int
      24                 :          1 : test_rte_strsplit(void)
      25                 :            : {
      26                 :            :         int i;
      27                 :            :         do {
      28                 :            :                 /* =======================================================
      29                 :            :                  * split a mac address correct number of splits requested
      30                 :            :                  * =======================================================*/
      31                 :          1 :                 char test_string[] = "54:65:76:87:98:90";
      32                 :            :                 char *splits[6];
      33                 :            : 
      34                 :          1 :                 LOG("Source string: '%s', to split on ':'\n", test_string);
      35         [ -  + ]:          1 :                 if (rte_strsplit(test_string, sizeof(test_string),
      36                 :            :                                 splits, 6, ':') != 6) {
      37                 :          0 :                         LOG("Error splitting mac address\n");
      38                 :          0 :                         return -1;
      39                 :            :                 }
      40         [ +  + ]:          7 :                 for (i = 0; i < 6; i++)
      41                 :          6 :                         LOG("Token %d = %s\n", i + 1, splits[i]);
      42                 :            :         } while (0);
      43                 :            : 
      44                 :            : 
      45                 :            :         do {
      46                 :            :                 /* =======================================================
      47                 :            :                  * split on spaces smaller number of splits requested
      48                 :            :                  * =======================================================*/
      49                 :          1 :                 char test_string[] = "54 65 76 87 98 90";
      50                 :            :                 char *splits[6];
      51                 :            : 
      52                 :          1 :                 LOG("Source string: '%s', to split on ' '\n", test_string);
      53         [ -  + ]:          1 :                 if (rte_strsplit(test_string, sizeof(test_string),
      54                 :            :                                 splits, 3, ' ') != 3) {
      55                 :          0 :                         LOG("Error splitting mac address for max 2 splits\n");
      56                 :          0 :                         return -1;
      57                 :            :                 }
      58         [ +  + ]:          4 :                 for (i = 0; i < 3; i++)
      59                 :          3 :                         LOG("Token %d = %s\n", i + 1, splits[i]);
      60                 :            :         } while (0);
      61                 :            : 
      62                 :            :         do {
      63                 :            :                 /* =======================================================
      64                 :            :                  * split on commas - more splits than commas requested
      65                 :            :                  * =======================================================*/
      66                 :          1 :                 char test_string[] = "a,b,c,d";
      67                 :            :                 char *splits[6];
      68                 :            : 
      69                 :          1 :                 LOG("Source string: '%s', to split on ','\n", test_string);
      70         [ -  + ]:          1 :                 if (rte_strsplit(test_string, sizeof(test_string),
      71                 :            :                                 splits, 6, ',') != 4) {
      72                 :          0 :                         LOG("Error splitting %s on ','\n", test_string);
      73                 :          0 :                         return -1;
      74                 :            :                 }
      75         [ +  + ]:          5 :                 for (i = 0; i < 4; i++)
      76                 :          4 :                         LOG("Token %d = %s\n", i + 1, splits[i]);
      77                 :            :         } while(0);
      78                 :            : 
      79                 :            :         do {
      80                 :            :                 /* =======================================================
      81                 :            :                  * Try splitting on non-existent character.
      82                 :            :                  * =======================================================*/
      83                 :          1 :                 char test_string[] = "a,b,c,d";
      84                 :            :                 char *splits[6];
      85                 :            : 
      86                 :          1 :                 LOG("Source string: '%s', to split on ' '\n", test_string);
      87         [ -  + ]:          1 :                 if (rte_strsplit(test_string, sizeof(test_string),
      88                 :            :                                 splits, 6, ' ') != 1) {
      89                 :          0 :                         LOG("Error splitting %s on ' '\n", test_string);
      90                 :          0 :                         return -1;
      91                 :            :                 }
      92                 :          1 :                 LOG("String not split\n");
      93                 :            :         } while(0);
      94                 :            : 
      95                 :            :         do {
      96                 :            :                 /* =======================================================
      97                 :            :                  * Invalid / edge case parameter checks
      98                 :            :                  * =======================================================*/
      99                 :          1 :                 char test_string[] = "a,b,c,d";
     100                 :            :                 char *splits[6];
     101                 :            : 
     102         [ +  - ]:          1 :                 if (rte_strsplit(NULL, 0, splits, 6, ',') >= 0
     103         [ -  + ]:          1 :                                 || errno != EINVAL){
     104                 :          0 :                         LOG("Error: rte_strsplit accepted NULL string parameter\n");
     105                 :          0 :                         return -1;
     106                 :            :                 }
     107                 :            : 
     108         [ +  - ]:          1 :                 if (rte_strsplit(test_string, sizeof(test_string), NULL, 0, ',') >= 0
     109         [ -  + ]:          1 :                                 || errno != EINVAL){
     110                 :          0 :                         LOG("Error: rte_strsplit accepted NULL array parameter\n");
     111                 :          0 :                         return -1;
     112                 :            :                 }
     113                 :            : 
     114                 :          1 :                 errno = 0;
     115   [ +  -  -  + ]:          1 :                 if (rte_strsplit(test_string, 0, splits, 6, ',') != 0 || errno != 0) {
     116                 :          0 :                         LOG("Error: rte_strsplit did not accept 0 length string\n");
     117                 :          0 :                         return -1;
     118                 :            :                 }
     119                 :            : 
     120         [ +  - ]:          1 :                 if (rte_strsplit(test_string, sizeof(test_string), splits, 0, ',') != 0
     121         [ -  + ]:          1 :                                 || errno != 0) {
     122                 :          0 :                         LOG("Error: rte_strsplit did not accept 0 length array\n");
     123                 :          0 :                         return -1;
     124                 :            :                 }
     125                 :            : 
     126                 :          1 :                 LOG("Parameter test cases passed\n");
     127                 :            :         } while(0);
     128                 :            : 
     129                 :          1 :         LOG("%s - PASSED\n", __func__);
     130                 :          1 :         return 0;
     131                 :            : }
     132                 :            : 
     133                 :            : static int
     134                 :            : test_rte_strlcat(void)
     135                 :            : {
     136                 :            :         /* only run actual unit tests if we have system-provided strlcat */
     137                 :            : #if defined(__BSD_VISIBLE) || defined(RTE_USE_LIBBSD)
     138                 :            : #define BUF_LEN 32
     139                 :            :         const char dst[BUF_LEN] = "Test string";
     140                 :            :         const char src[] = " appended";
     141                 :            :         char bsd_dst[BUF_LEN];
     142                 :            :         char rte_dst[BUF_LEN];
     143                 :            :         size_t i, bsd_ret, rte_ret;
     144                 :            : 
     145                 :            :         LOG("dst = '%s', strlen(dst) = %zu\n", dst, strlen(dst));
     146                 :            :         LOG("src = '%s', strlen(src) = %zu\n", src, strlen(src));
     147                 :            :         LOG("---\n");
     148                 :            : 
     149                 :            :         for (i = 0; i < BUF_LEN; i++) {
     150                 :            :                 /* initialize destination buffers */
     151                 :            :                 memcpy(bsd_dst, dst, BUF_LEN);
     152                 :            :                 memcpy(rte_dst, dst, BUF_LEN);
     153                 :            :                 /* compare implementations */
     154                 :            :                 bsd_ret = strlcat(bsd_dst, src, i);
     155                 :            :                 rte_ret = rte_strlcat(rte_dst, src, i);
     156                 :            :                 if (bsd_ret != rte_ret) {
     157                 :            :                         LOG("Incorrect retval for buf length = %zu\n", i);
     158                 :            :                         LOG("BSD: '%zu', rte: '%zu'\n", bsd_ret, rte_ret);
     159                 :            :                         return -1;
     160                 :            :                 }
     161                 :            :                 if (memcmp(bsd_dst, rte_dst, BUF_LEN) != 0) {
     162                 :            :                         LOG("Resulting buffers don't match\n");
     163                 :            :                         LOG("BSD: '%s', rte: '%s'\n", bsd_dst, rte_dst);
     164                 :            :                         return -1;
     165                 :            :                 }
     166                 :            :                 LOG("buffer size = %zu: dst = '%s', ret = %zu\n",
     167                 :            :                         i, rte_dst, rte_ret);
     168                 :            :         }
     169                 :            :         LOG("Checked %zu combinations\n", i);
     170                 :            : #undef BUF_LEN
     171                 :            : #endif /* defined(__BSD_VISIBLE) || defined(RTE_USE_LIBBSD) */
     172                 :            : 
     173                 :            :         return 0;
     174                 :            : }
     175                 :            : 
     176                 :            : static int
     177                 :          1 : test_rte_str_skip_leading_spaces(void)
     178                 :            : {
     179                 :            :         static const char empty[] = "";
     180                 :            :         static const char nowhitespace[] = "Thereisreallynowhitespace";
     181                 :            :         static const char somewhitespaces[] = " \f\n\r\t\vThere are some whitespaces";
     182                 :            :         const char *p;
     183                 :            : 
     184                 :          1 :         LOG("Checking '%s'\n", empty);
     185                 :          1 :         p = rte_str_skip_leading_spaces(empty);
     186         [ -  + ]:          1 :         if (p != empty) {
     187                 :          0 :                 LOG("Returned address '%s' does not match expected result\n", p);
     188                 :          0 :                 return -1;
     189                 :            :         }
     190                 :          1 :         LOG("Got expected '%s'\n", p);
     191                 :          1 :         LOG("Checking '%s'\n", nowhitespace);
     192                 :          1 :         p = rte_str_skip_leading_spaces(nowhitespace);
     193         [ -  + ]:          1 :         if (p != nowhitespace) {
     194                 :          0 :                 LOG("Returned address '%s' does not match expected result\n", p);
     195                 :          0 :                 return -1;
     196                 :            :         }
     197                 :          1 :         LOG("Got expected '%s'\n", p);
     198                 :          1 :         LOG("Checking '%s'\n", somewhitespaces);
     199                 :          1 :         p = rte_str_skip_leading_spaces(somewhitespaces);
     200         [ -  + ]:          1 :         if (p != strchr(somewhitespaces, 'T')) {
     201                 :          0 :                 LOG("Returned address '%s' does not match expected result\n", p);
     202                 :          0 :                 return -1;
     203                 :            :         }
     204                 :          1 :         LOG("Got expected '%s'\n", p);
     205                 :            : 
     206                 :          1 :         return 0;
     207                 :            : }
     208                 :            : 
     209                 :            : static int
     210                 :          1 : test_rte_basename(void)
     211                 :            : {
     212                 :            :         /* Test case structure for positive cases */
     213                 :            :         struct {
     214                 :            :                 const char *input_path;    /* Input path string */
     215                 :            :                 const char *expected;      /* Expected result */
     216                 :          1 :         } test_cases[] = {
     217                 :            :                 /* Test cases from man 3 basename */
     218                 :            :                 {"/usr/lib", "lib"},
     219                 :            :                 {"/usr/", "usr"},
     220                 :            :                 {"usr", "usr"},
     221                 :            :                 {"/", "/"},
     222                 :            :                 {".", "."},
     223                 :            :                 {"..", ".."},
     224                 :            : 
     225                 :            :                 /* Additional requested test cases */
     226                 :            :                 {"/////", "/"},
     227                 :            :                 {"/path/to/file.txt", "file.txt"},
     228                 :            : 
     229                 :            :                 /* Additional edge cases with trailing slashes */
     230                 :            :                 {"///usr///", "usr"},
     231                 :            :                 {"/a/b/c/", "c"},
     232                 :            : 
     233                 :            :                 /* Empty string case */
     234                 :            :                 {"", "."},
     235                 :            :                 {NULL, "."}  /* NULL path should return "." */
     236                 :            :         };
     237                 :            : 
     238                 :            :         char buf[256];
     239                 :            :         size_t result;
     240                 :            : 
     241                 :            :         /* Run positive test cases from table */
     242         [ +  + ]:         13 :         for (size_t i = 0; i < RTE_DIM(test_cases); i++) {
     243                 :         12 :                 result = rte_basename(test_cases[i].input_path, buf, sizeof(buf));
     244                 :            : 
     245         [ -  + ]:         12 :                 if (strcmp(buf, test_cases[i].expected) != 0) {
     246                 :          0 :                         LOG("FAIL [%zu]: '%s' - buf contains '%s', expected '%s'\n",
     247                 :            :                             i, test_cases[i].input_path, buf, test_cases[i].expected);
     248                 :          0 :                         return -1;
     249                 :            :                 }
     250                 :            : 
     251                 :            :                 /* Check that the return value matches the expected string length */
     252         [ -  + ]:         12 :                 if (result != strlen(test_cases[i].expected)) {
     253                 :          0 :                         LOG("FAIL [%zu]: '%s' - returned length %zu, expected %zu\n",
     254                 :            :                             i, test_cases[i].input_path, result, strlen(test_cases[i].expected));
     255                 :          0 :                         return -1;
     256                 :            :                 }
     257                 :            : 
     258                 :         12 :                 LOG("PASS [%zu]: '%s' -> '%s' (len=%zu)\n",
     259                 :            :                                 i, test_cases[i].input_path, buf, result);
     260                 :            :         }
     261                 :            : 
     262                 :            :         /* re-run the table above verifying that for a NULL buffer, or zero length, we get
     263                 :            :          * correct length returned.
     264                 :            :          */
     265         [ +  + ]:         13 :         for (size_t i = 0; i < RTE_DIM(test_cases); i++) {
     266                 :         12 :                 result = rte_basename(test_cases[i].input_path, NULL, 0);
     267         [ -  + ]:         12 :                 if (result != strlen(test_cases[i].expected)) {
     268                 :          0 :                         LOG("FAIL [%zu]: '%s' - returned length %zu, expected %zu\n",
     269                 :            :                             i, test_cases[i].input_path, result, strlen(test_cases[i].expected));
     270                 :          0 :                         return -1;
     271                 :            :                 }
     272                 :         12 :                 LOG("PASS [%zu]: '%s' -> length %zu (NULL buffer case)\n",
     273                 :            :                     i, test_cases[i].input_path, result);
     274                 :            :         }
     275                 :            : 
     276                 :            :         /* Test case: buffer too small for result should truncate and return full length */
     277                 :            :         const size_t small_size = 5;
     278                 :          1 :         result = rte_basename("/path/to/very_long_filename.txt", buf, small_size);
     279                 :            :         /* Should be truncated to fit in 5 bytes (4 chars + null terminator) */
     280         [ -  + ]:          1 :         if (strlen(buf) >= small_size) {
     281                 :          0 :                 LOG("FAIL: small buffer test - result '%s' not properly truncated (len=%zu, buflen=%zu)\n",
     282                 :            :                     buf, strlen(buf), small_size);
     283                 :          0 :                 return -1;
     284                 :            :         }
     285                 :            :         /* Return value should indicate truncation occurred (>= buflen) */
     286         [ -  + ]:          1 :         if (result != strlen("very_long_filename.txt")) {
     287                 :          0 :                 LOG("FAIL: small buffer test - return value %zu doesn't indicate truncation (buflen=%zu)\n",
     288                 :            :                     result, small_size);
     289                 :          0 :                 return -1;
     290                 :            :         }
     291                 :          1 :         LOG("PASS: small buffer truncation -> '%s' (returned len=%zu, actual len=%zu)\n",
     292                 :            :             buf, result, strlen(buf));
     293                 :            : 
     294                 :            :         /* extreme length test case -  check that even with paths longer than PATH_MAX we still
     295                 :            :          * return the last component correctly. Use "/zzz...zzz/abc.txt" and check we get "abc.txt"
     296                 :            :          */
     297                 :          1 :         char basename_val[] = "abc.txt";
     298                 :            :         char long_path[PATH_MAX + 50];
     299         [ +  + ]:       4117 :         for (int i = 0; i < PATH_MAX + 20; i++)
     300         [ +  + ]:       8231 :                 long_path[i] = (i == 0) ? '/' : 'z';
     301                 :            :         sprintf(long_path + PATH_MAX + 20, "/%s", basename_val);
     302                 :            : 
     303                 :          1 :         result = rte_basename(long_path, buf, sizeof(buf));
     304         [ -  + ]:          1 :         if (strcmp(buf, basename_val) != 0) {
     305                 :          0 :                 LOG("FAIL: long path test - expected '%s', got '%s'\n",
     306                 :            :                     basename_val, buf);
     307                 :          0 :                 return -1;
     308                 :            :         }
     309         [ -  + ]:          1 :         if (result != strlen(basename_val)) {
     310                 :          0 :                 LOG("FAIL: long path test - expected length %zu, got %zu\n",
     311                 :            :                     strlen(basename_val), result);
     312                 :          0 :                 return -1;
     313                 :            :         }
     314                 :          1 :         LOG("PASS: long path test -> '%s' (len=%zu)\n", buf, result);
     315                 :          1 :         return 0;
     316                 :            : }
     317                 :            : 
     318                 :            : static int
     319                 :          1 : test_rte_str_to_size(void)
     320                 :            : {
     321                 :            :         struct {
     322                 :            :                 const char *str;
     323                 :            :                 uint64_t value;
     324                 :          1 :         } valid_values[] = {
     325                 :            :                 {"5G", (uint64_t)5 * 1024 * 1024 * 1024},
     326                 :            :                 {"0x20g", (uint64_t)0x20 * 1024 * 1024 * 1024},
     327                 :            :                 {"10M", 10 * 1024 * 1024},
     328                 :            :                 {"050m", 050 * 1024 * 1024},
     329                 :            :                 {"8K", 8 * 1024},
     330                 :            :                 {"15k", 15 * 1024},
     331                 :            :                 {"0200", 0200},
     332                 :            :                 {"0x103", 0x103},
     333                 :            :                 {"432", 432},
     334                 :            :                 {"-1", 0},
     335                 :            :                 {"  -2", 0},
     336                 :            :                 {"  -3MB", 0},
     337                 :            :         };
     338                 :            :         struct {
     339                 :            :                 const char *str;
     340                 :          1 :         } invalid_values[] = {
     341                 :            :                 /* we can only check for invalid input at the start of the string */
     342                 :            :                 {"garbage"},
     343                 :            :                 {""},
     344                 :            :                 {"   "},
     345                 :            :         };
     346                 :            :         unsigned int i;
     347                 :            :         uint64_t value;
     348                 :            : 
     349                 :          1 :         LOG("Checking valid rte_str_to_size inputs\n");
     350                 :            : 
     351         [ +  + ]:         13 :         for (i = 0; i < RTE_DIM(valid_values); i++) {
     352                 :         12 :                 errno = 0;
     353                 :         12 :                 value = rte_str_to_size(valid_values[i].str);
     354         [ -  + ]:         12 :                 if (value != valid_values[i].value) {
     355                 :          0 :                         LOG("FAIL: valid input '%s'\n", valid_values[i].str);
     356                 :          0 :                         return -1;
     357                 :            :                 }
     358                 :         12 :                 LOG("PASS: valid input '%s' -> %" PRIu64 "\n",
     359                 :            :                         valid_values[i].str, value);
     360                 :            :         }
     361                 :            : 
     362                 :          1 :         LOG("Checking invalid rte_str_to_size inputs\n");
     363                 :            : 
     364         [ +  + ]:          4 :         for (i = 0; i < RTE_DIM(invalid_values); i++) {
     365                 :          3 :                 errno = 0;
     366                 :          3 :                 (void)rte_str_to_size(invalid_values[i].str);
     367         [ -  + ]:          3 :                 if (errno == 0) {
     368                 :          0 :                         LOG("FAIL: invalid input '%s' did not set errno\n",
     369                 :            :                                 invalid_values[i].str);
     370                 :          0 :                         return -1;
     371                 :            :                 }
     372                 :          3 :                 LOG("PASS: invalid input '%s' set errno=%d\n",
     373                 :            :                         invalid_values[i].str, errno);
     374                 :            :         }
     375                 :            : 
     376                 :          1 :         LOG("%s - PASSED\n", __func__);
     377                 :            : 
     378                 :          1 :         return 0;
     379                 :            : }
     380                 :            : 
     381                 :            : static int
     382                 :          1 : test_string_fns(void)
     383                 :            : {
     384         [ +  - ]:          1 :         if (test_rte_strsplit() < 0)
     385                 :            :                 return -1;
     386                 :            :         if (test_rte_strlcat() < 0)
     387                 :            :                 return -1;
     388         [ +  - ]:          1 :         if (test_rte_str_skip_leading_spaces() < 0)
     389                 :            :                 return -1;
     390         [ +  - ]:          1 :         if (test_rte_basename() < 0)
     391                 :            :                 return -1;
     392         [ -  + ]:          1 :         if (test_rte_str_to_size() < 0)
     393                 :          0 :                 return -1;
     394                 :            :         return 0;
     395                 :            : }
     396                 :            : 
     397                 :        301 : REGISTER_FAST_TEST(string_autotest, NOHUGE_OK, ASAN_OK, test_string_fns);

Generated by: LCOV version 1.14