LCOV - code coverage report
Current view: top level - tests/pty - test_pty_mail_rules.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 97.8 % 223 218
Test Date: 2026-08-21 10:11:28 Functions: 100.0 % 16 16

            Line data    Source code
       1              : /**
       2              :  * @file test_pty_mail_rules.c
       3              :  * @brief PTY/functional tests for mail sorting rules (US-MR-01 … US-MR-06).
       4              :  *
       5              :  * Usage: test-pty-mail-rules <email-sync> <email-tui> <mock-imap-server>
       6              :  *
       7              :  * Tests verify that mail sorting rules defined in rules.ini are applied
       8              :  * during sync (and retroactively via --apply-rules), and that flag bits
       9              :  * are set correctly in the local manifest.
      10              :  *
      11              :  * MSG_FLAG values (from local_store.h):
      12              :  *   MSG_FLAG_UNSEEN  = 1 (bit 0)
      13              :  *   MSG_FLAG_FLAGGED = 2 (bit 1)
      14              :  *   MSG_FLAG_DONE    = 4 (bit 2)
      15              :  *   MSG_FLAG_ATTACH  = 8 (bit 3)
      16              :  *   MSG_FLAG_JUNK    = 64 (bit 6)
      17              :  */
      18              : 
      19              : #define _DEFAULT_SOURCE
      20              : #define _XOPEN_SOURCE 600
      21              : 
      22              : #include "ptytest.h"
      23              : #include "pty_assert.h"
      24              : #include <stdio.h>
      25              : #include <stdlib.h>
      26              : #include <string.h>
      27              : #include <signal.h>
      28              : #include <unistd.h>
      29              : #include <fcntl.h>
      30              : #include <sys/stat.h>
      31              : #include <sys/wait.h>
      32              : #include <sys/socket.h>
      33              : #include <netinet/in.h>
      34              : 
      35              : int g_tests_run    = 0;
      36              : int g_tests_failed = 0;
      37              : 
      38              : #define RUN_TEST(fn) do { printf("  %s...\n", #fn); fn(); } while(0)
      39              : 
      40              : /* ── Configuration ───────────────────────────────────────────────────── */
      41              : 
      42              : #define WAIT_MS   6000
      43              : #define SETTLE_MS  600
      44              : #define ROWS        24
      45              : #define COLS       100
      46              : 
      47              : /* Flag bit values (mirror local_store.h) */
      48              : #define FLAG_FLAGGED  (1 << 1)   /* MSG_FLAG_FLAGGED */
      49              : #define FLAG_JUNK     (1 << 6)   /* MSG_FLAG_JUNK    */
      50              : 
      51              : /* ── Global state ────────────────────────────────────────────────────── */
      52              : 
      53              : static pid_t g_mock_pid  = -1;
      54              : static char  g_test_home[256];
      55              : static char  g_old_home[512];
      56              : static char  g_sync_bin[512];
      57              : static char  g_tui_bin[512];
      58              : static char  g_mock_bin[512];
      59              : 
      60              : /* ── Infrastructure ──────────────────────────────────────────────────── */
      61              : 
      62              : /** Write the standard IMAP test config. */
      63           41 : static void write_config(void) {
      64              :     char d1[300], d2[300], d3[350], d4[400], path[450];
      65           41 :     snprintf(d1, sizeof(d1), "%s/.config",                                 g_test_home);
      66           41 :     snprintf(d2, sizeof(d2), "%s/.config/email-cli",                       g_test_home);
      67           41 :     snprintf(d3, sizeof(d3), "%s/.config/email-cli/accounts",              g_test_home);
      68           41 :     snprintf(d4, sizeof(d4), "%s/.config/email-cli/accounts/testuser",     g_test_home);
      69           41 :     mkdir(g_test_home, 0700);
      70           41 :     mkdir(d1, 0700);
      71           41 :     mkdir(d2, 0700);
      72           41 :     mkdir(d3, 0700);
      73           41 :     mkdir(d4, 0700);
      74           41 :     snprintf(path, sizeof(path), "%s/config.ini", d4);
      75           41 :     FILE *fp = fopen(path, "w");
      76           41 :     if (!fp) return;
      77           41 :     fprintf(fp,
      78              :         "EMAIL_HOST=imaps://localhost:9993\n"
      79              :         "EMAIL_USER=testuser\n"
      80              :         "EMAIL_PASS=testpass\n"
      81              :         "EMAIL_FOLDER=INBOX\n"
      82              :         "SSL_NO_VERIFY=1\n");
      83           41 :     fclose(fp);
      84           41 :     chmod(path, 0600);
      85              : }
      86              : 
      87              : /**
      88              :  * Write (or overwrite) rules.ini for the testuser account.
      89              :  * Pass NULL to delete the file (simulates missing rules.ini).
      90              :  */
      91           35 : static void write_rules(const char *content) {
      92              :     char dir[450], path[500];
      93           35 :     snprintf(dir, sizeof(dir),
      94              :              "%s/.config/email-cli/accounts/testuser", g_test_home);
      95           35 :     mkdir(dir, 0700);   /* ensure it exists */
      96           35 :     snprintf(path, sizeof(path), "%s/rules.ini", dir);
      97           35 :     if (!content) {
      98           11 :         unlink(path);
      99           11 :         return;
     100              :     }
     101           24 :     FILE *fp = fopen(path, "w");
     102           24 :     if (!fp) return;
     103           24 :     fputs(content, fp);
     104           24 :     fclose(fp);
     105           24 :     chmod(path, 0600);
     106              : }
     107              : 
     108              : /** Wipe the entire local email-cli store (account data + UI prefs). */
     109           33 : static void reset_all_state(void) {
     110              :     /* pty_close() only SIGTERMs the child: a previous email-sync may still be
     111              :      * flushing its manifest.  Wiping the store while that write is in flight
     112              :      * lets stale flags reappear, so give it a moment to finish first. */
     113           33 :     usleep(500000);
     114              :     char cmd[600];
     115           33 :     snprintf(cmd, sizeof(cmd),
     116              :              "rm -rf '/tmp/email-cli-rules-test-%d/.local/share/email-cli'",
     117           33 :              (int)getpid());
     118           33 :     int _rc = system(cmd); (void)_rc;
     119           33 : }
     120              : 
     121              : /* ── Mock IMAP server ────────────────────────────────────────────────── */
     122              : 
     123           33 : static int probe_server(void) {
     124           33 :     int fd = socket(AF_INET, SOCK_STREAM, 0);
     125           33 :     if (fd < 0) return -1;
     126           33 :     struct sockaddr_in addr = {
     127              :         .sin_family      = AF_INET,
     128           33 :         .sin_port        = htons(9993),
     129           33 :         .sin_addr.s_addr = htonl(INADDR_LOOPBACK)
     130              :     };
     131           33 :     int ret = connect(fd, (struct sockaddr *)&addr, sizeof(addr));
     132           33 :     close(fd);
     133           33 :     return ret;
     134              : }
     135              : 
     136           33 : static int start_mock_server(void) {
     137           33 :     g_mock_pid = fork();
     138           39 :     if (g_mock_pid < 0) return -1;
     139           39 :     if (g_mock_pid == 0) {
     140            6 :         int devnull = open("/dev/null", O_WRONLY);
     141            6 :         if (devnull >= 0) { dup2(devnull, 1); dup2(devnull, 2); close(devnull); }
     142            6 :         execl(g_mock_bin, "mock_imap_server", (char *)NULL);
     143            6 :         _exit(127);
     144              :     }
     145           33 :     usleep(800000);
     146           33 :     return 0;
     147              : }
     148              : 
     149            1 : static void stop_mock_server(void) {
     150            1 :     if (g_mock_pid > 0) {
     151            1 :         kill(g_mock_pid, SIGKILL);
     152            1 :         waitpid(g_mock_pid, NULL, 0);
     153            1 :         g_mock_pid = -1;
     154              :     }
     155            1 : }
     156              : 
     157           33 : static void restart_mock(void) {
     158           33 :     if (g_mock_pid > 0) {
     159           25 :         kill(g_mock_pid, SIGKILL);
     160           25 :         waitpid(g_mock_pid, NULL, 0);
     161           25 :         g_mock_pid = -1;
     162              :     }
     163           33 :     usleep(200000);
     164           33 :     start_mock_server();
     165           33 :     for (int i = 0; i < 30 && probe_server() != 0; i++)
     166            0 :         usleep(100000);
     167           33 : }
     168              : 
     169              : /* ── Sync / TUI helpers ──────────────────────────────────────────────── */
     170              : 
     171              : /** Run email-sync (possibly with extra args) in a PTY and return the session. */
     172           35 : static PtySession *sync_run(const char **extra_args) {
     173              :     const char *argv[16];
     174           35 :     int n = 0;
     175           35 :     argv[n++] = g_sync_bin;
     176           35 :     if (extra_args)
     177            4 :         for (int i = 0; extra_args[i] && n < 15; i++)
     178            2 :             argv[n++] = extra_args[i];
     179           35 :     argv[n] = NULL;
     180              : 
     181           35 :     PtySession *s = pty_open(COLS, ROWS);
     182           35 :     if (!s) return NULL;
     183           35 :     if (pty_run(s, argv) != 0) { pty_close(s); return NULL; }
     184           28 :     return s;
     185              : }
     186              : 
     187              : /**
     188              :  * Scan the manifest TSV for the testuser/INBOX folder and return the flags
     189              :  * integer of the first entry whose subject field contains @p subject_needle.
     190              :  *
     191              :  * Manifest line format (tab-separated):
     192              :  *   uid  from  subject  date  flags
     193              :  *
     194              :  * Returns -1 if the manifest cannot be opened or the entry is not found.
     195              :  */
     196           21 : static int find_manifest_flags(const char *subject_needle) {
     197              :     char path[600];
     198           21 :     snprintf(path, sizeof(path),
     199              :              "%s/.local/share/email-cli/accounts/testuser/manifests/INBOX.tsv",
     200              :              g_test_home);
     201           21 :     FILE *fp = fopen(path, "r");
     202           21 :     if (!fp) return -1;
     203              : 
     204              :     char line[1024];
     205           21 :     int found_flags = -1;
     206           30 :     while (fgets(line, sizeof(line), fp)) {
     207              :         /* Strip trailing newline */
     208           21 :         size_t len = strlen(line);
     209           42 :         while (len > 0 && (line[len-1] == '\n' || line[len-1] == '\r'))
     210           21 :             line[--len] = '\0';
     211              : 
     212              :         /* Split by tabs: uid, from, subject, date, flags */
     213           21 :         (void)strtok(line, "\t");         /* uid — discard */
     214           21 :         char *from = strtok(NULL, "\t");  /* from */
     215           21 :         char *subj = strtok(NULL, "\t");  /* subject */
     216           21 :         char *date = strtok(NULL, "\t");  /* date */
     217           21 :         char *fstr = strtok(NULL, "\t");  /* flags */
     218              :         (void)from; (void)date;
     219              : 
     220           21 :         if (!subj || !fstr) continue;
     221           21 :         if (subject_needle && strstr(subj, subject_needle) == NULL) continue;
     222              : 
     223           12 :         found_flags = atoi(fstr);
     224           12 :         break;
     225              :     }
     226           21 :     fclose(fp);
     227           21 :     return found_flags;
     228              : }
     229              : 
     230              : /* ══════════════════════════════════════════════════════════════════════
     231              :  *  US-MR-05: Missing rules.ini must not break sync
     232              :  * ══════════════════════════════════════════════════════════════════════ */
     233              : 
     234              : /**
     235              :  * US-MR-05: If no rules.ini exists the sync must complete normally and
     236              :  * print "Sync complete".
     237              :  */
     238            8 : static void test_rule_no_rules_sync_succeeds(void) {
     239            8 :     reset_all_state();
     240            8 :     write_config();
     241            8 :     write_rules(NULL);   /* ensure rules.ini is absent */
     242            8 :     restart_mock();
     243              : 
     244            8 :     PtySession *s = sync_run(NULL);
     245            7 :     ASSERT(s != NULL, "no-rules sync: PTY opens");
     246            7 :     ASSERT_WAIT_FOR(s, "Sync complete", WAIT_MS);
     247            7 :     pty_settle(s, SETTLE_MS);
     248            7 :     pty_close(s);
     249              : }
     250              : 
     251              : /* ══════════════════════════════════════════════════════════════════════
     252              :  *  US-MR-01: if-from glob flags matching messages
     253              :  * ══════════════════════════════════════════════════════════════════════ */
     254              : 
     255              : /**
     256              :  * US-MR-01: A rule matching the sender via if-from glob adds _flagged
     257              :  * label, which maps to MSG_FLAG_FLAGGED (bit 1) in the manifest.
     258              :  * Mock sends "From: Test User <test@example.com>".
     259              :  */
     260            7 : static void test_rule_from_glob_flags_message(void) {
     261            7 :     reset_all_state();
     262            7 :     write_config();
     263            7 :     write_rules(
     264              :         "[rule \"Flag example.com\"]\n"
     265              :         "if-from = *@example.com*\n"
     266              :         "then-add-label = _flagged\n"
     267              :     );
     268            7 :     restart_mock();
     269              : 
     270            7 :     PtySession *s = sync_run(NULL);
     271            6 :     ASSERT(s != NULL, "from-glob flag: PTY opens");
     272            6 :     ASSERT_WAIT_FOR(s, "Sync complete", WAIT_MS);
     273            6 :     pty_settle(s, SETTLE_MS);
     274            6 :     pty_close(s);
     275              : 
     276            6 :     int flags = find_manifest_flags("Test Message");
     277            6 :     ASSERT(flags >= 0, "from-glob flag: manifest entry found");
     278            6 :     ASSERT((flags & FLAG_FLAGGED) != 0,
     279              :            "from-glob flag: MSG_FLAG_FLAGGED bit set in manifest");
     280              : }
     281              : 
     282              : /* ══════════════════════════════════════════════════════════════════════
     283              :  *  US-MR-02: if-subject glob flags matching messages
     284              :  * ══════════════════════════════════════════════════════════════════════ */
     285              : 
     286              : /**
     287              :  * US-MR-02: A rule matching the subject via if-subject glob adds _flagged
     288              :  * label.  Mock message subject is "Test Message".
     289              :  */
     290            6 : static void test_rule_subject_glob_flags_message(void) {
     291            6 :     reset_all_state();
     292            6 :     write_config();
     293            6 :     write_rules(
     294              :         "[rule \"Flag Test subjects\"]\n"
     295              :         "if-subject = *Test*\n"
     296              :         "then-add-label = _flagged\n"
     297              :     );
     298            6 :     restart_mock();
     299              : 
     300            6 :     PtySession *s = sync_run(NULL);
     301            5 :     ASSERT(s != NULL, "subject-glob flag: PTY opens");
     302            5 :     ASSERT_WAIT_FOR(s, "Sync complete", WAIT_MS);
     303            5 :     pty_settle(s, SETTLE_MS);
     304            5 :     pty_close(s);
     305              : 
     306            5 :     int flags = find_manifest_flags("Test Message");
     307            5 :     ASSERT(flags >= 0, "subject-glob flag: manifest entry found");
     308            0 :     ASSERT((flags & FLAG_FLAGGED) != 0,
     309              :            "subject-glob flag: MSG_FLAG_FLAGGED bit set in manifest");
     310              : }
     311              : 
     312              : /* ══════════════════════════════════════════════════════════════════════
     313              :  *  US-MR-03: Non-matching rule must not affect unrelated messages
     314              :  * ══════════════════════════════════════════════════════════════════════ */
     315              : 
     316              : /**
     317              :  * US-MR-03: A rule whose if-from glob does not match the sender must not
     318              :  * set any flag bits.  Mock sends "test@example.com", rule matches
     319              :  * "*@nomatch.example.com" which will never fire.
     320              :  */
     321            5 : static void test_rule_nonmatch_no_effect(void) {
     322            5 :     reset_all_state();
     323            5 :     write_config();
     324            5 :     write_rules(
     325              :         "[rule \"No match\"]\n"
     326              :         "if-from = *@nomatch.example.com*\n"
     327              :         "then-add-label = _flagged\n"
     328              :     );
     329            5 :     restart_mock();
     330              : 
     331            5 :     PtySession *s = sync_run(NULL);
     332            4 :     ASSERT(s != NULL, "nonmatch rule: PTY opens");
     333            4 :     ASSERT_WAIT_FOR(s, "Sync complete", WAIT_MS);
     334            4 :     pty_settle(s, SETTLE_MS);
     335            4 :     pty_close(s);
     336              : 
     337            4 :     int flags = find_manifest_flags("Test Message");
     338            4 :     ASSERT(flags >= 0, "nonmatch rule: manifest entry found");
     339            0 :     ASSERT((flags & FLAG_FLAGGED) == 0,
     340              :            "nonmatch rule: MSG_FLAG_FLAGGED must NOT be set");
     341              : }
     342              : 
     343              : /* ══════════════════════════════════════════════════════════════════════
     344              :  *  US-MR-04: Multiple rules run in order; all matching actions apply
     345              :  * ══════════════════════════════════════════════════════════════════════ */
     346              : 
     347              : /**
     348              :  * US-MR-04: When two rules both match (one on subject, one on from),
     349              :  * both actions must be applied.  Expect FLAG_FLAGGED | FLAG_JUNK.
     350              :  */
     351            4 : static void test_rule_multiple_rules_both_apply(void) {
     352            4 :     reset_all_state();
     353            4 :     write_config();
     354            4 :     write_rules(
     355              :         "[rule \"Flag by subject\"]\n"
     356              :         "if-subject = *Test*\n"
     357              :         "then-add-label = _flagged\n"
     358              :         "\n"
     359              :         "[rule \"Junk by from\"]\n"
     360              :         "if-from = *@example.com*\n"
     361              :         "then-add-label = _junk\n"
     362              :     );
     363            4 :     restart_mock();
     364              : 
     365            4 :     PtySession *s = sync_run(NULL);
     366            3 :     ASSERT(s != NULL, "multi-rule: PTY opens");
     367            3 :     ASSERT_WAIT_FOR(s, "Sync complete", WAIT_MS);
     368            3 :     pty_settle(s, SETTLE_MS);
     369            3 :     pty_close(s);
     370              : 
     371            3 :     int flags = find_manifest_flags("Test Message");
     372            3 :     ASSERT(flags >= 0, "multi-rule: manifest entry found");
     373            3 :     ASSERT((flags & FLAG_FLAGGED) != 0,
     374              :            "multi-rule: MSG_FLAG_FLAGGED bit set (rule 1 fired)");
     375            3 :     ASSERT((flags & FLAG_JUNK) != 0,
     376              :            "multi-rule: MSG_FLAG_JUNK bit set (rule 2 fired)");
     377              : }
     378              : 
     379              : /* ══════════════════════════════════════════════════════════════════════
     380              :  *  US-MR-06: --apply-rules retroactively applies rules to existing messages
     381              :  * ══════════════════════════════════════════════════════════════════════ */
     382              : 
     383              : /**
     384              :  * US-MR-06: Sync without rules (message is downloaded, no flags set),
     385              :  * then create rules.ini, then sync --apply-rules → message is now flagged.
     386              :  */
     387            3 : static void test_rule_apply_rules_retroactive(void) {
     388              :     /* Step 1: sync without any rules */
     389            3 :     reset_all_state();
     390            3 :     write_config();
     391            3 :     write_rules(NULL);   /* no rules.ini */
     392            3 :     restart_mock();
     393              : 
     394              :     {
     395            3 :         PtySession *s = sync_run(NULL);
     396            2 :         ASSERT(s != NULL, "apply-rules retro: initial sync PTY opens");
     397            2 :         ASSERT_WAIT_FOR(s, "Sync complete", WAIT_MS);
     398            2 :         pty_settle(s, SETTLE_MS);
     399            2 :         pty_close(s);
     400              :     }
     401              : 
     402              :     /* Verify no flags set after initial sync */
     403            2 :     int flags_before = find_manifest_flags("Test Message");
     404            2 :     ASSERT(flags_before >= 0, "apply-rules retro: manifest entry found after initial sync");
     405            2 :     ASSERT((flags_before & FLAG_FLAGGED) == 0,
     406              :            "apply-rules retro: no FLAGGED bit before rules are created");
     407              : 
     408              :     /* Step 2: create rules.ini targeting the already-downloaded message */
     409            2 :     write_rules(
     410              :         "[rule \"Retroactive flag\"]\n"
     411              :         "if-from = *@example.com*\n"
     412              :         "then-add-label = _flagged\n"
     413              :     );
     414              : 
     415              :     /* Step 3: run email-sync --apply-rules.
     416              :      * It applies the rules locally, then syncs the resulting flag changes to
     417              :      * the server.  Wait for that whole sequence: "ule" alone would already
     418              :      * match the "=== Applying rules: … ===" banner printed on entry, and
     419              :      * pty_close() would then SIGTERM the process before it saves the
     420              :      * manifest. */
     421              :     {
     422            2 :         const char *args[] = {"--apply-rules", NULL};
     423            2 :         PtySession *s = sync_run(args);
     424            1 :         ASSERT(s != NULL, "apply-rules retro: --apply-rules PTY opens");
     425            1 :         ASSERT_WAIT_FOR(s, "Rules applied:", WAIT_MS);
     426            1 :         ASSERT_WAIT_FOR(s, "Sync complete", WAIT_MS);
     427            1 :         pty_settle(s, SETTLE_MS);
     428            1 :         pty_close(s);
     429              :     }
     430              : 
     431              :     /* Step 4: verify the flag bit is now set */
     432            1 :     int flags_after = find_manifest_flags("Test Message");
     433            1 :     ASSERT(flags_after >= 0, "apply-rules retro: manifest entry found after --apply-rules");
     434            1 :     ASSERT((flags_after & FLAG_FLAGGED) != 0,
     435              :            "apply-rules retro: MSG_FLAG_FLAGGED bit set after --apply-rules");
     436              : }
     437              : 
     438              : /* ══════════════════════════════════════════════════════════════════════
     439              :  *  main
     440              :  * ══════════════════════════════════════════════════════════════════════ */
     441              : 
     442            8 : int main(int argc, char *argv[]) {
     443            8 :     printf("--- email-cli PTY Mail Rules Tests ---\n\n");
     444              : 
     445            8 :     if (argc < 4) {
     446            0 :         fprintf(stderr,
     447              :                 "Usage: %s <email-sync> <email-tui> <mock-imap-server>\n",
     448              :                 argv[0]);
     449            0 :         return EXIT_FAILURE;
     450              :     }
     451            8 :     snprintf(g_sync_bin,  sizeof(g_sync_bin),  "%s", argv[1]);
     452            8 :     snprintf(g_tui_bin,   sizeof(g_tui_bin),   "%s", argv[2]);
     453            8 :     snprintf(g_mock_bin,  sizeof(g_mock_bin),  "%s", argv[3]);
     454              : 
     455            8 :     const char *home = getenv("HOME");
     456            8 :     if (home) snprintf(g_old_home, sizeof(g_old_home), "%s", home);
     457              : 
     458            8 :     snprintf(g_test_home, sizeof(g_test_home),
     459              :              "/tmp/email-cli-rules-test-%d", getpid());
     460            8 :     setenv("HOME", g_test_home, 1);
     461            8 :     unsetenv("XDG_CONFIG_HOME");
     462            8 :     unsetenv("XDG_CACHE_HOME");
     463            8 :     unsetenv("XDG_DATA_HOME");
     464              : 
     465            8 :     mkdir(g_test_home, 0700);
     466            8 :     write_config();
     467              : 
     468            8 :     printf("--- Mail rules: no rules ---\n");
     469            8 :     RUN_TEST(test_rule_no_rules_sync_succeeds);
     470              : 
     471            7 :     printf("\n--- Mail rules: from-glob (US-MR-01) ---\n");
     472            7 :     RUN_TEST(test_rule_from_glob_flags_message);
     473              : 
     474            6 :     printf("\n--- Mail rules: subject-glob (US-MR-02) ---\n");
     475            6 :     RUN_TEST(test_rule_subject_glob_flags_message);
     476              : 
     477            5 :     printf("\n--- Mail rules: non-matching rule (US-MR-03) ---\n");
     478            5 :     RUN_TEST(test_rule_nonmatch_no_effect);
     479              : 
     480            4 :     printf("\n--- Mail rules: multiple rules (US-MR-04) ---\n");
     481            4 :     RUN_TEST(test_rule_multiple_rules_both_apply);
     482              : 
     483            3 :     printf("\n--- Mail rules: retroactive --apply-rules (US-MR-06) ---\n");
     484            3 :     RUN_TEST(test_rule_apply_rules_retroactive);
     485              : 
     486            1 :     stop_mock_server();
     487            1 :     if (g_old_home[0]) setenv("HOME", g_old_home, 1);
     488              : 
     489            1 :     printf("\n--- PTY Mail Rules Test Results ---\n");
     490            1 :     printf("Tests Run:    %d\n", g_tests_run);
     491            1 :     printf("Tests Passed: %d\n", g_tests_run - g_tests_failed);
     492            1 :     printf("Tests Failed: %d\n", g_tests_failed);
     493              : 
     494            1 :     return g_tests_failed > 0 ? EXIT_FAILURE : EXIT_SUCCESS;
     495              : }
        

Generated by: LCOV version 2.0-1