1 /*
2 * This file Copyright (C) 2013-2014 Mnemosyne LLC
3 *
4 * It may be used under the GNU GPL versions 2 or 3
5 * or any future license endorsed by Mnemosyne LLC.
6 *
7 */
8
9 #include "libtransmission-test.h"
10
11 #include "transmission.h"
12 #include "metainfo.h"
13 #include "utils.h"
14
15 #include <errno.h>
16
test_magnet_link(void)17 static int test_magnet_link(void)
18 {
19 tr_info inf;
20 tr_ctor* ctor;
21 char const* magnet_link;
22 tr_parse_result parse_result;
23
24 /* background info @ http://wiki.theory.org/BitTorrent_Magnet-URI_Webseeding */
25 magnet_link =
26 "magnet:?"
27 "xt=urn:btih:14FFE5DD23188FD5CB53A1D47F1289DB70ABF31E"
28 "&dn=ubuntu+12+04+1+desktop+32+bit"
29 "&tr=http%3A%2F%2Ftracker.publicbt.com%2Fannounce"
30 "&tr=udp%3A%2F%2Ftracker.publicbt.com%3A80"
31 "&ws=http://transmissionbt.com ";
32 ctor = tr_ctorNew(NULL);
33 tr_ctorSetMetainfoFromMagnetLink(ctor, magnet_link);
34 parse_result = tr_torrentParse(ctor, &inf);
35 check_int(inf.fileCount, ==, 0); /* cos it's a magnet link */
36 check_int(parse_result, ==, TR_PARSE_OK);
37 check_int(inf.trackerCount, ==, 2);
38 check_str(inf.trackers[0].announce, ==, "http://tracker.publicbt.com/announce");
39 check_str(inf.trackers[1].announce, ==, "udp://tracker.publicbt.com:80");
40 check_int(inf.webseedCount, ==, 1);
41 check_str(inf.webseeds[0], ==, "http://transmissionbt.com");
42
43 /* cleanup */
44 tr_metainfoFree(&inf);
45 tr_ctorFree(ctor);
46 return 0;
47 }
48
49 #define BEFORE_PATH \
50 "d10:created by25:Transmission/2.82 (14160)13:creation datei1402280218e8:encoding5:UTF-84:infod5:filesld6:lengthi2e4:pathl"
51 #define AFTER_PATH \
52 "eed6:lengthi2e4:pathl5:b.txteee4:name3:foo12:piece lengthi32768e6:pieces20:ÞÉ`âMs¡Å;˺¬.åÂà7:privatei0eee"
53
test_metainfo(void)54 static int test_metainfo(void)
55 {
56 struct
57 {
58 int expected_benc_err;
59 int expected_parse_result;
60 void const* benc;
61 }
62 const metainfo[] =
63 {
64 { 0, TR_PARSE_OK, BEFORE_PATH "5:a.txt" AFTER_PATH },
65
66 /* allow empty components, but not =all= empty components, see bug #5517 */
67 { 0, TR_PARSE_OK, BEFORE_PATH "0:5:a.txt" AFTER_PATH },
68 { 0, TR_PARSE_ERR, BEFORE_PATH "0:0:" AFTER_PATH },
69
70 /* allow path separators in a filename (replaced with '_') */
71 { 0, TR_PARSE_OK, BEFORE_PATH "7:a/a.txt" AFTER_PATH },
72
73 /* allow "." components (skipped) */
74 { 0, TR_PARSE_OK, BEFORE_PATH "1:.5:a.txt" AFTER_PATH },
75 { 0, TR_PARSE_OK, BEFORE_PATH "5:a.txt1:." AFTER_PATH },
76
77 /* allow ".." components (replaced with "__") */
78 { 0, TR_PARSE_OK, BEFORE_PATH "2:..5:a.txt" AFTER_PATH },
79 { 0, TR_PARSE_OK, BEFORE_PATH "5:a.txt2:.." AFTER_PATH },
80
81 /* fail on empty string */
82 { EILSEQ, TR_PARSE_ERR, "" }
83 };
84
85 tr_logSetLevel(0); /* yes, we already know these will generate errors, thank you... */
86
87 for (size_t i = 0; i < TR_N_ELEMENTS(metainfo); i++)
88 {
89 tr_ctor* ctor = tr_ctorNew(NULL);
90 int const err = tr_ctorSetMetainfo(ctor, metainfo[i].benc, strlen(metainfo[i].benc));
91 check_int(err, ==, metainfo[i].expected_benc_err);
92
93 if (err == 0)
94 {
95 tr_parse_result const parse_result = tr_torrentParse(ctor, NULL);
96 check_int(parse_result, ==, metainfo[i].expected_parse_result);
97 }
98
99 tr_ctorFree(ctor);
100 }
101
102 return 0;
103 }
104
test_sanitize(void)105 static int test_sanitize(void)
106 {
107 struct
108 {
109 char const* str;
110 size_t len;
111 char const* expected_result;
112 bool expected_is_adjusted;
113 }
114 const test_data[] =
115 {
116 /* skipped */
117 { "", 0, NULL, false },
118 { ".", 1, NULL, false },
119 { "..", 2, NULL, true },
120 { ".....", 5, NULL, false },
121 { " ", 2, NULL, false },
122 { " . ", 3, NULL, false },
123 { ". . .", 5, NULL, false },
124 /* replaced with '_' */
125 { "/", 1, "_", true },
126 { "////", 4, "____", true },
127 { "\\\\", 2, "__", true },
128 { "/../", 4, "_.._", true },
129 { "foo<bar:baz/boo", 15, "foo_bar_baz_boo", true },
130 { "t\0e\x01s\tt\ri\nn\fg", 13, "t_e_s_t_i_n_g", true },
131 /* appended with '_' */
132 { "con", 3, "con_", true },
133 { "cOm4", 4, "cOm4_", true },
134 { "LPt9.txt", 8, "LPt9_.txt", true },
135 { "NUL.tar.gz", 10, "NUL_.tar.gz", true },
136 /* trimmed */
137 { " foo", 4, "foo", true },
138 { "foo ", 4, "foo", true },
139 { " foo ", 5, "foo", true },
140 { "foo.", 4, "foo", true },
141 { "foo...", 6, "foo", true },
142 { " foo... ", 8, "foo", true },
143 /* unmodified */
144 { "foo", 3, "foo", false },
145 { ".foo", 4, ".foo", false },
146 { "..foo", 5, "..foo", false },
147 { "foo.bar.baz", 11, "foo.bar.baz", false },
148 { "null", 4, "null", false },
149 { "compass", 7, "compass", false }
150 };
151
152 for (size_t i = 0; i < TR_N_ELEMENTS(test_data); ++i)
153 {
154 bool is_adjusted;
155 char* const result = tr_metainfo_sanitize_path_component(test_data[i].str, test_data[i].len, &is_adjusted);
156
157 check_str(result, ==, test_data[i].expected_result);
158
159 if (test_data[i].expected_result != NULL)
160 {
161 check_bool(is_adjusted, ==, test_data[i].expected_is_adjusted);
162 }
163
164 tr_free(result);
165 }
166
167 return 0;
168 }
169
main(void)170 int main(void)
171 {
172 testFunc const tests[] =
173 {
174 test_magnet_link,
175 test_metainfo,
176 test_sanitize
177 };
178
179 return runTests(tests, NUM_TESTS(tests));
180 }
181