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

            Line data    Source code
       1              : /**
       2              :  * @file test_gzip.c
       3              :  * @brief Unit tests for gzip_packed unwrapping (rpc_unwrap_gzip).
       4              :  *
       5              :  * Tests both the gzip decompression path (using real gzip data)
       6              :  * and the pass-through path (non-gzip data copied unchanged).
       7              :  */
       8              : 
       9              : #include "test_helpers.h"
      10              : #include "mtproto_rpc.h"
      11              : #include "tl_serial.h"
      12              : #include "tinf.h"
      13              : 
      14              : #include <string.h>
      15              : #include <stdlib.h>
      16              : 
      17              : /* ---- Pre-compressed gzip test data ----
      18              :  *
      19              :  * Created by compressing "Hello, MTProto!" (15 bytes) with gzip.
      20              :  * Generated via: echo -n "Hello, MTProto!" | gzip | xxd -i
      21              :  */
      22              : static const uint8_t gzip_hello[] = {
      23              :     0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
      24              :     0x00, 0x03, 0xf3, 0x48, 0xcd, 0xc9, 0xc9, 0xd7,
      25              :     0x51, 0xf0, 0x0d, 0x09, 0x28, 0xca, 0x2f, 0xc9,
      26              :     0x57, 0x04, 0x00, 0x59, 0xf5, 0x5d, 0x03, 0x0f,
      27              :     0x00, 0x00, 0x00
      28              : };
      29              : static const size_t gzip_hello_len = sizeof(gzip_hello);
      30              : 
      31              : /* ---- Tests ---- */
      32              : 
      33            1 : void test_unwrap_gzip_passthrough(void) {
      34              :     /* Non-gzip data should be copied unchanged */
      35            1 :     uint8_t data[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 };
      36              :     uint8_t out[256];
      37            1 :     size_t out_len = 0;
      38              : 
      39            1 :     int rc = rpc_unwrap_gzip(data, sizeof(data), out, sizeof(out), &out_len);
      40            1 :     ASSERT(rc == 0, "passthrough should succeed");
      41            1 :     ASSERT(out_len == sizeof(data), "output length should match input");
      42            1 :     ASSERT(memcmp(out, data, sizeof(data)) == 0, "data should be unchanged");
      43              : }
      44              : 
      45            1 : void test_unwrap_gzip_passthrough_constructor(void) {
      46              :     /* Data with a different constructor should pass through */
      47              :     TlWriter w;
      48            1 :     tl_writer_init(&w);
      49            1 :     tl_write_uint32(&w, 0x05162463); /* CRC_resPQ — not gzip_packed */
      50            1 :     tl_write_int32(&w, 42);
      51              : 
      52              :     uint8_t out[256];
      53            1 :     size_t out_len = 0;
      54            1 :     int rc = rpc_unwrap_gzip(w.data, w.len, out, sizeof(out), &out_len);
      55            1 :     ASSERT(rc == 0, "non-gzip constructor should pass through");
      56            1 :     ASSERT(out_len == w.len, "output length should match");
      57            1 :     ASSERT(memcmp(out, w.data, w.len) == 0, "data should be unchanged");
      58            1 :     tl_writer_free(&w);
      59              : }
      60              : 
      61            1 : void test_unwrap_gzip_decompress(void) {
      62              :     /* Build gzip_packed TL: constructor(4) + bytes(gzip_hello) */
      63              :     TlWriter w;
      64            1 :     tl_writer_init(&w);
      65            1 :     tl_write_uint32(&w, 0x3072cfa1); /* CRC_gzip_packed */
      66            1 :     tl_write_bytes(&w, gzip_hello, gzip_hello_len);
      67              : 
      68              :     uint8_t out[1024];
      69            1 :     size_t out_len = 0;
      70            1 :     int rc = rpc_unwrap_gzip(w.data, w.len, out, sizeof(out), &out_len);
      71            1 :     tl_writer_free(&w);
      72              : 
      73            1 :     ASSERT(rc == 0, "gzip decompression should succeed");
      74            1 :     ASSERT(out_len == 15, "decompressed length should be 15");
      75            1 :     ASSERT(memcmp(out, "Hello, MTProto!", 15) == 0,
      76              :            "decompressed data should match original");
      77              : }
      78              : 
      79            1 : void test_unwrap_gzip_null_args(void) {
      80              :     uint8_t buf[16];
      81            1 :     size_t len = 0;
      82            1 :     ASSERT(rpc_unwrap_gzip(NULL, 4, buf, 16, &len) == -1, "NULL data should fail");
      83            1 :     ASSERT(rpc_unwrap_gzip(buf, 4, NULL, 16, &len) == -1, "NULL out should fail");
      84            1 :     ASSERT(rpc_unwrap_gzip(buf, 4, buf, 16, NULL) == -1, "NULL out_len should fail");
      85              : }
      86              : 
      87            1 : void test_unwrap_gzip_short_data(void) {
      88              :     /* Data shorter than 4 bytes — pass through */
      89            1 :     uint8_t data[] = { 0xAA, 0xBB };
      90              :     uint8_t out[16];
      91            1 :     size_t out_len = 0;
      92            1 :     int rc = rpc_unwrap_gzip(data, 2, out, sizeof(out), &out_len);
      93            1 :     ASSERT(rc == 0, "short data should pass through");
      94            1 :     ASSERT(out_len == 2, "output length should be 2");
      95              : }
      96              : 
      97            1 : void test_unwrap_gzip_buffer_too_small(void) {
      98              :     /* Passthrough with too-small buffer */
      99              :     uint8_t data[32];
     100            1 :     memset(data, 0x42, 32);
     101              :     uint8_t out[8];
     102            1 :     size_t out_len = 0;
     103            1 :     int rc = rpc_unwrap_gzip(data, 32, out, 8, &out_len);
     104            1 :     ASSERT(rc == -1, "buffer too small should fail");
     105              : }
     106              : 
     107            1 : void test_unwrap_gzip_corrupt_data(void) {
     108              :     /* gzip_packed with corrupt compressed data */
     109              :     TlWriter w;
     110            1 :     tl_writer_init(&w);
     111            1 :     tl_write_uint32(&w, 0x3072cfa1); /* CRC_gzip_packed */
     112            1 :     uint8_t garbage[] = { 0xFF, 0xFE, 0xFD, 0xFC, 0xFB };
     113            1 :     tl_write_bytes(&w, garbage, sizeof(garbage));
     114              : 
     115              :     uint8_t out[1024];
     116            1 :     size_t out_len = 0;
     117            1 :     int rc = rpc_unwrap_gzip(w.data, w.len, out, sizeof(out), &out_len);
     118            1 :     tl_writer_free(&w);
     119              : 
     120            1 :     ASSERT(rc == -1, "corrupt gzip data should fail");
     121              : }
     122              : 
     123            1 : void test_unwrap_gzip_empty_bytes(void) {
     124              :     /* gzip_packed with empty bytes field */
     125              :     TlWriter w;
     126            1 :     tl_writer_init(&w);
     127            1 :     tl_write_uint32(&w, 0x3072cfa1);
     128            1 :     tl_write_bytes(&w, (uint8_t[]){0}, 0); /* empty bytes */
     129              : 
     130              :     uint8_t out[1024];
     131            1 :     size_t out_len = 0;
     132            1 :     int rc = rpc_unwrap_gzip(w.data, w.len, out, sizeof(out), &out_len);
     133            1 :     tl_writer_free(&w);
     134              : 
     135            1 :     ASSERT(rc == -1, "empty gzip data should fail");
     136              : }
     137              : 
     138            1 : void test_tinf_gzip_direct(void) {
     139              :     /* Verify tinf works directly with known data */
     140              :     uint8_t out[256];
     141            1 :     unsigned int out_len = sizeof(out);
     142            1 :     int rc = tinf_gzip_uncompress(out, &out_len, gzip_hello, (unsigned int)gzip_hello_len);
     143            1 :     ASSERT(rc == TINF_OK, "tinf_gzip_uncompress should succeed");
     144            1 :     ASSERT(out_len == 15, "decompressed length should be 15");
     145            1 :     ASSERT(memcmp(out, "Hello, MTProto!", 15) == 0, "data should match");
     146              : }
     147              : 
     148              : /* ---- Test suite entry point ---- */
     149              : 
     150            1 : void test_gzip(void) {
     151            1 :     RUN_TEST(test_unwrap_gzip_passthrough);
     152            1 :     RUN_TEST(test_unwrap_gzip_passthrough_constructor);
     153            1 :     RUN_TEST(test_unwrap_gzip_decompress);
     154            1 :     RUN_TEST(test_unwrap_gzip_null_args);
     155            1 :     RUN_TEST(test_unwrap_gzip_short_data);
     156            1 :     RUN_TEST(test_unwrap_gzip_buffer_too_small);
     157            1 :     RUN_TEST(test_unwrap_gzip_corrupt_data);
     158            1 :     RUN_TEST(test_unwrap_gzip_empty_bytes);
     159            1 :     RUN_TEST(test_tinf_gzip_direct);
     160            1 : }
        

Generated by: LCOV version 2.0-1