| // Copyright 2021 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/download/bubble/download_display_controller.h" |
| |
| #include "base/command_line.h" |
| #include "base/files/file_path.h" |
| #include "base/memory/raw_ptr.h" |
| #include "base/memory/raw_ptr_exclusion.h" |
| #include "chrome/browser/download/bubble/download_bubble_controller.h" |
| #include "chrome/browser/download/bubble/download_display.h" |
| #include "chrome/browser/download/bubble/download_icon_state.h" |
| #include "chrome/browser/download/chrome_download_manager_delegate.h" |
| #include "chrome/browser/download/download_core_service.h" |
| #include "chrome/browser/download/download_core_service_factory.h" |
| #include "chrome/browser/download/download_item_model.h" |
| #include "chrome/browser/download/download_prefs.h" |
| #include "chrome/browser/ui/browser.h" |
| #include "chrome/common/chrome_switches.h" |
| #include "chrome/test/base/test_browser_window.h" |
| #include "chrome/test/base/testing_browser_process.h" |
| #include "chrome/test/base/testing_profile.h" |
| #include "chrome/test/base/testing_profile_manager.h" |
| #include "components/download/public/common/download_danger_type.h" |
| #include "components/download/public/common/mock_download_item.h" |
| #include "components/offline_items_collection/core/offline_item.h" |
| #include "content/public/browser/download_item_utils.h" |
| #include "content/public/test/browser_task_environment.h" |
| #include "content/public/test/mock_download_manager.h" |
| #include "content/public/test/test_utils.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| using testing::_; |
| using testing::NiceMock; |
| using testing::Return; |
| using testing::ReturnRef; |
| using testing::ReturnRefOfCopy; |
| using testing::SetArgPointee; |
| |
| namespace { |
| using StrictMockDownloadItem = testing::StrictMock<download::MockDownloadItem>; |
| using DownloadIconState = download::DownloadIconState; |
| using DownloadState = download::DownloadItem::DownloadState; |
| using OfflineItemState = offline_items_collection::OfflineItemState; |
| |
| class FakeDownloadDisplay : public DownloadDisplay { |
| public: |
| FakeDownloadDisplay() = default; |
| FakeDownloadDisplay(const FakeDownloadDisplay&) = delete; |
| FakeDownloadDisplay& operator=(const FakeDownloadDisplay&) = delete; |
| |
| void SetController(DownloadDisplayController* controller) { |
| controller_ = controller; |
| } |
| |
| void ResetState() { |
| shown_ = false; |
| detail_shown_ = false; |
| icon_state_ = DownloadIconState::kComplete; |
| is_active_ = false; |
| } |
| |
| void Show() override { shown_ = true; } |
| |
| void Hide() override { |
| shown_ = false; |
| detail_shown_ = false; |
| } |
| |
| bool IsShowing() override { return shown_; } |
| |
| void Enable() override { enabled_ = true; } |
| |
| void Disable() override { enabled_ = false; } |
| |
| void UpdateDownloadIcon() override { |
| icon_state_ = controller_->GetIconInfo().icon_state; |
| is_active_ = controller_->GetIconInfo().is_active; |
| } |
| |
| void ShowDetails() override { detail_shown_ = true; } |
| void HideDetails() override { detail_shown_ = false; } |
| bool IsShowingDetails() override { return detail_shown_; } |
| bool IsFullscreenWithParentViewHidden() override { return is_fullscreen_; } |
| |
| DownloadIconState GetDownloadIconState() { return icon_state_; } |
| bool IsActive() { return is_active_; } |
| void SetIsFullscreen(bool is_fullscreen) { is_fullscreen_ = is_fullscreen; } |
| |
| private: |
| bool shown_ = false; |
| bool enabled_ = false; |
| DownloadIconState icon_state_ = DownloadIconState::kComplete; |
| bool is_active_ = false; |
| bool detail_shown_ = false; |
| bool is_fullscreen_ = false; |
| // This field is not a raw_ptr<> because it was filtered by the rewriter for: |
| // #constexpr-ctor-field-initializer |
| RAW_PTR_EXCLUSION DownloadDisplayController* controller_ = nullptr; |
| }; |
| |
| class FakeDownloadBubbleUIController : public DownloadBubbleUIController { |
| public: |
| explicit FakeDownloadBubbleUIController(Browser* browser) |
| : DownloadBubbleUIController(browser) {} |
| ~FakeDownloadBubbleUIController() override = default; |
| const OfflineItemList& GetOfflineItems() override { return offline_items_; } |
| void InitOfflineItems(DownloadDisplayController* display_controller, |
| base::OnceCallback<void()> callback) override { |
| std::move(callback).Run(); |
| } |
| void AddOfflineItem(OfflineItem& item) { offline_items_.push_back(item); } |
| void UpdateOfflineItem(int index, OfflineItemState state) { |
| offline_items_[index].state = state; |
| } |
| |
| protected: |
| OfflineItemList offline_items_; |
| }; |
| |
| class MockDownloadCoreService : public DownloadCoreService { |
| public: |
| MOCK_METHOD(ChromeDownloadManagerDelegate*, GetDownloadManagerDelegate, ()); |
| MOCK_METHOD(DownloadUIController*, GetDownloadUIController, ()); |
| MOCK_METHOD(DownloadHistory*, GetDownloadHistory, ()); |
| MOCK_METHOD(extensions::ExtensionDownloadsEventRouter*, |
| GetExtensionEventRouter, |
| ()); |
| MOCK_METHOD(bool, HasCreatedDownloadManager, ()); |
| MOCK_METHOD(int, NonMaliciousDownloadCount, (), (const)); |
| MOCK_METHOD(void, CancelDownloads, ()); |
| MOCK_METHOD(void, |
| SetDownloadManagerDelegateForTesting, |
| (std::unique_ptr<ChromeDownloadManagerDelegate> delegate)); |
| MOCK_METHOD(bool, IsDownloadUiEnabled, ()); |
| MOCK_METHOD(bool, IsDownloadObservedByExtension, ()); |
| }; |
| |
| std::unique_ptr<KeyedService> BuildMockDownloadCoreService( |
| content::BrowserContext* browser_context) { |
| return std::make_unique<MockDownloadCoreService>(); |
| } |
| |
| } // namespace |
| |
| class DownloadDisplayControllerTest : public testing::Test { |
| public: |
| DownloadDisplayControllerTest() |
| : manager_(std::make_unique<NiceMock<content::MockDownloadManager>>()), |
| testing_profile_manager_(TestingBrowserProcess::GetGlobal()) { |
| base::CommandLine::ForCurrentProcess()->AppendSwitch(switches::kNoFirstRun); |
| } |
| DownloadDisplayControllerTest(const DownloadDisplayControllerTest&) = delete; |
| DownloadDisplayControllerTest& operator=( |
| const DownloadDisplayControllerTest&) = delete; |
| |
| void SetUp() override { |
| ASSERT_TRUE(testing_profile_manager_.SetUp()); |
| |
| profile_ = testing_profile_manager_.CreateTestingProfile("testing_profile"); |
| EXPECT_CALL(*manager_.get(), GetBrowserContext()) |
| .WillRepeatedly(Return(profile_.get())); |
| |
| DownloadCoreServiceFactory::GetInstance()->SetTestingFactory( |
| profile_, base::BindRepeating(&BuildMockDownloadCoreService)); |
| mock_download_core_service_ = static_cast<MockDownloadCoreService*>( |
| DownloadCoreServiceFactory::GetForBrowserContext(profile_)); |
| EXPECT_CALL(*mock_download_core_service(), IsDownloadUiEnabled()) |
| .WillRepeatedly(Return(true)); |
| delegate_ = std::make_unique<ChromeDownloadManagerDelegate>(profile_); |
| EXPECT_CALL(*mock_download_core_service(), GetDownloadManagerDelegate()) |
| .WillRepeatedly(Return(delegate_.get())); |
| |
| display_ = std::make_unique<FakeDownloadDisplay>(); |
| window_ = std::make_unique<TestBrowserWindow>(); |
| Browser::CreateParams params(profile_, true); |
| params.type = Browser::TYPE_NORMAL; |
| params.window = window_.get(); |
| browser_ = std::unique_ptr<Browser>(Browser::Create(params)); |
| bubble_controller_ = |
| std::make_unique<FakeDownloadBubbleUIController>(browser_.get()); |
| bubble_controller_->set_manager_for_testing(manager_.get()); |
| controller_ = std::make_unique<DownloadDisplayController>( |
| display_.get(), browser_.get(), bubble_controller_.get()); |
| controller_->set_manager_for_testing(manager_.get()); |
| display_->SetController(controller_.get()); |
| } |
| |
| void TearDown() override { |
| for (auto& item : items_) { |
| item->RemoveObserver(&controller_->get_download_notifier_for_testing()); |
| } |
| // The controller needs to be reset before download manager, because the |
| // download_notifier_ will unregister itself from the manager. |
| controller_.reset(); |
| } |
| |
| Browser* browser() { return browser_.get(); } |
| |
| protected: |
| NiceMock<content::MockDownloadManager>& manager() { return *manager_.get(); } |
| download::MockDownloadItem& item(size_t index) { return *items_[index]; } |
| FakeDownloadDisplay& display() { return *display_; } |
| DownloadDisplayController& controller() { return *controller_; } |
| FakeDownloadBubbleUIController& bubble_controller() { |
| return *bubble_controller_; |
| } |
| Profile* profile() { return profile_; } |
| MockDownloadCoreService* mock_download_core_service() { |
| return mock_download_core_service_; |
| } |
| |
| void InitDownloadItem(const base::FilePath::CharType* path, |
| DownloadState state, |
| bool show_details = true, |
| base::FilePath target_file_path = |
| base::FilePath(FILE_PATH_LITERAL("foo"))) { |
| size_t index = items_.size(); |
| items_.push_back(std::make_unique<StrictMockDownloadItem>()); |
| EXPECT_CALL(item(index), GetId()) |
| .WillRepeatedly(Return(static_cast<uint32_t>(items_.size() + 1))); |
| EXPECT_CALL(item(index), GetState()).WillRepeatedly(Return(state)); |
| EXPECT_CALL(item(index), IsPaused()).WillRepeatedly(Return(false)); |
| EXPECT_CALL(item(index), GetStartTime()) |
| .WillRepeatedly(Return(base::Time::Now())); |
| EXPECT_CALL(item(index), GetDangerType()) |
| .WillRepeatedly(Return(download::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS)); |
| EXPECT_CALL(item(index), IsDangerous()).WillRepeatedly(Return(false)); |
| int received_bytes = |
| state == download::DownloadItem::IN_PROGRESS ? 50 : 100; |
| EXPECT_CALL(item(index), GetReceivedBytes()) |
| .WillRepeatedly(Return(received_bytes)); |
| EXPECT_CALL(item(index), GetTotalBytes()).WillRepeatedly(Return(100)); |
| EXPECT_CALL(item(index), AllDataSaved()) |
| .WillRepeatedly(Return( |
| state == download::DownloadItem::IN_PROGRESS ? false : true)); |
| EXPECT_CALL(item(index), IsDone()).WillRepeatedly(Return(false)); |
| EXPECT_CALL(item(index), IsTransient()).WillRepeatedly(Return(false)); |
| EXPECT_CALL(item(index), GetTargetFilePath()) |
| .WillRepeatedly(ReturnRefOfCopy(target_file_path)); |
| EXPECT_CALL(item(index), GetLastReason()) |
| .WillRepeatedly(Return(download::DOWNLOAD_INTERRUPT_REASON_NONE)); |
| EXPECT_CALL(item(index), GetInsecureDownloadStatus()) |
| .WillRepeatedly( |
| Return(download::DownloadItem::InsecureDownloadStatus::SAFE)); |
| if (state == DownloadState::IN_PROGRESS) { |
| in_progress_count_++; |
| } |
| EXPECT_CALL(manager(), InProgressCount()) |
| .WillRepeatedly(Return(in_progress_count_)); |
| |
| std::vector<download::DownloadItem*> items; |
| for (size_t i = 0; i < items_.size(); ++i) { |
| items.push_back(&item(i)); |
| } |
| EXPECT_CALL(*manager_.get(), GetAllDownloads(_)) |
| .WillRepeatedly(SetArgPointee<0>(items)); |
| item(index).AddObserver(&controller().get_download_notifier_for_testing()); |
| content::DownloadItemUtils::AttachInfoForTesting(&(item(index)), profile_, |
| nullptr); |
| controller().OnNewItem((state == download::DownloadItem::IN_PROGRESS) && |
| show_details); |
| } |
| |
| void InitOfflineItem(OfflineItemState state) { |
| OfflineItem item; |
| item.state = state; |
| bubble_controller().AddOfflineItem(item); |
| controller().OnNewItem(state == OfflineItemState::IN_PROGRESS); |
| } |
| |
| void UpdateOfflineItem(int item_index, OfflineItemState state) { |
| if (state == OfflineItemState::COMPLETE) { |
| bubble_controller().UpdateOfflineItem(item_index, state); |
| } |
| controller().OnUpdatedItem(state == OfflineItemState::COMPLETE, |
| /*show_details_if_done=*/false); |
| } |
| |
| void UpdateDownloadItem(int item_index, |
| DownloadState state, |
| download::DownloadDangerType danger_type = |
| download::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, |
| bool show_details_if_done = false) { |
| DCHECK_GT(items_.size(), static_cast<size_t>(item_index)); |
| |
| EXPECT_CALL(item(item_index), GetState()).WillRepeatedly(Return(state)); |
| EXPECT_CALL(item(item_index), GetDangerType()) |
| .WillRepeatedly(Return(danger_type)); |
| if (state == DownloadState::COMPLETE) { |
| EXPECT_CALL(item(item_index), IsDone()).WillRepeatedly(Return(true)); |
| in_progress_count_--; |
| EXPECT_CALL(manager(), InProgressCount()) |
| .WillRepeatedly(Return(in_progress_count_)); |
| DownloadPrefs::FromDownloadManager(&manager()) |
| ->SetLastCompleteTime(base::Time::Now()); |
| } else { |
| EXPECT_CALL(item(item_index), IsDone()).WillRepeatedly(Return(false)); |
| } |
| controller().OnUpdatedItem(state == DownloadState::COMPLETE, |
| show_details_if_done); |
| } |
| |
| void OnRemovedItem(const ContentId& id) { controller().OnRemovedItem(id); } |
| |
| void RemoveLastDownload() { |
| items_.pop_back(); |
| std::vector<download::DownloadItem*> items; |
| for (size_t i = 0; i < items_.size(); ++i) { |
| items.push_back(&item(i)); |
| } |
| EXPECT_CALL(*manager_.get(), GetAllDownloads(_)) |
| .WillRepeatedly(SetArgPointee<0>(items)); |
| } |
| |
| bool VerifyDisplayState(bool shown, |
| bool detail_shown, |
| DownloadIconState icon_state, |
| bool is_active) { |
| bool success = true; |
| if (shown != display().IsShowing()) { |
| success = false; |
| ADD_FAILURE() << "Display should have shown state " << shown |
| << ", but found " << display().IsShowing(); |
| } |
| if (detail_shown != display().IsShowingDetails()) { |
| success = false; |
| ADD_FAILURE() << "Display should have detailed shown state " |
| << detail_shown << ", but found " |
| << display().IsShowingDetails(); |
| } |
| if (icon_state != display().GetDownloadIconState()) { |
| success = false; |
| ADD_FAILURE() << "Display should have detailed icon state " |
| << static_cast<int>(icon_state) << ", but found " |
| << static_cast<int>(display().GetDownloadIconState()); |
| } |
| if (is_active != display().IsActive()) { |
| success = false; |
| ADD_FAILURE() << "Display should have is_active set to " << is_active |
| << ", but found " << display().IsActive(); |
| } |
| return success; |
| } |
| |
| content::BrowserTaskEnvironment task_environment_{ |
| base::test::TaskEnvironment::TimeSource::MOCK_TIME}; |
| |
| private: |
| int in_progress_count_ = 0; |
| |
| std::unique_ptr<DownloadDisplayController> controller_; |
| std::unique_ptr<FakeDownloadDisplay> display_; |
| std::vector<std::unique_ptr<StrictMockDownloadItem>> items_; |
| |
| std::unique_ptr<NiceMock<content::MockDownloadManager>> manager_; |
| std::unique_ptr<FakeDownloadBubbleUIController> bubble_controller_; |
| TestingProfileManager testing_profile_manager_; |
| raw_ptr<Profile> profile_; |
| std::unique_ptr<TestBrowserWindow> window_; |
| std::unique_ptr<Browser> browser_; |
| MockDownloadCoreService* mock_download_core_service_; |
| std::unique_ptr<ChromeDownloadManagerDelegate> delegate_; |
| }; |
| |
| TEST_F(DownloadDisplayControllerTest, GetProgressItemsInProgress) { |
| InitDownloadItem(FILE_PATH_LITERAL("/foo/bar.pdf"), |
| download::DownloadItem::IN_PROGRESS); |
| InitDownloadItem(FILE_PATH_LITERAL("/foo/bar2.pdf"), |
| download::DownloadItem::COMPLETE); |
| InitDownloadItem(FILE_PATH_LITERAL("/foo/bar4.pdf"), |
| download::DownloadItem::IN_PROGRESS); |
| DownloadDisplayController::ProgressInfo progress = controller().GetProgress(); |
| |
| EXPECT_EQ(progress.download_count, 2); |
| EXPECT_EQ(progress.progress_percentage, 50); |
| } |
| |
| TEST_F(DownloadDisplayControllerTest, OfflineItemsUncertainProgress) { |
| InitDownloadItem(FILE_PATH_LITERAL("/foo/bar.pdf"), |
| download::DownloadItem::IN_PROGRESS); |
| InitDownloadItem(FILE_PATH_LITERAL("/foo/bar2.pdf"), |
| download::DownloadItem::COMPLETE); |
| InitDownloadItem(FILE_PATH_LITERAL("/foo/bar4.pdf"), |
| download::DownloadItem::IN_PROGRESS); |
| // This offline item has uncertain progress |
| InitOfflineItem(OfflineItemState::IN_PROGRESS); |
| DownloadDisplayController::ProgressInfo progress = controller().GetProgress(); |
| |
| EXPECT_EQ(progress.download_count, 3); |
| EXPECT_EQ(progress.progress_percentage, 50); |
| EXPECT_FALSE(progress.progress_certain); |
| } |
| |
| TEST_F(DownloadDisplayControllerTest, GetProgressItemsAllComplete) { |
| InitDownloadItem(FILE_PATH_LITERAL("/foo/bar.pdf"), |
| download::DownloadItem::COMPLETE); |
| InitDownloadItem(FILE_PATH_LITERAL("/foo/bar2.pdf"), |
| download::DownloadItem::COMPLETE); |
| DownloadDisplayController::ProgressInfo progress = controller().GetProgress(); |
| |
| EXPECT_EQ(progress.download_count, 0); |
| EXPECT_EQ(progress.progress_percentage, 0); |
| } |
| |
| TEST_F(DownloadDisplayControllerTest, UpdateToolbarButtonState) { |
| EXPECT_TRUE(VerifyDisplayState(/*shown=*/false, /*detail_shown=*/false, |
| /*icon_state=*/DownloadIconState::kComplete, |
| /*is_active=*/false)); |
| |
| InitDownloadItem(FILE_PATH_LITERAL("/foo/bar.pdf"), |
| download::DownloadItem::IN_PROGRESS, |
| /*show_details=*/false); |
| EXPECT_TRUE(VerifyDisplayState(/*shown=*/true, /*detail_shown=*/false, |
| /*icon_state=*/DownloadIconState::kProgress, |
| /*is_active=*/true)); |
| |
| InitDownloadItem(FILE_PATH_LITERAL("/foo/bar.pdf"), |
| download::DownloadItem::IN_PROGRESS); |
| EXPECT_TRUE(VerifyDisplayState(/*shown=*/true, /*detail_shown=*/true, |
| /*icon_state=*/DownloadIconState::kProgress, |
| /*is_active=*/true)); |
| |
| EXPECT_CALL(item(0), IsPaused()).WillRepeatedly(Return(true)); |
| UpdateDownloadItem(/*item_index=*/0, DownloadState::IN_PROGRESS); |
| EXPECT_TRUE(VerifyDisplayState(/*shown=*/true, /*detail_shown=*/true, |
| /*icon_state=*/DownloadIconState::kProgress, |
| /*is_active=*/true)); |
| EXPECT_CALL(item(1), IsPaused()).WillRepeatedly(Return(true)); |
| UpdateDownloadItem(/*item_index=*/1, DownloadState::IN_PROGRESS); |
| // The download display is not active anymore, because all in progress |
| // downloads are paused. |
| EXPECT_TRUE(VerifyDisplayState(/*shown=*/true, /*detail_shown=*/true, |
| /*icon_state=*/DownloadIconState::kProgress, |
| /*is_active=*/false)); |
| EXPECT_CALL(item(0), IsPaused()).WillRepeatedly(Return(false)); |
| UpdateDownloadItem(/*item_index=*/0, DownloadState::IN_PROGRESS); |
| EXPECT_TRUE(VerifyDisplayState(/*shown=*/true, /*detail_shown=*/true, |
| /*icon_state=*/DownloadIconState::kProgress, |
| /*is_active=*/true)); |
| |
| UpdateDownloadItem(/*item_index=*/0, DownloadState::COMPLETE); |
| UpdateDownloadItem(/*item_index=*/1, DownloadState::COMPLETE); |
| EXPECT_TRUE(VerifyDisplayState(/*shown=*/true, /*detail_shown=*/true, |
| /*icon_state=*/DownloadIconState::kComplete, |
| /*is_active=*/true)); |
| |
| task_environment_.FastForwardBy(base::Minutes(1)); |
| // The display is still showing but the state has changed to inactive. |
| EXPECT_TRUE(VerifyDisplayState(/*shown=*/true, /*detail_shown=*/true, |
| /*icon_state=*/DownloadIconState::kComplete, |
| /*is_active=*/false)); |
| |
| task_environment_.FastForwardBy(base::Hours(23)); |
| // The display is still showing because the last download is less than 1 |
| // day ago. |
| EXPECT_TRUE(VerifyDisplayState(/*shown=*/true, /*detail_shown=*/true, |
| /*icon_state=*/DownloadIconState::kComplete, |
| /*is_active=*/false)); |
| |
| task_environment_.FastForwardBy(base::Hours(1)); |
| // The display should stop showing once the last download is more than 1 |
| // day ago. |
| EXPECT_TRUE(VerifyDisplayState(/*shown=*/false, /*detail_shown=*/false, |
| /*icon_state=*/DownloadIconState::kComplete, |
| /*is_active=*/false)); |
| } |
| |
| TEST_F(DownloadDisplayControllerTest, |
| UpdateToolbarButtonState_MultipleDownloads) { |
| EXPECT_TRUE(VerifyDisplayState(/*shown=*/false, /*detail_shown=*/false, |
| /*icon_state=*/DownloadIconState::kComplete, |
| /*is_active=*/false)); |
| |
| InitDownloadItem(FILE_PATH_LITERAL("/foo/bar.pdf"), |
| download::DownloadItem::IN_PROGRESS); |
| EXPECT_TRUE(VerifyDisplayState(/*shown=*/true, /*detail_shown=*/true, |
| /*icon_state=*/DownloadIconState::kProgress, |
| /*is_active=*/true)); |
| |
| // Reset details_shown before the second download starts. This can happen if |
| // the user clicks somewhere else to dismiss the download bubble. |
| display().HideDetails(); |
| |
| InitDownloadItem(FILE_PATH_LITERAL("/foo/bar2.pdf"), |
| download::DownloadItem::IN_PROGRESS); |
| EXPECT_TRUE(VerifyDisplayState(/*shown=*/true, /*detail_shown=*/true, |
| /*icon_state=*/DownloadIconState::kProgress, |
| /*is_active=*/true)); |
| |
| // Reset details_shown while the downloads are in progress. This can happen if |
| // the user clicks somewhere else to dismiss the download bubble. |
| display().HideDetails(); |
| |
| UpdateDownloadItem(/*item_index=*/0, DownloadState::COMPLETE); |
| // The download icon state is still kProgress because not all downloads are |
| // completed. details_shown is still false, because the details are only |
| // popped up when the download is created. |
| EXPECT_TRUE(VerifyDisplayState(/*shown=*/true, /*detail_shown=*/false, |
| /*icon_state=*/DownloadIconState::kProgress, |
| /*is_active=*/true)); |
| |
| UpdateDownloadItem(/*item_index=*/1, DownloadState::COMPLETE); |
| EXPECT_TRUE(VerifyDisplayState(/*shown=*/true, /*detail_shown=*/false, |
| /*icon_state=*/DownloadIconState::kComplete, |
| /*is_active=*/true)); |
| |
| InitOfflineItem(OfflineItemState::IN_PROGRESS); |
| EXPECT_TRUE(VerifyDisplayState(/*shown=*/true, /*detail_shown=*/true, |
| /*icon_state=*/DownloadIconState::kProgress, |
| /*is_active=*/true)); |
| display().HideDetails(); |
| |
| UpdateOfflineItem(/*item_index=*/0, OfflineItemState::COMPLETE); |
| EXPECT_TRUE(VerifyDisplayState(/*shown=*/true, /*detail_shown=*/false, |
| /*icon_state=*/DownloadIconState::kComplete, |
| /*is_active=*/true)); |
| |
| InitDownloadItem(FILE_PATH_LITERAL("/foo/bar3.pdf"), |
| download::DownloadItem::IN_PROGRESS); |
| display().HideDetails(); |
| // Don't pop up the view on completed download. |
| UpdateDownloadItem(/*item_index=*/2, DownloadState::COMPLETE, |
| download::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, |
| /*show_details_if_done=*/true); |
| EXPECT_TRUE(VerifyDisplayState(/*shown=*/true, /*detail_shown=*/false, |
| /*icon_state=*/DownloadIconState::kComplete, |
| /*is_active=*/true)); |
| } |
| |
| TEST_F(DownloadDisplayControllerTest, |
| UpdateToolbarButtonState_OnCompleteItemCreated) { |
| EXPECT_TRUE(VerifyDisplayState(/*shown=*/false, /*detail_shown=*/false, |
| /*icon_state=*/DownloadIconState::kComplete, |
| /*is_active=*/false)); |
| |
| InitDownloadItem(FILE_PATH_LITERAL("/foo/bar.pdf"), |
| download::DownloadItem::COMPLETE); |
| // Don't show the button if the new download is already completed. |
| EXPECT_TRUE(VerifyDisplayState(/*shown=*/false, /*detail_shown=*/false, |
| /*icon_state=*/DownloadIconState::kComplete, |
| /*is_active=*/false)); |
| } |
| |
| TEST_F(DownloadDisplayControllerTest, UpdateToolbarButtonState_DeepScanning) { |
| EXPECT_TRUE(VerifyDisplayState(/*shown=*/false, /*detail_shown=*/false, |
| /*icon_state=*/DownloadIconState::kComplete, |
| /*is_active=*/false)); |
| |
| InitDownloadItem(FILE_PATH_LITERAL("/foo/bar.pdf"), |
| download::DownloadItem::IN_PROGRESS); |
| EXPECT_TRUE(VerifyDisplayState(/*shown=*/true, /*detail_shown=*/true, |
| /*icon_state=*/DownloadIconState::kProgress, |
| /*is_active=*/true)); |
| |
| UpdateDownloadItem(/*item_index=*/0, DownloadState::IN_PROGRESS, |
| download::DOWNLOAD_DANGER_TYPE_ASYNC_SCANNING); |
| EXPECT_TRUE( |
| VerifyDisplayState(/*shown=*/true, /*detail_shown=*/true, |
| /*icon_state=*/DownloadIconState::kDeepScanning, |
| /*is_active=*/true)); |
| |
| UpdateDownloadItem(/*item_index=*/0, DownloadState::COMPLETE); |
| EXPECT_TRUE(VerifyDisplayState(/*shown=*/true, /*detail_shown=*/true, |
| /*icon_state=*/DownloadIconState::kComplete, |
| /*is_active=*/true)); |
| } |
| |
| TEST_F(DownloadDisplayControllerTest, UpdateToolbarButtonState_EmptyFilePath) { |
| EXPECT_TRUE(VerifyDisplayState(/*shown=*/false, /*detail_shown=*/false, |
| /*icon_state=*/DownloadIconState::kComplete, |
| /*is_active=*/false)); |
| |
| InitDownloadItem(FILE_PATH_LITERAL("/foo/bar.pdf"), |
| download::DownloadItem::IN_PROGRESS, /*show_details=*/false, |
| /*target_file_path=*/base::FilePath(FILE_PATH_LITERAL(""))); |
| // Empty file path should not be reflected in the UI. |
| EXPECT_TRUE(VerifyDisplayState(/*shown=*/false, /*detail_shown=*/false, |
| /*icon_state=*/DownloadIconState::kComplete, |
| /*is_active=*/false)); |
| |
| EXPECT_CALL(item(0), GetTargetFilePath()) |
| .WillRepeatedly( |
| ReturnRefOfCopy(base::FilePath(FILE_PATH_LITERAL("bar.pdf")))); |
| controller().OnNewItem(/*show_details=*/true); |
| EXPECT_TRUE(VerifyDisplayState(/*shown=*/true, /*detail_shown=*/true, |
| /*icon_state=*/DownloadIconState::kProgress, |
| /*is_active=*/true)); |
| } |
| |
| TEST_F(DownloadDisplayControllerTest, |
| UpdateToolbarButtonState_DangerousDownload) { |
| EXPECT_TRUE(VerifyDisplayState(/*shown=*/false, /*detail_shown=*/false, |
| /*icon_state=*/DownloadIconState::kComplete, |
| /*is_active=*/false)); |
| |
| InitDownloadItem(FILE_PATH_LITERAL("/foo/bar.pdf"), |
| download::DownloadItem::IN_PROGRESS); |
| EXPECT_TRUE(VerifyDisplayState(/*shown=*/true, /*detail_shown=*/true, |
| /*icon_state=*/DownloadIconState::kProgress, |
| /*is_active=*/true)); |
| |
| EXPECT_CALL(item(0), IsDangerous()).WillRepeatedly(Return(true)); |
| UpdateDownloadItem(/*item_index=*/0, DownloadState::IN_PROGRESS, |
| download::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST, |
| /*show_details_if_done=*/true); |
| EXPECT_TRUE(VerifyDisplayState(/*shown=*/true, /*detail_shown=*/true, |
| /*icon_state=*/DownloadIconState::kComplete, |
| /*is_active=*/false)); |
| |
| // Downloads prompted for deep scanning should be considered in progress. |
| UpdateDownloadItem(/*item_index=*/0, DownloadState::IN_PROGRESS, |
| download::DOWNLOAD_DANGER_TYPE_PROMPT_FOR_SCANNING, |
| /*show_details_if_done=*/true); |
| EXPECT_TRUE(VerifyDisplayState(/*shown=*/true, /*detail_shown=*/true, |
| /*icon_state=*/DownloadIconState::kProgress, |
| /*is_active=*/true)); |
| } |
| |
| TEST_F(DownloadDisplayControllerTest, UpdateToolbarButtonState_OnRemovedItem) { |
| InitDownloadItem(FILE_PATH_LITERAL("/foo/bar.pdf"), |
| download::DownloadItem::IN_PROGRESS); |
| std::string same_id = "Download 1"; |
| std::string different_id = "Download 2"; |
| EXPECT_CALL(item(0), GetGuid()).WillRepeatedly(ReturnRef(same_id)); |
| |
| OnRemovedItem(ContentId("LEGACY_DOWNLOAD", different_id)); |
| // The download display is still shown, because the removed download is |
| // different. |
| EXPECT_TRUE(VerifyDisplayState(/*shown=*/true, /*detail_shown=*/true, |
| /*icon_state=*/DownloadIconState::kProgress, |
| /*is_active=*/true)); |
| |
| OnRemovedItem(ContentId("LEGACY_DOWNLOAD", same_id)); |
| // The download display is hided, because the only item in the download list |
| // is about to be removed. |
| EXPECT_TRUE(VerifyDisplayState(/*shown=*/false, /*detail_shown=*/false, |
| /*icon_state=*/DownloadIconState::kProgress, |
| /*is_active=*/true)); |
| } |
| |
| TEST_F(DownloadDisplayControllerTest, |
| UpdateToolbarButtonState_OnRemovedItemMultipleDownloads) { |
| InitDownloadItem(FILE_PATH_LITERAL("/foo/bar.pdf"), |
| download::DownloadItem::IN_PROGRESS); |
| InitDownloadItem(FILE_PATH_LITERAL("/foo/bar1.pdf"), |
| download::DownloadItem::IN_PROGRESS); |
| std::vector<std::string> ids = {"Download 1", "Download 2"}; |
| EXPECT_CALL(item(0), GetGuid()).WillRepeatedly(ReturnRef(ids[0])); |
| EXPECT_CALL(item(1), GetGuid()).WillRepeatedly(ReturnRef(ids[1])); |
| |
| // The download display is still shown, because there are multiple downloads |
| // in the list. |
| OnRemovedItem(ContentId("LEGACY_DOWNLOAD", ids[0])); |
| EXPECT_TRUE(VerifyDisplayState(/*shown=*/true, /*detail_shown=*/true, |
| /*icon_state=*/DownloadIconState::kProgress, |
| /*is_active=*/true)); |
| |
| RemoveLastDownload(); |
| OnRemovedItem(ContentId("LEGACY_DOWNLOAD", ids[0])); |
| EXPECT_TRUE(VerifyDisplayState(/*shown=*/false, /*detail_shown=*/false, |
| /*icon_state=*/DownloadIconState::kProgress, |
| /*is_active=*/true)); |
| } |
| |
| TEST_F(DownloadDisplayControllerTest, |
| UpdateToolbarButtonState_DownloadWasActionedOn) { |
| InitDownloadItem(FILE_PATH_LITERAL("/foo/bar.pdf"), |
| download::DownloadItem::IN_PROGRESS); |
| EXPECT_TRUE(VerifyDisplayState(/*shown=*/true, /*detail_shown=*/true, |
| /*icon_state=*/DownloadIconState::kProgress, |
| /*is_active=*/true)); |
| |
| UpdateDownloadItem(/*item_index=*/0, DownloadState::COMPLETE); |
| EXPECT_TRUE(VerifyDisplayState(/*shown=*/true, /*detail_shown=*/true, |
| /*icon_state=*/DownloadIconState::kComplete, |
| /*is_active=*/true)); |
| |
| DownloadItemModel(&item(0)).SetActionedOn(true); |
| UpdateDownloadItem(/*item_index=*/0, DownloadState::COMPLETE); |
| EXPECT_TRUE(VerifyDisplayState(/*shown=*/true, /*detail_shown=*/true, |
| /*icon_state=*/DownloadIconState::kComplete, |
| /*is_active=*/false)); |
| } |
| |
| TEST_F(DownloadDisplayControllerTest, UpdateToolbarButtonState_OnResume) { |
| InitDownloadItem(FILE_PATH_LITERAL("/foo/bar.pdf"), |
| download::DownloadItem::IN_PROGRESS); |
| EXPECT_TRUE(VerifyDisplayState(/*shown=*/true, /*detail_shown=*/true, |
| /*icon_state=*/DownloadIconState::kProgress, |
| /*is_active=*/true)); |
| |
| EXPECT_CALL(item(0), IsPaused()).WillRepeatedly(Return(true)); |
| controller().OnResume(); |
| // is_active state should be updated after OnResume is called. |
| EXPECT_TRUE(VerifyDisplayState(/*shown=*/true, /*detail_shown=*/true, |
| /*icon_state=*/DownloadIconState::kProgress, |
| /*is_active=*/false)); |
| } |
| |
| TEST_F(DownloadDisplayControllerTest, InitialState_OldLastDownload) { |
| InitDownloadItem(FILE_PATH_LITERAL("/foo/bar.pdf"), |
| download::DownloadItem::COMPLETE); |
| base::Time current_time = base::Time::Now(); |
| // Set the last complete time to more than 1 day ago. |
| DownloadPrefs::FromDownloadManager(&manager()) |
| ->SetLastCompleteTime(current_time - base::Hours(25)); |
| |
| DownloadDisplayController controller(&display(), browser(), |
| &bubble_controller()); |
| EXPECT_TRUE(VerifyDisplayState(/*shown=*/false, /*detail_shown=*/false, |
| /*icon_state=*/DownloadIconState::kComplete, |
| /*is_active=*/false)); |
| } |
| |
| TEST_F(DownloadDisplayControllerTest, InitialState_NewLastDownload) { |
| InitDownloadItem(FILE_PATH_LITERAL("/foo/bar.pdf"), |
| download::DownloadItem::COMPLETE); |
| base::Time current_time = base::Time::Now(); |
| // Set the last complete time to less than 1 day ago. |
| DownloadPrefs::FromDownloadManager(&manager()) |
| ->SetLastCompleteTime(current_time - base::Hours(23)); |
| |
| DownloadDisplayController controller(&display(), browser(), |
| &bubble_controller()); |
| // The initial state should not display details. |
| EXPECT_TRUE(VerifyDisplayState(/*shown=*/true, /*detail_shown=*/false, |
| /*icon_state=*/DownloadIconState::kComplete, |
| /*is_active=*/false)); |
| |
| // The display should stop showing once the last download is more than 1 day |
| // ago. |
| task_environment_.FastForwardBy(base::Hours(1)); |
| EXPECT_TRUE(VerifyDisplayState(/*shown=*/false, /*detail_shown=*/false, |
| /*icon_state=*/DownloadIconState::kComplete, |
| /*is_active=*/false)); |
| } |
| |
| TEST_F(DownloadDisplayControllerTest, InitialState_InProgressDownload) { |
| InitDownloadItem(FILE_PATH_LITERAL("/foo/bar.pdf"), |
| download::DownloadItem::IN_PROGRESS); |
| |
| // Simulate a new window opened. |
| display().ResetState(); |
| DownloadDisplayController controller(&display(), browser(), |
| &bubble_controller()); |
| EXPECT_TRUE(VerifyDisplayState(/*shown=*/true, /*detail_shown=*/false, |
| /*icon_state=*/DownloadIconState::kProgress, |
| /*is_active=*/true)); |
| } |
| |
| TEST_F(DownloadDisplayControllerTest, |
| InitialState_NewLastDownloadWithEmptyItem) { |
| base::Time current_time = base::Time::Now(); |
| // Set the last complete time to less than 1 day ago. |
| DownloadPrefs::FromDownloadManager(&manager()) |
| ->SetLastCompleteTime(current_time - base::Hours(23)); |
| |
| DownloadDisplayController controller(&display(), browser(), |
| &bubble_controller()); |
| // Although the last complete time is set, the download display is not shown |
| // because the download item list is empty. This can happen if the download |
| // history is deleted by the user. |
| EXPECT_TRUE(VerifyDisplayState(/*shown=*/false, /*detail_shown=*/false, |
| /*icon_state=*/DownloadIconState::kComplete, |
| /*is_active=*/false)); |
| } |
| |
| TEST_F(DownloadDisplayControllerTest, InitialState_NoLastDownload) { |
| DownloadDisplayController controller(&display(), browser(), |
| &bubble_controller()); |
| EXPECT_TRUE(VerifyDisplayState(/*shown=*/false, /*detail_shown=*/false, |
| /*icon_state=*/DownloadIconState::kComplete, |
| /*is_active=*/false)); |
| } |
| |
| TEST_F(DownloadDisplayControllerTest, OnButtonPressed_IconStateComplete) { |
| InitDownloadItem(FILE_PATH_LITERAL("/foo/bar.pdf"), |
| download::DownloadItem::IN_PROGRESS); |
| UpdateDownloadItem(/*item_index=*/0, DownloadState::COMPLETE); |
| EXPECT_TRUE(VerifyDisplayState(/*shown=*/true, /*detail_shown=*/true, |
| /*icon_state=*/DownloadIconState::kComplete, |
| /*is_active=*/true)); |
| |
| controller().HandleButtonPressed(); |
| |
| EXPECT_TRUE(VerifyDisplayState(/*shown=*/true, /*detail_shown=*/true, |
| /*icon_state=*/DownloadIconState::kComplete, |
| /*is_active=*/false)); |
| } |
| |
| TEST_F(DownloadDisplayControllerTest, OnButtonPressed_IconStateInProgress) { |
| InitDownloadItem(FILE_PATH_LITERAL("/foo/bar.pdf"), |
| download::DownloadItem::IN_PROGRESS); |
| EXPECT_TRUE(VerifyDisplayState(/*shown=*/true, /*detail_shown=*/true, |
| /*icon_state=*/DownloadIconState::kProgress, |
| /*is_active=*/true)); |
| |
| controller().OnButtonPressed(); |
| |
| // Keep is_active to true because the download is still in progress. |
| EXPECT_TRUE(VerifyDisplayState(/*shown=*/true, /*detail_shown=*/true, |
| /*icon_state=*/DownloadIconState::kProgress, |
| /*is_active=*/true)); |
| } |
| |
| TEST_F(DownloadDisplayControllerTest, |
| Fullscreen_ShowsDetailsForInProgressOnExitFullscreen) { |
| display().SetIsFullscreen(true); |
| InitDownloadItem(FILE_PATH_LITERAL("/foo/bar.pdf"), |
| download::DownloadItem::IN_PROGRESS); |
| // Do not show bubble for in-progress download in full screen mode. |
| EXPECT_TRUE(VerifyDisplayState(/*shown=*/true, /*detail_shown=*/false, |
| /*icon_state=*/DownloadIconState::kProgress, |
| /*is_active=*/true)); |
| |
| display().SetIsFullscreen(false); |
| controller().OnFullscreenStateChanged(); |
| // Show bubble for in-progress download when exiting full screen mode. |
| EXPECT_TRUE(VerifyDisplayState(/*shown=*/true, /*detail_shown=*/true, |
| /*icon_state=*/DownloadIconState::kProgress, |
| /*is_active=*/true)); |
| } |
| |
| TEST_F(DownloadDisplayControllerTest, |
| Fullscreen_ShowsIconForCompletedOnExitFullscreen) { |
| display().SetIsFullscreen(true); |
| InitDownloadItem(FILE_PATH_LITERAL("/foo/bar.pdf"), |
| download::DownloadItem::IN_PROGRESS); |
| EXPECT_TRUE(VerifyDisplayState(/*shown=*/true, /*detail_shown=*/false, |
| /*icon_state=*/DownloadIconState::kProgress, |
| /*is_active=*/true)); |
| |
| UpdateDownloadItem(/*item_index=*/0, DownloadState::COMPLETE, |
| download::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, |
| /*show_details_if_done=*/true); |
| // While the bubble does not pop up, and the toolbar not shown, the icon |
| // state is still updated. So |is_active| should be true for one minute |
| // after completed download. |
| EXPECT_TRUE(VerifyDisplayState(/*shown=*/true, /*detail_shown=*/false, |
| /*icon_state=*/DownloadIconState::kComplete, |
| /*is_active=*/true)); |
| |
| task_environment_.FastForwardBy(base::Minutes(1)); |
| // The display is still showing but the state has changed to inactive. |
| EXPECT_TRUE(VerifyDisplayState(/*shown=*/true, /*detail_shown=*/false, |
| /*icon_state=*/DownloadIconState::kComplete, |
| /*is_active=*/false)); |
| |
| display().SetIsFullscreen(false); |
| controller().OnFullscreenStateChanged(); |
| // On exiting full screen, show download icon as active for 1 minute. |
| EXPECT_TRUE(VerifyDisplayState(/*shown=*/true, /*detail_shown=*/false, |
| /*icon_state=*/DownloadIconState::kComplete, |
| /*is_active=*/true)); |
| |
| task_environment_.FastForwardBy(base::Minutes(1)); |
| // The display is still showing but the state has changed to inactive. |
| EXPECT_TRUE(VerifyDisplayState(/*shown=*/true, /*detail_shown=*/false, |
| /*icon_state=*/DownloadIconState::kComplete, |
| /*is_active=*/false)); |
| } |
| |
| TEST_F(DownloadDisplayControllerTest, |
| ShowsDetailsWhenExtensionObservingDownloads) { |
| EXPECT_CALL(*mock_download_core_service(), IsDownloadObservedByExtension()) |
| .WillRepeatedly(Return(true)); |
| InitDownloadItem(FILE_PATH_LITERAL("/foo/bar.pdf"), |
| download::DownloadItem::IN_PROGRESS); |
| EXPECT_TRUE(VerifyDisplayState(/*shown=*/true, /*detail_shown=*/true, |
| /*icon_state=*/DownloadIconState::kProgress, |
| /*is_active=*/true)); |
| } |