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:ÞÉ`âM‘‹Šs¡Å;˺¬.åÂà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