Line data Source code
1 : /**
2 : * @file test_domain_self.c
3 : * @brief Unit tests for domain_get_self (US-05).
4 : *
5 : * Uses mock socket + mock crypto. Builds a fake Vector<User> response and
6 : * verifies field extraction and error handling.
7 : */
8 :
9 : #include "test_helpers.h"
10 : #include "domain/read/self.h"
11 : #include "tl_serial.h"
12 : #include "tl_registry.h"
13 : #include "mock_socket.h"
14 : #include "mock_crypto.h"
15 : #include "mtproto_session.h"
16 : #include "transport.h"
17 : #include "api_call.h"
18 :
19 : #include <stdlib.h>
20 : #include <string.h>
21 :
22 : /* Re-used helper for building an "encrypted" response (passthrough crypto). */
23 4 : static void build_fake_encrypted_response(const uint8_t *payload, size_t plen,
24 : uint8_t *out, size_t *out_len) {
25 : TlWriter w;
26 4 : tl_writer_init(&w);
27 4 : uint8_t zeros24[24] = {0};
28 4 : tl_write_raw(&w, zeros24, 24); /* auth_key_id + msg_key */
29 4 : uint8_t header[32] = {0};
30 4 : uint32_t plen32 = (uint32_t)plen;
31 4 : memcpy(header + 28, &plen32, 4); /* data_len */
32 4 : tl_write_raw(&w, header, 32);
33 4 : tl_write_raw(&w, payload, plen);
34 :
35 4 : size_t enc = w.len - 24;
36 4 : if (enc % 16 != 0) {
37 3 : uint8_t pad[16] = {0};
38 3 : tl_write_raw(&w, pad, 16 - (enc % 16));
39 : }
40 4 : size_t units = w.len / 4;
41 4 : out[0] = (uint8_t)units;
42 4 : memcpy(out + 1, w.data, w.len);
43 4 : *out_len = 1 + w.len;
44 4 : tl_writer_free(&w);
45 4 : }
46 :
47 4 : static void session_setup(MtProtoSession *s) {
48 4 : mtproto_session_init(s);
49 4 : s->session_id = 0; /* match the zero session_id in fake encrypted frames */
50 4 : uint8_t key[256] = {0};
51 4 : mtproto_session_set_auth_key(s, key);
52 4 : mtproto_session_set_salt(s, 0x1122334455667788ULL);
53 4 : }
54 :
55 4 : static void transport_setup(Transport *t) {
56 4 : transport_init(t);
57 4 : t->fd = 42;
58 4 : t->connected = 1;
59 4 : t->dc_id = 1;
60 4 : }
61 :
62 4 : static void cfg_setup(ApiConfig *cfg) {
63 4 : api_config_init(cfg);
64 4 : cfg->api_id = 12345;
65 4 : cfg->api_hash = "deadbeef";
66 4 : }
67 :
68 : /* Build a Vector<User> response with a single user#... entry. */
69 2 : static size_t make_vector_of_one_user(uint8_t *buf, size_t max,
70 : int64_t id,
71 : const char *first, const char *last,
72 : const char *username,
73 : const char *phone) {
74 : TlWriter w;
75 2 : tl_writer_init(&w);
76 2 : tl_write_uint32(&w, TL_vector);
77 2 : tl_write_uint32(&w, 1); /* count */
78 2 : tl_write_uint32(&w, TL_user); /* user#... */
79 2 : uint32_t flags = 0;
80 2 : if (first) flags |= (1u << 1);
81 2 : if (last) flags |= (1u << 2);
82 2 : if (username) flags |= (1u << 3);
83 2 : if (phone) flags |= (1u << 4);
84 2 : tl_write_uint32(&w, flags);
85 2 : tl_write_uint32(&w, 0); /* flags2 — always present in layer 144+ */
86 2 : tl_write_int64(&w, id);
87 2 : if (first) tl_write_string(&w, first);
88 2 : if (last) tl_write_string(&w, last);
89 2 : if (username) tl_write_string(&w, username);
90 2 : if (phone) tl_write_string(&w, phone);
91 :
92 2 : size_t n = w.len < max ? w.len : max;
93 2 : memcpy(buf, w.data, n);
94 2 : tl_writer_free(&w);
95 2 : return n;
96 : }
97 :
98 1 : static void test_self_success(void) {
99 1 : mock_socket_reset();
100 1 : mock_crypto_reset();
101 :
102 : uint8_t payload[256];
103 1 : size_t plen = make_vector_of_one_user(payload, sizeof(payload),
104 : 987654321LL,
105 : "Alice", "Example",
106 : "alice", "+15551234567");
107 :
108 1 : uint8_t resp[1024]; size_t rlen = 0;
109 1 : build_fake_encrypted_response(payload, plen, resp, &rlen);
110 1 : mock_socket_set_response(resp, rlen);
111 :
112 : MtProtoSession s; Transport t; ApiConfig cfg;
113 1 : session_setup(&s); transport_setup(&t); cfg_setup(&cfg);
114 :
115 1 : SelfInfo me = {0};
116 1 : int rc = domain_get_self(&cfg, &s, &t, &me);
117 1 : ASSERT(rc == 0, "get_self: must succeed");
118 1 : ASSERT(me.id == 987654321LL, "id must be parsed");
119 1 : ASSERT(strcmp(me.first_name, "Alice") == 0, "first_name");
120 1 : ASSERT(strcmp(me.last_name, "Example") == 0, "last_name");
121 1 : ASSERT(strcmp(me.username, "alice") == 0, "username");
122 1 : ASSERT(strcmp(me.phone, "+15551234567") == 0, "phone");
123 : }
124 :
125 1 : static void test_self_minimal_user(void) {
126 1 : mock_socket_reset();
127 1 : mock_crypto_reset();
128 :
129 : uint8_t payload[128];
130 1 : size_t plen = make_vector_of_one_user(payload, sizeof(payload),
131 : 42LL, NULL, NULL, NULL, NULL);
132 :
133 1 : uint8_t resp[512]; size_t rlen = 0;
134 1 : build_fake_encrypted_response(payload, plen, resp, &rlen);
135 1 : mock_socket_set_response(resp, rlen);
136 :
137 : MtProtoSession s; Transport t; ApiConfig cfg;
138 1 : session_setup(&s); transport_setup(&t); cfg_setup(&cfg);
139 :
140 1 : SelfInfo me = {0};
141 1 : int rc = domain_get_self(&cfg, &s, &t, &me);
142 1 : ASSERT(rc == 0, "minimal user must succeed");
143 1 : ASSERT(me.id == 42LL, "id parsed");
144 1 : ASSERT(me.first_name[0] == '\0', "empty first_name");
145 1 : ASSERT(me.username[0] == '\0', "empty username");
146 : }
147 :
148 1 : static void test_self_rpc_error(void) {
149 1 : mock_socket_reset();
150 1 : mock_crypto_reset();
151 :
152 : uint8_t payload[128];
153 : TlWriter w;
154 1 : tl_writer_init(&w);
155 1 : tl_write_uint32(&w, TL_rpc_error);
156 1 : tl_write_int32(&w, 401);
157 1 : tl_write_string(&w, "AUTH_KEY_UNREGISTERED");
158 1 : memcpy(payload, w.data, w.len);
159 1 : size_t plen = w.len;
160 1 : tl_writer_free(&w);
161 :
162 1 : uint8_t resp[512]; size_t rlen = 0;
163 1 : build_fake_encrypted_response(payload, plen, resp, &rlen);
164 1 : mock_socket_set_response(resp, rlen);
165 :
166 : MtProtoSession s; Transport t; ApiConfig cfg;
167 1 : session_setup(&s); transport_setup(&t); cfg_setup(&cfg);
168 :
169 1 : SelfInfo me = {0};
170 1 : int rc = domain_get_self(&cfg, &s, &t, &me);
171 1 : ASSERT(rc != 0, "RPC error must propagate");
172 : }
173 :
174 1 : static void test_self_empty_vector(void) {
175 1 : mock_socket_reset();
176 1 : mock_crypto_reset();
177 :
178 : uint8_t payload[32];
179 : TlWriter w;
180 1 : tl_writer_init(&w);
181 1 : tl_write_uint32(&w, TL_vector);
182 1 : tl_write_uint32(&w, 0);
183 1 : memcpy(payload, w.data, w.len);
184 1 : size_t plen = w.len;
185 1 : tl_writer_free(&w);
186 :
187 1 : uint8_t resp[512]; size_t rlen = 0;
188 1 : build_fake_encrypted_response(payload, plen, resp, &rlen);
189 1 : mock_socket_set_response(resp, rlen);
190 :
191 : MtProtoSession s; Transport t; ApiConfig cfg;
192 1 : session_setup(&s); transport_setup(&t); cfg_setup(&cfg);
193 :
194 1 : SelfInfo me = {0};
195 1 : int rc = domain_get_self(&cfg, &s, &t, &me);
196 1 : ASSERT(rc != 0, "empty vector must fail");
197 : }
198 :
199 1 : static void test_self_null_args(void) {
200 : SelfInfo me;
201 1 : ASSERT(domain_get_self(NULL, NULL, NULL, &me) == -1, "null cfg");
202 1 : ASSERT(domain_get_self(NULL, NULL, NULL, NULL) == -1, "null out");
203 : }
204 :
205 1 : void run_domain_self_tests(void) {
206 1 : RUN_TEST(test_self_success);
207 1 : RUN_TEST(test_self_minimal_user);
208 1 : RUN_TEST(test_self_rpc_error);
209 1 : RUN_TEST(test_self_empty_vector);
210 1 : RUN_TEST(test_self_null_args);
211 1 : }
|