LCOV - code coverage report
Current view: top level - src - testitall_test_hooks.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 84.3 % 172 145
Test Date: 2026-07-12 01:01:34 Functions: 100.0 % 12 12
Branches: 61.8 % 136 84

             Branch data     Line data    Source code
       1                 :             : #include "precizer.h"
       2                 :             : 
       3                 :             : #ifdef TESTITALL_TEST_HOOKS
       4                 :             : #include <errno.h>
       5                 :             : #include <limits.h>
       6                 :             : #include <stdint.h>
       7                 :             : #include <utime.h>
       8                 :             : 
       9                 :             : static const char *const signal_wait_ready_fd_env_name = "TESTITALL_SIGNAL_WAIT_READY_FD";
      10                 :             : static const int testitall_hash_checkpoint_exit_code_default = 77;
      11                 :             : 
      12                 :             : /**
      13                 :             :  * @brief Check whether a boolean test hook environment flag is enabled
      14                 :             :  *
      15                 :             :  * Only the exact string `true` enables the hook. Empty values, missing
      16                 :             :  * variables, and all other values leave the hook disabled
      17                 :             :  *
      18                 :             :  * @param[in] env_name Environment variable name to inspect
      19                 :             :  * @return true when the flag is explicitly enabled, otherwise false
      20                 :             :  */
      21                 :        2605 : static bool testitall_env_flag_is_true(const char *env_name)
      22                 :             : {
      23                 :        2605 :         const char *flag_value = NULL;
      24                 :             : 
      25         [ -  + ]:        2605 :         if(env_name == NULL)
      26                 :             :         {
      27                 :           0 :                 return(false);
      28                 :             :         }
      29                 :             : 
      30                 :        2605 :         flag_value = getenv(env_name);
      31                 :             : 
      32   [ +  +  +  + ]:        2605 :         if(flag_value == NULL || strcmp(flag_value,"true") != 0)
      33                 :             :         {
      34                 :        2597 :                 return(false);
      35                 :             :         }
      36                 :             : 
      37                 :           8 :         return(true);
      38                 :             : }
      39                 :             : 
      40                 :             : /**
      41                 :             :  * @brief Notify the background test parent that the configured wait point was reached
      42                 :             :  *
      43                 :             :  * The notification descriptor is supplied by runit_background() only for
      44                 :             :  * zero-min-delay scenarios. The helper closes the descriptor after one
      45                 :             :  * notification so repeated visits to the same wait point do not emit another
      46                 :             :  * readiness byte
      47                 :             :  */
      48                 :           4 : static void signal_wait_notify_ready(void)
      49                 :             : {
      50                 :           4 :         const char *ready_fd_text = getenv(signal_wait_ready_fd_env_name);
      51                 :             : 
      52   [ +  -  -  + ]:           4 :         if(NULL == ready_fd_text || '\0' == ready_fd_text[0])
      53                 :             :         {
      54                 :           0 :                 return;
      55                 :             :         }
      56                 :             : 
      57                 :           4 :         errno = 0;
      58                 :           4 :         char *end_ptr = NULL;
      59                 :           4 :         unsigned long long parsed_ready_fd = strtoull(ready_fd_text,&end_ptr,10);
      60                 :             : 
      61         [ +  - ]:           4 :         if(errno != 0
      62         [ +  - ]:           4 :                 || end_ptr == ready_fd_text
      63         [ +  - ]:           4 :                 || '\0' != *end_ptr
      64         [ -  + ]:           4 :                 || parsed_ready_fd > (unsigned long long)INT_MAX)
      65                 :             :         {
      66                 :           0 :                 return;
      67                 :             :         }
      68                 :             : 
      69                 :           4 :         const int ready_fd = (int)parsed_ready_fd;
      70                 :           4 :         const char notification = 'R';
      71                 :           4 :         ssize_t bytes_written = 0;
      72                 :             : 
      73                 :             :         do {
      74                 :           4 :                 bytes_written = write(ready_fd,&notification,sizeof(notification));
      75   [ -  +  -  - ]:           4 :         } while(bytes_written == -1 && errno == EINTR);
      76                 :             : 
      77                 :           4 :         (void)close(ready_fd);
      78                 :           4 :         (void)unsetenv(signal_wait_ready_fd_env_name);
      79                 :             : }
      80                 :             : 
      81                 :             : /**
      82                 :             :  * @brief Pause a test run at a configured wait point
      83                 :             :  *
      84                 :             :  * Used by signal-driven tests to delay a known execution point. The wait point
      85                 :             :  * and duration are selected with `TESTITALL_SIGNAL_WAIT_POINT` and
      86                 :             :  * `TESTITALL_SIGNAL_WAIT_MS`. The delay ends early when `global_interrupt_flag`
      87                 :             :  * is set. When `TESTITALL_SIGNAL_WAIT_READY_FD` is present, the function first
      88                 :             :  * notifies runit_background() that the configured wait point was reached
      89                 :             :  *
      90                 :             :  * @param point_id Wait point identifier reached by the caller
      91                 :             :  */
      92                 :         356 : void signal_wait_at_point(unsigned int point_id)
      93                 :             : {
      94                 :         356 :         const char *configured_point = getenv("TESTITALL_SIGNAL_WAIT_POINT");
      95                 :             : 
      96   [ +  +  -  + ]:         356 :         if(NULL == configured_point || '\0' == configured_point[0])
      97                 :             :         {
      98                 :         356 :                 return;
      99                 :             :         }
     100                 :             : 
     101                 :           6 :         errno = 0;
     102                 :           6 :         char *point_end_ptr = NULL;
     103                 :           6 :         unsigned long long parsed_point_id = strtoull(configured_point,&point_end_ptr,10);
     104                 :             : 
     105   [ +  -  +  -  :           6 :         if(errno != 0 || point_end_ptr == configured_point || '\0' != *point_end_ptr)
                   -  + ]
     106                 :             :         {
     107                 :           0 :                 return;
     108                 :             :         }
     109                 :             : 
     110         [ +  + ]:           6 :         if(parsed_point_id != (unsigned long long)point_id)
     111                 :             :         {
     112                 :           2 :                 return;
     113                 :             :         }
     114                 :             : 
     115                 :           4 :         signal_wait_notify_ready();
     116                 :             : 
     117                 :           4 :         const char *timeout_text = getenv("TESTITALL_SIGNAL_WAIT_MS");
     118                 :             : 
     119   [ +  -  -  + ]:           4 :         if(NULL == timeout_text || '\0' == timeout_text[0])
     120                 :             :         {
     121                 :           0 :                 return;
     122                 :             :         }
     123                 :             : 
     124                 :           4 :         errno = 0;
     125                 :           4 :         char *end_ptr = NULL;
     126                 :           4 :         unsigned long long parsed_timeout_ms = strtoull(timeout_text,&end_ptr,10);
     127                 :             : 
     128   [ +  -  +  -  :           4 :         if(errno != 0 || end_ptr == timeout_text || '\0' != *end_ptr || parsed_timeout_ms == 0ULL)
             +  -  -  + ]
     129                 :             :         {
     130                 :           0 :                 return;
     131                 :             :         }
     132                 :             : 
     133                 :           4 :         uint64_t remaining_timeout_ms = (uint64_t)parsed_timeout_ms;
     134                 :             : 
     135         [ +  - ]:           4 :         while(remaining_timeout_ms > 0U)
     136                 :             :         {
     137                 :             :                 /* Allow tests to release the delay as soon as the signal handler sets the flag. */
     138         [ -  + ]:           4 :                 if(atomic_load(&global_interrupt_flag) == true)
     139                 :             :                 {
     140                 :           4 :                         return;
     141                 :             :                 }
     142                 :             : 
     143                 :           4 :                 uint64_t chunk_ms = remaining_timeout_ms;
     144                 :             : 
     145         [ +  - ]:           4 :                 if(chunk_ms > 10U)
     146                 :             :                 {
     147                 :           4 :                         chunk_ms = 10U;
     148                 :             :                 }
     149                 :             : 
     150                 :           4 :                 struct timespec delay = {
     151                 :             :                         .tv_sec = 0,
     152                 :           4 :                         .tv_nsec = (long)(chunk_ms * 1000000ULL)
     153                 :             :                 };
     154                 :             : 
     155   [ +  -  +  - ]:           4 :                 while(nanosleep(&delay,&delay) == -1 && errno == EINTR)
     156                 :             :                 {
     157         [ +  - ]:           4 :                         if(atomic_load(&global_interrupt_flag) == true)
     158                 :             :                         {
     159                 :           4 :                                 return;
     160                 :             :                         }
     161                 :             :                 }
     162                 :             : 
     163                 :           0 :                 remaining_timeout_ms -= chunk_ms;
     164                 :             :         }
     165                 :             : }
     166                 :             : 
     167                 :             : /**
     168                 :             :  * @brief Check whether a path matches a configured test suffix
     169                 :             :  *
     170                 :             :  * Accepts an exact match or a suffix that begins after a path separator, so a
     171                 :             :  * relative test target can match both relative and absolute runtime paths
     172                 :             :  *
     173                 :             :  * @param[in] path Runtime path to inspect
     174                 :             :  * @param[in] suffix Test suffix to match
     175                 :             :  * @return true when the path matches the suffix, otherwise false
     176                 :             :  */
     177                 :         677 : static bool testitall_path_matches_suffix(
     178                 :             :         const char *path,
     179                 :             :         const char *suffix)
     180                 :             : {
     181                 :         677 :         size_t path_len = 0;
     182                 :         677 :         size_t suffix_len = 0;
     183                 :             : 
     184   [ +  -  -  + ]:         677 :         if(path == NULL || suffix == NULL)
     185                 :             :         {
     186                 :           0 :                 return false;
     187                 :             :         }
     188                 :             : 
     189         [ +  + ]:         677 :         if(strcmp(path,suffix) == 0)
     190                 :             :         {
     191                 :          31 :                 return true;
     192                 :             :         }
     193                 :             : 
     194                 :         646 :         path_len = strlen(path);
     195                 :         646 :         suffix_len = strlen(suffix);
     196                 :             : 
     197         [ +  + ]:         646 :         if(path_len < suffix_len + 1U)
     198                 :             :         {
     199                 :         602 :                 return false;
     200                 :             :         }
     201                 :             : 
     202         [ +  + ]:          44 :         if(path[path_len - suffix_len - 1U] != '/')
     203                 :             :         {
     204                 :          30 :                 return false;
     205                 :             :         }
     206                 :             : 
     207                 :          14 :         return strcmp(path + (path_len - suffix_len),suffix) == 0;
     208                 :             : }
     209                 :             : 
     210                 :             : /**
     211                 :             :  * @brief Apply a test-requested filesystem access status override
     212                 :             :  *
     213                 :             :  * Reads the target suffix and forced status from the test environment. When
     214                 :             :  * both values are present and the path matches, the requested status is written
     215                 :             :  * to @p access_status_out
     216                 :             :  *
     217                 :             :  * @param[in] path Runtime path being checked
     218                 :             :  * @param[out] access_status_out Receives the forced access status
     219                 :             :  * @return true when an override was applied, otherwise false
     220                 :             :  */
     221                 :       20877 : bool testitall_file_access_status_override(
     222                 :             :         const char       *path,
     223                 :             :         FileAccessStatus *access_status_out)
     224                 :             : {
     225                 :       20877 :         const char *target_suffix = getenv("TESTITALL_TEST_ENV_FILE_ACCESS_SUFFIX");
     226                 :       20877 :         const char *forced_status = getenv("TESTITALL_TEST_ENV_FILE_ACCESS_STATUS");
     227                 :             : 
     228         [ +  - ]:       20877 :         if(path == NULL
     229         [ +  - ]:       20877 :                 || access_status_out == NULL
     230         [ +  + ]:       20877 :                 || target_suffix == NULL
     231         [ +  - ]:       20869 :                 || forced_status == NULL
     232         [ +  + ]:       20869 :                 || target_suffix[0] == '\0'
     233         [ -  + ]:         677 :                 || forced_status[0] == '\0')
     234                 :             :         {
     235                 :       20200 :                 return false;
     236                 :             :         }
     237                 :             : 
     238         [ +  + ]:         677 :         if(testitall_path_matches_suffix(path,target_suffix) == false)
     239                 :             :         {
     240                 :         638 :                 return false;
     241                 :             :         }
     242                 :             : 
     243         [ -  + ]:          39 :         if(strcmp(forced_status,"FILE_ACCESS_ALLOWED") == 0)
     244                 :             :         {
     245                 :           0 :                 *access_status_out = FILE_ACCESS_ALLOWED;
     246                 :             : 
     247         [ +  + ]:          39 :         } else if(strcmp(forced_status,"FILE_ACCESS_DENIED") == 0){
     248                 :          12 :                 *access_status_out = FILE_ACCESS_DENIED;
     249                 :             : 
     250         [ +  + ]:          27 :         } else if(strcmp(forced_status,"FILE_NOT_FOUND") == 0){
     251                 :           2 :                 *access_status_out = FILE_NOT_FOUND;
     252                 :             : 
     253         [ +  - ]:          25 :         } else if(strcmp(forced_status,"FILE_ACCESS_ERROR") == 0){
     254                 :          25 :                 *access_status_out = FILE_ACCESS_ERROR;
     255                 :             : 
     256                 :             :         } else {
     257                 :           0 :                 slog(ERROR,"Test hook failed: unsupported TESTITALL_TEST_ENV_FILE_ACCESS_STATUS value %s\n",forced_status);
     258                 :           0 :                 *access_status_out = FILE_ACCESS_ERROR;
     259                 :             :         }
     260                 :             : 
     261                 :          39 :         return true;
     262                 :             : }
     263                 :             : 
     264                 :             : /**
     265                 :             :  * @brief Simulate an unexpected database metadata change in dry-run mode
     266                 :             :  *
     267                 :             :  * When enabled by environment variable
     268                 :             :  * `TESTITALL_TEST_ENV_DB_FILE_TIMESTAMPS_WILL_BUMPED=true`, this helper updates
     269                 :             :  * database file timestamps via utime(), forcing metadata drift before the final
     270                 :             :  * `stat()` comparison in db_check_changes()
     271                 :             :  *
     272                 :             :  * The hook is intentionally limited to dry-run on an existing primary DB file
     273                 :             :  *
     274                 :             :  * @return SUCCESS when the hook is inactive or updated the timestamps,
     275                 :             :  *         otherwise FAILURE
     276                 :             :  */
     277                 :         116 : Return testitall_db_bump_timestamps(void)
     278                 :             : {
     279                 :             :         /* Status returned by this function through provide()
     280                 :             :            Default value assumes successful completion */
     281                 :         116 :         Return status = SUCCESS;
     282                 :             : 
     283                 :         116 :         const char *flag_value = getenv("TESTITALL_TEST_ENV_DB_FILE_TIMESTAMPS_WILL_BUMPED");
     284                 :             : 
     285   [ +  +  +  + ]:         116 :         if(flag_value == NULL || strcmp(flag_value,"true") != 0)
     286                 :             :         {
     287                 :         114 :                 return(status);
     288                 :             :         }
     289                 :             : 
     290         [ -  + ]:           2 :         if(config->dry_run != true)
     291                 :             :         {
     292                 :           0 :                 slog(ERROR,"Test hook failed: TESTITALL_TEST_ENV_DB_FILE_TIMESTAMPS_WILL_BUMPED requires --dry-run\n");
     293                 :           0 :                 return(FAILURE);
     294                 :             :         }
     295                 :             : 
     296         [ -  + ]:           2 :         if(config->db_primary_file_exists != true)
     297                 :             :         {
     298                 :           0 :                 return(status);
     299                 :             :         }
     300                 :             : 
     301                 :           2 :         const char *db_path = confstr(db_primary_file_path);
     302                 :             : 
     303   [ +  -  -  + ]:           2 :         if(db_path == NULL || db_path[0] == '\0')
     304                 :             :         {
     305                 :           0 :                 slog(ERROR,"Test hook failed: database path is empty\n");
     306                 :           0 :                 return(FAILURE);
     307                 :             :         }
     308                 :             : 
     309         [ -  + ]:           2 :         if(utime(db_path,NULL) != 0)
     310                 :             :         {
     311                 :           0 :                 slog(ERROR,"Test hook failed: unable to bump timestamps for %s\n",db_path);
     312                 :           0 :                 return(FAILURE);
     313                 :             :         }
     314                 :             : 
     315                 :           2 :         slog(TESTING,"Test hook: database file timestamps were bumped for %s\n",confstr(db_file_name));
     316                 :             : 
     317                 :           2 :         return(status);
     318                 :             : }
     319                 :             : 
     320                 :             : /**
     321                 :             :  * @brief Simulate missing database metadata drift during update mode
     322                 :             :  *
     323                 :             :  * When enabled by environment variable
     324                 :             :  * `TESTITALL_TEST_ENV_DB_FILE_STAT_WILL_BE_RESYNCED=true`, this helper overwrites
     325                 :             :  * the saved baseline stat (`config->db_file_stat`) with the current DB file
     326                 :             :  * stat. This forces metadata comparison in db_check_changes() to report
     327                 :             :  * IDENTICAL, even if the database was modified earlier in the same run
     328                 :             :  *
     329                 :             :  * The hook is intentionally limited to non-dry-run mode and to cases where
     330                 :             :  * `config->db_primary_file_modified` is already true
     331                 :             :  *
     332                 :             :  * @param[in] db_current_stat Current metadata for the primary database file
     333                 :             :  * @return SUCCESS when the hook is inactive or resynchronized the baseline,
     334                 :             :  *         otherwise FAILURE
     335                 :             :  */
     336                 :         116 : Return testitall_db_resync_stat_baseline(const struct stat *db_current_stat)
     337                 :             : {
     338                 :             :         /* Status returned by this function through provide()
     339                 :             :            Default value assumes successful completion */
     340                 :         116 :         Return status = SUCCESS;
     341                 :             : 
     342                 :         116 :         const char *flag_value = getenv("TESTITALL_TEST_ENV_DB_FILE_STAT_WILL_BE_RESYNCED");
     343                 :             : 
     344   [ +  +  +  + ]:         116 :         if(flag_value == NULL || strcmp(flag_value,"true") != 0)
     345                 :             :         {
     346                 :         114 :                 return(status);
     347                 :             :         }
     348                 :             : 
     349         [ -  + ]:           2 :         if(config->dry_run == true)
     350                 :             :         {
     351                 :           0 :                 slog(ERROR,"Test hook failed: TESTITALL_TEST_ENV_DB_FILE_STAT_WILL_BE_RESYNCED requires non-dry-run mode\n");
     352                 :           0 :                 return(FAILURE);
     353                 :             :         }
     354                 :             : 
     355         [ -  + ]:           2 :         if(config->db_primary_file_exists != true)
     356                 :             :         {
     357                 :           0 :                 return(status);
     358                 :             :         }
     359                 :             : 
     360         [ -  + ]:           2 :         if(config->db_primary_file_modified != true)
     361                 :             :         {
     362                 :           0 :                 slog(ERROR,"Test hook failed: baseline resync requested, but database modification flag is false\n");
     363                 :           0 :                 return(FAILURE);
     364                 :             :         }
     365                 :             : 
     366         [ -  + ]:           2 :         if(db_current_stat == NULL)
     367                 :             :         {
     368                 :           0 :                 slog(ERROR,"Test hook failed: current database stat is unavailable\n");
     369                 :           0 :                 return(FAILURE);
     370                 :             :         }
     371                 :             : 
     372                 :             :         /*
     373                 :             :          * Intentionally corrupt the comparison baseline for test coverage:
     374                 :             :          * make "before" equal to "after" even after a real DB update.
     375                 :             :          */
     376                 :           2 :         config->db_file_stat = *db_current_stat;
     377                 :             : 
     378                 :           2 :         slog(TESTING,"Test hook: baseline database stat was resynced to current metadata for %s\n",confstr(db_file_name));
     379                 :             : 
     380                 :           2 :         return(status);
     381                 :             : }
     382                 :             : 
     383                 :             : /**
     384                 :             :  * @brief Check whether a path points to the large interruption test file
     385                 :             :  *
     386                 :             :  * @param[in] path Path being hashed during a test build
     387                 :             :  * @return true when the path ends with the interruption fixture name
     388                 :             :  */
     389                 :        2597 : bool testitall_is_huge_interruption_target(const char *path)
     390                 :             : {
     391         [ -  + ]:        2597 :         if(path == NULL)
     392                 :             :         {
     393                 :           0 :                 return(false);
     394                 :             :         }
     395                 :             : 
     396                 :        2597 :         const char *needle = "hugetestfile";
     397                 :        2597 :         const size_t path_length = strlen(path);
     398                 :        2597 :         const size_t needle_length = strlen(needle);
     399                 :             : 
     400         [ +  + ]:        2597 :         if(path_length < needle_length)
     401                 :             :         {
     402                 :          38 :                 return(false);
     403                 :             :         }
     404                 :             : 
     405                 :        2559 :         return(0 == strcmp(path + (path_length - needle_length),needle));
     406                 :             : }
     407                 :             : 
     408                 :             : /**
     409                 :             :  * @brief Generate a pseudo-random stop byte in the closed range [1, file_size]
     410                 :             :  *
     411                 :             :  * @param[in] file_size File size used as the inclusive upper bound
     412                 :             :  * @return Selected byte offset, or zero when @p file_size is zero
     413                 :             :  */
     414                 :          11 : uint64_t testitall_random_stop_byte(const uint64_t file_size)
     415                 :             : {
     416         [ -  + ]:          11 :         if(file_size == 0U)
     417                 :             :         {
     418                 :           0 :                 return(0U);
     419                 :             :         }
     420                 :             : 
     421                 :          11 :         struct timespec now = {0};
     422                 :          11 :         (void)clock_gettime(CLOCK_MONOTONIC,&now);
     423                 :             : 
     424                 :          11 :         uint64_t seed = (uint64_t)now.tv_nsec;
     425                 :          11 :         seed ^= ((uint64_t)now.tv_sec << 32);
     426                 :          11 :         seed ^= (uint64_t)getpid();
     427                 :             : 
     428                 :          11 :         return((seed % file_size) + 1U);
     429                 :             : }
     430                 :             : 
     431                 :             : /**
     432                 :             :  * @brief Check whether SHA512 checkpoint tests should checkpoint at a random byte
     433                 :             :  *
     434                 :             :  * Enabled by `TESTITALL_TEST_ENV_HASH_CHECKPOINT_AT_RANDOM_BYTE=true`
     435                 :             :  *
     436                 :             :  * @return true when the hook is enabled, otherwise false
     437                 :             :  */
     438                 :        2601 : bool testitall_hash_checkpoint_at_random_byte_enabled(void)
     439                 :             : {
     440                 :        2601 :         return(testitall_env_flag_is_true("TESTITALL_TEST_ENV_HASH_CHECKPOINT_AT_RANDOM_BYTE"));
     441                 :             : }
     442                 :             : 
     443                 :             : /**
     444                 :             :  * @brief Check whether SHA512 checkpoint tests should terminate after checkpoint
     445                 :             :  *
     446                 :             :  * Enabled by `TESTITALL_TEST_ENV_EXIT_AFTER_HASH_CHECKPOINT=true`
     447                 :             :  *
     448                 :             :  * @return true when the hook is enabled, otherwise false
     449                 :             :  */
     450                 :           4 : bool testitall_exit_after_hash_checkpoint_enabled(void)
     451                 :             : {
     452                 :           4 :         return(testitall_env_flag_is_true("TESTITALL_TEST_ENV_EXIT_AFTER_HASH_CHECKPOINT"));
     453                 :             : }
     454                 :             : 
     455                 :             : /**
     456                 :             :  * @brief Terminate the current process after a test-controlled hash checkpoint
     457                 :             :  *
     458                 :             :  * The exit status is read from `TESTITALL_TEST_ENV_HASH_CHECKPOINT_EXIT_CODE`.
     459                 :             :  * Invalid, empty, zero, and out-of-range values fall back to 77 so the process
     460                 :             :  * never exits successfully by accident
     461                 :             :  */
     462                 :           3 : void testitall_exit_after_hash_checkpoint(void)
     463                 :             : {
     464                 :           3 :         int exit_code = testitall_hash_checkpoint_exit_code_default;
     465                 :           3 :         const char *exit_code_text = getenv("TESTITALL_TEST_ENV_HASH_CHECKPOINT_EXIT_CODE");
     466                 :             : 
     467   [ +  -  +  - ]:           3 :         if(exit_code_text != NULL && exit_code_text[0] != '\0')
     468                 :             :         {
     469                 :           3 :                 errno = 0;
     470                 :           3 :                 char *end_ptr = NULL;
     471                 :           3 :                 const long parsed_exit_code = strtol(exit_code_text,&end_ptr,10);
     472                 :             : 
     473         [ +  - ]:           3 :                 if(errno == 0
     474         [ +  - ]:           3 :                         && end_ptr != exit_code_text
     475         [ +  - ]:           3 :                         && *end_ptr == '\0'
     476         [ +  - ]:           3 :                         && parsed_exit_code > 0L
     477         [ +  - ]:           3 :                         && parsed_exit_code <= 255L)
     478                 :             :                 {
     479                 :           3 :                         exit_code = (int)parsed_exit_code;
     480                 :             :                 }
     481                 :             :         }
     482                 :             : 
     483                 :           3 :         slog(TESTING,"Test hook: exiting after hash checkpoint with code %d\n",exit_code);
     484                 :           3 :         exit(exit_code);
     485                 :             : }
     486                 :             : #endif
        

Generated by: LCOV version 2.0-1