LCOV - code coverage report
Current view: top level - app/test - test_string_fns.c (source / functions) Hit Total Coverage
Test: Code coverage Lines: 74 111 66.7 %
Date: 2025-11-01 17:50:34 Functions: 5 5 100.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 39 64 60.9 %

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

Generated by: LCOV version 1.14