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