2007-10-24 Tatsuhiro Tsujikawa <tujikawa at rednoah dot com>

* src/Piece.{h, cc}: Added SubPiece infrastructure to track down
	the data smaller than block length.
	A block length can be specified by constructor's argument.
	* src/DefaultPieceStorage.{h, cc} (getMissingPiece):
	Get a missing piece in the range of given FileEntry. This 
function is
	not used in the program yet.
	* src/Util.h: Added some macros.
pull/1/head
Tatsuhiro Tsujikawa 2007-10-23 16:29:37 +00:00
parent 884a139e72
commit 3ab9fe706d
14 changed files with 419 additions and 32 deletions

View File

@ -1,3 +1,13 @@
2007-10-24 Tatsuhiro Tsujikawa <tujikawa at rednoah dot com>
* src/Piece.{h, cc}: Added SubPiece infrastructure to track down
the data smaller than block length.
A block length can be specified by constructor's argument.
* src/DefaultPieceStorage.{h, cc} (getMissingPiece):
Get a missing piece in the range of given FileEntry. This function is
not used in the program yet.
* src/Util.h: Added some macros.
2007-10-18 Tatsuhiro Tsujikawa <tujikawa at rednoah dot com>
Added HTTP/1.1 keep alive and pipelining support.

9
TODO
View File

@ -49,8 +49,13 @@
* Rewrite MetaFileUtil
* Reconsider the use of RecoverableException and FatalException
* Limit the number of opening file to,say,100 in MultiDiskAdaptor.
* Implement duplicate download checking in Bt
* Implement the feature to treat http/ftp as auxuality download method for BitTorrent
-- remaining features to be implemented for 0.12.0 release
* Reimplement ChecksumCommand(validation using 1 checksum for 1 file)
* Implement duplicate download checking in Bt
* Add PeerListenCommand to DownloadEngine only when it is really necessary.
* ftp://USER:PASSWD@Servername automatic parsing
* improve --metalink-location field
* Use content-type for PostDownloadHandler
* Torrent information

View File

