LCOV - code coverage report
Current view: top level - tests/src - test0022.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 100.0 % 98 98
Test Date: 2026-07-12 01:01:34 Functions: 100.0 % 4 4
Branches: 100.0 % 2 2

             Branch data     Line data    Source code
       1                 :             : #include "sute.h"
       2                 :             : 
       3                 :             : static const char expected_noisy_remove_trailing_slash_stdout_pattern[] =
       4                 :             :         "\\A"
       5                 :             :         "ERROR: Path normalization; Failed to access non-empty descriptor as a char buffer\n"
       6                 :             :         "\\Z";
       7                 :             : 
       8                 :             : static const char expected_noisy_remove_trailing_slash_stderr_pattern[] =
       9                 :             :         "\\A"
      10                 :             :         "ERROR: [^\\n]*Memory management; Invalid arguments for string length helper[^\\n]*\n"
      11                 :             :         "ERROR: [^\\n]*Memory management; Expected 1 bytes but descriptor uses 4[^\\n]*\n"
      12                 :             :         "ERROR: [^\\n]*Memory management; Descriptor has non-zero length with NULL data pointer[^\\n]*\n"
      13                 :             :         "\\Z";
      14                 :             : 
      15                 :             : static memory *noisy_non_string_path = NULL;
      16                 :             : static memory *noisy_wrong_type_path = NULL;
      17                 :             : static memory *noisy_invalid_path = NULL;
      18                 :             : static Return noisy_null_status = SUCCESS;
      19                 :             : static Return noisy_non_string_status = SUCCESS;
      20                 :             : static Return noisy_wrong_type_status = SUCCESS;
      21                 :             : static Return noisy_invalid_path_status = SUCCESS;
      22                 :             : 
      23                 :             : /**
      24                 :             :  * @brief Exercise descriptor edge cases for remove_trailing_slash() under output capture
      25                 :             :  *
      26                 :             :  * The helper is invoked through match_function_output() so expected diagnostics
      27                 :             :  * stay captured instead of leaking into the real terminal output. The individual
      28                 :             :  * function statuses are stored in file-scope variables so the outer test
      29                 :             :  * function can assert on them after output matching succeeds
      30                 :             :  *
      31                 :             :  * @return SUCCESS when all negative calls were exercised
      32                 :             :  */
      33                 :           1 : static Return capture_noisy_remove_trailing_slash_cases(void)
      34                 :             : {
      35                 :             :         /* Status returned by this function through deliver()
      36                 :             :            Default value assumes successful completion */
      37                 :           1 :         Return status = SUCCESS;
      38                 :             : 
      39                 :           1 :         noisy_null_status = remove_trailing_slash(NULL);
      40                 :           1 :         noisy_non_string_status = remove_trailing_slash(noisy_non_string_path);
      41                 :           1 :         noisy_wrong_type_status = remove_trailing_slash(noisy_wrong_type_path);
      42                 :           1 :         noisy_invalid_path_status = remove_trailing_slash(noisy_invalid_path);
      43                 :             : 
      44                 :           1 :         deliver(status);
      45                 :             : }
      46                 :             : 
      47                 :             : /**
      48                 :             :  * @brief Helper function to test remove_trailing_slash and compare with expected output
      49                 :             :  *
      50                 :             :  * This function copies the input string, applies remove_trailing_slash(), and
      51                 :             :  * compares the result with the expected output
      52                 :             :  *
      53                 :             :  * @param input The original path to be processed
      54                 :             :  * @param expected The expected output after removing trailing slashes
      55                 :             :  */
      56                 :          17 : static Return test_remove_trailing_slash(
      57                 :             :         const char *input,
      58                 :             :         const char *expected)
      59                 :             : {
      60                 :             :         /* The status that will be returned before exiting */
      61                 :             :         /* By default, assumes the function ran without errors */
      62                 :          17 :         Return status = SUCCESS;
      63                 :             : 
      64                 :          17 :         m_create(char,temp_buffer,MEMORY_STRING);
      65                 :          17 :         const size_t expected_length = strlen(expected) + 1;
      66                 :             : 
      67                 :          17 :         ASSERT(SUCCESS == m_copy_string(temp_buffer,input));
      68                 :          17 :         ASSERT(SUCCESS & remove_trailing_slash(temp_buffer));
      69                 :             : 
      70                 :          17 :         const char *buffer_view = m_text(temp_buffer);
      71                 :             : 
      72                 :          17 :         ASSERT(buffer_view != NULL);
      73                 :          17 :         ASSERT(0 == strcmp(buffer_view,expected));
      74                 :          17 :         ASSERT(temp_buffer->string_length == expected_length - 1U);
      75                 :          17 :         ASSERT(temp_buffer->length == expected_length);
      76                 :             : 
      77                 :          17 :         m_del(temp_buffer);
      78                 :             : 
      79                 :          17 :         deliver(status);
      80                 :             : }
      81                 :             : 
      82                 :             : /**
      83                 :             :  * @brief Helper function to test remove_trailing_slash against a raw char data descriptor
      84                 :             :  *
      85                 :             :  * @param input_data Raw input bytes to place into the descriptor
      86                 :             :  * @param input_size Number of bytes in @p input_data
      87                 :             :  * @param expected The expected C string after removing trailing slashes
      88                 :             :  * @return Test status indicating success or failure
      89                 :             :  */
      90                 :           2 : static Return test_remove_trailing_slash_data(
      91                 :             :         const char *input_data,
      92                 :             :         size_t     input_size,
      93                 :             :         const char *expected)
      94                 :             : {
      95                 :             :         /* The status that will be returned before exiting */
      96                 :             :         /* By default, assumes the function ran without errors */
      97                 :           2 :         Return status = SUCCESS;
      98                 :             : 
      99                 :           2 :         m_create(char,temp_buffer,MEMORY_DATA);
     100                 :           2 :         const size_t expected_length = strlen(expected) + 1;
     101                 :             : 
     102                 :           2 :         ASSERT(input_data != NULL);
     103                 :           2 :         ASSERT(SUCCESS == m_copy_buffer(temp_buffer,input_size,input_data));
     104                 :           2 :         ASSERT(SUCCESS & remove_trailing_slash(temp_buffer));
     105                 :             : 
     106                 :           2 :         char *buffer_data = m_data(char,temp_buffer);
     107                 :             : 
     108                 :           2 :         ASSERT(buffer_data != NULL);
     109                 :           2 :         ASSERT(0 == strcmp(buffer_data,expected));
     110                 :           2 :         ASSERT(temp_buffer->string_length == 0);
     111                 :           2 :         ASSERT(temp_buffer->length == expected_length);
     112                 :             : 
     113                 :           2 :         m_del(temp_buffer);
     114                 :             : 
     115                 :           2 :         deliver(status);
     116                 :             : }
     117                 :             : 
     118                 :             : /**
     119                 :             :  * @brief Runs a series of test cases for remove_trailing_slash()
     120                 :             :  *
     121                 :             :  * Unit Testing of precizer. This function tests various scenarios including:
     122                 :             :  * - Removing trailing slashes from paths
     123                 :             :  * - Ensuring single '/' paths remain unchanged
     124                 :             :  * - Handling edge cases with multiple slashes
     125                 :             :  * - Accepting managed char data descriptors that contain a bounded string payload
     126                 :             :  * - Compacting descriptor length to visible string plus one terminator
     127                 :             :  * - Returning FAILURE for NULL, wrong-width, and data-less non-empty descriptors
     128                 :             :  * - Preserving graceful propagated statuses while still trimming
     129                 :             :  */
     130                 :           1 : Return test0022(void)
     131                 :             : {
     132                 :           1 :         INITTEST;
     133                 :             : 
     134                 :             :         static const struct {
     135                 :             :                 const char *input;
     136                 :             :                 const char *expected;
     137                 :             :         } test_cases[] = {
     138                 :             :                 // Basic cases
     139                 :             :                 {"path/","path"},
     140                 :             :                 {"folder////","folder"},
     141                 :             :                 {"/home/user////","/home/user"},
     142                 :             :                 {"/var/log//","/var/log"},
     143                 :             :                 {"/usr/local/bin/","/usr/local/bin"},
     144                 :             :                 {"///home///","///home"},
     145                 :             : 
     146                 :             :                 // Root path cases
     147                 :             :                 {"/","/"},
     148                 :             :                 {"////","/"},
     149                 :             : 
     150                 :             :                 // No trailing slashes
     151                 :             :                 {"path","path"},
     152                 :             :                 {"/usr/local/bin","/usr/local/bin"},
     153                 :             :                 {"no/slash/here","no/slash/here"},
     154                 :             : 
     155                 :             :                 // Empty string
     156                 :             :                 {"",""},
     157                 :             : 
     158                 :             :                 // Edge cases
     159                 :             :                 {"//double//slash//","//double//slash"},
     160                 :             :                 {"////multiple///leading/slashes////","////multiple///leading/slashes"},
     161                 :             : 
     162                 :             :                 // Single character paths
     163                 :             :                 {"a/","a"},
     164                 :             :                 {"b////","b"},
     165                 :             :                 {"c","c"},
     166                 :             :                 {NULL,NULL} // Sentinel value
     167                 :             :         };
     168                 :             : 
     169         [ +  + ]:          18 :         for(size_t i = 0; test_cases[i].input != NULL; i++)
     170                 :             :         {
     171                 :          17 :                 ASSERT(SUCCESS & test_remove_trailing_slash(test_cases[i].input,test_cases[i].expected));
     172                 :             :         }
     173                 :             : 
     174                 :             :         static const char data_path_without_terminator[] = {
     175                 :             :                 'd','a','t','a'
     176                 :             :         };
     177                 :             : 
     178                 :             :         static const char slashy_data_path_without_terminator[] = {
     179                 :             :                 'd','a','t','a','/','/'
     180                 :             :         };
     181                 :             : 
     182                 :           1 :         ASSERT(SUCCESS & test_remove_trailing_slash_data(
     183                 :             :                 data_path_without_terminator,
     184                 :             :                 sizeof(data_path_without_terminator),
     185                 :             :                 "data"));
     186                 :           1 :         ASSERT(SUCCESS & test_remove_trailing_slash_data(
     187                 :             :                 slashy_data_path_without_terminator,
     188                 :             :                 sizeof(slashy_data_path_without_terminator),
     189                 :             :                 "data"));
     190                 :             : 
     191                 :           1 :         m_create(char,non_string_path,MEMORY_DATA);
     192                 :           1 :         ASSERT(SUCCESS == m_copy_buffer(non_string_path,sizeof("data////"),"data////"));
     193                 :             : 
     194                 :           1 :         int wrong_type_value = 0;
     195                 :           1 :         memory wrong_type_path = {
     196                 :             :                 .single_element_size = sizeof(int),
     197                 :             :                 .actually_allocated_bytes = sizeof(int),
     198                 :             :                 .length = 1,
     199                 :             :                 .string_length = 1,
     200                 :             :                 .is_string = true,
     201                 :             :                 .data = &wrong_type_value
     202                 :             :         };
     203                 :             : 
     204                 :           1 :         memory invalid_path = {
     205                 :             :                 .single_element_size = sizeof(char),
     206                 :             :                 .actually_allocated_bytes = 1,
     207                 :             :                 .length = 1,
     208                 :             :                 .string_length = 0,
     209                 :             :                 .is_string = true,
     210                 :             :                 .data = NULL
     211                 :             :         };
     212                 :             : 
     213                 :           1 :         noisy_non_string_path = non_string_path;
     214                 :           1 :         noisy_wrong_type_path = &wrong_type_path;
     215                 :           1 :         noisy_invalid_path = &invalid_path;
     216                 :           1 :         noisy_null_status = SUCCESS;
     217                 :           1 :         noisy_non_string_status = SUCCESS;
     218                 :           1 :         noisy_wrong_type_status = SUCCESS;
     219                 :           1 :         noisy_invalid_path_status = SUCCESS;
     220                 :             : 
     221                 :           1 :         ASSERT(SUCCESS == match_function_output(
     222                 :             :                 expected_noisy_remove_trailing_slash_stdout_pattern,
     223                 :             :                 expected_noisy_remove_trailing_slash_stderr_pattern,
     224                 :             :                 capture_noisy_remove_trailing_slash_cases));
     225                 :           1 :         ASSERT(FAILURE & noisy_null_status);
     226                 :           1 :         ASSERT(TRIUMPH & noisy_non_string_status);
     227                 :           1 :         ASSERT(FAILURE & noisy_wrong_type_status);
     228                 :           1 :         ASSERT(FAILURE & noisy_invalid_path_status);
     229                 :           1 :         char *non_string_path_data = m_data(char,non_string_path);
     230                 :             : 
     231                 :           1 :         ASSERT(non_string_path_data != NULL);
     232                 :           1 :         IF(SUCCESS == status)
     233                 :             :         {
     234                 :           1 :                 ASSERT(0 == strcmp(non_string_path_data,"data"));
     235                 :           1 :                 ASSERT(non_string_path->length == sizeof("data"));
     236                 :           1 :                 ASSERT(non_string_path->string_length == 0);
     237                 :             :         }
     238                 :           1 :         m_del(non_string_path);
     239                 :             : 
     240                 :           1 :         m_create(char,hidden_tail_path,MEMORY_STRING);
     241                 :             : 
     242                 :             :         static const char hidden_tail_bytes[] = {
     243                 :             :                 'a','b','c','\0','g','a','r','b','a','g','e','/','/'
     244                 :             :         };
     245                 :           1 :         char *hidden_tail_data = NULL;
     246                 :             : 
     247                 :           1 :         ASSERT(SUCCESS == m_resize(hidden_tail_path,sizeof(hidden_tail_bytes)));
     248                 :           1 :         hidden_tail_data = m_data(char,hidden_tail_path);
     249                 :           1 :         ASSERT(hidden_tail_data != NULL);
     250                 :           1 :         IF(SUCCESS == status)
     251                 :             :         {
     252                 :           1 :                 memcpy(hidden_tail_data,hidden_tail_bytes,sizeof(hidden_tail_bytes));
     253                 :             :         }
     254                 :           1 :         ASSERT(SUCCESS == m_finalize_string(hidden_tail_path,sizeof("abc") - 1U));
     255                 :           1 :         ASSERT(0 == memcmp(hidden_tail_path->data,hidden_tail_bytes,sizeof(hidden_tail_bytes)));
     256                 :           1 :         ASSERT(SUCCESS & remove_trailing_slash(hidden_tail_path));
     257                 :           1 :         ASSERT(0 == strcmp(m_text(hidden_tail_path),"abc"));
     258                 :           1 :         ASSERT(hidden_tail_path->string_length == strlen("abc"));
     259                 :           1 :         ASSERT(hidden_tail_path->length == sizeof("abc"));
     260                 :             : 
     261                 :           1 :         m_del(hidden_tail_path);
     262                 :             : 
     263                 :           1 :         m_create(char,slashy_path,MEMORY_STRING);
     264                 :             : 
     265                 :           1 :         ASSERT(SUCCESS == m_copy_literal(slashy_path,"abc//"));
     266                 :           1 :         ASSERT(SUCCESS & remove_trailing_slash(slashy_path));
     267                 :           1 :         ASSERT(0 == strcmp(m_text(slashy_path),"abc"));
     268                 :           1 :         ASSERT(slashy_path->string_length == strlen("abc"));
     269                 :           1 :         ASSERT(slashy_path->length == sizeof("abc"));
     270                 :             : 
     271                 :           1 :         m_del(slashy_path);
     272                 :             : 
     273                 :           1 :         m_create(char,graceful_path,MEMORY_STRING);
     274                 :           1 :         ASSERT(SUCCESS == m_copy_literal(graceful_path,"graceful////"));
     275                 :             : 
     276                 :           1 :         IF(SUCCESS == status)
     277                 :             :         {
     278                 :           1 :                 Return saved_global_status = atomic_exchange(&global_return_status,INFO);
     279                 :           1 :                 Return graceful_status = remove_trailing_slash(graceful_path);
     280                 :           1 :                 atomic_store(&global_return_status,saved_global_status);
     281                 :             : 
     282                 :           1 :                 ASSERT(TRIUMPH & graceful_status);
     283                 :           1 :                 ASSERT(INFO & graceful_status);
     284                 :           1 :                 ASSERT(0 == strcmp(m_text(graceful_path),"graceful"));
     285                 :           1 :                 ASSERT(graceful_path->string_length == strlen("graceful"));
     286                 :           1 :                 ASSERT(graceful_path->length == sizeof("graceful"));
     287                 :             :         }
     288                 :             : 
     289                 :           1 :         m_del(graceful_path);
     290                 :             : 
     291                 :           1 :         RETURN_STATUS;
     292                 :             : }
        

Generated by: LCOV version 2.0-1