diff --git a/ChangeLog b/ChangeLog index 5996885f..d5cb15fc 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,69 @@ +2007-11-20 Tatsuhiro Tsujikawa + + Preallocate non-requested file which is adjacent forward to requested + file('requested' files means the files given in --select-file option) + if they share a same piece. + This fixes long pause in the file system which doesn't support sparse + files like FAT32 while downloading. + * src/MultiFileAllocationIterator.{h, cc} + * test/MultiFileAllocationIteratorTest.cc + * src/FileEntry.{h, cc} + + Removed unused _option. + * src/MultiDiskAdaptor.h + * test/MultiDiskAdaptorTest.cc + * src/DefaultPieceStorage.cc + + Set the default value of --seed-ratio to 1.0. + If 0.0 is given, then seeding continues regardless of share ratio. + * src/version_usage.cc + * src/option_processing.cc + * src/BtSetup.cc + * doc/aria2c.1.txt + * doc/aria2c.1 + + Fixed: Selective download is not working in BitTorrent + * src/RequestGroup.cc + + Introduced Sequence class. Use this instead of Util::unfoldRange() + * src/PieceStorage.h + * test/MockPieceStorage.h + * src/UnknownLengthPieceStorage.h + * src/DefaultPieceStorage.{h, cc} + * src/Metalink2RequestGroup.cc + * src/RequestGroup.cc + * src/Sequence.h + * test/SequenceTest.cc + * src/IntSequence.h + * src/message.h + * src/Util.{h, cc} + * test/UtilTest.cc + + Added new function 'parse' to catch exception thrown by subclass's + parseArg + * src/OptionHandler.h + * src/OptionParser.cc + * src/NameMatchOptionHandler.h + * src/OptionHandlerImpl.h + * test/OptionHandlerTest.cc + + Added IntegerRangeOptionHandler. Used for --listen-port and + --select-file. Now --listen-port accepts range of port. + * src/OptionHandlerFactory.cc + * src/version_usage.cc + * src/OptionHandlerImpl.h + * src/option_processing.cc + * src/BtSetup.cc + * src/PeerListenCommand.{h, cc} + * doc/aria2c.1.txt + * doc/aria2c.1 + + Implemented operator< for Exception class to provide easy way to print + exception stack trace. + * src/Exception.{h, cc} + * src/main.cc + * src/option_processing.cc + 2007-11-18 Tatsuhiro Tsujikawa * src/version_usage.cc diff --git a/TODO b/TODO index 769ee24e..74a9a18e 100644 --- a/TODO +++ b/TODO @@ -4,7 +4,6 @@ * Add SSL client cert support * Better HTTP status handling * Add the feature which adds or removes URLs on-the-fly. -* Add port range command-line option * Add max peers command-line option * Refacturing HttpConnection and FtpConnection * Query resource by location @@ -57,3 +56,5 @@ -- remaining issues to be implemented for 0.12.0 release * Update translation +* replace strtol with Util::parseInt +* precision of share ratio diff --git a/doc/aria2c.1 b/doc/aria2c.1 index 2dba73ce..6d98b748 100644 --- a/doc/aria2c.1 +++ b/doc/aria2c.1 @@ -1,11 +1,11 @@ .\" Title: aria2c .\" Author: .\" Generator: DocBook XSL Stylesheets v1.73.1 -.\" Date: 11/18/2007 +.\" Date: 11/22/2007 .\" Manual: .\" Source: .\" -.TH "ARIA2C" "1" "11/18/2007" "" "" +.TH "ARIA2C" "1" "11/22/2007" "" "" .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) @@ -319,6 +319,15 @@ to specify a range: "1\-5"\. and \fI\-\fR can be used together\. When used with the \-M option, index may vary depending on the query(see \-\-metalink\-* options)\. +.sp +.RS 4 +.nf +Note: In multi file torrent, it seems that adjacent files specified +by this option are downloaded\. This is by design, not a bug\. +A single piece may include several files or part of files, +and aria2 writes the piece to the appropriate files\. +.fi +.RE .RE .PP \-T, \-\-torrent\-file=TORRENT_FILE @@ -335,11 +344,18 @@ Set to false to prevent aria2 from entering BitTorrent mode even if the filename .RS 4 Directly read from and write to each file mentioned in \.torrent file\. Default: \fItrue\fR -.RE -.PP -\-\-listen\-port=PORT +.sp .RS 4 -Set TCP port number for BitTorrent downloads\. Default: 6881\-6999 +.nf +\-\-listen\-port=PORT\.\.\. + Set TCP port number for BitTorrent downloads\. + Multiple values can be specified by using \',\', + for example: "6881,6885"\. + You can also use \'\-\' to specify a range: "6881\-6999"\. + \',\' and \'\-\' can be used together\. + Default: 6881\-6999 +.fi +.RE .RE .PP \-\-max\-upload\-limit=SPEED @@ -360,7 +376,7 @@ Specify seeding time in minutes\. Also see the \-\-seed\-ratio option\. .PP \-\-seed\-ratio=RATIO .RS 4 -Specify share ratio\. Seed completed torrents until share ratio reaches RATIO\. 1\.0 is encouraged\. If \-\-seed\-time option is specified along with this option, seeding ends when at least one of the conditions is satisfied\. +Specify share ratio\. Seed completed torrents until share ratio reaches RATIO\. 1\.0 is encouraged\. Specify 0\.0 if you intend to do seeding regardless of share ratio\. If \-\-seed\-time option is specified along with this option, seeding ends when at least one of the conditions is satisfied\. Default: 1\.0 .RE .PP \-\-peer\-id\-prefix=PEERI_ID_PREFIX diff --git a/doc/aria2c.1.txt b/doc/aria2c.1.txt index 81431ec3..5a7ca2b9 100644 --- a/doc/aria2c.1.txt +++ b/doc/aria2c.1.txt @@ -229,14 +229,19 @@ http://host/image[000-100:2].img and exit. --select-file=INDEX...:: - Set file to download by specifing its index. - You can find the file index using the - --show-files option. Multiple indexes can be - specified by using ',', for example: "3,6". - You can also use '-' to specify a range: "1-5". - ',' and '-' can be used together. - When used with the -M option, index may vary - depending on the query(see --metalink-* options). + Set file to download by specifing its index. + You can find the file index using the + --show-files option. Multiple indexes can be + specified by using ',', for example: "3,6". + You can also use '-' to specify a range: "1-5". + ',' and '-' can be used together. + When used with the -M option, index may vary + depending on the query(see --metalink-* options). + + Note: In multi file torrent, it seems that adjacent files specified + by this option are downloaded. This is by design, not a bug. + A single piece may include several files or part of files, + and aria2 writes the piece to the appropriate files. -T, --torrent-file=TORRENT_FILE:: The path to the .torrent file. @@ -252,9 +257,13 @@ http://host/image[000-100:2].img mentioned in .torrent file. Default: 'true' - --listen-port=PORT:: - Set TCP port number for BitTorrent downloads. - Default: 6881-6999 + --listen-port=PORT... + Set TCP port number for BitTorrent downloads. + Multiple values can be specified by using ',', + for example: "6881,6885". + You can also use '-' to specify a range: "6881-6999". + ',' and '-' can be used together. + Default: 6881-6999 --max-upload-limit=SPEED:: Set max upload speed in bytes per sec. @@ -267,11 +276,14 @@ http://host/image[000-100:2].img --seed-ratio option. --seed-ratio=RATIO:: - Specify share ratio. Seed completed torrents - until share ratio reaches RATIO. 1.0 is - encouraged. If --seed-time option is specified - along with this option, seeding ends when at - least one of the conditions is satisfied. + Specify share ratio. Seed completed torrents + until share ratio reaches RATIO. 1.0 is + encouraged. Specify 0.0 if you intend to do + seeding regardless of share ratio. + If --seed-time option is specified along with + this option, seeding ends when at least one of + the conditions is satisfied. + Default: 1.0 --peer-id-prefix=PEERI_ID_PREFIX:: Specify the prefix of peer ID. The peer ID in diff --git a/src/BtSetup.cc b/src/BtSetup.cc index 6302c8b7..03026c40 100644 --- a/src/BtSetup.cc +++ b/src/BtSetup.cc @@ -53,6 +53,7 @@ #include "LogFactory.h" #include "Logger.h" #include "Util.h" +#include "IntSequence.h" BtSetup::BtSetup():_logger(LogFactory::getInstance()) {} @@ -85,9 +86,12 @@ Commands BtSetup::setup(RequestGroup* requestGroup, if(option->defined(PREF_SEED_TIME)) { unionCri->addSeedCriteria(new TimeSeedCriteria(option->getAsInt(PREF_SEED_TIME)*60)); } - if(option->defined(PREF_SEED_RATIO)) { - unionCri->addSeedCriteria(new ShareRatioSeedCriteria(option->getAsDouble(PREF_SEED_RATIO), btContext)); - } + { + double ratio = option->getAsDouble(PREF_SEED_RATIO); + if(ratio > 0.0) { + unionCri->addSeedCriteria(new ShareRatioSeedCriteria(option->getAsDouble(PREF_SEED_RATIO), btContext)); + } + } if(unionCri->getSeedCriterion().size() > 0) { commands.push_back(new SeedCheckCommand(CUIDCounterSingletonHolder::instance()->newID(), requestGroup, @@ -98,13 +102,8 @@ Commands BtSetup::setup(RequestGroup* requestGroup, if(PeerListenCommand::getNumInstance() == 0) { PeerListenCommand* listenCommand = PeerListenCommand::getInstance(e); - int32_t port; - int32_t listenPort = option->getAsInt(PREF_LISTEN_PORT); - if(listenPort == -1) { - port = listenCommand->bindPort(6881, 6999); - } else { - port = listenCommand->bindPort(listenPort, listenPort); - } + IntSequence seq = Util::parseIntRange(option->get(PREF_LISTEN_PORT)); + int32_t port = listenCommand->bindPort(seq); if(port == -1) { _logger->error(_("Errors occurred while binding port.\n")); delete listenCommand; diff --git a/src/DefaultDiskWriter.cc b/src/DefaultDiskWriter.cc index 4a782205..f2bf72f9 100644 --- a/src/DefaultDiskWriter.cc +++ b/src/DefaultDiskWriter.cc @@ -33,11 +33,6 @@ */ /* copyright --> */ #include "DefaultDiskWriter.h" -#include "message.h" -#include "prefs.h" -#include "Util.h" -#include -#include DefaultDiskWriter::DefaultDiskWriter():AbstractDiskWriter() {} diff --git a/src/DefaultPieceStorage.cc b/src/DefaultPieceStorage.cc index 06577a15..0189d47e 100644 --- a/src/DefaultPieceStorage.cc +++ b/src/DefaultPieceStorage.cc @@ -391,8 +391,11 @@ void DefaultPieceStorage::setFileFilter(const Strings& filePaths) bitfieldMan->enableFilter(); } -void DefaultPieceStorage::setFileFilter(const Integers& fileIndexes) +void DefaultPieceStorage::setFileFilter(IntSequence seq) { + Integers fileIndexes = seq.flush(); + sort(fileIndexes.begin(), fileIndexes.end()); + fileIndexes.erase(unique(fileIndexes.begin(), fileIndexes.end()), fileIndexes.end()); Strings filePaths; const FileEntries& entries = diskAdaptor->getFileEntries(); for(int32_t i = 0; i < (int32_t)entries.size(); i++) { @@ -441,7 +444,6 @@ void DefaultPieceStorage::initStorage() MultiDiskAdaptorHandle multiDiskAdaptor = new MultiDiskAdaptor(); multiDiskAdaptor->setPieceLength(downloadContext->getPieceLength()); multiDiskAdaptor->setTopDir(downloadContext->getName()); - multiDiskAdaptor->setOption(option); this->diskAdaptor = multiDiskAdaptor; } else { logger->debug("Instantiating CopyDiskAdaptor"); @@ -456,11 +458,7 @@ void DefaultPieceStorage::initStorage() this->diskAdaptor = copyDiskAdaptor; } } - string storeDir = downloadContext->getDir();//option->get(PREF_DIR); -// if(storeDir == "") { -// storeDir = "."; -// } - diskAdaptor->setStoreDir(storeDir); + diskAdaptor->setStoreDir(downloadContext->getDir()); diskAdaptor->setFileEntries(downloadContext->getFileEntries()); } diff --git a/src/DefaultPieceStorage.h b/src/DefaultPieceStorage.h index e1ec4713..0c26bd5c 100644 --- a/src/DefaultPieceStorage.h +++ b/src/DefaultPieceStorage.h @@ -128,7 +128,7 @@ public: virtual void setFileFilter(const Strings& filePaths); - virtual void setFileFilter(const Integers& fileIndexes); + virtual void setFileFilter(IntSequence seq); virtual void clearFileFilter(); diff --git a/src/DownloadEngine.cc b/src/DownloadEngine.cc index d470d3ad..c2e2e860 100644 --- a/src/DownloadEngine.cc +++ b/src/DownloadEngine.cc @@ -47,9 +47,7 @@ #include #include #include -#include #include -#include volatile sig_atomic_t globalHaltRequested; diff --git a/src/Exception.cc b/src/Exception.cc new file mode 100644 index 00000000..45430495 --- /dev/null +++ b/src/Exception.cc @@ -0,0 +1,44 @@ +/* */ +#include "Exception.h" + +ostream& operator<<(ostream& o, const Exception& e) +{ + o << e.getMsg() << "\n"; + for(Exception* cause = e.getCause(); cause; cause = cause->getCause()) { + o << "Cause: " << cause->getMsg() << "\n"; + } + return o; +} diff --git a/src/Exception.h b/src/Exception.h index 2522051a..252f6d7f 100644 --- a/src/Exception.h +++ b/src/Exception.h @@ -63,6 +63,8 @@ public: const string& getMsg() const { return msg; } Exception* getCause() const { return cause; } + + friend ostream& operator<<(ostream& o, const Exception& e); }; #endif // _D_EXCEPTION_H_ diff --git a/src/FileEntry.cc b/src/FileEntry.cc index 80b6cedc..c5b1108f 100644 --- a/src/FileEntry.cc +++ b/src/FileEntry.cc @@ -62,3 +62,8 @@ FileEntry& FileEntry::operator=(const FileEntry& entry) } return *this; } + +bool FileEntry::operator<(const FileEntry& fileEntry) const +{ + return offset < fileEntry.offset; +} diff --git a/src/FileEntry.h b/src/FileEntry.h index d249a9ee..9c1d36dd 100644 --- a/src/FileEntry.h +++ b/src/FileEntry.h @@ -91,6 +91,8 @@ public: { return _uris; } + + bool operator<(const FileEntry& fileEntry) const; }; typedef SharedHandle FileEntryHandle; diff --git a/src/IntSequence.h b/src/IntSequence.h new file mode 100644 index 00000000..c285b60d --- /dev/null +++ b/src/IntSequence.h @@ -0,0 +1,42 @@ +/* */ +#ifndef _D_INT_SEQUENCE_H_ +#define _D_INT_SEQUENCE_H_ + +#include "Sequence.h" + +typedef Sequence IntSequence; + +#endif // _D_INT_SEQUENCE_H_ diff --git a/src/Makefile.am b/src/Makefile.am index 215db699..18e6a9cb 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -32,7 +32,7 @@ SRCS = Socket.h\ Request.cc Request.h\ common.h\ message.h\ - Exception.h\ + Exception.cc Exception.h\ FatalException.h\ RecoverableException.h\ DlAbortEx.h\ diff --git a/src/Makefile.in b/src/Makefile.in index ef79f561..141e05b1 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -202,29 +202,29 @@ am__libaria2c_a_SOURCES_DIST = Socket.h SocketCore.cc SocketCore.h \ DownloadEngine.cc DownloadEngine.h Segment.h GrowSegment.cc \ GrowSegment.h PiecedSegment.cc PiecedSegment.h SegmentMan.cc \ SegmentMan.h Util.cc Util.h Request.cc Request.h common.h \ - message.h Exception.h FatalException.h RecoverableException.h \ - DlAbortEx.h DlRetryEx.h Logger.h SimpleLogger.cc \ - SimpleLogger.h TransferEncoding.h ChunkedEncoding.cc \ - ChunkedEncoding.h DiskWriter.h AbstractDiskWriter.cc \ - AbstractDiskWriter.h DefaultDiskWriter.cc DefaultDiskWriter.h \ - File.cc File.h Option.cc Option.h Base64.cc Base64.h \ - CookieBox.cc CookieBox.h LogFactory.cc LogFactory.h \ - NullLogger.h TimeA2.cc TimeA2.h SharedHandle.h \ - HandleRegistry.h FeatureConfig.cc FeatureConfig.h \ - DownloadEngineFactory.cc DownloadEngineFactory.h RequestInfo.h \ - SpeedCalc.cc SpeedCalc.h PeerStat.h BitfieldMan.cc \ - BitfieldMan.h BitfieldManFactory.cc BitfieldManFactory.h \ - Randomizer.h SimpleRandomizer.cc SimpleRandomizer.h \ - FileAllocator.h HttpResponse.cc HttpResponse.h HttpRequest.cc \ - HttpRequest.h Range.h AbstractProxyRequestCommand.cc \ - AbstractProxyRequestCommand.h AbstractProxyResponseCommand.cc \ - AbstractProxyResponseCommand.h Netrc.cc Netrc.h AuthConfig.cc \ - AuthConfig.h AuthResolver.h AbstractAuthResolver.h \ - DefaultAuthResolver.cc DefaultAuthResolver.h \ - NetrcAuthResolver.cc NetrcAuthResolver.h AuthConfigFactory.cc \ - AuthConfigFactory.h OptionParser.cc OptionParser.h \ - OptionHandlerFactory.cc OptionHandlerFactory.h NameResolver.cc \ - NameResolver.h RequestGroup.cc RequestGroup.h \ + message.h Exception.cc Exception.h FatalException.h \ + RecoverableException.h DlAbortEx.h DlRetryEx.h Logger.h \ + SimpleLogger.cc SimpleLogger.h TransferEncoding.h \ + ChunkedEncoding.cc ChunkedEncoding.h DiskWriter.h \ + AbstractDiskWriter.cc AbstractDiskWriter.h \ + DefaultDiskWriter.cc DefaultDiskWriter.h File.cc File.h \ + Option.cc Option.h Base64.cc Base64.h CookieBox.cc CookieBox.h \ + LogFactory.cc LogFactory.h NullLogger.h TimeA2.cc TimeA2.h \ + SharedHandle.h HandleRegistry.h FeatureConfig.cc \ + FeatureConfig.h DownloadEngineFactory.cc \ + DownloadEngineFactory.h RequestInfo.h SpeedCalc.cc SpeedCalc.h \ + PeerStat.h BitfieldMan.cc BitfieldMan.h BitfieldManFactory.cc \ + BitfieldManFactory.h Randomizer.h SimpleRandomizer.cc \ + SimpleRandomizer.h FileAllocator.h HttpResponse.cc \ + HttpResponse.h HttpRequest.cc HttpRequest.h Range.h \ + AbstractProxyRequestCommand.cc AbstractProxyRequestCommand.h \ + AbstractProxyResponseCommand.cc AbstractProxyResponseCommand.h \ + Netrc.cc Netrc.h AuthConfig.cc AuthConfig.h AuthResolver.h \ + AbstractAuthResolver.h DefaultAuthResolver.cc \ + DefaultAuthResolver.h NetrcAuthResolver.cc NetrcAuthResolver.h \ + AuthConfigFactory.cc AuthConfigFactory.h OptionParser.cc \ + OptionParser.h OptionHandlerFactory.cc OptionHandlerFactory.h \ + NameResolver.cc NameResolver.h RequestGroup.cc RequestGroup.h \ RequestGroupAware.cc RequestGroupAware.h RequestGroupMan.cc \ RequestGroupMan.h FileAllocationMan.cc FileAllocationMan.h \ FileAllocationCommand.cc FileAllocationCommand.h \ @@ -433,7 +433,7 @@ am__objects_12 = SocketCore.$(OBJEXT) Command.$(OBJEXT) \ FtpTunnelResponseCommand.$(OBJEXT) SleepCommand.$(OBJEXT) \ DownloadEngine.$(OBJEXT) GrowSegment.$(OBJEXT) \ PiecedSegment.$(OBJEXT) SegmentMan.$(OBJEXT) Util.$(OBJEXT) \ - Request.$(OBJEXT) SimpleLogger.$(OBJEXT) \ + Request.$(OBJEXT) Exception.$(OBJEXT) SimpleLogger.$(OBJEXT) \ ChunkedEncoding.$(OBJEXT) AbstractDiskWriter.$(OBJEXT) \ DefaultDiskWriter.$(OBJEXT) File.$(OBJEXT) Option.$(OBJEXT) \ Base64.$(OBJEXT) CookieBox.$(OBJEXT) LogFactory.$(OBJEXT) \ @@ -694,29 +694,29 @@ SRCS = Socket.h SocketCore.cc SocketCore.h Command.cc Command.h \ DownloadEngine.cc DownloadEngine.h Segment.h GrowSegment.cc \ GrowSegment.h PiecedSegment.cc PiecedSegment.h SegmentMan.cc \ SegmentMan.h Util.cc Util.h Request.cc Request.h common.h \ - message.h Exception.h FatalException.h RecoverableException.h \ - DlAbortEx.h DlRetryEx.h Logger.h SimpleLogger.cc \ - SimpleLogger.h TransferEncoding.h ChunkedEncoding.cc \ - ChunkedEncoding.h DiskWriter.h AbstractDiskWriter.cc \ - AbstractDiskWriter.h DefaultDiskWriter.cc DefaultDiskWriter.h \ - File.cc File.h Option.cc Option.h Base64.cc Base64.h \ - CookieBox.cc CookieBox.h LogFactory.cc LogFactory.h \ - NullLogger.h TimeA2.cc TimeA2.h SharedHandle.h \ - HandleRegistry.h FeatureConfig.cc FeatureConfig.h \ - DownloadEngineFactory.cc DownloadEngineFactory.h RequestInfo.h \ - SpeedCalc.cc SpeedCalc.h PeerStat.h BitfieldMan.cc \ - BitfieldMan.h BitfieldManFactory.cc BitfieldManFactory.h \ - Randomizer.h SimpleRandomizer.cc SimpleRandomizer.h \ - FileAllocator.h HttpResponse.cc HttpResponse.h HttpRequest.cc \ - HttpRequest.h Range.h AbstractProxyRequestCommand.cc \ - AbstractProxyRequestCommand.h AbstractProxyResponseCommand.cc \ - AbstractProxyResponseCommand.h Netrc.cc Netrc.h AuthConfig.cc \ - AuthConfig.h AuthResolver.h AbstractAuthResolver.h \ - DefaultAuthResolver.cc DefaultAuthResolver.h \ - NetrcAuthResolver.cc NetrcAuthResolver.h AuthConfigFactory.cc \ - AuthConfigFactory.h OptionParser.cc OptionParser.h \ - OptionHandlerFactory.cc OptionHandlerFactory.h NameResolver.cc \ - NameResolver.h RequestGroup.cc RequestGroup.h \ + message.h Exception.cc Exception.h FatalException.h \ + RecoverableException.h DlAbortEx.h DlRetryEx.h Logger.h \ + SimpleLogger.cc SimpleLogger.h TransferEncoding.h \ + ChunkedEncoding.cc ChunkedEncoding.h DiskWriter.h \ + AbstractDiskWriter.cc AbstractDiskWriter.h \ + DefaultDiskWriter.cc DefaultDiskWriter.h File.cc File.h \ + Option.cc Option.h Base64.cc Base64.h CookieBox.cc CookieBox.h \ + LogFactory.cc LogFactory.h NullLogger.h TimeA2.cc TimeA2.h \ + SharedHandle.h HandleRegistry.h FeatureConfig.cc \ + FeatureConfig.h DownloadEngineFactory.cc \ + DownloadEngineFactory.h RequestInfo.h SpeedCalc.cc SpeedCalc.h \ + PeerStat.h BitfieldMan.cc BitfieldMan.h BitfieldManFactory.cc \ + BitfieldManFactory.h Randomizer.h SimpleRandomizer.cc \ + SimpleRandomizer.h FileAllocator.h HttpResponse.cc \ + HttpResponse.h HttpRequest.cc HttpRequest.h Range.h \ + AbstractProxyRequestCommand.cc AbstractProxyRequestCommand.h \ + AbstractProxyResponseCommand.cc AbstractProxyResponseCommand.h \ + Netrc.cc Netrc.h AuthConfig.cc AuthConfig.h AuthResolver.h \ + AbstractAuthResolver.h DefaultAuthResolver.cc \ + DefaultAuthResolver.h NetrcAuthResolver.cc NetrcAuthResolver.h \ + AuthConfigFactory.cc AuthConfigFactory.h OptionParser.cc \ + OptionParser.h OptionHandlerFactory.cc OptionHandlerFactory.h \ + NameResolver.cc NameResolver.h RequestGroup.cc RequestGroup.h \ RequestGroupAware.cc RequestGroupAware.h RequestGroupMan.cc \ RequestGroupMan.h FileAllocationMan.cc FileAllocationMan.h \ FileAllocationCommand.cc FileAllocationCommand.h \ @@ -925,6 +925,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DownloadCommand.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DownloadEngine.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DownloadEngineFactory.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Exception.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FeatureConfig.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/File.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FileAllocationCommand.Po@am__quote@ diff --git a/src/Metalink2RequestGroup.cc b/src/Metalink2RequestGroup.cc index cf9d1c35..3962c3b6 100644 --- a/src/Metalink2RequestGroup.cc +++ b/src/Metalink2RequestGroup.cc @@ -101,9 +101,8 @@ RequestGroups Metalink2RequestGroup::generate(const string& metalinkFile) _logger->notice(EX_NO_RESULT_WITH_YOUR_PREFS); return RequestGroups(); } + Integers selectIndexes = Util::parseIntRange(_option->get(PREF_SELECT_FILE)).flush(); bool useIndex; - Integers selectIndexes; - Util::unfoldRange(_option->get(PREF_SELECT_FILE), selectIndexes); if(selectIndexes.size()) { useIndex = true; } else { diff --git a/src/MultiDiskAdaptor.h b/src/MultiDiskAdaptor.h index a099f192..db9699a9 100644 --- a/src/MultiDiskAdaptor.h +++ b/src/MultiDiskAdaptor.h @@ -36,7 +36,6 @@ #define _D_MULTI_DISK_ADAPTOR_H_ #include "DiskAdaptor.h" -#include "Option.h" #include "DiskWriter.h" #include "File.h" @@ -108,7 +107,6 @@ private: string topDir; int32_t pieceLength; DiskWriterEntries diskWriterEntries; - const Option* option; void resetDiskWriterEntries(); @@ -122,8 +120,7 @@ private: string getTopDirPath() const; public: - MultiDiskAdaptor():pieceLength(0), - option(0) + MultiDiskAdaptor():pieceLength(0) {} virtual ~MultiDiskAdaptor() {} @@ -169,14 +166,6 @@ public: int32_t getPieceLength() const { return pieceLength; } - - void setOption(const Option* option) { - this->option = option; - } - - const Option* getOption() const { - return option; - } }; typedef SharedHandle MultiDiskAdaptorHandle; diff --git a/src/MultiFileAllocationIterator.cc b/src/MultiFileAllocationIterator.cc index fb2f7fe4..7d8cdfcb 100644 --- a/src/MultiFileAllocationIterator.cc +++ b/src/MultiFileAllocationIterator.cc @@ -40,7 +40,7 @@ MultiFileAllocationIterator::MultiFileAllocationIterator(MultiDiskAdaptor* diskAdaptor): _diskAdaptor(diskAdaptor), - _entries(diskAdaptor->getFileEntries()), + _entries(makeFileEntries(diskAdaptor->getFileEntries(), diskAdaptor->getPieceLength())), _currentEntry(0), _offset(0) {} @@ -51,16 +51,14 @@ void MultiFileAllocationIterator::prepareNextEntry() { _currentEntry = 0; _offset = 0; - while(!_entries.empty()) { + if(!_entries.empty()) { FileEntryHandle entry = _entries.front(); _entries.pop_front(); - if(entry->isRequested()) { - _currentEntry = entry; - _offset = File(_diskAdaptor->getStoreDir()+"/"+ - _diskAdaptor->getTopDir()+"/"+ - _currentEntry->getPath()).size(); - break; - } + + _currentEntry = entry; + _offset = File(_diskAdaptor->getStoreDir()+"/"+ + _diskAdaptor->getTopDir()+"/"+ + _currentEntry->getPath()).size(); } } @@ -99,3 +97,41 @@ int64_t MultiFileAllocationIterator::getTotalLength() return _currentEntry->getLength(); } } + +const FileEntries& MultiFileAllocationIterator::getFileEntries() const +{ + return _entries; +} + +FileEntries MultiFileAllocationIterator::makeFileEntries(const FileEntries& srcEntries, int32_t pieceLength) const +{ + if(pieceLength == 0) { + FileEntries entries; + for(FileEntries::const_iterator itr = srcEntries.begin(); itr != srcEntries.end(); ++itr) { + if((*itr)->isRequested()) { + entries.push_back(*itr); + } + } + return entries; + } + FileEntries temp(srcEntries); + temp.push_front(new FileEntry()); + FileEntries entries; + FileEntries::const_iterator done = temp.begin(); + for(FileEntries::const_iterator itr = temp.begin()+1; itr != temp.end(); ++itr) { + if(!(*itr)->isRequested()) { + continue; + } + int64_t pieceStartOffset = ((*itr)->getOffset()/pieceLength)*pieceLength; + for(FileEntries::const_iterator i = itr-1; i != done; --i) { + if(pieceStartOffset < (*i)->getOffset()+(*i)->getLength()) { + entries.push_back(*i); + } else { + break; + } + } + entries.push_back(*itr); + done = itr; + } + return entries; +} diff --git a/src/MultiFileAllocationIterator.h b/src/MultiFileAllocationIterator.h index 6f97723e..11d017bf 100644 --- a/src/MultiFileAllocationIterator.h +++ b/src/MultiFileAllocationIterator.h @@ -49,6 +49,8 @@ private: FileEntries _entries; FileEntryHandle _currentEntry; int64_t _offset; + + FileEntries makeFileEntries(const FileEntries& srcEntries, int32_t pieceLength) const; public: MultiFileAllocationIterator(MultiDiskAdaptor* diskAdaptor); @@ -66,6 +68,8 @@ public: } virtual int64_t getTotalLength(); + + const FileEntries& getFileEntries() const; }; typedef SharedHandle MultiFileAllocationIteratorHandle; diff --git a/src/NameMatchOptionHandler.h b/src/NameMatchOptionHandler.h index bf7724d2..2cdce59e 100644 --- a/src/NameMatchOptionHandler.h +++ b/src/NameMatchOptionHandler.h @@ -36,10 +36,13 @@ #define _D_NAME_MATCH_OPTION_HANDLER_H_ #include "OptionHandler.h" +#include "DlAbortEx.h" class NameMatchOptionHandler : public OptionHandler { protected: string _optName; + + virtual void parseArg(Option* option, const string& arg) = 0; public: NameMatchOptionHandler(const string& optName):_optName(optName) {} @@ -49,6 +52,15 @@ public: { return strcasecmp(_optName.c_str(), optName.c_str()) == 0; } + + virtual void parse(Option* option, const string& arg) + { + try { + parseArg(option, arg); + } catch(Exception* e) { + throw new DlAbortEx(e, "Exception occurred while processing option %s", _optName.c_str()); + } + } }; typedef SharedHandle NameMatchOptionHandlerHandle; diff --git a/src/OptionHandler.h b/src/OptionHandler.h index 4dd4b150..3a26d9f2 100644 --- a/src/OptionHandler.h +++ b/src/OptionHandler.h @@ -43,7 +43,7 @@ public: virtual ~OptionHandler() {} virtual bool canHandle(const string& optName) = 0; - virtual void parseArg(Option* option, const string& arg) = 0; + virtual void parse(Option* option, const string& arg) = 0; }; typedef SharedHandle OptionHandlerHandle; diff --git a/src/OptionHandlerFactory.cc b/src/OptionHandlerFactory.cc index 2c525043..22d93c45 100644 --- a/src/OptionHandlerFactory.cc +++ b/src/OptionHandlerFactory.cc @@ -55,11 +55,11 @@ OptionHandlers OptionHandlerFactory::createOptionHandlers() handlers.push_back(new UnitNumberOptionHandler(PREF_MIN_SEGMENT_SIZE, 1024)); handlers.push_back(new ParameterOptionHandler(PREF_HTTP_PROXY_METHOD, V_GET, V_TUNNEL)); - handlers.push_back(new NumberOptionHandler(PREF_LISTEN_PORT, 1024, UINT16_MAX)); + handlers.push_back(new IntegerRangeOptionHandler(PREF_LISTEN_PORT, 1024, UINT16_MAX)); handlers.push_back(new BooleanOptionHandler(PREF_FOLLOW_TORRENT)); handlers.push_back(new BooleanOptionHandler(PREF_NO_PREALLOCATION)); handlers.push_back(new BooleanOptionHandler(PREF_DIRECT_FILE_MAPPING)); - handlers.push_back(new DefaultOptionHandler(PREF_SELECT_FILE)); + handlers.push_back(new IntegerRangeOptionHandler(PREF_SELECT_FILE, 1, INT32_MAX)); handlers.push_back(new NumberOptionHandler(PREF_SEED_TIME, 0)); handlers.push_back(new FloatNumberOptionHandler(PREF_SEED_RATIO, 0.0)); handlers.push_back(new UnitNumberOptionHandler(PREF_MAX_UPLOAD_LIMIT, 0)); diff --git a/src/OptionHandlerImpl.h b/src/OptionHandlerImpl.h index 71b2cc55..4f60a78e 100644 --- a/src/OptionHandlerImpl.h +++ b/src/OptionHandlerImpl.h @@ -38,6 +38,7 @@ #include "OptionHandler.h" #include "NameMatchOptionHandler.h" #include "Util.h" +#include "DlAbortEx.h" #include "FatalException.h" #include "prefs.h" @@ -47,7 +48,7 @@ public: virtual bool canHandle(const string& optName) { return true; } - virtual void parseArg(Option* option, const string& arg) {} + virtual void parse(Option* option, const string& arg) {} }; class BooleanOptionHandler : public NameMatchOptionHandler { @@ -68,6 +69,29 @@ public: } }; +class IntegerRangeOptionHandler : public NameMatchOptionHandler { +private: + int32_t _min; + int32_t _max; +public: + IntegerRangeOptionHandler(const string& optName, int32_t min, int32_t max):NameMatchOptionHandler(optName), _min(min), _max(max) {} + + virtual ~IntegerRangeOptionHandler() {} + + virtual void parseArg(Option* option, const string& optarg) + { + IntSequence seq = Util::parseIntRange(optarg); + while(seq.hasNext()) { + int32_t v = seq.next(); + if(v < _min || _max < v) { + string msg = _optName+" "+_("must be between %s and %s."); + throw new DlAbortEx(msg.c_str(), Util::llitos(_min).c_str(), Util::llitos(_max).c_str()); + } + option->put(_optName, optarg); + } + } +}; + class NumberOptionHandler : public NameMatchOptionHandler { private: int64_t _min; @@ -79,7 +103,7 @@ public: virtual void parseArg(Option* option, const string& optarg) { - int64_t num = strtoll(optarg.c_str(), 0, 10); + int64_t num = Util::parseLLInt(optarg); parseArg(option, num); } @@ -217,7 +241,7 @@ public: virtual void parseArg(Option* option, const string& optarg) { pair proxy = Util::split(optarg, ":"); - int32_t port = strtol(proxy.second.c_str(), 0, 10); + int32_t port = Util::parseInt(proxy.second); if(proxy.first.empty() || proxy.second.empty() || port <= 0 || 65535 < port) { throw new FatalException(_("unrecognized proxy format")); diff --git a/src/OptionParser.cc b/src/OptionParser.cc index 70788650..95629c44 100644 --- a/src/OptionParser.cc +++ b/src/OptionParser.cc @@ -47,7 +47,7 @@ void OptionParser::parse(Option* option, istream& is) } pair nv = Util::split(line, "="); OptionHandlerHandle handler = getOptionHandlerByName(nv.first); - handler->parseArg(option, nv.second); + handler->parse(option, nv.second); } } diff --git a/src/PeerListenCommand.cc b/src/PeerListenCommand.cc index 023b81f8..b27fd759 100644 --- a/src/PeerListenCommand.cc +++ b/src/PeerListenCommand.cc @@ -58,13 +58,10 @@ PeerListenCommand::~PeerListenCommand() --__numInstance; } -int32_t PeerListenCommand::bindPort(int32_t portRangeStart, - int32_t portRangeEnd) +int32_t PeerListenCommand::bindPort(IntSequence& seq) { - if(portRangeStart > portRangeEnd) { - return -1; - } - for(int32_t port = portRangeStart; port <= portRangeEnd; port++) { + while(seq.hasNext()) { + int32_t port = seq.next(); try { socket->beginListen(port); logger->info(MSG_LISTENING_PORT, diff --git a/src/PeerListenCommand.h b/src/PeerListenCommand.h index aba8cf00..e2696f63 100644 --- a/src/PeerListenCommand.h +++ b/src/PeerListenCommand.h @@ -37,6 +37,7 @@ #include "Command.h" #include "Socket.h" +#include "IntSequence.h" class DownloadEngine; @@ -57,7 +58,7 @@ public: virtual bool execute(); - int32_t bindPort(int32_t portRangeStart, int32_t portRangeEnd); + int32_t bindPort(IntSequence& seq); void setLowestSpeedLimit(int32_t speed) { diff --git a/src/PieceStorage.h b/src/PieceStorage.h index 64e6d523..a440f82a 100644 --- a/src/PieceStorage.h +++ b/src/PieceStorage.h @@ -37,6 +37,7 @@ #include "common.h" #include "TimeA2.h" +#include "IntSequence.h" class Piece; extern typedef SharedHandle PieceHandle; @@ -124,7 +125,7 @@ public: virtual void setFileFilter(const Strings& filePaths) = 0; - virtual void setFileFilter(const Integers& fileIndexes) = 0; + virtual void setFileFilter(IntSequence seq) = 0; virtual void clearFileFilter() = 0; diff --git a/src/RequestGroup.cc b/src/RequestGroup.cc index 4e72ce58..c8f476f2 100644 --- a/src/RequestGroup.cc +++ b/src/RequestGroup.cc @@ -73,7 +73,6 @@ #ifdef ENABLE_METALINK # include "MetalinkPostDownloadHandler.h" #endif // ENABLE_METALINK -#include int32_t RequestGroup::_gidCounter = 0; @@ -148,16 +147,17 @@ Commands RequestGroup::createInitialCommand(DownloadEngine* e) throw new DownloadFailureException(EX_DUPLICATE_FILE_DOWNLOAD, getFilePath().c_str()); } + initPieceStorage(); if(btContext->getFileEntries().size() > 1) { // this is really multi file torrent. // clear http/ftp uris because the current implementation does not // allow integrating multi-file torrent and http/ftp. _logger->debug("Clearing http/ftp URIs because the current implementation does not allow integrating multi-file torrent and http/ftp."); _uris.clear(); + + _pieceStorage->setFileFilter(Util::parseIntRange(_option->get(PREF_SELECT_FILE))); } - - initPieceStorage(); - + BtProgressInfoFileHandle progressInfoFile = new DefaultBtProgressInfoFile(_downloadContext, _pieceStorage, diff --git a/src/SegmentMan.cc b/src/SegmentMan.cc index 598ab339..35221587 100644 --- a/src/SegmentMan.cc +++ b/src/SegmentMan.cc @@ -48,7 +48,6 @@ #include "DownloadContext.h" #include "Piece.h" #include "a2io.h" -#include SegmentEntry::SegmentEntry(int32_t cuid, const SegmentHandle& segment): cuid(cuid), segment(segment) {} diff --git a/src/Sequence.h b/src/Sequence.h new file mode 100644 index 00000000..c8ce1462 --- /dev/null +++ b/src/Sequence.h @@ -0,0 +1,99 @@ +/* */ +#ifndef _D_SEQUENCE_H_ +#define _D_SEQUENCE_H_ + +#include + +using namespace std; + +template +class Sequence +{ +public: + // Generates value in [_first, _last). _last is not included. + class Value { + private: + T _first; + T _last; + public: + Value(const T& first, const T& last):_first(first), _last(last) {} + + T next() + { + return _first++; + } + + bool hasNext() const + { + return _first != _last; + } + }; + + typedef deque Values; +private: + Values _values; +public: + Sequence(const Values& values): + _values(values) {} + + T next() + { + if(_values.empty()) { + return T(); + } + T t = _values.front().next(); + if(!_values.front().hasNext()) { + _values.pop_front(); + } + return t; + } + + bool hasNext() + { + return !_values.empty(); + } + + deque flush() + { + deque r; + while(hasNext()) { + r.push_back(next()); + } + return r; + } +}; + +#endif // _D_SEQUENCE_H_ diff --git a/src/UnknownLengthPieceStorage.h b/src/UnknownLengthPieceStorage.h index 8b4ee353..cf66a1a1 100644 --- a/src/UnknownLengthPieceStorage.h +++ b/src/UnknownLengthPieceStorage.h @@ -154,7 +154,7 @@ public: virtual void setFileFilter(const Strings& filePaths) {} - virtual void setFileFilter(const Integers& fileIndexes) {} + virtual void setFileFilter(IntSequence seq) {} virtual void clearFileFilter() {} diff --git a/src/Util.cc b/src/Util.cc index d4060fe9..ee93b4d9 100644 --- a/src/Util.cc +++ b/src/Util.cc @@ -464,6 +464,58 @@ void Util::unfoldRange(const string& src, Integers& range) { range.erase(unique(range.begin(), range.end()), range.end()); } +int32_t Util::parseInt(const string& s, int32_t base) +{ + char* stop; + errno = 0; + long int v = strtol(s.c_str(), &stop, base); + if(*stop != '\0') { + throw new DlAbortEx(MSG_ILLEGAL_CHARACTER, stop); + } else if((v == LONG_MIN || v == LONG_MAX) && errno == ERANGE || v > INT32_MAX || v < INT32_MIN) { + throw new DlAbortEx(MSG_OVERFLOW_UNDERFLOW_DETECTED, s.c_str()); + } + return v; +} + +int64_t Util::parseLLInt(const string& s, int32_t base) +{ + char* stop; + errno = 0; + int64_t v = strtoll(s.c_str(), &stop, base); + if(*stop != '\0') { + throw new DlAbortEx(MSG_ILLEGAL_CHARACTER, stop); + } else if((v == INT64_MIN || v == INT64_MAX) && errno == ERANGE) { + throw new DlAbortEx(MSG_OVERFLOW_UNDERFLOW_DETECTED, s.c_str()); + } + return v; +} + +IntSequence Util::parseIntRange(const string& src) +{ + IntSequence::Values values; + string temp = src; + while(temp.size()) { + pair p = Util::split(temp, ","); + temp = p.second; + if(p.first.empty()) { + continue; + } + if(p.first.find("-") == string::npos) { + int32_t v = Util::parseInt(p.first.c_str()); + values.push_back(IntSequence::Value(v, v+1)); + } else { + pair vp = Util::split(p.first.c_str(), "-"); + if(vp.first.empty() || vp.second.empty()) { + throw new DlAbortEx(MSG_INCOMPLETE_RANGE, p.first.c_str()); + } + int32_t v1 = Util::parseInt(vp.first.c_str()); + int32_t v2 = Util::parseInt(vp.second.c_str()); + values.push_back(IntSequence::Value(v1, v2+1)); + } + } + return values; +} + string Util::getContentDispositionFilename(const string& header) { string keyName = "filename="; string::size_type attributesp = header.find(keyName); diff --git a/src/Util.h b/src/Util.h index 0cfac8ea..143920c1 100644 --- a/src/Util.h +++ b/src/Util.h @@ -38,6 +38,7 @@ #include "common.h" #include "a2time.h" #include "FileEntry.h" +#include "IntSequence.h" #include #include #include @@ -112,6 +113,12 @@ public: static void unfoldRange(const string& src, Integers& range); + static int32_t parseInt(const string& s, int32_t base = 10); + + static int64_t parseLLInt(const string& s, int32_t base = 10); + + static IntSequence parseIntRange(const string& src); + // this function temporarily put here static string getContentDispositionFilename(const string& header); diff --git a/src/main.cc b/src/main.cc index dde08d12..295d4dbb 100644 --- a/src/main.cc +++ b/src/main.cc @@ -319,7 +319,7 @@ int main(int argc, char* argv[]) { downloadUri(op, args); } } catch(Exception* ex) { - cerr << EX_EXCEPTION_CAUGHT << "\n" << ex->getMsg() << endl; + cerr << EX_EXCEPTION_CAUGHT << "\n" << *ex << endl; delete ex; exit(EXIT_FAILURE); } diff --git a/src/message.h b/src/message.h index 36b46a2f..3a2f82d2 100644 --- a/src/message.h +++ b/src/message.h @@ -126,6 +126,9 @@ #define MSG_DAEMON_FAILED _("daemon failed.") #define MSG_VERIFICATION_SUCCESSFUL _("Verification finished successfully. file=%s") #define MSG_VERIFICATION_FAILED _("Checksum error detected. file=%s") +#define MSG_ILLEGAL_CHARACTER _("Illegal character detected: %s") +#define MSG_INCOMPLETE_RANGE _("Incomplete range specified. %s") +#define MSG_OVERFLOW_UNDERFLOW_DETECTED _("Overflow/underflow detected: %s") #define EX_TIME_OUT _("Timeout.") #define EX_INVALID_CHUNK_SIZE _("Invalid chunk size.") diff --git a/src/option_processing.cc b/src/option_processing.cc index e3cbef1d..61f98694 100644 --- a/src/option_processing.cc +++ b/src/option_processing.cc @@ -71,7 +71,7 @@ Option* option_processing(int argc, char* const argv[]) op->put(PREF_SPLIT, "1"); op->put(PREF_DAEMON, V_FALSE); op->put(PREF_SEGMENT_SIZE, Util::itos((int32_t)(1024*1024))); - op->put(PREF_LISTEN_PORT, "-1"); + op->put(PREF_LISTEN_PORT, "6881-6999"); op->put(PREF_METALINK_SERVERS, "5"); op->put(PREF_FOLLOW_TORRENT, #ifdef ENABLE_BITTORRENT @@ -124,6 +124,7 @@ Option* option_processing(int argc, char* const argv[]) op->put(PREF_ENABLE_HTTP_KEEP_ALIVE, V_FALSE); op->put(PREF_ENABLE_HTTP_PIPELINING, V_FALSE); op->put(PREF_MAX_HTTP_PIPELINING, "2"); + op->put(PREF_SEED_RATIO, "1.0"); while(1) { int optIndex = 0; int lopt; @@ -407,14 +408,14 @@ Option* option_processing(int argc, char* const argv[]) oparser.parse(op, cfstream); } catch(Exception* e) { cerr << "Parse error in " << cfname << endl; - cerr << e->getMsg() << endl; + cerr << *e << endl; delete e; exit(EXIT_FAILURE); } try { oparser.parse(op, cmdstream); } catch(Exception* e) { - cerr << e->getMsg() << endl; + cerr << *e << endl; delete e; exit(EXIT_FAILURE); } diff --git a/src/version_usage.cc b/src/version_usage.cc index 6adab969..ae38bad8 100644 --- a/src/version_usage.cc +++ b/src/version_usage.cc @@ -242,7 +242,11 @@ void showUsage() { cout << _(" --direct-file-mapping=true|false Directly read from and write to each file\n" " mentioned in .torrent file.\n" " Default: true") << endl; - cout << _(" --listen-port=PORT Set TCP port number for BitTorrent downloads.\n" + cout << _(" --listen-port=PORT... Set TCP port number for BitTorrent downloads.\n" + " Multiple values can be specified by using ',',\n" + " for example: \"6881,6885\".\n" + " You can also use '-' to specify a range: \"6881-6999\".\n" + " ',' and '-' can be used together.\n" " Default: 6881-6999") << endl; cout << _(" --max-upload-limit=SPEED Set max upload speed in bytes per sec.\n" " 0 means unrestricted.\n" @@ -252,9 +256,12 @@ void showUsage() { " --seed-ratio option.") << endl; cout << _(" --seed-ratio=RATIO Specify share ratio. Seed completed torrents\n" " until share ratio reaches RATIO. 1.0 is\n" - " encouraged. If --seed-time option is specified\n" - " along with this option, seeding ends when at\n" - " least one of the conditions is satisfied.") << endl; + " encouraged. Specify 0.0 if you intend to do\n" + " seeding regardless of share ratio.\n" + " If --seed-time option is specified along with\n" + " this option, seeding ends when at least one of\n" + " the conditions is satisfied.\n" + " Default: 1.0") << endl; cout << _(" --peer-id-prefix=PEERI_ID_PREFIX Specify the prefix of peer ID. The peer ID in\n" " in BitTorrent is 20 byte length. If more than 20\n" " bytes are specified, only first 20\n" diff --git a/test/Makefile.am b/test/Makefile.am index 1e1ada9a..a8cf166f 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -1,6 +1,7 @@ TESTS = aria2c check_PROGRAMS = $(TESTS) aria2c_SOURCES = AllTest.cc\ + SequenceTest.cc\ a2functionalTest.cc\ FileEntryTest.cc\ PieceTest.cc\ diff --git a/test/Makefile.in b/test/Makefile.in index 460f6fc2..ea522386 100644 --- a/test/Makefile.in +++ b/test/Makefile.in @@ -112,9 +112,10 @@ 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 a2functionalTest.cc \ - FileEntryTest.cc PieceTest.cc SegmentTest.cc \ - GrowSegmentTest.cc SingleFileAllocationIteratorTest.cc \ +am__aria2c_SOURCES_DIST = AllTest.cc SequenceTest.cc \ + a2functionalTest.cc FileEntryTest.cc PieceTest.cc \ + SegmentTest.cc GrowSegmentTest.cc \ + SingleFileAllocationIteratorTest.cc \ DefaultBtProgressInfoFileTest.cc \ SingleFileDownloadContextTest.cc RequestGroupTest.cc \ PStringBuildVisitorTest.cc ParameterizedStringParserTest.cc \ @@ -204,9 +205,10 @@ am__aria2c_SOURCES_DIST = AllTest.cc a2functionalTest.cc \ @ENABLE_METALINK_TRUE@ Metalink2RequestGroupTest.$(OBJEXT) \ @ENABLE_METALINK_TRUE@ MetalinkPostDownloadHandlerTest.$(OBJEXT) \ @ENABLE_METALINK_TRUE@ MetalinkHelperTest.$(OBJEXT) -am_aria2c_OBJECTS = AllTest.$(OBJEXT) a2functionalTest.$(OBJEXT) \ - FileEntryTest.$(OBJEXT) PieceTest.$(OBJEXT) \ - SegmentTest.$(OBJEXT) GrowSegmentTest.$(OBJEXT) \ +am_aria2c_OBJECTS = AllTest.$(OBJEXT) SequenceTest.$(OBJEXT) \ + a2functionalTest.$(OBJEXT) FileEntryTest.$(OBJEXT) \ + PieceTest.$(OBJEXT) SegmentTest.$(OBJEXT) \ + GrowSegmentTest.$(OBJEXT) \ SingleFileAllocationIteratorTest.$(OBJEXT) \ DefaultBtProgressInfoFileTest.$(OBJEXT) \ SingleFileDownloadContextTest.$(OBJEXT) \ @@ -416,9 +418,9 @@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ TESTS = aria2c -aria2c_SOURCES = AllTest.cc a2functionalTest.cc FileEntryTest.cc \ - PieceTest.cc SegmentTest.cc GrowSegmentTest.cc \ - SingleFileAllocationIteratorTest.cc \ +aria2c_SOURCES = AllTest.cc SequenceTest.cc a2functionalTest.cc \ + FileEntryTest.cc PieceTest.cc SegmentTest.cc \ + GrowSegmentTest.cc SingleFileAllocationIteratorTest.cc \ DefaultBtProgressInfoFileTest.cc \ SingleFileDownloadContextTest.cc RequestGroupTest.cc \ PStringBuildVisitorTest.cc ParameterizedStringParserTest.cc \ @@ -577,6 +579,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/RequestTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SegmentManTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SegmentTest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SequenceTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ShaVisitorTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ShareRatioSeedCriteriaTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SharedHandleTest.Po@am__quote@ diff --git a/test/MockPieceStorage.h b/test/MockPieceStorage.h index 4f7175cc..6d5edfea 100644 --- a/test/MockPieceStorage.h +++ b/test/MockPieceStorage.h @@ -109,7 +109,7 @@ public: virtual void setFileFilter(const Strings& filePaths) {} - virtual void setFileFilter(const Integers& fileIndexes) {} + virtual void setFileFilter(IntSequence seq) {} virtual void clearFileFilter() {} diff --git a/test/MultiDiskAdaptorTest.cc b/test/MultiDiskAdaptorTest.cc index 2f81012b..9983e1a4 100644 --- a/test/MultiDiskAdaptorTest.cc +++ b/test/MultiDiskAdaptorTest.cc @@ -11,18 +11,13 @@ class MultiDiskAdaptorTest:public CppUnit::TestFixture { CPPUNIT_TEST(testReadData); CPPUNIT_TEST_SUITE_END(); private: - Option* option; MultiDiskAdaptorHandle adaptor; public: - MultiDiskAdaptorTest():option(0), adaptor(0) {} + MultiDiskAdaptorTest():adaptor(0) {} void setUp() { - delete option; - option = new Option(); - adaptor = new MultiDiskAdaptor(); adaptor->setPieceLength(2); - adaptor->setOption(new Option()); adaptor->setStoreDir("."); adaptor->setTopDir("."); } diff --git a/test/MultiFileAllocationIteratorTest.cc b/test/MultiFileAllocationIteratorTest.cc index e64fa225..1ce89acb 100644 --- a/test/MultiFileAllocationIteratorTest.cc +++ b/test/MultiFileAllocationIteratorTest.cc @@ -7,6 +7,7 @@ class MultiFileAllocationIteratorTest:public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(MultiFileAllocationIteratorTest); CPPUNIT_TEST(testAllocate); + CPPUNIT_TEST(testMakeFileEntries); CPPUNIT_TEST_SUITE_END(); private: @@ -14,11 +15,54 @@ public: void setUp() {} void testAllocate(); + void testMakeFileEntries(); }; CPPUNIT_TEST_SUITE_REGISTRATION( MultiFileAllocationIteratorTest ); +void MultiFileAllocationIteratorTest::testMakeFileEntries() +{ + FileEntryHandle fs[] = { + new FileEntry("file1", 1536, 0), + new FileEntry("file2", 2048, 1536), + new FileEntry("file3", 1024, 3584), + new FileEntry("file4", 1024, 4608), + new FileEntry("file5", 1024, 5632), + new FileEntry("file6", 1024, 6656), + new FileEntry("file7", 256, 7680), + new FileEntry("file8", 768, 7936), + new FileEntry("file9", 256, 8704), + new FileEntry("fileA", 256, 8960), + }; + fs[1]->setRequested(false); + fs[3]->setRequested(false); + fs[4]->setRequested(false); + fs[5]->setRequested(false); + fs[6]->setRequested(false); + fs[8]->setRequested(false); + fs[9]->setRequested(false); + + MultiDiskAdaptorHandle diskAdaptor = new MultiDiskAdaptor(); + diskAdaptor->setFileEntries(FileEntries(&fs[0], &fs[10])); + diskAdaptor->setPieceLength(1024); + + MultiFileAllocationIteratorHandle itr = diskAdaptor->fileAllocationIterator(); + + FileEntries entries = itr->getFileEntries(); + + sort(entries.begin(), entries.end()); + + CPPUNIT_ASSERT_EQUAL((size_t)6, entries.size()); + + CPPUNIT_ASSERT_EQUAL(string("file1"), entries[0]->getPath()); + CPPUNIT_ASSERT_EQUAL(string("file2"), entries[1]->getPath()); + CPPUNIT_ASSERT_EQUAL(string("file3"), entries[2]->getPath()); + CPPUNIT_ASSERT_EQUAL(string("file6"), entries[3]->getPath()); + CPPUNIT_ASSERT_EQUAL(string("file7"), entries[4]->getPath()); + CPPUNIT_ASSERT_EQUAL(string("file8"), entries[5]->getPath()); +} + void MultiFileAllocationIteratorTest::testAllocate() { string dir = "/tmp"; diff --git a/test/OptionHandlerTest.cc b/test/OptionHandlerTest.cc index 67a549e3..c7486e6a 100644 --- a/test/OptionHandlerTest.cc +++ b/test/OptionHandlerTest.cc @@ -52,7 +52,7 @@ void OptionHandlerTest::testNullOptionHandler() { NullOptionHandler handler; CPPUNIT_ASSERT(handler.canHandle("foo")); - handler.parseArg(0, "bar"); + handler.parse(0, "bar"); } void OptionHandlerTest::testBooleanOptionHandler() @@ -61,12 +61,12 @@ void OptionHandlerTest::testBooleanOptionHandler() CPPUNIT_ASSERT(handler.canHandle("foo")); CPPUNIT_ASSERT(!handler.canHandle("foobar")); Option option; - handler.parseArg(&option, V_TRUE); + handler.parse(&option, V_TRUE); CPPUNIT_ASSERT_EQUAL(string(V_TRUE), option.get("foo")); - handler.parseArg(&option, V_FALSE); + handler.parse(&option, V_FALSE); CPPUNIT_ASSERT_EQUAL(string(V_FALSE), option.get("foo")); try { - handler.parseArg(&option, "hello"); + handler.parse(&option, "hello"); CPPUNIT_FAIL("exception must be thrown."); } catch(Exception* e) { cerr << e->getMsg() << endl; @@ -80,7 +80,7 @@ void OptionHandlerTest::testNumberOptionHandler() CPPUNIT_ASSERT(handler.canHandle("foo")); CPPUNIT_ASSERT(!handler.canHandle("foobar")); Option option; - handler.parseArg(&option, "0"); + handler.parse(&option, "0"); CPPUNIT_ASSERT_EQUAL(string("0"), option.get("foo")); } @@ -88,10 +88,10 @@ void OptionHandlerTest::testNumberOptionHandler_min() { NumberOptionHandler handler("foo", 1); Option option; - handler.parseArg(&option, "1"); + handler.parse(&option, "1"); CPPUNIT_ASSERT_EQUAL(string("1"), option.get("foo")); try { - handler.parseArg(&option, "0"); + handler.parse(&option, "0"); CPPUNIT_FAIL("exception must be thrown."); } catch(Exception* e) { cerr << e->getMsg() << endl; @@ -104,10 +104,10 @@ void OptionHandlerTest::testNumberOptionHandler_max() { NumberOptionHandler handler("foo", -1, 100); Option option; - handler.parseArg(&option, "100"); + handler.parse(&option, "100"); CPPUNIT_ASSERT_EQUAL(string("100"), option.get("foo")); try { - handler.parseArg(&option, "101"); + handler.parse(&option, "101"); CPPUNIT_FAIL("exception must be thrown."); } catch(Exception* e) { cerr << e->getMsg() << endl; @@ -119,19 +119,19 @@ void OptionHandlerTest::testNumberOptionHandler_min_max() { NumberOptionHandler handler("foo", 1, 100); Option option; - handler.parseArg(&option, "1"); + handler.parse(&option, "1"); CPPUNIT_ASSERT_EQUAL(string("1"), option.get("foo")); - handler.parseArg(&option, "100"); + handler.parse(&option, "100"); CPPUNIT_ASSERT_EQUAL(string("100"), option.get("foo")); try { - handler.parseArg(&option, "0"); + handler.parse(&option, "0"); CPPUNIT_FAIL("exception must be thrown."); } catch(Exception* e) { cerr << e->getMsg() << endl; delete e; } try { - handler.parseArg(&option, "101"); + handler.parse(&option, "101"); CPPUNIT_FAIL("exception must be thrown."); } catch(Exception* e) { cerr << e->getMsg() << endl; @@ -145,17 +145,17 @@ void OptionHandlerTest::testUnitNumberOptionHandler() CPPUNIT_ASSERT(handler.canHandle("foo")); CPPUNIT_ASSERT(!handler.canHandle("foobar")); Option option; - handler.parseArg(&option, "4294967296"); + handler.parse(&option, "4294967296"); CPPUNIT_ASSERT_EQUAL(string("4294967296"), option.get("foo")); - handler.parseArg(&option, "4096M"); + handler.parse(&option, "4096M"); CPPUNIT_ASSERT_EQUAL(string("4294967296"), option.get("foo")); - handler.parseArg(&option, "4096K"); + handler.parse(&option, "4096K"); CPPUNIT_ASSERT_EQUAL(string("4194304"), option.get("foo")); - handler.parseArg(&option, "K"); + handler.parse(&option, "K"); CPPUNIT_ASSERT_EQUAL(string("0"), option.get("foo")); - handler.parseArg(&option, "M"); + handler.parse(&option, "M"); CPPUNIT_ASSERT_EQUAL(string("0"), option.get("foo")); - handler.parseArg(&option, ""); + handler.parse(&option, ""); CPPUNIT_ASSERT_EQUAL(string("0"), option.get("foo")); } @@ -165,10 +165,10 @@ void OptionHandlerTest::testParameterOptionHandler_1argInit() CPPUNIT_ASSERT(handler.canHandle("foo")); CPPUNIT_ASSERT(!handler.canHandle("foobar")); Option option; - handler.parseArg(&option, "value1"); + handler.parse(&option, "value1"); CPPUNIT_ASSERT_EQUAL(string("value1"), option.get("foo")); try { - handler.parseArg(&option, "value3"); + handler.parse(&option, "value3"); CPPUNIT_FAIL("exception must be thrown."); } catch(Exception* e) { cerr << e->getMsg() << endl; @@ -182,12 +182,12 @@ void OptionHandlerTest::testParameterOptionHandler_2argsInit() CPPUNIT_ASSERT(handler.canHandle("foo")); CPPUNIT_ASSERT(!handler.canHandle("foobar")); Option option; - handler.parseArg(&option, "value1"); + handler.parse(&option, "value1"); CPPUNIT_ASSERT_EQUAL(string("value1"), option.get("foo")); - handler.parseArg(&option, "value2"); + handler.parse(&option, "value2"); CPPUNIT_ASSERT_EQUAL(string("value2"), option.get("foo")); try { - handler.parseArg(&option, "value3"); + handler.parse(&option, "value3"); CPPUNIT_FAIL("exception must be thrown."); } catch(Exception* e) { cerr << e->getMsg() << endl; @@ -205,12 +205,12 @@ void OptionHandlerTest::testParameterOptionHandler_listInit() CPPUNIT_ASSERT(handler.canHandle("foo")); CPPUNIT_ASSERT(!handler.canHandle("foobar")); Option option; - handler.parseArg(&option, "value1"); + handler.parse(&option, "value1"); CPPUNIT_ASSERT_EQUAL(string("value1"), option.get("foo")); - handler.parseArg(&option, "value2"); + handler.parse(&option, "value2"); CPPUNIT_ASSERT_EQUAL(string("value2"), option.get("foo")); try { - handler.parseArg(&option, "value3"); + handler.parse(&option, "value3"); CPPUNIT_FAIL("exception must be thrown."); } catch(Exception* e) { cerr << e->getMsg() << endl; @@ -224,9 +224,9 @@ void OptionHandlerTest::testDefaultOptionHandler() CPPUNIT_ASSERT(handler.canHandle("foo")); CPPUNIT_ASSERT(!handler.canHandle("foobar")); Option option; - handler.parseArg(&option, "bar"); + handler.parse(&option, "bar"); CPPUNIT_ASSERT_EQUAL(string("bar"), option.get("foo")); - handler.parseArg(&option, ""); + handler.parse(&option, ""); CPPUNIT_ASSERT_EQUAL(string(""), option.get("foo")); } @@ -236,7 +236,7 @@ void OptionHandlerTest::testFloatNumberOptionHandler() CPPUNIT_ASSERT(handler.canHandle("foo")); CPPUNIT_ASSERT(!handler.canHandle("foobar")); Option option; - handler.parseArg(&option, "1.0"); + handler.parse(&option, "1.0"); CPPUNIT_ASSERT_EQUAL(string("1.0"), option.get("foo")); } @@ -244,10 +244,10 @@ void OptionHandlerTest::testFloatNumberOptionHandler_min() { FloatNumberOptionHandler handler("foo", 0.0); Option option; - handler.parseArg(&option, "0.0"); + handler.parse(&option, "0.0"); CPPUNIT_ASSERT_EQUAL(string("0.0"), option.get("foo")); try { - handler.parseArg(&option, "-0.1"); + handler.parse(&option, "-0.1"); CPPUNIT_FAIL("exception must be thrown."); } catch(Exception* e) { cerr << e->getMsg() << endl; @@ -259,10 +259,10 @@ void OptionHandlerTest::testFloatNumberOptionHandler_max() { FloatNumberOptionHandler handler("foo", -1, 10.0); Option option; - handler.parseArg(&option, "10.0"); + handler.parse(&option, "10.0"); CPPUNIT_ASSERT_EQUAL(string("10.0"), option.get("foo")); try { - handler.parseArg(&option, "10.1"); + handler.parse(&option, "10.1"); CPPUNIT_FAIL("exception must be thrown."); } catch(Exception* e) { cerr << e->getMsg() << endl; @@ -274,19 +274,19 @@ void OptionHandlerTest::testFloatNumberOptionHandler_min_max() { FloatNumberOptionHandler handler("foo", 0.0, 10.0); Option option; - handler.parseArg(&option, "0.0"); + handler.parse(&option, "0.0"); CPPUNIT_ASSERT_EQUAL(string("0.0"), option.get("foo")); - handler.parseArg(&option, "10.0"); + handler.parse(&option, "10.0"); CPPUNIT_ASSERT_EQUAL(string("10.0"), option.get("foo")); try { - handler.parseArg(&option, "-0.1"); + handler.parse(&option, "-0.1"); CPPUNIT_FAIL("exception must be thrown."); } catch(Exception* e) { cerr << e->getMsg() << endl; delete e; } try { - handler.parseArg(&option, "10.1"); + handler.parse(&option, "10.1"); CPPUNIT_FAIL("exception must be thrown."); } catch(Exception* e) { cerr << e->getMsg() << endl; @@ -300,12 +300,12 @@ void OptionHandlerTest::testLogOptionHandler() CPPUNIT_ASSERT(handler.canHandle("foo")); CPPUNIT_ASSERT(!handler.canHandle("foobar")); Option option; - handler.parseArg(&option, "/tmp/log.txt"); + handler.parse(&option, "/tmp/log.txt"); CPPUNIT_ASSERT_EQUAL(string("/tmp/log.txt"), option.get(PREF_LOG)); CPPUNIT_ASSERT_EQUAL(string(""), option.get(PREF_STDOUT_LOG)); option.clear(); - handler.parseArg(&option, "-"); + handler.parse(&option, "-"); CPPUNIT_ASSERT_EQUAL(string(""), option.get(PREF_LOG)); CPPUNIT_ASSERT_EQUAL(string(V_TRUE), option.get(PREF_STDOUT_LOG)); } @@ -316,42 +316,42 @@ void OptionHandlerTest::testHttpProxyOptionHandler() CPPUNIT_ASSERT(handler.canHandle("foo")); CPPUNIT_ASSERT(!handler.canHandle("foobar")); Option option; - handler.parseArg(&option, "bar:80"); + handler.parse(&option, "bar:80"); CPPUNIT_ASSERT_EQUAL(string("bar:80"), option.get(PREF_HTTP_PROXY)); CPPUNIT_ASSERT_EQUAL(string("bar"), option.get(PREF_HTTP_PROXY_HOST)); CPPUNIT_ASSERT_EQUAL(string("80"), option.get(PREF_HTTP_PROXY_PORT)); CPPUNIT_ASSERT_EQUAL(string(V_TRUE), option.get(PREF_HTTP_PROXY_ENABLED)); try { - handler.parseArg(&option, "bar"); + handler.parse(&option, "bar"); CPPUNIT_FAIL("exception must be thrown."); } catch(Exception* e) { cerr << e->getMsg() << endl; delete e; } try { - handler.parseArg(&option, "bar:"); + handler.parse(&option, "bar:"); CPPUNIT_FAIL("exception must be thrown."); } catch(Exception* e) { cerr << e->getMsg() << endl; delete e; } try { - handler.parseArg(&option, ":"); + handler.parse(&option, ":"); CPPUNIT_FAIL("exception must be thrown."); } catch(Exception* e) { cerr << e->getMsg() << endl; delete e; } try { - handler.parseArg(&option, ":80"); + handler.parse(&option, ":80"); CPPUNIT_FAIL("exception must be thrown."); } catch(Exception* e) { cerr << e->getMsg() << endl; delete e; } try { - handler.parseArg(&option, "foo:bar"); + handler.parse(&option, "foo:bar"); CPPUNIT_FAIL("exception must be thrown."); } catch(Exception* e) { cerr << e->getMsg() << endl; diff --git a/test/SequenceTest.cc b/test/SequenceTest.cc new file mode 100644 index 00000000..d907f4ce --- /dev/null +++ b/test/SequenceTest.cc @@ -0,0 +1,79 @@ +#include "Sequence.h" +#include + +using namespace std; + +class SequenceTest:public CppUnit::TestFixture { + + CPPUNIT_TEST_SUITE(SequenceTest); + CPPUNIT_TEST(testParseAndNext); + CPPUNIT_TEST(testParseAndNext2); + CPPUNIT_TEST(testFlush); + CPPUNIT_TEST_SUITE_END(); +public: + void testParseAndNext(); + void testParseAndNext2(); + void testFlush(); +}; + + +CPPUNIT_TEST_SUITE_REGISTRATION(SequenceTest); + +typedef Sequence IntSequence; + +void SequenceTest::testParseAndNext() +{ + IntSequence::Value params[] = { + IntSequence::Value(1, 2), + IntSequence::Value(3, 9), + IntSequence::Value(10, 11), + }; + IntSequence seq(IntSequence::Values(¶ms[0], ¶ms[3])); + CPPUNIT_ASSERT(seq.hasNext()); + CPPUNIT_ASSERT_EQUAL((int32_t)1, seq.next()); + CPPUNIT_ASSERT(seq.hasNext()); + CPPUNIT_ASSERT_EQUAL((int32_t)3, seq.next()); + CPPUNIT_ASSERT(seq.hasNext()); + CPPUNIT_ASSERT_EQUAL((int32_t)4, seq.next()); + CPPUNIT_ASSERT(seq.hasNext()); + CPPUNIT_ASSERT_EQUAL((int32_t)5, seq.next()); + CPPUNIT_ASSERT(seq.hasNext()); + CPPUNIT_ASSERT_EQUAL((int32_t)6, seq.next()); + CPPUNIT_ASSERT(seq.hasNext()); + CPPUNIT_ASSERT_EQUAL((int32_t)7, seq.next()); + CPPUNIT_ASSERT(seq.hasNext()); + CPPUNIT_ASSERT_EQUAL((int32_t)8, seq.next()); + CPPUNIT_ASSERT(seq.hasNext()); + CPPUNIT_ASSERT_EQUAL((int32_t)10, seq.next()); + CPPUNIT_ASSERT(!seq.hasNext()); + CPPUNIT_ASSERT_EQUAL((int32_t)0, seq.next()); + +} + +void SequenceTest::testParseAndNext2() +{ + IntSequence::Value params[] = { + IntSequence::Value(1, 2), + }; + IntSequence seq(IntSequence::Values(¶ms[0], ¶ms[1])); + CPPUNIT_ASSERT(seq.hasNext()); + CPPUNIT_ASSERT_EQUAL((int32_t)1, seq.next()); + CPPUNIT_ASSERT(!seq.hasNext()); + CPPUNIT_ASSERT_EQUAL((int32_t)0, seq.next()); + +} + +void SequenceTest::testFlush() +{ + IntSequence::Value params[] = { + IntSequence::Value(1, 2), + IntSequence::Value(3, 9), + IntSequence::Value(10, 11), + }; + IntSequence seq(IntSequence::Values(¶ms[0], ¶ms[3])); + deque r = seq.flush(); + + int32_t answers[] = { 1, 3, 4, 5, 6, 7, 8, 10 }; + + CPPUNIT_ASSERT(equal(r.begin(), r.end(), &answers[0])); +} diff --git a/test/UtilTest.cc b/test/UtilTest.cc index 2ac556f9..183b72fb 100644 --- a/test/UtilTest.cc +++ b/test/UtilTest.cc @@ -32,6 +32,10 @@ class UtilTest:public CppUnit::TestFixture { CPPUNIT_TEST(testAlphaToNum); CPPUNIT_TEST(testMkdirs); CPPUNIT_TEST(testConvertBitfield); + CPPUNIT_TEST(testParseIntRange); + CPPUNIT_TEST(testParseIntRange_invalidRange); + CPPUNIT_TEST(testParseInt); + CPPUNIT_TEST(testParseLLInt); CPPUNIT_TEST_SUITE_END(); private: @@ -61,6 +65,10 @@ public: void testAlphaToNum(); void testMkdirs(); void testConvertBitfield(); + void testParseIntRange(); + void testParseIntRange_invalidRange(); + void testParseInt(); + void testParseLLInt(); }; @@ -407,3 +415,123 @@ void UtilTest::testConvertBitfield() Util::toHex(destBitfield.getBitfield(), destBitfield.getBitfieldLength())); } + +void UtilTest::testParseIntRange() +{ + IntSequence seq = Util::parseIntRange("1,3-8,10"); + + CPPUNIT_ASSERT(seq.hasNext()); + CPPUNIT_ASSERT_EQUAL((int32_t)1, seq.next()); + CPPUNIT_ASSERT(seq.hasNext()); + CPPUNIT_ASSERT_EQUAL((int32_t)3, seq.next()); + CPPUNIT_ASSERT(seq.hasNext()); + CPPUNIT_ASSERT_EQUAL((int32_t)4, seq.next()); + CPPUNIT_ASSERT(seq.hasNext()); + CPPUNIT_ASSERT_EQUAL((int32_t)5, seq.next()); + CPPUNIT_ASSERT(seq.hasNext()); + CPPUNIT_ASSERT_EQUAL((int32_t)6, seq.next()); + CPPUNIT_ASSERT(seq.hasNext()); + CPPUNIT_ASSERT_EQUAL((int32_t)7, seq.next()); + CPPUNIT_ASSERT(seq.hasNext()); + CPPUNIT_ASSERT_EQUAL((int32_t)8, seq.next()); + CPPUNIT_ASSERT(seq.hasNext()); + CPPUNIT_ASSERT_EQUAL((int32_t)10, seq.next()); + CPPUNIT_ASSERT(!seq.hasNext()); + CPPUNIT_ASSERT_EQUAL((int32_t)0, seq.next()); +} + +void UtilTest::testParseIntRange_invalidRange() +{ + try { + IntSequence seq = Util::parseIntRange("-1"); + CPPUNIT_FAIL("exception must be thrown."); + } catch(Exception* e) { + cerr << *e; + delete e; + } + try { + IntSequence seq = Util::parseIntRange("2147483648"); + CPPUNIT_FAIL("exception must be thrown."); + } catch(Exception* e) { + cerr << *e; + delete e; + } + try { + IntSequence seq = Util::parseIntRange("2147483647-2147483648"); + CPPUNIT_FAIL("exception must be thrown."); + } catch(Exception* e) { + cerr << *e; + delete e; + } + try { + IntSequence seq = Util::parseIntRange("1-2x"); + CPPUNIT_FAIL("exception must be thrown."); + } catch(Exception* e) { + cerr << *e; + delete e; + } + try { + IntSequence seq = Util::parseIntRange("3x-4"); + CPPUNIT_FAIL("exception must be thrown."); + } catch(Exception* e) { + cerr << *e; + delete e; + } +} + +void UtilTest::testParseInt() +{ + CPPUNIT_ASSERT_EQUAL((int32_t)-1, Util::parseInt("-1")); + CPPUNIT_ASSERT_EQUAL((int32_t)2147483647, Util::parseInt("2147483647")); + try { + Util::parseInt("2147483648"); + CPPUNIT_FAIL("exception must be thrown."); + } catch(Exception* e) { + cerr << *e; + delete e; + } + try { + Util::parseInt("-2147483649"); + CPPUNIT_FAIL("exception must be thrown."); + } catch(Exception* e) { + cerr << *e; + delete e; + } + try { + Util::parseInt("12x"); + CPPUNIT_FAIL("exception must be thrown."); + } catch(Exception* e) { + cerr << *e; + delete e; + } + +} + +void UtilTest::testParseLLInt() +{ + CPPUNIT_ASSERT_EQUAL((int64_t)-1, Util::parseLLInt("-1")); + CPPUNIT_ASSERT_EQUAL((int64_t)9223372036854775807LL, + Util::parseLLInt("9223372036854775807")); + try { + Util::parseLLInt("9223372036854775808"); + CPPUNIT_FAIL("exception must be thrown."); + } catch(Exception* e) { + cerr << *e; + delete e; + } + try { + Util::parseLLInt("-9223372036854775809"); + CPPUNIT_FAIL("exception must be thrown."); + } catch(Exception* e) { + cerr << *e; + delete e; + } + try { + Util::parseLLInt("12x"); + CPPUNIT_FAIL("exception must be thrown."); + } catch(Exception* e) { + cerr << *e; + delete e; + } + +}