Line data Source code
1 : /**
2 : * @file test_tl_serial.c
3 : * @brief Unit tests for TL binary serialization.
4 : */
5 :
6 : #include "test_helpers.h"
7 : #include "tl_serial.h"
8 :
9 : #include <stdlib.h>
10 : #include <string.h>
11 : #include <math.h>
12 :
13 : /* Forward declarations of individual test functions */
14 : void test_tl_writer_init_free(void);
15 : void test_tl_write_int32(void);
16 : void test_tl_write_int32_negative(void);
17 : void test_tl_write_uint32(void);
18 : void test_tl_write_int64(void);
19 : void test_tl_write_uint64(void);
20 : void test_tl_write_int128(void);
21 : void test_tl_write_int256(void);
22 : void test_tl_write_double(void);
23 : void test_tl_write_bool_true(void);
24 : void test_tl_write_bool_false(void);
25 : void test_tl_write_string_short(void);
26 : void test_tl_write_string_empty(void);
27 : void test_tl_write_string_needs_padding(void);
28 : void test_tl_write_string_aligned(void);
29 : void test_tl_write_bytes_long(void);
30 : void test_tl_write_vector_begin(void);
31 : void test_tl_write_multiple(void);
32 : void test_tl_reader_init(void);
33 : void test_tl_reader_ok(void);
34 : void test_tl_read_int32(void);
35 : void test_tl_read_uint32(void);
36 : void test_tl_read_int64(void);
37 : void test_tl_read_int128(void);
38 : void test_tl_read_int256(void);
39 : void test_tl_read_bool_true(void);
40 : void test_tl_read_bool_false(void);
41 : void test_tl_read_bool_invalid(void);
42 : void test_tl_read_string_short(void);
43 : void test_tl_read_string_empty(void);
44 : void test_tl_read_bytes_with_padding(void);
45 : void test_tl_read_bytes_empty(void);
46 : void test_tl_read_bytes_long_prefix(void);
47 : void test_tl_read_past_end(void);
48 : void test_tl_read_skip(void);
49 : void test_tl_read_raw(void);
50 : void test_tl_roundtrip_int32(void);
51 : void test_tl_roundtrip_uint64(void);
52 : void test_tl_roundtrip_string(void);
53 : void test_tl_roundtrip_int128_int256(void);
54 : void test_tl_roundtrip_double(void);
55 : void test_tl_roundtrip_bool(void);
56 : void test_tl_roundtrip_mixed(void);
57 : void test_tl_string_null(void);
58 : void test_tl_writer_grow(void);
59 : void test_tl_vector_overflow_uint32(void);
60 : void test_tl_vector_overflow_int32(void);
61 : void test_tl_vector_overflow_uint64(void);
62 : void test_tl_vector_overflow_string(void);
63 : void test_tl_vector_overflow_reader_saturates(void);
64 : void test_tl_read_bytes_giant_length_claim(void);
65 : void test_tl_read_bytes_long_prefix_exact(void);
66 : void test_tl_read_bytes_invalid_ff_prefix(void);
67 : void test_tl_string_roundtrip_lengths(void);
68 : void test_tl_int32_roundtrip_boundaries(void);
69 : void test_tl_int64_roundtrip_boundaries(void);
70 : void test_tl_vector_roundtrip_empty_single_many(void);
71 :
72 : /* ================================================================
73 : * Writer tests
74 : * ================================================================ */
75 :
76 1 : void test_tl_writer_init_free(void) {
77 : TlWriter w;
78 1 : tl_writer_init(&w);
79 1 : ASSERT(w.data == NULL, "data should be NULL after init");
80 1 : ASSERT(w.len == 0, "len should be 0 after init");
81 1 : ASSERT(w.cap == 0, "cap should be 0 after init");
82 1 : tl_writer_free(&w);
83 : }
84 :
85 1 : void test_tl_write_int32(void) {
86 : TlWriter w;
87 1 : tl_writer_init(&w);
88 1 : tl_write_int32(&w, 0x01020304);
89 1 : ASSERT(w.len == 4, "should have 4 bytes");
90 : /* Little-endian: 04 03 02 01 */
91 1 : ASSERT(w.data[0] == 0x04, "byte 0 should be 0x04");
92 1 : ASSERT(w.data[1] == 0x03, "byte 1 should be 0x03");
93 1 : ASSERT(w.data[2] == 0x02, "byte 2 should be 0x02");
94 1 : ASSERT(w.data[3] == 0x01, "byte 3 should be 0x01");
95 1 : tl_writer_free(&w);
96 : }
97 :
98 1 : void test_tl_write_int32_negative(void) {
99 : TlWriter w;
100 1 : tl_writer_init(&w);
101 1 : tl_write_int32(&w, -1);
102 1 : ASSERT(w.len == 4, "should have 4 bytes");
103 1 : ASSERT(w.data[0] == 0xFF && w.data[1] == 0xFF
104 : && w.data[2] == 0xFF && w.data[3] == 0xFF,
105 : "-1 should be 0xFFFFFFFF in LE");
106 1 : tl_writer_free(&w);
107 : }
108 :
109 1 : void test_tl_write_uint32(void) {
110 : TlWriter w;
111 1 : tl_writer_init(&w);
112 1 : tl_write_uint32(&w, 0xABCDEF01u);
113 1 : ASSERT(w.len == 4, "should have 4 bytes");
114 1 : ASSERT(w.data[0] == 0x01, "byte 0 LE");
115 1 : ASSERT(w.data[3] == 0xAB, "byte 3 LE");
116 1 : tl_writer_free(&w);
117 : }
118 :
119 1 : void test_tl_write_int64(void) {
120 : TlWriter w;
121 1 : tl_writer_init(&w);
122 1 : tl_write_int64(&w, 0x0102030405060708LL);
123 1 : ASSERT(w.len == 8, "should have 8 bytes");
124 1 : ASSERT(w.data[0] == 0x08, "byte 0 LE");
125 1 : ASSERT(w.data[7] == 0x01, "byte 7 LE");
126 1 : tl_writer_free(&w);
127 : }
128 :
129 1 : void test_tl_write_uint64(void) {
130 : TlWriter w;
131 1 : tl_writer_init(&w);
132 1 : tl_write_uint64(&w, 0xFEDCBA9876543210ULL);
133 1 : ASSERT(w.len == 8, "should have 8 bytes");
134 1 : ASSERT(w.data[0] == 0x10, "byte 0 LE");
135 1 : ASSERT(w.data[7] == 0xFE, "byte 7 LE");
136 1 : tl_writer_free(&w);
137 : }
138 :
139 1 : void test_tl_write_int128(void) {
140 : TlWriter w;
141 1 : tl_writer_init(&w);
142 : unsigned char val[16];
143 17 : for (int i = 0; i < 16; i++) val[i] = (unsigned char)(i + 1);
144 1 : tl_write_int128(&w, val);
145 1 : ASSERT(w.len == 16, "should have 16 bytes");
146 1 : ASSERT(w.data[0] == 1, "first byte should be 1");
147 1 : ASSERT(w.data[15] == 16, "last byte should be 16");
148 1 : tl_writer_free(&w);
149 : }
150 :
151 1 : void test_tl_write_int256(void) {
152 : TlWriter w;
153 1 : tl_writer_init(&w);
154 : unsigned char val[32];
155 33 : for (int i = 0; i < 32; i++) val[i] = (unsigned char)i;
156 1 : tl_write_int256(&w, val);
157 1 : ASSERT(w.len == 32, "should have 32 bytes");
158 1 : ASSERT(w.data[0] == 0, "first byte should be 0");
159 1 : ASSERT(w.data[31] == 31, "last byte should be 31");
160 1 : tl_writer_free(&w);
161 : }
162 :
163 1 : void test_tl_write_double(void) {
164 : TlWriter w;
165 1 : tl_writer_init(&w);
166 1 : tl_write_double(&w, 3.14);
167 1 : ASSERT(w.len == 8, "should have 8 bytes");
168 : /* Verify by reading back */
169 1 : TlReader r = tl_reader_init(w.data, w.len);
170 1 : double val = tl_read_double(&r);
171 1 : ASSERT(fabs(val - 3.14) < 1e-10, "round-trip should preserve value");
172 1 : tl_writer_free(&w);
173 : }
174 :
175 1 : void test_tl_write_bool_true(void) {
176 : TlWriter w;
177 1 : tl_writer_init(&w);
178 1 : tl_write_bool(&w, 1);
179 1 : ASSERT(w.len == 4, "should have 4 bytes");
180 : /* 0x997275b5 in LE */
181 1 : ASSERT(w.data[0] == 0xB5, "bool true magic byte 0");
182 1 : ASSERT(w.data[1] == 0x75, "bool true magic byte 1");
183 1 : ASSERT(w.data[2] == 0x72, "bool true magic byte 2");
184 1 : ASSERT(w.data[3] == 0x99, "bool true magic byte 3");
185 1 : tl_writer_free(&w);
186 : }
187 :
188 1 : void test_tl_write_bool_false(void) {
189 : TlWriter w;
190 1 : tl_writer_init(&w);
191 1 : tl_write_bool(&w, 0);
192 1 : ASSERT(w.len == 4, "should have 4 bytes");
193 : /* 0xbc799737 in LE */
194 1 : ASSERT(w.data[0] == 0x37, "bool false magic byte 0");
195 1 : ASSERT(w.data[1] == 0x97, "bool false magic byte 1");
196 1 : ASSERT(w.data[2] == 0x79, "bool false magic byte 2");
197 1 : ASSERT(w.data[3] == 0xBC, "bool false magic byte 3");
198 1 : tl_writer_free(&w);
199 : }
200 :
201 1 : void test_tl_write_string_short(void) {
202 : TlWriter w;
203 1 : tl_writer_init(&w);
204 1 : tl_write_string(&w, "abc");
205 : /* 1-byte prefix (3) + 3 bytes data + 0 padding (total 4, aligned) = 4 bytes */
206 1 : ASSERT(w.len == 4, "short string should be 4 bytes (1 prefix + 3 data)");
207 1 : ASSERT(w.data[0] == 3, "length prefix should be 3");
208 1 : ASSERT(w.data[1] == 'a', "first char");
209 1 : ASSERT(w.data[2] == 'b', "second char");
210 1 : ASSERT(w.data[3] == 'c', "third char");
211 1 : tl_writer_free(&w);
212 : }
213 :
214 1 : void test_tl_write_string_empty(void) {
215 : TlWriter w;
216 1 : tl_writer_init(&w);
217 1 : tl_write_string(&w, "");
218 : /* 1-byte prefix (0) + 0 data + 3 padding = 4 bytes */
219 1 : ASSERT(w.len == 4, "empty string should be 4 bytes (1 prefix + 3 pad)");
220 1 : ASSERT(w.data[0] == 0, "length prefix should be 0");
221 1 : tl_writer_free(&w);
222 : }
223 :
224 1 : void test_tl_write_string_needs_padding(void) {
225 : TlWriter w;
226 1 : tl_writer_init(&w);
227 1 : tl_write_string(&w, "a");
228 : /* 1-byte prefix (1) + 1 byte data + 2 padding = 4 bytes */
229 1 : ASSERT(w.len == 4, "1-char string should be 4 bytes (1 prefix + 1 data + 2 pad)");
230 1 : ASSERT(w.data[0] == 1, "length prefix should be 1");
231 1 : ASSERT(w.data[1] == 'a', "char data");
232 1 : ASSERT(w.data[2] == 0, "pad byte 1");
233 1 : ASSERT(w.data[3] == 0, "pad byte 2");
234 1 : tl_writer_free(&w);
235 : }
236 :
237 1 : void test_tl_write_string_aligned(void) {
238 : TlWriter w;
239 1 : tl_writer_init(&w);
240 1 : tl_write_string(&w, "abcde");
241 : /* 1-byte prefix (5) + 5 bytes data + 2 padding = 8 bytes */
242 1 : ASSERT(w.len == 8, "5-char string should be 8 bytes");
243 1 : ASSERT(w.data[0] == 5, "length prefix should be 5");
244 1 : tl_writer_free(&w);
245 : }
246 :
247 1 : void test_tl_write_bytes_long(void) {
248 : TlWriter w;
249 1 : tl_writer_init(&w);
250 : /* 256 bytes — needs 4-byte length prefix (>= 254) */
251 : unsigned char data[256];
252 1 : memset(data, 0xAB, sizeof(data));
253 1 : tl_write_bytes(&w, data, 256);
254 : /* 4-byte prefix + 256 data + 0 padding (260 is 4-aligned) = 260 */
255 1 : ASSERT(w.len == 260, "256-byte data should be 260 bytes");
256 1 : ASSERT(w.data[0] == 0xFE, "first byte signals long prefix");
257 1 : ASSERT(w.data[1] == 0x00 && w.data[2] == 0x01 && w.data[3] == 0x00,
258 : "3-byte length should be 256 (LE: 00 01 00)");
259 1 : ASSERT(w.data[4] == 0xAB, "data starts at offset 4");
260 1 : tl_writer_free(&w);
261 : }
262 :
263 1 : void test_tl_write_vector_begin(void) {
264 : TlWriter w;
265 1 : tl_writer_init(&w);
266 1 : tl_write_vector_begin(&w, 3);
267 1 : ASSERT(w.len == 8, "vector header should be 8 bytes (ctor + count)");
268 : /* Constructor 0x1cb5c415 in LE */
269 1 : ASSERT(w.data[0] == 0x15, "vector ctor byte 0");
270 1 : ASSERT(w.data[4] == 3, "count should be 3");
271 1 : tl_writer_free(&w);
272 : }
273 :
274 1 : void test_tl_write_multiple(void) {
275 : TlWriter w;
276 1 : tl_writer_init(&w);
277 1 : tl_write_int32(&w, 1);
278 1 : tl_write_int32(&w, 2);
279 1 : tl_write_int32(&w, 3);
280 1 : ASSERT(w.len == 12, "three int32s should be 12 bytes");
281 1 : tl_writer_free(&w);
282 : }
283 :
284 : /* ================================================================
285 : * Reader tests
286 : * ================================================================ */
287 :
288 1 : void test_tl_reader_init(void) {
289 1 : unsigned char buf[4] = {0};
290 1 : TlReader r = tl_reader_init(buf, 4);
291 1 : ASSERT(r.data == buf, "data should point to buffer");
292 1 : ASSERT(r.len == 4, "len should be 4");
293 1 : ASSERT(r.pos == 0, "pos should be 0");
294 : }
295 :
296 1 : void test_tl_reader_ok(void) {
297 1 : unsigned char buf[4] = {1, 2, 3, 4};
298 1 : TlReader r = tl_reader_init(buf, 4);
299 1 : ASSERT(tl_reader_ok(&r), "should be ok at start");
300 1 : r.pos = 4;
301 1 : ASSERT(!tl_reader_ok(&r), "should not be ok at end");
302 : }
303 :
304 1 : void test_tl_read_int32(void) {
305 1 : unsigned char buf[4] = {0x04, 0x03, 0x02, 0x01};
306 1 : TlReader r = tl_reader_init(buf, 4);
307 1 : int32_t val = tl_read_int32(&r);
308 1 : ASSERT(val == 0x01020304, "should read LE int32");
309 1 : ASSERT(r.pos == 4, "pos should advance by 4");
310 : }
311 :
312 1 : void test_tl_read_uint32(void) {
313 1 : unsigned char buf[4] = {0x01, 0xEF, 0xCD, 0xAB};
314 1 : TlReader r = tl_reader_init(buf, 4);
315 1 : uint32_t val = tl_read_uint32(&r);
316 1 : ASSERT(val == 0xABCDEF01u, "should read LE uint32");
317 : }
318 :
319 1 : void test_tl_read_int64(void) {
320 1 : unsigned char buf[8] = {0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01};
321 1 : TlReader r = tl_reader_init(buf, 8);
322 1 : int64_t val = tl_read_int64(&r);
323 1 : ASSERT(val == 0x0102030405060708LL, "should read LE int64");
324 : }
325 :
326 1 : void test_tl_read_int128(void) {
327 : unsigned char buf[16];
328 17 : for (int i = 0; i < 16; i++) buf[i] = (unsigned char)(i + 10);
329 1 : TlReader r = tl_reader_init(buf, 16);
330 1 : unsigned char out[16] = {0};
331 1 : tl_read_int128(&r, out);
332 1 : ASSERT(memcmp(out, buf, 16) == 0, "should read 16 raw bytes");
333 1 : ASSERT(r.pos == 16, "pos should advance by 16");
334 : }
335 :
336 1 : void test_tl_read_int256(void) {
337 : unsigned char buf[32];
338 33 : for (int i = 0; i < 32; i++) buf[i] = (unsigned char)(i + 5);
339 1 : TlReader r = tl_reader_init(buf, 32);
340 1 : unsigned char out[32] = {0};
341 1 : tl_read_int256(&r, out);
342 1 : ASSERT(memcmp(out, buf, 32) == 0, "should read 32 raw bytes");
343 : }
344 :
345 1 : void test_tl_read_bool_true(void) {
346 1 : unsigned char buf[4] = {0xB5, 0x75, 0x72, 0x99};
347 1 : TlReader r = tl_reader_init(buf, 4);
348 1 : ASSERT(tl_read_bool(&r) == 1, "should read bool true");
349 : }
350 :
351 1 : void test_tl_read_bool_false(void) {
352 1 : unsigned char buf[4] = {0x37, 0x97, 0x79, 0xBC};
353 1 : TlReader r = tl_reader_init(buf, 4);
354 1 : ASSERT(tl_read_bool(&r) == 0, "should read bool false");
355 : }
356 :
357 1 : void test_tl_read_bool_invalid(void) {
358 1 : unsigned char buf[4] = {0x00, 0x00, 0x00, 0x00};
359 1 : TlReader r = tl_reader_init(buf, 4);
360 1 : ASSERT(tl_read_bool(&r) == -1, "should return -1 for invalid bool magic");
361 : }
362 :
363 1 : void test_tl_read_string_short(void) {
364 : /* 1-byte prefix (3) + "abc" */
365 1 : unsigned char buf[] = {3, 'a', 'b', 'c'};
366 1 : TlReader r = tl_reader_init(buf, sizeof(buf));
367 1 : char *s = tl_read_string(&r);
368 1 : ASSERT(s != NULL, "string should not be NULL");
369 1 : ASSERT(strcmp(s, "abc") == 0, "should read 'abc'");
370 1 : ASSERT(r.pos == 4, "pos should advance past padded area");
371 1 : free(s);
372 : }
373 :
374 1 : void test_tl_read_string_empty(void) {
375 : /* 1-byte prefix (0) + 3 padding */
376 1 : unsigned char buf[] = {0, 0, 0, 0};
377 1 : TlReader r = tl_reader_init(buf, sizeof(buf));
378 1 : char *s = tl_read_string(&r);
379 1 : ASSERT(s != NULL, "empty string should not be NULL");
380 1 : ASSERT(s[0] == '\0', "empty string should be empty");
381 1 : ASSERT(r.pos == 4, "pos should advance past padding");
382 1 : free(s);
383 : }
384 :
385 1 : void test_tl_read_bytes_with_padding(void) {
386 : /* 1-byte prefix (5) + "abcde" + 2 pad bytes */
387 1 : unsigned char buf[] = {5, 'a', 'b', 'c', 'd', 'e', 0, 0};
388 1 : TlReader r = tl_reader_init(buf, sizeof(buf));
389 1 : size_t len = 0;
390 1 : unsigned char *b = tl_read_bytes(&r, &len);
391 1 : ASSERT(b != NULL, "bytes should not be NULL");
392 1 : ASSERT(len == 5, "length should be 5");
393 1 : ASSERT(memcmp(b, "abcde", 5) == 0, "content should be 'abcde'");
394 1 : ASSERT(r.pos == 8, "pos should advance past padding");
395 1 : free(b);
396 : }
397 :
398 1 : void test_tl_read_bytes_empty(void) {
399 : /* Zero-length bytes: 1-byte prefix (0) + 3 pad bytes.
400 : * Regression: QA-21 — tl_read_bytes must return a non-NULL pointer for
401 : * empty payloads even on platforms where malloc(0) returns NULL. */
402 : TlWriter w;
403 1 : tl_writer_init(&w);
404 1 : tl_write_bytes(&w, NULL, 0);
405 1 : ASSERT(w.len == 4, "empty bytes should serialize to 4 bytes");
406 :
407 1 : TlReader r = tl_reader_init(w.data, w.len);
408 1 : size_t len = 42;
409 1 : unsigned char *b = tl_read_bytes(&r, &len);
410 1 : ASSERT(b != NULL, "empty bytes should return non-NULL pointer");
411 1 : ASSERT(len == 0, "length should be 0");
412 1 : ASSERT(r.pos == 4, "pos should advance past padding");
413 1 : free(b);
414 1 : tl_writer_free(&w);
415 : }
416 :
417 1 : void test_tl_read_bytes_long_prefix(void) {
418 : /* 4-byte prefix: 0xFE, 0x00, 0x01, 0x00 = 256 bytes */
419 1 : size_t total = 4 + 256;
420 1 : unsigned char *buf = (unsigned char *)calloc(1, total);
421 1 : buf[0] = 0xFE;
422 1 : buf[1] = 0x00;
423 1 : buf[2] = 0x01;
424 1 : buf[3] = 0x00;
425 1 : memset(buf + 4, 'X', 256);
426 :
427 1 : TlReader r = tl_reader_init(buf, total);
428 1 : size_t len = 0;
429 1 : unsigned char *b = tl_read_bytes(&r, &len);
430 1 : ASSERT(b != NULL, "long bytes should not be NULL");
431 1 : ASSERT(len == 256, "length should be 256");
432 1 : ASSERT(b[0] == 'X' && b[255] == 'X', "content should be all X");
433 1 : ASSERT(r.pos == total, "pos should advance to end");
434 1 : free(b);
435 1 : free(buf);
436 : }
437 :
438 1 : void test_tl_read_past_end(void) {
439 1 : unsigned char buf[2] = {1, 2};
440 1 : TlReader r = tl_reader_init(buf, 2);
441 1 : int32_t val = tl_read_int32(&r);
442 1 : ASSERT(val == 0, "reading past end should return 0");
443 1 : ASSERT(r.pos == r.len, "pos should be at end");
444 1 : ASSERT(!tl_reader_ok(&r), "reader should not be ok");
445 : }
446 :
447 1 : void test_tl_read_skip(void) {
448 1 : unsigned char buf[8] = {0};
449 1 : TlReader r = tl_reader_init(buf, 8);
450 1 : tl_read_skip(&r, 5);
451 1 : ASSERT(r.pos == 5, "pos should advance by 5");
452 1 : tl_read_skip(&r, 10);
453 1 : ASSERT(r.pos == 8, "pos should clamp to len");
454 : }
455 :
456 1 : void test_tl_read_raw(void) {
457 1 : unsigned char buf[4] = {0xAA, 0xBB, 0xCC, 0xDD};
458 1 : TlReader r = tl_reader_init(buf, 4);
459 1 : unsigned char out[4] = {0};
460 1 : tl_read_raw(&r, out, 4);
461 1 : ASSERT(memcmp(out, buf, 4) == 0, "raw read should copy bytes exactly");
462 : }
463 :
464 : /* ================================================================
465 : * Round-trip tests
466 : * ================================================================ */
467 :
468 1 : void test_tl_roundtrip_int32(void) {
469 : TlWriter w;
470 1 : tl_writer_init(&w);
471 1 : int32_t values[] = {0, 1, -1, 0x7FFFFFFF, (int32_t)0x80000000};
472 6 : for (int i = 0; i < 5; i++) tl_write_int32(&w, values[i]);
473 :
474 1 : TlReader r = tl_reader_init(w.data, w.len);
475 6 : for (int i = 0; i < 5; i++) {
476 5 : ASSERT(tl_read_int32(&r) == values[i], "round-trip int32 mismatch");
477 : }
478 1 : ASSERT(!tl_reader_ok(&r), "reader should be at end");
479 1 : tl_writer_free(&w);
480 : }
481 :
482 1 : void test_tl_roundtrip_uint64(void) {
483 : TlWriter w;
484 1 : tl_writer_init(&w);
485 1 : tl_write_uint64(&w, 0);
486 1 : tl_write_uint64(&w, 0xFFFFFFFFFFFFFFFFULL);
487 :
488 1 : TlReader r = tl_reader_init(w.data, w.len);
489 1 : ASSERT(tl_read_uint64(&r) == 0, "round-trip uint64 zero");
490 1 : ASSERT(tl_read_uint64(&r) == 0xFFFFFFFFFFFFFFFFULL, "round-trip uint64 max");
491 1 : tl_writer_free(&w);
492 : }
493 :
494 1 : void test_tl_roundtrip_string(void) {
495 : TlWriter w;
496 1 : tl_writer_init(&w);
497 1 : tl_write_string(&w, "");
498 1 : tl_write_string(&w, "hello");
499 1 : tl_write_string(&w, "a longer string for testing purposes");
500 :
501 1 : TlReader r = tl_reader_init(w.data, w.len);
502 : char *s;
503 :
504 1 : s = tl_read_string(&r);
505 1 : ASSERT(s != NULL && strcmp(s, "") == 0, "round-trip empty string");
506 1 : free(s);
507 :
508 1 : s = tl_read_string(&r);
509 1 : ASSERT(s != NULL && strcmp(s, "hello") == 0, "round-trip 'hello'");
510 1 : free(s);
511 :
512 1 : s = tl_read_string(&r);
513 1 : ASSERT(s != NULL && strcmp(s, "a longer string for testing purposes") == 0,
514 : "round-trip longer string");
515 1 : free(s);
516 :
517 1 : ASSERT(!tl_reader_ok(&r), "reader should be at end");
518 1 : tl_writer_free(&w);
519 : }
520 :
521 1 : void test_tl_roundtrip_int128_int256(void) {
522 : TlWriter w;
523 1 : tl_writer_init(&w);
524 : unsigned char v128[16], v256[32];
525 17 : for (int i = 0; i < 16; i++) v128[i] = (unsigned char)(i * 17);
526 33 : for (int i = 0; i < 32; i++) v256[i] = (unsigned char)(i * 13);
527 :
528 1 : tl_write_int128(&w, v128);
529 1 : tl_write_int256(&w, v256);
530 :
531 1 : TlReader r = tl_reader_init(w.data, w.len);
532 : unsigned char o128[16], o256[32];
533 1 : tl_read_int128(&r, o128);
534 1 : tl_read_int256(&r, o256);
535 1 : ASSERT(memcmp(o128, v128, 16) == 0, "round-trip int128");
536 1 : ASSERT(memcmp(o256, v256, 32) == 0, "round-trip int256");
537 1 : tl_writer_free(&w);
538 : }
539 :
540 1 : void test_tl_roundtrip_double(void) {
541 : TlWriter w;
542 1 : tl_writer_init(&w);
543 1 : tl_write_double(&w, 0.0);
544 1 : tl_write_double(&w, -1.5);
545 1 : tl_write_double(&w, 1e20);
546 :
547 1 : TlReader r = tl_reader_init(w.data, w.len);
548 1 : ASSERT(tl_read_double(&r) == 0.0, "round-trip double 0.0");
549 1 : ASSERT(tl_read_double(&r) == -1.5, "round-trip double -1.5");
550 1 : ASSERT(fabs(tl_read_double(&r) - 1e20) < 1e10, "round-trip double 1e20");
551 1 : tl_writer_free(&w);
552 : }
553 :
554 1 : void test_tl_roundtrip_bool(void) {
555 : TlWriter w;
556 1 : tl_writer_init(&w);
557 1 : tl_write_bool(&w, 0);
558 1 : tl_write_bool(&w, 1);
559 1 : tl_write_bool(&w, 42); /* non-zero = true */
560 :
561 1 : TlReader r = tl_reader_init(w.data, w.len);
562 1 : ASSERT(tl_read_bool(&r) == 0, "round-trip bool false");
563 1 : ASSERT(tl_read_bool(&r) == 1, "round-trip bool true");
564 1 : ASSERT(tl_read_bool(&r) == 1, "round-trip bool 42→true");
565 1 : tl_writer_free(&w);
566 : }
567 :
568 1 : void test_tl_roundtrip_mixed(void) {
569 : TlWriter w;
570 1 : tl_writer_init(&w);
571 1 : tl_write_int32(&w, 0x12345678);
572 1 : tl_write_string(&w, "test");
573 1 : tl_write_bool(&w, 1);
574 1 : tl_write_uint64(&w, 999);
575 :
576 1 : TlReader r = tl_reader_init(w.data, w.len);
577 1 : ASSERT(tl_read_int32(&r) == 0x12345678, "mixed: int32");
578 1 : char *s = tl_read_string(&r);
579 1 : ASSERT(s != NULL && strcmp(s, "test") == 0, "mixed: string");
580 1 : free(s);
581 1 : ASSERT(tl_read_bool(&r) == 1, "mixed: bool");
582 1 : ASSERT(tl_read_uint64(&r) == 999, "mixed: uint64");
583 1 : ASSERT(!tl_reader_ok(&r), "mixed: reader at end");
584 1 : tl_writer_free(&w);
585 : }
586 :
587 1 : void test_tl_string_null(void) {
588 : TlWriter w;
589 1 : tl_writer_init(&w);
590 1 : tl_write_string(&w, NULL);
591 : /* Should behave like empty string */
592 1 : ASSERT(w.len == 4, "NULL string should be treated as empty (4 bytes)");
593 1 : ASSERT(w.data[0] == 0, "length prefix should be 0");
594 1 : tl_writer_free(&w);
595 : }
596 :
597 1 : void test_tl_writer_grow(void) {
598 : TlWriter w;
599 1 : tl_writer_init(&w);
600 : /* Write 1000 int32s — forces multiple reallocations */
601 1001 : for (int i = 0; i < 1000; i++) {
602 1000 : tl_write_int32(&w, i);
603 : }
604 1 : ASSERT(w.len == 4000, "1000 int32s should be 4000 bytes");
605 1 : TlReader r = tl_reader_init(w.data, w.len);
606 1001 : for (int i = 0; i < 1000; i++) {
607 1000 : ASSERT(tl_read_int32(&r) == i, "large round-trip mismatch");
608 : }
609 1 : tl_writer_free(&w);
610 : }
611 :
612 : /* ================================================================
613 : * Vector overflow / fuzz-style tests (TEST-30)
614 : *
615 : * Each test builds a TL vector header with count=0x7FFFFFFF followed by
616 : * only a few bytes of actual element data. The saturating TlReader must
617 : * bound all reads to the buffer: no OOB access, no infinite spin.
618 : * ================================================================ */
619 :
620 : /**
621 : * @brief Helper: build a buffer whose first 8 bytes are a TL vector header
622 : * (constructor 0x1cb5c415 + count) followed by @p extra bytes of payload.
623 : */
624 4 : static void build_vector_buf(unsigned char *buf, size_t buf_len,
625 : uint32_t count, const unsigned char *extra,
626 : size_t extra_len)
627 : {
628 : /* vector constructor LE */
629 4 : buf[0] = 0x15; buf[1] = 0xc4; buf[2] = 0xb5; buf[3] = 0x1c;
630 : /* count LE */
631 4 : buf[4] = (unsigned char)(count);
632 4 : buf[5] = (unsigned char)(count >> 8);
633 4 : buf[6] = (unsigned char)(count >> 16);
634 4 : buf[7] = (unsigned char)(count >> 24);
635 20 : for (size_t i = 0; i < extra_len && (8 + i) < buf_len; i++)
636 16 : buf[8 + i] = extra[i];
637 4 : }
638 :
639 : /**
640 : * @brief Vector with count=0x7FFFFFFF, only 4 bytes of uint32 payload.
641 : * Reading all claimed elements via tl_read_uint32 must not crash and
642 : * the reader must saturate after the real data runs out.
643 : */
644 1 : void test_tl_vector_overflow_uint32(void) {
645 : /* vector header (8) + one real uint32 element (4) = 12 bytes total */
646 : unsigned char buf[12];
647 1 : unsigned char elem[4] = {0xAA, 0xBB, 0xCC, 0xDD};
648 1 : build_vector_buf(buf, sizeof(buf), 0x7FFFFFFFu, elem, 4);
649 :
650 1 : TlReader r = tl_reader_init(buf, sizeof(buf));
651 : /* consume vector header */
652 1 : uint32_t ctor = tl_read_uint32(&r);
653 1 : uint32_t count = tl_read_uint32(&r);
654 1 : ASSERT(ctor == 0x1cb5c415u, "vector ctor magic");
655 1 : ASSERT(count == 0x7FFFFFFFu, "count should be 0x7FFFFFFF");
656 :
657 : /* iterate — reader saturates after the first real element */
658 1 : uint32_t last_val = 0;
659 1 : for (uint32_t i = 0; i < count; i++) {
660 1 : last_val = tl_read_uint32(&r);
661 1 : if (!tl_reader_ok(&r)) break; /* natural termination */
662 : }
663 : /* The first element read the real bytes; subsequent reads returned 0 */
664 : (void)last_val;
665 1 : ASSERT(r.pos == r.len, "reader must be saturated at end of buffer");
666 : }
667 :
668 : /**
669 : * @brief Same but elements are int32 — loop terminates, no OOB.
670 : */
671 1 : void test_tl_vector_overflow_int32(void) {
672 : unsigned char buf[12];
673 1 : unsigned char elem[4] = {0x01, 0x02, 0x03, 0x04};
674 1 : build_vector_buf(buf, sizeof(buf), 0x7FFFFFFFu, elem, 4);
675 :
676 1 : TlReader r = tl_reader_init(buf, sizeof(buf));
677 1 : tl_read_uint32(&r); /* ctor */
678 1 : uint32_t count = tl_read_uint32(&r);
679 1 : ASSERT(count == 0x7FFFFFFFu, "count should be 0x7FFFFFFF");
680 :
681 1 : for (uint32_t i = 0; i < count; i++) {
682 1 : tl_read_int32(&r);
683 1 : if (!tl_reader_ok(&r)) break;
684 : }
685 1 : ASSERT(r.pos == r.len, "reader saturated after overflow int32 loop");
686 : }
687 :
688 : /**
689 : * @brief Vector whose claimed elements are uint64 (8 bytes each).
690 : * Only 8 bytes of real payload follow the header — reader saturates after one.
691 : */
692 1 : void test_tl_vector_overflow_uint64(void) {
693 : unsigned char buf[16]; /* header(8) + one uint64(8) */
694 1 : unsigned char elem[8] = {1, 2, 3, 4, 5, 6, 7, 8};
695 1 : build_vector_buf(buf, sizeof(buf), 0x7FFFFFFFu, elem, 8);
696 :
697 1 : TlReader r = tl_reader_init(buf, sizeof(buf));
698 1 : tl_read_uint32(&r); /* ctor */
699 1 : uint32_t count = tl_read_uint32(&r);
700 1 : ASSERT(count == 0x7FFFFFFFu, "count should be 0x7FFFFFFF");
701 :
702 1 : for (uint32_t i = 0; i < count; i++) {
703 1 : tl_read_uint64(&r);
704 1 : if (!tl_reader_ok(&r)) break;
705 : }
706 1 : ASSERT(r.pos == r.len, "reader saturated after overflow uint64 loop");
707 : }
708 :
709 : /**
710 : * @brief Vector whose elements are TL strings — only 4 bytes follow the header.
711 : * tl_read_string / tl_read_bytes must return NULL once the buffer is exhausted.
712 : */
713 1 : void test_tl_vector_overflow_string(void) {
714 : /* header(8) + short string "hi" padded to 4 bytes = 12 bytes */
715 1 : unsigned char buf[12] = {
716 : 0x15, 0xc4, 0xb5, 0x1c, /* vector ctor */
717 : 0xFF, 0xFF, 0xFF, 0x7F, /* count = 0x7FFFFFFF LE */
718 : 0x02, 'h', 'i', 0x00 /* TL string: len=2, "hi", 1 pad byte */
719 : };
720 :
721 1 : TlReader r = tl_reader_init(buf, sizeof(buf));
722 1 : tl_read_uint32(&r); /* ctor */
723 1 : uint32_t count = tl_read_uint32(&r);
724 1 : ASSERT(count == 0x7FFFFFFFu, "count should be 0x7FFFFFFF");
725 :
726 1 : int null_seen = 0;
727 1 : for (uint32_t i = 0; i < count; i++) {
728 1 : char *s = tl_read_string(&r);
729 1 : if (s == NULL) { null_seen = 1; break; }
730 1 : free(s);
731 1 : if (!tl_reader_ok(&r)) { null_seen = 1; break; }
732 : }
733 1 : ASSERT(null_seen, "tl_read_string must return NULL when buffer exhausted");
734 1 : ASSERT(r.pos == r.len, "reader saturated after overflow string loop");
735 : }
736 :
737 : /**
738 : * @brief Minimal buffer: only the vector header, no element data.
739 : * The very first element read on a saturated reader must return 0 / NULL,
740 : * and pos must stay clamped to len throughout.
741 : */
742 1 : void test_tl_vector_overflow_reader_saturates(void) {
743 : /* Only 8 bytes: the vector header, no element data at all */
744 : unsigned char buf[8];
745 1 : build_vector_buf(buf, sizeof(buf), 0x7FFFFFFFu, NULL, 0);
746 :
747 1 : TlReader r = tl_reader_init(buf, sizeof(buf));
748 1 : tl_read_uint32(&r); /* ctor */
749 1 : uint32_t count = tl_read_uint32(&r);
750 1 : ASSERT(count == 0x7FFFFFFFu, "count should be 0x7FFFFFFF");
751 1 : ASSERT(r.pos == r.len, "reader exhausted after consuming header");
752 :
753 : /* Subsequent reads on exhausted reader must be safe */
754 1 : uint32_t v = tl_read_uint32(&r);
755 1 : ASSERT(v == 0, "read on exhausted reader returns 0");
756 1 : ASSERT(r.pos == r.len, "pos stays clamped at len");
757 :
758 1 : int64_t v64 = tl_read_int64(&r);
759 1 : ASSERT(v64 == 0, "int64 read on exhausted reader returns 0");
760 1 : ASSERT(r.pos == r.len, "pos still clamped");
761 : }
762 :
763 : /* ================================================================
764 : * TEST-36: tl_read_bytes giant / invalid length prefix tests
765 : * ================================================================ */
766 :
767 : /**
768 : * @brief 4-byte buffer [0xFE, 0xFF, 0xFF, 0xFF] claims 16 MB of data.
769 : * The reader_has() guard must reject this without allocating 16 MB and
770 : * return NULL cleanly.
771 : */
772 1 : void test_tl_read_bytes_giant_length_claim(void) {
773 1 : unsigned char buf[4] = {0xFE, 0xFF, 0xFF, 0xFF};
774 1 : TlReader r = tl_reader_init(buf, sizeof(buf));
775 1 : size_t len = 0;
776 1 : unsigned char *b = tl_read_bytes(&r, &len);
777 1 : ASSERT(b == NULL, "giant length claim must return NULL");
778 1 : ASSERT(len == 0, "out_len must remain 0 on failure");
779 1 : ASSERT(r.pos == r.len, "reader must be saturated after failure");
780 : }
781 :
782 : /**
783 : * @brief Exact maximum valid long-form case: 4-byte header [0xFE, 0x00, 0x01, 0x00]
784 : * followed by exactly 256 real bytes (260 total, already 4-aligned).
785 : * Asserts correct length and content are returned.
786 : */
787 1 : void test_tl_read_bytes_long_prefix_exact(void) {
788 1 : size_t total = 4 + 256; /* header + data, already 4-aligned: 260 */
789 1 : unsigned char *buf = (unsigned char *)calloc(1, total);
790 1 : buf[0] = 0xFE;
791 1 : buf[1] = 0x00; /* length LE: 0x000100 = 256 */
792 1 : buf[2] = 0x01;
793 1 : buf[3] = 0x00;
794 257 : for (size_t i = 0; i < 256; i++) buf[4 + i] = (unsigned char)(i & 0xFF);
795 :
796 1 : TlReader r = tl_reader_init(buf, total);
797 1 : size_t len = 0;
798 1 : unsigned char *b = tl_read_bytes(&r, &len);
799 1 : ASSERT(b != NULL, "exact 256-byte long prefix must succeed");
800 1 : ASSERT(len == 256, "length must be 256");
801 1 : int ok = 1;
802 257 : for (size_t i = 0; i < 256; i++) {
803 256 : if (b[i] != (unsigned char)(i & 0xFF)) { ok = 0; break; }
804 : }
805 1 : ASSERT(ok, "content must match the input bytes");
806 1 : ASSERT(r.pos == (size_t)total, "pos must advance to end of buffer");
807 1 : free(b);
808 1 : free(buf);
809 : }
810 :
811 : /**
812 : * @brief First byte 0xFF is an invalid TL bytes prefix (reserved/undefined).
813 : * The reader should treat it as a long-form prefix (>= 254) and then fail
814 : * cleanly because the claimed length will exceed the tiny buffer.
815 : */
816 1 : void test_tl_read_bytes_invalid_ff_prefix(void) {
817 : /* 0xFF as first byte: the code treats first >= 254 as long form,
818 : * reads 3-byte LE length from bytes 1-3. With a 4-byte buffer that
819 : * is all 0xFF, the claimed length is 0xFFFFFF = 16777215 bytes which
820 : * far exceeds the 4-byte buffer. reader_has() must reject it. */
821 1 : unsigned char buf[4] = {0xFF, 0xFF, 0xFF, 0xFF};
822 1 : TlReader r = tl_reader_init(buf, sizeof(buf));
823 1 : size_t len = 0;
824 1 : unsigned char *b = tl_read_bytes(&r, &len);
825 1 : ASSERT(b == NULL, "0xFF prefix with insufficient buffer must return NULL");
826 1 : ASSERT(len == 0, "out_len must remain 0 on 0xFF prefix failure");
827 1 : ASSERT(r.pos == r.len, "reader must be saturated after 0xFF prefix failure");
828 : }
829 :
830 : /* ================================================================
831 : * TEST-42: Property-style roundtrip tests covering boundary lengths/values
832 : * ================================================================ */
833 :
834 : /**
835 : * @brief Roundtrip tl_write_bytes / tl_read_bytes for boundary string lengths.
836 : *
837 : * Lengths tested: 0, 1, 253, 254, 1000, 100000 (proxy for 16 777 215).
838 : * Each buffer is filled with a repeating pattern; after a write+read the
839 : * content must match exactly.
840 : */
841 1 : void test_tl_string_roundtrip_lengths(void) {
842 : /* Boundary lengths per the TL spec: <254 uses 1-byte prefix,
843 : * >=254 uses 4-byte prefix. Also include a mid-range (1000) and a
844 : * cap of 100 000 bytes (instead of 16 777 215) to keep the test fast. */
845 1 : const size_t lengths[] = {0, 1, 253, 254, 1000, 100000};
846 1 : const int n = (int)(sizeof(lengths) / sizeof(lengths[0]));
847 :
848 7 : for (int li = 0; li < n; li++) {
849 6 : size_t slen = lengths[li];
850 :
851 : /* Build source data: repeating byte pattern 0x00..0xFF */
852 6 : unsigned char *src = NULL;
853 6 : if (slen > 0) {
854 5 : src = (unsigned char *)malloc(slen);
855 101513 : for (size_t i = 0; i < slen; i++)
856 101508 : src[i] = (unsigned char)(i & 0xFF);
857 : }
858 :
859 : TlWriter w;
860 6 : tl_writer_init(&w);
861 6 : tl_write_bytes(&w, src, slen);
862 6 : ASSERT(w.len > 0, "writer must produce bytes for any length");
863 :
864 6 : TlReader r = tl_reader_init(w.data, w.len);
865 6 : size_t out_len = 0;
866 6 : unsigned char *out = tl_read_bytes(&r, &out_len);
867 :
868 6 : ASSERT(out != NULL, "tl_read_bytes must return non-NULL");
869 6 : ASSERT(out_len == slen, "read length must equal written length");
870 6 : if (slen > 0) {
871 5 : ASSERT(memcmp(out, src, slen) == 0, "roundtrip content must match");
872 : }
873 6 : ASSERT(r.pos == w.len, "reader must consume exactly the serialized bytes");
874 :
875 6 : free(out);
876 6 : free(src);
877 6 : tl_writer_free(&w);
878 : }
879 : }
880 :
881 : /**
882 : * @brief Roundtrip int32 across boundary values:
883 : * INT32_MIN, -1, 0, 1, INT32_MAX, and UINT32_MAX reinterpreted as int32.
884 : */
885 1 : void test_tl_int32_roundtrip_boundaries(void) {
886 1 : int32_t values[] = {
887 : (int32_t)0x80000000, /* INT32_MIN */
888 : -1,
889 : 0,
890 : 1,
891 : 0x7FFFFFFF, /* INT32_MAX */
892 : (int32_t)0xFFFFFFFF /* -1 == UINT32_MAX cast to int32 */
893 : };
894 1 : const int n = (int)(sizeof(values) / sizeof(values[0]));
895 :
896 : TlWriter w;
897 1 : tl_writer_init(&w);
898 7 : for (int i = 0; i < n; i++)
899 6 : tl_write_int32(&w, values[i]);
900 :
901 1 : TlReader r = tl_reader_init(w.data, w.len);
902 7 : for (int i = 0; i < n; i++) {
903 6 : int32_t got = tl_read_int32(&r);
904 6 : ASSERT(got == values[i], "int32 boundary roundtrip mismatch");
905 : }
906 1 : ASSERT(!tl_reader_ok(&r), "reader must be at end after all int32 reads");
907 1 : tl_writer_free(&w);
908 : }
909 :
910 : /**
911 : * @brief Roundtrip int64 across boundary values:
912 : * INT64_MIN, -1, 0, 1, INT64_MAX.
913 : */
914 1 : void test_tl_int64_roundtrip_boundaries(void) {
915 1 : int64_t values[] = {
916 : (int64_t)0x8000000000000000LL, /* INT64_MIN */
917 : -1LL,
918 : 0LL,
919 : 1LL,
920 : 0x7FFFFFFFFFFFFFFFLL /* INT64_MAX */
921 : };
922 1 : const int n = (int)(sizeof(values) / sizeof(values[0]));
923 :
924 : TlWriter w;
925 1 : tl_writer_init(&w);
926 6 : for (int i = 0; i < n; i++)
927 5 : tl_write_int64(&w, values[i]);
928 :
929 1 : TlReader r = tl_reader_init(w.data, w.len);
930 6 : for (int i = 0; i < n; i++) {
931 5 : int64_t got = tl_read_int64(&r);
932 5 : ASSERT(got == values[i], "int64 boundary roundtrip mismatch");
933 : }
934 1 : ASSERT(!tl_reader_ok(&r), "reader must be at end after all int64 reads");
935 1 : tl_writer_free(&w);
936 : }
937 :
938 : /**
939 : * @brief Roundtrip TL vectors: empty (0 elements), single element, and many
940 : * elements (100). Each vector is serialised via tl_write_vector_begin +
941 : * individual tl_write_int32 calls and then read back via tl_read_uint32 for
942 : * the header and tl_read_int32 for the elements.
943 : */
944 1 : void test_tl_vector_roundtrip_empty_single_many(void) {
945 : /* --- empty vector --- */
946 : {
947 : TlWriter w;
948 1 : tl_writer_init(&w);
949 1 : tl_write_vector_begin(&w, 0);
950 :
951 1 : TlReader r = tl_reader_init(w.data, w.len);
952 1 : uint32_t ctor = tl_read_uint32(&r);
953 1 : uint32_t count = tl_read_uint32(&r);
954 1 : ASSERT(ctor == 0x1cb5c415u, "vector ctor magic (empty)");
955 1 : ASSERT(count == 0, "empty vector count must be 0");
956 1 : ASSERT(!tl_reader_ok(&r), "reader exhausted after empty vector header");
957 1 : tl_writer_free(&w);
958 : }
959 :
960 : /* --- single-element vector --- */
961 : {
962 : TlWriter w;
963 1 : tl_writer_init(&w);
964 1 : tl_write_vector_begin(&w, 1);
965 1 : tl_write_int32(&w, 42);
966 :
967 1 : TlReader r = tl_reader_init(w.data, w.len);
968 1 : uint32_t ctor = tl_read_uint32(&r);
969 1 : uint32_t count = tl_read_uint32(&r);
970 1 : ASSERT(ctor == 0x1cb5c415u, "vector ctor magic (single)");
971 1 : ASSERT(count == 1, "single-element vector count must be 1");
972 1 : int32_t val = tl_read_int32(&r);
973 1 : ASSERT(val == 42, "single-element roundtrip value mismatch");
974 1 : ASSERT(!tl_reader_ok(&r), "reader exhausted after single-element vector");
975 1 : tl_writer_free(&w);
976 : }
977 :
978 : /* --- many-element vector (100 elements) --- */
979 : {
980 1 : const uint32_t N = 100;
981 : TlWriter w;
982 1 : tl_writer_init(&w);
983 1 : tl_write_vector_begin(&w, N);
984 101 : for (uint32_t i = 0; i < N; i++)
985 100 : tl_write_int32(&w, (int32_t)i);
986 :
987 1 : TlReader r = tl_reader_init(w.data, w.len);
988 1 : uint32_t ctor = tl_read_uint32(&r);
989 1 : uint32_t count = tl_read_uint32(&r);
990 1 : ASSERT(ctor == 0x1cb5c415u, "vector ctor magic (many)");
991 1 : ASSERT(count == N, "many-element vector count must be 100");
992 101 : for (uint32_t i = 0; i < N; i++) {
993 100 : int32_t val = tl_read_int32(&r);
994 100 : ASSERT(val == (int32_t)i, "many-element roundtrip value mismatch");
995 : }
996 1 : ASSERT(!tl_reader_ok(&r), "reader exhausted after many-element vector");
997 1 : tl_writer_free(&w);
998 : }
999 : }
1000 :
1001 : /* ================================================================
1002 : * Test suite entry point
1003 : * ================================================================ */
1004 :
1005 1 : void test_tl_serial(void) {
1006 1 : RUN_TEST(test_tl_writer_init_free);
1007 1 : RUN_TEST(test_tl_write_int32);
1008 1 : RUN_TEST(test_tl_write_int32_negative);
1009 1 : RUN_TEST(test_tl_write_uint32);
1010 1 : RUN_TEST(test_tl_write_int64);
1011 1 : RUN_TEST(test_tl_write_uint64);
1012 1 : RUN_TEST(test_tl_write_int128);
1013 1 : RUN_TEST(test_tl_write_int256);
1014 1 : RUN_TEST(test_tl_write_double);
1015 1 : RUN_TEST(test_tl_write_bool_true);
1016 1 : RUN_TEST(test_tl_write_bool_false);
1017 1 : RUN_TEST(test_tl_write_string_short);
1018 1 : RUN_TEST(test_tl_write_string_empty);
1019 1 : RUN_TEST(test_tl_write_string_needs_padding);
1020 1 : RUN_TEST(test_tl_write_string_aligned);
1021 1 : RUN_TEST(test_tl_write_bytes_long);
1022 1 : RUN_TEST(test_tl_write_vector_begin);
1023 1 : RUN_TEST(test_tl_write_multiple);
1024 1 : RUN_TEST(test_tl_reader_init);
1025 1 : RUN_TEST(test_tl_reader_ok);
1026 1 : RUN_TEST(test_tl_read_int32);
1027 1 : RUN_TEST(test_tl_read_uint32);
1028 1 : RUN_TEST(test_tl_read_int64);
1029 1 : RUN_TEST(test_tl_read_int128);
1030 1 : RUN_TEST(test_tl_read_int256);
1031 1 : RUN_TEST(test_tl_read_bool_true);
1032 1 : RUN_TEST(test_tl_read_bool_false);
1033 1 : RUN_TEST(test_tl_read_bool_invalid);
1034 1 : RUN_TEST(test_tl_read_string_short);
1035 1 : RUN_TEST(test_tl_read_string_empty);
1036 1 : RUN_TEST(test_tl_read_bytes_with_padding);
1037 1 : RUN_TEST(test_tl_read_bytes_empty);
1038 1 : RUN_TEST(test_tl_read_bytes_long_prefix);
1039 1 : RUN_TEST(test_tl_read_past_end);
1040 1 : RUN_TEST(test_tl_read_skip);
1041 1 : RUN_TEST(test_tl_read_raw);
1042 1 : RUN_TEST(test_tl_roundtrip_int32);
1043 1 : RUN_TEST(test_tl_roundtrip_uint64);
1044 1 : RUN_TEST(test_tl_roundtrip_string);
1045 1 : RUN_TEST(test_tl_roundtrip_int128_int256);
1046 1 : RUN_TEST(test_tl_roundtrip_double);
1047 1 : RUN_TEST(test_tl_roundtrip_bool);
1048 1 : RUN_TEST(test_tl_roundtrip_mixed);
1049 1 : RUN_TEST(test_tl_string_null);
1050 1 : RUN_TEST(test_tl_writer_grow);
1051 1 : RUN_TEST(test_tl_vector_overflow_uint32);
1052 1 : RUN_TEST(test_tl_vector_overflow_int32);
1053 1 : RUN_TEST(test_tl_vector_overflow_uint64);
1054 1 : RUN_TEST(test_tl_vector_overflow_string);
1055 1 : RUN_TEST(test_tl_vector_overflow_reader_saturates);
1056 1 : RUN_TEST(test_tl_read_bytes_giant_length_claim);
1057 1 : RUN_TEST(test_tl_read_bytes_long_prefix_exact);
1058 1 : RUN_TEST(test_tl_read_bytes_invalid_ff_prefix);
1059 1 : RUN_TEST(test_tl_string_roundtrip_lengths);
1060 1 : RUN_TEST(test_tl_int32_roundtrip_boundaries);
1061 1 : RUN_TEST(test_tl_int64_roundtrip_boundaries);
1062 1 : RUN_TEST(test_tl_vector_roundtrip_empty_single_many);
1063 1 : }
|