LCOV - code coverage report
Current view: top level - libs/testitall/src - function_capture.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 81.2 % 80 65
Test Date: 2026-01-12 05:34:38 Functions: 100.0 % 1 1

            Line data    Source code
       1              : /**
       2              :  * @file function_capture.c
       3              :  * @brief Functionality for redirecting stdout and stderr streams to buffers
       4              :  */
       5              : 
       6              : #include "testitall.h"
       7              : 
       8              : /**
       9              :  * @brief Executes a function and captures both stdout and stderr output
      10              :  *
      11              :  * @param func Function pointer to the function to be executed
      12              :  * @param stdout_buffer memory structure to store captured stdout output
      13              :  * @param stderr_buffer memory structure to store captured stderr output
      14              :  * @return Return Status of execution (SUCCESS/FAILURE)
      15              :  *
      16              :  * @details This function:
      17              :  *   1. Creates temporary files to capture stdout and stderr
      18              :  *   2. Redirects stdout and stderr to these files
      19              :  *   3. Executes the provided function
      20              :  *   4. Captures both outputs into the provided memory structures
      21              :  *   5. Restores original stdout and stderr
      22              :  *   6. Cleans up resources
      23              :  */
      24          105 : Return function_capture(
      25              :         void  (*func)(void),
      26              :         memory *stdout_buffer,
      27              :         memory *stderr_buffer)
      28              : {
      29          105 :         Return status = SUCCESS;
      30              : 
      31              :         /* Save original file descriptors */
      32          105 :         int stdout_fd = dup(STDOUT_FILENO);
      33          105 :         int stderr_fd = dup(STDERR_FILENO);
      34              : 
      35          105 :         if(stdout_fd == -1 || stderr_fd == -1)
      36              :         {
      37            0 :                 slog(ERROR,"Failed to save original file descriptors\n");
      38            0 :                 return FAILURE;
      39              :         }
      40              : 
      41              :         /* Create temporary files for redirection */
      42          105 :         FILE *stdout_tmp = tmpfile();
      43          105 :         FILE *stderr_tmp = tmpfile();
      44              : 
      45          105 :         if(stdout_tmp == NULL || stderr_tmp == NULL)
      46              :         {
      47            0 :                 slog(ERROR,"Failed to create temporary files for redirection\n");
      48            0 :                 status = FAILURE;
      49              :         }
      50              : 
      51              :         /* Disable buffering for temporary files */
      52          105 :         if(SUCCESS == status)
      53              :         {
      54          210 :                 if(setvbuf(stdout_tmp,NULL,_IONBF,0) != 0 ||
      55          105 :                         setvbuf(stderr_tmp,NULL,_IONBF,0) != 0)
      56              :                 {
      57            0 :                         slog(ERROR,"Failed to disable buffering\n");
      58            0 :                         status = FAILURE;
      59              :                 }
      60              :         }
      61              : 
      62              :         /* Disable buffering for stdout and stderr */
      63          105 :         if(SUCCESS == status)
      64              :         {
      65          210 :                 if(setvbuf(stdout,NULL,_IONBF,0) != 0 ||
      66          105 :                         setvbuf(stderr,NULL,_IONBF,0) != 0)
      67              :                 {
      68            0 :                         slog(ERROR,"Failed to disable buffering\n");
      69            0 :                         status = FAILURE;
      70              :                 }
      71              :         }
      72              : 
      73              :         /* Redirect streams */
      74          105 :         if(SUCCESS == status)
      75              :         {
      76          210 :                 if(dup2(fileno(stdout_tmp),STDOUT_FILENO) == -1 ||
      77          105 :                         dup2(fileno(stderr_tmp),STDERR_FILENO) == -1)
      78              :                 {
      79            0 :                         slog(ERROR,"Failed to redirect streams\n");
      80            0 :                         status = FAILURE;
      81              :                 }
      82              :         }
      83              : 
      84              :         /* Execute target function */
      85          105 :         if(SUCCESS == status)
      86              :         {
      87          105 :                 func();
      88          105 :                 fflush(stdout);
      89          105 :                 fflush(stderr);
      90              :         }
      91              : 
      92              :         /* Restore original streams */
      93          105 :         if(SUCCESS == status)
      94              :         {
      95          210 :                 if(dup2(stdout_fd,STDOUT_FILENO) == -1 ||
      96          105 :                         dup2(stderr_fd,STDERR_FILENO) == -1)
      97              :                 {
      98            0 :                         slog(ERROR,"Failed to restore original streams\n");
      99            0 :                         status = FAILURE;
     100              :                 }
     101              :         }
     102              : 
     103              :         /* Read data from temporary files */
     104          105 :         if(SUCCESS == status)
     105              :         {
     106              :                 size_t stdout_size,stderr_size;
     107              : 
     108              :                 /* Get buffer sizes */
     109          105 :                 fseek(stdout_tmp,0,SEEK_END);
     110          105 :                 fseek(stderr_tmp,0,SEEK_END);
     111          105 :                 stdout_size = (size_t)ftell(stdout_tmp);
     112          105 :                 stderr_size = (size_t)ftell(stderr_tmp);
     113              : 
     114              :                 /* Allocate memory for buffers */
     115          105 :                 char *stdout_mem = NULL;
     116          105 :                 char *stderr_mem = NULL;
     117              : 
     118          105 :                 if(SUCCESS == status)
     119              :                 {
     120          105 :                         if(stdout_size > 0)
     121              :                         {
     122           94 :                                 status = resize(stdout_buffer,stdout_size + 1);
     123              : 
     124           94 :                                 if(SUCCESS == status)
     125              :                                 {
     126           94 :                                         stdout_mem = data(char,stdout_buffer);
     127              : 
     128           94 :                                         if(stdout_mem == NULL)
     129              :                                         {
     130            0 :                                                 status = FAILURE;
     131              :                                         }
     132              :                                 }
     133              :                         }
     134              :                 }
     135              : 
     136          105 :                 if(SUCCESS == status)
     137              :                 {
     138          105 :                         if(stderr_size > 0)
     139              :                         {
     140            2 :                                 status = resize(stderr_buffer,stderr_size + 1);
     141              : 
     142            2 :                                 if(SUCCESS == status)
     143              :                                 {
     144            2 :                                         stderr_mem = data(char,stderr_buffer);
     145              : 
     146            2 :                                         if(stderr_mem == NULL)
     147              :                                         {
     148            0 :                                                 status = FAILURE;
     149              :                                         }
     150              :                                 }
     151              :                         }
     152              :                 }
     153              : 
     154              :                 /* Read data */
     155          105 :                 if(SUCCESS == status)
     156              :                 {
     157          105 :                         fseek(stdout_tmp,0,SEEK_SET);
     158          105 :                         fseek(stderr_tmp,0,SEEK_SET);
     159              : 
     160          105 :                         size_t read_stdout = 0;
     161              : 
     162          105 :                         if(stdout_size > 0)
     163              :                         {
     164           94 :                                 read_stdout = fread(stdout_mem,1,stdout_size,stdout_tmp);
     165              :                         }
     166              : 
     167          105 :                         size_t read_stderr = 0;
     168              : 
     169          105 :                         if(stderr_size > 0)
     170              :                         {
     171            2 :                                 read_stderr = fread(stderr_mem,1,stderr_size,stderr_tmp);
     172              :                         }
     173              : 
     174          105 :                         if(read_stdout != stdout_size || read_stderr != stderr_size)
     175              :                         {
     176            0 :                                 status = FAILURE;
     177              :                         }
     178              : 
     179          105 :                         if(SUCCESS == status)
     180              :                         {
     181          105 :                                 if(read_stdout > 0 && stdout_mem != NULL)
     182              :                                 {
     183           94 :                                         stdout_mem[stdout_size] = '\0';
     184              :                                 }
     185              : 
     186          105 :                                 if(read_stderr > 0 && stderr_mem != NULL)
     187              :                                 {
     188            2 :                                         stderr_mem[stderr_size] = '\0';
     189              :                                 }
     190              :                         }
     191              :                 }
     192              :         }
     193              : 
     194          105 :         if(stdout_tmp != NULL)
     195              :         {
     196          105 :                 fclose(stdout_tmp);
     197              :         }
     198              : 
     199          105 :         if(stderr_tmp != NULL)
     200              :         {
     201          105 :                 fclose(stderr_tmp);
     202              :         }
     203              : 
     204          105 :         close(stdout_fd);
     205          105 :         close(stderr_fd);
     206              : 
     207          105 :         return(status);
     208              : }
        

Generated by: LCOV version 2.0-1