@ -236,7 +236,7 @@ void DefaultBtInteractive::addRequests() {
if(pieceStorage->isEndGame()) {
pieceNum = 1;
} else {
int32_t blocks = DIV_FLOOR(btContext->getPieceLength(), BLOCK_LENGTH);
int32_t blocks = DIV_FLOOR(btContext->getPieceLength(), Piece::BLOCK_LENGTH);
pieceNum = DIV_FLOOR(MAX_PENDING_REQUEST, blocks);
}
fillPiece(pieceNum);

View File

@ -46,6 +46,7 @@
#include "message.h"
#include "DefaultDiskWriterFactory.h"
#include "DlAbortEx.h"
#include "Util.h"
DefaultPieceStorage::DefaultPieceStorage(const DownloadContextHandle& downloadContext, const Option* option):
downloadContext(downloadContext),
@ -194,6 +195,36 @@ PieceHandle DefaultPieceStorage::getMissingPiece()
return checkOutPiece(bitfieldMan->getSparseMissingUnusedIndex());
}
PieceHandle DefaultPieceStorage::getMissingPiece(const FileEntryHandle& fileEntry)
{
BitfieldMan temp(*bitfieldMan);
temp.clearFilter();
temp.addFilter(fileEntry->getOffset(), fileEntry->getLength());
temp.enableFilter();
int32_t firstPieceIndex = START_INDEX(fileEntry->getOffset(), downloadContext->getPieceLength());
int32_t endPieceIndex = END_INDEX(fileEntry->getOffset(), fileEntry->getLength(), downloadContext->getPieceLength());
if(!temp.isBitSet(firstPieceIndex) && !temp.isUseBitSet(firstPieceIndex)) {
PieceHandle piece = findUsedPiece(firstPieceIndex);
if(!piece.isNull()) {
if(piece->isRangeComplete(fileEntry->getOffset()-firstPieceIndex*downloadContext->getPieceLength(),
fileEntry->getLength() > downloadContext->getPieceLength() ?
downloadContext->getPieceLength():fileEntry->getLength())) {
temp.setBit(firstPieceIndex);
}
}
}
if(firstPieceIndex != endPieceIndex && !temp.isBitSet(endPieceIndex) && !temp.isUseBitSet(endPieceIndex)) {
PieceHandle piece = findUsedPiece(endPieceIndex);
if(!piece.isNull()) {
if(piece->isRangeComplete(0, fileEntry->getOffset()+fileEntry->getLength()-endPieceIndex*downloadContext->getPieceLength())) {
temp.setBit(endPieceIndex);
}
}
}
return checkOutPiece(temp.getSparseMissingUnusedIndex());
}
PieceHandle DefaultPieceStorage::getMissingPiece(int32_t index)
{
if(hasPiece(index) || isPieceUsed(index)) {
@ -299,7 +330,7 @@ void DefaultPieceStorage::cancelPiece(const PieceHandle& piece)
}
bitfieldMan->unsetUseBit(piece->getIndex());
if(!isEndGame()) {
if(piece->countCompleteBlock() == 0) {
if(piece->getCompletedLength() == 0) {
deleteUsedPiece(piece);
}
}
@ -376,6 +407,7 @@ void DefaultPieceStorage::clearFileFilter()
// not unittested
bool DefaultPieceStorage::downloadFinished()
{
// TODO iterate all requested FileEntry and Call bitfieldMan->isBitSetOffsetRange()
return bitfieldMan->isFilteredAllBitSet();
}

View File

@ -45,6 +45,8 @@ class Option;
extern typedef deque<PieceHandle> Pieces;
class DiskWriterFactory;
extern typedef SharedHandle<DiskWriterFactory> DiskWriterFactoryHandle;
class FileEntry;
extern typedef SharedHandle<FileEntry> FileEntryHandle;
#define END_GAME_PIECE_NUM 20
@ -97,6 +99,7 @@ public:
virtual PieceHandle getMissingFastPiece(const PeerHandle& peer);
virtual PieceHandle getMissingPiece();
virtual PieceHandle getMissingPiece(const FileEntryHandle& fileEntry);
virtual PieceHandle getMissingPiece(int32_t index);

View File

@ -36,16 +36,17 @@
#include "Util.h"
#include "BitfieldManFactory.h"
Piece::Piece():index(0), length(0), bitfield(0) {}
Piece::Piece():index(0), length(0), _blockLength(BLOCK_LENGTH), bitfield(0) {}
Piece::Piece(int32_t index, int32_t length):index(index), length(length) {
Piece::Piece(int32_t index, int32_t length, int32_t blockLength):index(index), length(length), _blockLength(blockLength) {
bitfield =
BitfieldManFactory::getFactoryInstance()->createBitfieldMan(BLOCK_LENGTH, length);
BitfieldManFactory::getFactoryInstance()->createBitfieldMan(_blockLength, length);
}
Piece::Piece(const Piece& piece) {
index = piece.index;
length = piece.length;
_blockLength = piece._blockLength;
if(piece.bitfield == 0) {
bitfield = 0;
} else {
@ -53,10 +54,10 @@ Piece::Piece(const Piece& piece) {
}
}
void Piece::completeBlock(int32_t blockIndex) {
bitfield->setBit(blockIndex);
bitfield->unsetUseBit(blockIndex);
removeSubPiece(blockIndex);
}
void Piece::clearAllBlock() {
@ -106,7 +107,7 @@ void Piece::reconfigure(int32_t length)
{
this->length = length;
bitfield =
BitfieldManFactory::getFactoryInstance()->createBitfieldMan(BLOCK_LENGTH, length);
BitfieldManFactory::getFactoryInstance()->createBitfieldMan(_blockLength, length);
}
void Piece::setBitfield(const unsigned char* bitfield, int32_t len)
@ -114,3 +115,96 @@ void Piece::setBitfield(const unsigned char* bitfield, int32_t len)
this->bitfield->setBitfield(bitfield, len);
}
void Piece::addSubPiece(const PieceHandle& subPiece)
{
_subPieces.push_back(subPiece);
}
PieceHandle Piece::getSubPiece(int32_t blockIndex)
{
Pieces::iterator itr = getSubPieceIterator(blockIndex);
if(itr == _subPieces.end()) {
return 0;
} else {
return *itr;
}
}
void Piece::removeSubPiece(int32_t blockIndex)
{
Pieces::iterator itr = getSubPieceIterator(blockIndex);
if(itr != _subPieces.end()) {
_subPieces.erase(itr);
}
}
Pieces::iterator Piece::getSubPieceIterator(int32_t blockIndex)
{
for(Pieces::iterator itr = _subPieces.begin(); itr != _subPieces.end(); ++itr) {
if((*itr)->getIndex() == blockIndex) {
return itr;
}
}
return _subPieces.end();
}
bool Piece::isRangeComplete(int32_t offset, int32_t length)
{
int32_t startIndex = START_INDEX(offset, _blockLength);
int32_t endIndex = END_INDEX(offset, length, _blockLength);
if(countBlock() <= endIndex) {
endIndex = countBlock()-1;
}
if(startIndex+1 < endIndex) {
if(!bitfield->isBitRangeSet(startIndex+1, endIndex-1)) {
return false;
}
}
if(startIndex == endIndex) {
if(hasBlock(startIndex)) {
return true;
}
PieceHandle subPiece = getSubPiece(startIndex);
if(subPiece.isNull()) {
return false;
}
return subPiece->isRangeComplete(offset, length);
} else {
if(!hasBlock(startIndex)) {
PieceHandle subPiece = getSubPiece(startIndex);
if(subPiece.isNull()) {
return false;
}
if(!subPiece->isRangeComplete(offset-startIndex*_blockLength, length)) {
return false;
}
}
if(!hasBlock(endIndex)) {
PieceHandle subPiece = getSubPiece(endIndex);
if(subPiece.isNull()) {
return false;
}
if(!subPiece->isRangeComplete(0, offset+length-endIndex*_blockLength)) {
return false;
}
}
return true;
}
}
int32_t Piece::getCompletedLength()
{
int32_t length = 0;
for(int32_t i = 0; i < countBlock(); ++i) {
if(hasBlock(i)) {
length += getBlockLength(i);
} else {
PieceHandle subPiece = getSubPiece(i);
if(!subPiece.isNull()) {
length += subPiece->getCompletedLength();
}
}
}
return length;
}

View File

@ -38,17 +38,25 @@
#include "BitfieldMan.h"
#include "common.h"
#define BLOCK_LENGTH (16*1024)
class Piece;
typedef SharedHandle<Piece> PieceHandle;
typedef deque<PieceHandle> Pieces;
class Piece {
private:
int32_t index;
int32_t length;
int32_t _blockLength;
BitfieldMan* bitfield;
Pieces _subPieces;
public:
static const int32_t BLOCK_LENGTH = 16*1024;
Piece();
Piece(int32_t index, int32_t length);
Piece(int32_t index, int32_t length, int32_t blockLength = BLOCK_LENGTH);
Piece(const Piece& piece);
@ -118,6 +126,19 @@ public:
return bitfield->isUseBitSet(index);
}
void addSubPiece(const PieceHandle& subPiece);
PieceHandle getSubPiece(int32_t blockIndex);
void removeSubPiece(int32_t blockIndex);
Pieces::iterator getSubPieceIterator(int32_t blockIndex);
bool isRangeComplete(int32_t offset, int32_t length);
// Calculates completed length, taking into account SubPieces
int32_t getCompletedLength();
/**
* Loses current bitfield state.
*/

View File

@ -38,7 +38,7 @@
PiecedSegment::PiecedSegment(int32_t pieceLength, const PieceHandle& piece):
_pieceLength(pieceLength), _overflowLength(0), _piece(piece)
{
_writtenLength = _piece->getAllMissingBlockIndexes().front()*BLOCK_LENGTH;
_writtenLength = _piece->getAllMissingBlockIndexes().front()*_piece->getBlockLength();
}
PiecedSegment::~PiecedSegment() {}
@ -75,7 +75,7 @@ void PiecedSegment::updateWrittenLength(int32_t bytes)
_overflowLength = newWrittenLength-_piece->getLength();
newWrittenLength = _piece->getLength();
}
for(int32_t i = _writtenLength/BLOCK_LENGTH; i < newWrittenLength/BLOCK_LENGTH; ++i) {
for(int32_t i = _writtenLength/_piece->getBlockLength(); i < newWrittenLength/_piece->getBlockLength(); ++i) {
_piece->completeBlock(i);
}
if(newWrittenLength == _piece->getLength()) {

View File

@ -42,7 +42,7 @@ ostream& operator<<(ostream& o, const Segment& segment) {
if(segment.complete()) {
o << "writtenLength = " << segment._piece->getLength();
} else {
o << "writtenLength = " << (segment._piece->getMissingUnusedBlockIndex()-1)*BLOCK_LENGTH;
o << "writtenLength = " << (segment._piece->getMissingUnusedBlockIndex()-1)*segment._piece->getBlockLength();
}
return o;
}

View File

@ -43,7 +43,10 @@
#include <deque>
#include <ostream>
#define STRTOLL(X) strtoll(X, (char**)NULL, 10);
#define STRTOLL(X) strtoll(X, (char**)NULL, 10)
#define START_INDEX(OFFSET, PIECE_LENGTH) ((OFFSET)/(PIECE_LENGTH))
#define END_INDEX(OFFSET, LENGTH, PIECE_LENGTH) (((OFFSET)+(LENGTH)-1)/(PIECE_LENGTH))
class Util {
public:

View File

@ -7,6 +7,7 @@
#include "Piece.h"
#include "Peer.h"
#include "Option.h"
#include "MockBtContext.h"
#include <cppunit/extensions/HelperMacros.h>
using namespace std;
@ -22,6 +23,8 @@ class DefaultPieceStorageTest:public CppUnit::TestFixture {
CPPUNIT_TEST(testGetPiece);
CPPUNIT_TEST(testGetPieceInUsedPieces);
CPPUNIT_TEST(testGetPieceCompletedPiece);
CPPUNIT_TEST(testGetMissingPiece_fileEntry);
CPPUNIT_TEST(testCancelPiece);
CPPUNIT_TEST_SUITE_END();
private:
BtContextHandle btContext;
@ -43,6 +46,12 @@ public:
option = new Option();
}
void tearDown()
{
delete option;
option = 0;
}
void testGetTotalLength();
void testGetMissingPiece();
void testGetMissingFastPiece();
@ -51,6 +60,8 @@ public:
void testGetPiece();
void testGetPieceInUsedPieces();
void testGetPieceCompletedPiece();
void testGetMissingPiece_fileEntry();
void testCancelPiece();
};
@ -153,3 +164,102 @@ void DefaultPieceStorageTest::testGetPieceCompletedPiece() {
CPPUNIT_ASSERT_EQUAL((int32_t)128, pieceGot->getLength());
CPPUNIT_ASSERT_EQUAL(true, pieceGot->pieceComplete());
}
void DefaultPieceStorageTest::testGetMissingPiece_fileEntry()
{
// - 32KB
// +--------+
// |11111222|
int32_t pieceLength = 256*1024;
int64_t totalLength = 1*pieceLength;
int32_t blockLength = 16*1024;
Strings uris1;
uris1.push_back("http://localhost/src/file1.txt");
Strings uris2;
uris2.push_back("http://localhost/src/file2.txt");
FileEntryHandle file1 = new FileEntry("src/file1.txt", 150*1024, 0/*, uris1*/);
FileEntryHandle file2 = new FileEntry("src/file2.txt", 106*1024, file1->getLength() /*, uris2*/);
MockBtContextHandle dctx = new MockBtContext();
dctx->setPieceLength(pieceLength);
dctx->setTotalLength(totalLength);
dctx->addFileEntry(file1);
dctx->addFileEntry(file2);
DefaultPieceStorageHandle ps = new DefaultPieceStorage(dctx, option);
PieceHandle p = ps->getMissingPiece(file1);
CPPUNIT_ASSERT(!p.isNull());
CPPUNIT_ASSERT_EQUAL((int32_t)0, p->getIndex());
for(int32_t i = 0; i < 9; ++i) {
p->completeBlock(i);
}
PieceHandle subPiece = new Piece(9, blockLength, 1);
p->addSubPiece(subPiece);
ps->cancelPiece(p);
// Piece index = 0 should be retrieved again because the part of file1 is
// not complete
PieceHandle p2 = ps->getMissingPiece(file1);
CPPUNIT_ASSERT(!p2.isNull());
CPPUNIT_ASSERT_EQUAL((int32_t)0, p2->getIndex());
// Make the part of file1 complete
for(int32_t i = 0; i < 6*1024; ++i) {
p2->getSubPiece(9)->completeBlock(i);
}
ps->cancelPiece(p2);
// Null Piece should be retrieved
CPPUNIT_ASSERT(ps->getMissingPiece(file1).isNull());
// Next, I retrive the piece giving file2
PieceHandle p3 = ps->getMissingPiece(file2);
CPPUNIT_ASSERT(!p3.isNull());
CPPUNIT_ASSERT_EQUAL((int32_t)0, p3->getIndex());
// Make the part of file2 complete
for(int32_t i = 6*1024; i < 16*1024; ++i) {
p3->getSubPiece(9)->completeBlock(i);
}
for(int32_t i = 10; i < 16; ++i) {
p3->completeBlock(i);
}
ps->cancelPiece(p3);
// Null Piece should be retrieved
CPPUNIT_ASSERT(ps->getMissingPiece(file2).isNull());
}
void DefaultPieceStorageTest::testCancelPiece()
{
int32_t pieceLength = 256*1024;
int64_t totalLength = 32*pieceLength; // <-- make the number of piece greater than END_GAME_PIECE_NUM
int32_t blockLength = 16*1024;
Strings uris1;
uris1.push_back("http://localhost/src/file1.txt");
FileEntryHandle file1 = new FileEntry("src/file1.txt", totalLength, 0 /*, uris1*/);
MockBtContextHandle dctx = new MockBtContext();
dctx->setPieceLength(pieceLength);
dctx->setTotalLength(totalLength);
dctx->addFileEntry(file1);
DefaultPieceStorageHandle ps = new DefaultPieceStorage(dctx, option);
PieceHandle p = ps->getMissingPiece(file1);
PieceHandle subPiece = new Piece(0, blockLength, 1);
subPiece->completeBlock(0);
p->addSubPiece(subPiece);
ps->cancelPiece(p);
// See the sub piece is also hibernated...
PieceHandle p2 = ps->getMissingPiece(file1);
CPPUNIT_ASSERT(!p2->getSubPiece(0).isNull());
}

View File

@ -1,6 +1,8 @@
TESTS = aria2c
check_PROGRAMS = $(TESTS)
aria2c_SOURCES = AllTest.cc\
PieceTest.cc\
DefaultPieceStorageTest.cc\
SegmentTest.cc\
GrowSegmentTest.cc\
SingleFileAllocationIteratorTest.cc\
@ -67,7 +69,6 @@ aria2c_SOURCES += BtAllowedFastMessageTest.cc\
DefaultBtContextTest.cc\
DefaultBtMessageDispatcherTest.cc\
DefaultBtRequestFactoryTest.cc\
DefaultPieceStorageTest.cc\
MockBtMessage.h\
MockBtMessageDispatcher.h\
MockBtMessageFactory.h\

View File

@ -61,7 +61,6 @@ check_PROGRAMS = $(am__EXEEXT_1)
@ENABLE_BITTORRENT_TRUE@ DefaultBtContextTest.cc\
@ENABLE_BITTORRENT_TRUE@ DefaultBtMessageDispatcherTest.cc\
@ENABLE_BITTORRENT_TRUE@ DefaultBtRequestFactoryTest.cc\
@ENABLE_BITTORRENT_TRUE@ DefaultPieceStorageTest.cc\
@ENABLE_BITTORRENT_TRUE@ MockBtMessage.h\
@ENABLE_BITTORRENT_TRUE@ MockBtMessageDispatcher.h\
@ENABLE_BITTORRENT_TRUE@ MockBtMessageFactory.h\
@ -112,7 +111,8 @@ mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
CONFIG_HEADER = $(top_builddir)/config.h
CONFIG_CLEAN_FILES =
am__EXEEXT_1 = aria2c$(EXEEXT)
am__aria2c_SOURCES_DIST = AllTest.cc SegmentTest.cc GrowSegmentTest.cc \
am__aria2c_SOURCES_DIST = AllTest.cc PieceTest.cc \
DefaultPieceStorageTest.cc SegmentTest.cc GrowSegmentTest.cc \
SingleFileAllocationIteratorTest.cc \
DefaultBtProgressInfoFileTest.cc \
SingleFileDownloadContextTest.cc RequestGroupTest.cc \
@ -140,17 +140,17 @@ am__aria2c_SOURCES_DIST = AllTest.cc SegmentTest.cc GrowSegmentTest.cc \
BtRequestMessageTest.cc BtSuggestPieceMessageTest.cc \
BtUnchokeMessageTest.cc DefaultBtAnnounceTest.cc \
DefaultBtContextTest.cc DefaultBtMessageDispatcherTest.cc \
DefaultBtRequestFactoryTest.cc DefaultPieceStorageTest.cc \
MockBtMessage.h MockBtMessageDispatcher.h \
MockBtMessageFactory.h ShaVisitorTest.cc \
DefaultPeerListProcessorTest.cc AnnounceListTest.cc \
DefaultPeerStorageTest.cc MockPeerStorage.h DataTest.cc \
DictionaryTest.cc ListTest.cc MetaFileUtilTest.cc \
MultiDiskAdaptorTest.cc ByteArrayDiskWriterTest.cc PeerTest.cc \
PeerMessageUtilTest.cc ShareRatioSeedCriteriaTest.cc \
BtRegistryTest.cc MultiFileAllocationIteratorTest.cc \
BtDependencyTest.cc BtPostDownloadHandlerTest.cc \
TimeSeedCriteriaTest.cc MetalinkerTest.cc MetalinkEntryTest.cc \
DefaultBtRequestFactoryTest.cc MockBtMessage.h \
MockBtMessageDispatcher.h MockBtMessageFactory.h \
ShaVisitorTest.cc DefaultPeerListProcessorTest.cc \
AnnounceListTest.cc DefaultPeerStorageTest.cc \
MockPeerStorage.h DataTest.cc DictionaryTest.cc ListTest.cc \
MetaFileUtilTest.cc MultiDiskAdaptorTest.cc \
ByteArrayDiskWriterTest.cc PeerTest.cc PeerMessageUtilTest.cc \
ShareRatioSeedCriteriaTest.cc BtRegistryTest.cc \
MultiFileAllocationIteratorTest.cc BtDependencyTest.cc \
BtPostDownloadHandlerTest.cc TimeSeedCriteriaTest.cc \
MetalinkerTest.cc MetalinkEntryTest.cc \
Xml2MetalinkProcessorTest.cc Metalink2RequestGroupTest.cc \
MetalinkPostDownloadHandlerTest.cc
@ENABLE_MESSAGE_DIGEST_TRUE@am__objects_1 = \
@ -178,7 +178,6 @@ am__aria2c_SOURCES_DIST = AllTest.cc SegmentTest.cc GrowSegmentTest.cc \
@ENABLE_BITTORRENT_TRUE@ DefaultBtContextTest.$(OBJEXT) \
@ENABLE_BITTORRENT_TRUE@ DefaultBtMessageDispatcherTest.$(OBJEXT) \
@ENABLE_BITTORRENT_TRUE@ DefaultBtRequestFactoryTest.$(OBJEXT) \
@ENABLE_BITTORRENT_TRUE@ DefaultPieceStorageTest.$(OBJEXT) \
@ENABLE_BITTORRENT_TRUE@ ShaVisitorTest.$(OBJEXT) \
@ENABLE_BITTORRENT_TRUE@ DefaultPeerListProcessorTest.$(OBJEXT) \
@ENABLE_BITTORRENT_TRUE@ AnnounceListTest.$(OBJEXT) \
@ -202,7 +201,8 @@ am__aria2c_SOURCES_DIST = AllTest.cc SegmentTest.cc GrowSegmentTest.cc \
@ENABLE_METALINK_TRUE@ Xml2MetalinkProcessorTest.$(OBJEXT) \
@ENABLE_METALINK_TRUE@ Metalink2RequestGroupTest.$(OBJEXT) \
@ENABLE_METALINK_TRUE@ MetalinkPostDownloadHandlerTest.$(OBJEXT)
am_aria2c_OBJECTS = AllTest.$(OBJEXT) SegmentTest.$(OBJEXT) \
am_aria2c_OBJECTS = AllTest.$(OBJEXT) PieceTest.$(OBJEXT) \
DefaultPieceStorageTest.$(OBJEXT) SegmentTest.$(OBJEXT) \
GrowSegmentTest.$(OBJEXT) \
SingleFileAllocationIteratorTest.$(OBJEXT) \
DefaultBtProgressInfoFileTest.$(OBJEXT) \
@ -412,7 +412,8 @@ target_cpu = @target_cpu@
target_os = @target_os@
target_vendor = @target_vendor@
TESTS = aria2c
aria2c_SOURCES = AllTest.cc SegmentTest.cc GrowSegmentTest.cc \
aria2c_SOURCES = AllTest.cc PieceTest.cc DefaultPieceStorageTest.cc \
SegmentTest.cc GrowSegmentTest.cc \
SingleFileAllocationIteratorTest.cc \
DefaultBtProgressInfoFileTest.cc \
SingleFileDownloadContextTest.cc RequestGroupTest.cc \
@ -561,6 +562,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ParameterizedStringParserTest.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/PeerMessageUtilTest.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/PeerTest.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/PieceTest.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/RequestFactoryTest.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/RequestGroupManTest.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/RequestGroupTest.Po@am__quote@

106
test/PieceTest.cc Normal file
View File

@ -0,0 +1,106 @@
#include "Piece.h"
#include <string>
#include <cppunit/extensions/HelperMacros.h>
using namespace std;
class PieceTest:public CppUnit::TestFixture {
CPPUNIT_TEST_SUITE(PieceTest);
CPPUNIT_TEST(testCompleteBlock);
CPPUNIT_TEST(testIsRangeComplete);
CPPUNIT_TEST(testIsRangeComplete_subPiece);
CPPUNIT_TEST(testGetCompletedLength);
CPPUNIT_TEST_SUITE_END();
private:
public:
void setUp() {}
void testCompleteBlock();
void testIsRangeComplete();
void testIsRangeComplete_subPiece();
void testGetCompletedLength();
};
CPPUNIT_TEST_SUITE_REGISTRATION( PieceTest );
void PieceTest::testCompleteBlock()
{
int32_t blockLength = 32*1024;
Piece p(0, blockLength*10, blockLength);
// 5 is a block index inside the Piece p.
PieceHandle subPiece = new Piece(5, blockLength, 1);
p.addSubPiece(subPiece);
CPPUNIT_ASSERT(!p.getSubPiece(5).isNull());
// When block is complete, then its associated sub piece must be deleted.
p.completeBlock(5);
CPPUNIT_ASSERT(p.getSubPiece(5).isNull());
}
void PieceTest::testIsRangeComplete()
{
int32_t blockLength = 16*1024;
Piece p(0, blockLength*10, blockLength);
CPPUNIT_ASSERT(!p.isRangeComplete(8*1024, 16*1024));
p.completeBlock(0);
CPPUNIT_ASSERT(!p.isRangeComplete(8*1024, 16*1024));
CPPUNIT_ASSERT(p.isRangeComplete(8*1024, 8*1024));
p.completeBlock(1);
CPPUNIT_ASSERT(p.isRangeComplete(8*1024, 16*1024));
}
void PieceTest::testIsRangeComplete_subPiece()
{
int32_t blockLength = 16*1024;
Piece p(0, blockLength*10, blockLength);
CPPUNIT_ASSERT(!p.isRangeComplete(8*1024, 32*1024));
PieceHandle startSubPiece = new Piece(0, blockLength, 1);
p.addSubPiece(startSubPiece);
PieceHandle endSubPiece = new Piece(2, blockLength, 1);
p.addSubPiece(endSubPiece);
p.completeBlock(1);
CPPUNIT_ASSERT(!p.isRangeComplete(8*1024, 32*1024));
for(int32_t i = 8*1024; i < blockLength; ++i) {
startSubPiece->completeBlock(i);
}
CPPUNIT_ASSERT(!p.isRangeComplete(8*1024, 32*1024));
for(int32_t i = 0; i < 8*1024; ++i) {
endSubPiece->completeBlock(i);
}
CPPUNIT_ASSERT(p.isRangeComplete(8*1024, 32*1024));
}
void PieceTest::testGetCompletedLength()
{
int32_t blockLength = 16*1024;
Piece p(0, blockLength*10, blockLength);
PieceHandle subPiece = new Piece(0, blockLength, 1);
for(int32_t i = 0; i < blockLength-1; ++i) {
subPiece->completeBlock(i);
}
p.addSubPiece(subPiece);
p.completeBlock(1);
p.completeBlock(2);
p.completeBlock(9);
CPPUNIT_ASSERT_EQUAL(blockLength*3+blockLength-1, p.getCompletedLength());
}