Line data Source code
1 : #include "test_helpers.h"
2 : #include "smtp_adapter.h"
3 : #include "config.h"
4 : #include <stdlib.h>
5 : #include <string.h>
6 :
7 : /* ── smtp_send error paths ───────────────────────────────────────────── */
8 :
9 1 : static void test_send_null_cfg(void) {
10 1 : ASSERT(smtp_send(NULL, "a@b.com", "c@d.com", "msg", 3) == -1,
11 : "send: NULL cfg → -1");
12 : }
13 :
14 1 : static void test_send_null_from(void) {
15 1 : Config cfg = {0};
16 1 : ASSERT(smtp_send(&cfg, NULL, "c@d.com", "msg", 3) == -1,
17 : "send: NULL from → -1");
18 : }
19 :
20 1 : static void test_send_null_to(void) {
21 1 : Config cfg = {0};
22 1 : ASSERT(smtp_send(&cfg, "a@b.com", NULL, "msg", 3) == -1,
23 : "send: NULL to → -1");
24 : }
25 :
26 1 : static void test_send_null_message(void) {
27 1 : Config cfg = {0};
28 1 : ASSERT(smtp_send(&cfg, "a@b.com", "c@d.com", NULL, 0) == -1,
29 : "send: NULL message → -1");
30 : }
31 :
32 1 : static void test_send_rejects_insecure_url(void) {
33 : /* smtp:// without ssl_no_verify should be rejected */
34 1 : Config cfg = {0};
35 1 : cfg.smtp_host = "smtp://insecure.example.com";
36 1 : cfg.ssl_no_verify = 0;
37 1 : int rc = smtp_send(&cfg, "a@b.com", "c@d.com",
38 : "From: a\r\n\r\nbody\r\n", 20);
39 1 : ASSERT(rc == -1, "send: insecure smtp:// rejected");
40 : }
41 :
42 1 : static void test_send_rejects_derived_insecure(void) {
43 : /* Derived from imap:// (not imaps://) → smtp:// → rejected */
44 1 : Config cfg = {0};
45 1 : cfg.host = "imap://imap.example.com";
46 1 : cfg.ssl_no_verify = 0;
47 1 : int rc = smtp_send(&cfg, "a@b.com", "c@d.com",
48 : "From: a\r\n\r\nbody\r\n", 20);
49 1 : ASSERT(rc == -1, "send: derived smtp:// rejected");
50 : }
51 :
52 1 : static void test_send_url_from_host_no_scheme(void) {
53 : /* cfg->host without scheme → url = strdup(cfg->host) path in build_smtp_url;
54 : * then ssl check fails (not smtps://) → -1 */
55 1 : Config cfg = {0};
56 1 : cfg.host = "mail.example.com"; /* no :// — hits the else/strdup branch */
57 1 : cfg.ssl_no_verify = 0;
58 1 : int rc = smtp_send(&cfg, "a@b.com", "c@d.com",
59 : "From: a\r\n\r\nbody\r\n", 20);
60 1 : ASSERT(rc == -1, "send: bare host URL rejected (not smtps://)");
61 : }
62 :
63 1 : static void test_send_url_fallback_localhost(void) {
64 : /* No smtp_host, no host → url = "smtp://localhost";
65 : * ssl_no_verify=0 → rejected (not smtps://) */
66 1 : Config cfg = {0};
67 1 : cfg.ssl_no_verify = 0;
68 1 : int rc = smtp_send(&cfg, "a@b.com", "c@d.com",
69 : "From: a\r\n\r\nbody\r\n", 20);
70 1 : ASSERT(rc == -1, "send: fallback smtp://localhost rejected");
71 : }
72 :
73 1 : static void test_send_url_fallback_localhost_ssl_skip(void) {
74 : /* No smtp_host, no host → url = "smtp://localhost";
75 : * ssl_no_verify=1 → passes TLS check, reaches curl, curl fails to connect → -1 */
76 1 : Config cfg = {0};
77 1 : cfg.ssl_no_verify = 1;
78 1 : int rc = smtp_send(&cfg, "a@b.com", "c@d.com",
79 : "From: a\r\n\r\nbody\r\n", 20);
80 1 : ASSERT(rc == -1, "send: smtp://localhost + ssl_no_verify reaches curl (connection refused)");
81 : }
82 :
83 1 : static void test_send_smtp_host_with_embedded_port(void) {
84 : /* smtp_host already contains a port → build_smtp_url uses strdup branch */
85 1 : Config cfg = {0};
86 1 : cfg.smtp_host = "smtps://smtp.example.com:465";
87 1 : cfg.smtp_port = 587; /* ignored because port already in URL */
88 1 : cfg.ssl_no_verify = 1;
89 : /* smtps:// passes TLS check; curl will fail to connect → -1 */
90 1 : int rc = smtp_send(&cfg, "a@b.com", "c@d.com",
91 : "From: a\r\n\r\nbody\r\n", 20);
92 1 : ASSERT(rc == -1, "send: smtp_host with embedded port (strdup path), curl fails");
93 : }
94 :
95 1 : static void test_send_smtp_host_port_appended(void) {
96 : /* smtp_port set, no port in smtp_host → asprintf path */
97 1 : Config cfg = {0};
98 1 : cfg.smtp_host = "smtps://smtp.example.com";
99 1 : cfg.smtp_port = 465;
100 1 : cfg.ssl_no_verify = 1;
101 : /* smtps:// passes TLS check; curl will fail to connect → -1 */
102 1 : int rc = smtp_send(&cfg, "a@b.com", "c@d.com",
103 : "From: a\r\n\r\nbody\r\n", 20);
104 1 : ASSERT(rc == -1, "send: smtp_port appended to smtp_host URL, curl fails");
105 : }
106 :
107 1 : static void test_send_display_name_stripping(void) {
108 : /* from/to with display names → angle-bracket stripping in envelope */
109 1 : Config cfg = {0};
110 1 : cfg.smtp_host = "smtps://smtp.example.com";
111 1 : cfg.ssl_no_verify = 1;
112 : /* The display name parsing runs before curl; curl fails → -1 */
113 1 : int rc = smtp_send(&cfg,
114 : "Alice Smith <alice@example.com>",
115 : "Bob Jones <bob@example.com>",
116 : "From: Alice Smith <alice@example.com>\r\nTo: Bob Jones <bob@example.com>\r\n\r\nHello\r\n",
117 : 80);
118 1 : ASSERT(rc == -1, "send: display name stripping reaches curl (connection refused)");
119 : }
120 :
121 1 : static void test_send_smtps_derived_from_imaps(void) {
122 : /* Derive from imaps:// → smtps:// passes TLS check; curl fails → -1 */
123 1 : Config cfg = {0};
124 1 : cfg.host = "imaps://imap.example.com";
125 1 : cfg.ssl_no_verify = 1;
126 1 : int rc = smtp_send(&cfg, "a@b.com", "c@d.com",
127 : "From: a\r\n\r\nbody\r\n", 20);
128 1 : ASSERT(rc == -1, "send: smtps derived from imaps + ssl_no_verify reaches curl");
129 : }
130 :
131 : /* ── Registration ────────────────────────────────────────────────────── */
132 :
133 1 : void test_smtp_adapter(void) {
134 1 : RUN_TEST(test_send_null_cfg);
135 1 : RUN_TEST(test_send_null_from);
136 1 : RUN_TEST(test_send_null_to);
137 1 : RUN_TEST(test_send_null_message);
138 1 : RUN_TEST(test_send_rejects_insecure_url);
139 1 : RUN_TEST(test_send_rejects_derived_insecure);
140 1 : RUN_TEST(test_send_url_from_host_no_scheme);
141 1 : RUN_TEST(test_send_url_fallback_localhost);
142 1 : RUN_TEST(test_send_url_fallback_localhost_ssl_skip);
143 1 : RUN_TEST(test_send_smtp_host_with_embedded_port);
144 1 : RUN_TEST(test_send_smtp_host_port_appended);
145 1 : RUN_TEST(test_send_display_name_stripping);
146 1 : RUN_TEST(test_send_smtps_derived_from_imaps);
147 1 : }
|