1 #include "config.h"
2 
3 #define __STDC_CONSTANT_MACROS
4 
5 #include <iostream>
6 #include <sstream>
7 #include <inttypes.h>
8 #include <torrent/object.h>
9 
10 #include "object_stream_test.h"
11 #include "object_test_utils.h"
12 
13 CPPUNIT_TEST_SUITE_REGISTRATION(ObjectStreamTest);
14 
15 static const char* ordered_bencode = "d1:ei0e4:ipv44:XXXX4:ipv616:XXXXXXXXXXXXXXXX1:md11:upload_onlyi3e12:ut_holepunchi4e11:ut_metadatai2e6:ut_pexi1ee13:metadata_sizei15408e1:pi16033e4:reqqi255e1:v15:uuTorrent 1.8.46:yourip4:XXXXe";
16 static const char* unordered_bencode = "d1:ei0e1:md11:upload_onlyi3e12:ut_holepunchi4e11:ut_metadatai2e6:ut_pexi1ee4:ipv44:XXXX4:ipv616:XXXXXXXXXXXXXXXX13:metadata_sizei15408e1:pi16033e4:reqqi255e1:v15:uuTorrent 1.8.46:yourip4:XXXXe";
17 
18 static const char* string_bencode = "32:aaaaaaaabbbbbbbbccccccccdddddddd";
19 
20 void
testInputOrdered()21 ObjectStreamTest::testInputOrdered() {
22   torrent::Object orderedObj   = create_bencode(ordered_bencode);
23   torrent::Object unorderedObj = create_bencode(unordered_bencode);
24 
25   CPPUNIT_ASSERT(!(orderedObj.flags() & torrent::Object::flag_unordered));
26   CPPUNIT_ASSERT(unorderedObj.flags() & torrent::Object::flag_unordered);
27 }
28 
29 void
testInputNullKey()30 ObjectStreamTest::testInputNullKey() {
31   torrent::Object obj = create_bencode("d0:i1e5:filesi2ee");
32 
33   CPPUNIT_ASSERT(!(obj.flags() & torrent::Object::flag_unordered));
34 }
35 
36 void
testOutputMask()37 ObjectStreamTest::testOutputMask() {
38   torrent::Object normalObj = create_bencode("d1:ai1e1:bi2e1:ci3ee");
39 
40   CPPUNIT_ASSERT(compare_bencode(normalObj, "d1:ai1e1:bi2e1:ci3ee"));
41 
42   normalObj.get_key("b").set_flags(torrent::Object::flag_session_data);
43   normalObj.get_key("c").set_flags(torrent::Object::flag_static_data);
44 
45   CPPUNIT_ASSERT(compare_bencode(normalObj, "d1:ai1e1:ci3ee", torrent::Object::flag_session_data));
46 }
47 
48 //
49 // Testing for bugs in bencode write.
50 //
51 
52 // Dummy function that invalidates the buffer once called.
53 
54 torrent::object_buffer_t
object_write_to_invalidate(void * data,torrent::object_buffer_t buffer)55 object_write_to_invalidate(void* data, torrent::object_buffer_t buffer) {
56   return torrent::object_buffer_t(buffer.second, buffer.second);
57 }
58 
59 void
testBuffer()60 ObjectStreamTest::testBuffer() {
61   char raw_buffer[16];
62   torrent::object_buffer_t buffer(raw_buffer, raw_buffer + 16);
63 
64   torrent::Object obj = create_bencode(string_bencode);
65 
66   object_write_bencode_c(&object_write_to_invalidate, NULL, buffer, &obj);
67 }
68 
69 static const char* single_level_bencode = "d1:ai1e1:bi2e1:cl1:ai1e1:bi2eee";
70 
71 void
testReadBencodeC()72 ObjectStreamTest::testReadBencodeC() {
73   torrent::Object orderedObj   = create_bencode_c(ordered_bencode);
74   torrent::Object unorderedObj = create_bencode_c(unordered_bencode);
75 
76   CPPUNIT_ASSERT(!(orderedObj.flags() & torrent::Object::flag_unordered));
77   CPPUNIT_ASSERT(unorderedObj.flags() & torrent::Object::flag_unordered);
78   CPPUNIT_ASSERT(compare_bencode(orderedObj, ordered_bencode));
79 
80   //  torrent::Object single_level = create_bencode_c(single_level_bencode);
81   torrent::Object single_level = create_bencode_c(single_level_bencode);
82 
83   CPPUNIT_ASSERT(compare_bencode(single_level, single_level_bencode));
84 }
85 
object_write_bencode(const torrent::Object & obj,const char * original)86 bool object_write_bencode(const torrent::Object& obj, const char* original) {
87   try {
88     char buffer[1025];
89     char* last = torrent::object_write_bencode(buffer, buffer + 1024, &obj).first;
90     return std::strncmp(buffer, original, std::distance(buffer, last)) == 0;
91 
92   } catch (torrent::bencode_error& e) {
93     return false;
94   }
95 }
96 
object_stream_read_skip(const char * input)97 bool object_stream_read_skip(const char* input) {
98   try {
99     torrent::Object tmp;
100     return
101       torrent::object_read_bencode_c(input, input + strlen(input), &tmp) == input + strlen(input) &&
102       torrent::object_read_bencode_skip_c(input, input + strlen(input)) == input + strlen(input);
103   } catch (torrent::bencode_error& e) {
104     return false;
105   }
106 }
107 
object_stream_read_skip_catch(const char * input)108 bool object_stream_read_skip_catch(const char* input) {
109   try {
110     torrent::Object tmp;
111     torrent::object_read_bencode_c(input, input + strlen(input), &tmp);
112     std::cout << "(N)";
113     return false;
114   } catch (torrent::bencode_error& e) {
115   }
116 
117   try {
118     torrent::object_read_bencode_skip_c(input, input + strlen(input));
119     std::cout << "(S)";
120     return false;
121   } catch (torrent::bencode_error& e) {
122     return true;
123   }
124 }
125 
126 void
test_read_skip()127 ObjectStreamTest::test_read_skip() {
128   CPPUNIT_ASSERT(object_stream_read_skip("i0e"));
129   CPPUNIT_ASSERT(object_stream_read_skip("i9999e"));
130   CPPUNIT_ASSERT(object_stream_read_skip("i-1e"));
131   CPPUNIT_ASSERT(object_stream_read_skip("i-9999e"));
132 
133   CPPUNIT_ASSERT(object_stream_read_skip("0:"));
134   CPPUNIT_ASSERT(object_stream_read_skip("4:test"));
135 
136   CPPUNIT_ASSERT(object_stream_read_skip("le"));
137   CPPUNIT_ASSERT(object_stream_read_skip("li1ee"));
138   CPPUNIT_ASSERT(object_stream_read_skip("llee"));
139   CPPUNIT_ASSERT(object_stream_read_skip("ll1:a1:bel1:c1:dee"));
140 
141   CPPUNIT_ASSERT(object_stream_read_skip("de"));
142   CPPUNIT_ASSERT(object_stream_read_skip("d1:ai1e1:b1:xe"));
143   CPPUNIT_ASSERT(object_stream_read_skip("d1:ali1eee"));
144   CPPUNIT_ASSERT(object_stream_read_skip("d1:ad1:bi1eee"));
145 
146   CPPUNIT_ASSERT(object_stream_read_skip("d1:md6:ut_pexi0eee"));
147 }
148 
149 void
test_read_skip_invalid()150 ObjectStreamTest::test_read_skip_invalid() {
151   CPPUNIT_ASSERT(object_stream_read_skip_catch(""));
152   CPPUNIT_ASSERT(object_stream_read_skip_catch("i"));
153   CPPUNIT_ASSERT(object_stream_read_skip_catch("1"));
154   CPPUNIT_ASSERT(object_stream_read_skip_catch("d"));
155 
156   CPPUNIT_ASSERT(object_stream_read_skip_catch("i-0e"));
157   CPPUNIT_ASSERT(object_stream_read_skip_catch("i--1e"));
158   CPPUNIT_ASSERT(object_stream_read_skip_catch("-1"));
159   CPPUNIT_ASSERT(object_stream_read_skip_catch("-1a"));
160 
161   CPPUNIT_ASSERT(object_stream_read_skip_catch("llllllll" "llllllll" "llllllll" "llllllll"
162                                                "llllllll" "llllllll" "llllllll" "llllllll"
163                                                "llllllll" "llllllll" "llllllll" "llllllll"
164                                                "llllllll" "llllllll" "llllllll" "llllllll"));
165 }
166 
167 void
test_write()168 ObjectStreamTest::test_write() {
169   torrent::Object obj;
170 
171   CPPUNIT_ASSERT(object_write_bencode(torrent::Object(), ""));
172   CPPUNIT_ASSERT(object_write_bencode(torrent::Object((int64_t)0), "i0e"));
173   CPPUNIT_ASSERT(object_write_bencode(torrent::Object((int64_t)1), "i1e"));
174   CPPUNIT_ASSERT(object_write_bencode(torrent::Object((int64_t)-1), "i-1e"));
175   CPPUNIT_ASSERT(object_write_bencode(torrent::Object(INT64_C(123456789012345)), "i123456789012345e"));
176   CPPUNIT_ASSERT(object_write_bencode(torrent::Object(INT64_C(-123456789012345)), "i-123456789012345e"));
177 
178   CPPUNIT_ASSERT(object_write_bencode(torrent::Object("test"), "4:test"));
179   CPPUNIT_ASSERT(object_write_bencode(torrent::Object::create_list(), "le"));
180   CPPUNIT_ASSERT(object_write_bencode(torrent::Object::create_map(), "de"));
181 
182   obj = torrent::Object::create_map();
183   obj.as_map()["a"] = (int64_t)1;
184   CPPUNIT_ASSERT(object_write_bencode(obj, "d1:ai1ee"));
185 
186   obj.as_map()["b"] = "test";
187   CPPUNIT_ASSERT(object_write_bencode(obj, "d1:ai1e1:b4:teste"));
188 
189   obj.as_map()["c"] = torrent::Object::create_list();
190   obj.as_map()["c"].as_list().push_back("foo");
191   CPPUNIT_ASSERT(object_write_bencode(obj, "d1:ai1e1:b4:test1:cl3:fooee"));
192 
193   obj.as_map()["c"].as_list().push_back(torrent::Object());
194   obj.as_map()["d"] = torrent::Object();
195   CPPUNIT_ASSERT(object_write_bencode(obj, "d1:ai1e1:b4:test1:cl3:fooee"));
196 }
197