#include "ChunkedDecodingStreamFilter.h" #include #include #include #include "DlAbortEx.h" #include "Segment.h" #include "ByteArrayDiskWriter.h" #include "SinkStreamFilter.h" #include "MockSegment.h" #include "a2functional.h" namespace aria2 { class ChunkedDecodingStreamFilterTest:public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(ChunkedDecodingStreamFilterTest); CPPUNIT_TEST(testTransform); CPPUNIT_TEST(testTransform_withoutTrailer); CPPUNIT_TEST(testTransform_with2Trailers); CPPUNIT_TEST(testTransform_largeChunkSize); CPPUNIT_TEST(testTransform_tooLargeChunkSize); CPPUNIT_TEST(testTransform_chunkSizeMismatch); CPPUNIT_TEST(testGetName); CPPUNIT_TEST_SUITE_END(); std::unique_ptr filter_; std::shared_ptr writer_; std::shared_ptr segment_; void clearWriter() { writer_->setString(""); } public: void setUp() { writer_ = std::make_shared(); auto sinkFilter = make_unique(); sinkFilter->init(); filter_ = make_unique(std::move(sinkFilter)); filter_->init(); segment_ = std::make_shared(); } void testTransform(); void testTransform_withoutTrailer(); void testTransform_with2Trailers(); void testTransform_largeChunkSize(); void testTransform_tooLargeChunkSize(); void testTransform_chunkSizeMismatch(); void testGetName(); }; CPPUNIT_TEST_SUITE_REGISTRATION( ChunkedDecodingStreamFilterTest ); void ChunkedDecodingStreamFilterTest::testTransform() { try { std::basic_string msg = reinterpret_cast("a\r\n1234567890\r\n"); ssize_t r = filter_->transform(writer_, segment_, msg.data(), msg.size()); CPPUNIT_ASSERT_EQUAL((ssize_t)10, r); CPPUNIT_ASSERT_EQUAL(std::string("1234567890"), writer_->getString()); CPPUNIT_ASSERT_EQUAL((size_t)15, filter_->getBytesProcessed()); } catch(DlAbortEx& e) { CPPUNIT_FAIL(e.stackTrace()); } clearWriter(); try { // Feed extension; see it is ignored. std::basic_string msg = reinterpret_cast ("3;extensionIgnored\r\n123\r\n"); ssize_t r = filter_->transform(writer_, segment_, msg.data(), msg.size()); CPPUNIT_ASSERT_EQUAL((ssize_t)3, r); CPPUNIT_ASSERT_EQUAL(std::string("123"), writer_->getString()); CPPUNIT_ASSERT_EQUAL((size_t)25, filter_->getBytesProcessed()); } catch(DlAbortEx& e) { CPPUNIT_FAIL(e.stackTrace()); } clearWriter(); // Feed 2extensions; see it is ignored. try { std::basic_string msg = reinterpret_cast ("3;extension1;extension2;\r\n123\r\n"); ssize_t r = filter_->transform(writer_, segment_, msg.data(), msg.size()); CPPUNIT_ASSERT_EQUAL((ssize_t)3, r); CPPUNIT_ASSERT_EQUAL(std::string("123"), writer_->getString()); } catch(DlAbortEx& e) { CPPUNIT_FAIL(e.stackTrace()); } clearWriter(); // Not all chunk size is available try { std::basic_string msg = reinterpret_cast("1"); ssize_t r = filter_->transform(writer_, segment_, msg.data(), msg.size()); CPPUNIT_ASSERT_EQUAL((ssize_t)0, r); } catch(DlAbortEx& e) { CPPUNIT_FAIL(e.stackTrace()); } clearWriter(); try { std::basic_string msg = reinterpret_cast("0\r\n1234567890123456\r\n"); ssize_t r = filter_->transform(writer_, segment_, msg.data(), msg.size()); CPPUNIT_ASSERT_EQUAL((ssize_t)16, r); CPPUNIT_ASSERT_EQUAL(std::string("1234567890123456"), writer_->getString()); } catch(DlAbortEx& e) { CPPUNIT_FAIL(e.stackTrace()); } clearWriter(); // Not all chunk data is available try { std::basic_string msg = reinterpret_cast("10\r\n1234567890"); ssize_t r = filter_->transform(writer_, segment_, msg.data(), msg.size()); CPPUNIT_ASSERT_EQUAL((ssize_t)10, r); CPPUNIT_ASSERT_EQUAL(std::string("1234567890"), writer_->getString()); } catch(DlAbortEx& e) { CPPUNIT_FAIL(e.stackTrace()); } clearWriter(); try { std::basic_string msg = reinterpret_cast("123456\r\n"); ssize_t r = filter_->transform(writer_, segment_, msg.data(), msg.size()); CPPUNIT_ASSERT_EQUAL((ssize_t)6, r); CPPUNIT_ASSERT_EQUAL(std::string("123456"), writer_->getString()); } catch(DlAbortEx& e) { CPPUNIT_FAIL(e.stackTrace()); } clearWriter(); // no trailing CR LF. try { std::basic_string msg = reinterpret_cast("10\r\n1234567890123456"); ssize_t r = filter_->transform(writer_, segment_, msg.data(), msg.size()); CPPUNIT_ASSERT_EQUAL((ssize_t)16, r); CPPUNIT_ASSERT_EQUAL(std::string("1234567890123456"), writer_->getString()); } catch(DlAbortEx& e) { CPPUNIT_FAIL(e.stackTrace()); } clearWriter(); // feed only CR try { std::basic_string msg = reinterpret_cast("\r"); ssize_t r = filter_->transform(writer_, segment_, msg.data(), msg.size()); CPPUNIT_ASSERT_EQUAL((ssize_t)0, r); } catch(DlAbortEx& e) { CPPUNIT_FAIL(e.stackTrace()); } // feed next LF try { std::basic_string msg = reinterpret_cast("\n"); ssize_t r = filter_->transform(writer_, segment_, msg.data(), msg.size()); CPPUNIT_ASSERT_EQUAL((ssize_t)0, r); CPPUNIT_ASSERT_EQUAL(std::string(""), writer_->getString()); } catch(DlAbortEx& e) { CPPUNIT_FAIL(e.stackTrace()); } // feed 0 CR LF. try { std::basic_string msg = reinterpret_cast("0\r\n"); ssize_t r = filter_->transform(writer_, segment_, msg.data(), msg.size()); CPPUNIT_ASSERT_EQUAL((ssize_t)0, r); } catch(DlAbortEx& e) { CPPUNIT_FAIL(e.stackTrace()); } // feed trailer try { std::basic_string msg = reinterpret_cast("trailer\r\n"); ssize_t r = filter_->transform(writer_, segment_, msg.data(), msg.size()); CPPUNIT_ASSERT_EQUAL((ssize_t)0, r); } catch(DlAbortEx& e) { CPPUNIT_FAIL(e.stackTrace()); } // feed final CRLF try { std::basic_string msg = reinterpret_cast("\r\n"); ssize_t r = filter_->transform(writer_, segment_, msg.data(), msg.size()); CPPUNIT_ASSERT_EQUAL((ssize_t)0, r); } catch(DlAbortEx& e) { CPPUNIT_FAIL(e.stackTrace()); } // input is over CPPUNIT_ASSERT(filter_->finished()); } void ChunkedDecodingStreamFilterTest::testTransform_withoutTrailer() { CPPUNIT_ASSERT_EQUAL ((ssize_t)0, filter_->transform (writer_, segment_, reinterpret_cast("0\r\n\r\n"), 5)); CPPUNIT_ASSERT(filter_->finished()); } void ChunkedDecodingStreamFilterTest::testTransform_with2Trailers() { CPPUNIT_ASSERT_EQUAL ((ssize_t)0, filter_->transform (writer_, segment_, reinterpret_cast("0\r\nt1\r\nt2\r\n\r\n"), 13)); CPPUNIT_ASSERT(filter_->finished()); } void ChunkedDecodingStreamFilterTest::testTransform_largeChunkSize() { // chunkSize should be under 2^63-1 { std::basic_string msg = reinterpret_cast("7fffffffffffffff\r\n"); filter_->transform(writer_, segment_, msg.data(), msg.size()); } } void ChunkedDecodingStreamFilterTest::testTransform_tooLargeChunkSize() { // chunkSize 2^64 causes error { std::basic_string msg = reinterpret_cast("ffffffffffffffff\r\n"); try { filter_->transform(writer_, segment_, msg.data(), msg.size()); CPPUNIT_FAIL("exception must be thrown."); } catch(DlAbortEx& e) { // success } } } void ChunkedDecodingStreamFilterTest::testTransform_chunkSizeMismatch() { std::basic_string msg = reinterpret_cast("3\r\n1234\r\n"); try { filter_->transform(writer_, segment_, msg.data(), msg.size()); CPPUNIT_FAIL("exception must be thrown."); } catch(DlAbortEx& e) { // success } } void ChunkedDecodingStreamFilterTest::testGetName() { CPPUNIT_ASSERT_EQUAL (std::string("ChunkedDecodingStreamFilter"), filter_->getName()); } } // namespace aria2