LCOV - code coverage report
Current view: top level - tests/pty - test_pty_send_local.c (source / functions) Coverage Total Hit
Test: coverage-functional.info Lines: 97.0 % 263 255
Test Date: 2026-08-21 10:11:30 Functions: 100.0 % 21 21

            Line data    Source code
       1              : /**
       2              :  * @file test_pty_send_local.c
       3              :  * @brief PTY tests for local-first send behaviour (US-SL-01 to US-SL-04).
       4              :  *
       5              :  * US-SL-01: Successful SMTP send → message saved to local Sent folder,
       6              :  *           queued in pending_appends.tsv, TUI shows "Saved locally".
       7              :  * US-SL-02: Failed SMTP send → message saved to local Drafts folder,
       8              :  *           queued in pending_appends.tsv, TUI shows "Saved to Drafts".
       9              :  * US-SL-03: email-sync uploads pending messages and clears the queue.
      10              :  * US-SL-04: pending_appends.tsv survives between runs (persistent queue).
      11              :  *
      12              :  * Usage: test-pty-send-local <email-tui> <email-sync>
      13              :  *                             <mock-imap-server> <mock-smtp-server>
      14              :  */
      15              : 
      16              : #define _DEFAULT_SOURCE
      17              : #define _XOPEN_SOURCE 600
      18              : 
      19              : #include "ptytest.h"
      20              : #include "pty_assert.h"
      21              : 
      22              : #include <dirent.h>
      23              : #include <fcntl.h>
      24              : #include <netinet/in.h>
      25              : #include <signal.h>
      26              : #include <stdio.h>
      27              : #include <stdlib.h>
      28              : #include <string.h>
      29              : #include <sys/socket.h>
      30              : #include <sys/stat.h>
      31              : #include <sys/wait.h>
      32              : #include <unistd.h>
      33              : 
      34              : /* ── Test globals ────────────────────────────────────────────────────── */
      35              : 
      36              : int g_tests_run    = 0;
      37              : int g_tests_failed = 0;
      38              : 
      39              : static char g_tui_bin[512];
      40              : static char g_sync_bin[512];
      41              : static char g_imap_bin[512];
      42              : static char g_smtp_bin[512];
      43              : 
      44              : static char g_test_home[512];
      45              : static char g_old_home[512];
      46              : static char g_editor_script[600];
      47              : 
      48              : static pid_t g_imap_pid = -1;
      49              : static pid_t g_smtp_pid = -1;
      50              : 
      51              : #define WAIT_MS    8000
      52              : #define SETTLE_MS   400
      53              : #define ROWS 24
      54              : #define COLS 120
      55              : 
      56              : #define RUN_TEST(fn) do { printf("  %s...\n", #fn); fflush(stdout); fn(); } while(0)
      57              : 
      58              : /* Account directory under test HOME (username-based path) */
      59              : #define ACCOUNT_DIR  "/.local/share/email-cli/accounts/testuser@example.com"
      60              : 
      61              : /* ── Fake editor ─────────────────────────────────────────────────────── */
      62              : 
      63           23 : static void write_editor_script(void) {
      64           23 :     snprintf(g_editor_script, sizeof(g_editor_script),
      65              :              "%s/.fake_editor.sh", g_test_home);
      66           23 :     FILE *f = fopen(g_editor_script, "w");
      67           23 :     if (!f) return;
      68           23 :     fprintf(f, "#!/bin/sh\necho 'Test body' >> \"$1\"\n");
      69           23 :     fclose(f);
      70           23 :     chmod(g_editor_script, 0755);
      71           23 :     setenv("EDITOR", g_editor_script, 1);
      72              : }
      73              : 
      74              : /* ── Directory setup ──────────────────────────────────────────────────── */
      75              : 
      76           29 : static void mkdirs(void) {
      77              :     char d[700];
      78           29 :     snprintf(d, sizeof(d), "%s/.config",                              g_test_home); mkdir(d, 0700);
      79           29 :     snprintf(d, sizeof(d), "%s/.config/email-cli",                    g_test_home); mkdir(d, 0700);
      80           29 :     snprintf(d, sizeof(d), "%s/.config/email-cli/accounts",           g_test_home); mkdir(d, 0700);
      81           29 :     snprintf(d, sizeof(d), "%s/.config/email-cli/accounts/testuser",  g_test_home); mkdir(d, 0700);
      82           29 :     snprintf(d, sizeof(d), "%s/.local",                               g_test_home); mkdir(d, 0700);
      83           29 :     snprintf(d, sizeof(d), "%s/.local/share",                         g_test_home); mkdir(d, 0700);
      84           29 :     snprintf(d, sizeof(d), "%s/.local/share/email-cli",               g_test_home); mkdir(d, 0700);
      85           29 :     snprintf(d, sizeof(d), "%s/.local/share/email-cli/accounts",      g_test_home); mkdir(d, 0700);
      86           29 :     snprintf(d, sizeof(d), "%s%s",                                    g_test_home, ACCOUNT_DIR); mkdir(d, 0700);
      87           29 :     snprintf(d, sizeof(d), "%s%s/manifests",                          g_test_home, ACCOUNT_DIR); mkdir(d, 0700);
      88           29 : }
      89              : 
      90           23 : static void write_config(void) {
      91           23 :     mkdirs();
      92              :     char path[800];
      93           23 :     snprintf(path, sizeof(path),
      94              :              "%s/.config/email-cli/accounts/testuser/config.ini", g_test_home);
      95           23 :     FILE *fp = fopen(path, "w");
      96           23 :     if (!fp) return;
      97           23 :     fprintf(fp,
      98              :         "EMAIL_HOST=imaps://localhost:9993\n"
      99              :         "EMAIL_USER=testuser@example.com\n"
     100              :         "EMAIL_PASS=testpass\n"
     101              :         "EMAIL_FOLDER=INBOX\n"
     102              :         "SMTP_HOST=smtps://localhost:9025\n"
     103              :         "SMTP_PORT=9025\n"
     104              :         "SMTP_USER=testuser@example.com\n"
     105              :         "SMTP_PASS=testpass\n"
     106              :         "SSL_NO_VERIFY=1\n");
     107           23 :     fclose(fp);
     108           23 :     chmod(path, 0600);
     109              : }
     110              : 
     111              : /* ── Server helpers ───────────────────────────────────────────────────── */
     112              : 
     113           53 : static int probe_port(int port) {
     114           53 :     int fd = socket(AF_INET, SOCK_STREAM, 0);
     115           53 :     if (fd < 0) return -1;
     116           53 :     struct sockaddr_in a = {0};
     117           53 :     a.sin_family = AF_INET;
     118           53 :     a.sin_port   = htons((uint16_t)port);
     119           53 :     a.sin_addr.s_addr = htonl(0x7f000001);
     120           53 :     int r = connect(fd, (struct sockaddr *)&a, sizeof(a));
     121           53 :     close(fd);
     122           53 :     return r;
     123              : }
     124              : 
     125           53 : static void start_server(const char *bin, pid_t *pid_out) {
     126           53 :     *pid_out = fork();
     127           66 :     if (*pid_out < 0) return;
     128           66 :     if (*pid_out == 0) {
     129           13 :         int devnull = open("/dev/null", O_WRONLY);
     130           13 :         if (devnull >= 0) { dup2(devnull, 1); dup2(devnull, 2); close(devnull); }
     131           13 :         execl(bin, bin, (char *)NULL);
     132           13 :         _exit(127);
     133              :     }
     134           53 :     usleep(800000);
     135              : }
     136              : 
     137           61 : static void stop_server(pid_t *pid_out) {
     138           61 :     if (*pid_out > 0) {
     139           44 :         kill(*pid_out, SIGKILL);
     140           44 :         waitpid(*pid_out, NULL, 0);
     141           44 :         *pid_out = -1;
     142              :     }
     143           61 : }
     144              : 
     145              : /* Kill any process still listening on the given TCP port (cleanup of
     146              :  * lingering instances from previous test runs). */
     147            5 : static void kill_listeners_on_port(int port) {
     148              :     char cmd[80];
     149            5 :     snprintf(cmd, sizeof(cmd), "fuser -k -KILL %d/tcp >/dev/null 2>&1", port);
     150            5 :     int _unused = system(cmd); (void)_unused;
     151            5 :     usleep(200000);
     152            5 : }
     153              : 
     154           29 : static void restart_imap(void) {
     155           29 :     stop_server(&g_imap_pid);
     156           29 :     usleep(200000);
     157           29 :     start_server(g_imap_bin, &g_imap_pid);
     158           29 :     for (int i = 0; i < 30 && probe_port(9993) != 0; i++) usleep(100000);
     159           29 : }
     160              : 
     161           24 : static void restart_smtp(void) {
     162           24 :     stop_server(&g_smtp_pid);
     163           24 :     usleep(200000);
     164           24 :     start_server(g_smtp_bin, &g_smtp_pid);
     165           24 :     for (int i = 0; i < 30 && probe_port(9025) != 0; i++) usleep(100000);
     166           24 : }
     167              : 
     168              : /* ── TUI / sync runners ───────────────────────────────────────────────── */
     169              : 
     170           17 : static PtySession *tui_run(void) {
     171           17 :     const char *args[4] = { g_tui_bin, NULL };
     172           17 :     PtySession *s = pty_open(COLS, ROWS);
     173           17 :     if (!s) return NULL;
     174           17 :     if (pty_run(s, args) != 0) { pty_close(s); return NULL; }
     175           13 :     return s;
     176              : }
     177              : 
     178            3 : static PtySession *sync_run(const char **extra_args) {
     179              :     const char *argv[16];
     180            3 :     int n = 0;
     181            3 :     argv[n++] = g_sync_bin;
     182            3 :     if (extra_args)
     183            0 :         for (int i = 0; extra_args[i] && n < 15; i++)
     184            0 :             argv[n++] = extra_args[i];
     185            3 :     argv[n] = NULL;
     186            3 :     PtySession *s = pty_open(COLS, ROWS);
     187            3 :     if (!s) return NULL;
     188            3 :     if (pty_run(s, argv) != 0) { pty_close(s); return NULL; }
     189            2 :     return s;
     190              : }
     191              : 
     192              : /*
     193              :  * Navigate TUI to the folder browser for the test account.
     194              :  * Returns a running PtySession ready at the folder browser screen,
     195              :  * or NULL on failure.
     196              :  */
     197           17 : static PtySession *tui_open_to_folders(void) {
     198           17 :     write_config();
     199           17 :     PtySession *s = tui_run();
     200           13 :     if (!s) return NULL;
     201           13 :     if (pty_wait_for(s, "testuser", WAIT_MS) != 0) { pty_close(s); return NULL; }
     202           13 :     pty_settle(s, SETTLE_MS);
     203           13 :     pty_send_key(s, PTY_KEY_ENTER);
     204           13 :     if (pty_wait_for(s, "Folders", WAIT_MS) != 0) { pty_close(s); return NULL; }
     205           13 :     pty_settle(s, SETTLE_MS);
     206           13 :     return s;
     207              : }
     208              : 
     209              : /*
     210              :  * Navigate TUI to the INBOX message list.
     211              :  */
     212           17 : static PtySession *tui_open_to_inbox(void) {
     213           17 :     PtySession *s = tui_open_to_folders();
     214           13 :     if (!s) return NULL;
     215           13 :     pty_send_key(s, PTY_KEY_HOME);
     216           91 :     for (int i = 0; i < 6; i++) { pty_send_key(s, PTY_KEY_DOWN); pty_settle(s, 50); }
     217           13 :     if (pty_wait_for(s, "INBOX", WAIT_MS) != 0) { pty_close(s); return NULL; }
     218           13 :     pty_settle(s, SETTLE_MS);
     219           13 :     pty_send_key(s, PTY_KEY_ENTER);
     220           13 :     if (pty_wait_for(s, "message(s) in", WAIT_MS) != 0) { pty_close(s); return NULL; }
     221           13 :     pty_settle(s, SETTLE_MS);
     222           13 :     return s;
     223              : }
     224              : 
     225              : /* ── File-system helpers ──────────────────────────────────────────────── */
     226              : 
     227              : /* Return 1 if the pending_appends.tsv file contains a line starting with folder. */
     228           14 : static int pending_has_folder(const char *folder) {
     229              :     char path[800];
     230           14 :     snprintf(path, sizeof(path), "%s%s/pending_appends.tsv", g_test_home, ACCOUNT_DIR);
     231           14 :     FILE *fp = fopen(path, "r");
     232           14 :     if (!fp) return 0;
     233              :     char line[512];
     234           14 :     while (fgets(line, sizeof(line), fp)) {
     235           14 :         if (strncmp(line, folder, strlen(folder)) == 0 && line[strlen(folder)] == '\t') {
     236           14 :             fclose(fp);
     237           14 :             return 1;
     238              :         }
     239              :     }
     240            0 :     fclose(fp);
     241            0 :     return 0;
     242              : }
     243              : 
     244              : /* Return 1 if the pending_appends.tsv file is empty or does not exist. */
     245            2 : static int pending_is_empty(void) {
     246              :     char path[800];
     247            2 :     snprintf(path, sizeof(path), "%s%s/pending_appends.tsv", g_test_home, ACCOUNT_DIR);
     248            2 :     FILE *fp = fopen(path, "r");
     249            2 :     if (!fp) return 1; /* does not exist → empty */
     250            2 :     int c = fgetc(fp);
     251            2 :     fclose(fp);
     252            2 :     return (c == EOF);
     253              : }
     254              : 
     255              : /* Delete pending_appends.tsv to reset state between tests. */
     256           17 : static void pending_reset(void) {
     257              :     char path[800];
     258           17 :     snprintf(path, sizeof(path), "%s%s/pending_appends.tsv", g_test_home, ACCOUNT_DIR);
     259           17 :     unlink(path);
     260           17 : }
     261              : 
     262              : /* ══════════════════════════════════════════════════════════════════════
     263              :  * TC-SL-01 (US-SL-01): Successful SMTP send → local Sent + pending queue
     264              :  * ══════════════════════════════════════════════════════════════════════ */
     265              : 
     266            6 : static void test_successful_send_saves_locally(void) {
     267            6 :     pending_reset();
     268            6 :     restart_imap(); restart_smtp();
     269            6 :     write_editor_script();
     270            6 :     PtySession *s = tui_open_to_inbox();
     271            5 :     ASSERT(s != NULL, "TC-SL-01: reached inbox");
     272              : 
     273              :     /* Press 'c' to open compose dialog */
     274            5 :     pty_send_str(s, "c");
     275            5 :     ASSERT_WAIT_FOR(s, "New Message", WAIT_MS);
     276            5 :     pty_settle(s, SETTLE_MS);
     277              : 
     278              :     /* Fill To: field and Tab to Subject */
     279            5 :     pty_send_str(s, "recipient@example.com");
     280            5 :     pty_send_key(s, PTY_KEY_TAB); /* To → Cc */
     281            5 :     pty_send_key(s, PTY_KEY_TAB); /* Cc → Bcc */
     282            5 :     pty_send_key(s, PTY_KEY_TAB); /* Bcc → Subject */
     283            5 :     pty_send_str(s, "TC-SL-01 Test Subject");
     284            5 :     pty_send_key(s, PTY_KEY_ENTER); /* open editor */
     285              : 
     286              :     /* Wait for send confirmation prompt, confirm, then check result */
     287              :     /* US-85: the post-compose review screen replaced the old "Send? [y/n]"
     288              :      * prompt; 's' sends from there. */
     289            5 :     ASSERT_WAIT_FOR(s, "Review: Message", WAIT_MS * 2);
     290            5 :     pty_send_str(s, "s");
     291            5 :     ASSERT_WAIT_FOR(s, "Sending", WAIT_MS);
     292            5 :     ASSERT_WAIT_FOR(s, "Message sent.", WAIT_MS);
     293            5 :     ASSERT_WAIT_FOR(s, "Saved locally", WAIT_MS);
     294              : 
     295            5 :     pty_close(s);
     296              : 
     297              :     /* Verify pending_appends.tsv has a Sent entry */
     298            5 :     ASSERT(pending_has_folder("Sent"), "TC-SL-01: pending_appends.tsv has Sent entry");
     299              : }
     300              : 
     301              : /* ══════════════════════════════════════════════════════════════════════
     302              :  * TC-SL-02 (US-SL-02): Failed SMTP send → local Drafts + pending queue
     303              :  * ══════════════════════════════════════════════════════════════════════ */
     304              : 
     305            5 : static void test_failed_send_saves_to_drafts(void) {
     306            5 :     pending_reset();
     307            5 :     restart_imap();
     308            5 :     stop_server(&g_smtp_pid);       /* kill the server we started */
     309            5 :     kill_listeners_on_port(9025);   /* kill any lingering instance */
     310            5 :     write_editor_script();
     311            5 :     PtySession *s = tui_open_to_inbox();
     312            4 :     ASSERT(s != NULL, "TC-SL-02: reached inbox");
     313              : 
     314            4 :     pty_send_str(s, "c");
     315            4 :     ASSERT_WAIT_FOR(s, "New Message", WAIT_MS);
     316            4 :     pty_settle(s, SETTLE_MS);
     317              : 
     318            4 :     pty_send_str(s, "recipient@example.com");
     319            4 :     pty_send_key(s, PTY_KEY_TAB);
     320            4 :     pty_send_key(s, PTY_KEY_TAB);
     321            4 :     pty_send_key(s, PTY_KEY_TAB);
     322            4 :     pty_send_str(s, "TC-SL-02 Test Draft");
     323            4 :     pty_send_key(s, PTY_KEY_ENTER);
     324              : 
     325              :     /* Wait for send confirmation, confirm, then check failure path */
     326              :     /* US-85: the post-compose review screen replaced the old "Send? [y/n]"
     327              :      * prompt; 's' sends from there. */
     328            4 :     ASSERT_WAIT_FOR(s, "Review: Message", WAIT_MS * 2);
     329            4 :     pty_send_str(s, "s");
     330            4 :     ASSERT_WAIT_FOR(s, "Sending", WAIT_MS);
     331            4 :     ASSERT_WAIT_FOR(s, "Saved to Drafts", WAIT_MS);
     332              : 
     333            4 :     pty_close(s);
     334              : 
     335              :     /* Verify pending_appends.tsv has a Drafts entry */
     336            4 :     ASSERT(pending_has_folder("Drafts"), "TC-SL-02: pending_appends.tsv has Drafts entry");
     337              : }
     338              : 
     339              : /* ══════════════════════════════════════════════════════════════════════
     340              :  * TC-SL-03 (US-SL-03): email-sync uploads pending messages, clears queue
     341              :  * ══════════════════════════════════════════════════════════════════════ */
     342              : 
     343            4 : static void test_sync_uploads_pending_and_clears_queue(void) {
     344              :     /* Seed pending_appends.tsv via a successful send first */
     345            4 :     pending_reset();
     346            4 :     restart_imap(); restart_smtp();
     347            4 :     write_editor_script();
     348            4 :     PtySession *s = tui_open_to_inbox();
     349            3 :     ASSERT(s != NULL, "TC-SL-03 setup: reached inbox");
     350              : 
     351            3 :     pty_send_str(s, "c");
     352            3 :     ASSERT_WAIT_FOR(s, "New Message", WAIT_MS);
     353            3 :     pty_settle(s, SETTLE_MS);
     354            3 :     pty_send_str(s, "recipient@example.com");
     355            3 :     pty_send_key(s, PTY_KEY_TAB);
     356            3 :     pty_send_key(s, PTY_KEY_TAB);
     357            3 :     pty_send_key(s, PTY_KEY_TAB);
     358            3 :     pty_send_str(s, "TC-SL-03 Sync Test");
     359            3 :     pty_send_key(s, PTY_KEY_ENTER);
     360              :     /* US-85: the post-compose review screen replaced the old "Send? [y/n]"
     361              :      * prompt; 's' sends from there. */
     362            3 :     ASSERT_WAIT_FOR(s, "Review: Message", WAIT_MS * 2);
     363            3 :     pty_send_str(s, "s");
     364            3 :     ASSERT_WAIT_FOR(s, "Saved locally", WAIT_MS);
     365            3 :     pty_close(s);
     366              : 
     367            3 :     ASSERT(pending_has_folder("Sent"), "TC-SL-03 setup: Sent entry queued before sync");
     368              : 
     369              :     /* Run email-sync to upload the pending message */
     370            3 :     PtySession *ss = sync_run(NULL);
     371            2 :     ASSERT(ss != NULL, "TC-SL-03: email-sync started");
     372            2 :     ASSERT_WAIT_FOR(ss, "uploaded", WAIT_MS);
     373            2 :     pty_close(ss);
     374              : 
     375              :     /* Queue should now be empty */
     376            2 :     ASSERT(pending_is_empty(), "TC-SL-03: pending_appends.tsv empty after sync");
     377              : }
     378              : 
     379              : /* ══════════════════════════════════════════════════════════════════════
     380              :  * TC-SL-04 (US-SL-04): pending queue survives process restart
     381              :  * ══════════════════════════════════════════════════════════════════════ */
     382              : 
     383            2 : static void test_pending_queue_survives_restart(void) {
     384              :     /* Seed via a successful send */
     385            2 :     pending_reset();
     386            2 :     restart_imap(); restart_smtp();
     387            2 :     write_editor_script();
     388            2 :     PtySession *s = tui_open_to_inbox();
     389            1 :     ASSERT(s != NULL, "TC-SL-04 setup: reached inbox");
     390              : 
     391            1 :     pty_send_str(s, "c");
     392            1 :     ASSERT_WAIT_FOR(s, "New Message", WAIT_MS);
     393            1 :     pty_settle(s, SETTLE_MS);
     394            1 :     pty_send_str(s, "recipient@example.com");
     395            1 :     pty_send_key(s, PTY_KEY_TAB);
     396            1 :     pty_send_key(s, PTY_KEY_TAB);
     397            1 :     pty_send_key(s, PTY_KEY_TAB);
     398            1 :     pty_send_str(s, "TC-SL-04 Persist Test");
     399            1 :     pty_send_key(s, PTY_KEY_ENTER);
     400              :     /* US-85: the post-compose review screen replaced the old "Send? [y/n]"
     401              :      * prompt; 's' sends from there. */
     402            1 :     ASSERT_WAIT_FOR(s, "Review: Message", WAIT_MS * 2);
     403            1 :     pty_send_str(s, "s");
     404            1 :     ASSERT_WAIT_FOR(s, "Saved locally", WAIT_MS);
     405            1 :     pty_close(s);
     406              : 
     407            1 :     ASSERT(pending_has_folder("Sent"), "TC-SL-04: Sent entry in queue after send");
     408              : 
     409              :     /* Stop all servers; restart — queue must still be there */
     410            1 :     stop_server(&g_smtp_pid);
     411              : 
     412            1 :     ASSERT(pending_has_folder("Sent"), "TC-SL-04: Sent entry persists after process restart");
     413              : }
     414              : 
     415              : /* ── main ─────────────────────────────────────────────────────────────── */
     416              : 
     417            6 : int main(int argc, char **argv) {
     418            6 :     printf("--- Local-first send PTY Tests (US-SL-01 … US-SL-04) ---\n\n");
     419              : 
     420            6 :     if (argc < 5) {
     421            0 :         fprintf(stderr,
     422              :                 "Usage: %s <email-tui> <email-sync> "
     423              :                 "<mock-imap-server> <mock-smtp-server>\n",
     424              :                 argv[0]);
     425            0 :         return 1;
     426              :     }
     427              : 
     428            6 :     snprintf(g_tui_bin,  sizeof(g_tui_bin),  "%s", argv[1]);
     429            6 :     snprintf(g_sync_bin, sizeof(g_sync_bin), "%s", argv[2]);
     430            6 :     snprintf(g_imap_bin, sizeof(g_imap_bin), "%s", argv[3]);
     431            6 :     snprintf(g_smtp_bin, sizeof(g_smtp_bin), "%s", argv[4]);
     432              : 
     433            6 :     snprintf(g_test_home, sizeof(g_test_home), "/tmp/test-send-local-XXXXXX");
     434            6 :     if (!mkdtemp(g_test_home)) {
     435            0 :         perror("mkdtemp");
     436            0 :         return 1;
     437              :     }
     438            6 :     if (getenv("HOME"))
     439            6 :         snprintf(g_old_home, sizeof(g_old_home), "%s", getenv("HOME"));
     440            6 :     setenv("HOME", g_test_home, 1);
     441              :     /* XDG_*_HOME wins over $HOME in the binaries; if the caller's environment
     442              :      * sets them (GitHub runners do) the test home is bypassed and the setup
     443              :      * wizard opens instead of the configured account. */
     444            6 :     unsetenv("XDG_CONFIG_HOME");
     445            6 :     unsetenv("XDG_DATA_HOME");
     446            6 :     unsetenv("XDG_CACHE_HOME");
     447              : 
     448            6 :     mkdirs();
     449            6 :     write_config();
     450            6 :     write_editor_script();
     451              : 
     452            6 :     restart_imap();
     453            6 :     restart_smtp();
     454              : 
     455            6 :     printf("--- US-SL-01: Successful send saves locally ---\n");
     456            6 :     RUN_TEST(test_successful_send_saves_locally);
     457              : 
     458            5 :     printf("\n--- US-SL-02: Failed send saves to Drafts ---\n");
     459            5 :     RUN_TEST(test_failed_send_saves_to_drafts);
     460              : 
     461            4 :     printf("\n--- US-SL-03: Sync uploads pending messages ---\n");
     462            4 :     restart_imap(); restart_smtp();
     463            4 :     RUN_TEST(test_sync_uploads_pending_and_clears_queue);
     464              : 
     465            2 :     printf("\n--- US-SL-04: Pending queue survives restart ---\n");
     466            2 :     restart_imap(); restart_smtp();
     467            2 :     RUN_TEST(test_pending_queue_survives_restart);
     468              : 
     469            1 :     stop_server(&g_imap_pid);
     470            1 :     stop_server(&g_smtp_pid);
     471              : 
     472            1 :     if (g_old_home[0]) setenv("HOME", g_old_home, 1);
     473              : 
     474            1 :     printf("\n--- Test Results ---\n");
     475            1 :     printf("Tests Run:    %d\n", g_tests_run);
     476            1 :     printf("Tests Passed: %d\n", g_tests_run - g_tests_failed);
     477            1 :     printf("Tests Failed: %d\n", g_tests_failed);
     478              : 
     479            1 :     return g_tests_failed > 0 ? 1 : 0;
     480              : }
        

Generated by: LCOV version 2.0-1