text: // Copyright (c) 2006-2008 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 "chrome/browser/download/download_request_limiter.h"
  #include "chrome/test/testing_profile.h"
  #include "content/browser/browser_thread.h"
  #include "content/browser/renderer_host/test_render_view_host.h"
  #include "content/browser/tab_contents/navigation_controller.h"
  #include "testing/gtest/include/gtest/gtest.h"
  
  class DownloadRequestLimiterTest
      : public RenderViewHostTestHarness,
        public DownloadRequestLimiter::Callback {
   public:
    DownloadRequestLimiterTest() : io_thread_(BrowserThread::IO, &message_loop_) {
    }
  
    virtual void SetUp() {
      RenderViewHostTestHarness::SetUp();
  
      allow_download_ = true;
      ask_allow_count_ = cancel_count_ = continue_count_ = 0;
  
      download_request_limiter_ = new DownloadRequestLimiter();
      test_delegate_.reset(new DownloadRequestLimiterTestDelegate(this));
      DownloadRequestLimiter::SetTestingDelegate(test_delegate_.get());
    }
  
    virtual void TearDown() {
      DownloadRequestLimiter::SetTestingDelegate(NULL);
  
      RenderViewHostTestHarness::TearDown();
    }
  
    virtual void ContinueDownload() {
      continue_count_++;
    }
    virtual void CancelDownload() {
      cancel_count_++;
    }
  
    void CanDownload() {
      download_request_limiter_->CanDownloadImpl(
          controller().tab_contents(), -1, this);
      message_loop_.RunAllPending();
    }
  
    bool ShouldAllowDownload() {
      ask_allow_count_++;
      return allow_download_;
    }
  
   protected:
    class DownloadRequestLimiterTestDelegate
        : public DownloadRequestLimiter::TestingDelegate {
     public:
      explicit DownloadRequestLimiterTestDelegate(
          DownloadRequestLimiterTest* test)
          : test_(test) { }
  
      virtual bool ShouldAllowDownload() {
        return test_->ShouldAllowDownload();
      }
  
     private:
      DownloadRequestLimiterTest* test_;
    };
  
    scoped_ptr<DownloadRequestLimiterTestDelegate> test_delegate_;
    scoped_refptr<DownloadRequestLimiter> download_request_limiter_;
  
    // Number of times ContinueDownload was invoked.
    int continue_count_;
  
    // Number of times CancelDownload was invoked.
    int cancel_count_;
  
    // Whether the download should be allowed.
    bool allow_download_;
  
    // Number of times ShouldAllowDownload was invoked.
    int ask_allow_count_;
  
    BrowserThread io_thread_;
  };
  
  TEST_F(DownloadRequestLimiterTest, Allow) {
    // All tabs should initially start at ALLOW_ONE_DOWNLOAD.
    ASSERT_EQ(DownloadRequestLimiter::ALLOW_ONE_DOWNLOAD,
              download_request_limiter_->GetDownloadStatus(
                  controller().tab_contents()));
  
    // Ask if the tab can do a download. This moves to PROMPT_BEFORE_DOWNLOAD.
    CanDownload();
    ASSERT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD,
              download_request_limiter_->GetDownloadStatus(
                  controller().tab_contents()));
    // We should have been told we can download.
    ASSERT_EQ(1, continue_count_);
    ASSERT_EQ(0, cancel_count_);
    ASSERT_EQ(0, ask_allow_count_);
    continue_count_ = 0;
  
    // Ask again. This triggers asking the delegate for allow/disallow.
    allow_download_ = true;
    CanDownload();
    // This should ask us if the download is allowed.
    ASSERT_EQ(1, ask_allow_count_);
    ask_allow_count_ = 0;
    ASSERT_EQ(DownloadRequestLimiter::ALLOW_ALL_DOWNLOADS,
              download_request_limiter_->GetDownloadStatus(
                  controller().tab_contents()));
    // We should have been told we can download.
    ASSERT_EQ(1, continue_count_);
    ASSERT_EQ(0, cancel_count_);
    continue_count_ = 0;
  
    // Ask again and make sure continue is invoked.
    CanDownload();
    // The state is at allow_all, which means the delegate shouldn't be asked.
    ASSERT_EQ(0, ask_allow_count_);
    ASSERT_EQ(DownloadRequestLimiter::ALLOW_ALL_DOWNLOADS,
              download_request_limiter_->GetDownloadStatus(
                  controller().tab_contents()));
    // We should have been told we can download.
    ASSERT_EQ(1, continue_count_);
    ASSERT_EQ(0, cancel_count_);
    continue_count_ = 0;
  }
  
  TEST_F(DownloadRequestLimiterTest, ResetOnNavigation) {
    NavigateAndCommit(GURL("http://foo.com/bar"));
  
    // Do two downloads, allowing the second so that we end up with allow all.
    CanDownload();
    allow_download_ = true;
    CanDownload();
    ask_allow_count_ = continue_count_ = cancel_count_ = 0;
    ASSERT_EQ(DownloadRequestLimiter::ALLOW_ALL_DOWNLOADS,
              download_request_limiter_->GetDownloadStatus(
                  controller().tab_contents()));
  
    // Navigate to a new URL with the same host, which shouldn't reset the allow
    // all state.
    NavigateAndCommit(GURL("http://foo.com/bar2"));
    CanDownload();
    ASSERT_EQ(1, continue_count_);
    ASSERT_EQ(0, cancel_count_);
    ASSERT_EQ(0, ask_allow_count_);
    ask_allow_count_ = continue_count_ = cancel_count_ = 0;
    ASSERT_EQ(DownloadRequestLimiter::ALLOW_ALL_DOWNLOADS,
              download_request_limiter_->GetDownloadStatus(
                  controller().tab_contents()));
  
    // Do a user gesture, because we're at allow all, this shouldn't change the
    // state.
    download_request_limiter_->OnUserGesture(controller().tab_contents());
    ASSERT_EQ(DownloadRequestLimiter::ALLOW_ALL_DOWNLOADS,
              download_request_limiter_->GetDownloadStatus(
                  controller().tab_contents()));
  
    // Navigate to a completely different host, which should reset the state.
    NavigateAndCommit(GURL("http://fooey.com"));
    ASSERT_EQ(DownloadRequestLimiter::ALLOW_ONE_DOWNLOAD,
              download_request_limiter_->GetDownloadStatus(
                  controller().tab_contents()));
  }
  
  TEST_F(DownloadRequestLimiterTest, ResetOnUserGesture) {
    NavigateAndCommit(GURL("http://foo.com/bar"));
  
    // Do one download, which should change to prompt before download.
    CanDownload();
    ask_allow_count_ = continue_count_ = cancel_count_ = 0;
    ASSERT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD,
              download_request_limiter_->GetDownloadStatus(
                  controller().tab_contents()));
  
    // Do a user gesture, which should reset back to allow one.
    download_request_limiter_->OnUserGesture(controller().tab_contents());
    ASSERT_EQ(DownloadRequestLimiter::ALLOW_ONE_DOWNLOAD,
              download_request_limiter_->GetDownloadStatus(
                  controller().tab_contents()));
  
    // Ask twice, which triggers calling the delegate. Don't allow the download
    // so that we end up with not allowed.
    allow_download_ = false;
    CanDownload();
    CanDownload();
    ASSERT_EQ(DownloadRequestLimiter::DOWNLOADS_NOT_ALLOWED,
              download_request_limiter_->GetDownloadStatus(
                  controller().tab_contents()));
  
    // A user gesture now should NOT change the state.
    download_request_limiter_->OnUserGesture(controller().tab_contents());
    ASSERT_EQ(DownloadRequestLimiter::DOWNLOADS_NOT_ALLOWED,
              download_request_limiter_->GetDownloadStatus(
                  controller().tab_contents()));
    // And make sure we really can't download.
    ask_allow_count_ = continue_count_ = cancel_count_ = 0;
    CanDownload();
    ASSERT_EQ(0, ask_allow_count_);
    ASSERT_EQ(0, continue_count_);
    ASSERT_EQ(1, cancel_count_);
    // And the state shouldn't have changed.
    ASSERT_EQ(DownloadRequestLimiter::DOWNLOADS_NOT_ALLOWED,
              download_request_limiter_->GetDownloadStatus(
                  controller().tab_contents()));
  }
  