Line data Source code
1 : /**
2 : * @file test_tl_skip.c
3 : * @brief Unit tests for TL object skippers.
4 : */
5 :
6 : #include "test_helpers.h"
7 : #include "tl_skip.h"
8 : #include "tl_serial.h"
9 : #include "tl_registry.h"
10 :
11 : #include <stdlib.h>
12 : #include <string.h>
13 :
14 : /* CRCs duplicated from tl_skip.c for wire building in tests. */
15 : #define CRC_peerNotifySettings 0xa83b0426u
16 : #define CRC_notificationSoundDefault 0x97e8bebeu
17 : #define CRC_notificationSoundNone 0x6f0c34dfu
18 : #define CRC_notificationSoundLocal 0x830b9ae4u
19 : #define CRC_notificationSoundRingtone 0xff6c8049u
20 : #define CRC_draftMessageEmpty 0x1b0c841au
21 : #define CRC_messageEntityBold 0xbd610bc9u
22 : #define CRC_messageEntityTextUrl 0x76a6d327u
23 : #define CRC_messageFwdHeader 0x4e4df4bbu
24 : #define CRC_messageReplyHeader 0xafbc09dbu
25 : #define CRC_messageMediaEmpty 0x3ded6320u
26 : #define CRC_messageMediaUnsupported 0x9f84f49eu
27 : #define CRC_messageMediaGeo 0x56e0d474u
28 : #define CRC_messageMediaContact 0x70322949u
29 : #define CRC_messageMediaDice 0x3f7ee58bu
30 : #define CRC_messageMediaVenue 0x2ec0533fu
31 : #define CRC_messageMediaPhoto 0x695150d7u
32 : #define CRC_messageMediaDocument 0x4cf4d72du
33 : #define CRC_geoPointEmpty 0x1117dd5fu
34 : #define CRC_geoPoint 0xb2a2f663u
35 : #define CRC_photo 0xfb197a65u
36 : #define CRC_photoEmpty 0x2331b22du
37 : #define CRC_documentEmpty 0x36f8c871u
38 : #define CRC_photoSize 0x75c78e60u
39 : #define CRC_chatPhotoEmpty 0x37c1011cu
40 : #define CRC_chatPhoto 0x1c6e1c11u
41 : #define CRC_userProfilePhotoEmpty 0x4f11bae1u
42 :
43 1 : static void test_skip_bool(void) {
44 1 : TlWriter w; tl_writer_init(&w);
45 1 : tl_write_bool(&w, 1);
46 1 : tl_write_int32(&w, 42); /* sentinel to verify cursor position */
47 1 : TlReader r = tl_reader_init(w.data, w.len);
48 :
49 1 : ASSERT(tl_skip_bool(&r) == 0, "skip_bool ok");
50 1 : ASSERT(tl_read_int32(&r) == 42, "cursor past bool");
51 1 : tl_writer_free(&w);
52 : }
53 :
54 1 : static void test_skip_string(void) {
55 1 : TlWriter w; tl_writer_init(&w);
56 1 : tl_write_string(&w, "hello world");
57 1 : tl_write_int32(&w, 7);
58 1 : TlReader r = tl_reader_init(w.data, w.len);
59 :
60 1 : ASSERT(tl_skip_string(&r) == 0, "skip_string ok");
61 1 : ASSERT(tl_read_int32(&r) == 7, "cursor past string");
62 1 : tl_writer_free(&w);
63 : }
64 :
65 1 : static void test_skip_peer(void) {
66 1 : TlWriter w; tl_writer_init(&w);
67 1 : tl_write_uint32(&w, TL_peerUser);
68 1 : tl_write_int64(&w, 123456LL);
69 1 : tl_write_int32(&w, 99);
70 1 : TlReader r = tl_reader_init(w.data, w.len);
71 :
72 1 : ASSERT(tl_skip_peer(&r) == 0, "skip_peer ok");
73 1 : ASSERT(tl_read_int32(&r) == 99, "cursor past peer");
74 1 : tl_writer_free(&w);
75 : }
76 :
77 1 : static void test_skip_peer_unknown(void) {
78 1 : TlWriter w; tl_writer_init(&w);
79 1 : tl_write_uint32(&w, 0xDEADBEEF);
80 1 : tl_write_int64(&w, 0);
81 1 : TlReader r = tl_reader_init(w.data, w.len);
82 :
83 1 : ASSERT(tl_skip_peer(&r) == -1, "unknown peer rejected");
84 1 : tl_writer_free(&w);
85 : }
86 :
87 1 : static void test_skip_notification_sound_default(void) {
88 1 : TlWriter w; tl_writer_init(&w);
89 1 : tl_write_uint32(&w, CRC_notificationSoundDefault);
90 1 : tl_write_int32(&w, 55);
91 1 : TlReader r = tl_reader_init(w.data, w.len);
92 :
93 1 : ASSERT(tl_skip_notification_sound(&r) == 0, "default ok");
94 1 : ASSERT(tl_read_int32(&r) == 55, "cursor past");
95 1 : tl_writer_free(&w);
96 : }
97 :
98 1 : static void test_skip_notification_sound_ringtone(void) {
99 1 : TlWriter w; tl_writer_init(&w);
100 1 : tl_write_uint32(&w, CRC_notificationSoundRingtone);
101 1 : tl_write_int64(&w, 0x1122334455667788LL);
102 1 : tl_write_int32(&w, 88);
103 1 : TlReader r = tl_reader_init(w.data, w.len);
104 :
105 1 : ASSERT(tl_skip_notification_sound(&r) == 0, "ringtone ok");
106 1 : ASSERT(tl_read_int32(&r) == 88, "cursor past");
107 1 : tl_writer_free(&w);
108 : }
109 :
110 1 : static void test_skip_notification_sound_local(void) {
111 1 : TlWriter w; tl_writer_init(&w);
112 1 : tl_write_uint32(&w, CRC_notificationSoundLocal);
113 1 : tl_write_string(&w, "bell");
114 1 : tl_write_string(&w, "bell.mp3");
115 1 : tl_write_int32(&w, 33);
116 1 : TlReader r = tl_reader_init(w.data, w.len);
117 :
118 1 : ASSERT(tl_skip_notification_sound(&r) == 0, "local ok");
119 1 : ASSERT(tl_read_int32(&r) == 33, "cursor past");
120 1 : tl_writer_free(&w);
121 : }
122 :
123 1 : static void test_skip_peer_notify_settings_empty(void) {
124 1 : TlWriter w; tl_writer_init(&w);
125 1 : tl_write_uint32(&w, CRC_peerNotifySettings);
126 1 : tl_write_uint32(&w, 0); /* no flags */
127 1 : tl_write_int32(&w, 11);
128 1 : TlReader r = tl_reader_init(w.data, w.len);
129 :
130 1 : ASSERT(tl_skip_peer_notify_settings(&r) == 0, "empty notify ok");
131 1 : ASSERT(tl_read_int32(&r) == 11, "cursor past");
132 1 : tl_writer_free(&w);
133 : }
134 :
135 1 : static void test_skip_peer_notify_settings_full(void) {
136 1 : TlWriter w; tl_writer_init(&w);
137 1 : tl_write_uint32(&w, CRC_peerNotifySettings);
138 1 : uint32_t flags = (1u << 0) /* show_previews (bool) */
139 : | (1u << 1) /* silent (bool) */
140 : | (1u << 2) /* mute_until (int) */
141 : | (1u << 3) /* ios_sound (NS) */
142 : | (1u << 6); /* stories_muted (bool) */
143 1 : tl_write_uint32(&w, flags);
144 1 : tl_write_bool(&w, 1);
145 1 : tl_write_bool(&w, 0);
146 1 : tl_write_int32(&w, 1000);
147 1 : tl_write_uint32(&w, CRC_notificationSoundDefault);
148 1 : tl_write_bool(&w, 1);
149 1 : tl_write_int32(&w, 77);
150 1 : TlReader r = tl_reader_init(w.data, w.len);
151 :
152 1 : ASSERT(tl_skip_peer_notify_settings(&r) == 0, "full notify ok");
153 1 : ASSERT(tl_read_int32(&r) == 77, "cursor past");
154 1 : tl_writer_free(&w);
155 : }
156 :
157 1 : static void test_skip_draft_message_empty(void) {
158 1 : TlWriter w; tl_writer_init(&w);
159 1 : tl_write_uint32(&w, CRC_draftMessageEmpty);
160 1 : tl_write_uint32(&w, 1); /* flags.0: date present */
161 1 : tl_write_int32(&w, 1700000000);
162 1 : tl_write_int32(&w, 5);
163 1 : TlReader r = tl_reader_init(w.data, w.len);
164 :
165 1 : ASSERT(tl_skip_draft_message(&r) == 0, "draft empty ok");
166 1 : ASSERT(tl_read_int32(&r) == 5, "cursor past");
167 1 : tl_writer_free(&w);
168 : }
169 :
170 1 : static void test_skip_message_entity_bold(void) {
171 1 : TlWriter w; tl_writer_init(&w);
172 1 : tl_write_uint32(&w, CRC_messageEntityBold);
173 1 : tl_write_int32(&w, 5); /* offset */
174 1 : tl_write_int32(&w, 10); /* length */
175 1 : tl_write_int32(&w, 42);
176 1 : TlReader r = tl_reader_init(w.data, w.len);
177 1 : ASSERT(tl_skip_message_entity(&r) == 0, "bold entity");
178 1 : ASSERT(tl_read_int32(&r) == 42, "cursor past entity");
179 1 : tl_writer_free(&w);
180 : }
181 :
182 1 : static void test_skip_message_entity_text_url(void) {
183 1 : TlWriter w; tl_writer_init(&w);
184 1 : tl_write_uint32(&w, CRC_messageEntityTextUrl);
185 1 : tl_write_int32(&w, 0);
186 1 : tl_write_int32(&w, 4);
187 1 : tl_write_string(&w, "https://example.com");
188 1 : tl_write_int32(&w, 42);
189 1 : TlReader r = tl_reader_init(w.data, w.len);
190 1 : ASSERT(tl_skip_message_entity(&r) == 0, "text_url entity");
191 1 : ASSERT(tl_read_int32(&r) == 42, "cursor past entity");
192 1 : tl_writer_free(&w);
193 : }
194 :
195 1 : static void test_skip_entities_vector(void) {
196 1 : TlWriter w; tl_writer_init(&w);
197 1 : tl_write_uint32(&w, TL_vector);
198 1 : tl_write_uint32(&w, 2);
199 1 : tl_write_uint32(&w, CRC_messageEntityBold);
200 1 : tl_write_int32(&w, 0); tl_write_int32(&w, 3);
201 1 : tl_write_uint32(&w, CRC_messageEntityBold);
202 1 : tl_write_int32(&w, 10); tl_write_int32(&w, 5);
203 1 : tl_write_int32(&w, 99);
204 1 : TlReader r = tl_reader_init(w.data, w.len);
205 1 : ASSERT(tl_skip_message_entities_vector(&r) == 0, "entities vector");
206 1 : ASSERT(tl_read_int32(&r) == 99, "cursor past vector");
207 1 : tl_writer_free(&w);
208 : }
209 :
210 1 : static void test_skip_fwd_header_minimal(void) {
211 1 : TlWriter w; tl_writer_init(&w);
212 1 : tl_write_uint32(&w, CRC_messageFwdHeader);
213 1 : tl_write_uint32(&w, 0); /* no flags */
214 1 : tl_write_int32(&w, 1700000000); /* date */
215 1 : tl_write_int32(&w, 21);
216 1 : TlReader r = tl_reader_init(w.data, w.len);
217 1 : ASSERT(tl_skip_message_fwd_header(&r) == 0, "fwd header minimal");
218 1 : ASSERT(tl_read_int32(&r) == 21, "cursor past fwd_header");
219 1 : tl_writer_free(&w);
220 : }
221 :
222 1 : static void test_skip_fwd_header_with_channel(void) {
223 1 : TlWriter w; tl_writer_init(&w);
224 1 : tl_write_uint32(&w, CRC_messageFwdHeader);
225 1 : uint32_t flags = (1u << 0) /* from_id */
226 : | (1u << 2) /* channel_post */
227 : | (1u << 3); /* post_author */
228 1 : tl_write_uint32(&w, flags);
229 1 : tl_write_uint32(&w, TL_peerChannel);
230 1 : tl_write_int64(&w, -1001234567890LL);
231 1 : tl_write_int32(&w, 1700000000); /* date */
232 1 : tl_write_int32(&w, 42); /* channel_post */
233 1 : tl_write_string(&w, "author");
234 1 : tl_write_int32(&w, 77);
235 1 : TlReader r = tl_reader_init(w.data, w.len);
236 1 : ASSERT(tl_skip_message_fwd_header(&r) == 0, "fwd header with channel");
237 1 : ASSERT(tl_read_int32(&r) == 77, "cursor past");
238 1 : tl_writer_free(&w);
239 : }
240 :
241 1 : static void test_skip_reply_header_minimal(void) {
242 1 : TlWriter w; tl_writer_init(&w);
243 1 : tl_write_uint32(&w, CRC_messageReplyHeader);
244 1 : tl_write_uint32(&w, (1u << 4)); /* reply_to_msg_id */
245 1 : tl_write_int32(&w, 1234);
246 1 : tl_write_int32(&w, 88);
247 1 : TlReader r = tl_reader_init(w.data, w.len);
248 1 : ASSERT(tl_skip_message_reply_header(&r) == 0, "reply header minimal");
249 1 : ASSERT(tl_read_int32(&r) == 88, "cursor past");
250 1 : tl_writer_free(&w);
251 : }
252 :
253 : /* ---- Error / short-buffer coverage ---- */
254 :
255 1 : static void test_skip_bool_short(void) {
256 1 : TlWriter w; tl_writer_init(&w);
257 1 : tl_write_uint32(&w, 0); /* only 4 bytes */
258 1 : TlReader r = tl_reader_init(w.data, 2); /* truncated */
259 1 : ASSERT(tl_skip_bool(&r) == -1, "short bool rejected");
260 1 : tl_writer_free(&w);
261 : }
262 :
263 1 : static void test_skip_notification_sound_unknown(void) {
264 1 : TlWriter w; tl_writer_init(&w);
265 1 : tl_write_uint32(&w, 0xDEADBEEF);
266 1 : TlReader r = tl_reader_init(w.data, w.len);
267 1 : ASSERT(tl_skip_notification_sound(&r) == -1, "unknown NS rejected");
268 1 : tl_writer_free(&w);
269 : }
270 :
271 1 : static void test_skip_peer_notify_settings_wrong_crc(void) {
272 1 : TlWriter w; tl_writer_init(&w);
273 1 : tl_write_uint32(&w, 0xBADF00D);
274 1 : tl_write_uint32(&w, 0);
275 1 : TlReader r = tl_reader_init(w.data, w.len);
276 1 : ASSERT(tl_skip_peer_notify_settings(&r) == -1, "wrong CRC rejected");
277 1 : tl_writer_free(&w);
278 : }
279 :
280 1 : static void test_skip_draft_message_nonempty(void) {
281 : /* Non-empty draftMessage (0x3fccf7ef) is not parseable yet — must bail. */
282 1 : TlWriter w; tl_writer_init(&w);
283 1 : tl_write_uint32(&w, 0x3fccf7efu);
284 1 : TlReader r = tl_reader_init(w.data, w.len);
285 1 : ASSERT(tl_skip_draft_message(&r) == -1, "non-empty draft bails");
286 1 : tl_writer_free(&w);
287 : }
288 :
289 1 : static void test_skip_draft_message_unknown(void) {
290 1 : TlWriter w; tl_writer_init(&w);
291 1 : tl_write_uint32(&w, 0xCAFEBABE);
292 1 : TlReader r = tl_reader_init(w.data, w.len);
293 1 : ASSERT(tl_skip_draft_message(&r) == -1, "unknown draft rejected");
294 1 : tl_writer_free(&w);
295 : }
296 :
297 1 : static void test_skip_message_entity_unknown(void) {
298 1 : TlWriter w; tl_writer_init(&w);
299 1 : tl_write_uint32(&w, 0xDEADCAFE);
300 1 : TlReader r = tl_reader_init(w.data, w.len);
301 1 : ASSERT(tl_skip_message_entity(&r) == -1, "unknown entity rejected");
302 1 : tl_writer_free(&w);
303 : }
304 :
305 1 : static void test_skip_entities_vector_wrong_header(void) {
306 1 : TlWriter w; tl_writer_init(&w);
307 1 : tl_write_uint32(&w, 0xBADBADBA); /* not TL_vector */
308 1 : tl_write_uint32(&w, 0);
309 1 : TlReader r = tl_reader_init(w.data, w.len);
310 1 : ASSERT(tl_skip_message_entities_vector(&r) == -1, "non-vector rejected");
311 1 : tl_writer_free(&w);
312 : }
313 :
314 1 : static void test_skip_fwd_header_wrong_crc(void) {
315 1 : TlWriter w; tl_writer_init(&w);
316 1 : tl_write_uint32(&w, 0x12345678);
317 1 : TlReader r = tl_reader_init(w.data, w.len);
318 1 : ASSERT(tl_skip_message_fwd_header(&r) == -1, "bad fwd crc rejected");
319 1 : tl_writer_free(&w);
320 : }
321 :
322 1 : static void test_skip_reply_header_wrong_crc(void) {
323 1 : TlWriter w; tl_writer_init(&w);
324 1 : tl_write_uint32(&w, 0x87654321);
325 1 : TlReader r = tl_reader_init(w.data, w.len);
326 1 : ASSERT(tl_skip_message_reply_header(&r) == -1, "bad reply crc rejected");
327 1 : tl_writer_free(&w);
328 : }
329 :
330 1 : static void test_skip_reply_header_reply_media_bail(void) {
331 : /* flags.8 set → reply_media is present but we haven't implemented the
332 : * MessageMedia skipper, so must bail. */
333 1 : TlWriter w; tl_writer_init(&w);
334 1 : tl_write_uint32(&w, 0xafbc09dbu);
335 1 : tl_write_uint32(&w, (1u << 8));
336 1 : TlReader r = tl_reader_init(w.data, w.len);
337 1 : ASSERT(tl_skip_message_reply_header(&r) == -1, "reply_media bail");
338 1 : tl_writer_free(&w);
339 : }
340 :
341 : /* ---- MessageMedia skipper tests ---- */
342 :
343 1 : static void test_skip_media_empty(void) {
344 1 : TlWriter w; tl_writer_init(&w);
345 1 : tl_write_uint32(&w, CRC_messageMediaEmpty);
346 1 : tl_write_int32(&w, 101);
347 1 : TlReader r = tl_reader_init(w.data, w.len);
348 1 : ASSERT(tl_skip_message_media(&r) == 0, "media empty");
349 1 : ASSERT(tl_read_int32(&r) == 101, "cursor past media empty");
350 1 : tl_writer_free(&w);
351 : }
352 :
353 1 : static void test_skip_media_unsupported(void) {
354 1 : TlWriter w; tl_writer_init(&w);
355 1 : tl_write_uint32(&w, CRC_messageMediaUnsupported);
356 1 : tl_write_int32(&w, 202);
357 1 : TlReader r = tl_reader_init(w.data, w.len);
358 1 : ASSERT(tl_skip_message_media(&r) == 0, "media unsupported");
359 1 : ASSERT(tl_read_int32(&r) == 202, "cursor past media unsupported");
360 1 : tl_writer_free(&w);
361 : }
362 :
363 1 : static void test_skip_media_geo_empty_point(void) {
364 1 : TlWriter w; tl_writer_init(&w);
365 1 : tl_write_uint32(&w, CRC_messageMediaGeo);
366 1 : tl_write_uint32(&w, CRC_geoPointEmpty);
367 1 : tl_write_int32(&w, 303);
368 1 : TlReader r = tl_reader_init(w.data, w.len);
369 1 : ASSERT(tl_skip_message_media(&r) == 0, "geo empty");
370 1 : ASSERT(tl_read_int32(&r) == 303, "cursor past");
371 1 : tl_writer_free(&w);
372 : }
373 :
374 1 : static void test_skip_media_geo(void) {
375 1 : TlWriter w; tl_writer_init(&w);
376 1 : tl_write_uint32(&w, CRC_messageMediaGeo);
377 1 : tl_write_uint32(&w, CRC_geoPoint);
378 1 : tl_write_uint32(&w, 0); /* flags */
379 1 : tl_write_double(&w, 19.12); /* long */
380 1 : tl_write_double(&w, 47.49); /* lat */
381 1 : tl_write_int64(&w, 0xCAFE); /* access_hash */
382 1 : tl_write_int32(&w, 404);
383 1 : TlReader r = tl_reader_init(w.data, w.len);
384 1 : ASSERT(tl_skip_message_media(&r) == 0, "geo full");
385 1 : ASSERT(tl_read_int32(&r) == 404, "cursor past");
386 1 : tl_writer_free(&w);
387 : }
388 :
389 1 : static void test_skip_media_contact(void) {
390 1 : TlWriter w; tl_writer_init(&w);
391 1 : tl_write_uint32(&w, CRC_messageMediaContact);
392 1 : tl_write_string(&w, "+15551234567");
393 1 : tl_write_string(&w, "Alice");
394 1 : tl_write_string(&w, "Smith");
395 1 : tl_write_string(&w, ""); /* vcard */
396 1 : tl_write_int64(&w, 42LL);
397 1 : tl_write_int32(&w, 505);
398 1 : TlReader r = tl_reader_init(w.data, w.len);
399 1 : ASSERT(tl_skip_message_media(&r) == 0, "contact");
400 1 : ASSERT(tl_read_int32(&r) == 505, "cursor past");
401 1 : tl_writer_free(&w);
402 : }
403 :
404 1 : static void test_skip_media_dice(void) {
405 1 : TlWriter w; tl_writer_init(&w);
406 1 : tl_write_uint32(&w, CRC_messageMediaDice);
407 1 : tl_write_int32(&w, 6);
408 1 : tl_write_string(&w, "🎲");
409 1 : tl_write_int32(&w, 606);
410 1 : TlReader r = tl_reader_init(w.data, w.len);
411 1 : ASSERT(tl_skip_message_media(&r) == 0, "dice");
412 1 : ASSERT(tl_read_int32(&r) == 606, "cursor past");
413 1 : tl_writer_free(&w);
414 : }
415 :
416 1 : static void test_skip_media_venue(void) {
417 1 : TlWriter w; tl_writer_init(&w);
418 1 : tl_write_uint32(&w, CRC_messageMediaVenue);
419 1 : tl_write_uint32(&w, CRC_geoPointEmpty);
420 1 : tl_write_string(&w, "Title");
421 1 : tl_write_string(&w, "Address");
422 1 : tl_write_string(&w, "Provider");
423 1 : tl_write_string(&w, "VenueID");
424 1 : tl_write_string(&w, "Type");
425 1 : tl_write_int32(&w, 707);
426 1 : TlReader r = tl_reader_init(w.data, w.len);
427 1 : ASSERT(tl_skip_message_media(&r) == 0, "venue");
428 1 : ASSERT(tl_read_int32(&r) == 707, "cursor past");
429 1 : tl_writer_free(&w);
430 : }
431 :
432 1 : static void test_skip_media_photo_empty_photo(void) {
433 1 : TlWriter w; tl_writer_init(&w);
434 1 : tl_write_uint32(&w, CRC_messageMediaPhoto);
435 1 : tl_write_uint32(&w, (1u << 0)); /* flags: photo present */
436 1 : tl_write_uint32(&w, CRC_photoEmpty);
437 1 : tl_write_int64(&w, 1234567890LL);
438 1 : tl_write_int32(&w, 808);
439 1 : TlReader r = tl_reader_init(w.data, w.len);
440 1 : ASSERT(tl_skip_message_media(&r) == 0, "media-photo with photoEmpty");
441 1 : ASSERT(tl_read_int32(&r) == 808, "cursor past");
442 1 : tl_writer_free(&w);
443 : }
444 :
445 1 : static void test_skip_media_photo_with_sizes(void) {
446 1 : TlWriter w; tl_writer_init(&w);
447 1 : tl_write_uint32(&w, CRC_messageMediaPhoto);
448 1 : tl_write_uint32(&w, (1u << 0)); /* photo flag */
449 : /* photo#fb197a65 flags:# id:long access_hash:long file_reference:bytes
450 : * date:int sizes:Vector<PhotoSize> dc_id:int */
451 1 : tl_write_uint32(&w, CRC_photo);
452 1 : tl_write_uint32(&w, 0); /* photo flags */
453 1 : tl_write_int64(&w, 111LL); /* id */
454 1 : tl_write_int64(&w, 222LL); /* access_hash */
455 1 : uint8_t fr[8] = {1,2,3,4,5,6,7,8};
456 1 : tl_write_bytes(&w, fr, 8); /* file_reference */
457 1 : tl_write_int32(&w, 1700000000); /* date */
458 : /* sizes vector: one photoSize */
459 1 : tl_write_uint32(&w, TL_vector);
460 1 : tl_write_uint32(&w, 1);
461 1 : tl_write_uint32(&w, CRC_photoSize);
462 1 : tl_write_string(&w, "x");
463 1 : tl_write_int32(&w, 640); tl_write_int32(&w, 480); tl_write_int32(&w, 12345);
464 1 : tl_write_int32(&w, 2); /* dc_id */
465 1 : tl_write_int32(&w, 909); /* sentinel */
466 1 : TlReader r = tl_reader_init(w.data, w.len);
467 1 : ASSERT(tl_skip_message_media(&r) == 0, "media-photo with photoSize");
468 1 : ASSERT(tl_read_int32(&r) == 909, "cursor past");
469 1 : tl_writer_free(&w);
470 : }
471 :
472 1 : static void test_skip_media_document_empty(void) {
473 1 : TlWriter w; tl_writer_init(&w);
474 1 : tl_write_uint32(&w, CRC_messageMediaDocument);
475 1 : tl_write_uint32(&w, (1u << 0)); /* document present */
476 1 : tl_write_uint32(&w, CRC_documentEmpty);
477 1 : tl_write_int64(&w, 99999LL);
478 1 : tl_write_int32(&w, 1010);
479 1 : TlReader r = tl_reader_init(w.data, w.len);
480 1 : ASSERT(tl_skip_message_media(&r) == 0, "media-document empty");
481 1 : ASSERT(tl_read_int32(&r) == 1010, "cursor past");
482 1 : tl_writer_free(&w);
483 : }
484 :
485 : /* ---- Chat / User skipper tests ---- */
486 :
487 1 : static void test_skip_chat_forbidden(void) {
488 1 : TlWriter w; tl_writer_init(&w);
489 1 : tl_write_uint32(&w, TL_chatForbidden);
490 1 : tl_write_int64(&w, 12345LL);
491 1 : tl_write_string(&w, "Forbidden Chat");
492 1 : tl_write_int32(&w, 1111);
493 1 : TlReader r = tl_reader_init(w.data, w.len);
494 1 : ASSERT(tl_skip_chat(&r) == 0, "chatForbidden skip");
495 1 : ASSERT(tl_read_int32(&r) == 1111, "cursor past chatForbidden");
496 1 : tl_writer_free(&w);
497 : }
498 :
499 1 : static void test_skip_channel_forbidden(void) {
500 1 : TlWriter w; tl_writer_init(&w);
501 1 : tl_write_uint32(&w, TL_channelForbidden);
502 1 : tl_write_uint32(&w, 0); /* flags: no until_date */
503 1 : tl_write_int64(&w, -1001234567LL); /* id */
504 1 : tl_write_int64(&w, 0xCAFEBABELL); /* access_hash */
505 1 : tl_write_string(&w, "Forbidden Channel");
506 1 : tl_write_int32(&w, 2222);
507 1 : TlReader r = tl_reader_init(w.data, w.len);
508 1 : ASSERT(tl_skip_chat(&r) == 0, "channelForbidden skip");
509 1 : ASSERT(tl_read_int32(&r) == 2222, "cursor past channelForbidden");
510 1 : tl_writer_free(&w);
511 : }
512 :
513 1 : static void test_skip_chat_plain(void) {
514 1 : TlWriter w; tl_writer_init(&w);
515 1 : tl_write_uint32(&w, TL_chat);
516 1 : tl_write_uint32(&w, 0); /* flags (no optionals) */
517 1 : tl_write_int64(&w, 42LL); /* id */
518 1 : tl_write_string(&w, "Group Name");
519 1 : tl_write_uint32(&w, CRC_chatPhotoEmpty); /* photo */
520 1 : tl_write_int32(&w, 10); /* participants_count */
521 1 : tl_write_int32(&w, 1700000000); /* date */
522 1 : tl_write_int32(&w, 3); /* version */
523 1 : tl_write_int32(&w, 3333); /* sentinel */
524 1 : TlReader r = tl_reader_init(w.data, w.len);
525 1 : ASSERT(tl_skip_chat(&r) == 0, "chat skip");
526 1 : ASSERT(tl_read_int32(&r) == 3333, "cursor past chat");
527 1 : tl_writer_free(&w);
528 : }
529 :
530 1 : static void test_skip_channel_minimal(void) {
531 1 : TlWriter w; tl_writer_init(&w);
532 1 : tl_write_uint32(&w, TL_channel);
533 1 : tl_write_uint32(&w, 0); /* flags */
534 1 : tl_write_uint32(&w, 0); /* flags2 */
535 1 : tl_write_int64(&w, -1009876543LL); /* id */
536 1 : tl_write_string(&w, "Chan");
537 1 : tl_write_uint32(&w, CRC_chatPhotoEmpty); /* photo */
538 1 : tl_write_int32(&w, 1700000000); /* date */
539 1 : tl_write_int32(&w, 4444); /* sentinel */
540 1 : TlReader r = tl_reader_init(w.data, w.len);
541 1 : ASSERT(tl_skip_chat(&r) == 0, "channel skip");
542 1 : ASSERT(tl_read_int32(&r) == 4444, "cursor past channel");
543 1 : tl_writer_free(&w);
544 : }
545 :
546 1 : static void test_skip_user_empty(void) {
547 1 : TlWriter w; tl_writer_init(&w);
548 1 : tl_write_uint32(&w, TL_userEmpty);
549 1 : tl_write_int64(&w, 777LL);
550 1 : tl_write_int32(&w, 5555);
551 1 : TlReader r = tl_reader_init(w.data, w.len);
552 1 : ASSERT(tl_skip_user(&r) == 0, "userEmpty skip");
553 1 : ASSERT(tl_read_int32(&r) == 5555, "cursor past userEmpty");
554 1 : tl_writer_free(&w);
555 : }
556 :
557 1 : static void test_skip_user_full(void) {
558 1 : TlWriter w; tl_writer_init(&w);
559 1 : tl_write_uint32(&w, TL_user);
560 1 : uint32_t flags = (1u << 1) /* first_name */
561 : | (1u << 2) /* last_name */
562 : | (1u << 3); /* username */
563 1 : tl_write_uint32(&w, flags);
564 1 : tl_write_uint32(&w, 0); /* flags2 */
565 1 : tl_write_int64(&w, 999LL); /* id */
566 1 : tl_write_string(&w, "Alice");
567 1 : tl_write_string(&w, "Smith");
568 1 : tl_write_string(&w, "asmith");
569 1 : tl_write_int32(&w, 6666);
570 1 : TlReader r = tl_reader_init(w.data, w.len);
571 1 : ASSERT(tl_skip_user(&r) == 0, "user skip");
572 1 : ASSERT(tl_read_int32(&r) == 6666, "cursor past user");
573 1 : tl_writer_free(&w);
574 : }
575 :
576 1 : static void test_extract_chat_forbidden(void) {
577 1 : TlWriter w; tl_writer_init(&w);
578 1 : tl_write_uint32(&w, TL_chatForbidden);
579 1 : tl_write_int64(&w, 0xABCDEF00LL);
580 1 : tl_write_string(&w, "Secret Room");
581 1 : tl_write_int32(&w, 7777);
582 1 : TlReader r = tl_reader_init(w.data, w.len);
583 : ChatSummary cs;
584 1 : ASSERT(tl_extract_chat(&r, &cs) == 0, "extract chatForbidden");
585 1 : ASSERT(cs.id == 0xABCDEF00LL, "chat id");
586 1 : ASSERT(strcmp(cs.title, "Secret Room") == 0, "chat title");
587 1 : ASSERT(tl_read_int32(&r) == 7777, "cursor past extract");
588 1 : tl_writer_free(&w);
589 : }
590 :
591 1 : static void test_extract_user(void) {
592 1 : TlWriter w; tl_writer_init(&w);
593 1 : tl_write_uint32(&w, TL_user);
594 1 : uint32_t flags = (1u << 1) | (1u << 2) | (1u << 3);
595 1 : tl_write_uint32(&w, flags);
596 1 : tl_write_uint32(&w, 0);
597 1 : tl_write_int64(&w, 0x1234567890LL);
598 1 : tl_write_string(&w, "Alice");
599 1 : tl_write_string(&w, "Smith");
600 1 : tl_write_string(&w, "asmith");
601 1 : tl_write_int32(&w, 8888);
602 1 : TlReader r = tl_reader_init(w.data, w.len);
603 : UserSummary us;
604 1 : ASSERT(tl_extract_user(&r, &us) == 0, "extract user");
605 1 : ASSERT(us.id == 0x1234567890LL, "user id");
606 1 : ASSERT(us.have_access_hash == 0, "no access_hash when flag clear");
607 1 : ASSERT(us.access_hash == 0, "access_hash zero when absent");
608 1 : ASSERT(strcmp(us.name, "Alice Smith") == 0, "user name joined");
609 1 : ASSERT(strcmp(us.username, "asmith") == 0, "user username");
610 1 : ASSERT(tl_read_int32(&r) == 8888, "cursor past extract user");
611 1 : tl_writer_free(&w);
612 : }
613 :
614 1 : static void test_extract_user_access_hash(void) {
615 1 : TlWriter w; tl_writer_init(&w);
616 1 : tl_write_uint32(&w, TL_user);
617 1 : uint32_t flags = (1u << 0) | (1u << 1) | (1u << 3); /* access_hash + first_name + username */
618 1 : tl_write_uint32(&w, flags);
619 1 : tl_write_uint32(&w, 0);
620 1 : tl_write_int64(&w, 123LL);
621 1 : tl_write_int64(&w, 0xDEADBEEFCAFEBABELL); /* access_hash */
622 1 : tl_write_string(&w, "Bob");
623 1 : tl_write_string(&w, "bob");
624 1 : tl_write_int32(&w, 9999);
625 1 : TlReader r = tl_reader_init(w.data, w.len);
626 : UserSummary us;
627 1 : ASSERT(tl_extract_user(&r, &us) == 0, "extract user with access_hash");
628 1 : ASSERT(us.id == 123LL, "user id");
629 1 : ASSERT(us.have_access_hash == 1, "have_access_hash set");
630 1 : ASSERT(us.access_hash == (int64_t)0xDEADBEEFCAFEBABELL, "access_hash value");
631 1 : ASSERT(strcmp(us.name, "Bob") == 0, "user name");
632 1 : ASSERT(strcmp(us.username, "bob") == 0, "user username");
633 1 : ASSERT(tl_read_int32(&r) == 9999, "cursor past user");
634 1 : tl_writer_free(&w);
635 : }
636 :
637 1 : static void test_extract_channel_access_hash(void) {
638 1 : TlWriter w; tl_writer_init(&w);
639 1 : tl_write_uint32(&w, TL_channel);
640 1 : uint32_t flags = (1u << 13); /* access_hash */
641 1 : tl_write_uint32(&w, flags);
642 1 : tl_write_uint32(&w, 0); /* flags2 */
643 1 : tl_write_int64(&w, -1001234567LL); /* id */
644 1 : tl_write_int64(&w, 0x1111222233334444LL); /* access_hash */
645 1 : tl_write_string(&w, "My Channel");
646 1 : tl_write_uint32(&w, CRC_chatPhotoEmpty); /* photo */
647 1 : tl_write_int32(&w, 1700000000); /* date */
648 1 : tl_write_int32(&w, 5555); /* sentinel */
649 1 : TlReader r = tl_reader_init(w.data, w.len);
650 : ChatSummary cs;
651 1 : ASSERT(tl_extract_chat(&r, &cs) == 0, "extract channel with access_hash");
652 1 : ASSERT(cs.id == -1001234567LL, "channel id");
653 1 : ASSERT(cs.have_access_hash == 1, "have_access_hash set");
654 1 : ASSERT(cs.access_hash == 0x1111222233334444LL, "access_hash value");
655 1 : ASSERT(strcmp(cs.title, "My Channel") == 0, "channel title");
656 1 : ASSERT(tl_read_int32(&r) == 5555, "cursor past channel");
657 1 : tl_writer_free(&w);
658 : }
659 :
660 1 : static void test_extract_channel_forbidden_access_hash(void) {
661 1 : TlWriter w; tl_writer_init(&w);
662 1 : tl_write_uint32(&w, TL_channelForbidden);
663 1 : tl_write_uint32(&w, 0); /* flags: no until_date */
664 1 : tl_write_int64(&w, -1009999999LL);
665 1 : tl_write_int64(&w, 0xA5A5A5A5A5A5A5A5LL); /* access_hash */
666 1 : tl_write_string(&w, "Forbidden");
667 1 : tl_write_int32(&w, 6666);
668 1 : TlReader r = tl_reader_init(w.data, w.len);
669 : ChatSummary cs;
670 1 : ASSERT(tl_extract_chat(&r, &cs) == 0, "extract channelForbidden");
671 1 : ASSERT(cs.have_access_hash == 1, "have_access_hash set");
672 1 : ASSERT(cs.access_hash == (int64_t)0xA5A5A5A5A5A5A5A5LL, "access_hash value");
673 1 : ASSERT(strcmp(cs.title, "Forbidden") == 0, "title extracted");
674 1 : ASSERT(tl_read_int32(&r) == 6666, "cursor past channelForbidden");
675 1 : tl_writer_free(&w);
676 : }
677 :
678 1 : static void test_extract_chat_no_access_hash(void) {
679 1 : TlWriter w; tl_writer_init(&w);
680 1 : tl_write_uint32(&w, TL_chat);
681 1 : tl_write_uint32(&w, 0); /* flags */
682 1 : tl_write_int64(&w, 42LL);
683 1 : tl_write_string(&w, "Legacy Group");
684 1 : tl_write_uint32(&w, CRC_chatPhotoEmpty);
685 1 : tl_write_int32(&w, 5);
686 1 : tl_write_int32(&w, 1700000000);
687 1 : tl_write_int32(&w, 1);
688 1 : tl_write_int32(&w, 7777);
689 1 : TlReader r = tl_reader_init(w.data, w.len);
690 : ChatSummary cs;
691 1 : ASSERT(tl_extract_chat(&r, &cs) == 0, "extract legacy chat");
692 1 : ASSERT(cs.id == 42LL, "chat id");
693 1 : ASSERT(cs.have_access_hash == 0, "legacy chat has no access_hash");
694 1 : ASSERT(strcmp(cs.title, "Legacy Group") == 0, "title");
695 1 : ASSERT(tl_read_int32(&r) == 7777, "cursor past chat");
696 1 : tl_writer_free(&w);
697 : }
698 :
699 : /* ---- ReplyMarkup skipper ---- */
700 :
701 : #define CRC_replyKeyboardHide 0xa03e5b85u
702 : #define CRC_replyKeyboardForceReply 0x86b40b08u
703 : #define CRC_replyInlineMarkup_test 0x48a30254u
704 : #define CRC_keyboardButtonRow_test 0x77608b83u
705 : #define CRC_keyboardButtonUrl_test 0x258aff05u
706 : #define CRC_keyboardButtonCallback_test 0x35bbdb6bu
707 :
708 1 : static void test_skip_reply_markup_hide(void) {
709 1 : TlWriter w; tl_writer_init(&w);
710 1 : tl_write_uint32(&w, CRC_replyKeyboardHide);
711 1 : tl_write_uint32(&w, 0); /* flags */
712 1 : tl_write_int32 (&w, 777); /* trailer */
713 1 : TlReader r = tl_reader_init(w.data, w.len);
714 1 : ASSERT(tl_skip_reply_markup(&r) == 0, "replyKeyboardHide skipped");
715 1 : ASSERT(tl_read_int32(&r) == 777, "cursor past hide");
716 1 : tl_writer_free(&w);
717 : }
718 :
719 1 : static void test_skip_reply_markup_force_reply_with_placeholder(void) {
720 1 : TlWriter w; tl_writer_init(&w);
721 1 : tl_write_uint32(&w, CRC_replyKeyboardForceReply);
722 1 : tl_write_uint32(&w, (1u << 3)); /* placeholder flag */
723 1 : tl_write_string(&w, "Type here...");
724 1 : tl_write_int32 (&w, 42);
725 1 : TlReader r = tl_reader_init(w.data, w.len);
726 1 : ASSERT(tl_skip_reply_markup(&r) == 0, "forceReply w/ placeholder skipped");
727 1 : ASSERT(tl_read_int32(&r) == 42, "cursor past forceReply");
728 1 : tl_writer_free(&w);
729 : }
730 :
731 1 : static void test_skip_reply_markup_inline_url_callback(void) {
732 1 : TlWriter w; tl_writer_init(&w);
733 : /* replyInlineMarkup with one row, two buttons (url + callback). */
734 1 : tl_write_uint32(&w, CRC_replyInlineMarkup_test);
735 1 : tl_write_uint32(&w, TL_vector);
736 1 : tl_write_uint32(&w, 1); /* row count */
737 1 : tl_write_uint32(&w, CRC_keyboardButtonRow_test);
738 1 : tl_write_uint32(&w, TL_vector);
739 1 : tl_write_uint32(&w, 2); /* button count */
740 1 : tl_write_uint32(&w, CRC_keyboardButtonUrl_test);
741 1 : tl_write_string(&w, "Open");
742 1 : tl_write_string(&w, "https://example.com");
743 1 : tl_write_uint32(&w, CRC_keyboardButtonCallback_test);
744 1 : tl_write_uint32(&w, 0); /* inner flags */
745 1 : tl_write_string(&w, "Click");
746 1 : tl_write_string(&w, "payload-bytes");
747 1 : tl_write_int32 (&w, 12345); /* trailer */
748 1 : TlReader r = tl_reader_init(w.data, w.len);
749 1 : ASSERT(tl_skip_reply_markup(&r) == 0, "inline url+callback skipped");
750 1 : ASSERT(tl_read_int32(&r) == 12345, "cursor past inline markup");
751 1 : tl_writer_free(&w);
752 : }
753 :
754 1 : static void test_skip_reply_markup_unknown_bails(void) {
755 1 : TlWriter w; tl_writer_init(&w);
756 1 : tl_write_uint32(&w, 0xdeadbeefu); /* unknown ReplyMarkup variant */
757 1 : TlReader r = tl_reader_init(w.data, w.len);
758 1 : ASSERT(tl_skip_reply_markup(&r) == -1, "unknown variant rejected");
759 1 : tl_writer_free(&w);
760 : }
761 :
762 1 : static void test_skip_reply_markup_unknown_button_bails(void) {
763 1 : TlWriter w; tl_writer_init(&w);
764 1 : tl_write_uint32(&w, CRC_replyInlineMarkup_test);
765 1 : tl_write_uint32(&w, TL_vector);
766 1 : tl_write_uint32(&w, 1);
767 1 : tl_write_uint32(&w, CRC_keyboardButtonRow_test);
768 1 : tl_write_uint32(&w, TL_vector);
769 1 : tl_write_uint32(&w, 1);
770 1 : tl_write_uint32(&w, 0xfeedfacu); /* unknown button */
771 1 : TlReader r = tl_reader_init(w.data, w.len);
772 1 : ASSERT(tl_skip_reply_markup(&r) == -1, "unknown button rejected");
773 1 : tl_writer_free(&w);
774 : }
775 :
776 : /* ---- MessageReactions skipper ---- */
777 :
778 : #define CRC_messageReactions_test 0x4f2b9479u
779 : #define CRC_reactionCount_test 0xa3d1cb80u
780 : #define CRC_reactionEmoji_test 0x1b2286b8u
781 : #define CRC_reactionCustomEmoji_t 0x8935fc73u
782 : #define CRC_reactionEmpty_test 0x79f5d419u
783 :
784 1 : static void test_skip_reactions_empty_results(void) {
785 1 : TlWriter w; tl_writer_init(&w);
786 1 : tl_write_uint32(&w, CRC_messageReactions_test);
787 1 : tl_write_uint32(&w, 0); /* flags */
788 1 : tl_write_uint32(&w, TL_vector);
789 1 : tl_write_uint32(&w, 0); /* empty results */
790 1 : tl_write_int32 (&w, 555);
791 1 : TlReader r = tl_reader_init(w.data, w.len);
792 1 : ASSERT(tl_skip_message_reactions(&r) == 0, "empty reactions");
793 1 : ASSERT(tl_read_int32(&r) == 555, "cursor past reactions");
794 1 : tl_writer_free(&w);
795 : }
796 :
797 1 : static void test_skip_reactions_emoji_and_custom(void) {
798 1 : TlWriter w; tl_writer_init(&w);
799 1 : tl_write_uint32(&w, CRC_messageReactions_test);
800 1 : tl_write_uint32(&w, 0); /* flags */
801 1 : tl_write_uint32(&w, TL_vector);
802 1 : tl_write_uint32(&w, 2); /* 2 reaction counts */
803 :
804 : /* #1: emoji reaction, chosen_order set. */
805 1 : tl_write_uint32(&w, CRC_reactionCount_test);
806 1 : tl_write_uint32(&w, (1u << 0)); /* chosen_order present */
807 1 : tl_write_int32 (&w, 1); /* chosen_order */
808 1 : tl_write_uint32(&w, CRC_reactionEmoji_test);
809 1 : tl_write_string(&w, "\xf0\x9f\x91\x8d"); /* 👍 */
810 1 : tl_write_int32 (&w, 7); /* count */
811 :
812 : /* #2: custom emoji reaction, no chosen_order. */
813 1 : tl_write_uint32(&w, CRC_reactionCount_test);
814 1 : tl_write_uint32(&w, 0);
815 1 : tl_write_uint32(&w, CRC_reactionCustomEmoji_t);
816 1 : tl_write_int64 (&w, 0x1234567890abcdefLL);
817 1 : tl_write_int32 (&w, 3);
818 :
819 1 : tl_write_int32 (&w, 9999); /* trailer */
820 1 : TlReader r = tl_reader_init(w.data, w.len);
821 1 : ASSERT(tl_skip_message_reactions(&r) == 0, "reactions skipped");
822 1 : ASSERT(tl_read_int32(&r) == 9999, "cursor past reactions");
823 1 : tl_writer_free(&w);
824 : }
825 :
826 : /* ---- MessageReplies skipper ---- */
827 :
828 : #define CRC_messageReplies_test 0x83d60fc2u
829 :
830 1 : static void test_skip_message_replies_minimal(void) {
831 1 : TlWriter w; tl_writer_init(&w);
832 1 : tl_write_uint32(&w, CRC_messageReplies_test);
833 1 : tl_write_uint32(&w, 0); /* flags = 0 */
834 1 : tl_write_int32 (&w, 5); /* replies */
835 1 : tl_write_int32 (&w, 100); /* replies_pts */
836 1 : tl_write_int32 (&w, 0xCAFE); /* trailer */
837 1 : TlReader r = tl_reader_init(w.data, w.len);
838 1 : ASSERT(tl_skip_message_replies(&r) == 0, "minimal replies");
839 1 : ASSERT(tl_read_int32(&r) == 0xCAFE, "cursor past replies");
840 1 : tl_writer_free(&w);
841 : }
842 :
843 1 : static void test_skip_message_replies_with_commenters(void) {
844 1 : TlWriter w; tl_writer_init(&w);
845 1 : tl_write_uint32(&w, CRC_messageReplies_test);
846 1 : tl_write_uint32(&w, (1u << 0) | (1u << 1) | (1u << 2));
847 1 : tl_write_int32 (&w, 9); /* replies */
848 1 : tl_write_int32 (&w, 200); /* replies_pts */
849 : /* recent_repliers:Vector<Peer> = 2 peers */
850 1 : tl_write_uint32(&w, TL_vector);
851 1 : tl_write_uint32(&w, 2);
852 1 : tl_write_uint32(&w, TL_peerUser); tl_write_int64(&w, 111LL);
853 1 : tl_write_uint32(&w, TL_peerChannel); tl_write_int64(&w, 222LL);
854 1 : tl_write_int64 (&w, 0xDEADBEEFLL); /* channel_id */
855 1 : tl_write_int32 (&w, 2048); /* max_id */
856 1 : tl_write_int32 (&w, 1337); /* trailer */
857 1 : TlReader r = tl_reader_init(w.data, w.len);
858 1 : ASSERT(tl_skip_message_replies(&r) == 0, "full replies skipped");
859 1 : ASSERT(tl_read_int32(&r) == 1337, "cursor past replies");
860 1 : tl_writer_free(&w);
861 : }
862 :
863 1 : static void test_skip_message_replies_unknown_crc_bails(void) {
864 1 : TlWriter w; tl_writer_init(&w);
865 1 : tl_write_uint32(&w, 0xbadbadbu);
866 1 : TlReader r = tl_reader_init(w.data, w.len);
867 1 : ASSERT(tl_skip_message_replies(&r) == -1, "unknown crc rejected");
868 1 : tl_writer_free(&w);
869 : }
870 :
871 : /* ---- FactCheck skipper ---- */
872 :
873 : #define CRC_factCheck_test 0xb89bfccfu
874 : #define CRC_textWithEntities_test 0x751f3146u
875 :
876 1 : static void test_skip_factcheck_need_check_only(void) {
877 1 : TlWriter w; tl_writer_init(&w);
878 1 : tl_write_uint32(&w, CRC_factCheck_test);
879 1 : tl_write_uint32(&w, (1u << 0)); /* only need_check */
880 1 : tl_write_int64 (&w, 0x1234567890LL); /* hash */
881 1 : tl_write_int32 (&w, 777);
882 1 : TlReader r = tl_reader_init(w.data, w.len);
883 1 : ASSERT(tl_skip_factcheck(&r) == 0, "factcheck need_check skipped");
884 1 : ASSERT(tl_read_int32(&r) == 777, "cursor past factcheck");
885 1 : tl_writer_free(&w);
886 : }
887 :
888 1 : static void test_skip_factcheck_with_text(void) {
889 1 : TlWriter w; tl_writer_init(&w);
890 1 : tl_write_uint32(&w, CRC_factCheck_test);
891 1 : tl_write_uint32(&w, (1u << 1)); /* country + text set */
892 1 : tl_write_string(&w, "HU");
893 1 : tl_write_uint32(&w, CRC_textWithEntities_test);
894 1 : tl_write_string(&w, "Fact-checked claim");
895 1 : tl_write_uint32(&w, TL_vector);
896 1 : tl_write_uint32(&w, 1);
897 1 : tl_write_uint32(&w, 0xbd610bc9u); /* messageEntityBold */
898 1 : tl_write_int32 (&w, 0);
899 1 : tl_write_int32 (&w, 4);
900 1 : tl_write_int64 (&w, 0xabcdefLL); /* hash */
901 1 : tl_write_int32 (&w, 0x1234);
902 1 : TlReader r = tl_reader_init(w.data, w.len);
903 1 : ASSERT(tl_skip_factcheck(&r) == 0, "factcheck with text skipped");
904 1 : ASSERT(tl_read_int32(&r) == 0x1234, "cursor past factcheck");
905 1 : tl_writer_free(&w);
906 : }
907 :
908 : /* ---- messageMediaPoll ---- */
909 :
910 : #define CRC_messageMediaPoll_t 0x4bd6e798u
911 : #define CRC_poll_t 0x58747131u
912 : #define CRC_pollAnswer_t 0x6ca9c2e9u
913 : #define CRC_pollResults_t 0x7adc669du
914 : #define CRC_textWithEntities_p 0x751f3146u
915 :
916 5 : static void write_textWithEntities(TlWriter *w, const char *text) {
917 5 : tl_write_uint32(w, CRC_textWithEntities_p);
918 5 : tl_write_string(w, text);
919 5 : tl_write_uint32(w, TL_vector);
920 5 : tl_write_uint32(w, 0); /* no entities */
921 5 : }
922 :
923 1 : static void test_skip_media_poll_minimal(void) {
924 1 : TlWriter w; tl_writer_init(&w);
925 1 : tl_write_uint32(&w, CRC_messageMediaPoll_t);
926 : /* Poll */
927 1 : tl_write_uint32(&w, CRC_poll_t);
928 1 : tl_write_uint32(&w, 0); /* flags */
929 1 : tl_write_int64 (&w, 1234567LL); /* id */
930 1 : write_textWithEntities(&w, "Favourite colour?");
931 1 : tl_write_uint32(&w, TL_vector);
932 1 : tl_write_uint32(&w, 2);
933 1 : tl_write_uint32(&w, CRC_pollAnswer_t);
934 1 : write_textWithEntities(&w, "Blue");
935 1 : tl_write_string(&w, "b");
936 1 : tl_write_uint32(&w, CRC_pollAnswer_t);
937 1 : write_textWithEntities(&w, "Red");
938 1 : tl_write_string(&w, "r");
939 :
940 : /* PollResults: empty flags = no results, no voters, no solution */
941 1 : tl_write_uint32(&w, CRC_pollResults_t);
942 1 : tl_write_uint32(&w, 0); /* flags */
943 1 : tl_write_int32 (&w, 0xC0FFEE);
944 1 : TlReader r = tl_reader_init(w.data, w.len);
945 1 : MediaInfo mi = {0};
946 1 : ASSERT(tl_skip_message_media_ex(&r, &mi) == 0, "poll minimal ok");
947 1 : ASSERT(mi.kind == MEDIA_POLL, "kind = poll");
948 1 : ASSERT(tl_read_int32(&r) == 0xC0FFEE, "cursor past poll");
949 1 : tl_writer_free(&w);
950 : }
951 :
952 1 : static void test_skip_media_poll_with_results(void) {
953 1 : TlWriter w; tl_writer_init(&w);
954 1 : tl_write_uint32(&w, CRC_messageMediaPoll_t);
955 : /* Poll — quiz w/ close_date (flags.3 + flags.5) */
956 1 : tl_write_uint32(&w, CRC_poll_t);
957 1 : tl_write_uint32(&w, (1u << 3) | (1u << 5));
958 1 : tl_write_int64 (&w, 9LL);
959 1 : write_textWithEntities(&w, "2+2?");
960 1 : tl_write_uint32(&w, TL_vector);
961 1 : tl_write_uint32(&w, 1);
962 1 : tl_write_uint32(&w, CRC_pollAnswer_t);
963 1 : write_textWithEntities(&w, "4");
964 1 : tl_write_string(&w, "1");
965 1 : tl_write_int32 (&w, 1700000000); /* close_date */
966 :
967 : /* PollResults with results + total_voters + recent_voters + solution */
968 1 : tl_write_uint32(&w, CRC_pollResults_t);
969 1 : tl_write_uint32(&w, (1u << 1) | (1u << 2) | (1u << 3) | (1u << 4));
970 : /* results */
971 1 : tl_write_uint32(&w, TL_vector);
972 1 : tl_write_uint32(&w, 1);
973 1 : tl_write_uint32(&w, 0x3b6ddad2u); /* pollAnswerVoters */
974 1 : tl_write_uint32(&w, (1u << 0) | (1u << 1)); /* chosen + correct */
975 1 : tl_write_string(&w, "1"); /* option:bytes */
976 1 : tl_write_int32 (&w, 42); /* voters */
977 : /* total_voters */
978 1 : tl_write_int32 (&w, 42);
979 : /* recent_voters */
980 1 : tl_write_uint32(&w, TL_vector);
981 1 : tl_write_uint32(&w, 1);
982 1 : tl_write_uint32(&w, TL_peerUser);
983 1 : tl_write_int64 (&w, 999LL);
984 : /* solution + solution_entities */
985 1 : tl_write_string(&w, "Trivia says 4.");
986 1 : tl_write_uint32(&w, TL_vector);
987 1 : tl_write_uint32(&w, 0);
988 :
989 1 : tl_write_int32 (&w, 0xDEAD);
990 1 : TlReader r = tl_reader_init(w.data, w.len);
991 1 : MediaInfo mi = {0};
992 1 : ASSERT(tl_skip_message_media_ex(&r, &mi) == 0, "poll w/ results ok");
993 1 : ASSERT(mi.kind == MEDIA_POLL, "kind = poll");
994 1 : ASSERT(tl_read_int32(&r) == 0xDEAD, "cursor past poll");
995 1 : tl_writer_free(&w);
996 : }
997 :
998 : /* ---- messageMediaInvoice / Story / Giveaway ---- */
999 :
1000 : #define CRC_messageMediaInvoice_t 0xf6a548d3u
1001 : #define CRC_messageMediaStory_t 0x68cb6283u
1002 : #define CRC_messageMediaGiveaway_t 0xaa073beeu
1003 :
1004 1 : static void test_skip_media_invoice_minimal(void) {
1005 1 : TlWriter w; tl_writer_init(&w);
1006 1 : tl_write_uint32(&w, CRC_messageMediaInvoice_t);
1007 1 : tl_write_uint32(&w, 0); /* flags */
1008 1 : tl_write_string(&w, "Pizza Margherita");
1009 1 : tl_write_string(&w, "1 piece");
1010 1 : tl_write_string(&w, "EUR");
1011 1 : tl_write_int64 (&w, 999); /* cents */
1012 1 : tl_write_string(&w, "start_abc");
1013 1 : tl_write_int32 (&w, 0xBEEF);
1014 1 : TlReader r = tl_reader_init(w.data, w.len);
1015 1 : MediaInfo mi = {0};
1016 1 : ASSERT(tl_skip_message_media_ex(&r, &mi) == 0, "invoice minimal ok");
1017 1 : ASSERT(mi.kind == MEDIA_INVOICE, "kind=invoice");
1018 1 : ASSERT(tl_read_int32(&r) == 0xBEEF, "cursor past invoice");
1019 1 : tl_writer_free(&w);
1020 : }
1021 :
1022 1 : static void test_skip_media_invoice_photo_bails(void) {
1023 1 : TlWriter w; tl_writer_init(&w);
1024 1 : tl_write_uint32(&w, CRC_messageMediaInvoice_t);
1025 1 : tl_write_uint32(&w, (1u << 0)); /* photo flag */
1026 1 : tl_write_string(&w, "T"); tl_write_string(&w, "D");
1027 1 : TlReader r = tl_reader_init(w.data, w.len);
1028 1 : ASSERT(tl_skip_message_media_ex(&r, NULL) == -1,
1029 : "invoice photo still bails");
1030 1 : tl_writer_free(&w);
1031 : }
1032 :
1033 1 : static void test_skip_media_story_minimal(void) {
1034 1 : TlWriter w; tl_writer_init(&w);
1035 1 : tl_write_uint32(&w, CRC_messageMediaStory_t);
1036 1 : tl_write_uint32(&w, 0); /* flags */
1037 1 : tl_write_uint32(&w, TL_peerUser);
1038 1 : tl_write_int64 (&w, 42LL);
1039 1 : tl_write_int32 (&w, 77); /* story id */
1040 1 : tl_write_int32 (&w, 0x1010);
1041 1 : TlReader r = tl_reader_init(w.data, w.len);
1042 1 : MediaInfo mi = {0};
1043 1 : ASSERT(tl_skip_message_media_ex(&r, &mi) == 0, "story minimal ok");
1044 1 : ASSERT(mi.kind == MEDIA_STORY, "kind=story");
1045 1 : ASSERT(tl_read_int32(&r) == 0x1010, "cursor past story");
1046 1 : tl_writer_free(&w);
1047 : }
1048 :
1049 1 : static void test_skip_media_giveaway_minimal(void) {
1050 1 : TlWriter w; tl_writer_init(&w);
1051 1 : tl_write_uint32(&w, CRC_messageMediaGiveaway_t);
1052 1 : tl_write_uint32(&w, 0); /* flags */
1053 : /* channels vector */
1054 1 : tl_write_uint32(&w, TL_vector);
1055 1 : tl_write_uint32(&w, 2);
1056 1 : tl_write_int64 (&w, 10LL);
1057 1 : tl_write_int64 (&w, 20LL);
1058 1 : tl_write_int32 (&w, 5); /* quantity */
1059 1 : tl_write_int32 (&w, 1700000999); /* until_date */
1060 1 : tl_write_int32 (&w, 0xFACE);
1061 1 : TlReader r = tl_reader_init(w.data, w.len);
1062 1 : MediaInfo mi = {0};
1063 1 : ASSERT(tl_skip_message_media_ex(&r, &mi) == 0, "giveaway minimal ok");
1064 1 : ASSERT(mi.kind == MEDIA_GIVEAWAY, "kind=giveaway");
1065 1 : ASSERT(tl_read_int32(&r) == 0xFACE, "cursor past giveaway");
1066 1 : tl_writer_free(&w);
1067 : }
1068 :
1069 1 : static void test_skip_media_giveaway_countries_prize(void) {
1070 1 : TlWriter w; tl_writer_init(&w);
1071 1 : tl_write_uint32(&w, CRC_messageMediaGiveaway_t);
1072 1 : tl_write_uint32(&w, (1u << 1) | (1u << 3) | (1u << 4));
1073 1 : tl_write_uint32(&w, TL_vector);
1074 1 : tl_write_uint32(&w, 1);
1075 1 : tl_write_int64 (&w, 99LL);
1076 : /* countries_iso2 */
1077 1 : tl_write_uint32(&w, TL_vector);
1078 1 : tl_write_uint32(&w, 2);
1079 1 : tl_write_string(&w, "HU");
1080 1 : tl_write_string(&w, "DE");
1081 : /* prize_description */
1082 1 : tl_write_string(&w, "Premium subscription");
1083 1 : tl_write_int32 (&w, 10); /* quantity */
1084 1 : tl_write_int32 (&w, 3); /* months (flag.4) */
1085 1 : tl_write_int32 (&w, 1700001000); /* until_date */
1086 1 : tl_write_int32 (&w, 0xEEEE);
1087 1 : TlReader r = tl_reader_init(w.data, w.len);
1088 1 : ASSERT(tl_skip_message_media_ex(&r, NULL) == 0, "giveaway rich ok");
1089 1 : ASSERT(tl_read_int32(&r) == 0xEEEE, "cursor past giveaway");
1090 1 : tl_writer_free(&w);
1091 : }
1092 :
1093 : /* ---- messageMediaDocument with full Document ---- */
1094 :
1095 : #define CRC_messageMediaDocument_t 0x4cf4d72du
1096 : #define CRC_document_t 0x8fd4c4d8u
1097 : #define CRC_documentAttributeFilename_t 0x15590068u
1098 :
1099 1 : static void test_skip_media_document_full(void) {
1100 1 : TlWriter w; tl_writer_init(&w);
1101 1 : tl_write_uint32(&w, CRC_messageMediaDocument_t);
1102 1 : tl_write_uint32(&w, (1u << 0)); /* document present */
1103 1 : tl_write_uint32(&w, CRC_document_t);
1104 1 : tl_write_uint32(&w, 0); /* flags (no thumbs) */
1105 1 : tl_write_int64 (&w, 5551212LL);
1106 1 : tl_write_int64 (&w, 0xCAFECAFEDEADBEEFLL);
1107 1 : uint8_t fr[4] = { 0x01, 0x02, 0x03, 0x04 };
1108 1 : tl_write_bytes (&w, fr, sizeof(fr));
1109 1 : tl_write_int32 (&w, 1700000000); /* date */
1110 1 : tl_write_string(&w, "application/pdf");
1111 1 : tl_write_int64 (&w, 1024LL); /* size */
1112 1 : tl_write_int32 (&w, 2); /* dc_id */
1113 1 : tl_write_uint32(&w, TL_vector);
1114 1 : tl_write_uint32(&w, 1); /* one attribute */
1115 1 : tl_write_uint32(&w, CRC_documentAttributeFilename_t);
1116 1 : tl_write_string(&w, "report.pdf");
1117 1 : tl_write_int32 (&w, 0xfeed); /* trailer */
1118 1 : TlReader r = tl_reader_init(w.data, w.len);
1119 1 : MediaInfo mi = {0};
1120 1 : ASSERT(tl_skip_message_media_ex(&r, &mi) == 0, "document extract ok");
1121 1 : ASSERT(mi.kind == MEDIA_DOCUMENT, "kind=document");
1122 1 : ASSERT(mi.document_id == 5551212LL, "document_id captured");
1123 1 : ASSERT(mi.access_hash == (int64_t)0xCAFECAFEDEADBEEFLL, "access_hash");
1124 1 : ASSERT(mi.file_reference_len == 4, "file_reference_len");
1125 1 : ASSERT(mi.file_reference[0] == 0x01 && mi.file_reference[3] == 0x04,
1126 : "file_reference bytes");
1127 1 : ASSERT(mi.document_size == 1024, "size captured");
1128 1 : ASSERT(strcmp(mi.document_mime, "application/pdf") == 0, "mime");
1129 1 : ASSERT(strcmp(mi.document_filename, "report.pdf") == 0, "filename");
1130 1 : ASSERT(tl_read_int32(&r) == 0xfeed, "cursor past document");
1131 1 : tl_writer_free(&w);
1132 : }
1133 :
1134 : /* LIM-02: Document with thumbs (Vector<PhotoSize>) set via flags.0. */
1135 : #define CRC_photoSize_t 0x75c78e60u
1136 1 : static void test_skip_media_document_with_thumbs(void) {
1137 1 : TlWriter w; tl_writer_init(&w);
1138 1 : tl_write_uint32(&w, CRC_messageMediaDocument_t);
1139 1 : tl_write_uint32(&w, (1u << 0));
1140 1 : tl_write_uint32(&w, CRC_document_t);
1141 1 : tl_write_uint32(&w, (1u << 0)); /* thumbs present */
1142 1 : tl_write_int64 (&w, 777LL);
1143 1 : tl_write_int64 (&w, 888LL);
1144 1 : uint8_t fr[2] = { 0xaa, 0xbb };
1145 1 : tl_write_bytes (&w, fr, sizeof(fr));
1146 1 : tl_write_int32 (&w, 1700000000);
1147 1 : tl_write_string(&w, "video/mp4");
1148 1 : tl_write_int64 (&w, 42LL);
1149 : /* thumbs: [photoSize "m" 320x240 size=1234] */
1150 1 : tl_write_uint32(&w, TL_vector);
1151 1 : tl_write_uint32(&w, 1);
1152 1 : tl_write_uint32(&w, CRC_photoSize_t);
1153 1 : tl_write_string(&w, "m");
1154 1 : tl_write_int32 (&w, 320);
1155 1 : tl_write_int32 (&w, 240);
1156 1 : tl_write_int32 (&w, 1234);
1157 1 : tl_write_int32 (&w, 4); /* dc_id */
1158 1 : tl_write_uint32(&w, TL_vector);
1159 1 : tl_write_uint32(&w, 0); /* no attributes */
1160 1 : tl_write_int32 (&w, 0x1234);
1161 1 : TlReader r = tl_reader_init(w.data, w.len);
1162 1 : MediaInfo mi = {0};
1163 1 : ASSERT(tl_skip_message_media_ex(&r, &mi) == 0,
1164 : "document with thumbs iterates");
1165 1 : ASSERT(mi.kind == MEDIA_DOCUMENT, "kind=document");
1166 1 : ASSERT(mi.document_id == 777LL, "id");
1167 1 : ASSERT(tl_read_int32(&r) == 0x1234, "cursor past document");
1168 1 : tl_writer_free(&w);
1169 : }
1170 :
1171 : /* LIM-02: Document with video_thumbs (Vector<VideoSize>). */
1172 : #define CRC_videoSize_t 0xde33b094u
1173 1 : static void test_skip_media_document_with_video_thumbs(void) {
1174 1 : TlWriter w; tl_writer_init(&w);
1175 1 : tl_write_uint32(&w, CRC_messageMediaDocument_t);
1176 1 : tl_write_uint32(&w, (1u << 0));
1177 1 : tl_write_uint32(&w, CRC_document_t);
1178 1 : tl_write_uint32(&w, (1u << 1)); /* video_thumbs present */
1179 1 : tl_write_int64 (&w, 99LL);
1180 1 : tl_write_int64 (&w, 100LL);
1181 1 : uint8_t fr[1] = { 0x01 };
1182 1 : tl_write_bytes (&w, fr, sizeof(fr));
1183 1 : tl_write_int32 (&w, 1700000000);
1184 1 : tl_write_string(&w, "video/mp4");
1185 1 : tl_write_int64 (&w, 999LL);
1186 : /* video_thumbs: [videoSize flags=0 "u" 100x100 size=50] */
1187 1 : tl_write_uint32(&w, TL_vector);
1188 1 : tl_write_uint32(&w, 1);
1189 1 : tl_write_uint32(&w, CRC_videoSize_t);
1190 1 : tl_write_uint32(&w, 0);
1191 1 : tl_write_string(&w, "u");
1192 1 : tl_write_int32 (&w, 100);
1193 1 : tl_write_int32 (&w, 100);
1194 1 : tl_write_int32 (&w, 50);
1195 1 : tl_write_int32 (&w, 2); /* dc_id */
1196 1 : tl_write_uint32(&w, TL_vector);
1197 1 : tl_write_uint32(&w, 0);
1198 1 : tl_write_int32 (&w, 0x5678);
1199 1 : TlReader r = tl_reader_init(w.data, w.len);
1200 1 : MediaInfo mi = {0};
1201 1 : ASSERT(tl_skip_message_media_ex(&r, &mi) == 0,
1202 : "document with video_thumbs iterates");
1203 1 : ASSERT(mi.kind == MEDIA_DOCUMENT, "kind=document");
1204 1 : ASSERT(tl_read_int32(&r) == 0x5678, "cursor past document");
1205 1 : tl_writer_free(&w);
1206 : }
1207 :
1208 : /* LIM-02: Document with documentAttributeSticker (inputStickerSetID). */
1209 : #define CRC_documentAttributeSticker_t 0x6319d612u
1210 : #define CRC_inputStickerSetID_t 0x9de7a269u
1211 : #define CRC_inputStickerSetEmpty_t 0xffb62b95u
1212 : #define CRC_maskCoords_t 0xaed6dbb2u
1213 1 : static void test_skip_media_document_sticker_attr(void) {
1214 1 : TlWriter w; tl_writer_init(&w);
1215 1 : tl_write_uint32(&w, CRC_messageMediaDocument_t);
1216 1 : tl_write_uint32(&w, (1u << 0));
1217 1 : tl_write_uint32(&w, CRC_document_t);
1218 1 : tl_write_uint32(&w, 0); /* no thumbs */
1219 1 : tl_write_int64 (&w, 1);
1220 1 : tl_write_int64 (&w, 2);
1221 1 : uint8_t fr[1] = { 0 };
1222 1 : tl_write_bytes (&w, fr, sizeof(fr));
1223 1 : tl_write_int32 (&w, 1700000000);
1224 1 : tl_write_string(&w, "image/webp");
1225 1 : tl_write_int64 (&w, 5000);
1226 1 : tl_write_int32 (&w, 2);
1227 1 : tl_write_uint32(&w, TL_vector);
1228 1 : tl_write_uint32(&w, 1);
1229 1 : tl_write_uint32(&w, CRC_documentAttributeSticker_t);
1230 1 : tl_write_uint32(&w, 0); /* no mask, no mask_coords */
1231 1 : tl_write_string(&w, "🦊"); /* alt */
1232 1 : tl_write_uint32(&w, CRC_inputStickerSetID_t);
1233 1 : tl_write_int64 (&w, 42);
1234 1 : tl_write_int64 (&w, 43);
1235 1 : tl_write_int32 (&w, 0x9ABC);
1236 1 : TlReader r = tl_reader_init(w.data, w.len);
1237 1 : MediaInfo mi = {0};
1238 1 : ASSERT(tl_skip_message_media_ex(&r, &mi) == 0,
1239 : "document with Sticker attr iterates");
1240 1 : ASSERT(mi.kind == MEDIA_DOCUMENT, "kind=document");
1241 1 : ASSERT(tl_read_int32(&r) == 0x9ABC, "cursor past document");
1242 1 : tl_writer_free(&w);
1243 : }
1244 :
1245 : /* LIM-02: Document with documentAttributeSticker + mask_coords. */
1246 1 : static void test_skip_media_document_sticker_with_mask(void) {
1247 1 : TlWriter w; tl_writer_init(&w);
1248 1 : tl_write_uint32(&w, CRC_messageMediaDocument_t);
1249 1 : tl_write_uint32(&w, (1u << 0));
1250 1 : tl_write_uint32(&w, CRC_document_t);
1251 1 : tl_write_uint32(&w, 0);
1252 1 : tl_write_int64 (&w, 1);
1253 1 : tl_write_int64 (&w, 2);
1254 1 : uint8_t fr[1] = { 0 };
1255 1 : tl_write_bytes (&w, fr, sizeof(fr));
1256 1 : tl_write_int32 (&w, 1700000000);
1257 1 : tl_write_string(&w, "image/webp");
1258 1 : tl_write_int64 (&w, 5000);
1259 1 : tl_write_int32 (&w, 2);
1260 1 : tl_write_uint32(&w, TL_vector);
1261 1 : tl_write_uint32(&w, 1);
1262 1 : tl_write_uint32(&w, CRC_documentAttributeSticker_t);
1263 1 : tl_write_uint32(&w, (1u << 0)); /* mask_coords present */
1264 1 : tl_write_string(&w, "😀");
1265 1 : tl_write_uint32(&w, CRC_inputStickerSetEmpty_t);
1266 1 : tl_write_uint32(&w, CRC_maskCoords_t);
1267 1 : tl_write_int32 (&w, 1); /* n */
1268 1 : tl_write_double(&w, 0.5); /* x */
1269 1 : tl_write_double(&w, 0.25); /* y */
1270 1 : tl_write_double(&w, 1.5); /* zoom */
1271 1 : tl_write_int32 (&w, 0xDEF0);
1272 1 : TlReader r = tl_reader_init(w.data, w.len);
1273 1 : ASSERT(tl_skip_message_media_ex(&r, NULL) == 0,
1274 : "sticker + mask_coords iterates");
1275 1 : ASSERT(tl_read_int32(&r) == 0xDEF0, "cursor past document");
1276 1 : tl_writer_free(&w);
1277 : }
1278 :
1279 : /* LIM-02: Document with documentAttributeCustomEmoji. */
1280 : #define CRC_documentAttributeCustomEmoji_t 0xfd149899u
1281 : #define CRC_inputStickerSetShortName_t 0x861cc8a0u
1282 1 : static void test_skip_media_document_custom_emoji_attr(void) {
1283 1 : TlWriter w; tl_writer_init(&w);
1284 1 : tl_write_uint32(&w, CRC_messageMediaDocument_t);
1285 1 : tl_write_uint32(&w, (1u << 0));
1286 1 : tl_write_uint32(&w, CRC_document_t);
1287 1 : tl_write_uint32(&w, 0);
1288 1 : tl_write_int64 (&w, 11);
1289 1 : tl_write_int64 (&w, 22);
1290 1 : uint8_t fr[1] = { 0 };
1291 1 : tl_write_bytes (&w, fr, sizeof(fr));
1292 1 : tl_write_int32 (&w, 1700000000);
1293 1 : tl_write_string(&w, "image/webp");
1294 1 : tl_write_int64 (&w, 123);
1295 1 : tl_write_int32 (&w, 2);
1296 1 : tl_write_uint32(&w, TL_vector);
1297 1 : tl_write_uint32(&w, 1);
1298 1 : tl_write_uint32(&w, CRC_documentAttributeCustomEmoji_t);
1299 1 : tl_write_uint32(&w, 0);
1300 1 : tl_write_string(&w, "⚡");
1301 1 : tl_write_uint32(&w, CRC_inputStickerSetShortName_t);
1302 1 : tl_write_string(&w, "animated_pack");
1303 1 : tl_write_int32 (&w, 0xFACE);
1304 1 : TlReader r = tl_reader_init(w.data, w.len);
1305 1 : ASSERT(tl_skip_message_media_ex(&r, NULL) == 0,
1306 : "document with CustomEmoji attr iterates");
1307 1 : ASSERT(tl_read_int32(&r) == 0xFACE, "cursor past document");
1308 1 : tl_writer_free(&w);
1309 : }
1310 :
1311 : /* ---- MessageMediaWebPage ---- */
1312 :
1313 : #define CRC_messageMediaWebPage_test 0xddf8c26eu
1314 : #define CRC_webPage_test 0xe89c45b2u
1315 : #define CRC_webPageEmpty_test 0xeb1477e8u
1316 : #define CRC_webPagePending_test 0xb0d13e47u
1317 :
1318 1 : static void test_skip_media_webpage_empty(void) {
1319 1 : TlWriter w; tl_writer_init(&w);
1320 1 : tl_write_uint32(&w, CRC_messageMediaWebPage_test);
1321 1 : tl_write_uint32(&w, 0); /* outer flags */
1322 1 : tl_write_uint32(&w, CRC_webPageEmpty_test);
1323 1 : tl_write_uint32(&w, (1u << 0)); /* url flag */
1324 1 : tl_write_int64 (&w, 0x123LL);
1325 1 : tl_write_string(&w, "https://example.com");
1326 1 : tl_write_int32 (&w, 42);
1327 1 : TlReader r = tl_reader_init(w.data, w.len);
1328 1 : MediaInfo mi = {0};
1329 1 : ASSERT(tl_skip_message_media_ex(&r, &mi) == 0, "webpage empty ok");
1330 1 : ASSERT(mi.kind == MEDIA_WEBPAGE, "kind == webpage");
1331 1 : ASSERT(tl_read_int32(&r) == 42, "cursor past webpage");
1332 1 : tl_writer_free(&w);
1333 : }
1334 :
1335 1 : static void test_skip_media_webpage_rich(void) {
1336 : /* webPage with url + display_url + hash + site_name + title. */
1337 1 : TlWriter w; tl_writer_init(&w);
1338 1 : tl_write_uint32(&w, CRC_messageMediaWebPage_test);
1339 1 : tl_write_uint32(&w, 0); /* outer flags */
1340 1 : tl_write_uint32(&w, CRC_webPage_test);
1341 1 : tl_write_uint32(&w, (1u << 1) | (1u << 2)); /* site_name + title */
1342 1 : tl_write_int64 (&w, 0xABC);
1343 1 : tl_write_string(&w, "https://example.com/page");
1344 1 : tl_write_string(&w, "example.com/page");
1345 1 : tl_write_int32 (&w, 12345); /* hash */
1346 1 : tl_write_string(&w, "Example"); /* site_name */
1347 1 : tl_write_string(&w, "A Title"); /* title */
1348 1 : tl_write_int32 (&w, 0xdead); /* trailer */
1349 1 : TlReader r = tl_reader_init(w.data, w.len);
1350 1 : MediaInfo mi = {0};
1351 1 : ASSERT(tl_skip_message_media_ex(&r, &mi) == 0, "webpage rich ok");
1352 1 : ASSERT(mi.kind == MEDIA_WEBPAGE, "kind == webpage");
1353 1 : ASSERT(tl_read_int32(&r) == 0xdead, "cursor past webpage");
1354 1 : tl_writer_free(&w);
1355 : }
1356 :
1357 1 : static void test_skip_media_webpage_pending(void) {
1358 1 : TlWriter w; tl_writer_init(&w);
1359 1 : tl_write_uint32(&w, CRC_messageMediaWebPage_test);
1360 1 : tl_write_uint32(&w, 0);
1361 1 : tl_write_uint32(&w, CRC_webPagePending_test);
1362 1 : tl_write_uint32(&w, (1u << 0)); /* url */
1363 1 : tl_write_int64 (&w, 0x999);
1364 1 : tl_write_string(&w, "https://pending.example");
1365 1 : tl_write_int32 (&w, 1700000000);
1366 1 : tl_write_int32 (&w, 0xCAFE);
1367 1 : TlReader r = tl_reader_init(w.data, w.len);
1368 1 : MediaInfo mi = {0};
1369 1 : ASSERT(tl_skip_message_media_ex(&r, &mi) == 0, "webpage pending ok");
1370 1 : ASSERT(tl_read_int32(&r) == 0xCAFE, "cursor past pending");
1371 1 : tl_writer_free(&w);
1372 : }
1373 :
1374 : /* TUI-11: webPage with cached_page set, Page contains two simple
1375 : * PageBlock rows (title + paragraph). Skipper must iterate past them. */
1376 : #define CRC_page_test 0x98657f0du
1377 : #define CRC_pageBlockTitle_test 0x70abc3fdu
1378 : #define CRC_pageBlockParagraph_test 0x467a0766u
1379 : #define CRC_pageBlockDivider_test 0xdb20b188u
1380 : #define CRC_pageBlockAnchor_test 0xce0d37b0u
1381 : #define CRC_pageBlockAuthorDate_t 0xbaafe5e0u
1382 : #define CRC_textPlain_test 0x744694e0u
1383 : #define CRC_textEmpty_test 0xdc3d824fu
1384 : #define CRC_textBold_test 0x6724abc4u
1385 : #define CRC_textConcat_test 0x7e6260d7u
1386 :
1387 1 : static void test_skip_media_webpage_cached_page_simple(void) {
1388 1 : TlWriter w; tl_writer_init(&w);
1389 1 : tl_write_uint32(&w, CRC_messageMediaWebPage_test);
1390 1 : tl_write_uint32(&w, 0);
1391 1 : tl_write_uint32(&w, CRC_webPage_test);
1392 1 : tl_write_uint32(&w, (1u << 10)); /* cached_page flag */
1393 1 : tl_write_int64 (&w, 0x111);
1394 1 : tl_write_string(&w, "u");
1395 1 : tl_write_string(&w, "u");
1396 1 : tl_write_int32 (&w, 1); /* hash */
1397 : /* cached_page body — page#98657f0d. */
1398 1 : tl_write_uint32(&w, CRC_page_test);
1399 1 : tl_write_uint32(&w, 0); /* page flags */
1400 1 : tl_write_string(&w, "https://x/a"); /* url */
1401 : /* blocks: [Title(plain), Paragraph(bold(plain)), Divider, Anchor] */
1402 1 : tl_write_uint32(&w, TL_vector);
1403 1 : tl_write_uint32(&w, 4);
1404 : /* block 0: Title(textPlain) */
1405 1 : tl_write_uint32(&w, CRC_pageBlockTitle_test);
1406 1 : tl_write_uint32(&w, CRC_textPlain_test);
1407 1 : tl_write_string(&w, "The Article");
1408 : /* block 1: Paragraph(textBold(textPlain)) */
1409 1 : tl_write_uint32(&w, CRC_pageBlockParagraph_test);
1410 1 : tl_write_uint32(&w, CRC_textBold_test);
1411 1 : tl_write_uint32(&w, CRC_textPlain_test);
1412 1 : tl_write_string(&w, "Body");
1413 : /* block 2: Divider */
1414 1 : tl_write_uint32(&w, CRC_pageBlockDivider_test);
1415 : /* block 3: Anchor */
1416 1 : tl_write_uint32(&w, CRC_pageBlockAnchor_test);
1417 1 : tl_write_string(&w, "section-1");
1418 : /* photos: empty */
1419 1 : tl_write_uint32(&w, TL_vector);
1420 1 : tl_write_uint32(&w, 0);
1421 : /* documents: empty */
1422 1 : tl_write_uint32(&w, TL_vector);
1423 1 : tl_write_uint32(&w, 0);
1424 : /* sentinel past the whole media */
1425 1 : tl_write_int32(&w, 0xFACE);
1426 1 : TlReader r = tl_reader_init(w.data, w.len);
1427 1 : MediaInfo mi = {0};
1428 1 : ASSERT(tl_skip_message_media_ex(&r, &mi) == 0, "cached_page iterates");
1429 1 : ASSERT(mi.kind == MEDIA_WEBPAGE, "kind=webpage");
1430 1 : ASSERT(tl_read_int32(&r) == 0xFACE, "cursor past whole media");
1431 1 : tl_writer_free(&w);
1432 : }
1433 :
1434 : /* TUI-11: same but with textConcat (vector of RichTexts). */
1435 1 : static void test_skip_media_webpage_cached_page_textconcat(void) {
1436 1 : TlWriter w; tl_writer_init(&w);
1437 1 : tl_write_uint32(&w, CRC_messageMediaWebPage_test);
1438 1 : tl_write_uint32(&w, 0);
1439 1 : tl_write_uint32(&w, CRC_webPage_test);
1440 1 : tl_write_uint32(&w, (1u << 10));
1441 1 : tl_write_int64 (&w, 0x222);
1442 1 : tl_write_string(&w, "u");
1443 1 : tl_write_string(&w, "u");
1444 1 : tl_write_int32 (&w, 1);
1445 1 : tl_write_uint32(&w, CRC_page_test);
1446 1 : tl_write_uint32(&w, 0);
1447 1 : tl_write_string(&w, "x");
1448 1 : tl_write_uint32(&w, TL_vector);
1449 1 : tl_write_uint32(&w, 1);
1450 : /* block: Paragraph(textConcat([textPlain, textEmpty])) */
1451 1 : tl_write_uint32(&w, CRC_pageBlockParagraph_test);
1452 1 : tl_write_uint32(&w, CRC_textConcat_test);
1453 1 : tl_write_uint32(&w, TL_vector);
1454 1 : tl_write_uint32(&w, 2);
1455 1 : tl_write_uint32(&w, CRC_textPlain_test);
1456 1 : tl_write_string(&w, "foo");
1457 1 : tl_write_uint32(&w, CRC_textEmpty_test);
1458 1 : tl_write_uint32(&w, TL_vector); tl_write_uint32(&w, 0); /* photos */
1459 1 : tl_write_uint32(&w, TL_vector); tl_write_uint32(&w, 0); /* documents */
1460 1 : tl_write_int32(&w, 0xDEAD);
1461 1 : TlReader r = tl_reader_init(w.data, w.len);
1462 1 : ASSERT(tl_skip_message_media_ex(&r, NULL) == 0, "textConcat iterates");
1463 1 : ASSERT(tl_read_int32(&r) == 0xDEAD, "cursor past media");
1464 1 : tl_writer_free(&w);
1465 : }
1466 :
1467 : /* LIM-03: PageBlock CRCs beyond the TUI-11 whitelist. */
1468 : #define CRC_pageCaption_t 0x6f747657u
1469 : #define CRC_pageBlockBlockquote_t 0x263d7c26u
1470 : #define CRC_pageBlockPullquote_t 0x4f4456d5u
1471 : #define CRC_pageBlockPhoto_t 0x1759c560u
1472 : #define CRC_pageBlockVideo_t 0x7c8fe7b6u
1473 : #define CRC_pageBlockAudio_t 0x804361eau
1474 : #define CRC_pageBlockCover_t 0x39f23300u
1475 : #define CRC_pageBlockChannel_t 0xef1751b5u
1476 : #define CRC_pageBlockMap_t 0xa44f3ef6u
1477 : #define CRC_pageBlockList_t 0xe4e88011u
1478 : #define CRC_pageBlockOrderedList_t 0x9a8ae1e1u
1479 : #define CRC_pageBlockCollage_t 0x65a0fa4du
1480 : #define CRC_pageBlockSlideshow_t 0x031f9590u
1481 : #define CRC_pageBlockDetails_t 0x76768bedu
1482 : #define CRC_pageBlockRelatedArticles_t 0x16115a96u
1483 : #define CRC_pageBlockTable_t 0xbf4dea82u
1484 : #define CRC_pageBlockEmbed_t 0xa8718dc5u
1485 : #define CRC_pageBlockEmbedPost_t 0xf259a80bu
1486 : #define CRC_pageListItemText_t 0xb92fb6cdu
1487 : #define CRC_pageListItemBlocks_t 0x25e073fcu
1488 : #define CRC_pageListOrderedItemText_t 0x5e068047u
1489 : #define CRC_pageTableRow_t 0xe0c0c5e5u
1490 : #define CRC_pageTableCell_t 0x34566b6au
1491 : #define CRC_pageRelatedArticle_t 0xb390dc08u
1492 : #define CRC_geoPointEmpty_t 0x1117dd5fu
1493 : #define CRC_chatEmpty_t 0x29562865u
1494 :
1495 : /* Helper: wraps @p builder output into messageMediaWebPage + webPage
1496 : * with flags.10 (cached_page) set, writes sentinel 0xCAFE after.
1497 : * @p builder emits the Page body (flags, url, vectors). */
1498 16 : static void run_cached_page_roundtrip(void (*builder)(TlWriter *)) {
1499 16 : TlWriter w; tl_writer_init(&w);
1500 16 : tl_write_uint32(&w, CRC_messageMediaWebPage_test);
1501 16 : tl_write_uint32(&w, 0);
1502 16 : tl_write_uint32(&w, CRC_webPage_test);
1503 16 : tl_write_uint32(&w, (1u << 10));
1504 16 : tl_write_int64 (&w, 1);
1505 16 : tl_write_string(&w, "u");
1506 16 : tl_write_string(&w, "u");
1507 16 : tl_write_int32 (&w, 1);
1508 : /* Page wrapper. */
1509 16 : tl_write_uint32(&w, CRC_page_test);
1510 16 : tl_write_uint32(&w, 0);
1511 16 : tl_write_string(&w, "x");
1512 16 : builder(&w);
1513 : /* photos + documents — empty. */
1514 16 : tl_write_uint32(&w, TL_vector); tl_write_uint32(&w, 0);
1515 16 : tl_write_uint32(&w, TL_vector); tl_write_uint32(&w, 0);
1516 16 : tl_write_int32(&w, 0xCAFE);
1517 16 : TlReader r = tl_reader_init(w.data, w.len);
1518 16 : ASSERT(tl_skip_message_media_ex(&r, NULL) == 0, "cached_page iterates");
1519 16 : ASSERT(tl_read_int32(&r) == 0xCAFE, "cursor past media");
1520 16 : tl_writer_free(&w);
1521 : }
1522 :
1523 8 : static void empty_caption(TlWriter *w) {
1524 8 : tl_write_uint32(w, CRC_pageCaption_t);
1525 8 : tl_write_uint32(w, CRC_textEmpty_test);
1526 8 : tl_write_uint32(w, CRC_textEmpty_test);
1527 8 : }
1528 :
1529 1 : static void build_blockquote(TlWriter *w) {
1530 1 : tl_write_uint32(w, TL_vector); tl_write_uint32(w, 1);
1531 1 : tl_write_uint32(w, CRC_pageBlockBlockquote_t);
1532 1 : tl_write_uint32(w, CRC_textPlain_test); tl_write_string(w, "quote");
1533 1 : tl_write_uint32(w, CRC_textPlain_test); tl_write_string(w, "credit");
1534 1 : }
1535 1 : static void test_skip_cached_page_blockquote(void) {
1536 1 : run_cached_page_roundtrip(build_blockquote);
1537 1 : }
1538 :
1539 1 : static void build_photo_block(TlWriter *w) {
1540 1 : tl_write_uint32(w, TL_vector); tl_write_uint32(w, 1);
1541 1 : tl_write_uint32(w, CRC_pageBlockPhoto_t);
1542 1 : tl_write_uint32(w, 0); /* no url */
1543 1 : tl_write_int64 (w, 99LL);
1544 1 : empty_caption(w);
1545 1 : }
1546 1 : static void test_skip_cached_page_photo(void) {
1547 1 : run_cached_page_roundtrip(build_photo_block);
1548 1 : }
1549 :
1550 1 : static void build_video_block(TlWriter *w) {
1551 1 : tl_write_uint32(w, TL_vector); tl_write_uint32(w, 1);
1552 1 : tl_write_uint32(w, CRC_pageBlockVideo_t);
1553 1 : tl_write_uint32(w, 0);
1554 1 : tl_write_int64 (w, 42LL);
1555 1 : empty_caption(w);
1556 1 : }
1557 1 : static void test_skip_cached_page_video(void) {
1558 1 : run_cached_page_roundtrip(build_video_block);
1559 1 : }
1560 :
1561 1 : static void build_audio_block(TlWriter *w) {
1562 1 : tl_write_uint32(w, TL_vector); tl_write_uint32(w, 1);
1563 1 : tl_write_uint32(w, CRC_pageBlockAudio_t);
1564 1 : tl_write_int64 (w, 7LL);
1565 1 : empty_caption(w);
1566 1 : }
1567 1 : static void test_skip_cached_page_audio(void) {
1568 1 : run_cached_page_roundtrip(build_audio_block);
1569 1 : }
1570 :
1571 1 : static void build_cover_block(TlWriter *w) {
1572 1 : tl_write_uint32(w, TL_vector); tl_write_uint32(w, 1);
1573 1 : tl_write_uint32(w, CRC_pageBlockCover_t);
1574 : /* nested: paragraph(textEmpty) */
1575 1 : tl_write_uint32(w, CRC_pageBlockParagraph_test);
1576 1 : tl_write_uint32(w, CRC_textEmpty_test);
1577 1 : }
1578 1 : static void test_skip_cached_page_cover(void) {
1579 1 : run_cached_page_roundtrip(build_cover_block);
1580 1 : }
1581 :
1582 1 : static void build_channel_block(TlWriter *w) {
1583 1 : tl_write_uint32(w, TL_vector); tl_write_uint32(w, 1);
1584 1 : tl_write_uint32(w, CRC_pageBlockChannel_t);
1585 1 : tl_write_uint32(w, CRC_chatEmpty_t);
1586 1 : tl_write_int64 (w, 123LL);
1587 1 : }
1588 1 : static void test_skip_cached_page_channel(void) {
1589 1 : run_cached_page_roundtrip(build_channel_block);
1590 1 : }
1591 :
1592 1 : static void build_map_block(TlWriter *w) {
1593 1 : tl_write_uint32(w, TL_vector); tl_write_uint32(w, 1);
1594 1 : tl_write_uint32(w, CRC_pageBlockMap_t);
1595 1 : tl_write_uint32(w, CRC_geoPointEmpty_t);
1596 1 : tl_write_int32 (w, 14); /* zoom */
1597 1 : tl_write_int32 (w, 800); /* w */
1598 1 : tl_write_int32 (w, 600); /* h */
1599 1 : empty_caption(w);
1600 1 : }
1601 1 : static void test_skip_cached_page_map(void) {
1602 1 : run_cached_page_roundtrip(build_map_block);
1603 1 : }
1604 :
1605 1 : static void build_list_block(TlWriter *w) {
1606 1 : tl_write_uint32(w, TL_vector); tl_write_uint32(w, 1);
1607 1 : tl_write_uint32(w, CRC_pageBlockList_t);
1608 1 : tl_write_uint32(w, TL_vector); tl_write_uint32(w, 2);
1609 1 : tl_write_uint32(w, CRC_pageListItemText_t);
1610 1 : tl_write_uint32(w, CRC_textPlain_test); tl_write_string(w, "one");
1611 1 : tl_write_uint32(w, CRC_pageListItemBlocks_t);
1612 1 : tl_write_uint32(w, TL_vector); tl_write_uint32(w, 1);
1613 1 : tl_write_uint32(w, CRC_pageBlockParagraph_test);
1614 1 : tl_write_uint32(w, CRC_textPlain_test); tl_write_string(w, "two");
1615 1 : }
1616 1 : static void test_skip_cached_page_list(void) {
1617 1 : run_cached_page_roundtrip(build_list_block);
1618 1 : }
1619 :
1620 1 : static void build_ordered_list_block(TlWriter *w) {
1621 1 : tl_write_uint32(w, TL_vector); tl_write_uint32(w, 1);
1622 1 : tl_write_uint32(w, CRC_pageBlockOrderedList_t);
1623 1 : tl_write_uint32(w, TL_vector); tl_write_uint32(w, 1);
1624 1 : tl_write_uint32(w, CRC_pageListOrderedItemText_t);
1625 1 : tl_write_string(w, "1.");
1626 1 : tl_write_uint32(w, CRC_textPlain_test); tl_write_string(w, "first");
1627 1 : }
1628 1 : static void test_skip_cached_page_ordered_list(void) {
1629 1 : run_cached_page_roundtrip(build_ordered_list_block);
1630 1 : }
1631 :
1632 1 : static void build_collage_block(TlWriter *w) {
1633 1 : tl_write_uint32(w, TL_vector); tl_write_uint32(w, 1);
1634 1 : tl_write_uint32(w, CRC_pageBlockCollage_t);
1635 : /* items: empty vector (still covers Collage's structure) */
1636 1 : tl_write_uint32(w, TL_vector); tl_write_uint32(w, 0);
1637 1 : empty_caption(w);
1638 1 : }
1639 1 : static void test_skip_cached_page_collage(void) {
1640 1 : run_cached_page_roundtrip(build_collage_block);
1641 1 : }
1642 :
1643 1 : static void build_slideshow_block(TlWriter *w) {
1644 1 : tl_write_uint32(w, TL_vector); tl_write_uint32(w, 1);
1645 1 : tl_write_uint32(w, CRC_pageBlockSlideshow_t);
1646 1 : tl_write_uint32(w, TL_vector); tl_write_uint32(w, 1);
1647 1 : tl_write_uint32(w, CRC_pageBlockParagraph_test);
1648 1 : tl_write_uint32(w, CRC_textPlain_test); tl_write_string(w, "slide");
1649 1 : empty_caption(w);
1650 1 : }
1651 1 : static void test_skip_cached_page_slideshow(void) {
1652 1 : run_cached_page_roundtrip(build_slideshow_block);
1653 1 : }
1654 :
1655 1 : static void build_details_block(TlWriter *w) {
1656 1 : tl_write_uint32(w, TL_vector); tl_write_uint32(w, 1);
1657 1 : tl_write_uint32(w, CRC_pageBlockDetails_t);
1658 1 : tl_write_uint32(w, 0);
1659 1 : tl_write_uint32(w, TL_vector); tl_write_uint32(w, 1);
1660 1 : tl_write_uint32(w, CRC_pageBlockParagraph_test);
1661 1 : tl_write_uint32(w, CRC_textEmpty_test);
1662 1 : tl_write_uint32(w, CRC_textPlain_test); tl_write_string(w, "Title");
1663 1 : }
1664 1 : static void test_skip_cached_page_details(void) {
1665 1 : run_cached_page_roundtrip(build_details_block);
1666 1 : }
1667 :
1668 1 : static void build_related_articles_block(TlWriter *w) {
1669 1 : tl_write_uint32(w, TL_vector); tl_write_uint32(w, 1);
1670 1 : tl_write_uint32(w, CRC_pageBlockRelatedArticles_t);
1671 1 : tl_write_uint32(w, CRC_textPlain_test); tl_write_string(w, "Related");
1672 1 : tl_write_uint32(w, TL_vector); tl_write_uint32(w, 1);
1673 1 : tl_write_uint32(w, CRC_pageRelatedArticle_t);
1674 1 : tl_write_uint32(w, 0); /* flags */
1675 1 : tl_write_string(w, "https://a");
1676 1 : tl_write_int64 (w, 111LL);
1677 1 : }
1678 1 : static void test_skip_cached_page_related_articles(void) {
1679 1 : run_cached_page_roundtrip(build_related_articles_block);
1680 1 : }
1681 :
1682 1 : static void build_table_block(TlWriter *w) {
1683 1 : tl_write_uint32(w, TL_vector); tl_write_uint32(w, 1);
1684 1 : tl_write_uint32(w, CRC_pageBlockTable_t);
1685 1 : tl_write_uint32(w, 0);
1686 1 : tl_write_uint32(w, CRC_textEmpty_test);
1687 1 : tl_write_uint32(w, TL_vector); tl_write_uint32(w, 1);
1688 1 : tl_write_uint32(w, CRC_pageTableRow_t);
1689 1 : tl_write_uint32(w, TL_vector); tl_write_uint32(w, 1);
1690 1 : tl_write_uint32(w, CRC_pageTableCell_t);
1691 1 : tl_write_uint32(w, (1u << 7)); /* text:flags.7 */
1692 1 : tl_write_uint32(w, CRC_textPlain_test); tl_write_string(w, "cell");
1693 1 : }
1694 1 : static void test_skip_cached_page_table(void) {
1695 1 : run_cached_page_roundtrip(build_table_block);
1696 1 : }
1697 :
1698 1 : static void build_embed_block(TlWriter *w) {
1699 1 : tl_write_uint32(w, TL_vector); tl_write_uint32(w, 1);
1700 1 : tl_write_uint32(w, CRC_pageBlockEmbed_t);
1701 1 : tl_write_uint32(w, (1u << 1)); /* url present */
1702 1 : tl_write_string(w, "https://example/e");
1703 1 : empty_caption(w);
1704 1 : }
1705 1 : static void test_skip_cached_page_embed(void) {
1706 1 : run_cached_page_roundtrip(build_embed_block);
1707 1 : }
1708 :
1709 1 : static void build_embed_post_block(TlWriter *w) {
1710 1 : tl_write_uint32(w, TL_vector); tl_write_uint32(w, 1);
1711 1 : tl_write_uint32(w, CRC_pageBlockEmbedPost_t);
1712 1 : tl_write_string(w, "https://p");
1713 1 : tl_write_int64 (w, 1); /* webpage_id */
1714 1 : tl_write_int64 (w, 2); /* author_photo_id */
1715 1 : tl_write_string(w, "author");
1716 1 : tl_write_int32 (w, 1700000000);
1717 1 : tl_write_uint32(w, TL_vector); tl_write_uint32(w, 0);
1718 1 : empty_caption(w);
1719 1 : }
1720 1 : static void test_skip_cached_page_embed_post(void) {
1721 1 : run_cached_page_roundtrip(build_embed_post_block);
1722 1 : }
1723 :
1724 : /* TUI-11: cached_page with an unsupported PageBlock (Cover etc.) bails. */
1725 1 : static void test_skip_media_webpage_cached_page_unsupported(void) {
1726 1 : TlWriter w; tl_writer_init(&w);
1727 1 : tl_write_uint32(&w, CRC_messageMediaWebPage_test);
1728 1 : tl_write_uint32(&w, 0);
1729 1 : tl_write_uint32(&w, CRC_webPage_test);
1730 1 : tl_write_uint32(&w, (1u << 10));
1731 1 : tl_write_int64 (&w, 0x333);
1732 1 : tl_write_string(&w, "u");
1733 1 : tl_write_string(&w, "u");
1734 1 : tl_write_int32 (&w, 1);
1735 1 : tl_write_uint32(&w, CRC_page_test);
1736 1 : tl_write_uint32(&w, 0);
1737 1 : tl_write_string(&w, "x");
1738 1 : tl_write_uint32(&w, TL_vector);
1739 1 : tl_write_uint32(&w, 1);
1740 : /* unknown PageBlock CRC */
1741 1 : tl_write_uint32(&w, 0xDEADBEEFu);
1742 1 : TlReader r = tl_reader_init(w.data, w.len);
1743 1 : ASSERT(tl_skip_message_media_ex(&r, NULL) == -1,
1744 : "unknown PageBlock bails");
1745 1 : tl_writer_free(&w);
1746 : }
1747 :
1748 : /* TUI-11: webPageAttribute — Vector with a theme (no settings). */
1749 : #define CRC_webPageAttributeTheme_t 0x54b56617u
1750 : #define CRC_webPageAttributeStickerSet_t 0x50cc03d3u
1751 : #define CRC_webPageAttributeStory_t 0x2e94c3e7u
1752 : #define CRC_storyItemDeleted_t 0x51e6ee4fu
1753 :
1754 1 : static void test_skip_media_webpage_attributes_theme(void) {
1755 1 : TlWriter w; tl_writer_init(&w);
1756 1 : tl_write_uint32(&w, CRC_messageMediaWebPage_test);
1757 1 : tl_write_uint32(&w, 0);
1758 1 : tl_write_uint32(&w, CRC_webPage_test);
1759 1 : tl_write_uint32(&w, (1u << 12)); /* attributes flag */
1760 1 : tl_write_int64 (&w, 1);
1761 1 : tl_write_string(&w, "u");
1762 1 : tl_write_string(&w, "u");
1763 1 : tl_write_int32 (&w, 1);
1764 : /* attributes: [Theme{documents=[]}] */
1765 1 : tl_write_uint32(&w, TL_vector);
1766 1 : tl_write_uint32(&w, 1);
1767 1 : tl_write_uint32(&w, CRC_webPageAttributeTheme_t);
1768 1 : tl_write_uint32(&w, (1u << 0)); /* documents present */
1769 1 : tl_write_uint32(&w, TL_vector);
1770 1 : tl_write_uint32(&w, 0);
1771 1 : tl_write_int32(&w, 0xBEEF);
1772 1 : TlReader r = tl_reader_init(w.data, w.len);
1773 1 : ASSERT(tl_skip_message_media_ex(&r, NULL) == 0, "theme attrs iterate");
1774 1 : ASSERT(tl_read_int32(&r) == 0xBEEF, "cursor past media");
1775 1 : tl_writer_free(&w);
1776 : }
1777 :
1778 : /* TUI-11: webPageAttribute — StickerSet with a couple of documents. */
1779 1 : static void test_skip_media_webpage_attributes_stickerset(void) {
1780 1 : TlWriter w; tl_writer_init(&w);
1781 1 : tl_write_uint32(&w, CRC_messageMediaWebPage_test);
1782 1 : tl_write_uint32(&w, 0);
1783 1 : tl_write_uint32(&w, CRC_webPage_test);
1784 1 : tl_write_uint32(&w, (1u << 12));
1785 1 : tl_write_int64 (&w, 1);
1786 1 : tl_write_string(&w, "u");
1787 1 : tl_write_string(&w, "u");
1788 1 : tl_write_int32 (&w, 1);
1789 1 : tl_write_uint32(&w, TL_vector);
1790 1 : tl_write_uint32(&w, 1);
1791 1 : tl_write_uint32(&w, CRC_webPageAttributeStickerSet_t);
1792 1 : tl_write_uint32(&w, 0); /* flags */
1793 : /* stickers: [documentEmpty, documentEmpty] */
1794 1 : tl_write_uint32(&w, TL_vector);
1795 1 : tl_write_uint32(&w, 2);
1796 1 : tl_write_uint32(&w, CRC_documentEmpty);
1797 1 : tl_write_int64 (&w, 11LL);
1798 1 : tl_write_uint32(&w, CRC_documentEmpty);
1799 1 : tl_write_int64 (&w, 22LL);
1800 1 : tl_write_int32(&w, 0xABCD);
1801 1 : TlReader r = tl_reader_init(w.data, w.len);
1802 1 : ASSERT(tl_skip_message_media_ex(&r, NULL) == 0, "stickerset iterates");
1803 1 : ASSERT(tl_read_int32(&r) == 0xABCD, "cursor past media");
1804 1 : tl_writer_free(&w);
1805 : }
1806 :
1807 : /* TUI-11: webPageAttribute — Story without a nested story (flag.0 clear). */
1808 1 : static void test_skip_media_webpage_attributes_story_noinline(void) {
1809 1 : TlWriter w; tl_writer_init(&w);
1810 1 : tl_write_uint32(&w, CRC_messageMediaWebPage_test);
1811 1 : tl_write_uint32(&w, 0);
1812 1 : tl_write_uint32(&w, CRC_webPage_test);
1813 1 : tl_write_uint32(&w, (1u << 12));
1814 1 : tl_write_int64 (&w, 1);
1815 1 : tl_write_string(&w, "u");
1816 1 : tl_write_string(&w, "u");
1817 1 : tl_write_int32 (&w, 1);
1818 1 : tl_write_uint32(&w, TL_vector);
1819 1 : tl_write_uint32(&w, 1);
1820 1 : tl_write_uint32(&w, CRC_webPageAttributeStory_t);
1821 1 : tl_write_uint32(&w, 0); /* no inline story */
1822 1 : tl_write_uint32(&w, TL_peerUser); /* peer */
1823 1 : tl_write_int64 (&w, 42LL);
1824 1 : tl_write_int32 (&w, 7); /* story id */
1825 1 : tl_write_int32(&w, 0x1234);
1826 1 : TlReader r = tl_reader_init(w.data, w.len);
1827 1 : ASSERT(tl_skip_message_media_ex(&r, NULL) == 0, "story attr iterates");
1828 1 : ASSERT(tl_read_int32(&r) == 0x1234, "cursor past media");
1829 1 : tl_writer_free(&w);
1830 : }
1831 :
1832 : /* TUI-11: webPageAttribute — Story with an inline storyItemDeleted. */
1833 1 : static void test_skip_media_webpage_attributes_story_inline(void) {
1834 1 : TlWriter w; tl_writer_init(&w);
1835 1 : tl_write_uint32(&w, CRC_messageMediaWebPage_test);
1836 1 : tl_write_uint32(&w, 0);
1837 1 : tl_write_uint32(&w, CRC_webPage_test);
1838 1 : tl_write_uint32(&w, (1u << 12));
1839 1 : tl_write_int64 (&w, 1);
1840 1 : tl_write_string(&w, "u");
1841 1 : tl_write_string(&w, "u");
1842 1 : tl_write_int32 (&w, 1);
1843 1 : tl_write_uint32(&w, TL_vector);
1844 1 : tl_write_uint32(&w, 1);
1845 1 : tl_write_uint32(&w, CRC_webPageAttributeStory_t);
1846 1 : tl_write_uint32(&w, (1u << 0)); /* inline story */
1847 1 : tl_write_uint32(&w, TL_peerUser);
1848 1 : tl_write_int64 (&w, 42LL);
1849 1 : tl_write_int32 (&w, 7);
1850 : /* story: storyItemDeleted{id=7} — simplest variant */
1851 1 : tl_write_uint32(&w, CRC_storyItemDeleted_t);
1852 1 : tl_write_int32 (&w, 7);
1853 1 : tl_write_int32(&w, 0xBABE);
1854 1 : TlReader r = tl_reader_init(w.data, w.len);
1855 1 : ASSERT(tl_skip_message_media_ex(&r, NULL) == 0, "story inline iterates");
1856 1 : ASSERT(tl_read_int32(&r) == 0xBABE, "cursor past media");
1857 1 : tl_writer_free(&w);
1858 : }
1859 :
1860 : /* TUI-11: unknown WebPageAttribute variant bails. */
1861 1 : static void test_skip_media_webpage_attributes_unknown(void) {
1862 1 : TlWriter w; tl_writer_init(&w);
1863 1 : tl_write_uint32(&w, CRC_messageMediaWebPage_test);
1864 1 : tl_write_uint32(&w, 0);
1865 1 : tl_write_uint32(&w, CRC_webPage_test);
1866 1 : tl_write_uint32(&w, (1u << 12));
1867 1 : tl_write_int64 (&w, 1);
1868 1 : tl_write_string(&w, "u");
1869 1 : tl_write_string(&w, "u");
1870 1 : tl_write_int32 (&w, 1);
1871 1 : tl_write_uint32(&w, TL_vector);
1872 1 : tl_write_uint32(&w, 1);
1873 1 : tl_write_uint32(&w, 0xDEADC0DE);
1874 1 : TlReader r = tl_reader_init(w.data, w.len);
1875 1 : ASSERT(tl_skip_message_media_ex(&r, NULL) == -1,
1876 : "unknown WebPageAttribute bails");
1877 1 : tl_writer_free(&w);
1878 : }
1879 :
1880 : /* TUI-11: both cached_page AND attributes set, combined page + stickerset. */
1881 1 : static void test_skip_media_webpage_cached_page_plus_attributes(void) {
1882 1 : TlWriter w; tl_writer_init(&w);
1883 1 : tl_write_uint32(&w, CRC_messageMediaWebPage_test);
1884 1 : tl_write_uint32(&w, 0);
1885 1 : tl_write_uint32(&w, CRC_webPage_test);
1886 1 : tl_write_uint32(&w, (1u << 10) | (1u << 12));
1887 1 : tl_write_int64 (&w, 1);
1888 1 : tl_write_string(&w, "u");
1889 1 : tl_write_string(&w, "u");
1890 1 : tl_write_int32 (&w, 1);
1891 : /* cached_page: empty page */
1892 1 : tl_write_uint32(&w, CRC_page_test);
1893 1 : tl_write_uint32(&w, 0);
1894 1 : tl_write_string(&w, "p");
1895 1 : tl_write_uint32(&w, TL_vector); tl_write_uint32(&w, 0); /* blocks */
1896 1 : tl_write_uint32(&w, TL_vector); tl_write_uint32(&w, 0); /* photos */
1897 1 : tl_write_uint32(&w, TL_vector); tl_write_uint32(&w, 0); /* documents */
1898 : /* attributes: one StickerSet with no stickers */
1899 1 : tl_write_uint32(&w, TL_vector); tl_write_uint32(&w, 1);
1900 1 : tl_write_uint32(&w, CRC_webPageAttributeStickerSet_t);
1901 1 : tl_write_uint32(&w, 0);
1902 1 : tl_write_uint32(&w, TL_vector); tl_write_uint32(&w, 0);
1903 1 : tl_write_int32(&w, 0x5678);
1904 1 : TlReader r = tl_reader_init(w.data, w.len);
1905 1 : ASSERT(tl_skip_message_media_ex(&r, NULL) == 0,
1906 : "cached_page + attributes iterate together");
1907 1 : ASSERT(tl_read_int32(&r) == 0x5678, "cursor past media");
1908 1 : tl_writer_free(&w);
1909 : }
1910 :
1911 : /* ---- messageMediaGame ---- */
1912 :
1913 : #define CRC_messageMediaGame_t 0xfdb19008u
1914 : #define CRC_game_t 0xbdf9653bu
1915 :
1916 1 : static void test_skip_media_game_photo_only(void) {
1917 1 : TlWriter w; tl_writer_init(&w);
1918 1 : tl_write_uint32(&w, CRC_messageMediaGame_t);
1919 1 : tl_write_uint32(&w, CRC_game_t);
1920 1 : tl_write_uint32(&w, 0); /* game flags (no document) */
1921 1 : tl_write_int64 (&w, 0x11LL);
1922 1 : tl_write_int64 (&w, 0x22LL);
1923 1 : tl_write_string(&w, "short");
1924 1 : tl_write_string(&w, "title");
1925 1 : tl_write_string(&w, "desc");
1926 : /* photo:photoEmpty */
1927 1 : tl_write_uint32(&w, CRC_photoEmpty);
1928 1 : tl_write_int64 (&w, 7777LL);
1929 1 : tl_write_int32 (&w, 0xCAFE);
1930 1 : TlReader r = tl_reader_init(w.data, w.len);
1931 1 : MediaInfo mi = {0};
1932 1 : ASSERT(tl_skip_message_media_ex(&r, &mi) == 0, "game photo-only ok");
1933 1 : ASSERT(mi.kind == MEDIA_GAME, "kind=game");
1934 1 : ASSERT(tl_read_int32(&r) == 0xCAFE, "cursor past game");
1935 1 : tl_writer_free(&w);
1936 : }
1937 :
1938 1 : static void test_skip_media_game_with_document(void) {
1939 1 : TlWriter w; tl_writer_init(&w);
1940 1 : tl_write_uint32(&w, CRC_messageMediaGame_t);
1941 1 : tl_write_uint32(&w, CRC_game_t);
1942 1 : tl_write_uint32(&w, (1u << 0)); /* document flag set */
1943 1 : tl_write_int64 (&w, 1LL);
1944 1 : tl_write_int64 (&w, 2LL);
1945 1 : tl_write_string(&w, "s");
1946 1 : tl_write_string(&w, "t");
1947 1 : tl_write_string(&w, "d");
1948 1 : tl_write_uint32(&w, CRC_photoEmpty);
1949 1 : tl_write_int64 (&w, 3LL);
1950 : /* document:documentEmpty (id only) */
1951 1 : tl_write_uint32(&w, 0x36f8c871u);
1952 1 : tl_write_int64 (&w, 4LL);
1953 1 : tl_write_int32 (&w, 0xABC);
1954 1 : TlReader r = tl_reader_init(w.data, w.len);
1955 1 : ASSERT(tl_skip_message_media_ex(&r, NULL) == 0, "game+doc ok");
1956 1 : ASSERT(tl_read_int32(&r) == 0xABC, "cursor past game+doc");
1957 1 : tl_writer_free(&w);
1958 : }
1959 :
1960 1 : static void test_skip_media_game_wrong_inner_crc_bails(void) {
1961 1 : TlWriter w; tl_writer_init(&w);
1962 1 : tl_write_uint32(&w, CRC_messageMediaGame_t);
1963 1 : tl_write_uint32(&w, 0xdeadbeefu); /* not a Game CRC */
1964 1 : TlReader r = tl_reader_init(w.data, w.len);
1965 1 : ASSERT(tl_skip_message_media_ex(&r, NULL) == -1, "non-Game inner rejected");
1966 1 : tl_writer_free(&w);
1967 : }
1968 :
1969 : /* ---- messageMediaPaidMedia ---- */
1970 :
1971 : #define CRC_messageMediaPaidMedia_t 0xa8852491u
1972 : #define CRC_messageExtendedMediaPreview_t 0xad628cc8u
1973 : #define CRC_messageExtendedMedia_t 0xee479c64u
1974 :
1975 1 : static void test_skip_media_paid_preview_only(void) {
1976 1 : TlWriter w; tl_writer_init(&w);
1977 1 : tl_write_uint32(&w, CRC_messageMediaPaidMedia_t);
1978 1 : tl_write_int64 (&w, 500LL); /* stars_amount */
1979 1 : tl_write_uint32(&w, TL_vector);
1980 1 : tl_write_uint32(&w, 1); /* one extended_media */
1981 1 : tl_write_uint32(&w, CRC_messageExtendedMediaPreview_t);
1982 1 : tl_write_uint32(&w, 0); /* no flags */
1983 1 : tl_write_int32 (&w, 0x55AA);
1984 1 : TlReader r = tl_reader_init(w.data, w.len);
1985 1 : MediaInfo mi = {0};
1986 1 : ASSERT(tl_skip_message_media_ex(&r, &mi) == 0, "paid preview ok");
1987 1 : ASSERT(mi.kind == MEDIA_PAID, "kind=paid");
1988 1 : ASSERT(tl_read_int32(&r) == 0x55AA, "cursor past paid");
1989 1 : tl_writer_free(&w);
1990 : }
1991 :
1992 1 : static void test_skip_media_paid_preview_with_dims_and_thumb(void) {
1993 1 : TlWriter w; tl_writer_init(&w);
1994 1 : tl_write_uint32(&w, CRC_messageMediaPaidMedia_t);
1995 1 : tl_write_int64 (&w, 1000LL);
1996 1 : tl_write_uint32(&w, TL_vector);
1997 1 : tl_write_uint32(&w, 1);
1998 1 : tl_write_uint32(&w, CRC_messageExtendedMediaPreview_t);
1999 1 : tl_write_uint32(&w, (1u << 0) | (1u << 1) | (1u << 2));
2000 1 : tl_write_int32 (&w, 1280); tl_write_int32(&w, 720);
2001 : /* thumb: photoStrippedSize#e0b0bc2e type:string bytes:bytes */
2002 1 : tl_write_uint32(&w, 0xe0b0bc2eu);
2003 1 : tl_write_string(&w, "i");
2004 1 : uint8_t stripped[3] = { 0x01, 0x02, 0x03 };
2005 1 : tl_write_bytes(&w, stripped, sizeof(stripped));
2006 1 : tl_write_int32 (&w, 12); /* video_duration */
2007 1 : tl_write_int32 (&w, 0xFACE);
2008 1 : TlReader r = tl_reader_init(w.data, w.len);
2009 1 : ASSERT(tl_skip_message_media_ex(&r, NULL) == 0, "paid preview full ok");
2010 1 : ASSERT(tl_read_int32(&r) == 0xFACE, "cursor past paid");
2011 1 : tl_writer_free(&w);
2012 : }
2013 :
2014 1 : static void test_skip_media_paid_wrapped_inner_media(void) {
2015 : /* extended_media variant that wraps an inner MessageMedia (here
2016 : * messageMediaEmpty). Confirms the recursive tl_skip_message_media_ex
2017 : * dispatch path. */
2018 1 : TlWriter w; tl_writer_init(&w);
2019 1 : tl_write_uint32(&w, CRC_messageMediaPaidMedia_t);
2020 1 : tl_write_int64 (&w, 42LL);
2021 1 : tl_write_uint32(&w, TL_vector);
2022 1 : tl_write_uint32(&w, 2); /* two extended_media entries */
2023 1 : tl_write_uint32(&w, CRC_messageExtendedMediaPreview_t);
2024 1 : tl_write_uint32(&w, 0);
2025 1 : tl_write_uint32(&w, CRC_messageExtendedMedia_t);
2026 1 : tl_write_uint32(&w, CRC_messageMediaEmpty);
2027 1 : tl_write_int32 (&w, 0xBEEF);
2028 1 : TlReader r = tl_reader_init(w.data, w.len);
2029 1 : ASSERT(tl_skip_message_media_ex(&r, NULL) == 0, "paid wrapped ok");
2030 1 : ASSERT(tl_read_int32(&r) == (int32_t)0xBEEF, "cursor past wrapped paid");
2031 1 : tl_writer_free(&w);
2032 : }
2033 :
2034 : /* ---- messageMediaInvoice with WebDocument photo + extended_media ---- */
2035 :
2036 : #define CRC_webDocument_t 0x1c570ed1u
2037 : #define CRC_webDocumentNoProxy_t 0xf9c8bcc6u
2038 : #define CRC_documentAttributeFilename_test 0x15590068u
2039 :
2040 1 : static void test_skip_media_invoice_with_webdocument_photo(void) {
2041 1 : TlWriter w; tl_writer_init(&w);
2042 1 : tl_write_uint32(&w, CRC_messageMediaInvoice_t);
2043 1 : tl_write_uint32(&w, (1u << 0)); /* photo flag */
2044 1 : tl_write_string(&w, "Pro");
2045 1 : tl_write_string(&w, "Subscription");
2046 : /* webDocument with one Filename attribute */
2047 1 : tl_write_uint32(&w, CRC_webDocument_t);
2048 1 : tl_write_string(&w, "https://icon.example");
2049 1 : tl_write_int64 (&w, 0x12345LL); /* access_hash */
2050 1 : tl_write_int32 (&w, 4096); /* size */
2051 1 : tl_write_string(&w, "image/png");
2052 1 : tl_write_uint32(&w, TL_vector);
2053 1 : tl_write_uint32(&w, 1);
2054 1 : tl_write_uint32(&w, CRC_documentAttributeFilename_test);
2055 1 : tl_write_string(&w, "icon.png");
2056 : /* continuing messageMediaInvoice fields */
2057 1 : tl_write_string(&w, "EUR");
2058 1 : tl_write_int64 (&w, 1999);
2059 1 : tl_write_string(&w, "start");
2060 1 : tl_write_int32 (&w, 0xBEEF);
2061 1 : TlReader r = tl_reader_init(w.data, w.len);
2062 1 : MediaInfo mi = {0};
2063 1 : ASSERT(tl_skip_message_media_ex(&r, &mi) == 0,
2064 : "invoice + webDocument iterates");
2065 1 : ASSERT(mi.kind == MEDIA_INVOICE, "kind=invoice");
2066 1 : ASSERT(tl_read_int32(&r) == 0xBEEF, "cursor past invoice");
2067 1 : tl_writer_free(&w);
2068 : }
2069 :
2070 1 : static void test_skip_media_invoice_noproxy_webdocument(void) {
2071 1 : TlWriter w; tl_writer_init(&w);
2072 1 : tl_write_uint32(&w, CRC_messageMediaInvoice_t);
2073 1 : tl_write_uint32(&w, (1u << 0));
2074 1 : tl_write_string(&w, "T"); tl_write_string(&w, "D");
2075 : /* webDocumentNoProxy — no access_hash */
2076 1 : tl_write_uint32(&w, CRC_webDocumentNoProxy_t);
2077 1 : tl_write_string(&w, "https://x");
2078 1 : tl_write_int32 (&w, 512);
2079 1 : tl_write_string(&w, "image/jpeg");
2080 1 : tl_write_uint32(&w, TL_vector);
2081 1 : tl_write_uint32(&w, 0); /* no attributes */
2082 1 : tl_write_string(&w, "USD");
2083 1 : tl_write_int64 (&w, 99);
2084 1 : tl_write_string(&w, "s");
2085 1 : tl_write_int32 (&w, 0xDEAD);
2086 1 : TlReader r = tl_reader_init(w.data, w.len);
2087 1 : ASSERT(tl_skip_message_media_ex(&r, NULL) == 0, "noProxy variant ok");
2088 1 : ASSERT(tl_read_int32(&r) == (int32_t)0xDEAD, "cursor past");
2089 1 : tl_writer_free(&w);
2090 : }
2091 :
2092 1 : static void test_skip_media_invoice_extended_media_preview(void) {
2093 : /* flags.4 (extended_media) now walks through messageExtendedMediaPreview. */
2094 1 : TlWriter w; tl_writer_init(&w);
2095 1 : tl_write_uint32(&w, CRC_messageMediaInvoice_t);
2096 1 : tl_write_uint32(&w, (1u << 4)); /* extended_media flag only */
2097 1 : tl_write_string(&w, "T"); tl_write_string(&w, "D");
2098 1 : tl_write_string(&w, "EUR");
2099 1 : tl_write_int64 (&w, 42);
2100 1 : tl_write_string(&w, "s");
2101 : /* extended_media: messageExtendedMediaPreview#ad628cc8 with no inner
2102 : * flags — just the flags int. */
2103 1 : tl_write_uint32(&w, 0xad628cc8u);
2104 1 : tl_write_uint32(&w, 0);
2105 1 : tl_write_int32 (&w, 0xBABE);
2106 1 : TlReader r = tl_reader_init(w.data, w.len);
2107 1 : ASSERT(tl_skip_message_media_ex(&r, NULL) == 0,
2108 : "invoice.extended_media now handled");
2109 1 : ASSERT(tl_read_int32(&r) == (int32_t)0xBABE, "cursor past invoice");
2110 1 : tl_writer_free(&w);
2111 : }
2112 :
2113 : /* ---- messageMediaStory with inline StoryItem variants ---- */
2114 :
2115 : #define CRC_storyItemDeleted_t 0x51e6ee4fu
2116 : #define CRC_storyItemSkipped_t 0xffadc913u
2117 : #define CRC_storyItem_t 0x79b26a24u
2118 :
2119 1 : static void test_skip_media_story_inline_deleted(void) {
2120 1 : TlWriter w; tl_writer_init(&w);
2121 1 : tl_write_uint32(&w, CRC_messageMediaStory_t);
2122 1 : tl_write_uint32(&w, (1u << 0)); /* inline story */
2123 1 : tl_write_uint32(&w, TL_peerUser);
2124 1 : tl_write_int64 (&w, 7LL);
2125 1 : tl_write_int32 (&w, 11); /* id */
2126 : /* storyItemDeleted */
2127 1 : tl_write_uint32(&w, CRC_storyItemDeleted_t);
2128 1 : tl_write_int32 (&w, 11);
2129 1 : tl_write_int32 (&w, 0xFACE);
2130 1 : TlReader r = tl_reader_init(w.data, w.len);
2131 1 : MediaInfo mi = {0};
2132 1 : ASSERT(tl_skip_message_media_ex(&r, &mi) == 0,
2133 : "inline storyItemDeleted iterates");
2134 1 : ASSERT(mi.kind == MEDIA_STORY, "kind=story");
2135 1 : ASSERT(tl_read_int32(&r) == (int32_t)0xFACE, "cursor past story");
2136 1 : tl_writer_free(&w);
2137 : }
2138 :
2139 1 : static void test_skip_media_story_inline_skipped(void) {
2140 1 : TlWriter w; tl_writer_init(&w);
2141 1 : tl_write_uint32(&w, CRC_messageMediaStory_t);
2142 1 : tl_write_uint32(&w, (1u << 0));
2143 1 : tl_write_uint32(&w, TL_peerUser);
2144 1 : tl_write_int64 (&w, 7LL);
2145 1 : tl_write_int32 (&w, 11);
2146 : /* storyItemSkipped#ffadc913 flags:# id:int date:int expire_date:int */
2147 1 : tl_write_uint32(&w, CRC_storyItemSkipped_t);
2148 1 : tl_write_uint32(&w, 0); /* no close_friends flag */
2149 1 : tl_write_int32 (&w, 11);
2150 1 : tl_write_int32 (&w, 1700000000);
2151 1 : tl_write_int32 (&w, 1700086400);
2152 1 : tl_write_int32 (&w, 0xFEED);
2153 1 : TlReader r = tl_reader_init(w.data, w.len);
2154 1 : ASSERT(tl_skip_message_media_ex(&r, NULL) == 0,
2155 : "inline storyItemSkipped iterates");
2156 1 : ASSERT(tl_read_int32(&r) == (int32_t)0xFEED, "cursor past story");
2157 1 : tl_writer_free(&w);
2158 : }
2159 :
2160 1 : static void test_skip_media_story_truncated_full_bails(void) {
2161 : /* Full storyItem body missing: the skipper must bail cleanly rather
2162 : * than overrun the buffer. */
2163 1 : TlWriter w; tl_writer_init(&w);
2164 1 : tl_write_uint32(&w, CRC_messageMediaStory_t);
2165 1 : tl_write_uint32(&w, (1u << 0));
2166 1 : tl_write_uint32(&w, TL_peerUser);
2167 1 : tl_write_int64 (&w, 7LL);
2168 1 : tl_write_int32 (&w, 11);
2169 1 : tl_write_uint32(&w, CRC_storyItem_t);
2170 : /* No body bytes — skipper should detect truncation. */
2171 1 : TlReader r = tl_reader_init(w.data, w.len);
2172 1 : ASSERT(tl_skip_message_media_ex(&r, NULL) == -1,
2173 : "truncated full storyItem bails");
2174 1 : tl_writer_free(&w);
2175 : }
2176 :
2177 : /* Full storyItem#79b26a24 minimal: only mandatory fields + empty media. */
2178 1 : static void test_skip_media_story_full_minimal(void) {
2179 1 : TlWriter w; tl_writer_init(&w);
2180 1 : tl_write_uint32(&w, CRC_messageMediaStory_t);
2181 1 : tl_write_uint32(&w, (1u << 0)); /* inline story */
2182 1 : tl_write_uint32(&w, TL_peerUser);
2183 1 : tl_write_int64 (&w, 42LL);
2184 1 : tl_write_int32 (&w, 99); /* outer id */
2185 : /* storyItem with no optional flags. */
2186 1 : tl_write_uint32(&w, CRC_storyItem_t);
2187 1 : tl_write_uint32(&w, 0); /* flags */
2188 1 : tl_write_int32 (&w, 99); /* id */
2189 1 : tl_write_int32 (&w, 1700000000); /* date */
2190 1 : tl_write_int32 (&w, 1700086400); /* expire_date */
2191 1 : tl_write_uint32(&w, CRC_messageMediaEmpty); /* media */
2192 1 : tl_write_int32 (&w, 0x12345678);
2193 1 : TlReader r = tl_reader_init(w.data, w.len);
2194 1 : ASSERT(tl_skip_message_media_ex(&r, NULL) == 0,
2195 : "minimal full storyItem iterates");
2196 1 : ASSERT(tl_read_int32(&r) == 0x12345678, "cursor past full storyItem");
2197 1 : tl_writer_free(&w);
2198 : }
2199 :
2200 : /* Full storyItem with caption + entities + views (flags.0|1|3). */
2201 1 : static void test_skip_media_story_full_with_views(void) {
2202 1 : TlWriter w; tl_writer_init(&w);
2203 1 : tl_write_uint32(&w, CRC_messageMediaStory_t);
2204 1 : tl_write_uint32(&w, (1u << 0));
2205 1 : tl_write_uint32(&w, TL_peerChannel);
2206 1 : tl_write_int64 (&w, 500LL);
2207 1 : tl_write_int32 (&w, 1);
2208 : /* storyItem w/ caption (flags.0) + entities (flags.1) + views (flags.3). */
2209 1 : tl_write_uint32(&w, CRC_storyItem_t);
2210 1 : tl_write_uint32(&w, (1u << 0) | (1u << 1) | (1u << 3));
2211 1 : tl_write_int32 (&w, 1);
2212 1 : tl_write_int32 (&w, 1700000000);
2213 1 : tl_write_int32 (&w, 1700086400);
2214 1 : tl_write_string(&w, "Hello story");
2215 : /* entities: empty vector */
2216 1 : tl_write_uint32(&w, TL_vector);
2217 1 : tl_write_uint32(&w, 0);
2218 : /* media: empty */
2219 1 : tl_write_uint32(&w, CRC_messageMediaEmpty);
2220 : /* views: storyViews flags=0, just views_count */
2221 1 : tl_write_uint32(&w, 0x8d595cd6u); /* storyViews */
2222 1 : tl_write_uint32(&w, 0);
2223 1 : tl_write_int32 (&w, 1234); /* views_count */
2224 1 : tl_write_int32 (&w, 0xABBA);
2225 1 : TlReader r = tl_reader_init(w.data, w.len);
2226 1 : ASSERT(tl_skip_message_media_ex(&r, NULL) == 0,
2227 : "full storyItem with views iterates");
2228 1 : ASSERT(tl_read_int32(&r) == (int32_t)0xABBA, "cursor past");
2229 1 : tl_writer_free(&w);
2230 : }
2231 :
2232 : /* LIM-04: storyItem whose inner media is a supported variant (photo /
2233 : * document / webpage / empty) must iterate end-to-end. */
2234 1 : static void test_skip_media_story_inner_media_photo(void) {
2235 1 : TlWriter w; tl_writer_init(&w);
2236 1 : tl_write_uint32(&w, CRC_messageMediaStory_t);
2237 1 : tl_write_uint32(&w, (1u << 0));
2238 1 : tl_write_uint32(&w, TL_peerUser);
2239 1 : tl_write_int64 (&w, 1LL);
2240 1 : tl_write_int32 (&w, 1);
2241 1 : tl_write_uint32(&w, CRC_storyItem_t);
2242 1 : tl_write_uint32(&w, 0);
2243 1 : tl_write_int32 (&w, 1);
2244 1 : tl_write_int32 (&w, 1700000000);
2245 1 : tl_write_int32 (&w, 1700086400);
2246 : /* inner media: messageMediaPhoto with photoEmpty. */
2247 1 : tl_write_uint32(&w, 0x695150d7u); /* CRC_messageMediaPhoto */
2248 1 : tl_write_uint32(&w, (1u << 0)); /* photo flag set */
2249 1 : tl_write_uint32(&w, CRC_photoEmpty); /* photoEmpty body */
2250 1 : tl_write_int64 (&w, 42LL);
2251 1 : tl_write_int32 (&w, 0xBEE);
2252 1 : TlReader r = tl_reader_init(w.data, w.len);
2253 1 : ASSERT(tl_skip_message_media_ex(&r, NULL) == 0,
2254 : "storyItem with inner photoEmpty iterates");
2255 1 : ASSERT(tl_read_int32(&r) == 0xBEE, "cursor past outer story");
2256 1 : tl_writer_free(&w);
2257 : }
2258 :
2259 : /* LIM-04: doubly-nested storyItem is blocked by the recursion guard
2260 : * (returns -1) instead of blowing the stack. */
2261 1 : static void test_skip_media_story_nested_recursion_guard(void) {
2262 1 : TlWriter w; tl_writer_init(&w);
2263 : /* depth 1: messageMediaStory with inline storyItem whose inner
2264 : * media is another messageMediaStory (depth 2) … up to 6 levels to
2265 : * exceed the configured MEDIA_RECURSION_MAX (4). */
2266 1 : const int DEPTH = 6;
2267 7 : for (int d = 0; d < DEPTH; d++) {
2268 6 : tl_write_uint32(&w, CRC_messageMediaStory_t);
2269 6 : tl_write_uint32(&w, (1u << 0));
2270 6 : tl_write_uint32(&w, TL_peerUser);
2271 6 : tl_write_int64 (&w, 1LL);
2272 6 : tl_write_int32 (&w, 1);
2273 6 : tl_write_uint32(&w, CRC_storyItem_t);
2274 6 : tl_write_uint32(&w, 0);
2275 6 : tl_write_int32 (&w, 1);
2276 6 : tl_write_int32 (&w, 1700000000);
2277 6 : tl_write_int32 (&w, 1700086400);
2278 : /* inner media will be written by next iteration, or final Empty. */
2279 : }
2280 1 : tl_write_uint32(&w, CRC_messageMediaEmpty); /* terminator */
2281 1 : TlReader r = tl_reader_init(w.data, w.len);
2282 1 : int rc = tl_skip_message_media_ex(&r, NULL);
2283 1 : ASSERT(rc == -1, "nested recursion beyond guard bails");
2284 1 : tl_writer_free(&w);
2285 : }
2286 :
2287 : /* Full storyItem with a privacy list + a media_area. */
2288 1 : static void test_skip_media_story_full_with_privacy_and_area(void) {
2289 1 : TlWriter w; tl_writer_init(&w);
2290 1 : tl_write_uint32(&w, CRC_messageMediaStory_t);
2291 1 : tl_write_uint32(&w, (1u << 0));
2292 1 : tl_write_uint32(&w, TL_peerUser);
2293 1 : tl_write_int64 (&w, 1LL);
2294 1 : tl_write_int32 (&w, 1);
2295 : /* flags.14 media_areas + flags.2 privacy. */
2296 1 : tl_write_uint32(&w, CRC_storyItem_t);
2297 1 : tl_write_uint32(&w, (1u << 14) | (1u << 2));
2298 1 : tl_write_int32 (&w, 1);
2299 1 : tl_write_int32 (&w, 1700000000);
2300 1 : tl_write_int32 (&w, 1700086400);
2301 1 : tl_write_uint32(&w, CRC_messageMediaEmpty);
2302 : /* media_areas: [mediaAreaUrl with coordinates + url]. */
2303 1 : tl_write_uint32(&w, TL_vector);
2304 1 : tl_write_uint32(&w, 1);
2305 1 : tl_write_uint32(&w, 0x37381085u); /* mediaAreaUrl */
2306 : /* mediaAreaCoordinates flags=0 + 5 doubles */
2307 1 : tl_write_uint32(&w, 0x03d1ea4eu);
2308 1 : tl_write_uint32(&w, 0);
2309 6 : for (int i = 0; i < 5; i++) tl_write_double(&w, 0.0);
2310 1 : tl_write_string(&w, "https://example.org");
2311 : /* privacy: [allowAll, allowUsers([7,11])]. */
2312 1 : tl_write_uint32(&w, TL_vector);
2313 1 : tl_write_uint32(&w, 2);
2314 1 : tl_write_uint32(&w, 0x65427b82u); /* privacyValueAllowAll */
2315 1 : tl_write_uint32(&w, 0xb8905fb2u); /* privacyValueAllowUsers */
2316 1 : tl_write_uint32(&w, TL_vector);
2317 1 : tl_write_uint32(&w, 2);
2318 1 : tl_write_int64 (&w, 7LL);
2319 1 : tl_write_int64 (&w, 11LL);
2320 1 : tl_write_int32 (&w, 0xC0DE);
2321 1 : TlReader r = tl_reader_init(w.data, w.len);
2322 1 : ASSERT(tl_skip_message_media_ex(&r, NULL) == 0,
2323 : "full storyItem with privacy + media_area iterates");
2324 1 : ASSERT(tl_read_int32(&r) == (int32_t)0xC0DE, "cursor past");
2325 1 : tl_writer_free(&w);
2326 : }
2327 :
2328 1 : static void test_skip_media_paid_unknown_variant_bails(void) {
2329 1 : TlWriter w; tl_writer_init(&w);
2330 1 : tl_write_uint32(&w, CRC_messageMediaPaidMedia_t);
2331 1 : tl_write_int64 (&w, 1LL);
2332 1 : tl_write_uint32(&w, TL_vector);
2333 1 : tl_write_uint32(&w, 1);
2334 1 : tl_write_uint32(&w, 0xdeadbeefu); /* unknown ExtendedMedia */
2335 1 : TlReader r = tl_reader_init(w.data, w.len);
2336 1 : ASSERT(tl_skip_message_media_ex(&r, NULL) == -1, "unknown variant bails");
2337 1 : tl_writer_free(&w);
2338 : }
2339 :
2340 1 : static void test_skip_factcheck_unknown_crc_bails(void) {
2341 1 : TlWriter w; tl_writer_init(&w);
2342 1 : tl_write_uint32(&w, 0xdeadbeefu);
2343 1 : TlReader r = tl_reader_init(w.data, w.len);
2344 1 : ASSERT(tl_skip_factcheck(&r) == -1, "unknown crc rejected");
2345 1 : tl_writer_free(&w);
2346 : }
2347 :
2348 1 : static void test_skip_reactions_recent_reactors_bails(void) {
2349 1 : TlWriter w; tl_writer_init(&w);
2350 1 : tl_write_uint32(&w, CRC_messageReactions_test);
2351 1 : tl_write_uint32(&w, (1u << 1)); /* recent_reactions present */
2352 1 : tl_write_uint32(&w, TL_vector);
2353 1 : tl_write_uint32(&w, 0); /* empty results */
2354 : /* recent_reactions would follow — we bail before reading. */
2355 1 : TlReader r = tl_reader_init(w.data, w.len);
2356 1 : ASSERT(tl_skip_message_reactions(&r) == -1, "bails on recent_reactions");
2357 1 : tl_writer_free(&w);
2358 : }
2359 :
2360 1 : void run_tl_skip_tests(void) {
2361 1 : RUN_TEST(test_skip_bool);
2362 1 : RUN_TEST(test_skip_string);
2363 1 : RUN_TEST(test_skip_peer);
2364 1 : RUN_TEST(test_skip_peer_unknown);
2365 1 : RUN_TEST(test_skip_notification_sound_default);
2366 1 : RUN_TEST(test_skip_notification_sound_ringtone);
2367 1 : RUN_TEST(test_skip_notification_sound_local);
2368 1 : RUN_TEST(test_skip_peer_notify_settings_empty);
2369 1 : RUN_TEST(test_skip_peer_notify_settings_full);
2370 1 : RUN_TEST(test_skip_draft_message_empty);
2371 1 : RUN_TEST(test_skip_message_entity_bold);
2372 1 : RUN_TEST(test_skip_message_entity_text_url);
2373 1 : RUN_TEST(test_skip_entities_vector);
2374 1 : RUN_TEST(test_skip_fwd_header_minimal);
2375 1 : RUN_TEST(test_skip_fwd_header_with_channel);
2376 1 : RUN_TEST(test_skip_reply_header_minimal);
2377 1 : RUN_TEST(test_skip_bool_short);
2378 1 : RUN_TEST(test_skip_notification_sound_unknown);
2379 1 : RUN_TEST(test_skip_peer_notify_settings_wrong_crc);
2380 1 : RUN_TEST(test_skip_draft_message_nonempty);
2381 1 : RUN_TEST(test_skip_draft_message_unknown);
2382 1 : RUN_TEST(test_skip_message_entity_unknown);
2383 1 : RUN_TEST(test_skip_entities_vector_wrong_header);
2384 1 : RUN_TEST(test_skip_fwd_header_wrong_crc);
2385 1 : RUN_TEST(test_skip_reply_header_wrong_crc);
2386 1 : RUN_TEST(test_skip_reply_header_reply_media_bail);
2387 1 : RUN_TEST(test_skip_media_empty);
2388 1 : RUN_TEST(test_skip_media_unsupported);
2389 1 : RUN_TEST(test_skip_media_geo_empty_point);
2390 1 : RUN_TEST(test_skip_media_geo);
2391 1 : RUN_TEST(test_skip_media_contact);
2392 1 : RUN_TEST(test_skip_media_dice);
2393 1 : RUN_TEST(test_skip_media_venue);
2394 1 : RUN_TEST(test_skip_media_photo_empty_photo);
2395 1 : RUN_TEST(test_skip_media_photo_with_sizes);
2396 1 : RUN_TEST(test_skip_media_document_empty);
2397 1 : RUN_TEST(test_skip_chat_forbidden);
2398 1 : RUN_TEST(test_skip_channel_forbidden);
2399 1 : RUN_TEST(test_skip_chat_plain);
2400 1 : RUN_TEST(test_skip_channel_minimal);
2401 1 : RUN_TEST(test_skip_user_empty);
2402 1 : RUN_TEST(test_skip_user_full);
2403 1 : RUN_TEST(test_extract_chat_forbidden);
2404 1 : RUN_TEST(test_extract_user);
2405 1 : RUN_TEST(test_extract_user_access_hash);
2406 1 : RUN_TEST(test_extract_channel_access_hash);
2407 1 : RUN_TEST(test_extract_channel_forbidden_access_hash);
2408 1 : RUN_TEST(test_extract_chat_no_access_hash);
2409 1 : RUN_TEST(test_skip_reply_markup_hide);
2410 1 : RUN_TEST(test_skip_reply_markup_force_reply_with_placeholder);
2411 1 : RUN_TEST(test_skip_reply_markup_inline_url_callback);
2412 1 : RUN_TEST(test_skip_reply_markup_unknown_bails);
2413 1 : RUN_TEST(test_skip_reply_markup_unknown_button_bails);
2414 1 : RUN_TEST(test_skip_reactions_empty_results);
2415 1 : RUN_TEST(test_skip_reactions_emoji_and_custom);
2416 1 : RUN_TEST(test_skip_reactions_recent_reactors_bails);
2417 1 : RUN_TEST(test_skip_message_replies_minimal);
2418 1 : RUN_TEST(test_skip_message_replies_with_commenters);
2419 1 : RUN_TEST(test_skip_message_replies_unknown_crc_bails);
2420 1 : RUN_TEST(test_skip_factcheck_need_check_only);
2421 1 : RUN_TEST(test_skip_factcheck_with_text);
2422 1 : RUN_TEST(test_skip_factcheck_unknown_crc_bails);
2423 1 : RUN_TEST(test_skip_media_webpage_empty);
2424 1 : RUN_TEST(test_skip_media_webpage_rich);
2425 1 : RUN_TEST(test_skip_media_webpage_pending);
2426 1 : RUN_TEST(test_skip_media_webpage_cached_page_simple);
2427 1 : RUN_TEST(test_skip_media_webpage_cached_page_textconcat);
2428 1 : RUN_TEST(test_skip_media_webpage_cached_page_unsupported);
2429 1 : RUN_TEST(test_skip_cached_page_blockquote);
2430 1 : RUN_TEST(test_skip_cached_page_photo);
2431 1 : RUN_TEST(test_skip_cached_page_video);
2432 1 : RUN_TEST(test_skip_cached_page_audio);
2433 1 : RUN_TEST(test_skip_cached_page_cover);
2434 1 : RUN_TEST(test_skip_cached_page_channel);
2435 1 : RUN_TEST(test_skip_cached_page_map);
2436 1 : RUN_TEST(test_skip_cached_page_list);
2437 1 : RUN_TEST(test_skip_cached_page_ordered_list);
2438 1 : RUN_TEST(test_skip_cached_page_collage);
2439 1 : RUN_TEST(test_skip_cached_page_slideshow);
2440 1 : RUN_TEST(test_skip_cached_page_details);
2441 1 : RUN_TEST(test_skip_cached_page_related_articles);
2442 1 : RUN_TEST(test_skip_cached_page_table);
2443 1 : RUN_TEST(test_skip_cached_page_embed);
2444 1 : RUN_TEST(test_skip_cached_page_embed_post);
2445 1 : RUN_TEST(test_skip_media_webpage_attributes_theme);
2446 1 : RUN_TEST(test_skip_media_webpage_attributes_stickerset);
2447 1 : RUN_TEST(test_skip_media_webpage_attributes_story_noinline);
2448 1 : RUN_TEST(test_skip_media_webpage_attributes_story_inline);
2449 1 : RUN_TEST(test_skip_media_webpage_attributes_unknown);
2450 1 : RUN_TEST(test_skip_media_webpage_cached_page_plus_attributes);
2451 1 : RUN_TEST(test_skip_media_document_full);
2452 1 : RUN_TEST(test_skip_media_document_with_thumbs);
2453 1 : RUN_TEST(test_skip_media_document_with_video_thumbs);
2454 1 : RUN_TEST(test_skip_media_document_sticker_attr);
2455 1 : RUN_TEST(test_skip_media_document_sticker_with_mask);
2456 1 : RUN_TEST(test_skip_media_document_custom_emoji_attr);
2457 1 : RUN_TEST(test_skip_media_poll_minimal);
2458 1 : RUN_TEST(test_skip_media_poll_with_results);
2459 1 : RUN_TEST(test_skip_media_invoice_minimal);
2460 1 : RUN_TEST(test_skip_media_invoice_photo_bails);
2461 1 : RUN_TEST(test_skip_media_story_minimal);
2462 1 : RUN_TEST(test_skip_media_giveaway_minimal);
2463 1 : RUN_TEST(test_skip_media_giveaway_countries_prize);
2464 1 : RUN_TEST(test_skip_media_game_photo_only);
2465 1 : RUN_TEST(test_skip_media_game_with_document);
2466 1 : RUN_TEST(test_skip_media_game_wrong_inner_crc_bails);
2467 1 : RUN_TEST(test_skip_media_paid_preview_only);
2468 1 : RUN_TEST(test_skip_media_paid_preview_with_dims_and_thumb);
2469 1 : RUN_TEST(test_skip_media_paid_wrapped_inner_media);
2470 1 : RUN_TEST(test_skip_media_paid_unknown_variant_bails);
2471 1 : RUN_TEST(test_skip_media_invoice_with_webdocument_photo);
2472 1 : RUN_TEST(test_skip_media_invoice_noproxy_webdocument);
2473 1 : RUN_TEST(test_skip_media_invoice_extended_media_preview);
2474 1 : RUN_TEST(test_skip_media_story_inline_deleted);
2475 1 : RUN_TEST(test_skip_media_story_inline_skipped);
2476 1 : RUN_TEST(test_skip_media_story_truncated_full_bails);
2477 1 : RUN_TEST(test_skip_media_story_full_minimal);
2478 1 : RUN_TEST(test_skip_media_story_full_with_views);
2479 1 : RUN_TEST(test_skip_media_story_inner_media_photo);
2480 1 : RUN_TEST(test_skip_media_story_nested_recursion_guard);
2481 1 : RUN_TEST(test_skip_media_story_full_with_privacy_and_area);
2482 1 : }
|