Home | History | Annotate | Download | only in download
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "base/callback.h"
      6 #include "base/command_line.h"
      7 #include "base/message_loop/message_loop.h"
      8 #include "base/stl_util.h"
      9 #include "base/threading/thread.h"
     10 #include "content/browser/byte_stream.h"
     11 #include "content/browser/download/download_create_info.h"
     12 #include "content/browser/download/download_file_factory.h"
     13 #include "content/browser/download/download_item_impl.h"
     14 #include "content/browser/download/download_item_impl_delegate.h"
     15 #include "content/browser/download/download_request_handle.h"
     16 #include "content/browser/download/mock_download_file.h"
     17 #include "content/public/browser/download_destination_observer.h"
     18 #include "content/public/browser/download_interrupt_reasons.h"
     19 #include "content/public/browser/download_url_parameters.h"
     20 #include "content/public/common/content_switches.h"
     21 #include "content/public/test/mock_download_item.h"
     22 #include "content/public/test/test_browser_thread.h"
     23 #include "testing/gmock/include/gmock/gmock.h"
     24 #include "testing/gtest/include/gtest/gtest.h"
     25 
     26 using ::testing::_;
     27 using ::testing::NiceMock;
     28 using ::testing::Property;
     29 using ::testing::Return;
     30 using ::testing::SaveArg;
     31 using ::testing::StrictMock;
     32 
     33 const int kDownloadChunkSize = 1000;
     34 const int kDownloadSpeed = 1000;
     35 const base::FilePath::CharType kDummyPath[] = FILE_PATH_LITERAL("/testpath");
     36 
     37 namespace content {
     38 
     39 namespace {
     40 
     41 class MockDelegate : public DownloadItemImplDelegate {
     42  public:
     43   MockDelegate() : DownloadItemImplDelegate() {
     44     SetDefaultExpectations();
     45   }
     46 
     47   MOCK_METHOD2(DetermineDownloadTarget, void(
     48       DownloadItemImpl*, const DownloadTargetCallback&));
     49   MOCK_METHOD2(ShouldCompleteDownload,
     50                bool(DownloadItemImpl*, const base::Closure&));
     51   MOCK_METHOD2(ShouldOpenDownload,
     52                bool(DownloadItemImpl*, const ShouldOpenDownloadCallback&));
     53   MOCK_METHOD1(ShouldOpenFileBasedOnExtension, bool(const base::FilePath&));
     54   MOCK_METHOD1(CheckForFileRemoval, void(DownloadItemImpl*));
     55 
     56   virtual void ResumeInterruptedDownload(
     57       scoped_ptr<DownloadUrlParameters> params, uint32 id) OVERRIDE {
     58     MockResumeInterruptedDownload(params.get(), id);
     59   }
     60   MOCK_METHOD2(MockResumeInterruptedDownload,
     61                void(DownloadUrlParameters* params, uint32 id));
     62 
     63   MOCK_CONST_METHOD0(GetBrowserContext, BrowserContext*());
     64   MOCK_METHOD1(UpdatePersistence, void(DownloadItemImpl*));
     65   MOCK_METHOD1(DownloadOpened, void(DownloadItemImpl*));
     66   MOCK_METHOD1(DownloadRemoved, void(DownloadItemImpl*));
     67   MOCK_CONST_METHOD1(AssertStateConsistent, void(DownloadItemImpl*));
     68 
     69   void VerifyAndClearExpectations() {
     70     ::testing::Mock::VerifyAndClearExpectations(this);
     71     SetDefaultExpectations();
     72   }
     73 
     74  private:
     75   void SetDefaultExpectations() {
     76     EXPECT_CALL(*this, AssertStateConsistent(_))
     77         .WillRepeatedly(Return());
     78     EXPECT_CALL(*this, ShouldOpenFileBasedOnExtension(_))
     79         .WillRepeatedly(Return(false));
     80     EXPECT_CALL(*this, ShouldOpenDownload(_, _))
     81         .WillRepeatedly(Return(true));
     82   }
     83 };
     84 
     85 class MockRequestHandle : public DownloadRequestHandleInterface {
     86  public:
     87   MOCK_CONST_METHOD0(GetWebContents, WebContents*());
     88   MOCK_CONST_METHOD0(GetDownloadManager, DownloadManager*());
     89   MOCK_CONST_METHOD0(PauseRequest, void());
     90   MOCK_CONST_METHOD0(ResumeRequest, void());
     91   MOCK_CONST_METHOD0(CancelRequest, void());
     92   MOCK_CONST_METHOD0(DebugString, std::string());
     93 };
     94 
     95 // Schedules a task to invoke the RenameCompletionCallback with |new_path| on
     96 // the UI thread. Should only be used as the action for
     97 // MockDownloadFile::Rename as follows:
     98 //   EXPECT_CALL(download_file, Rename*(_,_))
     99 //       .WillOnce(ScheduleRenameCallback(DOWNLOAD_INTERRUPT_REASON_NONE,
    100 //                                        new_path));
    101 ACTION_P2(ScheduleRenameCallback, interrupt_reason, new_path) {
    102   BrowserThread::PostTask(
    103       BrowserThread::UI, FROM_HERE,
    104       base::Bind(arg1, interrupt_reason, new_path));
    105 }
    106 
    107 }  // namespace
    108 
    109 class DownloadItemTest : public testing::Test {
    110  public:
    111   class MockObserver : public DownloadItem::Observer {
    112    public:
    113     explicit MockObserver(DownloadItem* item)
    114       : item_(item),
    115         last_state_(item->GetState()),
    116         removed_(false),
    117         destroyed_(false),
    118         updated_(false),
    119         interrupt_count_(0),
    120         resume_count_(0) {
    121       item_->AddObserver(this);
    122     }
    123 
    124     virtual ~MockObserver() {
    125       if (item_) item_->RemoveObserver(this);
    126     }
    127 
    128     virtual void OnDownloadRemoved(DownloadItem* download) OVERRIDE {
    129       DVLOG(20) << " " << __FUNCTION__
    130                 << " download = " << download->DebugString(false);
    131       removed_ = true;
    132     }
    133 
    134     virtual void OnDownloadUpdated(DownloadItem* download) OVERRIDE {
    135       DVLOG(20) << " " << __FUNCTION__
    136                 << " download = " << download->DebugString(false);
    137       updated_ = true;
    138       DownloadItem::DownloadState new_state = download->GetState();
    139       if (last_state_ == DownloadItem::IN_PROGRESS &&
    140           new_state == DownloadItem::INTERRUPTED) {
    141         interrupt_count_++;
    142       }
    143       if (last_state_ == DownloadItem::INTERRUPTED &&
    144           new_state == DownloadItem::IN_PROGRESS) {
    145         resume_count_++;
    146       }
    147       last_state_ = new_state;
    148     }
    149 
    150     virtual void OnDownloadOpened(DownloadItem* download) OVERRIDE {
    151       DVLOG(20) << " " << __FUNCTION__
    152                 << " download = " << download->DebugString(false);
    153     }
    154 
    155     virtual void OnDownloadDestroyed(DownloadItem* download) OVERRIDE {
    156       DVLOG(20) << " " << __FUNCTION__
    157                 << " download = " << download->DebugString(false);
    158       destroyed_ = true;
    159       item_->RemoveObserver(this);
    160       item_ = NULL;
    161     }
    162 
    163     bool CheckRemoved() {
    164       return removed_;
    165     }
    166 
    167     bool CheckDestroyed() {
    168       return destroyed_;
    169     }
    170 
    171     bool CheckUpdated() {
    172       bool was_updated = updated_;
    173       updated_ = false;
    174       return was_updated;
    175     }
    176 
    177     int GetInterruptCount() {
    178       return interrupt_count_;
    179     }
    180 
    181     int GetResumeCount() {
    182       return resume_count_;
    183     }
    184 
    185    private:
    186     DownloadItem* item_;
    187     DownloadItem::DownloadState last_state_;
    188     bool removed_;
    189     bool destroyed_;
    190     bool updated_;
    191     int interrupt_count_;
    192     int resume_count_;
    193   };
    194 
    195   DownloadItemTest()
    196       : ui_thread_(BrowserThread::UI, &loop_),
    197         file_thread_(BrowserThread::FILE, &loop_),
    198         delegate_() {
    199   }
    200 
    201   ~DownloadItemTest() {
    202   }
    203 
    204   virtual void SetUp() {
    205   }
    206 
    207   virtual void TearDown() {
    208     ui_thread_.DeprecatedGetThreadObject()->message_loop()->RunUntilIdle();
    209     STLDeleteElements(&allocated_downloads_);
    210     allocated_downloads_.clear();
    211   }
    212 
    213   // This class keeps ownership of the created download item; it will
    214   // be torn down at the end of the test unless DestroyDownloadItem is
    215   // called.
    216   DownloadItemImpl* CreateDownloadItem() {
    217     // Normally, the download system takes ownership of info, and is
    218     // responsible for deleting it.  In these unit tests, however, we
    219     // don't call the function that deletes it, so we do so ourselves.
    220     scoped_ptr<DownloadCreateInfo> info_;
    221 
    222     info_.reset(new DownloadCreateInfo());
    223     static uint32 next_id = DownloadItem::kInvalidId + 1;
    224     info_->save_info = scoped_ptr<DownloadSaveInfo>(new DownloadSaveInfo());
    225     info_->save_info->prompt_for_save_location = false;
    226     info_->url_chain.push_back(GURL());
    227     info_->etag = "SomethingToSatisfyResumption";
    228 
    229     DownloadItemImpl* download =
    230         new DownloadItemImpl(
    231             &delegate_, next_id++, *(info_.get()), net::BoundNetLog());
    232     allocated_downloads_.insert(download);
    233     return download;
    234   }
    235 
    236   // Add DownloadFile to DownloadItem
    237   MockDownloadFile* AddDownloadFileToDownloadItem(
    238       DownloadItemImpl* item,
    239       DownloadItemImplDelegate::DownloadTargetCallback *callback) {
    240     MockDownloadFile* mock_download_file(new StrictMock<MockDownloadFile>);
    241     scoped_ptr<DownloadFile> download_file(mock_download_file);
    242     EXPECT_CALL(*mock_download_file, Initialize(_));
    243     if (callback) {
    244       // Save the callback.
    245       EXPECT_CALL(*mock_delegate(), DetermineDownloadTarget(item, _))
    246           .WillOnce(SaveArg<1>(callback));
    247     } else {
    248       // Drop it on the floor.
    249       EXPECT_CALL(*mock_delegate(), DetermineDownloadTarget(item, _));
    250     }
    251 
    252     scoped_ptr<DownloadRequestHandleInterface> request_handle(
    253         new NiceMock<MockRequestHandle>);
    254     item->Start(download_file.Pass(), request_handle.Pass());
    255     loop_.RunUntilIdle();
    256 
    257     // So that we don't have a function writing to a stack variable
    258     // lying around if the above failed.
    259     mock_delegate()->VerifyAndClearExpectations();
    260     EXPECT_CALL(*mock_delegate(), AssertStateConsistent(_))
    261         .WillRepeatedly(Return());
    262     EXPECT_CALL(*mock_delegate(), ShouldOpenFileBasedOnExtension(_))
    263         .WillRepeatedly(Return(false));
    264     EXPECT_CALL(*mock_delegate(), ShouldOpenDownload(_, _))
    265         .WillRepeatedly(Return(true));
    266 
    267     return mock_download_file;
    268   }
    269 
    270   // Perform the intermediate rename for |item|. The target path for the
    271   // download will be set to kDummyPath. Returns the MockDownloadFile* that was
    272   // added to the DownloadItem.
    273   MockDownloadFile* DoIntermediateRename(DownloadItemImpl* item,
    274                                          DownloadDangerType danger_type) {
    275     EXPECT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
    276     EXPECT_TRUE(item->GetTargetFilePath().empty());
    277     DownloadItemImplDelegate::DownloadTargetCallback callback;
    278     MockDownloadFile* download_file =
    279         AddDownloadFileToDownloadItem(item, &callback);
    280     base::FilePath target_path(kDummyPath);
    281     base::FilePath intermediate_path(
    282         target_path.InsertBeforeExtensionASCII("x"));
    283     EXPECT_CALL(*download_file, RenameAndUniquify(intermediate_path, _))
    284         .WillOnce(ScheduleRenameCallback(DOWNLOAD_INTERRUPT_REASON_NONE,
    285                                          intermediate_path));
    286     callback.Run(target_path, DownloadItem::TARGET_DISPOSITION_OVERWRITE,
    287                  danger_type, intermediate_path);
    288     RunAllPendingInMessageLoops();
    289     return download_file;
    290   }
    291 
    292   // Cleanup a download item (specifically get rid of the DownloadFile on it).
    293   // The item must be in the expected state.
    294   void CleanupItem(DownloadItemImpl* item,
    295                    MockDownloadFile* download_file,
    296                    DownloadItem::DownloadState expected_state) {
    297     EXPECT_EQ(expected_state, item->GetState());
    298 
    299     if (expected_state == DownloadItem::IN_PROGRESS) {
    300       EXPECT_CALL(*download_file, Cancel());
    301       item->Cancel(true);
    302       loop_.RunUntilIdle();
    303     }
    304   }
    305 
    306   // Destroy a previously created download item.
    307   void DestroyDownloadItem(DownloadItem* item) {
    308     allocated_downloads_.erase(item);
    309     delete item;
    310   }
    311 
    312   void RunAllPendingInMessageLoops() {
    313     loop_.RunUntilIdle();
    314   }
    315 
    316   MockDelegate* mock_delegate() {
    317     return &delegate_;
    318   }
    319 
    320   void OnDownloadFileAcquired(base::FilePath* return_path,
    321                               const base::FilePath& path) {
    322     *return_path = path;
    323   }
    324 
    325  private:
    326   base::MessageLoopForUI loop_;
    327   TestBrowserThread ui_thread_;    // UI thread
    328   TestBrowserThread file_thread_;  // FILE thread
    329   StrictMock<MockDelegate> delegate_;
    330   std::set<DownloadItem*> allocated_downloads_;
    331 };
    332 
    333 // Tests to ensure calls that change a DownloadItem generate an update to
    334 // observers.
    335 // State changing functions not tested:
    336 //  void OpenDownload();
    337 //  void ShowDownloadInShell();
    338 //  void CompleteDelayedDownload();
    339 //  set_* mutators
    340 
    341 TEST_F(DownloadItemTest, NotificationAfterUpdate) {
    342   DownloadItemImpl* item = CreateDownloadItem();
    343   MockObserver observer(item);
    344 
    345   item->DestinationUpdate(kDownloadChunkSize, kDownloadSpeed, std::string());
    346   ASSERT_TRUE(observer.CheckUpdated());
    347   EXPECT_EQ(kDownloadSpeed, item->CurrentSpeed());
    348 }
    349 
    350 TEST_F(DownloadItemTest, NotificationAfterCancel) {
    351   DownloadItemImpl* user_cancel = CreateDownloadItem();
    352   MockDownloadFile* download_file =
    353       AddDownloadFileToDownloadItem(user_cancel, NULL);
    354   EXPECT_CALL(*download_file, Cancel());
    355   MockObserver observer1(user_cancel);
    356 
    357   user_cancel->Cancel(true);
    358   ASSERT_TRUE(observer1.CheckUpdated());
    359 
    360   DownloadItemImpl* system_cancel = CreateDownloadItem();
    361   download_file = AddDownloadFileToDownloadItem(system_cancel, NULL);
    362   EXPECT_CALL(*download_file, Cancel());
    363   MockObserver observer2(system_cancel);
    364 
    365   system_cancel->Cancel(false);
    366   ASSERT_TRUE(observer2.CheckUpdated());
    367 }
    368 
    369 TEST_F(DownloadItemTest, NotificationAfterComplete) {
    370   DownloadItemImpl* item = CreateDownloadItem();
    371   MockObserver observer(item);
    372 
    373   item->OnAllDataSaved(DownloadItem::kEmptyFileHash);
    374   ASSERT_TRUE(observer.CheckUpdated());
    375 
    376   item->MarkAsComplete();
    377   ASSERT_TRUE(observer.CheckUpdated());
    378 }
    379 
    380 TEST_F(DownloadItemTest, NotificationAfterDownloadedFileRemoved) {
    381   DownloadItemImpl* item = CreateDownloadItem();
    382   MockObserver observer(item);
    383 
    384   item->OnDownloadedFileRemoved();
    385   ASSERT_TRUE(observer.CheckUpdated());
    386 }
    387 
    388 TEST_F(DownloadItemTest, NotificationAfterInterrupted) {
    389   DownloadItemImpl* item = CreateDownloadItem();
    390   MockDownloadFile* download_file =
    391       DoIntermediateRename(item, DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS);
    392   EXPECT_CALL(*download_file, Cancel());
    393   MockObserver observer(item);
    394 
    395   EXPECT_CALL(*mock_delegate(), MockResumeInterruptedDownload(_,_))
    396       .Times(0);
    397 
    398   item->DestinationObserverAsWeakPtr()->DestinationError(
    399       DOWNLOAD_INTERRUPT_REASON_FILE_FAILED);
    400   ASSERT_TRUE(observer.CheckUpdated());
    401 }
    402 
    403 TEST_F(DownloadItemTest, NotificationAfterDestroyed) {
    404   DownloadItemImpl* item = CreateDownloadItem();
    405   MockObserver observer(item);
    406 
    407   DestroyDownloadItem(item);
    408   ASSERT_TRUE(observer.CheckDestroyed());
    409 }
    410 
    411 TEST_F(DownloadItemTest, ContinueAfterInterrupted) {
    412   CommandLine::ForCurrentProcess()->AppendSwitch(
    413       switches::kEnableDownloadResumption);
    414 
    415   DownloadItemImpl* item = CreateDownloadItem();
    416   MockObserver observer(item);
    417   DownloadItemImplDelegate::DownloadTargetCallback callback;
    418   MockDownloadFile* download_file =
    419       DoIntermediateRename(item, DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS);
    420 
    421   // Interrupt the download, using a continuable interrupt.
    422   EXPECT_CALL(*download_file, FullPath())
    423       .WillOnce(Return(base::FilePath()));
    424   EXPECT_CALL(*download_file, Detach());
    425   item->DestinationObserverAsWeakPtr()->DestinationError(
    426       DOWNLOAD_INTERRUPT_REASON_FILE_TRANSIENT_ERROR);
    427   ASSERT_TRUE(observer.CheckUpdated());
    428   // Should attempt to auto-resume.  Because we don't have a mock WebContents,
    429   // ResumeInterruptedDownload() will abort early, with another interrupt,
    430   // which will be ignored.
    431   ASSERT_EQ(1, observer.GetInterruptCount());
    432   ASSERT_EQ(0, observer.GetResumeCount());
    433   RunAllPendingInMessageLoops();
    434 
    435   CleanupItem(item, download_file, DownloadItem::INTERRUPTED);
    436 }
    437 
    438 // Same as above, but with a non-continuable interrupt.
    439 TEST_F(DownloadItemTest, RestartAfterInterrupted) {
    440   CommandLine::ForCurrentProcess()->AppendSwitch(
    441       switches::kEnableDownloadResumption);
    442 
    443   DownloadItemImpl* item = CreateDownloadItem();
    444   MockObserver observer(item);
    445   DownloadItemImplDelegate::DownloadTargetCallback callback;
    446   MockDownloadFile* download_file =
    447       DoIntermediateRename(item, DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS);
    448 
    449   // Interrupt the download, using a restartable interrupt.
    450   EXPECT_CALL(*download_file, Cancel());
    451   item->DestinationObserverAsWeakPtr()->DestinationError(
    452       DOWNLOAD_INTERRUPT_REASON_FILE_FAILED);
    453   ASSERT_TRUE(observer.CheckUpdated());
    454   // Should not try to auto-resume.
    455   ASSERT_EQ(1, observer.GetInterruptCount());
    456   ASSERT_EQ(0, observer.GetResumeCount());
    457   RunAllPendingInMessageLoops();
    458 
    459   CleanupItem(item, download_file, DownloadItem::INTERRUPTED);
    460 }
    461 
    462 TEST_F(DownloadItemTest, LimitRestartsAfterInterrupted) {
    463   CommandLine::ForCurrentProcess()->AppendSwitch(
    464       switches::kEnableDownloadResumption);
    465 
    466   DownloadItemImpl* item = CreateDownloadItem();
    467   base::WeakPtr<DownloadDestinationObserver> as_observer(
    468       item->DestinationObserverAsWeakPtr());
    469   MockObserver observer(item);
    470   MockDownloadFile* mock_download_file(NULL);
    471   scoped_ptr<DownloadFile> download_file;
    472   MockRequestHandle* mock_request_handle(NULL);
    473   scoped_ptr<DownloadRequestHandleInterface> request_handle;
    474   DownloadItemImplDelegate::DownloadTargetCallback callback;
    475 
    476   EXPECT_CALL(*mock_delegate(), DetermineDownloadTarget(item, _))
    477       .WillRepeatedly(SaveArg<1>(&callback));
    478   for (int i = 0; i < (DownloadItemImpl::kMaxAutoResumeAttempts + 1); ++i) {
    479     DVLOG(20) << "Loop iteration " << i;
    480 
    481     mock_download_file = new NiceMock<MockDownloadFile>;
    482     download_file.reset(mock_download_file);
    483     mock_request_handle = new NiceMock<MockRequestHandle>;
    484     request_handle.reset(mock_request_handle);
    485 
    486     ON_CALL(*mock_download_file, FullPath())
    487         .WillByDefault(Return(base::FilePath()));
    488 
    489     // It's too complicated to set up a WebContents instance that would cause
    490     // the MockDownloadItemDelegate's ResumeInterruptedDownload() function
    491     // to be callled, so we simply verify that GetWebContents() is called.
    492     if (i < (DownloadItemImpl::kMaxAutoResumeAttempts - 1)) {
    493       EXPECT_CALL(*mock_request_handle, GetWebContents())
    494           .WillRepeatedly(Return(static_cast<WebContents*>(NULL)));
    495     }
    496 
    497     // Copied key parts of DoIntermediateRename & AddDownloadFileToDownloadItem
    498     // to allow for holding onto the request handle.
    499     item->Start(download_file.Pass(), request_handle.Pass());
    500     RunAllPendingInMessageLoops();
    501     if (i == 0) {
    502       // Target determination is only done the first time through.
    503       base::FilePath target_path(kDummyPath);
    504       base::FilePath intermediate_path(
    505           target_path.InsertBeforeExtensionASCII("x"));
    506       EXPECT_CALL(*mock_download_file, RenameAndUniquify(intermediate_path, _))
    507           .WillOnce(ScheduleRenameCallback(DOWNLOAD_INTERRUPT_REASON_NONE,
    508                                            intermediate_path));
    509       callback.Run(target_path, DownloadItem::TARGET_DISPOSITION_OVERWRITE,
    510                    DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, intermediate_path);
    511       RunAllPendingInMessageLoops();
    512     }
    513     ASSERT_EQ(i, observer.GetResumeCount());
    514 
    515     // Use a continuable interrupt.
    516     item->DestinationObserverAsWeakPtr()->DestinationError(
    517         DOWNLOAD_INTERRUPT_REASON_FILE_TRANSIENT_ERROR);
    518 
    519     ASSERT_EQ(i + 1, observer.GetInterruptCount());
    520     ::testing::Mock::VerifyAndClearExpectations(mock_download_file);
    521   }
    522 
    523   CleanupItem(item, mock_download_file, DownloadItem::INTERRUPTED);
    524 }
    525 
    526 TEST_F(DownloadItemTest, NotificationAfterRemove) {
    527   DownloadItemImpl* item = CreateDownloadItem();
    528   MockDownloadFile* download_file = AddDownloadFileToDownloadItem(item, NULL);
    529   EXPECT_CALL(*download_file, Cancel());
    530   EXPECT_CALL(*mock_delegate(), DownloadRemoved(_));
    531   MockObserver observer(item);
    532 
    533   item->Remove();
    534   ASSERT_TRUE(observer.CheckUpdated());
    535   ASSERT_TRUE(observer.CheckRemoved());
    536 }
    537 
    538 TEST_F(DownloadItemTest, NotificationAfterOnContentCheckCompleted) {
    539   // Setting to NOT_DANGEROUS does not trigger a notification.
    540   DownloadItemImpl* safe_item = CreateDownloadItem();
    541   MockObserver safe_observer(safe_item);
    542 
    543   safe_item->OnAllDataSaved(std::string());
    544   EXPECT_TRUE(safe_observer.CheckUpdated());
    545   safe_item->OnContentCheckCompleted(DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS);
    546   EXPECT_TRUE(safe_observer.CheckUpdated());
    547 
    548   // Setting to unsafe url or unsafe file should trigger a notification.
    549   DownloadItemImpl* unsafeurl_item =
    550       CreateDownloadItem();
    551   MockObserver unsafeurl_observer(unsafeurl_item);
    552 
    553   unsafeurl_item->OnAllDataSaved(std::string());
    554   EXPECT_TRUE(unsafeurl_observer.CheckUpdated());
    555   unsafeurl_item->OnContentCheckCompleted(DOWNLOAD_DANGER_TYPE_DANGEROUS_URL);
    556   EXPECT_TRUE(unsafeurl_observer.CheckUpdated());
    557 
    558   unsafeurl_item->ValidateDangerousDownload();
    559   EXPECT_TRUE(unsafeurl_observer.CheckUpdated());
    560 
    561   DownloadItemImpl* unsafefile_item =
    562       CreateDownloadItem();
    563   MockObserver unsafefile_observer(unsafefile_item);
    564 
    565   unsafefile_item->OnAllDataSaved(std::string());
    566   EXPECT_TRUE(unsafefile_observer.CheckUpdated());
    567   unsafefile_item->OnContentCheckCompleted(DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE);
    568   EXPECT_TRUE(unsafefile_observer.CheckUpdated());
    569 
    570   unsafefile_item->ValidateDangerousDownload();
    571   EXPECT_TRUE(unsafefile_observer.CheckUpdated());
    572 }
    573 
    574 // DownloadItemImpl::OnDownloadTargetDetermined will schedule a task to run
    575 // DownloadFile::Rename(). Once the rename
    576 // completes, DownloadItemImpl receives a notification with the new file
    577 // name. Check that observers are updated when the new filename is available and
    578 // not before.
    579 TEST_F(DownloadItemTest, NotificationAfterOnDownloadTargetDetermined) {
    580   DownloadItemImpl* item = CreateDownloadItem();
    581   DownloadItemImplDelegate::DownloadTargetCallback callback;
    582   MockDownloadFile* download_file =
    583       AddDownloadFileToDownloadItem(item, &callback);
    584   MockObserver observer(item);
    585   base::FilePath target_path(kDummyPath);
    586   base::FilePath intermediate_path(target_path.InsertBeforeExtensionASCII("x"));
    587   base::FilePath new_intermediate_path(
    588       target_path.InsertBeforeExtensionASCII("y"));
    589   EXPECT_CALL(*download_file, RenameAndUniquify(intermediate_path, _))
    590       .WillOnce(ScheduleRenameCallback(DOWNLOAD_INTERRUPT_REASON_NONE,
    591                                        new_intermediate_path));
    592 
    593   // Currently, a notification would be generated if the danger type is anything
    594   // other than NOT_DANGEROUS.
    595   callback.Run(target_path, DownloadItem::TARGET_DISPOSITION_OVERWRITE,
    596                DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, intermediate_path);
    597   EXPECT_FALSE(observer.CheckUpdated());
    598   RunAllPendingInMessageLoops();
    599   EXPECT_TRUE(observer.CheckUpdated());
    600   EXPECT_EQ(new_intermediate_path, item->GetFullPath());
    601 
    602   CleanupItem(item, download_file, DownloadItem::IN_PROGRESS);
    603 }
    604 
    605 TEST_F(DownloadItemTest, NotificationAfterTogglePause) {
    606   DownloadItemImpl* item = CreateDownloadItem();
    607   MockObserver observer(item);
    608   MockDownloadFile* mock_download_file(new MockDownloadFile);
    609   scoped_ptr<DownloadFile> download_file(mock_download_file);
    610   scoped_ptr<DownloadRequestHandleInterface> request_handle(
    611       new NiceMock<MockRequestHandle>);
    612 
    613   EXPECT_CALL(*mock_download_file, Initialize(_));
    614   EXPECT_CALL(*mock_delegate(), DetermineDownloadTarget(_, _));
    615   item->Start(download_file.Pass(), request_handle.Pass());
    616 
    617   item->Pause();
    618   ASSERT_TRUE(observer.CheckUpdated());
    619 
    620   ASSERT_TRUE(item->IsPaused());
    621 
    622   item->Resume();
    623   ASSERT_TRUE(observer.CheckUpdated());
    624 
    625   RunAllPendingInMessageLoops();
    626 
    627   CleanupItem(item, mock_download_file, DownloadItem::IN_PROGRESS);
    628 }
    629 
    630 TEST_F(DownloadItemTest, DisplayName) {
    631   DownloadItemImpl* item = CreateDownloadItem();
    632   DownloadItemImplDelegate::DownloadTargetCallback callback;
    633   MockDownloadFile* download_file =
    634       AddDownloadFileToDownloadItem(item, &callback);
    635   base::FilePath target_path(base::FilePath(kDummyPath).AppendASCII("foo.bar"));
    636   base::FilePath intermediate_path(target_path.InsertBeforeExtensionASCII("x"));
    637   EXPECT_EQ(FILE_PATH_LITERAL(""),
    638             item->GetFileNameToReportUser().value());
    639   EXPECT_CALL(*download_file, RenameAndUniquify(_, _))
    640       .WillOnce(ScheduleRenameCallback(DOWNLOAD_INTERRUPT_REASON_NONE,
    641                                        intermediate_path));
    642   callback.Run(target_path, DownloadItem::TARGET_DISPOSITION_OVERWRITE,
    643                DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, intermediate_path);
    644   RunAllPendingInMessageLoops();
    645   EXPECT_EQ(FILE_PATH_LITERAL("foo.bar"),
    646             item->GetFileNameToReportUser().value());
    647   item->SetDisplayName(base::FilePath(FILE_PATH_LITERAL("new.name")));
    648   EXPECT_EQ(FILE_PATH_LITERAL("new.name"),
    649             item->GetFileNameToReportUser().value());
    650   CleanupItem(item, download_file, DownloadItem::IN_PROGRESS);
    651 }
    652 
    653 // Test to make sure that Start method calls DF initialize properly.
    654 TEST_F(DownloadItemTest, Start) {
    655   MockDownloadFile* mock_download_file(new MockDownloadFile);
    656   scoped_ptr<DownloadFile> download_file(mock_download_file);
    657   DownloadItemImpl* item = CreateDownloadItem();
    658   EXPECT_CALL(*mock_download_file, Initialize(_));
    659   scoped_ptr<DownloadRequestHandleInterface> request_handle(
    660       new NiceMock<MockRequestHandle>);
    661   EXPECT_CALL(*mock_delegate(), DetermineDownloadTarget(item, _));
    662   item->Start(download_file.Pass(), request_handle.Pass());
    663   RunAllPendingInMessageLoops();
    664 
    665   CleanupItem(item, mock_download_file, DownloadItem::IN_PROGRESS);
    666 }
    667 
    668 // Test that the delegate is invoked after the download file is renamed.
    669 TEST_F(DownloadItemTest, CallbackAfterRename) {
    670   DownloadItemImpl* item = CreateDownloadItem();
    671   DownloadItemImplDelegate::DownloadTargetCallback callback;
    672   MockDownloadFile* download_file =
    673       AddDownloadFileToDownloadItem(item, &callback);
    674   base::FilePath final_path(base::FilePath(kDummyPath).AppendASCII("foo.bar"));
    675   base::FilePath intermediate_path(final_path.InsertBeforeExtensionASCII("x"));
    676   base::FilePath new_intermediate_path(
    677       final_path.InsertBeforeExtensionASCII("y"));
    678   EXPECT_CALL(*download_file, RenameAndUniquify(intermediate_path, _))
    679       .WillOnce(ScheduleRenameCallback(DOWNLOAD_INTERRUPT_REASON_NONE,
    680                                        new_intermediate_path));
    681 
    682   callback.Run(final_path, DownloadItem::TARGET_DISPOSITION_OVERWRITE,
    683                DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, intermediate_path);
    684   RunAllPendingInMessageLoops();
    685   // All the callbacks should have happened by now.
    686   ::testing::Mock::VerifyAndClearExpectations(download_file);
    687   mock_delegate()->VerifyAndClearExpectations();
    688 
    689   EXPECT_CALL(*mock_delegate(), ShouldCompleteDownload(item, _))
    690       .WillOnce(Return(true));
    691   EXPECT_CALL(*download_file, RenameAndAnnotate(final_path, _))
    692       .WillOnce(ScheduleRenameCallback(DOWNLOAD_INTERRUPT_REASON_NONE,
    693                                        final_path));
    694   EXPECT_CALL(*download_file, FullPath())
    695       .WillOnce(Return(base::FilePath()));
    696   EXPECT_CALL(*download_file, Detach());
    697   item->DestinationObserverAsWeakPtr()->DestinationCompleted(std::string());
    698   RunAllPendingInMessageLoops();
    699   ::testing::Mock::VerifyAndClearExpectations(download_file);
    700   mock_delegate()->VerifyAndClearExpectations();
    701 }
    702 
    703 // Test that the delegate is invoked after the download file is renamed and the
    704 // download item is in an interrupted state.
    705 TEST_F(DownloadItemTest, CallbackAfterInterruptedRename) {
    706   DownloadItemImpl* item = CreateDownloadItem();
    707   DownloadItemImplDelegate::DownloadTargetCallback callback;
    708   MockDownloadFile* download_file =
    709       AddDownloadFileToDownloadItem(item, &callback);
    710   base::FilePath final_path(base::FilePath(kDummyPath).AppendASCII("foo.bar"));
    711   base::FilePath intermediate_path(final_path.InsertBeforeExtensionASCII("x"));
    712   base::FilePath new_intermediate_path(
    713       final_path.InsertBeforeExtensionASCII("y"));
    714   EXPECT_CALL(*download_file, RenameAndUniquify(intermediate_path, _))
    715       .WillOnce(ScheduleRenameCallback(DOWNLOAD_INTERRUPT_REASON_FILE_FAILED,
    716                                        new_intermediate_path));
    717   EXPECT_CALL(*download_file, Cancel())
    718       .Times(1);
    719 
    720   callback.Run(final_path, DownloadItem::TARGET_DISPOSITION_OVERWRITE,
    721                DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, intermediate_path);
    722   RunAllPendingInMessageLoops();
    723   // All the callbacks should have happened by now.
    724   ::testing::Mock::VerifyAndClearExpectations(download_file);
    725   mock_delegate()->VerifyAndClearExpectations();
    726 }
    727 
    728 TEST_F(DownloadItemTest, Interrupted) {
    729   DownloadItemImpl* item = CreateDownloadItem();
    730   MockDownloadFile* download_file =
    731       DoIntermediateRename(item, DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS);
    732 
    733   const DownloadInterruptReason reason(
    734       DOWNLOAD_INTERRUPT_REASON_FILE_ACCESS_DENIED);
    735 
    736   // Confirm interrupt sets state properly.
    737   EXPECT_CALL(*download_file, Cancel());
    738   item->DestinationObserverAsWeakPtr()->DestinationError(reason);
    739   RunAllPendingInMessageLoops();
    740   EXPECT_EQ(DownloadItem::INTERRUPTED, item->GetState());
    741   EXPECT_EQ(reason, item->GetLastReason());
    742 
    743   // Cancel should kill it.
    744   item->Cancel(true);
    745   EXPECT_EQ(DownloadItem::CANCELLED, item->GetState());
    746   EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_USER_CANCELED, item->GetLastReason());
    747 }
    748 
    749 // Destination errors that occur before the intermediate rename shouldn't cause
    750 // the download to be marked as interrupted until after the intermediate rename.
    751 TEST_F(DownloadItemTest, InterruptedBeforeIntermediateRename_Restart) {
    752   DownloadItemImpl* item = CreateDownloadItem();
    753   DownloadItemImplDelegate::DownloadTargetCallback callback;
    754   MockDownloadFile* download_file =
    755       AddDownloadFileToDownloadItem(item, &callback);
    756   item->DestinationObserverAsWeakPtr()->DestinationError(
    757       DOWNLOAD_INTERRUPT_REASON_FILE_FAILED);
    758   ASSERT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
    759 
    760   base::FilePath final_path(base::FilePath(kDummyPath).AppendASCII("foo.bar"));
    761   base::FilePath intermediate_path(final_path.InsertBeforeExtensionASCII("x"));
    762   base::FilePath new_intermediate_path(
    763       final_path.InsertBeforeExtensionASCII("y"));
    764   EXPECT_CALL(*download_file, RenameAndUniquify(intermediate_path, _))
    765       .WillOnce(ScheduleRenameCallback(DOWNLOAD_INTERRUPT_REASON_NONE,
    766                                        new_intermediate_path));
    767   EXPECT_CALL(*download_file, Cancel())
    768       .Times(1);
    769 
    770   callback.Run(final_path, DownloadItem::TARGET_DISPOSITION_OVERWRITE,
    771                DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, intermediate_path);
    772   RunAllPendingInMessageLoops();
    773   // All the callbacks should have happened by now.
    774   ::testing::Mock::VerifyAndClearExpectations(download_file);
    775   mock_delegate()->VerifyAndClearExpectations();
    776   EXPECT_EQ(DownloadItem::INTERRUPTED, item->GetState());
    777   EXPECT_TRUE(item->GetFullPath().empty());
    778   EXPECT_EQ(final_path, item->GetTargetFilePath());
    779 }
    780 
    781 // As above. But if the download can be resumed by continuing, then the
    782 // intermediate path should be retained when the download is interrupted after
    783 // the intermediate rename succeeds.
    784 TEST_F(DownloadItemTest, InterruptedBeforeIntermediateRename_Continue) {
    785   CommandLine::ForCurrentProcess()->AppendSwitch(
    786       switches::kEnableDownloadResumption);
    787   DownloadItemImpl* item = CreateDownloadItem();
    788   DownloadItemImplDelegate::DownloadTargetCallback callback;
    789   MockDownloadFile* download_file =
    790       AddDownloadFileToDownloadItem(item, &callback);
    791   item->DestinationObserverAsWeakPtr()->DestinationError(
    792       DOWNLOAD_INTERRUPT_REASON_NETWORK_FAILED);
    793   ASSERT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
    794 
    795   base::FilePath final_path(base::FilePath(kDummyPath).AppendASCII("foo.bar"));
    796   base::FilePath intermediate_path(final_path.InsertBeforeExtensionASCII("x"));
    797   base::FilePath new_intermediate_path(
    798       final_path.InsertBeforeExtensionASCII("y"));
    799   EXPECT_CALL(*download_file, RenameAndUniquify(intermediate_path, _))
    800       .WillOnce(ScheduleRenameCallback(DOWNLOAD_INTERRUPT_REASON_NONE,
    801                                        new_intermediate_path));
    802   EXPECT_CALL(*download_file, FullPath())
    803       .WillOnce(Return(base::FilePath(new_intermediate_path)));
    804   EXPECT_CALL(*download_file, Detach());
    805 
    806   callback.Run(final_path, DownloadItem::TARGET_DISPOSITION_OVERWRITE,
    807                DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, intermediate_path);
    808   RunAllPendingInMessageLoops();
    809   // All the callbacks should have happened by now.
    810   ::testing::Mock::VerifyAndClearExpectations(download_file);
    811   mock_delegate()->VerifyAndClearExpectations();
    812   EXPECT_EQ(DownloadItem::INTERRUPTED, item->GetState());
    813   EXPECT_EQ(new_intermediate_path, item->GetFullPath());
    814   EXPECT_EQ(final_path, item->GetTargetFilePath());
    815 }
    816 
    817 // As above. If the intermediate rename fails, then the interrupt reason should
    818 // be set to the destination error and the intermediate path should be empty.
    819 TEST_F(DownloadItemTest, InterruptedBeforeIntermediateRename_Failed) {
    820   CommandLine::ForCurrentProcess()->AppendSwitch(
    821       switches::kEnableDownloadResumption);
    822   DownloadItemImpl* item = CreateDownloadItem();
    823   DownloadItemImplDelegate::DownloadTargetCallback callback;
    824   MockDownloadFile* download_file =
    825       AddDownloadFileToDownloadItem(item, &callback);
    826   item->DestinationObserverAsWeakPtr()->DestinationError(
    827       DOWNLOAD_INTERRUPT_REASON_NETWORK_FAILED);
    828   ASSERT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
    829 
    830   base::FilePath final_path(base::FilePath(kDummyPath).AppendASCII("foo.bar"));
    831   base::FilePath intermediate_path(final_path.InsertBeforeExtensionASCII("x"));
    832   base::FilePath new_intermediate_path(
    833       final_path.InsertBeforeExtensionASCII("y"));
    834   EXPECT_CALL(*download_file, RenameAndUniquify(intermediate_path, _))
    835       .WillOnce(ScheduleRenameCallback(DOWNLOAD_INTERRUPT_REASON_FILE_FAILED,
    836                                        new_intermediate_path));
    837   EXPECT_CALL(*download_file, Cancel())
    838       .Times(1);
    839 
    840   callback.Run(final_path, DownloadItem::TARGET_DISPOSITION_OVERWRITE,
    841                DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, intermediate_path);
    842   RunAllPendingInMessageLoops();
    843   // All the callbacks should have happened by now.
    844   ::testing::Mock::VerifyAndClearExpectations(download_file);
    845   mock_delegate()->VerifyAndClearExpectations();
    846   EXPECT_EQ(DownloadItem::INTERRUPTED, item->GetState());
    847   EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NETWORK_FAILED, item->GetLastReason());
    848   EXPECT_TRUE(item->GetFullPath().empty());
    849   EXPECT_EQ(final_path, item->GetTargetFilePath());
    850 }
    851 
    852 TEST_F(DownloadItemTest, Canceled) {
    853   DownloadItemImpl* item = CreateDownloadItem();
    854   MockDownloadFile* download_file = AddDownloadFileToDownloadItem(item, NULL);
    855 
    856   // Confirm cancel sets state properly.
    857   EXPECT_CALL(*download_file, Cancel());
    858   item->Cancel(true);
    859   EXPECT_EQ(DownloadItem::CANCELLED, item->GetState());
    860 }
    861 
    862 TEST_F(DownloadItemTest, FileRemoved) {
    863   DownloadItemImpl* item = CreateDownloadItem();
    864 
    865   EXPECT_FALSE(item->GetFileExternallyRemoved());
    866   item->OnDownloadedFileRemoved();
    867   EXPECT_TRUE(item->GetFileExternallyRemoved());
    868 }
    869 
    870 TEST_F(DownloadItemTest, DestinationUpdate) {
    871   DownloadItemImpl* item = CreateDownloadItem();
    872   base::WeakPtr<DownloadDestinationObserver> as_observer(
    873       item->DestinationObserverAsWeakPtr());
    874   MockObserver observer(item);
    875 
    876   EXPECT_EQ(0l, item->CurrentSpeed());
    877   EXPECT_EQ("", item->GetHashState());
    878   EXPECT_EQ(0l, item->GetReceivedBytes());
    879   EXPECT_EQ(0l, item->GetTotalBytes());
    880   EXPECT_FALSE(observer.CheckUpdated());
    881   item->SetTotalBytes(100l);
    882   EXPECT_EQ(100l, item->GetTotalBytes());
    883 
    884   as_observer->DestinationUpdate(10, 20, "deadbeef");
    885   EXPECT_EQ(20l, item->CurrentSpeed());
    886   EXPECT_EQ("deadbeef", item->GetHashState());
    887   EXPECT_EQ(10l, item->GetReceivedBytes());
    888   EXPECT_EQ(100l, item->GetTotalBytes());
    889   EXPECT_TRUE(observer.CheckUpdated());
    890 
    891   as_observer->DestinationUpdate(200, 20, "livebeef");
    892   EXPECT_EQ(20l, item->CurrentSpeed());
    893   EXPECT_EQ("livebeef", item->GetHashState());
    894   EXPECT_EQ(200l, item->GetReceivedBytes());
    895   EXPECT_EQ(0l, item->GetTotalBytes());
    896   EXPECT_TRUE(observer.CheckUpdated());
    897 }
    898 
    899 TEST_F(DownloadItemTest, DestinationError) {
    900   DownloadItemImpl* item = CreateDownloadItem();
    901   MockDownloadFile* download_file =
    902       DoIntermediateRename(item, DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS);
    903   base::WeakPtr<DownloadDestinationObserver> as_observer(
    904       item->DestinationObserverAsWeakPtr());
    905   MockObserver observer(item);
    906 
    907   EXPECT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
    908   EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE, item->GetLastReason());
    909   EXPECT_FALSE(observer.CheckUpdated());
    910 
    911   EXPECT_CALL(*download_file, Cancel());
    912   as_observer->DestinationError(
    913       DOWNLOAD_INTERRUPT_REASON_FILE_ACCESS_DENIED);
    914   mock_delegate()->VerifyAndClearExpectations();
    915   EXPECT_TRUE(observer.CheckUpdated());
    916   EXPECT_EQ(DownloadItem::INTERRUPTED, item->GetState());
    917   EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_FILE_ACCESS_DENIED,
    918             item->GetLastReason());
    919 }
    920 
    921 TEST_F(DownloadItemTest, DestinationCompleted) {
    922   DownloadItemImpl* item = CreateDownloadItem();
    923   base::WeakPtr<DownloadDestinationObserver> as_observer(
    924       item->DestinationObserverAsWeakPtr());
    925   MockObserver observer(item);
    926 
    927   EXPECT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
    928   EXPECT_EQ("", item->GetHash());
    929   EXPECT_EQ("", item->GetHashState());
    930   EXPECT_FALSE(item->AllDataSaved());
    931   EXPECT_FALSE(observer.CheckUpdated());
    932 
    933   as_observer->DestinationUpdate(10, 20, "deadbeef");
    934   EXPECT_TRUE(observer.CheckUpdated());
    935   EXPECT_FALSE(observer.CheckUpdated()); // Confirm reset.
    936   EXPECT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
    937   EXPECT_EQ("", item->GetHash());
    938   EXPECT_EQ("deadbeef", item->GetHashState());
    939   EXPECT_FALSE(item->AllDataSaved());
    940 
    941   as_observer->DestinationCompleted("livebeef");
    942   mock_delegate()->VerifyAndClearExpectations();
    943   EXPECT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
    944   EXPECT_TRUE(observer.CheckUpdated());
    945   EXPECT_EQ("livebeef", item->GetHash());
    946   EXPECT_EQ("", item->GetHashState());
    947   EXPECT_TRUE(item->AllDataSaved());
    948 }
    949 
    950 TEST_F(DownloadItemTest, EnabledActionsForNormalDownload) {
    951   DownloadItemImpl* item = CreateDownloadItem();
    952   MockDownloadFile* download_file =
    953       DoIntermediateRename(item, DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS);
    954 
    955   // InProgress
    956   ASSERT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
    957   ASSERT_FALSE(item->GetTargetFilePath().empty());
    958   EXPECT_TRUE(item->CanShowInFolder());
    959   EXPECT_TRUE(item->CanOpenDownload());
    960 
    961   // Complete
    962   EXPECT_CALL(*download_file, RenameAndAnnotate(_, _))
    963       .WillOnce(ScheduleRenameCallback(DOWNLOAD_INTERRUPT_REASON_NONE,
    964                                        base::FilePath(kDummyPath)));
    965   EXPECT_CALL(*mock_delegate(), ShouldCompleteDownload(item, _))
    966       .WillOnce(Return(true));
    967   EXPECT_CALL(*download_file, FullPath())
    968       .WillOnce(Return(base::FilePath()));
    969   EXPECT_CALL(*download_file, Detach());
    970   item->DestinationObserverAsWeakPtr()->DestinationCompleted(std::string());
    971   RunAllPendingInMessageLoops();
    972 
    973   ASSERT_EQ(DownloadItem::COMPLETE, item->GetState());
    974   EXPECT_TRUE(item->CanShowInFolder());
    975   EXPECT_TRUE(item->CanOpenDownload());
    976 }
    977 
    978 TEST_F(DownloadItemTest, EnabledActionsForTemporaryDownload) {
    979   DownloadItemImpl* item = CreateDownloadItem();
    980   MockDownloadFile* download_file =
    981       DoIntermediateRename(item, DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS);
    982   item->SetIsTemporary(true);
    983 
    984   // InProgress Temporary
    985   ASSERT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
    986   ASSERT_FALSE(item->GetTargetFilePath().empty());
    987   ASSERT_TRUE(item->IsTemporary());
    988   EXPECT_FALSE(item->CanShowInFolder());
    989   EXPECT_FALSE(item->CanOpenDownload());
    990 
    991   // Complete Temporary
    992   EXPECT_CALL(*mock_delegate(), ShouldCompleteDownload(item, _))
    993       .WillOnce(Return(true));
    994   EXPECT_CALL(*download_file, RenameAndAnnotate(_, _))
    995       .WillOnce(ScheduleRenameCallback(DOWNLOAD_INTERRUPT_REASON_NONE,
    996                                        base::FilePath(kDummyPath)));
    997   EXPECT_CALL(*download_file, FullPath())
    998       .WillOnce(Return(base::FilePath()));
    999   EXPECT_CALL(*download_file, Detach());
   1000   item->DestinationObserverAsWeakPtr()->DestinationCompleted(std::string());
   1001   RunAllPendingInMessageLoops();
   1002 
   1003   ASSERT_EQ(DownloadItem::COMPLETE, item->GetState());
   1004   EXPECT_FALSE(item->CanShowInFolder());
   1005   EXPECT_FALSE(item->CanOpenDownload());
   1006 }
   1007 
   1008 TEST_F(DownloadItemTest, EnabledActionsForInterruptedDownload) {
   1009   DownloadItemImpl* item = CreateDownloadItem();
   1010   MockDownloadFile* download_file =
   1011       DoIntermediateRename(item, DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS);
   1012 
   1013   EXPECT_CALL(*download_file, Cancel());
   1014   item->DestinationObserverAsWeakPtr()->DestinationError(
   1015       DOWNLOAD_INTERRUPT_REASON_FILE_FAILED);
   1016   RunAllPendingInMessageLoops();
   1017 
   1018   ASSERT_EQ(DownloadItem::INTERRUPTED, item->GetState());
   1019   ASSERT_FALSE(item->GetTargetFilePath().empty());
   1020   EXPECT_FALSE(item->CanShowInFolder());
   1021   EXPECT_FALSE(item->CanOpenDownload());
   1022 }
   1023 
   1024 TEST_F(DownloadItemTest, EnabledActionsForCancelledDownload) {
   1025   DownloadItemImpl* item = CreateDownloadItem();
   1026   MockDownloadFile* download_file =
   1027       DoIntermediateRename(item, DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS);
   1028 
   1029   EXPECT_CALL(*download_file, Cancel());
   1030   item->Cancel(true);
   1031   RunAllPendingInMessageLoops();
   1032 
   1033   ASSERT_EQ(DownloadItem::CANCELLED, item->GetState());
   1034   EXPECT_FALSE(item->CanShowInFolder());
   1035   EXPECT_FALSE(item->CanOpenDownload());
   1036 }
   1037 
   1038 // Test various aspects of the delegate completion blocker.
   1039 
   1040 // Just allowing completion.
   1041 TEST_F(DownloadItemTest, CompleteDelegate_ReturnTrue) {
   1042   // Test to confirm that if we have a callback that returns true,
   1043   // we complete immediately.
   1044   DownloadItemImpl* item = CreateDownloadItem();
   1045   MockDownloadFile* download_file =
   1046       DoIntermediateRename(item, DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS);
   1047 
   1048   // Drive the delegate interaction.
   1049   EXPECT_CALL(*mock_delegate(), ShouldCompleteDownload(item, _))
   1050       .WillOnce(Return(true));
   1051   item->DestinationObserverAsWeakPtr()->DestinationCompleted(std::string());
   1052   EXPECT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
   1053   EXPECT_FALSE(item->IsDangerous());
   1054 
   1055   // Make sure the download can complete.
   1056   EXPECT_CALL(*download_file, RenameAndAnnotate(base::FilePath(kDummyPath), _))
   1057       .WillOnce(ScheduleRenameCallback(DOWNLOAD_INTERRUPT_REASON_NONE,
   1058                                        base::FilePath(kDummyPath)));
   1059   EXPECT_CALL(*mock_delegate(), ShouldOpenDownload(item, _))
   1060       .WillOnce(Return(true));
   1061   EXPECT_CALL(*download_file, FullPath())
   1062       .WillOnce(Return(base::FilePath()));
   1063   EXPECT_CALL(*download_file, Detach());
   1064   RunAllPendingInMessageLoops();
   1065   EXPECT_EQ(DownloadItem::COMPLETE, item->GetState());
   1066 }
   1067 
   1068 // Just delaying completion.
   1069 TEST_F(DownloadItemTest, CompleteDelegate_BlockOnce) {
   1070   // Test to confirm that if we have a callback that returns true,
   1071   // we complete immediately.
   1072   DownloadItemImpl* item = CreateDownloadItem();
   1073   MockDownloadFile* download_file =
   1074       DoIntermediateRename(item, DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS);
   1075 
   1076   // Drive the delegate interaction.
   1077   base::Closure delegate_callback;
   1078   base::Closure copy_delegate_callback;
   1079   EXPECT_CALL(*mock_delegate(), ShouldCompleteDownload(item, _))
   1080       .WillOnce(DoAll(SaveArg<1>(&delegate_callback),
   1081                       Return(false)))
   1082       .WillOnce(Return(true));
   1083   item->DestinationObserverAsWeakPtr()->DestinationCompleted(std::string());
   1084   ASSERT_FALSE(delegate_callback.is_null());
   1085   copy_delegate_callback = delegate_callback;
   1086   delegate_callback.Reset();
   1087   EXPECT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
   1088   copy_delegate_callback.Run();
   1089   ASSERT_TRUE(delegate_callback.is_null());
   1090   EXPECT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
   1091   EXPECT_FALSE(item->IsDangerous());
   1092 
   1093   // Make sure the download can complete.
   1094   EXPECT_CALL(*download_file, RenameAndAnnotate(base::FilePath(kDummyPath), _))
   1095       .WillOnce(ScheduleRenameCallback(DOWNLOAD_INTERRUPT_REASON_NONE,
   1096                                        base::FilePath(kDummyPath)));
   1097   EXPECT_CALL(*mock_delegate(), ShouldOpenDownload(item, _))
   1098       .WillOnce(Return(true));
   1099   EXPECT_CALL(*download_file, FullPath())
   1100       .WillOnce(Return(base::FilePath()));
   1101   EXPECT_CALL(*download_file, Detach());
   1102   RunAllPendingInMessageLoops();
   1103   EXPECT_EQ(DownloadItem::COMPLETE, item->GetState());
   1104 }
   1105 
   1106 // Delay and set danger.
   1107 TEST_F(DownloadItemTest, CompleteDelegate_SetDanger) {
   1108   // Test to confirm that if we have a callback that returns true,
   1109   // we complete immediately.
   1110   DownloadItemImpl* item = CreateDownloadItem();
   1111   MockDownloadFile* download_file =
   1112       DoIntermediateRename(item, DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS);
   1113 
   1114   // Drive the delegate interaction.
   1115   base::Closure delegate_callback;
   1116   base::Closure copy_delegate_callback;
   1117   EXPECT_CALL(*mock_delegate(), ShouldCompleteDownload(item, _))
   1118       .WillOnce(DoAll(SaveArg<1>(&delegate_callback),
   1119                       Return(false)))
   1120       .WillOnce(Return(true));
   1121   item->DestinationObserverAsWeakPtr()->DestinationCompleted(std::string());
   1122   ASSERT_FALSE(delegate_callback.is_null());
   1123   copy_delegate_callback = delegate_callback;
   1124   delegate_callback.Reset();
   1125   EXPECT_FALSE(item->IsDangerous());
   1126   item->OnContentCheckCompleted(
   1127       content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE);
   1128   EXPECT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
   1129   copy_delegate_callback.Run();
   1130   ASSERT_TRUE(delegate_callback.is_null());
   1131   EXPECT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
   1132   EXPECT_TRUE(item->IsDangerous());
   1133 
   1134   // Make sure the download doesn't complete until we've validated it.
   1135   EXPECT_CALL(*download_file, RenameAndAnnotate(base::FilePath(kDummyPath), _))
   1136       .WillOnce(ScheduleRenameCallback(DOWNLOAD_INTERRUPT_REASON_NONE,
   1137                                        base::FilePath(kDummyPath)));
   1138   EXPECT_CALL(*mock_delegate(), ShouldOpenDownload(item, _))
   1139       .WillOnce(Return(true));
   1140   EXPECT_CALL(*download_file, FullPath())
   1141       .WillOnce(Return(base::FilePath()));
   1142   EXPECT_CALL(*download_file, Detach());
   1143   RunAllPendingInMessageLoops();
   1144   EXPECT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
   1145   EXPECT_TRUE(item->IsDangerous());
   1146 
   1147   item->ValidateDangerousDownload();
   1148   EXPECT_EQ(DOWNLOAD_DANGER_TYPE_USER_VALIDATED, item->GetDangerType());
   1149   RunAllPendingInMessageLoops();
   1150   EXPECT_EQ(DownloadItem::COMPLETE, item->GetState());
   1151 }
   1152 
   1153 // Just delaying completion twice.
   1154 TEST_F(DownloadItemTest, CompleteDelegate_BlockTwice) {
   1155   // Test to confirm that if we have a callback that returns true,
   1156   // we complete immediately.
   1157   DownloadItemImpl* item = CreateDownloadItem();
   1158   MockDownloadFile* download_file =
   1159       DoIntermediateRename(item, DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS);
   1160 
   1161   // Drive the delegate interaction.
   1162   base::Closure delegate_callback;
   1163   base::Closure copy_delegate_callback;
   1164   EXPECT_CALL(*mock_delegate(), ShouldCompleteDownload(item, _))
   1165       .WillOnce(DoAll(SaveArg<1>(&delegate_callback),
   1166                       Return(false)))
   1167       .WillOnce(DoAll(SaveArg<1>(&delegate_callback),
   1168                       Return(false)))
   1169       .WillOnce(Return(true));
   1170   item->DestinationObserverAsWeakPtr()->DestinationCompleted(std::string());
   1171   ASSERT_FALSE(delegate_callback.is_null());
   1172   copy_delegate_callback = delegate_callback;
   1173   delegate_callback.Reset();
   1174   EXPECT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
   1175   copy_delegate_callback.Run();
   1176   ASSERT_FALSE(delegate_callback.is_null());
   1177   copy_delegate_callback = delegate_callback;
   1178   delegate_callback.Reset();
   1179   EXPECT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
   1180   copy_delegate_callback.Run();
   1181   ASSERT_TRUE(delegate_callback.is_null());
   1182   EXPECT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
   1183   EXPECT_FALSE(item->IsDangerous());
   1184 
   1185   // Make sure the download can complete.
   1186   EXPECT_CALL(*download_file, RenameAndAnnotate(base::FilePath(kDummyPath), _))
   1187       .WillOnce(ScheduleRenameCallback(DOWNLOAD_INTERRUPT_REASON_NONE,
   1188                                        base::FilePath(kDummyPath)));
   1189   EXPECT_CALL(*mock_delegate(), ShouldOpenDownload(item, _))
   1190       .WillOnce(Return(true));
   1191   EXPECT_CALL(*download_file, FullPath())
   1192       .WillOnce(Return(base::FilePath()));
   1193   EXPECT_CALL(*download_file, Detach());
   1194   RunAllPendingInMessageLoops();
   1195   EXPECT_EQ(DownloadItem::COMPLETE, item->GetState());
   1196 }
   1197 
   1198 TEST_F(DownloadItemTest, StealDangerousDownload) {
   1199   DownloadItemImpl* item = CreateDownloadItem();
   1200   MockDownloadFile* download_file =
   1201       DoIntermediateRename(item, DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE);
   1202   ASSERT_TRUE(item->IsDangerous());
   1203   base::FilePath full_path(FILE_PATH_LITERAL("foo.txt"));
   1204   base::FilePath returned_path;
   1205 
   1206   EXPECT_CALL(*download_file, FullPath())
   1207       .WillOnce(Return(full_path));
   1208   EXPECT_CALL(*download_file, Detach());
   1209   EXPECT_CALL(*mock_delegate(), DownloadRemoved(_));
   1210   base::WeakPtrFactory<DownloadItemTest> weak_ptr_factory(this);
   1211   item->StealDangerousDownload(
   1212       base::Bind(&DownloadItemTest::OnDownloadFileAcquired,
   1213                  weak_ptr_factory.GetWeakPtr(),
   1214                  base::Unretained(&returned_path)));
   1215   RunAllPendingInMessageLoops();
   1216   EXPECT_EQ(full_path, returned_path);
   1217 }
   1218 
   1219 TEST_F(DownloadItemTest, StealInterruptedDangerousDownload) {
   1220   CommandLine::ForCurrentProcess()->AppendSwitch(
   1221       switches::kEnableDownloadResumption);
   1222   base::FilePath returned_path;
   1223   DownloadItemImpl* item = CreateDownloadItem();
   1224   MockDownloadFile* download_file =
   1225       DoIntermediateRename(item, DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE);
   1226   base::FilePath full_path = item->GetFullPath();
   1227   EXPECT_FALSE(full_path.empty());
   1228   EXPECT_CALL(*download_file, FullPath())
   1229       .WillOnce(Return(full_path));
   1230   EXPECT_CALL(*download_file, Detach());
   1231   item->DestinationObserverAsWeakPtr()->DestinationError(
   1232       DOWNLOAD_INTERRUPT_REASON_NETWORK_FAILED);
   1233   ASSERT_TRUE(item->IsDangerous());
   1234 
   1235   EXPECT_CALL(*mock_delegate(), DownloadRemoved(_));
   1236   base::WeakPtrFactory<DownloadItemTest> weak_ptr_factory(this);
   1237   item->StealDangerousDownload(
   1238       base::Bind(&DownloadItemTest::OnDownloadFileAcquired,
   1239                  weak_ptr_factory.GetWeakPtr(),
   1240                  base::Unretained(&returned_path)));
   1241   RunAllPendingInMessageLoops();
   1242   EXPECT_EQ(full_path, returned_path);
   1243 }
   1244 
   1245 TEST_F(DownloadItemTest, StealInterruptedNonResumableDangerousDownload) {
   1246   CommandLine::ForCurrentProcess()->AppendSwitch(
   1247       switches::kEnableDownloadResumption);
   1248   base::FilePath returned_path;
   1249   DownloadItemImpl* item = CreateDownloadItem();
   1250   MockDownloadFile* download_file =
   1251       DoIntermediateRename(item, DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE);
   1252   EXPECT_CALL(*download_file, Cancel());
   1253   item->DestinationObserverAsWeakPtr()->DestinationError(
   1254       DOWNLOAD_INTERRUPT_REASON_FILE_FAILED);
   1255   ASSERT_TRUE(item->IsDangerous());
   1256 
   1257   EXPECT_CALL(*mock_delegate(), DownloadRemoved(_));
   1258   base::WeakPtrFactory<DownloadItemTest> weak_ptr_factory(this);
   1259   item->StealDangerousDownload(
   1260       base::Bind(&DownloadItemTest::OnDownloadFileAcquired,
   1261                  weak_ptr_factory.GetWeakPtr(),
   1262                  base::Unretained(&returned_path)));
   1263   RunAllPendingInMessageLoops();
   1264   EXPECT_TRUE(returned_path.empty());
   1265 }
   1266 
   1267 TEST(MockDownloadItem, Compiles) {
   1268   MockDownloadItem mock_item;
   1269 }
   1270 
   1271 }  // namespace content
   1272