LCOV - code coverage report
Current view: top level - tests/unit - test_domain_self.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 100.0 % 131 131
Test Date: 2026-04-20 19:54:22 Functions: 100.0 % 11 11

            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 : }
        

Generated by: LCOV version 2.0-1