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/bind.h"
6#include "base/files/file_path.h"
7#include "chrome/browser/download/download_danger_prompt.h"
8#include "chrome/browser/ui/browser.h"
9#include "chrome/browser/ui/browser_commands.h"
10#include "chrome/browser/ui/browser_tabstrip.h"
11#include "chrome/browser/ui/tabs/tab_strip_model.h"
12#include "chrome/test/base/in_process_browser_test.h"
13#include "chrome/test/base/ui_test_utils.h"
14#include "content/public/test/mock_download_item.h"
15#include "testing/gmock/include/gmock/gmock.h"
16#include "testing/gtest/include/gtest/gtest.h"
17
18using ::testing::_;
19using ::testing::ByRef;
20using ::testing::Eq;
21using ::testing::Return;
22using ::testing::SaveArg;
23
24class DownloadDangerPromptTest : public InProcessBrowserTest {
25 public:
26  DownloadDangerPromptTest()
27    : download_observer_(NULL),
28      prompt_(NULL),
29      expected_action_(DownloadDangerPrompt::CANCEL),
30      did_receive_callback_(false) {
31  }
32
33  virtual ~DownloadDangerPromptTest() {
34  }
35
36  // Opens a new tab and waits for navigations to finish. If there are pending
37  // navigations, the constrained prompt might be dismissed when the navigation
38  // completes.
39  void OpenNewTab() {
40    ui_test_utils::NavigateToURLWithDisposition(
41        browser(), GURL("about:blank"),
42        NEW_FOREGROUND_TAB,
43        ui_test_utils::BROWSER_TEST_WAIT_FOR_TAB |
44        ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
45  }
46
47  void SetUpExpectations(DownloadDangerPrompt::Action expected_action) {
48    did_receive_callback_ = false;
49    expected_action_ = expected_action;
50    SetUpDownloadItemExpectations();
51    CreatePrompt();
52  }
53
54  void VerifyExpectations() {
55    content::RunAllPendingInMessageLoop();
56    // At the end of each test, we expect no more activity from the prompt. The
57    // prompt shouldn't exist anymore either.
58    EXPECT_TRUE(did_receive_callback_);
59    EXPECT_FALSE(prompt_);
60    testing::Mock::VerifyAndClearExpectations(&download_);
61  }
62
63  void SimulatePromptAction(DownloadDangerPrompt::Action action) {
64    prompt_->InvokeActionForTesting(action);
65  }
66
67  content::MockDownloadItem& download() { return download_; }
68
69  content::DownloadItem::Observer* download_observer() {
70    return download_observer_;
71  }
72
73  DownloadDangerPrompt* prompt() { return prompt_; }
74
75 private:
76  void SetUpDownloadItemExpectations() {
77    EXPECT_CALL(download_, GetFileNameToReportUser()).WillRepeatedly(Return(
78        base::FilePath(FILE_PATH_LITERAL("evil.exe"))));
79    EXPECT_CALL(download_, AddObserver(_))
80      .WillOnce(SaveArg<0>(&download_observer_));
81    EXPECT_CALL(download_, RemoveObserver(Eq(ByRef(download_observer_))));
82  }
83
84  void CreatePrompt() {
85    prompt_ = DownloadDangerPrompt::Create(
86        &download_,
87        browser()->tab_strip_model()->GetActiveWebContents(),
88        false,
89        base::Bind(&DownloadDangerPromptTest::PromptCallback, this));
90    content::RunAllPendingInMessageLoop();
91  }
92
93  void PromptCallback(DownloadDangerPrompt::Action action) {
94    EXPECT_FALSE(did_receive_callback_);
95    EXPECT_EQ(expected_action_, action);
96    did_receive_callback_ = true;
97    prompt_ = NULL;
98  }
99
100  content::MockDownloadItem download_;
101  content::DownloadItem::Observer* download_observer_;
102  DownloadDangerPrompt* prompt_;
103  DownloadDangerPrompt::Action expected_action_;
104  bool did_receive_callback_;
105
106  DISALLOW_COPY_AND_ASSIGN(DownloadDangerPromptTest);
107};
108
109IN_PROC_BROWSER_TEST_F(DownloadDangerPromptTest, TestAll) {
110  OpenNewTab();
111
112  // Clicking the Accept button should invoke the ACCEPT action.
113  SetUpExpectations(DownloadDangerPrompt::ACCEPT);
114  SimulatePromptAction(DownloadDangerPrompt::ACCEPT);
115  VerifyExpectations();
116
117  // Clicking the Cancel button should invoke the CANCEL action.
118  SetUpExpectations(DownloadDangerPrompt::CANCEL);
119  SimulatePromptAction(DownloadDangerPrompt::CANCEL);
120  VerifyExpectations();
121
122  // If the download is no longer dangerous (because it was accepted), the
123  // dialog should DISMISS itself.
124  SetUpExpectations(DownloadDangerPrompt::DISMISS);
125  EXPECT_CALL(download(), IsDangerous()).WillOnce(Return(false));
126  download_observer()->OnDownloadUpdated(&download());
127  VerifyExpectations();
128
129  // If the download is in a terminal state then the dialog should DISMISS
130  // itself.
131  SetUpExpectations(DownloadDangerPrompt::DISMISS);
132  EXPECT_CALL(download(), IsDangerous()).WillOnce(Return(true));
133  EXPECT_CALL(download(), IsDone()).WillOnce(Return(true));
134  download_observer()->OnDownloadUpdated(&download());
135  VerifyExpectations();
136
137  // If the download is dangerous and is not in a terminal state, don't dismiss
138  // the dialog.
139  SetUpExpectations(DownloadDangerPrompt::ACCEPT);
140  EXPECT_CALL(download(), IsDangerous()).WillOnce(Return(true));
141  EXPECT_CALL(download(), IsDone()).WillOnce(Return(false));
142  download_observer()->OnDownloadUpdated(&download());
143  SimulatePromptAction(DownloadDangerPrompt::ACCEPT);
144  VerifyExpectations();
145
146  // If the containing tab is closed, the dialog should DISMISS itself.
147  OpenNewTab();
148  // TODO(benjhayden):
149  // SetUpExpectations(DownloadDangerPrompt::DISMISS);
150  SetUpExpectations(DownloadDangerPrompt::CANCEL);
151  chrome::CloseTab(browser());
152  VerifyExpectations();
153}
154