Line data Source code
1 : #include "test_helpers.h"
2 : #include "config_store.h"
3 : #include "fs_util.h"
4 : #include "logger.h"
5 : #include "raii.h"
6 : #include <string.h>
7 : #include <stdlib.h>
8 : #include <unistd.h>
9 : #include <sys/stat.h>
10 :
11 5 : static void config_cleanup(void *ptr) {
12 5 : Config **cfg = (Config **)ptr;
13 5 : if (cfg && *cfg) {
14 2 : config_free(*cfg);
15 2 : *cfg = NULL;
16 : }
17 5 : }
18 :
19 1 : void test_config_store(void) {
20 1 : char *old_home = getenv("HOME");
21 1 : char *old_xdg = getenv("XDG_CONFIG_HOME");
22 1 : setenv("HOME", "/tmp/email-cli-test-home", 1);
23 1 : unsetenv("XDG_CONFIG_HOME");
24 : /* Pre-clean: remove any leftover account from previous test runs */
25 1 : unlink("/tmp/email-cli-test-home/.config/email-cli/accounts/test@test.com/config.ini");
26 1 : rmdir("/tmp/email-cli-test-home/.config/email-cli/accounts/test@test.com");
27 1 : rmdir("/tmp/email-cli-test-home/.config/email-cli/accounts");
28 :
29 : // 1. Test Save
30 : {
31 1 : Config cfg = {0};
32 1 : cfg.host = strdup("imaps://imap.test.com");
33 1 : cfg.user = strdup("test@test.com");
34 1 : cfg.pass = strdup("password123");
35 1 : cfg.folder = strdup("INBOX");
36 :
37 1 : int res = config_save_to_store(&cfg);
38 1 : ASSERT(res == 0, "config_save_to_store should return 0");
39 :
40 1 : free(cfg.host);
41 1 : free(cfg.user);
42 1 : free(cfg.pass);
43 1 : free(cfg.folder);
44 : }
45 :
46 : // 2. Test Load - full config
47 : {
48 2 : RAII_WITH_CLEANUP(config_cleanup) Config *loaded = config_load_from_store();
49 1 : ASSERT(loaded != NULL, "config_load_from_store should not return NULL");
50 1 : ASSERT(strcmp(loaded->host, "imaps://imap.test.com") == 0, "Host should match");
51 1 : ASSERT(strcmp(loaded->user, "test@test.com") == 0, "User should match");
52 1 : ASSERT(strcmp(loaded->pass, "password123") == 0, "Pass should match");
53 : }
54 :
55 : // 3. Test Load - incomplete config (missing host) → should return NULL
56 : {
57 1 : const char *acct_path =
58 : "/tmp/email-cli-test-home/.config/email-cli/accounts/test@test.com/config.ini";
59 1 : FILE *fp = fopen(acct_path, "w");
60 1 : if (fp) {
61 1 : fprintf(fp, "EMAIL_USER=test@test.com\n");
62 1 : fprintf(fp, "EMAIL_PASS=password123\n");
63 1 : fclose(fp);
64 : }
65 2 : RAII_WITH_CLEANUP(config_cleanup) Config *loaded = config_load_from_store();
66 1 : ASSERT(loaded == NULL, "config_load_from_store should return NULL for incomplete config");
67 : }
68 :
69 : // 4. Test Load - no config file → should return NULL
70 : {
71 1 : unlink("/tmp/email-cli-test-home/.config/email-cli/accounts/test@test.com/config.ini");
72 2 : RAII_WITH_CLEANUP(config_cleanup) Config *loaded = config_load_from_store();
73 1 : ASSERT(loaded == NULL, "config_load_from_store should return NULL when file is missing");
74 : }
75 :
76 : // 5. Test Save/Load with ssl_no_verify=1
77 : {
78 1 : Config cfg2 = {0};
79 1 : cfg2.host = strdup("imaps://imap.test.com");
80 1 : cfg2.user = strdup("test@test.com");
81 1 : cfg2.pass = strdup("password123");
82 1 : cfg2.folder = strdup("INBOX");
83 1 : cfg2.ssl_no_verify = 1;
84 :
85 1 : int res = config_save_to_store(&cfg2);
86 1 : ASSERT(res == 0, "config_save_to_store with ssl_no_verify=1 should return 0");
87 :
88 2 : RAII_WITH_CLEANUP(config_cleanup) Config *loaded2 = config_load_from_store();
89 1 : ASSERT(loaded2 != NULL, "config_load_from_store should not return NULL");
90 1 : ASSERT(loaded2->ssl_no_verify == 1, "ssl_no_verify should be 1 after load");
91 :
92 1 : free(cfg2.host);
93 1 : free(cfg2.user);
94 1 : free(cfg2.pass);
95 1 : free(cfg2.folder);
96 : }
97 :
98 : // 6. Test Load - host without protocol prefix → should return NULL with error
99 : {
100 1 : const char *acct_path =
101 : "/tmp/email-cli-test-home/.config/email-cli/accounts/test@test.com/config.ini";
102 1 : FILE *fp = fopen(acct_path, "w");
103 1 : if (fp) {
104 1 : fprintf(fp, "EMAIL_HOST=box.example.com\n");
105 1 : fprintf(fp, "EMAIL_USER=test@test.com\n");
106 1 : fprintf(fp, "EMAIL_PASS=password123\n");
107 1 : fclose(fp);
108 : }
109 2 : RAII_WITH_CLEANUP(config_cleanup) Config *loaded = config_load_from_store();
110 1 : ASSERT(loaded == NULL, "config_load_from_store should return NULL for host without protocol");
111 1 : unlink(acct_path);
112 : }
113 :
114 : // 7. Test config_free with NULL (should not crash)
115 1 : config_free(NULL);
116 :
117 : // 8. config_save_to_store fails: fs_mkdir_p fails
118 : // Make .config directory non-writable so subdirectory creation fails
119 : {
120 1 : setenv("HOME", "/tmp/email-cli-test-home-fail", 1);
121 1 : fs_mkdir_p("/tmp/email-cli-test-home-fail/.config", 0700);
122 1 : chmod("/tmp/email-cli-test-home-fail/.config", 0000);
123 :
124 1 : Config cfg_fail = {0};
125 1 : cfg_fail.host = strdup("imaps://imap.test.com");
126 1 : cfg_fail.user = strdup("test@test.com");
127 1 : cfg_fail.pass = strdup("password123");
128 1 : cfg_fail.folder = strdup("INBOX");
129 :
130 1 : int res = config_save_to_store(&cfg_fail);
131 1 : ASSERT(res == -1, "config_save_to_store: mkdir fail should return -1");
132 :
133 1 : chmod("/tmp/email-cli-test-home-fail/.config", 0700);
134 1 : free(cfg_fail.host);
135 1 : free(cfg_fail.user);
136 1 : free(cfg_fail.pass);
137 1 : free(cfg_fail.folder);
138 : }
139 :
140 : // 9. config_save_to_store fails: fopen fails
141 : // Create account dir, then place a directory at the config.ini path
142 : {
143 1 : setenv("HOME", "/tmp/email-cli-test-home-fopen", 1);
144 1 : fs_mkdir_p("/tmp/email-cli-test-home-fopen/.config/email-cli/accounts/test@test.com",
145 : 0700);
146 : // Create a directory at the config file path to make fopen("w") fail
147 1 : mkdir("/tmp/email-cli-test-home-fopen/.config/email-cli/accounts/test@test.com/config.ini",
148 : 0700);
149 :
150 1 : Config cfg_fopen = {0};
151 1 : cfg_fopen.host = strdup("imaps://imap.test.com");
152 1 : cfg_fopen.user = strdup("test@test.com");
153 1 : cfg_fopen.pass = strdup("password123");
154 1 : cfg_fopen.folder = strdup("INBOX");
155 :
156 1 : int res = config_save_to_store(&cfg_fopen);
157 1 : ASSERT(res == -1, "config_save_to_store: fopen on dir should return -1");
158 :
159 1 : rmdir("/tmp/email-cli-test-home-fopen/.config/email-cli/accounts/test@test.com/config.ini");
160 1 : free(cfg_fopen.host);
161 1 : free(cfg_fopen.user);
162 1 : free(cfg_fopen.pass);
163 1 : free(cfg_fopen.folder);
164 : }
165 :
166 1 : if (old_home) setenv("HOME", old_home, 1);
167 0 : else unsetenv("HOME");
168 1 : if (old_xdg) setenv("XDG_CONFIG_HOME", old_xdg, 1);
169 : }
|