1 /*
2
3 Copyright (c) 2012, Arvid Norberg
4 All rights reserved.
5
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions
8 are met:
9
10 * Redistributions of source code must retain the above copyright
11 notice, this list of conditions and the following disclaimer.
12 * Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions and the following disclaimer in
14 the documentation and/or other materials provided with the distribution.
15 * Neither the name of the author nor the names of its
16 contributors may be used to endorse or promote products derived
17 from this software without specific prior written permission.
18
19 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 POSSIBILITY OF SUCH DAMAGE.
30
31 */
32
33 #include "test.hpp"
34 #include "libtorrent/file_storage.hpp"
35 #include "libtorrent/aux_/path.hpp"
36 #include "libtorrent/torrent_info.hpp"
37 #include "libtorrent/create_torrent.hpp"
38 #include "libtorrent/announce_entry.hpp"
39 #include "libtorrent/aux_/escape_string.hpp" // for convert_path_to_posix
40 #include "libtorrent/hex.hpp" // to_hex
41
42 #include <iostream>
43
44 using namespace lt;
45
46 #ifndef TORRENT_DISABLE_MUTABLE_TORRENTS
TORRENT_TEST(mutable_torrents)47 TORRENT_TEST(mutable_torrents)
48 {
49 file_storage fs;
50
51 fs.add_file("test/temporary.txt", 0x4000);
52
53 lt::create_torrent t(fs, 0x4000);
54
55 // calculate the hash for all pieces
56 sha1_hash ph;
57 for (auto const i : fs.piece_range())
58 t.set_hash(i, ph);
59
60 t.add_collection("collection1");
61 t.add_collection("collection2");
62
63 t.add_similar_torrent(sha1_hash("abababababababababab"));
64 t.add_similar_torrent(sha1_hash("babababababababababa"));
65
66 std::vector<char> tmp;
67 std::back_insert_iterator<std::vector<char>> out(tmp);
68
69 entry tor = t.generate();
70 bencode(out, tor);
71
72 torrent_info ti(tmp, from_span);
73
74 std::vector<sha1_hash> similar;
75 similar.push_back(sha1_hash("abababababababababab"));
76 similar.push_back(sha1_hash("babababababababababa"));
77
78 std::vector<std::string> collections;
79 collections.push_back("collection1");
80 collections.push_back("collection2");
81
82 TEST_CHECK(similar == ti.similar_torrents());
83 TEST_CHECK(collections == ti.collections());
84 }
85 #endif
86
87 namespace {
88
89 struct test_torrent_t
90 {
91 char const* file;
92 };
93
94 using namespace lt;
95
96 static test_torrent_t test_torrents[] =
97 {
98 { "base.torrent" },
99 { "empty_path.torrent" },
100 { "parent_path.torrent" },
101 { "hidden_parent_path.torrent" },
102 { "single_multi_file.torrent" },
103 { "slash_path.torrent" },
104 { "slash_path2.torrent" },
105 { "slash_path3.torrent" },
106 { "backslash_path.torrent" },
107 { "url_list.torrent" },
108 { "url_list2.torrent" },
109 { "url_list3.torrent" },
110 { "httpseed.torrent" },
111 { "empty_httpseed.torrent" },
112 { "long_name.torrent" },
113 { "whitespace_url.torrent" },
114 { "duplicate_files.torrent" },
115 { "pad_file.torrent" },
116 { "creation_date.torrent" },
117 { "no_creation_date.torrent" },
118 { "url_seed.torrent" },
119 { "url_seed_multi.torrent" },
120 { "url_seed_multi_single_file.torrent" },
121 { "url_seed_multi_space.torrent" },
122 { "url_seed_multi_space_nolist.torrent" },
123 { "root_hash.torrent" },
124 { "empty_path_multi.torrent" },
125 { "duplicate_web_seeds.torrent" },
126 { "invalid_name2.torrent" },
127 { "invalid_name3.torrent" },
128 { "symlink1.torrent" },
129 { "symlink2.torrent" },
130 { "unordered.torrent" },
131 { "symlink_zero_size.torrent" },
132 { "pad_file_no_path.torrent" },
133 { "large.torrent" },
134 { "absolute_filename.torrent" },
135 { "invalid_filename.torrent" },
136 { "invalid_filename2.torrent" },
137 { "overlapping_symlinks.torrent" },
138 };
139
140 struct test_failing_torrent_t
141 {
142 char const* file;
143 error_code error; // the expected error
144 };
145
146 test_failing_torrent_t test_error_torrents[] =
147 {
148 { "missing_piece_len.torrent", errors::torrent_missing_piece_length },
149 { "invalid_piece_len.torrent", errors::torrent_missing_piece_length },
150 { "negative_piece_len.torrent", errors::torrent_missing_piece_length },
151 { "no_name.torrent", errors::torrent_missing_name },
152 { "bad_name.torrent", errors::torrent_missing_name },
153 { "invalid_name.torrent", errors::torrent_missing_name },
154 { "invalid_info.torrent", errors::torrent_missing_info },
155 { "string.torrent", errors::torrent_is_no_dict },
156 { "negative_size.torrent", errors::torrent_invalid_length },
157 { "negative_file_size.torrent", errors::torrent_invalid_length },
158 { "invalid_path_list.torrent", errors::torrent_invalid_name},
159 { "missing_path_list.torrent", errors::torrent_missing_name },
160 { "invalid_pieces.torrent", errors::torrent_missing_pieces },
161 { "unaligned_pieces.torrent", errors::torrent_invalid_hashes },
162 { "invalid_root_hash.torrent", errors::torrent_invalid_hashes },
163 { "invalid_root_hash2.torrent", errors::torrent_missing_pieces },
164 { "invalid_merkle.torrent", errors::no_files_in_torrent},
165 { "invalid_file_size.torrent", errors::torrent_invalid_length },
166 { "invalid_symlink.torrent", errors::torrent_invalid_name },
167 { "many_pieces.torrent", errors::too_many_pieces_in_torrent },
168 { "no_files.torrent", errors::no_files_in_torrent},
169 { "zero.torrent", errors::torrent_invalid_length},
170 { "zero2.torrent", errors::torrent_invalid_length},
171 };
172
173 } // anonymous namespace
174
175 // TODO: test remap_files
176 // TODO: merkle torrents. specifically torrent_info::add_merkle_nodes and torrent with "root hash"
177 // TODO: torrent with 'p' (padfile) attribute
178 // TODO: torrent with 'h' (hidden) attribute
179 // TODO: torrent with 'x' (executable) attribute
180 // TODO: torrent with 'l' (symlink) attribute
181 // TODO: creating a merkle torrent (torrent_info::build_merkle_list)
182 // TODO: torrent with multiple trackers in multiple tiers, making sure we
183 // shuffle them (how do you test shuffling?, load it multiple times and make
184 // sure it's in different order at least once)
185 // TODO: torrents with a zero-length name
186 // TODO: torrents with a merkle tree and add_merkle_nodes
187 // TODO: torrent with a non-dictionary info-section
188 // TODO: torrents with DHT nodes
189 // TODO: torrent with url-list as a single string
190 // TODO: torrent with http seed as a single string
191 // TODO: torrent with a comment
192 // TODO: torrent with an SSL cert
193 // TODO: torrent with attributes (executable and hidden)
194 // TODO: torrent_info::add_tracker
195 // TODO: torrent_info constructor that takes an invalid bencoded buffer
196 // TODO: verify_encoding with a string that triggers character replacement
197
TORRENT_TEST(url_list_and_httpseeds)198 TORRENT_TEST(url_list_and_httpseeds)
199 {
200 entry info;
201 info["pieces"] = "aaaaaaaaaaaaaaaaaaaa";
202 info["name.utf-8"] = "test1";
203 info["name"] = "test__";
204 info["piece length"] = 16 * 1024;
205 info["length"] = 3245;
206 entry::list_type l;
207 l.push_back(entry("http://foo.com/bar1"));
208 l.push_back(entry("http://foo.com/bar1"));
209 l.push_back(entry("http://foo.com/bar2"));
210 entry const e(l);
211 entry torrent;
212 torrent["url-list"] = e;
213 torrent["httpseeds"] = e;
214 torrent["info"] = info;
215 std::vector<char> buf;
216 bencode(std::back_inserter(buf), torrent);
217 torrent_info ti(buf, from_span);
218 TEST_EQUAL(ti.web_seeds().size(), 4);
219 }
220
TORRENT_TEST(add_url_seed)221 TORRENT_TEST(add_url_seed)
222 {
223 torrent_info ti(sha1_hash(" "));
224 TEST_EQUAL(ti.web_seeds().size(), 0);
225
226 ti.add_url_seed("http://test.com");
227
228 TEST_EQUAL(ti.web_seeds().size(), 1);
229 web_seed_entry we = ti.web_seeds()[0];
230 TEST_EQUAL(we.type, web_seed_entry::url_seed);
231 TEST_EQUAL(we.url, "http://test.com");
232 }
233
TORRENT_TEST(add_http_seed)234 TORRENT_TEST(add_http_seed)
235 {
236 torrent_info ti(sha1_hash(" "));
237 TEST_EQUAL(ti.web_seeds().size(), 0);
238
239 ti.add_http_seed("http://test.com");
240
241 TEST_EQUAL(ti.web_seeds().size(), 1);
242 web_seed_entry we = ti.web_seeds()[0];
243 TEST_EQUAL(we.type, web_seed_entry::http_seed);
244 TEST_EQUAL(we.url, "http://test.com");
245 }
246
TORRENT_TEST(set_web_seeds)247 TORRENT_TEST(set_web_seeds)
248 {
249 torrent_info ti(sha1_hash(" "));
250 TEST_EQUAL(ti.web_seeds().size(), 0);
251
252 std::vector<web_seed_entry> seeds;
253 web_seed_entry e1("http://test1.com", web_seed_entry::url_seed);
254 seeds.push_back(e1);
255 web_seed_entry e2("http://test2com", web_seed_entry::http_seed);
256 seeds.push_back(e2);
257
258 ti.set_web_seeds(seeds);
259
260 TEST_EQUAL(ti.web_seeds().size(), 2);
261 TEST_CHECK(ti.web_seeds() == seeds);
262 }
263
264 #ifdef TORRENT_WINDOWS
265 #define SEPARATOR "\\"
266 #else
267 #define SEPARATOR "/"
268 #endif
269
TORRENT_TEST(sanitize_path_truncate)270 TORRENT_TEST(sanitize_path_truncate)
271 {
272 std::string path;
273 sanitize_append_path_element(path,
274 "abcdefghi_abcdefghi_abcdefghi_abcdefghi_abcdefghi_"
275 "abcdefghi_abcdefghi_abcdefghi_abcdefghi_abcdefghi_"
276 "abcdefghi_abcdefghi_abcdefghi_abcdefghi_abcdefghi_"
277 "abcdefghi_abcdefghi_abcdefghi_abcdefghi_abcdefghi_"
278 "abcdefghi_abcdefghi_abcdefghi_abcdefghi_abcdefghi_");
279 sanitize_append_path_element(path,
280 "abcdefghi_abcdefghi_abcdefghi_abcdefghi_abcdefghi_"
281 "abcdefghi_abcdefghi_abcdefghi_abcdefghi_abcdefghi_"
282 "abcdefghi_abcdefghi_abcdefghi_abcdefghi_abcdefghi_"
283 "abcdefghi_abcdefghi_abcdefghi_abcdefghi_abcdefghi_"
284 "abcdefghi_abcdefghi_abcdefghi_abcdefghi_abcde.test");
285 TEST_EQUAL(path,
286 "abcdefghi_abcdefghi_abcdefghi_abcdefghi_abcdefghi_"
287 "abcdefghi_abcdefghi_abcdefghi_abcdefghi_abcdefghi_"
288 "abcdefghi_abcdefghi_abcdefghi_abcdefghi_abcdefghi_"
289 "abcdefghi_abcdefghi_abcdefghi_abcdefghi_abcdefghi_"
290 "abcdefghi_abcdefghi_abcdefghi_abcdefghi_" SEPARATOR
291 "abcdefghi_abcdefghi_abcdefghi_abcdefghi_abcdefghi_"
292 "abcdefghi_abcdefghi_abcdefghi_abcdefghi_abcdefghi_"
293 "abcdefghi_abcdefghi_abcdefghi_abcdefghi_abcdefghi_"
294 "abcdefghi_abcdefghi_abcdefghi_abcdefghi_abcdefghi_"
295 "abcdefghi_abcdefghi_abcdefghi_abcdefghi_.test");
296 }
297
TORRENT_TEST(sanitize_path_truncate_utf)298 TORRENT_TEST(sanitize_path_truncate_utf)
299 {
300 std::string path;
301 // msvc doesn't like unicode string literals, so we encode it as UTF-8 explicitly
302 sanitize_append_path_element(path,
303 "abcdefghi_abcdefghi_abcdefghi_abcdefghi_abcdefghi_"
304 "abcdefghi_abcdefghi_abcdefghi_abcdefghi_abcdefghi_"
305 "abcdefghi_abcdefghi_abcdefghi_abcdefghi_abcdefghi_"
306 "abcdefghi_abcdefghi_abcdefghi_abcdefghi_abcdefghi_"
307 "abcdefghi_abcdefghi_abcdefghi_abcdefghi" "\xE2" "\x80" "\x94" "abcde.jpg");
308 TEST_EQUAL(path,
309 "abcdefghi_abcdefghi_abcdefghi_abcdefghi_abcdefghi_"
310 "abcdefghi_abcdefghi_abcdefghi_abcdefghi_abcdefghi_"
311 "abcdefghi_abcdefghi_abcdefghi_abcdefghi_abcdefghi_"
312 "abcdefghi_abcdefghi_abcdefghi_abcdefghi_abcdefghi_"
313 "abcdefghi_abcdefghi_abcdefghi_abcdefghi" "\xE2" "\x80" "\x94" ".jpg");
314 }
315
TORRENT_TEST(sanitize_path_trailing_dots)316 TORRENT_TEST(sanitize_path_trailing_dots)
317 {
318 std::string path;
319 sanitize_append_path_element(path, "a");
320 sanitize_append_path_element(path, "abc...");
321 sanitize_append_path_element(path, "c");
322 #ifdef TORRENT_WINDOWS
323 TEST_EQUAL(path, "a" SEPARATOR "abc" SEPARATOR "c");
324 #else
325 TEST_EQUAL(path, "a" SEPARATOR "abc..." SEPARATOR "c");
326 #endif
327
328 path.clear();
329 sanitize_append_path_element(path, "abc...");
330 #ifdef TORRENT_WINDOWS
331 TEST_EQUAL(path, "abc");
332 #else
333 TEST_EQUAL(path, "abc...");
334 #endif
335
336 path.clear();
337 sanitize_append_path_element(path, "abc.");
338 #ifdef TORRENT_WINDOWS
339 TEST_EQUAL(path, "abc");
340 #else
341 TEST_EQUAL(path, "abc.");
342 #endif
343
344
345 path.clear();
346 sanitize_append_path_element(path, "a. . .");
347 #ifdef TORRENT_WINDOWS
348 TEST_EQUAL(path, "a");
349 #else
350 TEST_EQUAL(path, "a. . .");
351 #endif
352 }
353
TORRENT_TEST(sanitize_path_trailing_spaces)354 TORRENT_TEST(sanitize_path_trailing_spaces)
355 {
356 std::string path;
357 sanitize_append_path_element(path, "a");
358 sanitize_append_path_element(path, "abc ");
359 sanitize_append_path_element(path, "c");
360 #ifdef TORRENT_WINDOWS
361 TEST_EQUAL(path, "a" SEPARATOR "abc" SEPARATOR "c");
362 #else
363 TEST_EQUAL(path, "a" SEPARATOR "abc " SEPARATOR "c");
364 #endif
365
366 path.clear();
367 sanitize_append_path_element(path, "abc ");
368 #ifdef TORRENT_WINDOWS
369 TEST_EQUAL(path, "abc");
370 #else
371 TEST_EQUAL(path, "abc ");
372 #endif
373
374 path.clear();
375 sanitize_append_path_element(path, "abc ");
376 #ifdef TORRENT_WINDOWS
377 TEST_EQUAL(path, "abc");
378 #else
379 TEST_EQUAL(path, "abc ");
380 #endif
381 }
382
TORRENT_TEST(sanitize_path)383 TORRENT_TEST(sanitize_path)
384 {
385 std::string path;
386 sanitize_append_path_element(path, "\0\0\xed\0\x80");
387 TEST_EQUAL(path, "_");
388
389 path.clear();
390 sanitize_append_path_element(path, "/a/");
391 sanitize_append_path_element(path, "b");
392 sanitize_append_path_element(path, "c");
393 TEST_EQUAL(path, "a" SEPARATOR "b" SEPARATOR "c");
394
395 path.clear();
396 sanitize_append_path_element(path, "a...b");
397 TEST_EQUAL(path, "a...b");
398
399 path.clear();
400 sanitize_append_path_element(path, "a");
401 sanitize_append_path_element(path, "..");
402 sanitize_append_path_element(path, "c");
403 TEST_EQUAL(path, "a" SEPARATOR "c");
404
405 path.clear();
406 sanitize_append_path_element(path, "a");
407 sanitize_append_path_element(path, "..");
408 TEST_EQUAL(path, "a");
409
410 path.clear();
411 sanitize_append_path_element(path, "/..");
412 sanitize_append_path_element(path, ".");
413 sanitize_append_path_element(path, "c");
414 TEST_EQUAL(path, "c");
415
416 path.clear();
417 sanitize_append_path_element(path, "dev:");
418 #ifdef TORRENT_WINDOWS
419 TEST_EQUAL(path, "dev_");
420 #else
421 TEST_EQUAL(path, "dev:");
422 #endif
423
424 path.clear();
425 sanitize_append_path_element(path, "c:");
426 sanitize_append_path_element(path, "b");
427 #ifdef TORRENT_WINDOWS
428 TEST_EQUAL(path, "c_" SEPARATOR "b");
429 #else
430 TEST_EQUAL(path, "c:" SEPARATOR "b");
431 #endif
432
433 path.clear();
434 sanitize_append_path_element(path, "c:");
435 sanitize_append_path_element(path, ".");
436 sanitize_append_path_element(path, "c");
437 #ifdef TORRENT_WINDOWS
438 TEST_EQUAL(path, "c_" SEPARATOR "c");
439 #else
440 TEST_EQUAL(path, "c:" SEPARATOR "c");
441 #endif
442
443 path.clear();
444 sanitize_append_path_element(path, "\\c");
445 sanitize_append_path_element(path, ".");
446 sanitize_append_path_element(path, "c");
447 TEST_EQUAL(path, "c" SEPARATOR "c");
448
449 path.clear();
450 sanitize_append_path_element(path, "\b");
451 TEST_EQUAL(path, "_");
452
453 path.clear();
454 sanitize_append_path_element(path, "\b");
455 sanitize_append_path_element(path, "filename");
456 TEST_EQUAL(path, "_" SEPARATOR "filename");
457
458 path.clear();
459 sanitize_append_path_element(path, "filename");
460 sanitize_append_path_element(path, "\b");
461 TEST_EQUAL(path, "filename" SEPARATOR "_");
462
463 path.clear();
464 sanitize_append_path_element(path, "abc");
465 sanitize_append_path_element(path, "");
466 TEST_EQUAL(path, "abc" SEPARATOR "_");
467
468 path.clear();
469 sanitize_append_path_element(path, "abc");
470 sanitize_append_path_element(path, " ");
471 #ifdef TORRENT_WINDOWS
472 TEST_EQUAL(path, "abc");
473 #else
474 TEST_EQUAL(path, "abc" SEPARATOR " ");
475 #endif
476
477 path.clear();
478 sanitize_append_path_element(path, "");
479 sanitize_append_path_element(path, "abc");
480 TEST_EQUAL(path, "_" SEPARATOR "abc");
481
482 path.clear();
483 sanitize_append_path_element(path, "\b?filename=4");
484 #ifdef TORRENT_WINDOWS
485 TEST_EQUAL(path, "__filename=4");
486 #else
487 TEST_EQUAL(path, "_?filename=4");
488 #endif
489
490 path.clear();
491 sanitize_append_path_element(path, "filename=4");
492 TEST_EQUAL(path, "filename=4");
493
494 // valid 2-byte sequence
495 path.clear();
496 sanitize_append_path_element(path, "filename\xc2\xa1");
497 TEST_EQUAL(path, "filename\xc2\xa1");
498
499 // truncated 2-byte sequence
500 path.clear();
501 sanitize_append_path_element(path, "filename\xc2");
502 TEST_EQUAL(path, "filename_");
503
504 // valid 3-byte sequence
505 path.clear();
506 sanitize_append_path_element(path, "filename\xe2\x9f\xb9");
507 TEST_EQUAL(path, "filename\xe2\x9f\xb9");
508
509 // truncated 3-byte sequence
510 path.clear();
511 sanitize_append_path_element(path, "filename\xe2\x9f");
512 TEST_EQUAL(path, "filename_");
513
514 // truncated 3-byte sequence
515 path.clear();
516 sanitize_append_path_element(path, "filename\xe2");
517 TEST_EQUAL(path, "filename_");
518
519 // valid 4-byte sequence
520 path.clear();
521 sanitize_append_path_element(path, "filename\xf0\x9f\x92\x88");
522 TEST_EQUAL(path, "filename\xf0\x9f\x92\x88");
523
524 // truncated 4-byte sequence
525 path.clear();
526 sanitize_append_path_element(path, "filename\xf0\x9f\x92");
527 TEST_EQUAL(path, "filename_");
528
529 // 5-byte utf-8 sequence (not allowed)
530 path.clear();
531 sanitize_append_path_element(path, "filename\xf8\x9f\x9f\x9f\x9f" "foobar");
532 TEST_EQUAL(path, "filename_foobar");
533
534 // redundant (overlong) 2-byte sequence
535 // ascii code 0x2e encoded with a leading 0
536 path.clear();
537 sanitize_append_path_element(path, "filename\xc0\xae");
538 TEST_EQUAL(path, "filename_");
539
540 // redundant (overlong) 3-byte sequence
541 // ascii code 0x2e encoded with two leading 0s
542 path.clear();
543 sanitize_append_path_element(path, "filename\xe0\x80\xae");
544 TEST_EQUAL(path, "filename_");
545
546 // redundant (overlong) 4-byte sequence
547 // ascii code 0x2e encoded with three leading 0s
548 path.clear();
549 sanitize_append_path_element(path, "filename\xf0\x80\x80\xae");
550 TEST_EQUAL(path, "filename_");
551
552 // a filename where every character is filtered is not replaced by an understcore
553 path.clear();
554 sanitize_append_path_element(path, "//\\");
555 TEST_EQUAL(path, "");
556
557 // make sure suspicious unicode characters are filtered out
558 path.clear();
559 // that's utf-8 for U+200e LEFT-TO-RIGHT MARK
560 sanitize_append_path_element(path, "foo\xe2\x80\x8e" "bar");
561 TEST_EQUAL(path, "foobar");
562
563 // make sure suspicious unicode characters are filtered out
564 path.clear();
565 // that's utf-8 for U+202b RIGHT-TO-LEFT EMBEDDING
566 sanitize_append_path_element(path, "foo\xe2\x80\xab" "bar");
567 TEST_EQUAL(path, "foobar");
568 }
569
TORRENT_TEST(sanitize_path_zeroes)570 TORRENT_TEST(sanitize_path_zeroes)
571 {
572 std::string path;
573 sanitize_append_path_element(path, "\0foo");
574 TEST_EQUAL(path, "_");
575
576 path.clear();
577 sanitize_append_path_element(path, "\0\0\0\0");
578 TEST_EQUAL(path, "_");
579 }
580
TORRENT_TEST(sanitize_path_colon)581 TORRENT_TEST(sanitize_path_colon)
582 {
583 std::string path;
584 sanitize_append_path_element(path, "foo:bar");
585 #ifdef TORRENT_WINDOWS
586 TEST_EQUAL(path, "foo_bar");
587 #else
588 TEST_EQUAL(path, "foo:bar");
589 #endif
590 }
591
TORRENT_TEST(verify_encoding)592 TORRENT_TEST(verify_encoding)
593 {
594 // verify_encoding
595 std::string test = "\b?filename=4";
596 TEST_CHECK(verify_encoding(test));
597 TEST_CHECK(test == "\b?filename=4");
598
599 test = "filename=4";
600 TEST_CHECK(verify_encoding(test));
601 TEST_CHECK(test == "filename=4");
602
603 // valid 2-byte sequence
604 test = "filename\xc2\xa1";
605 TEST_CHECK(verify_encoding(test));
606 std::printf("%s\n", test.c_str());
607 TEST_CHECK(test == "filename\xc2\xa1");
608
609 // truncated 2-byte sequence
610 test = "filename\xc2";
611 TEST_CHECK(!verify_encoding(test));
612 std::printf("%s\n", test.c_str());
613 TEST_CHECK(test == "filename_");
614
615 // valid 3-byte sequence
616 test = "filename\xe2\x9f\xb9";
617 TEST_CHECK(verify_encoding(test));
618 std::printf("%s\n", test.c_str());
619 TEST_CHECK(test == "filename\xe2\x9f\xb9");
620
621 // truncated 3-byte sequence
622 test = "filename\xe2\x9f";
623 TEST_CHECK(!verify_encoding(test));
624 std::printf("%s\n", test.c_str());
625 TEST_CHECK(test == "filename_");
626
627 // truncated 3-byte sequence
628 test = "filename\xe2";
629 TEST_CHECK(!verify_encoding(test));
630 std::printf("%s\n", test.c_str());
631 TEST_CHECK(test == "filename_");
632
633 // valid 4-byte sequence
634 test = "filename\xf0\x9f\x92\x88";
635 TEST_CHECK(verify_encoding(test));
636 std::printf("%s\n", test.c_str());
637 TEST_CHECK(test == "filename\xf0\x9f\x92\x88");
638
639 // truncated 4-byte sequence
640 test = "filename\xf0\x9f\x92";
641 TEST_CHECK(!verify_encoding(test));
642 std::printf("%s\n", test.c_str());
643 TEST_CHECK(test == "filename_");
644
645 // 5-byte utf-8 sequence (not allowed)
646 test = "filename\xf8\x9f\x9f\x9f\x9f""foobar";
647 TEST_CHECK(!verify_encoding(test));
648 std::printf("%s\n", test.c_str());
649 TEST_CHECK(test == "filename_foobar");
650
651 // redundant (overlong) 2-byte sequence
652 // ascii code 0x2e encoded with a leading 0
653 test = "filename\xc0\xae";
654 TEST_CHECK(!verify_encoding(test));
655 std::printf("%s\n", test.c_str());
656 TEST_CHECK(test == "filename_");
657
658 // redundant (overlong) 3-byte sequence
659 // ascii code 0x2e encoded with two leading 0s
660 test = "filename\xe0\x80\xae";
661 TEST_CHECK(!verify_encoding(test));
662 std::printf("%s\n", test.c_str());
663 TEST_CHECK(test == "filename_");
664
665 // redundant (overlong) 4-byte sequence
666 // ascii code 0x2e encoded with three leading 0s
667 test = "filename\xf0\x80\x80\xae";
668 TEST_CHECK(!verify_encoding(test));
669 std::printf("%s\n", test.c_str());
670 TEST_CHECK(test == "filename_");
671
672 // missing byte header
673 test = "filename\xed\0\x80";
674 TEST_CHECK(!verify_encoding(test));
675 fprintf(stdout, "%s\n", test.c_str());
676 TEST_CHECK(test == "filename_");
677 }
678
TORRENT_TEST(parse_torrents)679 TORRENT_TEST(parse_torrents)
680 {
681 // test torrent parsing
682
683 entry info;
684 info["pieces"] = "aaaaaaaaaaaaaaaaaaaa";
685 info["name.utf-8"] = "test1";
686 info["name"] = "test__";
687 info["piece length"] = 16 * 1024;
688 info["length"] = 3245;
689 entry torrent;
690 torrent["info"] = info;
691
692 std::vector<char> buf;
693 bencode(std::back_inserter(buf), torrent);
694 torrent_info ti1(buf, from_span);
695 std::cout << ti1.name() << std::endl;
696 TEST_CHECK(ti1.name() == "test1");
697
698 #ifdef TORRENT_WINDOWS
699 info["name.utf-8"] = "c:/test1/test2/test3";
700 #else
701 info["name.utf-8"] = "/test1/test2/test3";
702 #endif
703 torrent["info"] = info;
704 buf.clear();
705 bencode(std::back_inserter(buf), torrent);
706 torrent_info ti2(buf, from_span);
707 std::cout << ti2.name() << std::endl;
708 #ifdef TORRENT_WINDOWS
709 TEST_EQUAL(ti2.name(), "c_test1test2test3");
710 #else
711 TEST_EQUAL(ti2.name(), "test1test2test3");
712 #endif
713
714 info["name.utf-8"] = "test2/../test3/.././../../test4";
715 torrent["info"] = info;
716 buf.clear();
717 bencode(std::back_inserter(buf), torrent);
718 torrent_info ti3(buf, from_span);
719 std::cout << ti3.name() << std::endl;
720 TEST_EQUAL(ti3.name(), "test2..test3.......test4");
721
722 std::string root_dir = parent_path(current_working_directory());
723 for (auto const t : test_torrents)
724 {
725 std::printf("loading %s\n", t.file);
726 std::string filename = combine_path(combine_path(root_dir, "test_torrents")
727 , t.file);
728 error_code ec;
729 auto ti = std::make_shared<torrent_info>(filename, ec);
730 TEST_CHECK(!ec);
731 if (ec) std::printf(" loading(\"%s\") -> failed %s\n", filename.c_str()
732 , ec.message().c_str());
733
734 if (t.file == "whitespace_url.torrent"_sv)
735 {
736 // make sure we trimmed the url
737 TEST_CHECK(ti->trackers().size() > 0);
738 if (ti->trackers().size() > 0)
739 TEST_CHECK(ti->trackers()[0].url == "udp://test.com/announce");
740 }
741 else if (t.file == "duplicate_files.torrent"_sv)
742 {
743 // make sure we disambiguated the files
744 TEST_EQUAL(ti->num_files(), 2);
745 TEST_CHECK(ti->files().file_path(file_index_t{0}) == combine_path(combine_path("temp", "foo"), "bar.txt"));
746 TEST_CHECK(ti->files().file_path(file_index_t{1}) == combine_path(combine_path("temp", "foo"), "bar.1.txt"));
747 }
748 else if (t.file == "pad_file.torrent"_sv)
749 {
750 TEST_EQUAL(ti->num_files(), 2);
751 TEST_EQUAL(bool(ti->files().file_flags(file_index_t{0}) & file_storage::flag_pad_file), false);
752 TEST_EQUAL(bool(ti->files().file_flags(file_index_t{1}) & file_storage::flag_pad_file), true);
753 }
754 else if (t.file == "creation_date.torrent"_sv)
755 {
756 TEST_EQUAL(ti->creation_date(), 1234567);
757 }
758 else if (t.file == "duplicate_web_seeds.torrent"_sv)
759 {
760 TEST_EQUAL(ti->web_seeds().size(), 3);
761 }
762 else if (t.file == "no_creation_date.torrent"_sv)
763 {
764 TEST_CHECK(!ti->creation_date());
765 }
766 else if (t.file == "url_seed.torrent"_sv)
767 {
768 TEST_EQUAL(ti->web_seeds().size(), 1);
769 TEST_EQUAL(ti->web_seeds()[0].url, "http://test.com/file");
770 #if TORRENT_ABI_VERSION == 1
771 TEST_EQUAL(ti->http_seeds().size(), 0);
772 TEST_EQUAL(ti->url_seeds().size(), 1);
773 TEST_EQUAL(ti->url_seeds()[0], "http://test.com/file");
774 #endif
775 }
776 else if (t.file == "url_seed_multi.torrent"_sv)
777 {
778 TEST_EQUAL(ti->web_seeds().size(), 1);
779 TEST_EQUAL(ti->web_seeds()[0].url, "http://test.com/file/");
780 #if TORRENT_ABI_VERSION == 1
781 TEST_EQUAL(ti->http_seeds().size(), 0);
782 TEST_EQUAL(ti->url_seeds().size(), 1);
783 TEST_EQUAL(ti->url_seeds()[0], "http://test.com/file/");
784 #endif
785 }
786 else if (t.file == "url_seed_multi_single_file.torrent"_sv)
787 {
788 TEST_EQUAL(ti->web_seeds().size(), 1);
789 TEST_EQUAL(ti->web_seeds()[0].url, "http://test.com/file/temp/foo/bar.txt");
790 }
791 else if (t.file == "url_seed_multi_space.torrent"_sv
792 || t.file == "url_seed_multi_space_nolist.torrent"_sv)
793 {
794 TEST_EQUAL(ti->web_seeds().size(), 1);
795 TEST_EQUAL(ti->web_seeds()[0].url, "http://test.com/test%20file/foo%20bar/");
796 #if TORRENT_ABI_VERSION == 1
797 TEST_EQUAL(ti->http_seeds().size(), 0);
798 TEST_EQUAL(ti->url_seeds().size(), 1);
799 TEST_EQUAL(ti->url_seeds()[0], "http://test.com/test%20file/foo%20bar/");
800 #endif
801 }
802 else if (t.file == "invalid_name2.torrent"_sv)
803 {
804 // if, after all invalid characters are removed from the name, it ends up
805 // being empty, it's set to the info-hash. Some torrents also have an empty name
806 // in which case it's also set to the info-hash
807 TEST_EQUAL(ti->name(), "b61560c2918f463768cd122b6d2fdd47b77bdb35");
808 }
809 else if (t.file == "invalid_name3.torrent"_sv)
810 {
811 // windows does not allow trailing spaces in filenames
812 #ifdef TORRENT_WINDOWS
813 TEST_EQUAL(ti->name(), "foobar");
814 #else
815 TEST_EQUAL(ti->name(), "foobar ");
816 #endif
817 }
818 else if (t.file == "symlink1.torrent"_sv)
819 {
820 TEST_EQUAL(ti->num_files(), 2);
821 TEST_EQUAL(ti->files().symlink(file_index_t{1}), "temp" SEPARATOR "a" SEPARATOR "b" SEPARATOR "bar");
822 }
823 else if (t.file == "symlink2.torrent"_sv)
824 {
825 TEST_EQUAL(ti->num_files(), 5);
826 TEST_EQUAL(ti->files().symlink(file_index_t{0}), "Some.framework" SEPARATOR "Versions" SEPARATOR "A" SEPARATOR "SDL2");
827 TEST_EQUAL(ti->files().symlink(file_index_t{4}), "Some.framework" SEPARATOR "Versions" SEPARATOR "A");
828 }
829 else if (t.file == "slash_path.torrent"_sv)
830 {
831 TEST_EQUAL(ti->num_files(), 1);
832 TEST_EQUAL(ti->files().file_path(file_index_t{0}), "temp" SEPARATOR "bar");
833 }
834 else if (t.file == "slash_path2.torrent"_sv)
835 {
836 TEST_EQUAL(ti->num_files(), 1);
837 TEST_EQUAL(ti->files().file_path(file_index_t{0}), "temp" SEPARATOR "abc....def" SEPARATOR "bar");
838 }
839 else if (t.file == "slash_path3.torrent"_sv)
840 {
841 TEST_EQUAL(ti->num_files(), 1);
842 TEST_EQUAL(ti->files().file_path(file_index_t{0}), "temp....abc");
843 }
844 else if (t.file == "symlink_zero_size.torrent"_sv)
845 {
846 TEST_EQUAL(ti->num_files(), 2);
847 TEST_EQUAL(ti->files().symlink(file_index_t(1)), "temp" SEPARATOR "a" SEPARATOR "b" SEPARATOR "bar");
848 }
849 else if (t.file == "pad_file_no_path.torrent"_sv)
850 {
851 TEST_EQUAL(ti->num_files(), 2);
852 TEST_EQUAL(ti->files().file_path(file_index_t{1}), combine_path(".pad", "0"));
853 }
854 else if (t.file == "absolute_filename.torrent"_sv)
855 {
856 TEST_EQUAL(ti->num_files(), 2);
857 TEST_EQUAL(ti->files().file_path(file_index_t{0}), combine_path("temp", "abcde"));
858 TEST_EQUAL(ti->files().file_path(file_index_t{1}), combine_path("temp", "foobar"));
859 }
860 else if (t.file == "invalid_filename.torrent"_sv)
861 {
862 TEST_EQUAL(ti->num_files(), 2);
863 }
864 else if (t.file == "invalid_filename2.torrent"_sv)
865 {
866 TEST_EQUAL(ti->num_files(), 3);
867 }
868 else if (t.file == "overlapping_symlinks.torrent"_sv)
869 {
870 TEST_CHECK(ti->num_files() > 3);
871 TEST_EQUAL(ti->files().symlink(file_index_t{0}), "SDL2.framework" SEPARATOR "Versions" SEPARATOR "Current" SEPARATOR "Headers");
872 TEST_EQUAL(ti->files().symlink(file_index_t{1}), "SDL2.framework" SEPARATOR "Versions" SEPARATOR "Current" SEPARATOR "Resources");
873 TEST_EQUAL(ti->files().symlink(file_index_t{2}), "SDL2.framework" SEPARATOR "Versions" SEPARATOR "Current" SEPARATOR "SDL2");
874 }
875
876 file_storage const& fs = ti->files();
877 for (file_index_t idx{0}; idx != file_index_t(fs.num_files()); ++idx)
878 {
879 piece_index_t const first = ti->map_file(idx, 0, 0).piece;
880 piece_index_t const last = ti->map_file(idx, std::max(fs.file_size(idx)-1, std::int64_t(0)), 0).piece;
881 file_flags_t const flags = fs.file_flags(idx);
882 sha1_hash const ih = fs.hash(idx);
883 std::printf(" %11" PRId64 " %c%c%c%c [ %4d, %4d ] %7u %s %s %s%s\n"
884 , fs.file_size(idx)
885 , (flags & file_storage::flag_pad_file)?'p':'-'
886 , (flags & file_storage::flag_executable)?'x':'-'
887 , (flags & file_storage::flag_hidden)?'h':'-'
888 , (flags & file_storage::flag_symlink)?'l':'-'
889 , static_cast<int>(first), static_cast<int>(last)
890 , std::uint32_t(fs.mtime(idx))
891 , ih != sha1_hash(nullptr) ? aux::to_hex(ih).c_str() : ""
892 , fs.file_path(idx).c_str()
893 , flags & file_storage::flag_symlink ? "-> ": ""
894 , flags & file_storage::flag_symlink ? fs.symlink(idx).c_str() : "");
895 }
896 }
897
898 for (int i = 0; i < int(sizeof(test_error_torrents)/sizeof(test_error_torrents[0])); ++i)
899 {
900 error_code ec;
901 std::printf("loading %s\n", test_error_torrents[i].file);
902 auto ti = std::make_shared<torrent_info>(combine_path(
903 combine_path(root_dir, "test_torrents"), test_error_torrents[i].file), ec);
904 std::printf("E: \"%s\"\nexpected: \"%s\"\n", ec.message().c_str()
905 , test_error_torrents[i].error.message().c_str());
906 TEST_CHECK(ec.message() == test_error_torrents[i].error.message());
907 TEST_EQUAL(ti->is_valid(), false);
908 }
909 }
910
911 namespace {
912
913 struct file_t
914 {
915 std::string filename;
916 int size;
917 file_flags_t flags;
918 string_view expected_filename;
919 };
920
921 std::vector<lt::aux::vector<file_t, lt::file_index_t>> const test_cases
922 {
923 {
924 {"test/temporary.txt", 0x4000, {}, "test/temporary.txt"},
925 {"test/Temporary.txt", 0x4000, {}, "test/Temporary.1.txt"},
926 {"test/TeMPorArY.txT", 0x4000, {}, "test/TeMPorArY.2.txT"},
927 // a file with the same name in a seprate directory is fine
928 {"test/test/TEMPORARY.TXT", 0x4000, {}, "test/test/TEMPORARY.TXT"},
929 },
930 {
931 {"test/b.exe", 0x4000, {}, "test/b.exe"},
932 // duplicate of b.exe
933 {"test/B.ExE", 0x4000, {}, "test/B.1.ExE"},
934 // duplicate of b.exe
935 {"test/B.exe", 0x4000, {}, "test/B.2.exe"},
936 {"test/filler", 0x4000, {}, "test/filler"},
937 },
938 {
939 {"test/a/b/c/d/e/f/g/h/i/j/k/l/m", 0x4000, {}, "test/a/b/c/d/e/f/g/h/i/j/k/l/m"},
940 {"test/a", 0x4000, {}, "test/a.1"},
941 {"test/a/b", 0x4000, {}, "test/a/b.1"},
942 {"test/a/b/c", 0x4000, {}, "test/a/b/c.1"},
943 {"test/a/b/c/d", 0x4000, {}, "test/a/b/c/d.1"},
944 {"test/a/b/c/d/e", 0x4000, {}, "test/a/b/c/d/e.1"},
945 {"test/a/b/c/d/e/f", 0x4000, {}, "test/a/b/c/d/e/f.1"},
946 {"test/a/b/c/d/e/f/g", 0x4000, {}, "test/a/b/c/d/e/f/g.1"},
947 {"test/a/b/c/d/e/f/g/h", 0x4000, {}, "test/a/b/c/d/e/f/g/h.1"},
948 {"test/a/b/c/d/e/f/g/h/i", 0x4000, {}, "test/a/b/c/d/e/f/g/h/i.1"},
949 {"test/a/b/c/d/e/f/g/h/i/j", 0x4000, {}, "test/a/b/c/d/e/f/g/h/i/j.1"},
950 },
951 {
952 // it doesn't matter whether the file comes before the directory,
953 // directories take precedence
954 {"test/a", 0x4000, {}, "test/a.1"},
955 {"test/a/b", 0x4000, {}, "test/a/b"},
956 },
957 {
958 {"test/A/tmp", 0x4000, {}, "test/A/tmp"},
959 // a file may not have the same name as a directory
960 {"test/a", 0x4000, {}, "test/a.1"},
961 // duplicate of directory a
962 {"test/A", 0x4000, {}, "test/A.2"},
963 {"test/filler", 0x4000, {}, "test/filler"},
964 },
965 {
966 // a subset of this path collides with the next filename
967 {"test/long/path/name/that/collides", 0x4000, {}, "test/long/path/name/that/collides"},
968 // so this file needs to be renamed, to not collide with the path name
969 {"test/long/path", 0x4000, {}, "test/long/path.1"},
970 {"test/filler-1", 0x4000, {}, "test/filler-1"},
971 {"test/filler-2", 0x4000, {}, "test/filler-2"},
972 },
973 {
974 // pad files are allowed to collide, as long as they have the same size
975 {"test/.pad/1234", 0x4000, file_storage::flag_pad_file, "test/.pad/1234"},
976 {"test/filler-1", 0x4000, {}, "test/filler-1"},
977 {"test/.pad/1234", 0x4000, file_storage::flag_pad_file, "test/.pad/1234"},
978 {"test/filler-2", 0x4000, {}, "test/filler-2"},
979 },
980 {
981 // pad files of different sizes are NOT allowed to collide
982 {"test/.pad/1234", 0x8000, file_storage::flag_pad_file, "test/.pad/1234"},
983 {"test/filler-1", 0x4000, {}, "test/filler-1"},
984 {"test/.pad/1234", 0x4000, file_storage::flag_pad_file, "test/.pad/1234.1"},
985 {"test/filler-2", 0x4000, {}, "test/filler-2"},
986 },
987 {
988 // pad files are NOT allowed to collide with normal files
989 {"test/.pad/1234", 0x4000, {}, "test/.pad/1234"},
990 {"test/filler-1", 0x4000, {}, "test/filler-1"},
991 {"test/.pad/1234", 0x4000, file_storage::flag_pad_file, "test/.pad/1234.1"},
992 {"test/filler-2", 0x4000, {}, "test/filler-2"},
993 },
994 {
995 // normal files are NOT allowed to collide with pad files
996 {"test/.pad/1234", 0x4000, file_storage::flag_pad_file, "test/.pad/1234"},
997 {"test/filler-1", 0x4000, {}, "test/filler-1"},
998 {"test/.pad/1234", 0x4000, {}, "test/.pad/1234.1"},
999 {"test/filler-2", 0x4000, {}, "test/filler-2"},
1000 },
1001 {
1002 // pad files are NOT allowed to collide with directories
1003 {"test/.pad/1234", 0x4000, file_storage::flag_pad_file, "test/.pad/1234.1"},
1004 {"test/filler-1", 0x4000, {}, "test/filler-1"},
1005 {"test/.pad/1234/filler-2", 0x4000, {}, "test/.pad/1234/filler-2"},
1006 },
1007 };
1008
test_resolve_duplicates(aux::vector<file_t,file_index_t> const & test)1009 void test_resolve_duplicates(aux::vector<file_t, file_index_t> const& test)
1010 {
1011 file_storage fs;
1012 for (auto const& f : test) fs.add_file(f.filename, f.size, f.flags);
1013
1014 lt::create_torrent t(fs, 0x4000);
1015
1016 // calculate the hash for all pieces
1017 sha1_hash ph;
1018 for (auto const i : fs.piece_range())
1019 t.set_hash(i, ph);
1020
1021 std::vector<char> tmp;
1022 std::back_insert_iterator<std::vector<char>> out(tmp);
1023
1024 entry tor = t.generate();
1025 bencode(out, tor);
1026
1027 torrent_info ti(tmp, from_span);
1028 for (auto const i : fs.file_range())
1029 {
1030 std::string p = ti.files().file_path(i);
1031 convert_path_to_posix(p);
1032 std::printf("%s == %s\n", p.c_str(), test[i].expected_filename.to_string().c_str());
1033
1034 TEST_EQUAL(p, test[i].expected_filename);
1035 }
1036 }
1037
1038 } // anonymous namespace
1039
TORRENT_TEST(resolve_duplicates)1040 TORRENT_TEST(resolve_duplicates)
1041 {
1042 for (auto const& t : test_cases)
1043 test_resolve_duplicates(t);
1044 }
1045
TORRENT_TEST(empty_file)1046 TORRENT_TEST(empty_file)
1047 {
1048 error_code ec;
1049 auto ti = std::make_shared<torrent_info>("", ec, from_span);
1050 TEST_CHECK(ec);
1051 }
1052
TORRENT_TEST(empty_file2)1053 TORRENT_TEST(empty_file2)
1054 {
1055 try
1056 {
1057 auto ti = std::make_shared<torrent_info>("", from_span);
1058 TEST_ERROR("expected exception thrown");
1059 }
1060 catch (system_error const& e)
1061 {
1062 std::printf("Expected error: %s\n", e.code().message().c_str());
1063 }
1064 }
1065
TORRENT_TEST(copy)1066 TORRENT_TEST(copy)
1067 {
1068 using namespace lt;
1069
1070 std::shared_ptr<torrent_info> a = std::make_shared<torrent_info>(
1071 combine_path(parent_path(current_working_directory())
1072 , combine_path("test_torrents", "sample.torrent")));
1073
1074 aux::vector<char const*, file_index_t> expected_files =
1075 {
1076 "sample/text_file2.txt",
1077 "sample/.____padding_file/0",
1078 "sample/text_file.txt",
1079 };
1080
1081 aux::vector<sha1_hash, file_index_t> file_hashes =
1082 {
1083 sha1_hash(nullptr),
1084 sha1_hash(nullptr),
1085 sha1_hash("abababababababababab")
1086 };
1087
1088 file_storage const& fs = a->files();
1089 for (auto const i : fs.file_range())
1090 {
1091 std::string p = fs.file_path(i);
1092 convert_path_to_posix(p);
1093 TEST_EQUAL(p, expected_files[i]);
1094 std::printf("%s\n", p.c_str());
1095
1096 TEST_EQUAL(a->files().hash(i), file_hashes[i]);
1097 }
1098
1099 // copy the torrent_info object
1100 std::shared_ptr<torrent_info> b = std::make_shared<torrent_info>(*a);
1101
1102 a.reset();
1103
1104 TEST_EQUAL(b->num_files(), 3);
1105
1106 file_storage const& fs2 = b->files();
1107 for (auto const i : fs2.file_range())
1108 {
1109 std::string p = fs2.file_path(i);
1110 convert_path_to_posix(p);
1111 TEST_EQUAL(p, expected_files[i]);
1112 std::printf("%s\n", p.c_str());
1113
1114 TEST_EQUAL(fs2.hash(i), file_hashes[i]);
1115 }
1116 }
1117
1118 struct A
1119 {
1120 int val;
1121 };
1122
TORRENT_TEST(copy_ptr)1123 TORRENT_TEST(copy_ptr)
1124 {
1125 copy_ptr<A> a(new A{4});
1126 copy_ptr<A> b(a);
1127
1128 TEST_EQUAL(a->val, b->val);
1129 TEST_CHECK(&*a != &*b);
1130 a->val = 5;
1131 TEST_EQUAL(b->val, 4);
1132 }
1133