Line data Source code
1 : /**
2 : * @file test_domain_upload.c
3 : * @brief Unit tests for domain_send_file (US-P6-02).
4 : */
5 :
6 : #include "test_helpers.h"
7 : #include "domain/write/upload.h"
8 : #include "tl_serial.h"
9 : #include "tl_registry.h"
10 : #include "mock_socket.h"
11 : #include "mock_crypto.h"
12 : #include "mtproto_session.h"
13 : #include "transport.h"
14 : #include "api_call.h"
15 :
16 : #include <stdio.h>
17 : #include <stdlib.h>
18 : #include <string.h>
19 : #include <unistd.h>
20 :
21 32 : static void build_fake_encrypted_response(const uint8_t *payload, size_t plen,
22 : uint8_t *out, size_t *out_len) {
23 32 : TlWriter w; tl_writer_init(&w);
24 32 : uint8_t zeros24[24] = {0}; tl_write_raw(&w, zeros24, 24);
25 32 : uint8_t header[32] = {0};
26 32 : uint32_t plen32 = (uint32_t)plen;
27 32 : memcpy(header + 28, &plen32, 4);
28 32 : tl_write_raw(&w, header, 32);
29 32 : tl_write_raw(&w, payload, plen);
30 32 : size_t enc = w.len - 24;
31 32 : if (enc % 16 != 0) {
32 32 : uint8_t pad[16] = {0}; tl_write_raw(&w, pad, 16 - (enc % 16));
33 : }
34 32 : size_t dwords = w.len / 4;
35 32 : size_t off = 0;
36 32 : if (dwords < 0x7F) { out[0] = (uint8_t)dwords; off = 1; }
37 : else {
38 0 : out[0] = 0x7F;
39 0 : out[1] = (uint8_t)dwords;
40 0 : out[2] = (uint8_t)(dwords >> 8);
41 0 : out[3] = (uint8_t)(dwords >> 16);
42 0 : off = 4;
43 : }
44 32 : memcpy(out + off, w.data, w.len);
45 32 : *out_len = off + w.len;
46 32 : tl_writer_free(&w);
47 32 : }
48 :
49 9 : static void fix_session(MtProtoSession *s) {
50 9 : mtproto_session_init(s);
51 9 : s->session_id = 0; /* match the zero session_id in fake encrypted frames */
52 9 : uint8_t k[256] = {0}; mtproto_session_set_auth_key(s, k);
53 9 : mtproto_session_set_salt(s, 0xBADCAFEDEADBEEFULL);
54 9 : }
55 9 : static void fix_transport(Transport *t) {
56 9 : transport_init(t); t->fd = 42; t->connected = 1; t->dc_id = 1;
57 9 : }
58 9 : static void fix_cfg(ApiConfig *cfg) {
59 9 : api_config_init(cfg); cfg->api_id = 12345; cfg->api_hash = "deadbeef";
60 9 : }
61 :
62 : /* Write a small temp file, return its path (caller unlinks). */
63 5 : static void write_temp(const char *path, const uint8_t *data, size_t n) {
64 5 : FILE *fp = fopen(path, "wb");
65 5 : if (fp) { fwrite(data, 1, n, fp); fclose(fp); }
66 5 : }
67 :
68 : /* Build a response buffer carrying two frames: boolTrue (for
69 : * saveFilePart) followed by updateShort (for sendMedia). */
70 3 : static void seed_two_frame_response(void) {
71 3 : mock_socket_reset();
72 :
73 : /* frame 1: boolTrue */
74 3 : TlWriter w1; tl_writer_init(&w1);
75 3 : tl_write_uint32(&w1, TL_boolTrue);
76 3 : uint8_t resp1[128]; size_t r1 = 0;
77 3 : build_fake_encrypted_response(w1.data, w1.len, resp1, &r1);
78 3 : tl_writer_free(&w1);
79 :
80 : /* frame 2: updateShort (crc + 4 bytes update + 4 bytes date) */
81 3 : TlWriter w2; tl_writer_init(&w2);
82 3 : tl_write_uint32(&w2, TL_updateShort);
83 3 : tl_write_uint32(&w2, 0);
84 3 : tl_write_int32 (&w2, 1700000000);
85 3 : uint8_t resp2[128]; size_t r2 = 0;
86 3 : build_fake_encrypted_response(w2.data, w2.len, resp2, &r2);
87 3 : tl_writer_free(&w2);
88 :
89 3 : mock_socket_set_response(resp1, r1);
90 3 : mock_socket_append_response(resp2, r2);
91 3 : }
92 :
93 1 : static void test_upload_small_file_success(void) {
94 1 : mock_crypto_reset();
95 1 : const char *path = "/tmp/tg-cli-upload-test.bin";
96 1 : unlink(path);
97 : uint8_t body[200];
98 201 : for (size_t i = 0; i < sizeof(body); i++) body[i] = (uint8_t)i;
99 1 : write_temp(path, body, sizeof(body));
100 :
101 1 : seed_two_frame_response();
102 :
103 : MtProtoSession s; Transport t; ApiConfig cfg;
104 1 : fix_session(&s); fix_transport(&t); fix_cfg(&cfg);
105 1 : HistoryPeer peer = { .kind = HISTORY_PEER_SELF };
106 1 : RpcError err = {0};
107 1 : int rc = domain_send_file(&cfg, &s, &t, &peer, path, "hello", NULL, &err);
108 1 : ASSERT(rc == 0, "upload ok for a small file");
109 1 : unlink(path);
110 : }
111 :
112 1 : static void test_upload_rejects_missing_file(void) {
113 : MtProtoSession s; Transport t; ApiConfig cfg;
114 1 : fix_session(&s); fix_transport(&t); fix_cfg(&cfg);
115 1 : HistoryPeer peer = { .kind = HISTORY_PEER_SELF };
116 1 : int rc = domain_send_file(&cfg, &s, &t, &peer,
117 : "/tmp/tg-cli-no-such-file", NULL, NULL, NULL);
118 1 : ASSERT(rc == -1, "missing file rejected");
119 : }
120 :
121 1 : static void test_upload_rejects_empty_file(void) {
122 1 : const char *path = "/tmp/tg-cli-upload-empty.bin";
123 1 : unlink(path);
124 1 : FILE *fp = fopen(path, "wb"); if (fp) fclose(fp);
125 :
126 : MtProtoSession s; Transport t; ApiConfig cfg;
127 1 : fix_session(&s); fix_transport(&t); fix_cfg(&cfg);
128 1 : HistoryPeer peer = { .kind = HISTORY_PEER_SELF };
129 1 : int rc = domain_send_file(&cfg, &s, &t, &peer, path, NULL, NULL, NULL);
130 1 : ASSERT(rc == -1, "empty file rejected");
131 1 : unlink(path);
132 : }
133 :
134 1 : static void test_upload_null_args(void) {
135 1 : ASSERT(domain_send_file(NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL) == -1,
136 : "null args rejected");
137 : }
138 :
139 : /* Wire-inspection: the outbound buffer must contain the
140 : * upload.saveFilePart CRC and the filename + mime type. */
141 1 : static void test_upload_writes_expected_bytes(void) {
142 1 : mock_crypto_reset();
143 1 : const char *path = "/tmp/tg-cli-upload-inspect.bin";
144 1 : unlink(path);
145 : uint8_t body[32];
146 33 : for (size_t i = 0; i < sizeof(body); i++) body[i] = (uint8_t)(i + 1);
147 1 : write_temp(path, body, sizeof(body));
148 :
149 1 : seed_two_frame_response();
150 :
151 : MtProtoSession s; Transport t; ApiConfig cfg;
152 1 : fix_session(&s); fix_transport(&t); fix_cfg(&cfg);
153 1 : HistoryPeer peer = { .kind = HISTORY_PEER_SELF };
154 1 : int rc = domain_send_file(&cfg, &s, &t, &peer, path,
155 : "hi", "text/plain", NULL);
156 1 : ASSERT(rc == 0, "upload ok");
157 :
158 1 : size_t sent_len = 0;
159 1 : const uint8_t *sent = mock_socket_get_sent(&sent_len);
160 :
161 1 : uint32_t crc_part = 0xb304a621u;
162 1 : int found_part = 0;
163 114 : for (size_t i = 0; i + 4 <= sent_len; i++)
164 114 : if (memcmp(sent + i, &crc_part, 4) == 0) { found_part = 1; break; }
165 1 : ASSERT(found_part, "upload.saveFilePart CRC present on the wire");
166 :
167 1 : int found_name = 0;
168 1 : const char *basename = "tg-cli-upload-inspect.bin";
169 336 : for (size_t i = 0; i + strlen(basename) <= sent_len; i++)
170 336 : if (memcmp(sent + i, basename, strlen(basename)) == 0) {
171 1 : found_name = 1; break;
172 : }
173 1 : ASSERT(found_name, "filename appears in sendMedia payload");
174 :
175 1 : int found_mime = 0;
176 1 : const char *mime = "text/plain";
177 368 : for (size_t i = 0; i + strlen(mime) <= sent_len; i++)
178 368 : if (memcmp(sent + i, mime, strlen(mime)) == 0) {
179 1 : found_mime = 1; break;
180 : }
181 1 : ASSERT(found_mime, "mime_type appears in sendMedia payload");
182 :
183 1 : unlink(path);
184 : }
185 :
186 : /* Seed the mock socket with @p n boolTrue frames (for N saveBigFilePart
187 : * acks) followed by an updateShort frame (for the final sendMedia). */
188 1 : static void seed_big_response(int n_parts) {
189 1 : mock_socket_reset();
190 25 : for (int i = 0; i < n_parts; i++) {
191 24 : TlWriter w; tl_writer_init(&w);
192 24 : tl_write_uint32(&w, TL_boolTrue);
193 24 : uint8_t resp[128]; size_t rlen = 0;
194 24 : build_fake_encrypted_response(w.data, w.len, resp, &rlen);
195 24 : tl_writer_free(&w);
196 24 : if (i == 0) mock_socket_set_response(resp, rlen);
197 23 : else mock_socket_append_response(resp, rlen);
198 : }
199 1 : TlWriter w; tl_writer_init(&w);
200 1 : tl_write_uint32(&w, TL_updateShort);
201 1 : tl_write_uint32(&w, 0);
202 1 : tl_write_int32 (&w, 1700000000);
203 1 : uint8_t resp[128]; size_t rlen = 0;
204 1 : build_fake_encrypted_response(w.data, w.len, resp, &rlen);
205 1 : tl_writer_free(&w);
206 1 : mock_socket_append_response(resp, rlen);
207 1 : }
208 :
209 1 : static void test_upload_big_file_uses_saveBigFilePart(void) {
210 1 : mock_crypto_reset();
211 1 : const char *path = "/tmp/tg-cli-upload-big.bin";
212 1 : unlink(path);
213 :
214 : /* 12 MiB, just over the 10 MiB big threshold. */
215 1 : const size_t big_size = 12 * 1024 * 1024;
216 1 : uint8_t *body = (uint8_t *)malloc(big_size);
217 1 : ASSERT(body != NULL, "alloc 12 MiB body");
218 12582913 : for (size_t i = 0; i < big_size; i++) body[i] = (uint8_t)(i & 0xff);
219 1 : write_temp(path, body, big_size);
220 1 : free(body);
221 :
222 1 : int expected_parts = (int)((big_size + UPLOAD_CHUNK_SIZE - 1)
223 1 : / UPLOAD_CHUNK_SIZE);
224 1 : seed_big_response(expected_parts);
225 :
226 : MtProtoSession s; Transport t; ApiConfig cfg;
227 1 : fix_session(&s); fix_transport(&t); fix_cfg(&cfg);
228 1 : HistoryPeer peer = { .kind = HISTORY_PEER_SELF };
229 1 : int rc = domain_send_file(&cfg, &s, &t, &peer, path, NULL, NULL, NULL);
230 1 : ASSERT(rc == 0, "big-file upload ok");
231 :
232 1 : size_t sent_len = 0;
233 1 : const uint8_t *sent = mock_socket_get_sent(&sent_len);
234 :
235 1 : uint32_t big_part = 0xde7b673du;
236 1 : int found_big = 0;
237 117 : for (size_t i = 0; i + 4 <= sent_len; i++)
238 117 : if (memcmp(sent + i, &big_part, 4) == 0) { found_big = 1; break; }
239 1 : ASSERT(found_big, "upload.saveBigFilePart CRC transmitted");
240 :
241 1 : uint32_t input_file_big = 0xfa4f0bb5u;
242 1 : int found_ifb = 0;
243 12586790 : for (size_t i = 0; i + 4 <= sent_len; i++)
244 12586790 : if (memcmp(sent + i, &input_file_big, 4) == 0) { found_ifb = 1; break; }
245 1 : ASSERT(found_ifb, "inputFileBig CRC on sendMedia");
246 :
247 : /* Plain saveFilePart CRC must NOT appear when is_big. */
248 1 : uint32_t small_part = 0xb304a621u;
249 1 : int found_small = 0;
250 12586919 : for (size_t i = 0; i + 4 <= sent_len; i++)
251 12586918 : if (memcmp(sent + i, &small_part, 4) == 0) {
252 0 : found_small = 1; break;
253 : }
254 1 : ASSERT(!found_small, "saveFilePart NOT used for big file");
255 :
256 1 : unlink(path);
257 : }
258 :
259 1 : static void test_upload_rejects_oversized_file(void) {
260 : /* Fabricate a file just over UPLOAD_MAX_SIZE by seeking — avoids
261 : * actually writing 1.5 GiB. */
262 1 : const char *path = "/tmp/tg-cli-upload-oversize.bin";
263 1 : unlink(path);
264 1 : FILE *fp = fopen(path, "wb");
265 1 : ASSERT(fp != NULL, "open oversize file");
266 1 : if (fp) {
267 1 : off_t too_big = (off_t)UPLOAD_MAX_SIZE + 1024;
268 : /* Seek then write one byte to create a sparse file. */
269 1 : if (fseeko(fp, too_big - 1, SEEK_SET) == 0) {
270 1 : fputc(0, fp);
271 : }
272 1 : fclose(fp);
273 : }
274 :
275 : MtProtoSession s; Transport t; ApiConfig cfg;
276 1 : fix_session(&s); fix_transport(&t); fix_cfg(&cfg);
277 1 : HistoryPeer peer = { .kind = HISTORY_PEER_SELF };
278 1 : int rc = domain_send_file(&cfg, &s, &t, &peer, path, NULL, NULL, NULL);
279 1 : ASSERT(rc == -1, "over-cap file rejected");
280 1 : unlink(path);
281 : }
282 :
283 : /* saveFilePart returns a non-migrate RPC error — domain_send_file must
284 : * bail out rather than entering the cross-DC retry path. */
285 1 : static void test_upload_non_migrate_error_bails(void) {
286 1 : mock_crypto_reset();
287 :
288 1 : const char *path = "/tmp/tg-cli-upload-err.bin";
289 1 : unlink(path);
290 : uint8_t body[64];
291 65 : for (size_t i = 0; i < sizeof(body); i++) body[i] = (uint8_t)i;
292 1 : write_temp(path, body, sizeof(body));
293 :
294 : /* Prime one frame with an FLOOD_WAIT_10 RPC error (no migrate_dc). */
295 : uint8_t payload[128];
296 1 : TlWriter w; tl_writer_init(&w);
297 1 : tl_write_uint32(&w, TL_rpc_error);
298 1 : tl_write_int32 (&w, 420);
299 1 : tl_write_string(&w, "FLOOD_WAIT_10");
300 1 : memcpy(payload, w.data, w.len);
301 1 : size_t plen = w.len;
302 1 : tl_writer_free(&w);
303 :
304 1 : uint8_t resp[512]; size_t rlen = 0;
305 1 : build_fake_encrypted_response(payload, plen, resp, &rlen);
306 1 : mock_socket_reset();
307 1 : mock_socket_set_response(resp, rlen);
308 :
309 : MtProtoSession s; Transport t; ApiConfig cfg;
310 1 : fix_session(&s); fix_transport(&t); fix_cfg(&cfg);
311 1 : int creates_before = mock_socket_was_created();
312 :
313 1 : HistoryPeer peer = { .kind = HISTORY_PEER_SELF };
314 1 : int rc = domain_send_file(&cfg, &s, &t, &peer, path, NULL, NULL, NULL);
315 1 : ASSERT(rc == -1, "non-migrate error propagates");
316 1 : ASSERT(mock_socket_was_created() == creates_before,
317 : "no cross-DC socket opened for non-migrate error");
318 1 : unlink(path);
319 : }
320 :
321 : /* ---- LIM-01: photo upload ---- */
322 :
323 1 : static void test_path_is_image_detects_common_extensions(void) {
324 1 : ASSERT(domain_path_is_image("foo.jpg") == 1, "jpg is image");
325 1 : ASSERT(domain_path_is_image("/a/b.JPEG") == 1, "JPEG case-insensitive");
326 1 : ASSERT(domain_path_is_image("/abc/x.png") == 1, "png is image");
327 1 : ASSERT(domain_path_is_image("/abc/x.Webp") == 1, "Webp case");
328 1 : ASSERT(domain_path_is_image("a.gif") == 1, "gif is image");
329 1 : ASSERT(domain_path_is_image("a.pdf") == 0, "pdf not image");
330 1 : ASSERT(domain_path_is_image("a.txt") == 0, "txt not image");
331 1 : ASSERT(domain_path_is_image("noext") == 0, "no extension not image");
332 1 : ASSERT(domain_path_is_image("") == 0, "empty not image");
333 1 : ASSERT(domain_path_is_image(NULL) == 0, "NULL safe");
334 : }
335 :
336 1 : static void test_send_photo_small_success(void) {
337 1 : mock_crypto_reset();
338 1 : const char *path = "/tmp/tg-cli-photo.jpg";
339 1 : unlink(path);
340 : uint8_t body[256];
341 257 : for (size_t i = 0; i < sizeof(body); i++) body[i] = (uint8_t)(i * 3);
342 1 : write_temp(path, body, sizeof(body));
343 :
344 1 : seed_two_frame_response();
345 :
346 : MtProtoSession s; Transport t; ApiConfig cfg;
347 1 : fix_session(&s); fix_transport(&t); fix_cfg(&cfg);
348 1 : HistoryPeer peer = { .kind = HISTORY_PEER_SELF };
349 1 : RpcError err = {0};
350 1 : int rc = domain_send_photo(&cfg, &s, &t, &peer, path, "cheese", &err);
351 1 : ASSERT(rc == 0, "photo upload ok");
352 :
353 1 : size_t sent_len = 0;
354 1 : const uint8_t *sent = mock_socket_get_sent(&sent_len);
355 :
356 : /* inputMediaUploadedPhoto CRC must appear — not the document one. */
357 1 : uint32_t photo_crc = 0x1e287d04u;
358 1 : uint32_t doc_crc = 0x5b38c6c1u;
359 1 : int found_photo = 0, found_doc = 0;
360 608 : for (size_t i = 0; i + 4 <= sent_len; i++) {
361 607 : if (memcmp(sent + i, &photo_crc, 4) == 0) found_photo = 1;
362 607 : if (memcmp(sent + i, &doc_crc, 4) == 0) found_doc = 1;
363 : }
364 1 : ASSERT(found_photo, "inputMediaUploadedPhoto on the wire");
365 1 : ASSERT(!found_doc, "inputMediaUploadedDocument NOT on the wire");
366 :
367 1 : unlink(path);
368 : }
369 :
370 1 : static void test_send_photo_null_args(void) {
371 1 : ASSERT(domain_send_photo(NULL, NULL, NULL, NULL, NULL, NULL, NULL) == -1,
372 : "null args rejected");
373 : }
374 :
375 1 : static void test_send_photo_rejects_missing_file(void) {
376 : MtProtoSession s; Transport t; ApiConfig cfg;
377 1 : fix_session(&s); fix_transport(&t); fix_cfg(&cfg);
378 1 : HistoryPeer peer = { .kind = HISTORY_PEER_SELF };
379 1 : int rc = domain_send_photo(&cfg, &s, &t, &peer,
380 : "/tmp/tg-cli-no-such-photo", NULL, NULL);
381 1 : ASSERT(rc == -1, "missing photo rejected");
382 : }
383 :
384 : /* TEST-37: Empty TL string encoding of md5_checksum in inputFile.
385 : *
386 : * An empty TL string is encoded as: 0x00 (1-byte length prefix = 0) followed
387 : * by 3 zero padding bytes → 4 bytes total: { 0x00, 0x00, 0x00, 0x00 }.
388 : *
389 : * Build what write_input_file() would produce for a small (non-big) file and
390 : * verify the md5_checksum field appears as exactly these 4 bytes after the
391 : * filename TL string. For inputFileBig, confirm those 4 bytes are absent
392 : * from the serialized body (the spec omits md5_checksum entirely).
393 : */
394 1 : static void test_inputfile_md5_empty_tl_encoding(void) {
395 : /* Replicate write_input_file logic for a small file. */
396 1 : TlWriter w; tl_writer_init(&w);
397 1 : uint32_t crc_inputFile = 0xf52ff27fu;
398 1 : tl_write_uint32(&w, crc_inputFile);
399 1 : tl_write_int64 (&w, (int64_t)0x1122334455667788LL); /* file_id */
400 1 : tl_write_int32 (&w, 1); /* part_count */
401 1 : tl_write_string(&w, "test.bin"); /* file_name */
402 1 : tl_write_string(&w, ""); /* md5_checksum */
403 :
404 : /* The last 4 bytes of the serialized buffer must be the empty TL string:
405 : * 0x00 (len=0) + 3 zero pad bytes. */
406 1 : ASSERT(w.len >= 4, "inputFile serialization has at least 4 bytes");
407 1 : const uint8_t *tail = w.data + w.len - 4;
408 1 : uint8_t expected[4] = {0x00, 0x00, 0x00, 0x00};
409 1 : ASSERT(memcmp(tail, expected, 4) == 0,
410 : "inputFile md5_checksum is 4 zero bytes (empty TL string)");
411 :
412 : /* Verify the CRC is at the start. */
413 1 : uint32_t got_crc = 0;
414 1 : memcpy(&got_crc, w.data, 4);
415 1 : ASSERT(got_crc == crc_inputFile, "inputFile CRC at offset 0");
416 :
417 1 : tl_writer_free(&w);
418 : }
419 :
420 1 : static void test_inputfilebig_has_no_md5_field(void) {
421 : /* Replicate write_input_file logic for a big file (no md5_checksum). */
422 1 : TlWriter w; tl_writer_init(&w);
423 1 : uint32_t crc_inputFileBig = 0xfa4f0bb5u;
424 1 : tl_write_uint32(&w, crc_inputFileBig);
425 1 : tl_write_int64 (&w, (int64_t)0xAABBCCDDEEFF0011LL); /* file_id */
426 1 : tl_write_int32 (&w, 3); /* part_count */
427 1 : tl_write_string(&w, "big.bin"); /* file_name */
428 : /* No md5_checksum field for inputFileBig. */
429 :
430 : /* The last 4 bytes are the tail of the filename TL string, NOT an empty
431 : * md5 field. Scan the entire buffer: an empty TL string (0 0 0 0) might
432 : * coincidentally appear in the padding of the filename, but it must NOT
433 : * be appended as an extra field. The total length must match exactly the
434 : * layout without a trailing empty string. */
435 :
436 : /* Expected layout:
437 : * 4 CRC
438 : * 8 file_id
439 : * 4 part_count
440 : * ? tl_string("big.bin") = 1 + 7 + 0 pad = 8 bytes
441 : * Total = 24 bytes. With md5 it would be 28. */
442 1 : ASSERT(w.len == 24, "inputFileBig serialized length is 24 (no md5 field)");
443 :
444 1 : uint32_t got_crc = 0;
445 1 : memcpy(&got_crc, w.data, 4);
446 1 : ASSERT(got_crc == crc_inputFileBig, "inputFileBig CRC at offset 0");
447 :
448 1 : tl_writer_free(&w);
449 : }
450 :
451 1 : void run_domain_upload_tests(void) {
452 1 : RUN_TEST(test_upload_small_file_success);
453 1 : RUN_TEST(test_upload_rejects_missing_file);
454 1 : RUN_TEST(test_upload_rejects_empty_file);
455 1 : RUN_TEST(test_upload_null_args);
456 1 : RUN_TEST(test_upload_writes_expected_bytes);
457 1 : RUN_TEST(test_upload_big_file_uses_saveBigFilePart);
458 1 : RUN_TEST(test_upload_rejects_oversized_file);
459 1 : RUN_TEST(test_upload_non_migrate_error_bails);
460 1 : RUN_TEST(test_path_is_image_detects_common_extensions);
461 1 : RUN_TEST(test_send_photo_small_success);
462 1 : RUN_TEST(test_send_photo_null_args);
463 1 : RUN_TEST(test_send_photo_rejects_missing_file);
464 1 : RUN_TEST(test_inputfile_md5_empty_tl_encoding);
465 1 : RUN_TEST(test_inputfilebig_has_no_md5_field);
466 1 : }
|