text: // Copyright (c) 2012 The Chromium Authors. All rights reserved.
  // Use of this source code is governed by a BSD-style license that can be
  // found in the LICENSE file.
  
  #include "base/compiler_specific.h"
  #include "base/memory/scoped_ptr.h"
  #include "base/message_loop/message_loop.h"
  #include "base/run_loop.h"
  #include "chrome/browser/chrome_notification_types.h"
  #include "chrome/browser/download/download_item_model.h"
  #include "chrome/browser/download/download_service.h"
  #include "chrome/browser/download/download_service_factory.h"
  #include "chrome/browser/download/test_download_shelf.h"
  #include "chrome/test/base/testing_profile.h"
  #include "content/public/browser/notification_service.h"
  #include "content/public/test/mock_download_item.h"
  #include "content/public/test/mock_download_manager.h"
  #include "content/public/test/test_browser_thread.h"
  #include "extensions/common/extension.h"
  #include "testing/gmock/include/gmock/gmock.h"
  #include "testing/gtest/include/gtest/gtest.h"
  
  using ::testing::Return;
  using ::testing::ReturnRefOfCopy;
  using ::testing::SaveArg;
  using ::testing::_;
  using content::DownloadItem;
  
  namespace {
  
  KeyedService* CreateDownloadService(content::BrowserContext* context) {
    return new DownloadService(Profile::FromBrowserContext(context));
  }
  
  class DownloadShelfTest : public testing::Test {
   public:
    DownloadShelfTest();
  
   protected:
    content::MockDownloadItem* download_item() {
      return download_item_.get();
    }
    content::MockDownloadManager* download_manager() {
      return download_manager_.get();
    }
    TestDownloadShelf* shelf() {
      return &shelf_;
    }
    Profile* profile() { return profile_.get(); }
  
    virtual void SetUp() OVERRIDE {
      DownloadServiceFactory::GetInstance()->SetTestingFactory(
          profile(), &CreateDownloadService);
    }
  
    virtual void TearDown() OVERRIDE {
      DownloadServiceFactory::GetInstance()->SetTestingFactory(
          profile(), NULL);
    }
  
   private:
    scoped_ptr<content::MockDownloadItem> GetInProgressMockDownload();
  
    base::MessageLoopForUI message_loop_;
    content::TestBrowserThread ui_thread_;
    scoped_ptr<content::MockDownloadItem> download_item_;
    scoped_ptr<content::MockDownloadManager> download_manager_;
    TestDownloadShelf shelf_;
    scoped_ptr<TestingProfile> profile_;
  };
  
  DownloadShelfTest::DownloadShelfTest()
      : ui_thread_(content::BrowserThread::UI, &message_loop_),
        profile_(new TestingProfile()) {
    download_item_.reset(new ::testing::NiceMock<content::MockDownloadItem>());
    ON_CALL(*download_item_, GetAutoOpened()).WillByDefault(Return(false));
    ON_CALL(*download_item_, GetMimeType()).WillByDefault(Return("text/plain"));
    ON_CALL(*download_item_, GetOpenWhenComplete()).WillByDefault(Return(false));
    ON_CALL(*download_item_, GetTargetDisposition())
        .WillByDefault(Return(DownloadItem::TARGET_DISPOSITION_OVERWRITE));
    ON_CALL(*download_item_, GetURL())
        .WillByDefault(ReturnRefOfCopy(GURL("http://example.com/foo")));
    ON_CALL(*download_item_, GetState())
        .WillByDefault(Return(DownloadItem::IN_PROGRESS));
    ON_CALL(*download_item_, IsTemporary()).WillByDefault(Return(false));
    ON_CALL(*download_item_, ShouldOpenFileBasedOnExtension())
        .WillByDefault(Return(false));
    ON_CALL(*download_item_, GetBrowserContext())
        .WillByDefault(Return(profile()));
  
    download_manager_.reset(
        new ::testing::NiceMock<content::MockDownloadManager>());
    ON_CALL(*download_manager_, GetDownload(_))
        .WillByDefault(Return(download_item_.get()));
    ON_CALL(*download_manager_, GetBrowserContext())
        .WillByDefault(Return(profile()));
  
    shelf_.set_download_manager(download_manager_.get());
  }
  
  } // namespace
  
  TEST_F(DownloadShelfTest, ClosesShelfWhenHidden) {
    shelf()->Show();
    EXPECT_TRUE(shelf()->IsShowing());
    shelf()->Hide();
    EXPECT_FALSE(shelf()->IsShowing());
    shelf()->Unhide();
    EXPECT_TRUE(shelf()->IsShowing());
  }
  
  TEST_F(DownloadShelfTest, CloseWhileHiddenPreventsShowOnUnhide) {
    shelf()->Show();
    shelf()->Hide();
    shelf()->Close(DownloadShelf::AUTOMATIC);
    shelf()->Unhide();
    EXPECT_FALSE(shelf()->IsShowing());
  }
  
  TEST_F(DownloadShelfTest, UnhideDoesntShowIfNotShownOnHide) {
    shelf()->Hide();
    shelf()->Unhide();
    EXPECT_FALSE(shelf()->IsShowing());
  }
  
  TEST_F(DownloadShelfTest, AddDownloadWhileHiddenUnhides) {
    shelf()->Show();
    shelf()->Hide();
    shelf()->AddDownload(download_item());
    EXPECT_TRUE(shelf()->IsShowing());
  }
  
  TEST_F(DownloadShelfTest, AddDownloadWhileHiddenUnhidesAndShows) {
    shelf()->Hide();
    shelf()->AddDownload(download_item());
    EXPECT_TRUE(shelf()->IsShowing());
  }
  
  // Normal downloads should be added synchronously and cause the shelf to show.
  TEST_F(DownloadShelfTest, AddNormalDownload) {
    EXPECT_FALSE(shelf()->IsShowing());
    shelf()->AddDownload(download_item());
    EXPECT_TRUE(shelf()->did_add_download());
    EXPECT_TRUE(shelf()->IsShowing());
  }
  
  // Add a transient download. It should not be added immediately. Instead it
  // should be added after a delay. For testing, the delay is set to 0 seconds. So
  // the download should be added once the message loop is flushed.
  TEST_F(DownloadShelfTest, AddDelayedDownload) {
    EXPECT_CALL(*download_item(), ShouldOpenFileBasedOnExtension())
        .WillRepeatedly(Return(true));
    ASSERT_TRUE(DownloadItemModel(download_item())
                .ShouldRemoveFromShelfWhenComplete());
    shelf()->AddDownload(download_item());
  
    EXPECT_FALSE(shelf()->did_add_download());
    EXPECT_FALSE(shelf()->IsShowing());
  
    base::RunLoop run_loop;
    run_loop.RunUntilIdle();
  
    EXPECT_TRUE(shelf()->did_add_download());
    EXPECT_TRUE(shelf()->IsShowing());
  }
  
  // Add a transient download that completes before the delay. It should not be
  // displayed on the shelf.
  TEST_F(DownloadShelfTest, AddDelayedCompletedDownload) {
    EXPECT_CALL(*download_item(), ShouldOpenFileBasedOnExtension())
        .WillRepeatedly(Return(true));
    ASSERT_TRUE(DownloadItemModel(download_item())
                .ShouldRemoveFromShelfWhenComplete());
    shelf()->AddDownload(download_item());
  
    EXPECT_FALSE(shelf()->did_add_download());
    EXPECT_FALSE(shelf()->IsShowing());
  
    EXPECT_CALL(*download_item(), GetState())
        .WillRepeatedly(Return(DownloadItem::COMPLETE));
    EXPECT_CALL(*download_item(), GetAutoOpened())
        .WillRepeatedly(Return(true));
  
    base::RunLoop run_loop;
    run_loop.RunUntilIdle();
  
    EXPECT_FALSE(shelf()->did_add_download());
    EXPECT_FALSE(shelf()->IsShowing());
  }
  
  // Add a transient download that completes and becomes non-transient before the
  // delay. It should be displayed on the shelf even though it is complete.
  TEST_F(DownloadShelfTest, AddDelayedCompleteNonTransientDownload) {
    EXPECT_CALL(*download_item(), ShouldOpenFileBasedOnExtension())
        .WillRepeatedly(Return(true));
    ASSERT_TRUE(DownloadItemModel(download_item())
                .ShouldRemoveFromShelfWhenComplete());
    shelf()->AddDownload(download_item());
  
    EXPECT_FALSE(shelf()->did_add_download());
    EXPECT_FALSE(shelf()->IsShowing());
  
    EXPECT_CALL(*download_item(), GetState())
        .WillRepeatedly(Return(DownloadItem::COMPLETE));
    EXPECT_CALL(*download_item(), ShouldOpenFileBasedOnExtension())
        .WillRepeatedly(Return(false));
    ASSERT_FALSE(DownloadItemModel(download_item())
                 .ShouldRemoveFromShelfWhenComplete());
  
    base::RunLoop run_loop;
    run_loop.RunUntilIdle();
  
    EXPECT_TRUE(shelf()->did_add_download());
    EXPECT_TRUE(shelf()->IsShowing());
  }
  