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

            Line data    Source code
       1              : /**
       2              :  * @file test_domain_user_info.c
       3              :  * @brief Unit tests for domain_resolve_username (US-09 v1).
       4              :  */
       5              : 
       6              : #include "test_helpers.h"
       7              : #include "domain/read/user_info.h"
       8              : #include "tl_serial.h"
       9              : #include "tl_registry.h"
      10              : #include "mock_socket.h"
      11              : #include "mock_crypto.h"
      12              : #include "mtproto_session.h"
      13              : #include "transport.h"
      14              : #include "api_call.h"
      15              : 
      16              : #include <stdlib.h>
      17              : #include <string.h>
      18              : 
      19            2 : static void build_fake_encrypted_response(const uint8_t *payload, size_t plen,
      20              :                                           uint8_t *out, size_t *out_len) {
      21            2 :     TlWriter w; tl_writer_init(&w);
      22            2 :     uint8_t zeros24[24] = {0}; tl_write_raw(&w, zeros24, 24);
      23            2 :     uint8_t header[32] = {0};
      24            2 :     uint32_t plen32 = (uint32_t)plen;
      25            2 :     memcpy(header + 28, &plen32, 4);
      26            2 :     tl_write_raw(&w, header, 32);
      27            2 :     tl_write_raw(&w, payload, plen);
      28            2 :     size_t enc = w.len - 24;
      29            2 :     if (enc % 16 != 0) {
      30            2 :         uint8_t pad[16] = {0}; tl_write_raw(&w, pad, 16 - (enc % 16));
      31              :     }
      32            2 :     out[0] = (uint8_t)(w.len / 4);
      33            2 :     memcpy(out + 1, w.data, w.len);
      34            2 :     *out_len = 1 + w.len;
      35            2 :     tl_writer_free(&w);
      36            2 : }
      37              : 
      38            3 : static void fix_session(MtProtoSession *s) {
      39            3 :     mtproto_session_init(s);
      40            3 :     s->session_id = 0; /* match the zero session_id in fake encrypted frames */
      41            3 :     uint8_t k[256] = {0}; mtproto_session_set_auth_key(s, k);
      42            3 :     mtproto_session_set_salt(s, 0xFFEEDDCCBBAA9988ULL);
      43            3 : }
      44            3 : static void fix_transport(Transport *t) {
      45            3 :     transport_init(t); t->fd = 42; t->connected = 1; t->dc_id = 1;
      46            3 : }
      47            3 : static void fix_cfg(ApiConfig *cfg) {
      48            3 :     api_config_init(cfg); cfg->api_id = 12345; cfg->api_hash = "deadbeef";
      49            3 : }
      50              : 
      51              : /* Build a minimal contacts.resolvedPeer response where peer is a channel,
      52              :  * chats contains a single channel with access_hash, and users is empty. */
      53            1 : static size_t make_channel_response(uint8_t *buf, size_t max,
      54              :                                      int64_t channel_id, int64_t hash) {
      55            1 :     TlWriter w; tl_writer_init(&w);
      56            1 :     tl_write_uint32(&w, TL_contacts_resolvedPeer);
      57            1 :     tl_write_uint32(&w, TL_peerChannel);
      58            1 :     tl_write_int64 (&w, channel_id);
      59              : 
      60            1 :     tl_write_uint32(&w, TL_vector);
      61            1 :     tl_write_uint32(&w, 1);
      62            1 :     tl_write_uint32(&w, TL_channel);
      63            1 :     tl_write_uint32(&w, 1u << 13);       /* flags: access_hash present */
      64            1 :     tl_write_uint32(&w, 0);              /* flags2 */
      65            1 :     tl_write_int64 (&w, channel_id);
      66            1 :     tl_write_int64 (&w, hash);
      67              : 
      68            1 :     tl_write_uint32(&w, TL_vector);
      69            1 :     tl_write_uint32(&w, 0);
      70              : 
      71            1 :     size_t n = w.len < max ? w.len : max;
      72            1 :     memcpy(buf, w.data, n);
      73            1 :     tl_writer_free(&w);
      74            1 :     return n;
      75              : }
      76              : 
      77            1 : static void test_resolve_channel(void) {
      78            1 :     mock_socket_reset(); mock_crypto_reset();
      79              : 
      80              :     uint8_t payload[256];
      81            1 :     size_t plen = make_channel_response(payload, sizeof(payload),
      82              :                                           1001234567890LL, 0xABCDEF1234567890LL);
      83            1 :     uint8_t resp[1024]; size_t rlen = 0;
      84            1 :     build_fake_encrypted_response(payload, plen, resp, &rlen);
      85            1 :     mock_socket_set_response(resp, rlen);
      86              : 
      87              :     MtProtoSession s; Transport t; ApiConfig cfg;
      88            1 :     fix_session(&s); fix_transport(&t); fix_cfg(&cfg);
      89              : 
      90            1 :     ResolvedPeer r = {0};
      91            1 :     int rc = domain_resolve_username(&cfg, &s, &t, "@channel_example", &r);
      92            1 :     ASSERT(rc == 0, "resolve: must succeed");
      93            1 :     ASSERT(r.kind == RESOLVED_KIND_CHANNEL, "kind=channel");
      94            1 :     ASSERT(r.id == 1001234567890LL, "id matches");
      95            1 :     ASSERT(r.have_hash == 1, "access_hash present");
      96            1 :     ASSERT(r.access_hash == (int64_t)0xABCDEF1234567890LL, "access_hash value");
      97            1 :     ASSERT(strcmp(r.username, "channel_example") == 0, "username echoed");
      98              : }
      99              : 
     100            1 : static void test_resolve_rpc_error(void) {
     101            1 :     mock_socket_reset(); mock_crypto_reset();
     102              : 
     103            1 :     TlWriter w; tl_writer_init(&w);
     104            1 :     tl_write_uint32(&w, TL_rpc_error);
     105            1 :     tl_write_int32(&w, 400);
     106            1 :     tl_write_string(&w, "USERNAME_INVALID");
     107            1 :     uint8_t payload[64]; memcpy(payload, w.data, w.len);
     108            1 :     size_t plen = w.len; tl_writer_free(&w);
     109              : 
     110            1 :     uint8_t resp[512]; size_t rlen = 0;
     111            1 :     build_fake_encrypted_response(payload, plen, resp, &rlen);
     112            1 :     mock_socket_set_response(resp, rlen);
     113              : 
     114              :     MtProtoSession s; Transport t; ApiConfig cfg;
     115            1 :     fix_session(&s); fix_transport(&t); fix_cfg(&cfg);
     116              : 
     117            1 :     ResolvedPeer r = {0};
     118            1 :     int rc = domain_resolve_username(&cfg, &s, &t, "@bogus", &r);
     119            1 :     ASSERT(rc != 0, "RPC error must propagate");
     120              : }
     121              : 
     122            1 : static void test_resolve_null_args(void) {
     123              :     ResolvedPeer r;
     124            1 :     ASSERT(domain_resolve_username(NULL, NULL, NULL, NULL, &r) == -1, "nulls");
     125            1 :     ApiConfig cfg; fix_cfg(&cfg);
     126            1 :     MtProtoSession s; fix_session(&s);
     127            1 :     Transport t; fix_transport(&t);
     128            1 :     ASSERT(domain_resolve_username(&cfg, &s, &t, NULL, &r) == -1, "null name");
     129              : }
     130              : 
     131            1 : void run_domain_user_info_tests(void) {
     132            1 :     RUN_TEST(test_resolve_channel);
     133            1 :     RUN_TEST(test_resolve_rpc_error);
     134            1 :     RUN_TEST(test_resolve_null_args);
     135            1 : }
        

Generated by: LCOV version 2.0-1