LCOV - code coverage report
Current view: top level - tests/src - test0023.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 96.2 % 105 101
Test Date: 2026-07-12 01:01:34 Functions: 100.0 % 3 3
Branches: 61.7 % 60 37

             Branch data     Line data    Source code
       1                 :             : #include "sute.h"
       2                 :             : 
       3                 :             : enum
       4                 :             : {
       5                 :             :         TEST0023_EXPECTED_PATH_COUNT = 8
       6                 :             : };
       7                 :             : 
       8                 :             : static const char *const test0023_expected_paths[TEST0023_EXPECTED_PATH_COUNT] = {
       9                 :             :         ".",
      10                 :             :         "AAA",
      11                 :             :         "AAA/BBB",
      12                 :             :         "AAA/BBB/CCC",
      13                 :             :         "AAA/BBB/CCC/a.txt",
      14                 :             :         "AAA/BBB/uuu.txt",
      15                 :             :         "AAA/tttt.txt",
      16                 :             :         "sss.txt"
      17                 :             : };
      18                 :             : 
      19                 :             : /**
      20                 :             :  * @brief Compare two FTS entries by filename
      21                 :             :  * @param first Pointer to first FTSENT structure
      22                 :             :  * @param second Pointer to second FTSENT structure
      23                 :             :  * @return Integer less than, equal to, or greater than zero when the first
      24                 :             :  *         name is sorted before, matches, or is sorted after the second name
      25                 :             :  */
      26                 :          21 : static int test0023_compare_by_name(
      27                 :             : #ifdef __CYGWIN__
      28                 :             :         const FTSENT * const *first,
      29                 :             :         const FTSENT * const *second)
      30                 :             : #else
      31                 :             :         const FTSENT **first,
      32                 :             :         const FTSENT **second)
      33                 :             : #endif
      34                 :             : {
      35                 :          21 :         return strcmp((*first)->fts_name,(*second)->fts_name);
      36                 :             : }
      37                 :             : 
      38                 :             : /**
      39                 :             :  * @brief Check path_build_relative() for one textual form of the same fixture root
      40                 :             :  *
      41                 :             :  * @details
      42                 :             :  * The helper opens the supplied root path with FTS and verifies that every
      43                 :             :  * directory or regular file in the fixture is represented by the same
      44                 :             :  * root-relative path set. The root spelling itself may be plain relative,
      45                 :             :  * dot-relative, contain `..`, or be absolute; the built child paths must stay
      46                 :             :  * relative to that opened root
      47                 :             :  *
      48                 :             :  * @param[in] root_path_text Root path spelling passed to FTS
      49                 :             :  * @return SUCCESS when all expected root-relative paths are produced
      50                 :             :  */
      51                 :           7 : static Return test0023_expect_paths_for_root(const char *root_path_text)
      52                 :             : {
      53                 :             :         /* Status returned by this function through provide()
      54                 :             :            Default value assumes successful completion */
      55                 :           7 :         Return status = SUCCESS;
      56                 :             : 
      57                 :           7 :         bool seen[TEST0023_EXPECTED_PATH_COUNT] = {false};
      58                 :           7 :         FTS *file_systems = NULL;
      59                 :             : 
      60                 :           7 :         m_create(char,root_path,MEMORY_STRING);
      61                 :           7 :         m_create(char,relative_path,MEMORY_STRING);
      62                 :             : 
      63                 :           7 :         ASSERT(root_path_text != NULL);
      64                 :             : 
      65         [ +  - ]:           7 :         if(SUCCESS == status)
      66                 :             :         {
      67                 :           7 :                 run(m_copy_string(root_path,root_path_text));
      68                 :             :         }
      69                 :             : 
      70         [ +  - ]:           7 :         if(SUCCESS == status)
      71                 :             :         {
      72                 :           7 :                 char *runtime_root_path = m_data(char,root_path);
      73                 :           7 :                 ASSERT(runtime_root_path != NULL);
      74                 :             : 
      75         [ +  - ]:           7 :                 if(SUCCESS == status)
      76                 :             :                 {
      77                 :           7 :                         char *root_argv[] = {
      78                 :             :                                 runtime_root_path,
      79                 :             :                                 NULL
      80                 :             :                         };
      81                 :           7 :                         int fts_options = FTS_PHYSICAL;
      82                 :             : 
      83                 :             : #ifdef FTS_NOCHDIR
      84                 :           7 :                         fts_options |= FTS_NOCHDIR;
      85                 :             : #endif
      86                 :             : 
      87                 :           7 :                         file_systems = fts_open(root_argv,fts_options,test0023_compare_by_name);
      88                 :           7 :                         ASSERT(file_systems != NULL);
      89                 :             :                 }
      90                 :             :         }
      91                 :             : 
      92         [ +  - ]:           7 :         if(SUCCESS == status)
      93                 :             :         {
      94                 :           7 :                 FTSENT *entry = NULL;
      95                 :             : 
      96         [ +  + ]:          91 :                 while((entry = fts_read(file_systems)) != NULL)
      97                 :             :                 {
      98   [ +  +  +  + ]:          84 :                         if(entry->fts_info != FTS_D && entry->fts_info != FTS_F)
      99                 :             :                         {
     100                 :          28 :                                 continue;
     101                 :             :                         }
     102                 :             : 
     103                 :          56 :                         run(path_build_relative(relative_path,entry));
     104                 :             : 
     105         [ -  + ]:          56 :                         if(SUCCESS != status)
     106                 :             :                         {
     107                 :           0 :                                 break;
     108                 :             :                         }
     109                 :             : 
     110                 :          56 :                         const char *relative_path_text = m_text(relative_path);
     111                 :          56 :                         bool expected_path_seen = false;
     112                 :             : 
     113                 :          56 :                         ASSERT(relative_path_text != NULL);
     114                 :          56 :                         ASSERT(relative_path_text[0] != '\0');
     115                 :          56 :                         ASSERT(relative_path_text[0] != '/');
     116                 :             : 
     117         [ +  - ]:         252 :                         for(size_t i = 0; i < TEST0023_EXPECTED_PATH_COUNT; i++)
     118                 :             :                         {
     119         [ +  + ]:         252 :                                 if(strcmp(relative_path_text,test0023_expected_paths[i]) == COMPLETED)
     120                 :             :                                 {
     121                 :          56 :                                         seen[i] = true;
     122                 :          56 :                                         expected_path_seen = true;
     123                 :             : 
     124                 :          56 :                                         break;
     125                 :             :                                 }
     126                 :             :                         }
     127                 :             : 
     128                 :          56 :                         ASSERT(expected_path_seen == true);
     129                 :             :                 }
     130                 :             :         }
     131                 :             : 
     132         [ +  - ]:           7 :         if(file_systems != NULL)
     133                 :             :         {
     134         [ -  + ]:           7 :                 if(fts_close(file_systems) != COMPLETED)
     135                 :             :                 {
     136                 :           0 :                         status = FAILURE;
     137                 :             :                 }
     138                 :             :         }
     139                 :             : 
     140         [ +  - ]:           7 :         if(SUCCESS == status)
     141                 :             :         {
     142         [ +  + ]:          63 :                 for(size_t i = 0; i < TEST0023_EXPECTED_PATH_COUNT; i++)
     143                 :             :                 {
     144                 :          56 :                         ASSERT(seen[i] == true);
     145                 :             :                 }
     146                 :             :         }
     147                 :             : 
     148                 :           7 :         call(m_del(relative_path));
     149                 :           7 :         call(m_del(root_path));
     150                 :             : 
     151                 :           7 :         provide(status);
     152                 :             : }
     153                 :             : 
     154                 :             : /**
     155                 :             :  * @brief Test path_build_relative() with several root path spellings
     156                 :             :  *
     157                 :             :  * @details
     158                 :             :  * The test uses one real fixture directory and opens it through different
     159                 :             :  * root spellings. Relative spellings are checked from the isolated test
     160                 :             :  * workspace, because application tests also run against fixtures copied under
     161                 :             :  * `$TMPDIR`. This checks the behavior that matters to the application: the
     162                 :             :  * root path is chosen by the user and stored separately, while each file path
     163                 :             :  * produced by traversal is built relative to that opened root
     164                 :             :  *
     165                 :             :  * @return Test status indicating success or failure
     166                 :             :  */
     167                 :           1 : Return test0023(void)
     168                 :             : {
     169                 :           1 :         INITTEST;
     170                 :             : 
     171                 :           1 :         bool cwd_changed = false;
     172                 :           1 :         char *saved_cwd = NULL;
     173                 :           1 :         const char *tmpdir = getenv("TMPDIR");
     174                 :           1 :         const char *tmpdir_basename = NULL;
     175                 :           1 :         const char *tmpdir_last_slash = NULL;
     176                 :           1 :         const char *parent_basename = NULL;
     177                 :           1 :         const char *parent_end = NULL;
     178                 :           1 :         size_t parent_basename_length = 0U;
     179                 :             : 
     180                 :           1 :         m_create(char,parent_relative_root_path,MEMORY_STRING);
     181                 :           1 :         m_create(char,grandparent_relative_root_path,MEMORY_STRING);
     182                 :           1 :         m_create(char,absolute_root_path,MEMORY_STRING);
     183                 :             : 
     184                 :             :         /*
     185                 :             :          * Save the current directory because the relative-root checks below run
     186                 :             :          * from TMPDIR, just like application runs launched through testitall helpers
     187                 :             :          */
     188                 :             : #if defined(__GLIBC__)
     189                 :           1 :         saved_cwd = get_current_dir_name();
     190                 :             : #else
     191                 :             :         // Portable fallback for platforms without get_current_dir_name, such as macOS
     192                 :             :         saved_cwd = getcwd(NULL,0);
     193                 :             : #endif
     194                 :             : 
     195                 :           1 :         ASSERT(tmpdir != NULL);
     196                 :           1 :         ASSERT(saved_cwd != NULL);
     197                 :             : 
     198                 :             :         /*
     199                 :             :          * Split TMPDIR into its final directory name and its parent directory name.
     200                 :             :          * Those pieces let the test spell the same fixture root through ../ and
     201                 :             :          * ../../ without hard-coding the generated temporary directory path
     202                 :             :          */
     203         [ +  - ]:           1 :         if(SUCCESS == status)
     204                 :             :         {
     205                 :           1 :                 tmpdir_last_slash = strrchr(tmpdir,'/');
     206                 :             : 
     207                 :           1 :                 ASSERT(tmpdir_last_slash != NULL);
     208                 :           1 :                 ASSERT(tmpdir_last_slash[1] != '\0');
     209                 :             :         }
     210                 :             : 
     211         [ +  - ]:           1 :         if(SUCCESS == status)
     212                 :             :         {
     213                 :           1 :                 tmpdir_basename = tmpdir_last_slash + 1;
     214                 :           1 :                 parent_end = tmpdir_last_slash;
     215                 :             : 
     216   [ +  -  -  + ]:           1 :                 while(parent_end > tmpdir && parent_end[-1] == '/')
     217                 :             :                 {
     218                 :           0 :                         parent_end--;
     219                 :             :                 }
     220                 :             : 
     221                 :           1 :                 parent_basename = parent_end;
     222                 :             : 
     223   [ +  -  +  + ]:           4 :                 while(parent_basename > tmpdir && parent_basename[-1] != '/')
     224                 :             :                 {
     225                 :           3 :                         parent_basename--;
     226                 :             :                 }
     227                 :             : 
     228                 :           1 :                 parent_basename_length = (size_t)(parent_end - parent_basename);
     229                 :             : 
     230                 :           1 :                 ASSERT(parent_basename_length > 0U);
     231                 :           1 :                 ASSERT(parent_basename_length <= INT_MAX);
     232                 :             :         }
     233                 :             : 
     234                 :             :         /*
     235                 :             :          * Build two parent-relative root spellings that still resolve to the same
     236                 :             :          * fixture directory after the test changes into TMPDIR
     237                 :             :          */
     238         [ +  - ]:           1 :         if(SUCCESS == status)
     239                 :             :         {
     240                 :           1 :                 run(m_formatted_string(parent_relative_root_path,
     241                 :             :                         "../%s/tests/fixtures/4",
     242                 :             :                         tmpdir_basename));
     243                 :           1 :                 run(m_formatted_string(grandparent_relative_root_path,
     244                 :             :                         "../../%.*s/%s/tests/fixtures/4",
     245                 :             :                         (int)parent_basename_length,
     246                 :             :                         parent_basename,
     247                 :             :                         tmpdir_basename));
     248                 :             :         }
     249                 :             : 
     250                 :             :         /*
     251                 :             :          * Run the relative spelling checks from TMPDIR. The main application tests
     252                 :             :          * also run commands from this isolated workspace, so this mirrors the
     253                 :             :          * command-line environment used by system-style tests
     254                 :             :          */
     255         [ +  - ]:           1 :         if(SUCCESS == status)
     256                 :             :         {
     257                 :           1 :                 ASSERT(chdir(tmpdir) == COMPLETED);
     258                 :             : 
     259         [ +  - ]:           1 :                 if(SUCCESS == status)
     260                 :             :                 {
     261                 :           1 :                         cwd_changed = true;
     262                 :             :                 }
     263                 :             :         }
     264                 :             : 
     265                 :             :         /*
     266                 :             :          * Open the same fixture root through several user-facing spellings and
     267                 :             :          * require path_build_relative() to produce the same root-relative path set
     268                 :             :          * for each spelling
     269                 :             :          */
     270         [ +  - ]:           1 :         if(SUCCESS == status)
     271                 :             :         {
     272                 :           3 :                 const char *const root_path_spellings[] = {
     273                 :             :                         "tests/fixtures/4",
     274                 :             :                         "tests/fixtures/4/",
     275                 :             :                         "./tests/fixtures/4",
     276                 :             :                         "tests/fixtures/diffs/../4",
     277                 :           1 :                         m_text(parent_relative_root_path),
     278                 :           1 :                         m_text(grandparent_relative_root_path),
     279                 :             :                         NULL
     280                 :             :                 };
     281                 :             : 
     282         [ +  + ]:           7 :                 for(size_t i = 0; root_path_spellings[i] != NULL; i++)
     283                 :             :                 {
     284                 :           6 :                         run(test0023_expect_paths_for_root(root_path_spellings[i]));
     285                 :             :                 }
     286                 :             :         }
     287                 :             : 
     288                 :             :         /*
     289                 :             :          * Restore the original working directory before checking the absolute root
     290                 :             :          * spelling. This keeps the rest of the test suite independent from this test
     291                 :             :          */
     292   [ +  -  +  - ]:           1 :         if(cwd_changed == true && saved_cwd != NULL)
     293                 :             :         {
     294         [ -  + ]:           1 :                 if(chdir(saved_cwd) != COMPLETED)
     295                 :             :                 {
     296                 :           0 :                         status = FAILURE;
     297                 :             :                 }
     298                 :             : 
     299                 :           1 :                 cwd_changed = false;
     300                 :             :         }
     301                 :             : 
     302                 :             :         /*
     303                 :             :          * Check the absolute spelling separately after restoring cwd. The expected
     304                 :             :          * root-relative paths must still be identical to the relative spelling cases
     305                 :             :          */
     306         [ +  - ]:           1 :         if(SUCCESS == status)
     307                 :             :         {
     308                 :           1 :                 run(construct_path("tests/fixtures/4",absolute_root_path));
     309                 :           1 :                 run(test0023_expect_paths_for_root(m_text(absolute_root_path)));
     310                 :             :         }
     311                 :             : 
     312                 :           1 :         call(m_del(absolute_root_path));
     313                 :           1 :         call(m_del(grandparent_relative_root_path));
     314                 :           1 :         call(m_del(parent_relative_root_path));
     315                 :             : 
     316         [ +  - ]:           1 :         if(saved_cwd != NULL)
     317                 :             :         {
     318                 :           1 :                 free(saved_cwd);
     319                 :             :         }
     320                 :             : 
     321                 :           1 :         RETURN_STATUS;
     322                 :             : }
        

Generated by: LCOV version 2.0-1