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 "components/web_modal/web_contents_modal_dialog_manager.h"
6
7 #include <map>
8
9 #include "base/memory/scoped_ptr.h"
10 #include "components/web_modal/native_web_contents_modal_dialog_manager.h"
11 #include "components/web_modal/test_web_contents_modal_dialog_manager_delegate.h"
12 #include "content/public/test/test_renderer_host.h"
13 #include "testing/gtest/include/gtest/gtest.h"
14
15 namespace web_modal {
16
17 class TestNativeWebContentsModalDialogManager
18 : public NativeWebContentsModalDialogManager {
19 public:
20 enum DialogState {
21 UNKNOWN,
22 NOT_SHOWN,
23 SHOWN,
24 HIDDEN,
25 CLOSED
26 };
27
TestNativeWebContentsModalDialogManager(NativeWebContentsModalDialogManagerDelegate * delegate)28 explicit TestNativeWebContentsModalDialogManager(
29 NativeWebContentsModalDialogManagerDelegate* delegate)
30 : delegate_(delegate) {}
ManageDialog(NativeWebContentsModalDialog dialog)31 virtual void ManageDialog(NativeWebContentsModalDialog dialog) OVERRIDE {
32 dialog_state_[dialog] = NOT_SHOWN;
33 }
ShowDialog(NativeWebContentsModalDialog dialog)34 virtual void ShowDialog(NativeWebContentsModalDialog dialog) OVERRIDE {
35 dialog_state_[dialog] = SHOWN;
36 }
HideDialog(NativeWebContentsModalDialog dialog)37 virtual void HideDialog(NativeWebContentsModalDialog dialog) OVERRIDE {
38 dialog_state_[dialog] = HIDDEN;
39 }
CloseDialog(NativeWebContentsModalDialog dialog)40 virtual void CloseDialog(NativeWebContentsModalDialog dialog) OVERRIDE {
41 delegate_->WillClose(dialog);
42 dialog_state_[dialog] = CLOSED;
43 }
FocusDialog(NativeWebContentsModalDialog dialog)44 virtual void FocusDialog(NativeWebContentsModalDialog dialog) OVERRIDE {
45 }
PulseDialog(NativeWebContentsModalDialog dialog)46 virtual void PulseDialog(NativeWebContentsModalDialog dialog) OVERRIDE {
47 }
HostChanged(WebContentsModalDialogHost * new_host)48 virtual void HostChanged(WebContentsModalDialogHost* new_host) OVERRIDE {
49 }
50
GetCloseCount() const51 int GetCloseCount() const {
52 int count = 0;
53 for (DialogStateMap::const_iterator it = dialog_state_.begin();
54 it != dialog_state_.end(); ++it) {
55 if (it->second == CLOSED)
56 count++;
57 }
58 return count;
59 }
60
GetDialogState(NativeWebContentsModalDialog dialog) const61 DialogState GetDialogState(NativeWebContentsModalDialog dialog) const {
62 DialogStateMap::const_iterator loc = dialog_state_.find(dialog);
63 return loc == dialog_state_.end() ? UNKNOWN : loc->second;
64 }
65
66 private:
67 typedef std::map<NativeWebContentsModalDialog, DialogState> DialogStateMap;
68
69 NativeWebContentsModalDialogManagerDelegate* delegate_;
70 DialogStateMap dialog_state_;
71
72 DISALLOW_COPY_AND_ASSIGN(TestNativeWebContentsModalDialogManager);
73 };
74
75 class WebContentsModalDialogManagerTest
76 : public content::RenderViewHostTestHarness {
77 public:
WebContentsModalDialogManagerTest()78 WebContentsModalDialogManagerTest()
79 : next_dialog_id(1),
80 manager(NULL),
81 native_manager(NULL) {
82 }
83
SetUp()84 virtual void SetUp() {
85 content::RenderViewHostTestHarness::SetUp();
86
87 delegate.reset(new TestWebContentsModalDialogManagerDelegate);
88 WebContentsModalDialogManager::CreateForWebContents(web_contents());
89 manager = WebContentsModalDialogManager::FromWebContents(web_contents());
90 manager->SetDelegate(delegate.get());
91 test_api.reset(new WebContentsModalDialogManager::TestApi(manager));
92 native_manager = new TestNativeWebContentsModalDialogManager(manager);
93
94 // |manager| owns |native_manager| as a result.
95 test_api->ResetNativeManager(native_manager);
96 }
97
TearDown()98 virtual void TearDown() {
99 test_api.reset();
100 content::RenderViewHostTestHarness::TearDown();
101 }
102
103 protected:
MakeFakeDialog()104 NativeWebContentsModalDialog MakeFakeDialog() {
105 // WebContentsModalDialogManager treats the NativeWebContentsModalDialog as
106 // an opaque type, so creating fake NativeWebContentsModalDialogs using
107 // reinterpret_cast is valid.
108 return reinterpret_cast<NativeWebContentsModalDialog>(next_dialog_id++);
109 }
110
111 int next_dialog_id;
112 scoped_ptr<TestWebContentsModalDialogManagerDelegate> delegate;
113 WebContentsModalDialogManager* manager;
114 scoped_ptr<WebContentsModalDialogManager::TestApi> test_api;
115 TestNativeWebContentsModalDialogManager* native_manager;
116
117 DISALLOW_COPY_AND_ASSIGN(WebContentsModalDialogManagerTest);
118 };
119
120 NativeWebContentsModalDialogManager*
CreateNativeManager(NativeWebContentsModalDialogManagerDelegate * native_delegate)121 WebContentsModalDialogManager::CreateNativeManager(
122 NativeWebContentsModalDialogManagerDelegate* native_delegate) {
123 return new TestNativeWebContentsModalDialogManager(native_delegate);
124 }
125
126 // Test that the dialog is shown immediately when the delegate indicates the web
127 // contents is visible.
TEST_F(WebContentsModalDialogManagerTest,WebContentsVisible)128 TEST_F(WebContentsModalDialogManagerTest, WebContentsVisible) {
129 // Dialog should be shown while WebContents is visible.
130 const NativeWebContentsModalDialog dialog1 = MakeFakeDialog();
131
132 manager->ShowDialog(dialog1);
133
134 EXPECT_EQ(TestNativeWebContentsModalDialogManager::SHOWN,
135 native_manager->GetDialogState(dialog1));
136 EXPECT_TRUE(manager->IsDialogActive());
137 EXPECT_TRUE(delegate->web_contents_blocked());
138 }
139
140 // Test that the dialog is not shown immediately when the delegate indicates the
141 // web contents is not visible.
TEST_F(WebContentsModalDialogManagerTest,WebContentsNotVisible)142 TEST_F(WebContentsModalDialogManagerTest, WebContentsNotVisible) {
143 // Dialog should not be shown while WebContents is not visible.
144 delegate->set_web_contents_visible(false);
145
146 const NativeWebContentsModalDialog dialog1 = MakeFakeDialog();
147
148 manager->ShowDialog(dialog1);
149
150 EXPECT_EQ(TestNativeWebContentsModalDialogManager::NOT_SHOWN,
151 native_manager->GetDialogState(dialog1));
152 EXPECT_TRUE(manager->IsDialogActive());
153 EXPECT_TRUE(delegate->web_contents_blocked());
154 }
155
156 // Test that only the first of multiple dialogs is shown.
TEST_F(WebContentsModalDialogManagerTest,ShowDialogs)157 TEST_F(WebContentsModalDialogManagerTest, ShowDialogs) {
158 const NativeWebContentsModalDialog dialog1 = MakeFakeDialog();
159 const NativeWebContentsModalDialog dialog2 = MakeFakeDialog();
160 const NativeWebContentsModalDialog dialog3 = MakeFakeDialog();
161
162 manager->ShowDialog(dialog1);
163 manager->ShowDialog(dialog2);
164 manager->ShowDialog(dialog3);
165
166 EXPECT_TRUE(delegate->web_contents_blocked());
167 EXPECT_EQ(TestNativeWebContentsModalDialogManager::SHOWN,
168 native_manager->GetDialogState(dialog1));
169 EXPECT_EQ(TestNativeWebContentsModalDialogManager::NOT_SHOWN,
170 native_manager->GetDialogState(dialog2));
171 EXPECT_EQ(TestNativeWebContentsModalDialogManager::NOT_SHOWN,
172 native_manager->GetDialogState(dialog3));
173 }
174
175 // Test that the dialog is shown/hidden when the WebContents is shown/hidden.
TEST_F(WebContentsModalDialogManagerTest,VisibilityObservation)176 TEST_F(WebContentsModalDialogManagerTest, VisibilityObservation) {
177 const NativeWebContentsModalDialog dialog1 = MakeFakeDialog();
178
179 manager->ShowDialog(dialog1);
180
181 EXPECT_TRUE(manager->IsDialogActive());
182 EXPECT_TRUE(delegate->web_contents_blocked());
183 EXPECT_EQ(TestNativeWebContentsModalDialogManager::SHOWN,
184 native_manager->GetDialogState(dialog1));
185
186 test_api->WebContentsWasHidden();
187
188 EXPECT_TRUE(manager->IsDialogActive());
189 EXPECT_TRUE(delegate->web_contents_blocked());
190 EXPECT_EQ(TestNativeWebContentsModalDialogManager::HIDDEN,
191 native_manager->GetDialogState(dialog1));
192
193 test_api->WebContentsWasShown();
194
195 EXPECT_TRUE(manager->IsDialogActive());
196 EXPECT_TRUE(delegate->web_contents_blocked());
197 EXPECT_EQ(TestNativeWebContentsModalDialogManager::SHOWN,
198 native_manager->GetDialogState(dialog1));
199 }
200
201 // Test that attaching an interstitial page closes dialogs configured to close.
TEST_F(WebContentsModalDialogManagerTest,InterstitialPage)202 TEST_F(WebContentsModalDialogManagerTest, InterstitialPage) {
203 const NativeWebContentsModalDialog dialog1 = MakeFakeDialog();
204 const NativeWebContentsModalDialog dialog2 = MakeFakeDialog();
205 const NativeWebContentsModalDialog dialog3 = MakeFakeDialog();
206
207 manager->ShowDialog(dialog1);
208 manager->ShowDialog(dialog2);
209 manager->ShowDialog(dialog3);
210
211 #if defined(OS_WIN) || defined(USE_AURA)
212 manager->SetCloseOnInterstitialPage(dialog2, false);
213 #else
214 // TODO(wittman): Remove this section once Mac is changed to close on
215 // interstitial pages by default.
216 manager->SetCloseOnInterstitialPage(dialog1, true);
217 manager->SetCloseOnInterstitialPage(dialog3, true);
218 #endif
219
220 test_api->DidAttachInterstitialPage();
221 EXPECT_EQ(TestNativeWebContentsModalDialogManager::CLOSED,
222 native_manager->GetDialogState(dialog1));
223 EXPECT_EQ(TestNativeWebContentsModalDialogManager::SHOWN,
224 native_manager->GetDialogState(dialog2));
225 EXPECT_EQ(TestNativeWebContentsModalDialogManager::CLOSED,
226 native_manager->GetDialogState(dialog3));
227 }
228
229
230 // Test that the first dialog is always shown, regardless of the order in which
231 // dialogs are closed.
TEST_F(WebContentsModalDialogManagerTest,CloseDialogs)232 TEST_F(WebContentsModalDialogManagerTest, CloseDialogs) {
233 // The front dialog is always shown regardless of dialog close order.
234 const NativeWebContentsModalDialog dialog1 = MakeFakeDialog();
235 const NativeWebContentsModalDialog dialog2 = MakeFakeDialog();
236 const NativeWebContentsModalDialog dialog3 = MakeFakeDialog();
237 const NativeWebContentsModalDialog dialog4 = MakeFakeDialog();
238
239 manager->ShowDialog(dialog1);
240 manager->ShowDialog(dialog2);
241 manager->ShowDialog(dialog3);
242 manager->ShowDialog(dialog4);
243
244 native_manager->CloseDialog(dialog1);
245
246 EXPECT_TRUE(manager->IsDialogActive());
247 EXPECT_TRUE(delegate->web_contents_blocked());
248 EXPECT_EQ(TestNativeWebContentsModalDialogManager::CLOSED,
249 native_manager->GetDialogState(dialog1));
250 EXPECT_EQ(TestNativeWebContentsModalDialogManager::SHOWN,
251 native_manager->GetDialogState(dialog2));
252 EXPECT_EQ(TestNativeWebContentsModalDialogManager::NOT_SHOWN,
253 native_manager->GetDialogState(dialog3));
254 EXPECT_EQ(TestNativeWebContentsModalDialogManager::NOT_SHOWN,
255 native_manager->GetDialogState(dialog4));
256
257 native_manager->CloseDialog(dialog3);
258
259 EXPECT_TRUE(manager->IsDialogActive());
260 EXPECT_TRUE(delegate->web_contents_blocked());
261 EXPECT_EQ(TestNativeWebContentsModalDialogManager::SHOWN,
262 native_manager->GetDialogState(dialog2));
263 EXPECT_EQ(TestNativeWebContentsModalDialogManager::CLOSED,
264 native_manager->GetDialogState(dialog3));
265 EXPECT_EQ(TestNativeWebContentsModalDialogManager::NOT_SHOWN,
266 native_manager->GetDialogState(dialog4));
267
268 native_manager->CloseDialog(dialog2);
269
270 EXPECT_TRUE(manager->IsDialogActive());
271 EXPECT_TRUE(delegate->web_contents_blocked());
272 EXPECT_EQ(TestNativeWebContentsModalDialogManager::CLOSED,
273 native_manager->GetDialogState(dialog2));
274 EXPECT_EQ(TestNativeWebContentsModalDialogManager::SHOWN,
275 native_manager->GetDialogState(dialog4));
276
277 native_manager->CloseDialog(dialog4);
278
279 EXPECT_FALSE(manager->IsDialogActive());
280 EXPECT_FALSE(delegate->web_contents_blocked());
281 EXPECT_EQ(TestNativeWebContentsModalDialogManager::CLOSED,
282 native_manager->GetDialogState(dialog4));
283 }
284
285 // Test that CloseAllDialogs does what it says.
TEST_F(WebContentsModalDialogManagerTest,CloseAllDialogs)286 TEST_F(WebContentsModalDialogManagerTest, CloseAllDialogs) {
287 const int kWindowCount = 4;
288 for (int i = 0; i < kWindowCount; i++)
289 manager->ShowDialog(MakeFakeDialog());
290
291 EXPECT_EQ(0, native_manager->GetCloseCount());
292
293 test_api->CloseAllDialogs();
294 EXPECT_FALSE(delegate->web_contents_blocked());
295 EXPECT_FALSE(manager->IsDialogActive());
296 EXPECT_EQ(kWindowCount, native_manager->GetCloseCount());
297 }
298
299 } // namespace web_modal
300