Line data Source code
1 : /**
2 : * @file DecoderTests.cpp
3 : * @copyright (c) 2014 by Petr Zemek (s3rvac@gmail.com) and contributors
4 : * @license BSD, see the @c LICENSE file for more details
5 : * @brief Tests for the Decoder class.
6 : */
7 :
8 : #include <memory>
9 : #include <sstream>
10 :
11 : #include <gtest/gtest.h>
12 :
13 : #include "BDictionary.h"
14 : #include "BInteger.h"
15 : #include "BList.h"
16 : #include "BString.h"
17 : #include "Decoder.h"
18 : #include "TestUtils.h"
19 :
20 : namespace bencoding {
21 : namespace tests {
22 :
23 : using namespace testing;
24 :
25 36 : class DecoderTests: public Test {
26 : protected:
27 36 : DecoderTests(): decoder(Decoder::create()) {}
28 :
29 : template <typename T>
30 : void assertDecodedAs(std::shared_ptr<BItem> bItem);
31 :
32 : protected:
33 : std::unique_ptr<Decoder> decoder;
34 : };
35 :
36 : template <typename T>
37 30 : void DecoderTests::assertDecodedAs(
38 : std::shared_ptr<BItem> bItem) {
39 :
40 60 : ASSERT_NE(bItem, nullptr)
41 0 : << "expected a correctly decoded item";
42 60 : EXPECT_NE(bItem->as<T>(), nullptr)
43 0 : << "expected " << typeid(T).name() << ", "
44 0 : << "got " << typeid(*bItem).name();
45 : }
46 :
47 : //
48 : // Dictionary decoding.
49 : //
50 :
51 5 : TEST_F(DecoderTests,
52 : EmptyDictionaryIsDecodedCorrectly) {
53 2 : std::string data("de");
54 2 : std::shared_ptr<BItem> bItem(decoder->decode(data));
55 :
56 2 : ADD_SCOPED_TRACE;
57 1 : assertDecodedAs<BDictionary>(bItem);
58 2 : auto bDictionary = bItem->as<BDictionary>();
59 1 : EXPECT_TRUE(bDictionary->empty());
60 1 : }
61 :
62 5 : TEST_F(DecoderTests,
63 : DictionaryWithSingleItemIsDecodedCorrectly) {
64 2 : std::string data("d4:testi1ee");
65 2 : std::shared_ptr<BItem> bItem(decoder->decode(data));
66 :
67 2 : ADD_SCOPED_TRACE;
68 1 : assertDecodedAs<BDictionary>(bItem);
69 2 : auto bDictionary = bItem->as<BDictionary>();
70 1 : EXPECT_EQ(1, bDictionary->size());
71 :
72 1 : auto i = bDictionary->begin();
73 1 : assertDecodedAs<BString>(i->first);
74 2 : auto key = i->first->as<BString>();
75 1 : EXPECT_EQ("test", key->value());
76 :
77 1 : assertDecodedAs<BInteger>(i->second);
78 2 : auto value = i->second->as<BInteger>();
79 1 : EXPECT_EQ(1, value->value());
80 1 : }
81 :
82 5 : TEST_F(DecoderTests,
83 : DictionaryWithTwoItemsIsDecodedCorrectly) {
84 2 : std::string data("d5:test1i1e5:test2i2ee");
85 2 : std::shared_ptr<BItem> bItem(decoder->decode(data));
86 :
87 2 : ADD_SCOPED_TRACE;
88 1 : assertDecodedAs<BDictionary>(bItem);
89 2 : auto bDictionary = bItem->as<BDictionary>();
90 1 : EXPECT_EQ(2, bDictionary->size());
91 :
92 1 : auto i = bDictionary->begin();
93 1 : assertDecodedAs<BString>(i->first);
94 2 : auto key1 = i->first->as<BString>();
95 1 : EXPECT_EQ("test1", key1->value());
96 :
97 1 : assertDecodedAs<BInteger>(i->second);
98 2 : auto value1 = i->second->as<BInteger>();
99 1 : EXPECT_EQ(1, value1->value());
100 :
101 1 : ++i;
102 1 : assertDecodedAs<BString>(i->first);
103 2 : auto key2 = i->first->as<BString>();
104 1 : EXPECT_EQ("test2", key2->value());
105 :
106 1 : assertDecodedAs<BInteger>(i->second);
107 2 : auto value2 = i->second->as<BInteger>();
108 1 : EXPECT_EQ(2, value2->value());
109 1 : }
110 :
111 5 : TEST_F(DecoderTests,
112 : DictionaryWithKeysThatAreNotSortedIsDecodedCorrectly) {
113 : // Even though the specification says that a dictionary has all its keys
114 : // lexicographically sorted, we support the decoding of dictionaries whose
115 : // keys are not sorted. The resulting dictionary, however, will always have
116 : // its keys sorted to conform to the specification.
117 2 : std::string data("d1:bi2e1:ai1ee");
118 2 : std::shared_ptr<BItem> bItem(decoder->decode(data));
119 :
120 2 : ADD_SCOPED_TRACE;
121 1 : assertDecodedAs<BDictionary>(bItem);
122 2 : auto bDictionary = bItem->as<BDictionary>();
123 1 : EXPECT_EQ(2, bDictionary->size());
124 :
125 1 : auto i = bDictionary->begin();
126 1 : assertDecodedAs<BString>(i->first);
127 2 : auto key1 = i->first->as<BString>();
128 1 : EXPECT_EQ("a", key1->value());
129 :
130 1 : assertDecodedAs<BInteger>(i->second);
131 2 : auto value1 = i->second->as<BInteger>();
132 1 : EXPECT_EQ(1, value1->value());
133 :
134 1 : ++i;
135 1 : assertDecodedAs<BString>(i->first);
136 2 : auto key2 = i->first->as<BString>();
137 1 : EXPECT_EQ("b", key2->value());
138 :
139 1 : assertDecodedAs<BInteger>(i->second);
140 2 : auto value2 = i->second->as<BInteger>();
141 1 : EXPECT_EQ(2, value2->value());
142 1 : }
143 :
144 5 : TEST_F(DecoderTests,
145 : DecodeThrowsDecodingErrorWhenDecodingDictionaryWithoutEndingE) {
146 2 : EXPECT_THROW(decoder->decode("d"), DecodingError);
147 1 : }
148 :
149 5 : TEST_F(DecoderTests,
150 : DecodeThrowsDecodingErrorWhenDecodingDictionaryWithKeyNotBeingString) {
151 2 : EXPECT_THROW(decoder->decode("di1ei2ee"), DecodingError);
152 1 : }
153 :
154 : //
155 : // Integer decoding.
156 : //
157 :
158 5 : TEST_F(DecoderTests,
159 : IntegerZeroIsCorrectlyDecoded) {
160 2 : std::string data("i0e");
161 2 : std::shared_ptr<BItem> bItem(decoder->decode(data));
162 :
163 2 : ADD_SCOPED_TRACE;
164 1 : assertDecodedAs<BInteger>(bItem);
165 2 : auto bInteger = bItem->as<BInteger>();
166 1 : EXPECT_EQ(0, bInteger->value());
167 1 : }
168 :
169 5 : TEST_F(DecoderTests,
170 : PositiveIntegerIsCorrectlyDecoded) {
171 2 : std::shared_ptr<BItem> bItem(decoder->decode("i13e"));
172 :
173 2 : ADD_SCOPED_TRACE;
174 1 : assertDecodedAs<BInteger>(bItem);
175 2 : auto bInteger = bItem->as<BInteger>();
176 1 : EXPECT_EQ(13, bInteger->value());
177 1 : }
178 :
179 5 : TEST_F(DecoderTests,
180 : ExplicitlyPositiveIntegerIsCorrectlyDecoded) {
181 2 : std::shared_ptr<BItem> bItem(decoder->decode("i+13e"));
182 :
183 2 : ADD_SCOPED_TRACE;
184 1 : assertDecodedAs<BInteger>(bItem);
185 2 : auto bInteger = bItem->as<BInteger>();
186 1 : EXPECT_EQ(+13, bInteger->value());
187 1 : }
188 :
189 5 : TEST_F(DecoderTests,
190 : NegativeIntegerIsCorrectlyDecoded) {
191 2 : std::shared_ptr<BItem> bItem(decoder->decode("i-13e"));
192 :
193 2 : ADD_SCOPED_TRACE;
194 1 : assertDecodedAs<BInteger>(bItem);
195 2 : auto bInteger = bItem->as<BInteger>();
196 1 : EXPECT_EQ(-13, bInteger->value());
197 1 : }
198 :
199 5 : TEST_F(DecoderTests,
200 : DecodeThrowsDecodingErrorWhenDecodingIntegerWithoutEndingE) {
201 2 : EXPECT_THROW(decoder->decode("i13"), DecodingError);
202 1 : }
203 :
204 5 : TEST_F(DecoderTests,
205 : DecodeThrowsDecodingErrorWhenDecodingIntegerWithoutValue) {
206 2 : EXPECT_THROW(decoder->decode("ie"), DecodingError);
207 1 : }
208 :
209 5 : TEST_F(DecoderTests,
210 : DecodeThrowsDecodingErrorWhenDecodingIntegerWithBeginningWhitespace) {
211 2 : EXPECT_THROW(decoder->decode("i 1e"), DecodingError);
212 1 : }
213 :
214 5 : TEST_F(DecoderTests,
215 : DecodeThrowsDecodingErrorWhenDecodingIntegerWithTrailingWhitespace) {
216 2 : EXPECT_THROW(decoder->decode("i1 e"), DecodingError);
217 1 : }
218 :
219 5 : TEST_F(DecoderTests,
220 : DecodeThrowsDecodingErrorWhenDecodingIntegerIsPaddedWithZeros) {
221 : // From https://wiki.theory.org/BitTorrentSpecification#Bencoding:
222 : //
223 : // "Only the significant digits should be used, one cannot pad the Integer
224 : // with zeroes. such as i04e."
225 : //
226 2 : EXPECT_THROW(decoder->decode("i001e"), DecodingError);
227 1 : }
228 :
229 5 : TEST_F(DecoderTests,
230 : DecodeThrowsDecodingErrorWhenDecodingIntegerOfInvalidValue) {
231 2 : EXPECT_THROW(decoder->decode("i e"), DecodingError);
232 2 : EXPECT_THROW(decoder->decode("i+e"), DecodingError);
233 2 : EXPECT_THROW(decoder->decode("i-e"), DecodingError);
234 2 : EXPECT_THROW(decoder->decode("i1-e"), DecodingError);
235 2 : EXPECT_THROW(decoder->decode("i1+e"), DecodingError);
236 2 : EXPECT_THROW(decoder->decode("i$e"), DecodingError);
237 2 : EXPECT_THROW(decoder->decode("i1.1e"), DecodingError);
238 1 : }
239 :
240 : //
241 : // List decoding.
242 : //
243 :
244 5 : TEST_F(DecoderTests,
245 : EmptyListIsCorrectlyDecoded) {
246 2 : std::string data("le");
247 2 : std::shared_ptr<BItem> bItem(decoder->decode(data));
248 :
249 2 : ADD_SCOPED_TRACE;
250 1 : assertDecodedAs<BList>(bItem);
251 2 : auto bList = bItem->as<BList>();
252 1 : EXPECT_TRUE(bList->empty());
253 1 : }
254 :
255 5 : TEST_F(DecoderTests,
256 : ListWithSingleIntegerIsDecodedCorrectly) {
257 2 : std::string data("li1ee");
258 2 : std::shared_ptr<BItem> bItem(decoder->decode(data));
259 :
260 2 : ADD_SCOPED_TRACE;
261 1 : assertDecodedAs<BList>(bItem);
262 2 : auto bList = bItem->as<BList>();
263 1 : ASSERT_EQ(1, bList->size());
264 2 : auto firstItem = bList->front();
265 1 : assertDecodedAs<BInteger>(firstItem);
266 2 : auto firstItemAsInteger = firstItem->as<BInteger>();
267 1 : EXPECT_EQ(1, firstItemAsInteger->value());
268 : }
269 :
270 5 : TEST_F(DecoderTests,
271 : ListWithTwoStringsIsDecodedCorrectly) {
272 2 : std::string data("l4:test5:helloe");
273 2 : std::shared_ptr<BItem> bItem(decoder->decode(data));
274 :
275 2 : ADD_SCOPED_TRACE;
276 1 : assertDecodedAs<BList>(bItem);
277 2 : auto bList = bItem->as<BList>();
278 1 : ASSERT_EQ(2, bList->size());
279 : // "test"
280 2 : auto firstItem = bList->front();
281 1 : assertDecodedAs<BString>(firstItem);
282 2 : auto firstItemAsString = firstItem->as<BString>();
283 1 : EXPECT_EQ("test", firstItemAsString->value());
284 : // "hello"
285 2 : auto secondItem = bList->back();
286 1 : assertDecodedAs<BString>(secondItem);
287 2 : auto secondItemAsString = secondItem->as<BString>();
288 1 : EXPECT_EQ("hello", secondItemAsString->value());
289 : }
290 :
291 5 : TEST_F(DecoderTests,
292 : DecodeThrowsDecodingErrorWhenCharEIsMissingFromEndOfList) {
293 2 : EXPECT_THROW(decoder->decode("li1e"), DecodingError);
294 2 : EXPECT_THROW(decoder->decode("l4:test"), DecodingError);
295 1 : }
296 :
297 5 : TEST_F(DecoderTests,
298 : DecodeThrowsDecodingErrorWhenListItemIsInvalidIsMissingFromEndOfList) {
299 2 : EXPECT_THROW(decoder->decode("l$e"), DecodingError);
300 1 : }
301 :
302 : //
303 : // String decoding.
304 : //
305 :
306 5 : TEST_F(DecoderTests,
307 : EmptyStringIsCorrrectlyDecoded) {
308 2 : std::string data("0:");
309 2 : std::shared_ptr<BItem> bItem(decoder->decode(data));
310 :
311 2 : ADD_SCOPED_TRACE;
312 1 : assertDecodedAs<BString>(bItem);
313 2 : auto bString = bItem->as<BString>();
314 1 : EXPECT_EQ("", bString->value());
315 1 : }
316 :
317 5 : TEST_F(DecoderTests,
318 : NonemptyStringWithSingleCharacterIsCorrrectlyDecoded) {
319 2 : std::string data("1:a");
320 2 : std::shared_ptr<BItem> bItem(decoder->decode(data));
321 :
322 2 : ADD_SCOPED_TRACE;
323 1 : assertDecodedAs<BString>(bItem);
324 2 : auto bString = bItem->as<BString>();
325 1 : EXPECT_EQ("a", bString->value());
326 1 : }
327 :
328 5 : TEST_F(DecoderTests,
329 : NonemptyStringWithTenCharacterIsCorrrectlyDecoded) {
330 2 : std::string data("10:abcdefghij");
331 2 : std::shared_ptr<BItem> bItem(decoder->decode(data));
332 :
333 2 : ADD_SCOPED_TRACE;
334 1 : assertDecodedAs<BString>(bItem);
335 2 : auto bString = bItem->as<BString>();
336 1 : EXPECT_EQ("abcdefghij", bString->value());
337 1 : }
338 :
339 5 : TEST_F(DecoderTests,
340 : DecodeThrowsDecodingErrorWhenColonIsMissingInString) {
341 2 : EXPECT_THROW(decoder->decode("1a"), DecodingError);
342 1 : }
343 :
344 5 : TEST_F(DecoderTests,
345 : DecodeThrowsDecodingErrorWhenStringHasNotEnoughCharacters) {
346 2 : EXPECT_THROW(decoder->decode("3:aa"), DecodingError);
347 1 : }
348 :
349 : //
350 : // Other.
351 : //
352 :
353 5 : TEST_F(DecoderTests,
354 : DecodeThrowsDecodingErrorWhenInputIsEmpty) {
355 2 : EXPECT_THROW(decoder->decode(""), DecodingError);
356 1 : }
357 :
358 5 : TEST_F(DecoderTests,
359 : DecodeThrowsDecodingErrorWhenInputIsAtEOF) {
360 2 : std::istringstream input;
361 1 : putIntoEOFState(input);
362 :
363 2 : EXPECT_THROW(decoder->decode(input), DecodingError);
364 1 : }
365 :
366 5 : TEST_F(DecoderTests,
367 : DecodeThrowsDecodingErrorWhenInputIsInError) {
368 2 : std::istringstream input;
369 1 : putIntoErrorState(input);
370 :
371 2 : EXPECT_THROW(decoder->decode(input), DecodingError);
372 1 : }
373 :
374 5 : TEST_F(DecoderTests,
375 : DecodeThrowsDecodingErrorWhenInputBeginsWithInvalidSymbol) {
376 2 : EXPECT_THROW(decoder->decode("$"), DecodingError);
377 1 : }
378 :
379 5 : TEST_F(DecoderTests,
380 : DecodeThrowsDecodingErrorWhenInputBeginsWithUnexpectedSymbol) {
381 2 : EXPECT_THROW(decoder->decode("e"), DecodingError);
382 1 : }
383 :
384 5 : TEST_F(DecoderTests,
385 : DecodeForStringThrowsDecodingErrorWhenInputIsNotCompletelyRead) {
386 : // Only the first i1e should be decoded, thus leaving i2e unread (such an
387 : // input is invalid as the integers are not inside of a list).
388 2 : EXPECT_THROW(decoder->decode("i1ei2e"), DecodingError);
389 1 : }
390 :
391 5 : TEST_F(DecoderTests,
392 : DecodeFromStreamWorksAsDecodeFromString) {
393 2 : std::istringstream input("i0e");
394 2 : std::shared_ptr<BItem> bItem(decoder->decode(input));
395 :
396 2 : ADD_SCOPED_TRACE;
397 1 : assertDecodedAs<BInteger>(bItem);
398 2 : auto bInteger = bItem->as<BInteger>();
399 1 : EXPECT_EQ(0, bInteger->value());
400 1 : }
401 :
402 5 : TEST_F(DecoderTests,
403 : DecodeForStreamDoesNotReadCharactersPassFirstDecodedItem) {
404 : // The second i2e is supposed to be left in the stream.
405 2 : std::istringstream input("i1ei2e");
406 2 : std::shared_ptr<BItem> bItem(decoder->decode(input));
407 :
408 1 : ASSERT_EQ('i', input.get());
409 1 : ASSERT_EQ('2', input.get());
410 1 : ASSERT_EQ('e', input.get());
411 : }
412 :
413 5 : TEST_F(DecoderTests,
414 : DecodeFunctionForStringWorksAsCreatingDecoderAndCallingDecode) {
415 2 : std::string input("i0e");
416 2 : std::shared_ptr<BItem> bItem(decode(input));
417 :
418 2 : ADD_SCOPED_TRACE;
419 1 : assertDecodedAs<BInteger>(bItem);
420 2 : auto bInteger = bItem->as<BInteger>();
421 1 : EXPECT_EQ(0, bInteger->value());
422 1 : }
423 :
424 5 : TEST_F(DecoderTests,
425 : DecodeFunctionForStreamWorksAsCreatingDecoderAndCallingDecode) {
426 2 : std::istringstream input("i0e");
427 2 : std::shared_ptr<BItem> bItem(decode(input));
428 :
429 2 : ADD_SCOPED_TRACE;
430 1 : assertDecodedAs<BInteger>(bItem);
431 2 : auto bInteger = bItem->as<BInteger>();
432 1 : EXPECT_EQ(0, bInteger->value());
433 1 : }
434 :
435 : } // namespace tests
436 3 : } // namespace bencoding
|